diff --git a/.changelog/epilogue.md b/.changelog/epilogue.md index 4515f0b26..9c812992b 100644 --- a/.changelog/epilogue.md +++ b/.changelog/epilogue.md @@ -1003,21 +1003,21 @@ Other highlights: [#195]: https://github.com/informalsystems/ibc-rs/pull/195 [ibc]: https://github.com/informalsystems/ibc-rs/tree/master/modules [#198]: https://github.com/informalsystems/ibc-rs/issues/198 -[ibc/ics02]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/ics02_client +[ibc/ics02]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/core/ics02_client [#185]: https://github.com/informalsystems/ibc-rs/issues/185 -[ibc/ics03]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/ics03_connection +[ibc/ics03]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/core/ics03_connection [#193]: https://github.com/informalsystems/ibc-rs/issues/193 -[ibc/ics04]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/ics04_channel +[ibc/ics04]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/core/ics04_channel [#192]: https://github.com/informalsystems/ibc-rs/issues/192 [ibc-relayer-cli]: https://github.com/informalsystems/ibc-rs/tree/master/relayer-cli -[architecture/FSM-1]: https://github.com/informalsystems/ibc-rs/blob/master/docs/architecture/fsm-async-connection.md +[architecture/FSM-1]: https://github.com/informalsystems/ibc-rs/blob/v0.1.0/docs/architecture/fsm-async-connection.md [#122]: https://github.com/informalsystems/ibc-rs/issues/122 [architecture/ADR-003]: https://github.com/informalsystems/ibc-rs/blob/master/docs/architecture/adr-003-handler-implementation.md [#119]: https://github.com/informalsystems/ibc-rs/issues/119 [#194]: https://github.com/informalsystems/ibc-rs/issues/194 -[ibc/ics24]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/ics24_host +[ibc/ics24]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/core/ics24_host [#168]: https://github.com/informalsystems/ibc-rs/issues/168 -[ibc/ics07]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/ics07_tendermint +[ibc/ics07]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/clients/ics07_tendermint ## v0.0.2 diff --git a/.changelog/unreleased/bug-fixes/ibc-relayer/1861-non-standard-ports.md b/.changelog/unreleased/bug-fixes/ibc-relayer/1861-non-standard-ports.md new file mode 100644 index 000000000..96ab22af0 --- /dev/null +++ b/.changelog/unreleased/bug-fixes/ibc-relayer/1861-non-standard-ports.md @@ -0,0 +1,3 @@ +- Fix support for non-standard ports in channel handshake + ([#1861](https://github.com/informalsystems/ibc-rs/issues/1861), + [#1837](https://github.com/informalsystems/ibc-rs/issues/1837)) diff --git a/.changelog/unreleased/bug-fixes/ibc/1770-deterministic-host-timestamp.md b/.changelog/unreleased/bug-fixes/ibc/1770-deterministic-host-timestamp.md new file mode 100644 index 000000000..821801926 --- /dev/null +++ b/.changelog/unreleased/bug-fixes/ibc/1770-deterministic-host-timestamp.md @@ -0,0 +1,2 @@ +- IBC handlers now retrieve the host timestamp from the latest host consensus + state ([#1770](https://github.com/informalsystems/ibc-rs/issues/1770)) \ No newline at end of file diff --git a/.changelog/unreleased/bug-fixes/relayer/1844-duplicate-send-packet-events.md b/.changelog/unreleased/bug-fixes/relayer/1844-duplicate-send-packet-events.md new file mode 100644 index 000000000..88cafb5b7 --- /dev/null +++ b/.changelog/unreleased/bug-fixes/relayer/1844-duplicate-send-packet-events.md @@ -0,0 +1,2 @@ +- Fix duplicate SendPacket events emitted by EndBlock + ([#1844](https://github.com/informalsystems/ibc-rs/issues/1844)) \ No newline at end of file diff --git a/.changelog/unreleased/bug-fixes/relayer/1872-clear-packets.md b/.changelog/unreleased/bug-fixes/relayer/1872-clear-packets.md new file mode 100644 index 000000000..4a72814e7 --- /dev/null +++ b/.changelog/unreleased/bug-fixes/relayer/1872-clear-packets.md @@ -0,0 +1,2 @@ +- Fixed bug where Hermes cleared packets at startup, despite + `clear_on_start = false` ([#1872](https://github.com/informalsystems/ibc-rs/issues/1872)) diff --git a/.changelog/unreleased/improvements/1388-more-health-checks.md b/.changelog/unreleased/improvements/1388-more-health-checks.md new file mode 100644 index 000000000..acd8d5530 --- /dev/null +++ b/.changelog/unreleased/improvements/1388-more-health-checks.md @@ -0,0 +1,2 @@ +- Add two more health checks: tx indexing enabled and historical entries > 0 + ([#1388](https://github.com/informalsystems/ibc-rs/issues/1388)) diff --git a/.changelog/unreleased/improvements/ibc-relayer-cli/1834-clear-packets-cmd.md b/.changelog/unreleased/improvements/ibc-relayer-cli/1834-clear-packets-cmd.md new file mode 100644 index 000000000..d9bb22fb4 --- /dev/null +++ b/.changelog/unreleased/improvements/ibc-relayer-cli/1834-clear-packets-cmd.md @@ -0,0 +1,3 @@ +- Added `clear packets` command, combining the effects of + `tx raw packet-recv` and `tx raw packet-ack`. + ([#1834](https://github.com/informalsystems/ibc-rs/pull/1834)) diff --git a/.changelog/unreleased/improvements/ibc-relayer/1880-nonallocating-verions-method.md b/.changelog/unreleased/improvements/ibc-relayer/1880-nonallocating-verions-method.md new file mode 100644 index 000000000..ecba32327 --- /dev/null +++ b/.changelog/unreleased/improvements/ibc-relayer/1880-nonallocating-verions-method.md @@ -0,0 +1 @@ +- Changed `ConnectionEnd::versions` method to be non-allocating by having it return a `&[Version]` instead of `Vec`. ([#1880](https://github.com/informalsystems/ibc-rs/pull/1880)) diff --git a/.changelog/unreleased/improvements/ibc/1769-cap-reader-keeper.md b/.changelog/unreleased/improvements/ibc/1769-cap-reader-keeper.md new file mode 100644 index 000000000..6e8f46352 --- /dev/null +++ b/.changelog/unreleased/improvements/ibc/1769-cap-reader-keeper.md @@ -0,0 +1,2 @@ +- Define CapabilityReader and CapabilityKeeper traits + ([#1769](https://github.com/informalsystems/ibc-rs/issues/1769)) \ No newline at end of file diff --git a/.changelog/v0.10.0/breaking-changes/1660-msrv-1.57.md b/.changelog/v0.10.0/breaking-changes/1660-msrv-1.57.md new file mode 100644 index 000000000..398ea568f --- /dev/null +++ b/.changelog/v0.10.0/breaking-changes/1660-msrv-1.57.md @@ -0,0 +1,2 @@ +- Update MSRV to Rust 1.57 + ([#1660](https://github.com/informalsystems/ibc-rs/issues/1660)) diff --git a/.changelog/v0.10.0/breaking-changes/1665-tendermint-0.23.2.md b/.changelog/v0.10.0/breaking-changes/1665-tendermint-0.23.2.md new file mode 100644 index 000000000..9ffadf79d --- /dev/null +++ b/.changelog/v0.10.0/breaking-changes/1665-tendermint-0.23.2.md @@ -0,0 +1,2 @@ +- Pin tendermint-rs dependencies to =0.23.2 + ([#1665](https://github.com/informalsystems/ibc-rs/pull/1665)) diff --git a/.changelog/v0.10.0/breaking-changes/ibc-relayer/1656-supervisor-spawn.md b/.changelog/v0.10.0/breaking-changes/ibc-relayer/1656-supervisor-spawn.md new file mode 100644 index 000000000..aab7c64a3 --- /dev/null +++ b/.changelog/v0.10.0/breaking-changes/ibc-relayer/1656-supervisor-spawn.md @@ -0,0 +1,3 @@ +- Improve spawning of supervisor worker tasks ([#1656](https://github.com/informalsystems/ibc-rs/issues/1656)) + - The `Supervisor` struct is removed. + - Supervisor is now spawned using the `spawn_supervisor` function. diff --git a/.changelog/v0.10.0/breaking-changes/ibc/1618-get-frozen-height.md b/.changelog/v0.10.0/breaking-changes/ibc/1618-get-frozen-height.md new file mode 100644 index 000000000..544d3c083 --- /dev/null +++ b/.changelog/v0.10.0/breaking-changes/ibc/1618-get-frozen-height.md @@ -0,0 +1,3 @@ +- Add the `frozen_height()` method to the `ClientState` trait. (Includes breaking changes to the Tendermint + `ClientState` API.) + ([#1618](https://github.com/informalsystems/ibc-rs/issues/1618)) diff --git a/.changelog/v0.10.0/breaking-changes/ibc/1665-remove-chrono.md b/.changelog/v0.10.0/breaking-changes/ibc/1665-remove-chrono.md new file mode 100644 index 000000000..c58260ee0 --- /dev/null +++ b/.changelog/v0.10.0/breaking-changes/ibc/1665-remove-chrono.md @@ -0,0 +1,4 @@ +- Remove `Timestamp` API that depended on the `chrono` crate: + ([#1665](https://github.com/informalsystems/ibc-rs/pull/1665)): + - `Timestamp::from_datetime`; use `From` + - `Timestamp::as_datetime`, superseded by `Timestamp::into_datetime` diff --git a/.changelog/v0.10.0/bug-fixes/1264-recover-acct-seq.md b/.changelog/v0.10.0/bug-fixes/1264-recover-acct-seq.md new file mode 100644 index 000000000..6a7bf3d09 --- /dev/null +++ b/.changelog/v0.10.0/bug-fixes/1264-recover-acct-seq.md @@ -0,0 +1,2 @@ +- Added a recovery mechanism to automatically retry or drop tx upon account + sequence mismatch errors ([#1264](https://github.com/informalsystems/ibc-rs/issues/1264)) diff --git a/.changelog/v0.10.0/bug-fixes/1634-update-unclog-instructions.md b/.changelog/v0.10.0/bug-fixes/1634-update-unclog-instructions.md new file mode 100644 index 000000000..e259131b1 --- /dev/null +++ b/.changelog/v0.10.0/bug-fixes/1634-update-unclog-instructions.md @@ -0,0 +1,2 @@ +- Update `CONTRIBUTING.md` for latest version of unclog + ([#1634](https://github.com/informalsystems/ibc-rs/issues/1634)) \ No newline at end of file diff --git a/.changelog/v0.10.0/bug-fixes/ibc-relayer/1664-handle-expired-client.md b/.changelog/v0.10.0/bug-fixes/ibc-relayer/1664-handle-expired-client.md new file mode 100644 index 000000000..8af52818c --- /dev/null +++ b/.changelog/v0.10.0/bug-fixes/ibc-relayer/1664-handle-expired-client.md @@ -0,0 +1 @@ +- Handle expired client errors in workers ([#1543](https://github.com/informalsystems/ibc-rs/issues/1543)) diff --git a/.changelog/v0.10.0/bug-fixes/ibc-relayer/1715-execute-schedule-after-packet-cmd.md b/.changelog/v0.10.0/bug-fixes/ibc-relayer/1715-execute-schedule-after-packet-cmd.md new file mode 100644 index 000000000..77aabfdda --- /dev/null +++ b/.changelog/v0.10.0/bug-fixes/ibc-relayer/1715-execute-schedule-after-packet-cmd.md @@ -0,0 +1 @@ +- Perform `execute_schedule` after handling packet commands in packet worker ([#1715](https://github.com/informalsystems/ibc-rs/issues/1715)) diff --git a/.changelog/v0.10.0/bug-fixes/ibc-relayer/1750-misbehavior-config.md b/.changelog/v0.10.0/bug-fixes/ibc-relayer/1750-misbehavior-config.md new file mode 100644 index 000000000..8c6ad062d --- /dev/null +++ b/.changelog/v0.10.0/bug-fixes/ibc-relayer/1750-misbehavior-config.md @@ -0,0 +1 @@ +- Do not spawn detect misbehavior task if it is disabled in config [#1750](https://github.com/informalsystems/ibc-rs/issues/1750) diff --git a/.changelog/v0.10.0/bug-fixes/ibc/1573-delete-commitment-in-acknowledgePacket.md b/.changelog/v0.10.0/bug-fixes/ibc/1573-delete-commitment-in-acknowledgePacket.md new file mode 100644 index 000000000..d8d3dc8a3 --- /dev/null +++ b/.changelog/v0.10.0/bug-fixes/ibc/1573-delete-commitment-in-acknowledgePacket.md @@ -0,0 +1,2 @@ +- Delete packet commitment instead of acknowledgement in acknowledgePacket + [#1573](https://github.com/informalsystems/ibc-rs/issues/1573) \ No newline at end of file diff --git a/.changelog/v0.10.0/bug-fixes/ibc/1649-fix-chan-open-ack-verify.md b/.changelog/v0.10.0/bug-fixes/ibc/1649-fix-chan-open-ack-verify.md new file mode 100644 index 000000000..62eb66710 --- /dev/null +++ b/.changelog/v0.10.0/bug-fixes/ibc/1649-fix-chan-open-ack-verify.md @@ -0,0 +1,2 @@ +- Set the `counterparty_channel_id` correctly to fix ICS04 [`chanOpenAck` handler verification](https://github.com/informalsystems/ibc-rs/blob/master/modules/src/core/ics04_channel/handler/chan_open_ack.rs) + ([#1649](https://github.com/informalsystems/ibc-rs/issues/1649)) diff --git a/.changelog/v0.10.0/bug-fixes/ibc/1697-assert-non-zero-trust-level.md b/.changelog/v0.10.0/bug-fixes/ibc/1697-assert-non-zero-trust-level.md new file mode 100644 index 000000000..efb81f033 --- /dev/null +++ b/.changelog/v0.10.0/bug-fixes/ibc/1697-assert-non-zero-trust-level.md @@ -0,0 +1,2 @@ +- Add missing assertion for non-zero trust-level in Tendermint client initialization. + ([#1697](https://github.com/informalsystems/ibc-rs/issues/1697)) diff --git a/.changelog/v0.10.0/bug-fixes/ibc/1710-fix-frozen-height-proto-conv.md b/.changelog/v0.10.0/bug-fixes/ibc/1710-fix-frozen-height-proto-conv.md new file mode 100644 index 000000000..a8938f9d3 --- /dev/null +++ b/.changelog/v0.10.0/bug-fixes/ibc/1710-fix-frozen-height-proto-conv.md @@ -0,0 +1,2 @@ +- Fix conversion to Protocol Buffers of `ClientState`'s `frozen_height` field. + ([#1710](https://github.com/informalsystems/ibc-rs/issues/1710)) \ No newline at end of file diff --git a/.changelog/v0.10.0/features/1410-dynamic-version.md b/.changelog/v0.10.0/features/1410-dynamic-version.md new file mode 100644 index 000000000..1ed737d8e --- /dev/null +++ b/.changelog/v0.10.0/features/1410-dynamic-version.md @@ -0,0 +1,2 @@ +- Support dynamic versions in channel open handshake & enable full support for + ibc-go v2 ([#1410](https://github.com/informalsystems/ibc-rs/issues/1410)) diff --git a/.changelog/v0.10.0/features/1550-ci-gaiav6.md b/.changelog/v0.10.0/features/1550-ci-gaiav6.md new file mode 100644 index 000000000..6215a94ea --- /dev/null +++ b/.changelog/v0.10.0/features/1550-ci-gaiav6.md @@ -0,0 +1 @@ +- Extend CI test suite to include E2E tests using Gaia v6.0.0 [#1550](https://github.com/informalsystems/ibc-rs/issues/1550) diff --git a/.changelog/v0.10.0/features/1606.md b/.changelog/v0.10.0/features/1606.md new file mode 100644 index 000000000..88dc7212b --- /dev/null +++ b/.changelog/v0.10.0/features/1606.md @@ -0,0 +1,2 @@ +- Added the `extra_wallets` parameter to `gm` to create additional funded wallets. +- Added the possibility of JSON output to `gm` by setting the environment variable `OUTPUT=json`. diff --git a/.changelog/v0.10.0/features/1633-allow-fee-granters.md b/.changelog/v0.10.0/features/1633-allow-fee-granters.md new file mode 100644 index 000000000..9c8344f7c --- /dev/null +++ b/.changelog/v0.10.0/features/1633-allow-fee-granters.md @@ -0,0 +1,2 @@ +- Added support for fee granters through config file + ([#1633](https://github.com/informalsystems/ibc-rs/issues/1633)) \ No newline at end of file diff --git a/.changelog/v0.10.0/features/ibc-relayer/1561-config-proof-specs.md b/.changelog/v0.10.0/features/ibc-relayer/1561-config-proof-specs.md new file mode 100644 index 000000000..a9d4447b5 --- /dev/null +++ b/.changelog/v0.10.0/features/ibc-relayer/1561-config-proof-specs.md @@ -0,0 +1,2 @@ +- Allow custom proof-specs in chain config + ([#1561](https://github.com/informalsystems/ibc-rs/issues/1561)) \ No newline at end of file diff --git a/.changelog/v0.10.0/features/ibc/1583-module-verification-ICS07.md b/.changelog/v0.10.0/features/ibc/1583-module-verification-ICS07.md new file mode 100644 index 000000000..5f11ff8e2 --- /dev/null +++ b/.changelog/v0.10.0/features/ibc/1583-module-verification-ICS07.md @@ -0,0 +1,3 @@ +- Implement proof verification for Tendermint client (ICS07). + ([#1583](https://github.com/informalsystems/ibc-rs/pull/1583)) + diff --git a/.changelog/v0.10.0/improvements/ibc-relayer-cli/1063-event-monitor-on-demand.md b/.changelog/v0.10.0/improvements/ibc-relayer-cli/1063-event-monitor-on-demand.md new file mode 100644 index 000000000..eba09eba3 --- /dev/null +++ b/.changelog/v0.10.0/improvements/ibc-relayer-cli/1063-event-monitor-on-demand.md @@ -0,0 +1,2 @@ +- Improve performance of standalone commands by starting the event monitor on-demand + ([#1063](https://github.com/informalsystems/ibc-rs/issues/1063)) diff --git a/.changelog/v0.10.0/improvements/ibc-relayer-cli/1636.md b/.changelog/v0.10.0/improvements/ibc-relayer-cli/1636.md new file mode 100644 index 000000000..5c333db4f --- /dev/null +++ b/.changelog/v0.10.0/improvements/ibc-relayer-cli/1636.md @@ -0,0 +1,2 @@ +- Increase the default for `max_gas` from `300_000` to `400_000` ([#1636](https://github.com/informalsystems/ibc-rs/pull/1636)) + diff --git a/.changelog/v0.10.0/improvements/ibc-relayer/1576-update-abscissa.md b/.changelog/v0.10.0/improvements/ibc-relayer/1576-update-abscissa.md new file mode 100644 index 000000000..31d107373 --- /dev/null +++ b/.changelog/v0.10.0/improvements/ibc-relayer/1576-update-abscissa.md @@ -0,0 +1,6 @@ +- Update to abscissa framework version 0.6.0-beta.1, adding support for + `--help` flags in subcommands and improving help and usage printouts. + The `--version` option of the `create channel` subcommand has been renamed + to `--channel-version`, with the old name still supported as an alias. + ([#1576](https://github.com/informalsystems/ibc-rs/pull/1576), + [#1743](https://github.com/informalsystems/ibc-rs/pull/1743)) diff --git a/.changelog/v0.10.0/improvements/ibc/1665-remove-chrono.md b/.changelog/v0.10.0/improvements/ibc/1665-remove-chrono.md new file mode 100644 index 000000000..477fa06f2 --- /dev/null +++ b/.changelog/v0.10.0/improvements/ibc/1665-remove-chrono.md @@ -0,0 +1,4 @@ +- More conventional ad-hoc conversion methods on `Timestamp` + ([#1665](https://github.com/informalsystems/ibc-rs/pull/1665)): + - `Timestamp::nanoseconds` replaces `Timestamp::as_nanoseconds` + - `Timestamp::into_datetime` substitutes `Timestamp::as_datetime` diff --git a/.changelog/v0.10.0/summary.md b/.changelog/v0.10.0/summary.md new file mode 100644 index 000000000..7d8ccc26c --- /dev/null +++ b/.changelog/v0.10.0/summary.md @@ -0,0 +1,16 @@ +*January 13th, 2021* + +This release notably updates the underlying CLI framework (`abscissa`) to version 0.6.0-beta.1, +which now uses `clap` for parsing command line arguments. This substantially improves the UX of the CLI, +by adding support for `--help` flags in subcommands and improving help and usage printouts. + +The `--version` option of the `create channel` subcommand has been renamed +to `--channel-version`, with the old name still supported as an alias. +Additionally, the `-h` short flag on many commands is now `-H` to avoid +clashes with the clap-provided short flag for help. + +This release also improves the handling of account sequence mismatch errors, +with a recovery mechanism to automatically retry or drop tx upon such errors. + +The relayer now also supports dynamic versions in channel open handshake (which is needed by Interchain Accounts), and enables full support for IBC v2. + diff --git a/.changelog/v0.11.0/1749-build-aarch64.md b/.changelog/v0.11.0/1749-build-aarch64.md new file mode 100644 index 000000000..5039c18a3 --- /dev/null +++ b/.changelog/v0.11.0/1749-build-aarch64.md @@ -0,0 +1,2 @@ +- Hermes builds for Linux on AArch64 are now released. + ([#1749](https://github.com/informalsystems/ibc-rs/pull/1749)) diff --git a/.changelog/v0.11.0/breaking-changes/1612-ibc-clock.md b/.changelog/v0.11.0/breaking-changes/1612-ibc-clock.md new file mode 100644 index 000000000..40954b86a --- /dev/null +++ b/.changelog/v0.11.0/breaking-changes/1612-ibc-clock.md @@ -0,0 +1 @@ +- Hide `ibc::Timestamp::now()` behind `clock` feature flag (#1612)[https://github.com/informalsystems/ibc-rs/issues/1612] diff --git a/.changelog/v0.11.0/breaking-changes/1765-msrv-1.58.md b/.changelog/v0.11.0/breaking-changes/1765-msrv-1.58.md new file mode 100644 index 000000000..eafdc89f8 --- /dev/null +++ b/.changelog/v0.11.0/breaking-changes/1765-msrv-1.58.md @@ -0,0 +1 @@ +- Update MSRV to Rust 1.58 ([#1765](https://github.com/informalsystems/ibc-rs/issues/1765)) diff --git a/.changelog/v0.11.0/breaking-changes/1767-tendermint-rs-0.23.5.md b/.changelog/v0.11.0/breaking-changes/1767-tendermint-rs-0.23.5.md new file mode 100644 index 000000000..4dff90782 --- /dev/null +++ b/.changelog/v0.11.0/breaking-changes/1767-tendermint-rs-0.23.5.md @@ -0,0 +1,2 @@ +- Update tendermint-rs dependencies to 0.23.5 + ([#1767](https://github.com/informalsystems/ibc-rs/issues/1767)) \ No newline at end of file diff --git a/.changelog/v0.11.0/breaking-changes/1817-remove-filter-option.md b/.changelog/v0.11.0/breaking-changes/1817-remove-filter-option.md new file mode 100644 index 000000000..a659b122f --- /dev/null +++ b/.changelog/v0.11.0/breaking-changes/1817-remove-filter-option.md @@ -0,0 +1,2 @@ +- Remove `mode.packets.filter` config option and enable filtering by default + ([#1817](https://github.com/informalsystems/ibc-rs/issues/1817)) \ No newline at end of file diff --git a/.changelog/v0.11.0/breaking-changes/ibc-relayer/1662-configurable-upgrade-denom.md b/.changelog/v0.11.0/breaking-changes/ibc-relayer/1662-configurable-upgrade-denom.md new file mode 100644 index 000000000..a4ce9eedc --- /dev/null +++ b/.changelog/v0.11.0/breaking-changes/ibc-relayer/1662-configurable-upgrade-denom.md @@ -0,0 +1,2 @@ +- Added a `denom` member to `upgrade_chain::UpgradePlanOptions`. + ([#1662](https://github.com/informalsystems/ibc-rs/issues/1662)) diff --git a/.changelog/v0.11.0/breaking-changes/ibc-relayer/1807-foreign-client-create-params.md b/.changelog/v0.11.0/breaking-changes/ibc-relayer/1807-foreign-client-create-params.md new file mode 100644 index 000000000..a57a9ca5b --- /dev/null +++ b/.changelog/v0.11.0/breaking-changes/ibc-relayer/1807-foreign-client-create-params.md @@ -0,0 +1,4 @@ +- `foreign_client::CreateParams` struct added, passed as the parameter to + `ForeignClient::build_create_client` and + `ForeignClient::build_create_client_and_send`. + ([#1807](https://github.com/informalsystems/ibc-rs/pull/1807)) diff --git a/.changelog/v0.11.0/bug-fixes/ibc/1745-fix-consensus-proof-verification.md b/.changelog/v0.11.0/bug-fixes/ibc/1745-fix-consensus-proof-verification.md new file mode 100644 index 000000000..0c8103df5 --- /dev/null +++ b/.changelog/v0.11.0/bug-fixes/ibc/1745-fix-consensus-proof-verification.md @@ -0,0 +1 @@ +- Verify the client consensus proof against the client's consensus state root and not the host's state root diff --git a/.changelog/v0.11.0/bug-fixes/ibc/1763-init-consensus-meta-on-client-create.md b/.changelog/v0.11.0/bug-fixes/ibc/1763-init-consensus-meta-on-client-create.md new file mode 100644 index 000000000..c32fbad95 --- /dev/null +++ b/.changelog/v0.11.0/bug-fixes/ibc/1763-init-consensus-meta-on-client-create.md @@ -0,0 +1,2 @@ +- Initialize consensus metadata on client creation + ([#1763](https://github.com/informalsystems/ibc-rs/issues/1763)) \ No newline at end of file diff --git a/.changelog/v0.11.0/improvements/1536-fast-start.md b/.changelog/v0.11.0/improvements/1536-fast-start.md new file mode 100644 index 000000000..414149536 --- /dev/null +++ b/.changelog/v0.11.0/improvements/1536-fast-start.md @@ -0,0 +1,3 @@ +- Improve startup time of the relayer + - When scanning a chain with filtering enabled and an allow list, skip scanning all the clients and query the allowed channels directly. This results in much fewer queries and a faster start. + - Add a `--full-scan` option to `hermes start` to opt out of the fast start mechanism and do a full scan. diff --git a/.changelog/v0.11.0/improvements/1641-tendermint-0.23.4.md b/.changelog/v0.11.0/improvements/1641-tendermint-0.23.4.md new file mode 100644 index 000000000..df22ac3c7 --- /dev/null +++ b/.changelog/v0.11.0/improvements/1641-tendermint-0.23.4.md @@ -0,0 +1,3 @@ +- Update `tendermint-rs` to v0.23.4 and harmonize the dependencies to use a single TLS stack. + A system installation of OpenSSL is no longer required to build Hermes. + ([#1641](https://github.com/informalsystems/ibc-rs/issues/1641)) \ No newline at end of file diff --git a/.changelog/v0.11.0/improvements/1687-remove-mock-sleep.md b/.changelog/v0.11.0/improvements/1687-remove-mock-sleep.md new file mode 100644 index 000000000..beb9510f9 --- /dev/null +++ b/.changelog/v0.11.0/improvements/1687-remove-mock-sleep.md @@ -0,0 +1 @@ +- Remove 1 second sleep in `generate_tm_block` during testing with mock context. [#1687](https://github.com/informalsystems/ibc-rs/issues/1687) diff --git a/.changelog/v0.11.0/improvements/ibc-relayer-cli/1662-configurable-upgrade-denom.md b/.changelog/v0.11.0/improvements/ibc-relayer-cli/1662-configurable-upgrade-denom.md new file mode 100644 index 000000000..324bb4025 --- /dev/null +++ b/.changelog/v0.11.0/improvements/ibc-relayer-cli/1662-configurable-upgrade-denom.md @@ -0,0 +1,2 @@ +- Make the deposit denomination configurable in `tx raw upgrade-chain` via a new `--denom` flag. + ([#1662](https://github.com/informalsystems/ibc-rs/issues/1662)) diff --git a/.changelog/v0.11.0/improvements/ibc-relayer-cli/1777-update-abscissa-and-clap.md b/.changelog/v0.11.0/improvements/ibc-relayer-cli/1777-update-abscissa-and-clap.md new file mode 100644 index 000000000..75f584a3e --- /dev/null +++ b/.changelog/v0.11.0/improvements/ibc-relayer-cli/1777-update-abscissa-and-clap.md @@ -0,0 +1,2 @@ +- Update to abscissa_core 0.6.0-rc.0 and clap 3.x + ([#1777](https://github.com/informalsystems/ibc-rs/pull/1777)) diff --git a/.changelog/v0.11.0/improvements/ibc-relayer-cli/1789-cli-completions.md b/.changelog/v0.11.0/improvements/ibc-relayer-cli/1789-cli-completions.md new file mode 100644 index 000000000..7d46b207e --- /dev/null +++ b/.changelog/v0.11.0/improvements/ibc-relayer-cli/1789-cli-completions.md @@ -0,0 +1,2 @@ +- Add `completions` CLI command to generate shell auto-completion scripts. + ([#1789](https://github.com/informalsystems/ibc-rs/pull/1789)) diff --git a/.changelog/v0.11.0/improvements/ibc-relayer-cli/836-create-client-options.md b/.changelog/v0.11.0/improvements/ibc-relayer-cli/836-create-client-options.md new file mode 100644 index 000000000..635234e9a --- /dev/null +++ b/.changelog/v0.11.0/improvements/ibc-relayer-cli/836-create-client-options.md @@ -0,0 +1,2 @@ +- Add custom options to the `create client` command. + ([#836](https://github.com/informalsystems/ibc-rs/issues/836)) diff --git a/.changelog/v0.11.0/improvements/ibc-relayer/1481-chainendpoint-any-consensus-state.md b/.changelog/v0.11.0/improvements/ibc-relayer/1481-chainendpoint-any-consensus-state.md new file mode 100644 index 000000000..743dc14e3 --- /dev/null +++ b/.changelog/v0.11.0/improvements/ibc-relayer/1481-chainendpoint-any-consensus-state.md @@ -0,0 +1,2 @@ +- Allow `ChainEndpoint` implementations to fetch any types of clients + and consensus states ([#1481](https://github.com/informalsystems/ibc-rs/issues/1481)) \ No newline at end of file diff --git a/.changelog/v0.11.0/improvements/ibc-relayer/1491-structured-logs.md b/.changelog/v0.11.0/improvements/ibc-relayer/1491-structured-logs.md new file mode 100644 index 000000000..1f1ae711e --- /dev/null +++ b/.changelog/v0.11.0/improvements/ibc-relayer/1491-structured-logs.md @@ -0,0 +1,2 @@ +- More structural logging in relayer, using tracing spans and key-value pairs. + ([#1491](https://github.com/informalsystems/ibc-rs/pull/1491)) diff --git a/.changelog/v0.11.0/improvements/ibc-relayer/1785-clarify-ethermint-keys.md b/.changelog/v0.11.0/improvements/ibc-relayer/1785-clarify-ethermint-keys.md new file mode 100644 index 000000000..94e4e72be --- /dev/null +++ b/.changelog/v0.11.0/improvements/ibc-relayer/1785-clarify-ethermint-keys.md @@ -0,0 +1,2 @@ +- Improved documention w.r.t. keys for Ethermint-based chains + ([#1785](https://github.com/informalsystems/ibc-rs/issues/1785)) \ No newline at end of file diff --git a/.changelog/v0.11.0/improvements/ibc/1760-path-variants-as-types.md b/.changelog/v0.11.0/improvements/ibc/1760-path-variants-as-types.md new file mode 100644 index 000000000..3045efb67 --- /dev/null +++ b/.changelog/v0.11.0/improvements/ibc/1760-path-variants-as-types.md @@ -0,0 +1,2 @@ +- Extract all `ics24_host::Path` variants into their separate types + ([#1760](https://github.com/informalsystems/ibc-rs/issues/1760)) \ No newline at end of file diff --git a/.changelog/v0.11.0/improvements/ibc/1761-disallow-empty-commitment-prefix-and-proof.md b/.changelog/v0.11.0/improvements/ibc/1761-disallow-empty-commitment-prefix-and-proof.md new file mode 100644 index 000000000..d59818fd5 --- /dev/null +++ b/.changelog/v0.11.0/improvements/ibc/1761-disallow-empty-commitment-prefix-and-proof.md @@ -0,0 +1,2 @@ +- Disallow empty `CommitmentPrefix` and `CommitmentProofBytes` + ([#1761](https://github.com/informalsystems/ibc-rs/issues/1761)) \ No newline at end of file diff --git a/.changelog/v0.11.0/summary.md b/.changelog/v0.11.0/summary.md new file mode 100644 index 000000000..8a19f4003 --- /dev/null +++ b/.changelog/v0.11.0/summary.md @@ -0,0 +1,36 @@ +This release notably speeds up the startup time of Hermes, +adds options to the `create client` command to customize the client parameters, +makes the deposit denomination configurable in `tx raw upgrade-chain` via a new `--denom` flag, +and adds a `completions` CLI command to generate shell auto-completion scripts. + +### Note for operators + +This release includes a breaking change, which requires the configuration file to be edited. +The `mode.packets.filter` configuration option has been removed and is now enabled by default. + +Before running Hermes v0.11.0, make sure you remove the `mode.packets.filter` option from the configuration file. + +```diff +--- a/config.toml ++++ b/config.toml +@@ -50,18 +50,6 @@ clear_interval = 100 + # Whether or not to clear packets on start. [Default: false] + clear_on_start = true + +-# Enable or disable the filtering mechanism. +-# Valid options are 'true', 'false'. +-# Currently Hermes supports two filters: +-# 1. Packet filtering on a per-chain basis; see the chain-specific +-# filter specification below in [chains.packet_filter]. +-# 2. Filter for all activities based on client state trust threshold; this filter +-# is parametrized with (numerator = 1, denominator = 3), so that clients with +-# thresholds different than this will be ignored. +-# If set to 'true', both of the above filters will be enabled. +-# [Default: false] +-filter = false +- + # Toggle the transaction confirmation mechanism. + # The tx confirmation mechanism periodically queries the `/tx_search` RPC + # endpoint to check that previously-submitted transactions +``` + diff --git a/.changelog/v0.11.1/bug-fixes/ibc-relayer-cli/1822-skip-config-for-completions.md b/.changelog/v0.11.1/bug-fixes/ibc-relayer-cli/1822-skip-config-for-completions.md new file mode 100644 index 000000000..36eed16cc --- /dev/null +++ b/.changelog/v0.11.1/bug-fixes/ibc-relayer-cli/1822-skip-config-for-completions.md @@ -0,0 +1,2 @@ +- Do not require a config file to be present for the `completions` command. + ([#1822](https://github.com/informalsystems/ibc-rs/pull/1822)) diff --git a/.changelog/v0.11.1/improvements/ibc-relayer/1389-add-connection-handshake-verification-logic.md b/.changelog/v0.11.1/improvements/ibc-relayer/1389-add-connection-handshake-verification-logic.md new file mode 100644 index 000000000..be5a15dae --- /dev/null +++ b/.changelog/v0.11.1/improvements/ibc-relayer/1389-add-connection-handshake-verification-logic.md @@ -0,0 +1 @@ +- Add missing checks for `ConnectionEnd::version` and `Counterparty::prefix` fields in the `check_destination_connection_state` method. ([#1389](https://github.com/informalsystems/ibc-rs/issues/1389)) diff --git a/.changelog/v0.11.1/improvements/ibc-relayer/1663-pending-timeout.md b/.changelog/v0.11.1/improvements/ibc-relayer/1663-pending-timeout.md new file mode 100644 index 000000000..d9da56b8c --- /dev/null +++ b/.changelog/v0.11.1/improvements/ibc-relayer/1663-pending-timeout.md @@ -0,0 +1,2 @@ +- Increased tx confirmation timeout to 300s to prevent aggressive tx + resubmission ([#1663](https://github.com/informalsystems/ibc-rs/issues/1663)) \ No newline at end of file diff --git a/.changelog/v0.11.1/improvements/ibc-relayer/1793-begin-end-block-chan-events.md b/.changelog/v0.11.1/improvements/ibc-relayer/1793-begin-end-block-chan-events.md new file mode 100644 index 000000000..369f3c51d --- /dev/null +++ b/.changelog/v0.11.1/improvements/ibc-relayer/1793-begin-end-block-chan-events.md @@ -0,0 +1,2 @@ +- Handle channel events originating from Tendermint ABCI's BeginBlock and EndBlock methods + ([#1793](https://github.com/informalsystems/ibc-rs/issues/1793)) \ No newline at end of file diff --git a/.changelog/v0.11.1/summary.md b/.changelog/v0.11.1/summary.md new file mode 100644 index 000000000..5a5f1350b --- /dev/null +++ b/.changelog/v0.11.1/summary.md @@ -0,0 +1 @@ +This release adds support for channel events originating from Tendermint ABCI's `BeginBlock` and `EndBlock` methods. diff --git a/.changelog/v0.8.0-pre.1/breaking-changes/ibc/1214-ics07.md b/.changelog/v0.8.0-pre.1/breaking-changes/ibc/1214-ics07.md new file mode 100644 index 000000000..42080cdef --- /dev/null +++ b/.changelog/v0.8.0-pre.1/breaking-changes/ibc/1214-ics07.md @@ -0,0 +1,3 @@ +- The `check_header_and_update_state` method of the `ClientDef` + trait (ICS02) has been expanded to facilitate ICS07 + ([#1214](https://github.com/informalsystems/ibc-rs/issues/1214)) \ No newline at end of file diff --git a/.changelog/v0.8.0-pre.1/features/1433-memo-field.md b/.changelog/v0.8.0-pre.1/features/1433-memo-field.md new file mode 100644 index 000000000..c25e65342 --- /dev/null +++ b/.changelog/v0.8.0-pre.1/features/1433-memo-field.md @@ -0,0 +1,3 @@ +- Add support for the `tx.memo` field ([#1433]) + +[#1433]: https://github.com/informalsystems/ibc-rs/issues/1433 diff --git a/.changelog/v0.8.0-pre.1/features/ibc-relayer/1457-default-gas.md b/.changelog/v0.8.0-pre.1/features/ibc-relayer/1457-default-gas.md new file mode 100644 index 000000000..94b731220 --- /dev/null +++ b/.changelog/v0.8.0-pre.1/features/ibc-relayer/1457-default-gas.md @@ -0,0 +1,2 @@ +- Add a `default_gas` setting to be used for submitting a tx when tx simulation + fails ([#1457](https://github.com/informalsystems/ibc-rs/issues/1457)) \ No newline at end of file diff --git a/.changelog/v0.8.0-pre.1/features/ibc-relayer/1464-ibc-go-check.md b/.changelog/v0.8.0-pre.1/features/ibc-relayer/1464-ibc-go-check.md new file mode 100644 index 000000000..69a75ed2a --- /dev/null +++ b/.changelog/v0.8.0-pre.1/features/ibc-relayer/1464-ibc-go-check.md @@ -0,0 +1,2 @@ +- Update compatibility check for IBC-Go dependency + ([#1464](https://github.com/informalsystems/ibc-rs/issues/1464)) \ No newline at end of file diff --git a/.changelog/v0.8.0-pre.1/features/ibc/1214-ics07.md b/.changelog/v0.8.0-pre.1/features/ibc/1214-ics07.md new file mode 100644 index 000000000..460b04b45 --- /dev/null +++ b/.changelog/v0.8.0-pre.1/features/ibc/1214-ics07.md @@ -0,0 +1,2 @@ +- Add ICS07 verification functionality by using `tendermint-light-client` + ([#1214](https://github.com/informalsystems/ibc-rs/issues/1214)) diff --git a/.changelog/v0.8.0-pre.1/improvements/ibc-relayer/1231-begin-end-block-events.md b/.changelog/v0.8.0-pre.1/improvements/ibc-relayer/1231-begin-end-block-events.md new file mode 100644 index 000000000..4f8f5af6a --- /dev/null +++ b/.changelog/v0.8.0-pre.1/improvements/ibc-relayer/1231-begin-end-block-events.md @@ -0,0 +1,2 @@ +- Handle SendPacket events originating from Tendermint ABCI's BeginBlock + and EndBlock methods ([#1231](https://github.com/informalsystems/ibc-rs/issues/1231)) diff --git a/.changelog/v0.8.0-pre.1/improvements/ibc-relayer/1440-improve-error-msg-create-client.md b/.changelog/v0.8.0-pre.1/improvements/ibc-relayer/1440-improve-error-msg-create-client.md new file mode 100644 index 000000000..eb6c3d817 --- /dev/null +++ b/.changelog/v0.8.0-pre.1/improvements/ibc-relayer/1440-improve-error-msg-create-client.md @@ -0,0 +1,3 @@ +- Improve error message when `create client` fails and add a health + check for the trusting period being smaller than the unbonding period + ([#1440](https://github.com/informalsystems/ibc-rs/issues/1440)) diff --git a/.changelog/v0.8.0-pre.1/summary.md b/.changelog/v0.8.0-pre.1/summary.md new file mode 100644 index 000000000..8ba672152 --- /dev/null +++ b/.changelog/v0.8.0-pre.1/summary.md @@ -0,0 +1,10 @@ +This is a pre-release which depends on forks of various Rust libraries. +As such, it is advised to avoid depending on the `ibc` and `ibc-relayer` crates +at version 0.8.0-pre.1. + +However, Hermes v0.8.0-pre.1 is considered stable and it is recommended for all +users to update to this version. + +This release notably includes a new [`memo_prefix`][memo] configuration option +for specifying a prefix to be include in the memo of each transaction submitted +by Hermes. diff --git a/.changelog/v0.8.0/breaking-changes/1519-msrv-1.56.md b/.changelog/v0.8.0/breaking-changes/1519-msrv-1.56.md new file mode 100644 index 000000000..3fec5b405 --- /dev/null +++ b/.changelog/v0.8.0/breaking-changes/1519-msrv-1.56.md @@ -0,0 +1,2 @@ +- Update MSRV to Rust 1.56 and use the 2021 edition + ([#1519](https://github.com/informalsystems/ibc-rs/issues/1519)) \ No newline at end of file diff --git a/.changelog/v0.8.0/bug-fixes/1445-clock-drift.md b/.changelog/v0.8.0/bug-fixes/1445-clock-drift.md new file mode 100644 index 000000000..a92f3b979 --- /dev/null +++ b/.changelog/v0.8.0/bug-fixes/1445-clock-drift.md @@ -0,0 +1,9 @@ +- Fix for client state clock drift [#1445]: + * Added new config param `max_clock_drift` to prevent + the problem for appearing in newly-created clients. + * Added a synchronos waiting in client update logic + to allow destination chain to reach a new height + before submitting a client update message. + + +[#1445]: https://github.com/informalsystems/ibc-rs/issues/1445 diff --git a/.changelog/v0.8.0/bug-fixes/1504-timeout_check.md b/.changelog/v0.8.0/bug-fixes/1504-timeout_check.md new file mode 100644 index 000000000..66bfdde2c --- /dev/null +++ b/.changelog/v0.8.0/bug-fixes/1504-timeout_check.md @@ -0,0 +1,2 @@ +- Fix for packet timeout computation + ([#1504](https://github.com/informalsystems/ibc-rs/issues/1504)) \ No newline at end of file diff --git a/.changelog/v0.8.0/improvements/1417-update-client-misbehavior-perf.md b/.changelog/v0.8.0/improvements/1417-update-client-misbehavior-perf.md new file mode 100644 index 000000000..40e88bed7 --- /dev/null +++ b/.changelog/v0.8.0/improvements/1417-update-client-misbehavior-perf.md @@ -0,0 +1,2 @@ +- Improve performance of misbehaviour checks triggered by an `UpdateClient` + event ([#1417](https://github.com/informalsystems/ibc-rs/issues/1417)) \ No newline at end of file diff --git a/.changelog/v0.8.0/improvements/1502-update-prost-09.md b/.changelog/v0.8.0/improvements/1502-update-prost-09.md new file mode 100644 index 000000000..8ec716b58 --- /dev/null +++ b/.changelog/v0.8.0/improvements/1502-update-prost-09.md @@ -0,0 +1,2 @@ +- Update to official releases of `prost` 0.9 and `tonic` 0.6 + ([#1502](https://github.com/informalsystems/ibc-rs/issues/1502)) \ No newline at end of file diff --git a/.changelog/v0.8.0/improvements/ibc/1436-restructure-to-match-ibc-go.md b/.changelog/v0.8.0/improvements/ibc/1436-restructure-to-match-ibc-go.md new file mode 100644 index 000000000..74e62cc06 --- /dev/null +++ b/.changelog/v0.8.0/improvements/ibc/1436-restructure-to-match-ibc-go.md @@ -0,0 +1,4 @@ +- Restructure the layout of the `ibc` crate to match `ibc-go`'s [layout][ibc-go-layout] ([#1436][issue-1436]). + +[issue-1436]: https://github.com/informalsystems/ibc-rs/issues/1436 +[ibc-go-layout]: https://github.com/cosmos/ibc-go#contents diff --git a/.changelog/v0.8.0/improvements/ibc/1460-path-fromstr.md b/.changelog/v0.8.0/improvements/ibc/1460-path-fromstr.md new file mode 100644 index 000000000..df0743ee6 --- /dev/null +++ b/.changelog/v0.8.0/improvements/ibc/1460-path-fromstr.md @@ -0,0 +1 @@ +- Implement `FromStr` to enable string-encoded paths to be converted into Path identifiers ([#1460](https://github.com/informalsystems/ibc-rs/issues/1460)) diff --git a/.changelog/v0.8.0/improvements/ibc/838-converting-IbcEvent-into-AbciEvent.md b/.changelog/v0.8.0/improvements/ibc/838-converting-IbcEvent-into-AbciEvent.md new file mode 100644 index 000000000..502e199cf --- /dev/null +++ b/.changelog/v0.8.0/improvements/ibc/838-converting-IbcEvent-into-AbciEvent.md @@ -0,0 +1 @@ +- Support for converting `ibc::events::IbcEvent` into `tendermint::abci::Event` ([#838](https://github.com/informalsystems/ibc-rs/issues/838)) diff --git a/.changelog/v0.8.0/summary.md b/.changelog/v0.8.0/summary.md new file mode 100644 index 000000000..e90a86f67 --- /dev/null +++ b/.changelog/v0.8.0/summary.md @@ -0,0 +1,10 @@ +This is the final release of version 0.8.0, which now depends on the official releases of the `prost` and `tonic` crates. +In addition to everything that's included in v0.8.0-pre.1, this release updates the minimum supported Rust version to 1.56, +and contains various bug fixes and performance improvements which make the relayer more reliable. + +#### Notice for operators +A new setting was added to the Hermes configuration: `max_block_time`. +This setting specifies the maximum time per block for this chain. +The block time together with the clock drift are added to the source drift to estimate +the maximum clock drift when creating a client on this chain. +For Cosmos-SDK chains a good approximation is `timeout_propose` + `timeout_commit` diff --git a/.changelog/v0.9.0/bug-fixes/ibc/1532-connOpenAck-counterparty-conn-id-not-set.md b/.changelog/v0.9.0/bug-fixes/ibc/1532-connOpenAck-counterparty-conn-id-not-set.md new file mode 100644 index 000000000..a0136fcd1 --- /dev/null +++ b/.changelog/v0.9.0/bug-fixes/ibc/1532-connOpenAck-counterparty-conn-id-not-set.md @@ -0,0 +1,5 @@ +- Set the connection counterparty in the ICS03 [`connOpenAck` handler][conn-open-ack-handler] + ([#1532](https://github.com/informalsystems/ibc-rs/issues/1532)) + +[conn-open-ack-handler]: https://github.com/informalsystems/ibc-rs/blob/master/modules/src/core/ics03_connection/handler/conn_open_ack.rs + diff --git a/.changelog/v0.9.0/features/1408-vega-protos.md b/.changelog/v0.9.0/features/1408-vega-protos.md new file mode 100644 index 000000000..d0e97aee0 --- /dev/null +++ b/.changelog/v0.9.0/features/1408-vega-protos.md @@ -0,0 +1,2 @@ +- Support for compatibility with gaia Vega upgrade (protos matching ibc-go v1.2.2 and SDK v0.44.3) + ([#1408](https://github.com/informalsystems/ibc-rs/issues/1408)) diff --git a/.changelog/v0.9.0/features/1534-ibc-queries.md b/.changelog/v0.9.0/features/1534-ibc-queries.md new file mode 100644 index 000000000..81868ac37 --- /dev/null +++ b/.changelog/v0.9.0/features/1534-ibc-queries.md @@ -0,0 +1,2 @@ +- Optimize the WS client to subscribe to IBC events only (instead of all Tx + events) ([#1534](https://github.com/informalsystems/ibc-rs/issues/1534)) \ No newline at end of file diff --git a/.changelog/v0.9.0/features/ibc-relayer/1518-config-modes.md b/.changelog/v0.9.0/features/ibc-relayer/1518-config-modes.md new file mode 100644 index 000000000..c42e7de9b --- /dev/null +++ b/.changelog/v0.9.0/features/ibc-relayer/1518-config-modes.md @@ -0,0 +1,2 @@ +- Allow for more granular control of relaying modes. The `mode` configuration section replaces the `strategy` option. + ([#1518](https://github.com/informalsystems/ibc-rs/issues/1518)) diff --git a/.changelog/v0.9.0/improvements/1544-typed-tla-mbt-specs.md b/.changelog/v0.9.0/improvements/1544-typed-tla-mbt-specs.md new file mode 100644 index 000000000..12679a61b --- /dev/null +++ b/.changelog/v0.9.0/improvements/1544-typed-tla-mbt-specs.md @@ -0,0 +1,2 @@ +- Upgrade IBC-rs TLA+ MBT models to modern Apalache type annotations + ([#1544](https://github.com/informalsystems/ibc-rs/issues/1544)) \ No newline at end of file diff --git a/.changelog/v0.9.0/improvements/1556-arch-doc.md b/.changelog/v0.9.0/improvements/1556-arch-doc.md new file mode 100644 index 000000000..1f019e127 --- /dev/null +++ b/.changelog/v0.9.0/improvements/1556-arch-doc.md @@ -0,0 +1,5 @@ +- Add architecture.md doc that gives a high-level overview of the structure of the codebase. +- Add some module-level documentation + ([#1556][1556]) + +[1556]: https://github.com/informalsystems/ibc-rs/pulls/1556 diff --git a/.changelog/v0.9.0/improvements/ibc-relayer-cli/1515-single-line-errors.md b/.changelog/v0.9.0/improvements/ibc-relayer-cli/1515-single-line-errors.md new file mode 100644 index 000000000..340a87363 --- /dev/null +++ b/.changelog/v0.9.0/improvements/ibc-relayer-cli/1515-single-line-errors.md @@ -0,0 +1,2 @@ +- Output errors on a single line if ANSI output is disabled + ([#1515](https://github.com/informalsystems/ibc-rs/issues/1515)) \ No newline at end of file diff --git a/.changelog/v0.9.0/improvements/ibc-relayer-cli/1555-fee-amount-overflow.md b/.changelog/v0.9.0/improvements/ibc-relayer-cli/1555-fee-amount-overflow.md new file mode 100644 index 000000000..9acc77b50 --- /dev/null +++ b/.changelog/v0.9.0/improvements/ibc-relayer-cli/1555-fee-amount-overflow.md @@ -0,0 +1,3 @@ +- Compute fee amount using big integers to prevent overflow + when using denominations with high decimal places + ([#1555](https://github.com/informalsystems/ibc-rs/issues/1555)) \ No newline at end of file diff --git a/.changelog/v0.9.0/improvements/ibc-relayer/1479-abort-failed-simulated-txs.md b/.changelog/v0.9.0/improvements/ibc-relayer/1479-abort-failed-simulated-txs.md new file mode 100644 index 000000000..fdf23c78d --- /dev/null +++ b/.changelog/v0.9.0/improvements/ibc-relayer/1479-abort-failed-simulated-txs.md @@ -0,0 +1,3 @@ +- The relayer will now avoid submitting a tx after the simulation failed + (in all but one special case) to avoid wasting fees unnecessarily + ([#1479](https://github.com/informalsystems/ibc-rs/issues/1479)) \ No newline at end of file diff --git a/.changelog/v0.9.0/improvements/ibc/1546-add-partialeq-ibcevent.md b/.changelog/v0.9.0/improvements/ibc/1546-add-partialeq-ibcevent.md new file mode 100644 index 000000000..af9048c54 --- /dev/null +++ b/.changelog/v0.9.0/improvements/ibc/1546-add-partialeq-ibcevent.md @@ -0,0 +1,2 @@ +- Derive `PartialEq` and `Eq` on `IbcEvent` and inner types + ([#1546](https://github.com/informalsystems/ibc-rs/issues/1546)) diff --git a/.changelog/v0.9.0/summary.md b/.changelog/v0.9.0/summary.md new file mode 100644 index 000000000..27fb85dc7 --- /dev/null +++ b/.changelog/v0.9.0/summary.md @@ -0,0 +1,52 @@ +*November 23rd, 2021* + +> This release honors Anca Zamfir, who has lead ibc-rs from its inception and through its first two years of life. +> The whole team is grateful for her dedication and the nurturing environment she created. +> To many more achievements, Anca!! 🥂 + +#### Notice for operators + +This release requires operators to update their Hermes configuration. +The `mode` configuration section now replaces the `strategy` option. + +##### `strategy = 'packets'` + +If Hermes was configured with `strategy = 'packets'`, then the configuration needs to be changed in the following way: + +```diff + [global] +-strategy = 'packets' + log_level = 'trace' +-clear_packets_interval = 100 +-tx_confirmation = true ++ ++[mode] ++ ++[mode.clients] ++enabled = true ++refresh = true ++misbehaviour = true ++ ++[mode.connections] ++enabled = false ++ ++[mode.channels] ++enabled = false ++ ++[mode.packets] ++enabled = true ++clear_interval = 100 ++clear_on_start = true ++filter = false ++tx_confirmation = true +``` + +##### `strategy = 'all'` + +If Hermes was configured to complete connection and channel handshakes as well, ie. with `strategy = 'all'`, +then on top of the changes above, `mode.connections.enabled` and `mode.chhanels.enabled` must be set to `true`. + +[See the relevant section][config-mode-toml] of the documented `config.toml` file in the repository for more details. + +[config-mode-toml]: https://github.com/informalsystems/ibc-rs/blob/v0.9.0/config.toml#L9-L59 + diff --git a/.github/ISSUE_TEMPLATE/rust-update.md b/.github/ISSUE_TEMPLATE/rust-update.md new file mode 100644 index 000000000..2763d111e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/rust-update.md @@ -0,0 +1,28 @@ +--- +name: Rust version update +about: A checklist to perform to update to a new version of Rust. +--- + +# Update to Rust release 1.x.y + +🦀 + +- [ ] Update the version in `rust-toolchain.toml`. +- [ ] Run `cargo clippy --all-features --fix`, review and commit the automatic + fixes, and fix all reported lints. Try to resolve the root causes for + the lints rather than silencing them with `#[allow(...)]`. + +## Update the MSRV (optional) + +Additional steps to perform in order to make the new minimal supported +Rust version: + +- [ ] Update the `rust-version` fields in all `Cargo.toml` files. +- [ ] Update the `msrv` field in `clippy.toml` and fix all lints reported by + `cargo clippy --all-features`. +- [ ] Update the MSRV shields in README files: + - `README.md` + - `relayer-rest/README.md` +- [ ] Update the MSRV in the guide: `guide/src/pre_requisites.md` +- [ ] Add a `.changelog` entry to the `breaking-changes` section, + announcing the new MSRV. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index e89131012..e20e5078b 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -15,10 +15,13 @@ are the most critical to review. ______ -For contributor use: +### PR author checklist: +- [ ] Added changelog entry, using [`unclog`](https://github.com/informalsystems/unclog). +- [ ] Added tests: integration (for Hermes) or unit/mock tests (for modules). +- [ ] Linked to GitHub issue. +- [ ] Updated code comments and documentation (e.g., `docs/`). -- [ ] Added a changelog entry, using [`unclog`](https://github.com/informalsystems/unclog). -- [ ] If applicable: Unit tests written, added test to CI. -- [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. -- [ ] Updated relevant documentation (`docs/`) and code comments. -- [ ] Re-reviewed `Files changed` in the Github PR explorer. +### Reviewer checklist: + +- [ ] Reviewed `Files changed` in the GitHub PR explorer. +- [ ] Manually tested (in case integration/unit/mock tests are absent). \ No newline at end of file diff --git a/.github/workflows/audit.yaml b/.github/workflows/audit.yaml index 4c52ea9c1..4ca65ae9f 100644 --- a/.github/workflows/audit.yaml +++ b/.github/workflows/audit.yaml @@ -1,10 +1,5 @@ name: Security Audit on: - pull_request: - paths: Cargo.lock - push: - branches: master - paths: Cargo.lock schedule: - cron: '0 0 * * *' diff --git a/.github/workflows/cargo-doc.yaml b/.github/workflows/cargo-doc.yaml new file mode 100644 index 000000000..640218503 --- /dev/null +++ b/.github/workflows/cargo-doc.yaml @@ -0,0 +1,27 @@ +name: Publish Cargo Doc + +on: + push: + branches: + - master + pull_request: {} + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + + - run: cargo doc + + - name: Deploy + if: ${{ github.ref == 'ref/head/master' }} + uses: peaceiris/actions-gh-pages@v3 + with: + deploy_key: ${{ secrets.IBC_RS_DOC_PRIVATE_KEY }} + external_repository: informalsystems/ibc-rs-doc + publish_dir: ./target/doc diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e-gaia-current-release.yaml similarity index 80% rename from .github/workflows/e2e.yaml rename to .github/workflows/e2e-gaia-current-release.yaml index 5debb0baa..4e3c5b95e 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e-gaia-current-release.yaml @@ -1,9 +1,10 @@ -name: End to End testing +name: End to End testing (Gaia - v5.0.8) on: pull_request: paths: - .github/workflows/e2e.yaml - Cargo.toml + - Cargo.lock - ci/** - e2e/** - proto/** @@ -17,6 +18,7 @@ on: paths: - .github/workflows/e2e.yaml - Cargo.toml + - Cargo.lock - ci/** - e2e/** - proto/** @@ -35,7 +37,7 @@ env: RUSTUP_MAX_RETRIES: 10 jobs: - test-end-to-end: + test-end-to-end-current-gaia: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 @@ -50,8 +52,8 @@ jobs: args: --workspace - run: cp ./target/debug/hermes . - name: Build relayer image - run: docker-compose -f ci/docker-compose.yml build relayer + run: docker-compose -f ci/docker-compose-gaia-current.yml build relayer - name: Start chains and relayer - run: docker-compose -f ci/docker-compose.yml up -d ibc-0 ibc-1 relayer + run: docker-compose -f ci/docker-compose-gaia-current.yml up -d ibc-0 ibc-1 relayer - name: Run relayer workflow run: docker exec relayer /bin/sh -c /relayer/e2e.sh diff --git a/.github/workflows/e2e-gaia-future-release.yaml b/.github/workflows/e2e-gaia-future-release.yaml new file mode 100644 index 000000000..429410dd2 --- /dev/null +++ b/.github/workflows/e2e-gaia-future-release.yaml @@ -0,0 +1,60 @@ +name: End to End testing (Gaia - v6.0.0) +on: + pull_request: + paths: + - .github/workflows/e2e.yaml + - Cargo.toml + - Cargo.lock + - ci/** + - e2e/** + - proto/** + - modules/** + - relayer/** + - relayer-cli/** + - relayer-rest/** + - telemetry/** + push: + branches: master + paths: + - .github/workflows/e2e.yaml + - Cargo.toml + - Cargo.lock + - ci/** + - e2e/** + - proto/** + - modules/** + - relayer/** + - relayer-cli/** + - relayer-rest/** + - telemetry/** + +env: + CARGO_INCREMENTAL: 0 + CARGO_PROFILE_DEV_DEBUG: 1 + CARGO_PROFILE_RELEASE_DEBUG: 1 + RUST_BACKTRACE: short + CARGO_NET_RETRY: 10 + RUSTUP_MAX_RETRIES: 10 + +jobs: + test-end-to-end-future-gaia: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + - uses: Swatinem/rust-cache@v1 + - uses: actions-rs/cargo@v1 + with: + command: build + args: --workspace + - run: cp ./target/debug/hermes . + - name: Build relayer image + run: docker-compose -f ci/docker-compose-gaia-future.yml build relayer + - name: Start chains and relayer + run: docker-compose -f ci/docker-compose-gaia-future.yml up -d ibc-0 ibc-1 relayer + - name: Run relayer workflow + continue-on-error: false + run: docker exec relayer /bin/sh -c /relayer/e2e.sh diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml new file mode 100644 index 000000000..349bf2f09 --- /dev/null +++ b/.github/workflows/integration.yaml @@ -0,0 +1,76 @@ +name: Rust +on: + pull_request: + paths: + - .github/workflows/integration.yaml + - Cargo.toml + - Cargo.lock + - ci/** + - e2e/** + - proto/** + - modules/** + - relayer/** + - relayer-cli/** + - relayer-rest/** + - telemetry/** + - tools/** + push: + branches: master + paths: + - .github/workflows/integration.yaml + - Cargo.toml + - Cargo.lock + - ci/** + - e2e/** + - proto/** + - modules/** + - relayer/** + - relayer-cli/** + - relayer-rest/** + - telemetry/** + - tools/** + +env: + CARGO_INCREMENTAL: 0 + CARGO_PROFILE_DEV_DEBUG: 1 + CARGO_PROFILE_RELEASE_DEBUG: 1 + RUST_BACKTRACE: short + CARGO_NET_RETRY: 10 + RUSTUP_MAX_RETRIES: 10 + +jobs: + integration-test: + runs-on: ubuntu-latest + strategy: + matrix: + gaiad: + - gaia4 + - gaia5 + - gaia6 + steps: + - uses: actions/checkout@v2 + - uses: cachix/install-nix-action@v15 + with: + install_url: https://nixos-nix-install-tests.cachix.org/serve/vij683ly7sl95nnhb67bdjjfabclr85m/install + install_options: '--tarball-url-prefix https://nixos-nix-install-tests.cachix.org/serve' + extra_nix_config: | + experimental-features = nix-command flakes + - uses: cachix/cachix-action@v10 + with: + name: cosmos + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + - uses: Swatinem/rust-cache@v1 + - uses: actions-rs/cargo@v1 + with: + command: test + args: -p ibc-integration-test --no-fail-fast --no-run + - env: + RUST_LOG: info + RUST_BACKTRACE: 1 + run: | + nix shell github:informalsystems/cosmos.nix#${{ matrix.gaiad }} -c cargo \ + test -p ibc-integration-test --no-fail-fast -- \ + --nocapture --test-threads=1 diff --git a/.github/workflows/no-std.yaml b/.github/workflows/no-std.yaml index d0ddd4832..c5d8dfd51 100644 --- a/.github/workflows/no-std.yaml +++ b/.github/workflows/no-std.yaml @@ -2,16 +2,18 @@ name: no_std check on: pull_request: paths: - - .github/workflows/rust.yml + - .github/workflows/no-std.yml - Cargo.toml + - Cargo.lock - ci/** - proto/** - modules/** push: branches: master paths: - - .github/workflows/rust.yml + - .github/workflows/no-std.yml - Cargo.toml + - Cargo.lock - ci/** - proto/** - modules/** @@ -36,8 +38,8 @@ jobs: steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 - with: - toolchain: nightly-2021-09-01 + with:= + toolchain: nightly target: wasm32-unknown-unknown override: true - run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 82fa05f13..fb64ad839 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,16 +21,19 @@ jobs: upload-assets: strategy: matrix: - os: - - ubuntu-latest - - macos-latest - runs-on: ${{ matrix.os }} + config: + - { os: ubuntu-latest, target: x86_64-unknown-linux-gnu } + - { os: ubuntu-latest, target: aarch64-unknown-linux-gnu } + - { os: macos-latest, target: x86_64-apple-darwin } + runs-on: ${{ matrix.config.os }} steps: - uses: actions/checkout@v2 - uses: taiki-e/upload-rust-binary-action@v1 with: # (required) bin: hermes + # (optional) Target triple + target: ${{ matrix.config.target }} # (optional) On which platform to distribute the `.tar.gz` file. # [default value: unix] # [possible values: all, unix, windows, none] diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 085ff3f3f..aa4d85f71 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -4,6 +4,7 @@ on: paths: - .github/workflows/rust.yml - Cargo.toml + - Cargo.lock - ci/** - e2e/** - proto/** @@ -12,11 +13,13 @@ on: - relayer-cli/** - relayer-rest/** - telemetry/** + - tools/** push: branches: master paths: - .github/workflows/rust.yml - Cargo.toml + - Cargo.lock - ci/** - e2e/** - proto/** @@ -25,6 +28,7 @@ on: - relayer-cli/** - relayer-rest/** - telemetry/** + - tools/** env: CARGO_INCREMENTAL: 0 @@ -102,7 +106,7 @@ jobs: - uses: actions-rs/cargo@v1 with: command: test - args: --all-features --no-fail-fast -- --nocapture + args: --all-features --no-fail-fast --workspace --exclude ibc-integration-test -- --nocapture # test-coverage: # runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index 9eada42f0..8c30a0d1e 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,6 @@ __pycache__/ # Ignore modelator aritfacts .modelator mc.log + +# Ignore OSX .DS_Store file +.DS_Store diff --git a/CHANGELOG.md b/CHANGELOG.md index ef0528745..3e94f326a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,402 @@ # CHANGELOG +## v0.11.1 +*February 4th, 2022* + +This release mainly adds support for channel events originating from Tendermint ABCI's `BeginBlock` and `EndBlock` methods. + +### BUG FIXES + +- [Relayer CLI](relayer-cli) + - Do not require a config file to be present for the `completions` command. + ([#1822](https://github.com/informalsystems/ibc-rs/pull/1822)) + +### IMPROVEMENTS + +- [Relayer Library](relayer) + - Increased tx confirmation timeout to 300s to prevent aggressive tx + resubmission ([#1663](https://github.com/informalsystems/ibc-rs/issues/1663)) + - Handle channel events originating from Tendermint ABCI's BeginBlock and EndBlock methods + ([#1793](https://github.com/informalsystems/ibc-rs/issues/1793)) + + +## v0.11.0 +*January 27th, 2022* + +This release notably speeds up the startup time of Hermes, +adds options to the `create client` command to customize the client parameters, +makes the deposit denomination configurable in `tx raw upgrade-chain` via a new `--denom` flag, +and adds a `completions` CLI command to generate shell auto-completion scripts. + +### Note for operators + +This release includes a breaking change, which requires the configuration file to be edited. +The `mode.packets.filter` configuration option has been removed and is now enabled by default. + +Before running Hermes v0.11.0, make sure you remove the `mode.packets.filter` option from the configuration file. + +```diff +--- a/config.toml ++++ b/config.toml +@@ -50,18 +50,6 @@ clear_interval = 100 + # Whether or not to clear packets on start. [Default: false] + clear_on_start = true + +-# Enable or disable the filtering mechanism. +-# Valid options are 'true', 'false'. +-# Currently Hermes supports two filters: +-# 1. Packet filtering on a per-chain basis; see the chain-specific +-# filter specification below in [chains.packet_filter]. +-# 2. Filter for all activities based on client state trust threshold; this filter +-# is parametrized with (numerator = 1, denominator = 3), so that clients with +-# thresholds different than this will be ignored. +-# If set to 'true', both of the above filters will be enabled. +-# [Default: false] +-filter = false +- + # Toggle the transaction confirmation mechanism. + # The tx confirmation mechanism periodically queries the `/tx_search` RPC + # endpoint to check that previously-submitted transactions +``` + + +### BREAKING CHANGES + +- General + - Update MSRV to Rust 1.58 ([#1765](https://github.com/informalsystems/ibc-rs/issues/1765)) + - Update tendermint-rs dependencies to 0.23.5 ([#1767](https://github.com/informalsystems/ibc-rs/issues/1767)) +- [Relayer Library](relayer) + - Added a `denom` member to `upgrade_chain::UpgradePlanOptions` + ([#1662](https://github.com/informalsystems/ibc-rs/issues/1662)) +- [IBC Modules](modules) + - Hide `ibc::Timestamp::now()` behind `clock` feature flag ([#1612](https://github.com/informalsystems/ibc-rs/issues/1612)) + +### BUG FIXES + +- [IBC Modules](modules) + - Verify the client consensus proof against the client's consensus state root and not the host's state root + [#1745](https://github.com/informalsystems/ibc-rs/issues/1745) + - Initialize consensus metadata on client creation + ([#1763](https://github.com/informalsystems/ibc-rs/issues/1763)) + +### IMPROVEMENTS + +- General + - Improve startup time of the relayer ([#1705](https://github.com/informalsystems/ibc-rs/issues/1705)) + * When scanning a chain with filtering enabled and an allow list, skip scanning all the clients and query the allowed channels directly. This results in much fewer queries and a faster start. + * Add a `--full-scan` option to `hermes start` to opt out of the fast start mechanism and do a full scan. + - Update `tendermint-rs` to v0.23.4 and harmonize the dependencies to use a single TLS stack. + A system installation of OpenSSL is no longer required to build Hermes. + ([#1641](https://github.com/informalsystems/ibc-rs/issues/1641)) + - Remove 1 second sleep in `generate_tm_block` during testing with mock context. + ([#1687](https://github.com/informalsystems/ibc-rs/issues/1687)) +- [IBC Modules](modules) + - Extract all `ics24_host::Path` variants into their separate types + ([#1760](https://github.com/informalsystems/ibc-rs/issues/1760)) + - Disallow empty `CommitmentPrefix` and `CommitmentProofBytes` + ([#1761](https://github.com/informalsystems/ibc-rs/issues/1761)) +- [Relayer Library](relayer) + - Allow `ChainEndpoint` implementations to fetch any types of clients + and consensus states ([#1481](https://github.com/informalsystems/ibc-rs/issues/1481)) + - More structural logging in relayer, using tracing spans and key-value pairs. + ([#1491](https://github.com/informalsystems/ibc-rs/pull/1491)) + - Improved documention w.r.t. keys for Ethermint-based chains + ([#1785](https://github.com/informalsystems/ibc-rs/issues/1785)) +- [Relayer CLI](relayer-cli) + - Add custom options to the `create client` command. + ([#836](https://github.com/informalsystems/ibc-rs/issues/836)) + - Make the deposit denomination configurable in `tx raw upgrade-chain` via a new `--denom` flag. + ([#1662](https://github.com/informalsystems/ibc-rs/issues/1662)) + - Update to abscissa_core 0.6.0-rc.0 and clap 3.x + ([#1777](https://github.com/informalsystems/ibc-rs/pull/1777)) + - Add `completions` CLI command to generate shell auto-completion scripts. + ([#1789](https://github.com/informalsystems/ibc-rs/pull/1789)) + +## v0.10.0 +*January 13th, 2021* + +This release notably updates the underlying CLI framework (`abscissa`) to version 0.6.0-beta.1, +which now uses `clap` for parsing command line arguments. This substantially improves the UX of the CLI, +by adding support for `--help` flags in subcommands and improving help and usage printouts. + +The `--version` option of the `create channel` subcommand has been renamed +to `--channel-version`, with the old name still supported as an alias. +Additionally, the `-h` short flag on many commands is now `-H` to avoid +clashes with the clap-provided short flag for help. + +This release also improves the handling of account sequence mismatch errors, +with a recovery mechanism to automatically retry or drop tx upon such errors. + +The relayer now also supports dynamic versions in channel open handshake (which is needed by Interchain Accounts), and enables full support for IBC v2. + +### BREAKING CHANGES + +- General + - Update MSRV to Rust 1.57 + ([#1660](https://github.com/informalsystems/ibc-rs/issues/1660)) + - Pin tendermint-rs dependencies to =0.23.2 + ([#1665](https://github.com/informalsystems/ibc-rs/pull/1665)) +- [IBC Modules](modules) + - Add the `frozen_height()` method to the `ClientState` trait (includes breaking changes to the Tendermint `ClientState` API). + ([#1618](https://github.com/informalsystems/ibc-rs/issues/1618)) + - Remove `Timestamp` API that depended on the `chrono` crate: + ([#1665](https://github.com/informalsystems/ibc-rs/pull/1665)): + - `Timestamp::from_datetime`; use `From` + - `Timestamp::as_datetime`, superseded by `Timestamp::into_datetime` +- [Relayer Library](relayer) + - Improve spawning of supervisor worker tasks ([#1656](https://github.com/informalsystems/ibc-rs/issues/1656)) + - The `Supervisor` struct is removed. + - Supervisor is now spawned using the `spawn_supervisor` function. +- [Relayer CLI](relayer-cli) + - Update to abscissa framework version 0.6.0-beta.1, adding support for + `--help` flags in subcommands and improving help and usage printouts. + The `--version` option of the `create channel` subcommand has been renamed + to `--channel-version`, with the old name still supported as an alias. + Additionally, the `-h` short flag on many commands is now `-H` to avoid + clashes with the clap-provided short flag for help. + ([#1576](https://github.com/informalsystems/ibc-rs/pull/1576), + [#1743](https://github.com/informalsystems/ibc-rs/pull/1743)) + +### BUG FIXES + +- [IBC Modules](modules) + - Delete packet commitment instead of acknowledgement in acknowledgePacket + [#1573](https://github.com/informalsystems/ibc-rs/issues/1573) + - Set the `counterparty_channel_id` correctly to fix ICS04 [`chanOpenAck` handler verification](https://github.com/informalsystems/ibc-rs/blob/master/modules/src/core/ics04_channel/handler/chan_open_ack.rs) + ([#1649](https://github.com/informalsystems/ibc-rs/issues/1649)) + - Add missing assertion for non-zero trust-level in Tendermint client initialization. + ([#1697](https://github.com/informalsystems/ibc-rs/issues/1697)) + - Fix conversion to Protocol Buffers of `ClientState`'s `frozen_height` field. + ([#1710](https://github.com/informalsystems/ibc-rs/issues/1710)) +- [Relayer Library](relayer) + - Handle expired client errors in workers ([#1543](https://github.com/informalsystems/ibc-rs/issues/1543)) + - Perform `execute_schedule` after handling packet commands in packet worker ([#1715](https://github.com/informalsystems/ibc-rs/issues/1715)) + - Do not spawn detect misbehavior task if it is disabled in config [#1750](https://github.com/informalsystems/ibc-rs/issues/1750) + +### FEATURES + +- General + - Extend CI test suite to include E2E tests using Gaia v6.0.0 [#1550](https://github.com/informalsystems/ibc-rs/issues/1550) + - Added the `extra_wallets` parameter to `gm` to create additional funded wallets. + - Added the possibility of JSON output to `gm` by setting the environment variable `OUTPUT=json`. + - Added support for fee granters through config file + ([#1633](https://github.com/informalsystems/ibc-rs/issues/1633)) +- [IBC Modules](modules) + - Implement proof verification for Tendermint client (ICS07). + ([#1583](https://github.com/informalsystems/ibc-rs/pull/1583)) +- [Relayer Library](relayer) + - Added a recovery mechanism to automatically retry or drop tx upon account + sequence mismatch errors ([#1264](https://github.com/informalsystems/ibc-rs/issues/1264)) + - Support dynamic versions in channel open handshake & enable full support for + ibc-go v2 ([#1410](https://github.com/informalsystems/ibc-rs/issues/1410)) + - Allow custom proof-specs in chain config + ([#1561](https://github.com/informalsystems/ibc-rs/issues/1561)) + +### IMPROVEMENTS + +- General + - Update `CONTRIBUTING.md` for latest version of unclog + ([#1634](https://github.com/informalsystems/ibc-rs/issues/1634)) +- [IBC Modules](modules) + - More conventional ad-hoc conversion methods on `Timestamp` + ([#1665](https://github.com/informalsystems/ibc-rs/pull/1665)): + - `Timestamp::nanoseconds` replaces `Timestamp::as_nanoseconds` + - `Timestamp::into_datetime` substitutes `Timestamp::as_datetime` +- [Relayer CLI](relayer-cli) + - Improve performance of standalone commands by starting the event monitor on-demand + ([#1063](https://github.com/informalsystems/ibc-rs/issues/1063)) + - Increase the default for `max_gas` from `300_000` to `400_000` + ([#1636](https://github.com/informalsystems/ibc-rs/pull/1636)) + +## v0.9.0, the “Zamfir” release +*November 23rd, 2021* + +> This release honors Anca Zamfir, who has lead ibc-rs from its inception and through its first two years of life. +> The whole team is grateful for her dedication and the nurturing environment she created. +> To many more achievements, Anca!! 🥂 + +#### Notice for operators + +This release requires operators to update their Hermes configuration. +The `mode` configuration section now replaces the `strategy` option. + +##### `strategy = 'packets'` + +If Hermes was configured with `strategy = 'packets'`, then the configuration needs to be changed in the following way: + +```diff + [global] +-strategy = 'packets' + log_level = 'trace' +-clear_packets_interval = 100 +-tx_confirmation = true ++ ++[mode] ++ ++[mode.clients] ++enabled = true ++refresh = true ++misbehaviour = true ++ ++[mode.connections] ++enabled = false ++ ++[mode.channels] ++enabled = false ++ ++[mode.packets] ++enabled = true ++clear_interval = 100 ++clear_on_start = true ++filter = false ++tx_confirmation = true +``` + +##### `strategy = 'all'` + +If Hermes was configured to complete connection and channel handshakes as well, ie. with `strategy = 'all'`, +then on top of the changes above, `mode.connections.enabled` and `mode.channels.enabled` must be set to `true`. + +[See the relevant section][config-mode-toml] of the documented `config.toml` file in the repository for more details. + +[config-mode-toml]: https://github.com/informalsystems/ibc-rs/blob/v0.9.0/config.toml#L9-L59 + + +### BUG FIXES + +- [IBC Modules](modules) + - Set the connection counterparty in the ICS 003 [`connOpenAck` handler][conn-open-ack-handler] + ([#1532](https://github.com/informalsystems/ibc-rs/issues/1532)) + +[conn-open-ack-handler]: https://github.com/informalsystems/ibc-rs/blob/master/modules/src/core/ics03_connection/handler/conn_open_ack.rs + +### FEATURES + +- General + - Support for compatibility with gaia Vega upgrade (protos matching ibc-go v1.2.2 and SDK v0.44.3) + ([#1408](https://github.com/informalsystems/ibc-rs/issues/1408)) + - Optimize the WS client to subscribe to IBC events only (instead of all Tx + events) ([#1534](https://github.com/informalsystems/ibc-rs/issues/1534)) +- [Relayer Library](relayer) + - Allow for more granular control of relaying modes. The `mode` configuration section replaces the `strategy` option. + ([#1518](https://github.com/informalsystems/ibc-rs/issues/1518)) + +### IMPROVEMENTS + +- General + - Upgrade IBC-rs TLA+ MBT models to modern Apalache type annotations + ([#1544](https://github.com/informalsystems/ibc-rs/issues/1544)) + - Add `architecture.md` doc that gives a high-level overview of the structure of the codebase + - Add some module-level documentation ([#1556](https://github.com/informalsystems/ibc-rs/pulls/1556)) +- [IBC Modules](modules) + - Derive `PartialEq` and `Eq` on `IbcEvent` and inner types + ([#1546](https://github.com/informalsystems/ibc-rs/issues/1546)) +- [Relayer Library](relayer) + - The relayer will now avoid submitting a tx after the simulation failed + (in all but one special case) to avoid wasting fees unnecessarily + ([#1479](https://github.com/informalsystems/ibc-rs/issues/1479)) +- [Relayer CLI](relayer-cli) + - Output errors on a single line if ANSI output is disabled + ([#1529](https://github.com/informalsystems/ibc-rs/issues/1529)) + - Compute fee amount using big integers to prevent overflow + when using denominations with high decimal places + ([#1555](https://github.com/informalsystems/ibc-rs/issues/1555)) + +## v0.8.0 +*October 29th, 2021* + +This is the final release of version 0.8.0, which now depends on the official releases of the `prost` and `tonic` crates. +In addition to everything that's included in v0.8.0-pre.1, this release updates the minimum supported Rust version to 1.56, +and contains various bug fixes and performance improvements which make the relayer more reliable. + +#### Notice for operators +A new setting was added to the Hermes configuration: `max_block_time`. +This setting specifies the maximum time per block for this chain. +The block time together with the clock drift are added to the source drift to estimate +the maximum clock drift when creating a client on this chain. +For Cosmos-SDK chains a good approximation is `timeout_propose` + `timeout_commit` + +### BREAKING CHANGES + +- Update MSRV to Rust 1.56 and use the 2021 edition + ([#1519](https://github.com/informalsystems/ibc-rs/issues/1519)) + +### BUG FIXES + +- Fix for "new header has a time from the future" chain error which would arise due to clock drift ([#1445](https://github.com/informalsystems/ibc-rs/issues/1445)): + * Added new config param `max_block_time` to prevent the problem for appearing in newly-created clients. + * Added a synchronous waiting in client update logic to allow destination chain to reach a new height + before submitting a client update message. +- Ensure Hermes does not send timeouts for packets that have not expired yet + ([#1504](https://github.com/informalsystems/ibc-rs/issues/1504)) + +### IMPROVEMENTS + +- General + - Update to official releases of `prost` 0.9 and `tonic` 0.6 + ([#1502](https://github.com/informalsystems/ibc-rs/issues/1502)) +- [IBC Modules](modules) + - Support for converting `ibc::events::IbcEvent` into `tendermint::abci::Event` + ([#838](https://github.com/informalsystems/ibc-rs/issues/838)) + - Restructure the layout of the `ibc` crate to match `ibc-go`'s [layout](https://github.com/cosmos/ibc-go#contents) + ([#1436](https://github.com/informalsystems/ibc-rs/issues/1436)) + - Implement `FromStr` to enable string-encoded paths to be converted into Path identifiers + ([#1460](https://github.com/informalsystems/ibc-rs/issues/1460)) +- [Relayer Library](relayer) + - Improve performance of misbehaviour checks triggered by an `UpdateClient` event + ([#1417](https://github.com/informalsystems/ibc-rs/issues/1417)) + +## v0.8.0-pre.1 +*October 22nd, 2021* + +This is a pre-release which depends on in-house forks of various Rust libraries. +As such, it is advised to avoid depending on the `ibc` and `ibc-relayer` crates +at version 0.8.0-pre.1. + +Hermes v0.8.0-pre.1 is considered stable and it is recommended for all +users to update to this version. + +This release notably includes a new [`memo_prefix`][memo] configuration option +for specifying a prefix to be included in the memo of each transaction submitted +by Hermes. + +Moreover, Hermes is now able to handle `SendPacket` events originating from Tendermint +ABCI's `BeginBlock` and `EndBlock` methods ([#1231](https://github.com/informalsystems/ibc-rs/issues/1231)). + +[memo]: https://github.com/informalsystems/ibc-rs/blob/v0.8.0-pre.1/config.toml#L161-L165 + +### BREAKING CHANGES + +- [IBC Modules](modules) + - The `check_header_and_update_state` method of the `ClientDef` + trait (ICS02) has been expanded to facilitate ICS07 + ([#1214](https://github.com/informalsystems/ibc-rs/issues/1214)) + +### FEATURES + +- General + - Add support for the `tx.memo` field + ([#1433](https://github.com/informalsystems/ibc-rs/issues/1433)) +- [IBC Modules](modules) + - Add ICS07 verification functionality by using `tendermint-light-client` + ([#1214](https://github.com/informalsystems/ibc-rs/issues/1214)) +- [Relayer Library](relayer) + - Add a `default_gas` setting to be used for submitting a tx when tx simulation + fails ([#1457](https://github.com/informalsystems/ibc-rs/issues/1457)) + - Update compatibility check for IBC-Go dependency + ([#1464](https://github.com/informalsystems/ibc-rs/issues/1464)) + +### IMPROVEMENTS + +- [Relayer Library](relayer) + - Handle SendPacket events originating from Tendermint ABCI's BeginBlock + and EndBlock methods ([#1231](https://github.com/informalsystems/ibc-rs/issues/1231)) + - Improve error message when `create client` fails and add a health + check for the trusting period being smaller than the unbonding period + ([#1440](https://github.com/informalsystems/ibc-rs/issues/1440)) + ## v0.7.3 +*October 4th, 2021* This minor release most notably includes a fix for a bug introduced in v0.7.0 where Hermes would always use the max gas when submitting transactions to @@ -25,6 +421,7 @@ It also improves the handling of account sequence numbers ([#1392](https://github.com/informalsystems/ibc-rs/issues/1392)) ## v0.7.2 +*September 24th, 2021* This minor release brings substantial performance improvements as well as support for chains using Secp256k1 signatures in consensus votes. @@ -52,6 +449,7 @@ It also bumps the compatibility to Cosmos SDK 0.44. - Improve reliability of health check ([#1382](https://github.com/informalsystems/ibc-rs/issues/1376)) ## v0.7.1 +*September 14th, 2021* This minor release of Hermes notably features support for Ethermint chains and transfer amounts expressed as a 256-bit unsigned integer. This release also fixes a bug where the chain runtime within the relayer would crash when failing to decode a invalid header included in a `ClientUpdate` IBC event. @@ -91,6 +489,7 @@ This release also fixes a bug where the chain runtime within the relayer would c [#1333]: https://github.com/informalsystems/ibc-rs/issues/1333 ## v0.7.0 +*August 24th, 2021* This release of Hermes is the first to be compatible with the development version of Cosmos SDK 0.43. Hermes 0.7.0 also improves the performance and reliability of the relayer, notably by waiting asynchronously for transactions to be confirmed. @@ -151,6 +550,7 @@ Additionnally, Hermes now includes a REST server which exposes the relayer's int [#1297]: https://github.com/informalsystems/ibc-rs/issues/1297 ## v0.6.2 +*August 2nd, 2021* This minor release of Hermes re-enables the `upgrade client`, `upgrade clients`, `tx raw upgrade-clients`, and `tx raw upgrade-chain`, and otherwise @@ -1191,21 +1591,21 @@ Other highlights: [#195]: https://github.com/informalsystems/ibc-rs/pull/195 [ibc]: https://github.com/informalsystems/ibc-rs/tree/master/modules [#198]: https://github.com/informalsystems/ibc-rs/issues/198 -[ibc/ics02]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/ics02_client +[ibc/ics02]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/core/ics02_client [#185]: https://github.com/informalsystems/ibc-rs/issues/185 -[ibc/ics03]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/ics03_connection +[ibc/ics03]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/core/ics03_connection [#193]: https://github.com/informalsystems/ibc-rs/issues/193 -[ibc/ics04]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/ics04_channel +[ibc/ics04]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/core/ics04_channel [#192]: https://github.com/informalsystems/ibc-rs/issues/192 [ibc-relayer-cli]: https://github.com/informalsystems/ibc-rs/tree/master/relayer-cli -[architecture/FSM-1]: https://github.com/informalsystems/ibc-rs/blob/master/docs/architecture/fsm-async-connection.md +[architecture/FSM-1]: https://github.com/informalsystems/ibc-rs/blob/v0.1.0/docs/architecture/fsm-async-connection.md [#122]: https://github.com/informalsystems/ibc-rs/issues/122 [architecture/ADR-003]: https://github.com/informalsystems/ibc-rs/blob/master/docs/architecture/adr-003-handler-implementation.md [#119]: https://github.com/informalsystems/ibc-rs/issues/119 [#194]: https://github.com/informalsystems/ibc-rs/issues/194 -[ibc/ics24]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/ics24_host +[ibc/ics24]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/core/ics24_host [#168]: https://github.com/informalsystems/ibc-rs/issues/168 -[ibc/ics07]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/ics07_tendermint +[ibc/ics07]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/clients/ics07_tendermint ## v0.0.2 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c090a5bb2..0d60d1160 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,7 +5,7 @@ of ibc-rs is to provide a high quality, formally verified implementation of the IBC protocol and relayer. All work on the code base should be motivated by a Github -Issue. Search is a good place to start when looking for places to contribute. +Issue. Search is a good place to start when looking for places to contribute. If you would like to work on an issue which already exists, please indicate so by leaving a comment. If you'd like to work on something else, open an Issue to start the discussion. @@ -17,6 +17,7 @@ repository: - [Forking](#forking) - fork the repo to make pull requests - [Changelog](#changelog) - changes must be recorded in the changelog - [Pull Requests](#pull-requests) - what makes a good pull request +- [Releases](#releases) - how to release new version of the crates ## Decision Making @@ -40,7 +41,7 @@ the form of an [Architectural Decision Record overall strategy to ensure the code base maintains coherence in the larger context. If you are not comfortable with writing an ADR, you can open a less-formal issue and the maintainers will help you -turn it into an ADR. +turn it into an ADR. When the problem as well as proposed solution are well understood, changes should start with a [draft @@ -63,7 +64,7 @@ Each stage of the process is aimed at creating feedback cycles which align contr ## Forking -If you do not have write access to the repository, your contribution should be +If you do not have write access to the repository, your contribution should be made through a fork on Github. Fork the repository, contribute to your fork, and make a pull request back upstream. @@ -87,31 +88,43 @@ To pull in updates from the origin repo, run Every non-trivial PR must update the [CHANGELOG](CHANGELOG.md). This is accomplished indirectly by adding entries to the `.changelog` folder in -[unclog](https://github.com/informalsystems/unclog) format. `CHANGELOG.md` will -be built by whomever is responsible for performing a release just prior to -release - this is to avoid changelog conflicts prior to releases. For example: +[`unclog`](https://github.com/informalsystems/unclog) format using the `unclog` CLI tool. +`CHANGELOG.md` will be built by whomever is responsible for performing a release just +prior to release - this is to avoid changelog conflicts prior to releases. + +### Install `unclog` ```bash -# Add a .changelog entry for the `ibc` crate (in the `modules` directory) -# under the `IMPROVEMENTS` section in CHANGELOG.md. -unclog add -c ibc improvements 1234-some-issue +cargo install unclog +``` -# Add a .changelog entry for the `ibc-relayer-cli` crate (in the `relayer-cli` -# directory) under the `FEATURES` section in CHANGELOG.md. -unclog add -c ibc-relayer-cli features 1235-some-other-issue +### Examples -# Preview unreleased changes -unclog build -u +Add a .changelog entry to signal that a bug was fixed, without mentioning any +component. + +```bash +$ unclog add -i update-unclog-instructions -s bug -n 1634 -m "Update CONTRIBUTING.md for latest version of unclog" --editor vim +``` + +Add a .changelog entry for the `ibc-relayer-cli` crate (the component in the `relayer-cli` +directory) under the `FEATURES` section in CHANGELOG.md. -# Build the new CHANGELOG.md from entries in ./.changelog/ -unclog build > CHANGELOG.md +```bash +$ unclog add -c ibc-relayer-cli -s features --id a-new-feature --issue-no 1235 -m "msg about this new-feature" --editor vim +``` + +### Preview unreleased changes + +```bash +unclog build -u ``` The Changelog is *not* a record of what Pull Requests were merged; the commit history already shows that. The Changelog is a notice to users -about how their expectations of the software should be modified. +about how their expectations of the software should be modified. It is part of the UX of a release and is a *critical* user facing integration point. -The Changelog must be clean, inviting, and readable, with concise, meaningful entries. +The Changelog must be clean, inviting, and readable, with concise, meaningful entries. Entries must be semantically meaningful to users. If a change takes multiple Pull Requests to complete, it should likely have only a single entry in the Changelog describing the net effect to the user. Instead of linking PRs directly, we @@ -119,13 +132,11 @@ instead prefer to log issues, which tend to be higher-level, hence more relevant When writing Changelog entries, ensure they are targeting users of the software, not fellow developers. Developers have much more context and care about more -things than users do. Changelogs are for users. +things than users do. Changelogs are for users. -Changelog structure is modeled after -[Tendermint -Core](https://github.com/tendermint/tendermint/blob/master/CHANGELOG.md) -and -[Hashicorp Consul](http://github.com/hashicorp/consul/tree/master/CHANGELOG.md). +Changelog structure is modeled after +[Tendermint Core](https://github.com/tendermint/tendermint/blob/master/CHANGELOG.md) +and [Hashicorp Consul](http://github.com/hashicorp/consul/tree/master/CHANGELOG.md). See those changelogs for examples. We currently split changes for a given release between these four sections: Breaking @@ -140,7 +151,7 @@ specific release number in Changelog. Changelog entries should be formatted as follows: ``` -- [pkg] Some description about the change ([#xxx]) (optional @contributor) +- [pkg] Some description about the change ([#xxx](https://github.com/informalsystems/ibc-rs/issues/xxx)) (optional @contributor) ``` Here, `pkg` is the part of the code that changed (typically a @@ -166,8 +177,8 @@ exposed. ## Pull Requests -The master development branch is `master`. -Branch names should be prefixed with the author, eg. `name/feature-x`. +The master development branch is `master`. +Branch names should be prefixed with the author, eg. `name/feature-x`. Pull requests are made against `master` and are squash merged into master. @@ -176,9 +187,59 @@ PRs must: - make reference to an issue outlining the context. - update any relevant documentation and include tests. -- update [CHANGELOG.md](CHANGELOG.md) with a description of the change in the __Unreleased__ section. +- add a corresponding entry in the `.changelog` directory using `unclog`, + see the section above for more details. Pull requests should aim to be small and self contained to facilitate quick review and merging. Larger change sets should be broken up across multiple PRs. Commits should be concise but informative, and moderately clean. Commits will be squashed into a single commit for the PR with all the commit messages. + +## Releases + +Our release process is as follows: + +1. Update the [changelog](#changelog) to reflect and summarize all changes in + the release. This involves: + 1. Running `unclog build -u` and copy pasting the output at the top + of the `CHANGELOG.md` file, making sure to update the header with + the new version. + 1. Running `unclog release vX.Y.Z` to create a summary of all of the changes + in this release. + 3. Committing the updated `CHANGELOG.md` file and `.changelog` directory to the repo. +2. Push this to a branch `release/vX.Y.Z` according to the version number of + the anticipated release (e.g. `release/v0.17.0`) and open a **draft PR**. +3. Bump all relevant versions in the codebase to the new version and push these + changes to the release PR. This includes: + 1. All `Cargo.toml` files (making sure dependencies' versions are updated + too). + 2. All crates' `lib.rs` files documentation references' `html_root_url` + parameters must point to the new version. + 3. Every reference to Hermes version in the [guide](./guide). + + **Important:** The `ibc-proto` crate version must only be bumped if it has + changed since the last release. All other crates are bumped together. + +4. Run `cargo doc --all-features --open` locally to double-check that all the + documentation compiles and seems up-to-date and coherent. Fix any potential + issues here and push them to the release PR. +5. Mark the PR as **Ready for Review** and incorporate feedback on the release. +6. Once approved, merge the PR. +7. Pull `master` and run the [`release.sh`](./scripts/release.sh) script. + If any problem arises, submit a new PR, get it merged to `master` and try again. + The reason for not releasing straight from the release branch, and therefore losing the + ability to fix publishing problems as they arise, is that we would like the embedded + metadata of the published crates, namely the Git commit at which the release was done, + to match the Git commit on the `master` branch which will be tagged. + [See this article][crates.io-security] for a more in-depth explanation. + **Note:** This step requires the appropriate privileges to push crates to [crates.io]. +8. Once all crates have been successfully released, create a signed tag and push it to + GitHub: `git tag -s -a vX.Y.Z`. In the tag message, write the version and the link + to the corresponding section of the changelog. +9. Once the tag is pushed, wait for the CI bot to create a GitHub release, and update + the release description to `[📖 CHANGELOG](https://github.com/informalsystems/ibc-rs/blob/master/CHANGELOG.md#vXYZ)`. +10. Wait an hour or so, and check that the CI job has uploaded the Hermes binaries to the release. +11. All done! 🎉 + +[crates.io]: https://crates.io +[crates.io-security]: https://codeandbitters.com/published-crate-analysis/ diff --git a/Cargo.lock b/Cargo.lock index b64e3ba51..50741fdf2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,39 +14,36 @@ dependencies = [ [[package]] name = "abscissa_core" -version = "0.5.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a07677093120a02583717b6dd1ef81d8de1e8d01bd226c83f0f9bdf3e56bb3a" +checksum = "6750843603bf31a83accd3c8177f9dbf53a7d64275688fc7371e0a4d9f8628b5" dependencies = [ "abscissa_derive", + "arc-swap", "backtrace", "canonical-path", - "chrono", - "color-backtrace", - "generational-arena", - "gumdrop 0.7.0", - "libc", + "clap", + "color-eyre", + "fs-err", "once_cell", "regex", - "secrecy 0.6.0", - "semver 0.9.0", + "secrecy", + "semver", "serde", - "signal-hook 0.1.17", "termcolor", "toml", "tracing", "tracing-log", - "tracing-subscriber 0.1.6", + "tracing-subscriber 0.3.9", "wait-timeout", ] [[package]] name = "abscissa_derive" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f5722bc48763cb9d81d8427ca05b6aa2842f6632cf8e4c0a29eef9baececcc" +checksum = "1a3473aa652e90865a06b723102aaa4a54a7d9f2092dbf4582497a61d0537d3f" dependencies = [ - "darling 0.10.2", "ident_case", "proc-macro2", "quote", @@ -116,15 +113,6 @@ dependencies = [ "alloc-no-stdlib", ] -[[package]] -name = "ansi_term" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" -dependencies = [ - "winapi", -] - [[package]] name = "ansi_term" version = "0.12.1" @@ -136,9 +124,15 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.53" +version = "1.0.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a99269dff3bc004caa411f38845c20303f1e393ca2bd6581576fa3a7f59577d" + +[[package]] +name = "arc-swap" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94a45b455c14666b85fc40a019e8ab9eb75e3a124e05494f5397122bc9eb06e0" +checksum = "c5d78ce20460b82d3fa150275ed9d55e21064fc7951177baacf86a145c4a4b1f" [[package]] name = "arrayref" @@ -253,6 +247,12 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base16ct" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" + [[package]] name = "base58" version = "0.2.0" @@ -271,6 +271,12 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +[[package]] +name = "base64ct" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "874f8444adcb4952a8bc51305c8be95c8ec8237bb0d2e78d2e039f771f8828a0" + [[package]] name = "bech32" version = "0.8.1" @@ -563,8 +569,6 @@ dependencies = [ "libc", "num-integer", "num-traits", - "serde", - "time 0.1.43", "winapi", ] @@ -595,7 +599,7 @@ dependencies = [ "indexmap", "lazy_static", "os_str_bytes", - "strsim 0.10.0", + "strsim", "termcolor", "textwrap", ] @@ -622,22 +626,11 @@ dependencies = [ "syn", ] -[[package]] -name = "color-backtrace" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65d13f1078cc63c791d0deba0dd43db37c9ec02b311f10bed10b577016f3a957" -dependencies = [ - "atty", - "backtrace", - "termcolor", -] - [[package]] name = "color-eyre" -version = "0.5.11" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f1885697ee8a177096d42f158922251a41973117f6d8a234cee94b9509157b7" +checksum = "9d6ec7641ff3474b7593009c809db602c414cd97c7d47a78ed004162b74ff96c" dependencies = [ "backtrace", "color-spantrace", @@ -650,9 +643,9 @@ dependencies = [ [[package]] name = "color-spantrace" -version = "0.1.6" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6eee477a4a8a72f4addd4de416eb56d54bc307b284d6601bafdee1f4ea462d1" +checksum = "1ba75b3d9449ecdccb27ecbc479fdc0b87fa2dd43d2f8298f9bf0e59aacc8dce" dependencies = [ "once_cell", "owo-colors", @@ -660,6 +653,12 @@ dependencies = [ "tracing-error", ] +[[package]] +name = "const-oid" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" + [[package]] name = "constant_time_eq" version = "0.1.5" @@ -790,9 +789,9 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-bigint" -version = "0.2.11" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83bd3bb4314701c568e340cd8cf78c975aa0ca79e03d3f6d1677d5b0c9c0c03" +checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" dependencies = [ "generic-array 0.14.5", "rand_core 0.6.3", @@ -865,38 +864,14 @@ dependencies = [ "zeroize", ] -[[package]] -name = "darling" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" -dependencies = [ - "darling_core 0.10.2", - "darling_macro 0.10.2", -] - [[package]] name = "darling" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0d720b8683f8dd83c65155f0530560cba68cd2bf395f6513a483caee57ff7f4" dependencies = [ - "darling_core 0.13.1", - "darling_macro 0.13.1", -] - -[[package]] -name = "darling_core" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim 0.9.3", - "syn", + "darling_core", + "darling_macro", ] [[package]] @@ -909,18 +884,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim 0.10.0", - "syn", -] - -[[package]] -name = "darling_macro" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" -dependencies = [ - "darling_core 0.10.2", - "quote", + "strsim", "syn", ] @@ -930,7 +894,7 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72c41b3b7352feb3211a0d743dc5700a4e3b60f51bd2b368892d1e0f9a95f44b" dependencies = [ - "darling_core 0.13.1", + "darling_core", "quote", "syn", ] @@ -957,9 +921,12 @@ dependencies = [ [[package]] name = "der" -version = "0.4.5" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79b71cca7d95d7681a4b3b9cdf63c8dbc3730d0584c2c74e31416d64a90493f4" +checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" +dependencies = [ + "const-oid", +] [[package]] name = "derive_more" @@ -1078,13 +1045,13 @@ checksum = "ee2626afccd7561a06cf1367e2950c4718ea04565e20fb5029b6c7d8ad09abcf" [[package]] name = "ecdsa" -version = "0.12.4" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43ee23aa5b4f68c7a092b5c3beb25f50c406adc75e2363634f242f28ab255372" +checksum = "d0d69ae62e0ce582d56380743515fefaf1a8c70cec685d9677636d7e30ae9dc9" dependencies = [ "der", "elliptic-curve", - "hmac 0.11.0", + "rfc6979", "signature", ] @@ -1119,15 +1086,18 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "elliptic-curve" -version = "0.10.6" +version = "0.11.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beca177dcb8eb540133e7680baff45e7cc4d93bf22002676cec549f82343721b" +checksum = "25b477563c2bfed38a3b7a60964c49e058b2510ad3f12ba3483fd8f62c2306d6" dependencies = [ + "base16ct", "crypto-bigint", + "der", "ff", "generic-array 0.14.5", "group", "rand_core 0.6.3", + "sec1", "subtle", "zeroize", ] @@ -1191,9 +1161,9 @@ dependencies = [ [[package]] name = "ff" -version = "0.10.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f" +checksum = "b2958d04124b9f27f175eaeb9a9f383d026098aa837eadd8ba22c11f13a05b9e" dependencies = [ "rand_core 0.6.3", "subtle", @@ -1241,6 +1211,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c606d892c9de11507fa0dcffc116434f94e105d0bbdc4e405b61519464c49d7b" dependencies = [ + "anyhow", "eyre", "paste", ] @@ -1251,21 +1222,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "form_urlencoded" version = "1.0.1" @@ -1276,15 +1232,6 @@ dependencies = [ "percent-encoding 2.1.0", ] -[[package]] -name = "fraction" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aba3510011eee8825018be07f08d9643421de007eaf62a3bde58d89b058abfa7" -dependencies = [ - "num", -] - [[package]] name = "frame-metadata" version = "14.2.0" @@ -1312,7 +1259,7 @@ dependencies = [ "paste", "scale-info", "serde", - "smallvec 1.8.0", + "smallvec", "sp-arithmetic", "sp-core", "sp-inherents", @@ -1375,6 +1322,12 @@ dependencies = [ "sp-version", ] +[[package]] +name = "fs-err" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd79fa345a495d3ae89fb7165fec01c0e72f41821d642dda363a1e97975652e" + [[package]] name = "funty" version = "1.1.0" @@ -1484,15 +1437,6 @@ dependencies = [ "slab", ] -[[package]] -name = "generational-arena" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d3b771574f62d0548cee0ad9057857e9fc25d7a3335f140c84f6acd0bf601" -dependencies = [ - "cfg-if 0.1.10", -] - [[package]] name = "generic-array" version = "0.12.4" @@ -1532,8 +1476,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c" dependencies = [ "cfg-if 1.0.0", + "js-sys", "libc", "wasi 0.10.2+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -1544,42 +1490,22 @@ checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" [[package]] name = "group" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c363a5301b8f153d80747126a04b3c82073b9fe3130571a9d170cacdeaf7912" +checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89" dependencies = [ "ff", "rand_core 0.6.3", "subtle", ] -[[package]] -name = "gumdrop" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee50908bc1beeac1f2902e0b4e0cd0d844e716f5ebdc6f0cfc1163fe5e10bcde" -dependencies = [ - "gumdrop_derive 0.7.0", -] - [[package]] name = "gumdrop" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46571f5d540478cf70d2a42dd0d6d8e9f4b9cc7531544b93311e657b86568a0b" dependencies = [ - "gumdrop_derive 0.8.0", -] - -[[package]] -name = "gumdrop_derive" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90454ce4de40b7ca6a8968b5ef367bdab48413962588d0d2b1638d60090c35d7" -dependencies = [ - "proc-macro2", - "quote", - "syn", + "gumdrop_derive", ] [[package]] @@ -1847,11 +1773,12 @@ dependencies = [ "headers", "http", "hyper", - "hyper-tls", - "native-tls", + "hyper-rustls 0.22.1", + "rustls-native-certs 0.5.0", "tokio", - "tokio-native-tls", + "tokio-rustls 0.22.0", "tower-service", + "webpki 0.21.4", ] [[package]] @@ -1881,7 +1808,7 @@ dependencies = [ "http", "hyper", "log", - "rustls 0.20.3", + "rustls 0.20.4", "rustls-native-certs 0.6.1", "tokio", "tokio-rustls 0.23.2", @@ -1900,28 +1827,15 @@ dependencies = [ "tokio-io-timeout", ] -[[package]] -name = "hyper-tls" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes", - "hyper", - "native-tls", - "tokio", - "tokio-native-tls", -] - [[package]] name = "ibc" -version = "0.7.3" +version = "0.11.1" dependencies = [ "beefy-light-client", "beefy-merkle-tree", "blake2-rfc", "bytes", - "chrono", + "derive_more", "env_logger 0.9.0", "flex-error", "frame-support", @@ -1930,17 +1844,16 @@ dependencies = [ "hex-literal", "ibc-proto", "ics23", - "informalsystems-prost", - "informalsystems-prost-types", "modelator", - "octopusxt", + "num-traits", "parity-scale-codec", + "prost", + "prost-types", "safe-regex", "serde", "serde_derive", "serde_json", "sha2 0.10.2", - "sha2 0.9.9", "sp-core", "sp-runtime", "sp-std 4.0.0-dev", @@ -1948,132 +1861,171 @@ dependencies = [ "subtle-encoding", "subxt", "tendermint", + "tendermint-light-client-verifier", "tendermint-proto", "tendermint-rpc", "tendermint-testgen", - "test-env-log", "test-log", + "time", "tokio", "tracing", "tracing-subscriber 0.3.9", ] +[[package]] +name = "ibc-integration-test" +version = "0.11.1" +dependencies = [ + "color-eyre", + "crossbeam-channel 0.5.2", + "env_logger 0.9.0", + "eyre", + "flex-error", + "hex", + "ibc", + "ibc-proto", + "ibc-relayer", + "ibc-relayer-cli", + "itertools", + "prost", + "prost-types", + "rand 0.8.5", + "semver", + "serde", + "serde_json", + "serde_yaml", + "sha2 0.10.2", + "subtle-encoding", + "tendermint", + "tendermint-rpc", + "tokio", + "toml", + "tracing", + "tracing-subscriber 0.3.9", +] + [[package]] name = "ibc-proto" -version = "0.11.0" +version = "0.15.0" dependencies = [ "bytes", - "informalsystems-prost", - "informalsystems-prost-types", - "informalsystems-tonic", + "prost", + "prost-types", + "serde", "tendermint-proto", + "tonic", ] [[package]] name = "ibc-relayer" -version = "0.7.3" +version = "0.11.1" dependencies = [ "anyhow", "async-stream", - "async-trait", "bech32", "beefy-light-client", "bitcoin", "bytes", - "chrono", "crossbeam-channel 0.5.2", "dirs-next", "env_logger 0.9.0", "flex-error", - "fraction", "futures 0.3.21", "hdpath", "hex", "http", + "humantime", "humantime-serde", "ibc", "ibc-proto", "ibc-telemetry", - "informalsystems-prost", - "informalsystems-prost-types", - "informalsystems-tonic", "itertools", "jsonrpsee", "k256", + "nanoid", + "num-bigint 0.4.3", + "num-rational 0.4.0", "octopusxt", "pallet-mmr-rpc", "parity-scale-codec", + "prost", + "prost-types", "retry", "ripemd160", - "semver 1.0.5", + "semver", "serde", - "serde_cbor", "serde_derive", "serde_json", "serial_test", - "sha2 0.9.9", + "sha2 0.10.2", "signature", "sp-core", "subtle-encoding", "subxt", "tendermint", "tendermint-light-client", + "tendermint-light-client-verifier", "tendermint-proto", "tendermint-rpc", "tendermint-testgen", - "test-env-log", + "test-log", "thiserror", "tiny-bip39", "tiny-keccak", "tokio", "toml", + "tonic", "tracing", - "tracing-subscriber 0.2.25", + "tracing-subscriber 0.3.9", "uint", ] [[package]] name = "ibc-relayer-cli" -version = "0.7.3" +version = "0.11.1" dependencies = [ "abscissa_core", "atty", + "clap", + "clap_complete", "color-eyre", "crossbeam-channel 0.5.2", "dirs-next", "eyre", "flex-error", "futures 0.3.21", - "gumdrop 0.7.0", "hex", + "humantime", "ibc", "ibc-proto", "ibc-relayer", "ibc-relayer-rest", "ibc-telemetry", - "informalsystems-prost", - "informalsystems-prost-types", "itertools", "once_cell", + "oneline-eyre", + "prost", + "prost-types", "regex", "serde", "serde_derive", "serde_json", - "signal-hook 0.3.13", + "signal-hook", "subtle-encoding", "tendermint", "tendermint-light-client", + "tendermint-light-client-verifier", "tendermint-proto", "tendermint-rpc", "tokio", "toml", "tracing", - "tracing-subscriber 0.2.25", + "tracing-subscriber 0.3.9", ] [[package]] name = "ibc-relayer-rest" -version = "0.7.3" +version = "0.11.1" dependencies = [ "crossbeam-channel 0.5.2", "ibc", @@ -2088,7 +2040,7 @@ dependencies = [ [[package]] name = "ibc-telemetry" -version = "0.7.3" +version = "0.11.1" dependencies = [ "crossbeam-channel 0.5.2", "ibc", @@ -2101,14 +2053,14 @@ dependencies = [ [[package]] name = "ics23" -version = "0.6.5" -source = "git+https://github.com/informalsystems/ics23.git?rev=4461b673#4461b67382341af6bc6fab9c991ccc5d49a6e83e" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce15e4758c46a0453bdf4b3b1dfcce70c43f79d1943c2ee0635b77eb2e7aa233" dependencies = [ "anyhow", "bytes", "hex", - "informalsystems-prost", - "informalsystems-prost-types", + "prost", "ripemd160", "sha2 0.9.9", "sha3", @@ -2188,69 +2140,6 @@ dependencies = [ "hashbrown 0.11.2", ] -[[package]] -name = "informalsystems-prost" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5620e41d3653c27671bee3e07822407365cae5d97f4a391a1c87cb2a4caf647b" -dependencies = [ - "bytes", - "informalsystems-prost-derive", -] - -[[package]] -name = "informalsystems-prost-derive" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c6af6594ef5bc7f879ba098055e084bf3562077b6dc83fcc96b579cdd319eba" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "informalsystems-prost-types" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41b094d80f1836c54e192146a58ef1ef1803b1a50a055ab6303ec757e034431a" -dependencies = [ - "bytes", - "informalsystems-prost", -] - -[[package]] -name = "informalsystems-tonic" -version = "0.5.2" -source = "git+https://github.com/informalsystems/tonic.git?rev=99edfe23#99edfe23ae3be257af6d970ff898b1d5ca884a45" -dependencies = [ - "async-stream", - "async-trait", - "base64 0.13.0", - "bytes", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-timeout", - "informalsystems-prost", - "informalsystems-prost-derive", - "percent-encoding 2.1.0", - "pin-project", - "tokio", - "tokio-stream", - "tokio-util 0.6.9", - "tower", - "tower-layer", - "tower-service", - "tracing", - "tracing-futures", -] - [[package]] name = "input_buffer" version = "0.4.0" @@ -2562,13 +2451,14 @@ dependencies = [ [[package]] name = "k256" -version = "0.9.6" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "903ae2481bcdfdb7b68e0a9baa4b7c9aff600b9ae2e8e5bb5833b8c91ab851ea" +checksum = "1cc5937366afd3b38071f400d1ce5bd8b1d40b5083cc14e6f8dbcc4032a7f5bb" dependencies = [ "cfg-if 1.0.0", "ecdsa", "elliptic-curve", + "sec1", "sha2 0.9.9", ] @@ -2585,7 +2475,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45a3f58dc069ec0e205a27f5b45920722a46faed802a0541538241af6228f512" dependencies = [ "parity-util-mem", - "smallvec 1.8.0", + "smallvec", ] [[package]] @@ -2596,9 +2486,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.118" +version = "0.2.119" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06e509672465a0504304aa87f9f176f2b2b716ed8fb105ebe5c02dc6dce96a94" +checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4" [[package]] name = "libsecp256k1" @@ -2633,7 +2523,6 @@ dependencies = [ "libsecp256k1-gen-genmult 0.3.0", "rand 0.8.5", "serde", - "sha2 0.9.9", ] [[package]] @@ -2694,6 +2583,12 @@ dependencies = [ "libsecp256k1-core 0.3.0", ] +[[package]] +name = "linked-hash-map" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" + [[package]] name = "lock_api" version = "0.4.6" @@ -2893,21 +2788,12 @@ dependencies = [ ] [[package]] -name = "native-tls" -version = "0.2.8" +name = "nanoid" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d" +checksum = "3ffa00dec017b5b1a8b7cf5e2c008bfda1aa7e0697ac1508b491fdf2622fb4d8" dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", + "rand 0.8.5", ] [[package]] @@ -2936,19 +2822,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "num" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36" -dependencies = [ - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - [[package]] name = "num-bigint" version = "0.2.6" @@ -2961,13 +2834,15 @@ dependencies = [ ] [[package]] -name = "num-complex" -version = "0.2.4" +name = "num-bigint" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" dependencies = [ "autocfg", + "num-integer", "num-traits", + "serde", ] [[package]] @@ -2992,26 +2867,28 @@ dependencies = [ ] [[package]] -name = "num-iter" -version = "0.1.42" +name = "num-rational" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" +checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" dependencies = [ "autocfg", + "num-bigint 0.2.6", "num-integer", "num-traits", ] [[package]] name = "num-rational" -version = "0.2.4" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" +checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a" dependencies = [ "autocfg", - "num-bigint", + "num-bigint 0.4.3", "num-integer", "num-traits", + "serde", ] [[package]] @@ -3054,7 +2931,7 @@ dependencies = [ [[package]] name = "octopusxt" version = "0.1.0" -source = "git+https://github.com/octopus-network/octopusxt.git?branch=main#a8355c353282ae6ca6e152b60089b4a455fe7d5a" +source = "git+https://github.com/octopus-network/octopusxt.git?branch=feature/dep-ibc-rs#2e1919e8be29fddda50107c8fb376985685ad5d6" dependencies = [ "beefy-light-client", "beefy-merkle-tree", @@ -3063,11 +2940,11 @@ dependencies = [ "hex", "ibc", "ibc-proto", - "informalsystems-prost-types", "jsonrpsee", "libsecp256k1 0.7.0", "pallet-mmr-rpc", "parity-scale-codec", + "prost-types", "serde", "sp-core", "sp-keyring", @@ -3085,30 +2962,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" [[package]] -name = "opaque-debug" -version = "0.2.3" +name = "oneline-eyre" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" +checksum = "862f17a1e689c0ce8ca158ea48e776c5101c5d14fdfbed3e01c15f89604c3097" +dependencies = [ + "eyre", +] [[package]] name = "opaque-debug" -version = "0.3.0" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" [[package]] -name = "openssl" -version = "0.10.38" +name = "opaque-debug" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95" -dependencies = [ - "bitflags", - "cfg-if 1.0.0", - "foreign-types", - "libc", - "once_cell", - "openssl-sys", -] +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl-probe" @@ -3116,30 +2988,19 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" -[[package]] -name = "openssl-sys" -version = "0.9.72" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb" -dependencies = [ - "autocfg", - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "opentelemetry" -version = "0.15.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff27b33e30432e7b9854936693ca103d8591b0501f7ae9f633de48cda3bf2a67" +checksum = "6105e89802af13fdf48c49d7646d3b533a70e536d818aae7e78ba0433d01acb8" dependencies = [ "async-trait", "crossbeam-channel 0.5.2", "dashmap", "fnv", - "futures 0.3.21", + "futures-channel", + "futures-executor", + "futures-util", "js-sys", "lazy_static", "percent-encoding 2.1.0", @@ -3150,9 +3011,9 @@ dependencies = [ [[package]] name = "opentelemetry-prometheus" -version = "0.8.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e06ddda4790151e8b494f9bb32720fce23722d7f395f81383b9b2934bb6356a0" +checksum = "9328977e479cebe12ce0d3fcecdaea4721d234895a9440c5b5dfd113f0594ac6" dependencies = [ "opentelemetry", "prometheus", @@ -3168,20 +3029,11 @@ dependencies = [ "memchr", ] -[[package]] -name = "owning_ref" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce" -dependencies = [ - "stable_deref_trait", -] - [[package]] name = "owo-colors" -version = "1.3.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2386b4ebe91c2f7f51082d4cefa145d030e33a1842a96b12e4885cc3c01f7a55" +checksum = "20448fd678ec04e6ea15bbe0476874af65e98a01515d667aa49f1434dc44ebf4" [[package]] name = "pallet-mmr-primitives" @@ -3305,7 +3157,7 @@ dependencies = [ "instant", "libc", "redox_syscall", - "smallvec 1.8.0", + "smallvec", "winapi", ] @@ -3318,7 +3170,7 @@ dependencies = [ "cfg-if 1.0.0", "libc", "redox_syscall", - "smallvec 1.8.0", + "smallvec", "windows-sys", ] @@ -3418,10 +3270,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] -name = "pkg-config" -version = "0.3.24" +name = "pkcs8" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" +checksum = "7cabda3fb821068a9a4fab19a683eac3af12edf0f34b94a8be53c4972b8149d0" +dependencies = [ + "der", + "spki", + "zeroize", +] [[package]] name = "ppv-lite86" @@ -3496,9 +3353,9 @@ dependencies = [ [[package]] name = "prometheus" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5986aa8d62380092d2f50f8b1cdba9cb9b6731ffd4b25b51fd126b6c3e05b99c" +checksum = "b7f64969ffd5dd8f39bd57a68ac53c163a095ed9d0fb707146da1b27025a3504" dependencies = [ "cfg-if 1.0.0", "fnv", @@ -3509,6 +3366,39 @@ dependencies = [ "thiserror", ] +[[package]] +name = "prost" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "prost-types" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534b7a0e836e3c482d2693070f982e39e7611da9695d4d1f5a4b186b51faef0a" +dependencies = [ + "bytes", + "prost", +] + [[package]] name = "protobuf" version = "2.27.1" @@ -3722,6 +3612,17 @@ version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac95c60a949a63fd2822f4964939662d8f2c16c4fa0624fd954bc6e703b9a3f6" +[[package]] +name = "rfc6979" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" +dependencies = [ + "crypto-bigint", + "hmac 0.11.0", + "zeroize", +] + [[package]] name = "ring" version = "0.16.20" @@ -3768,7 +3669,7 @@ dependencies = [ "serde_json", "sha1", "threadpool", - "time 0.3.7", + "time", "tiny_http", "url 2.2.2", ] @@ -3797,7 +3698,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.5", + "semver", ] [[package]] @@ -3815,9 +3716,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.20.3" +version = "0.20.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b323592e3164322f5b193dc4302e4e36cd8d37158a712d664efae1a5c2791700" +checksum = "4fbfeb8d0ddb84706bc597a5574ab8912817c52a397f819e5b614e2265206921" dependencies = [ "log", "ring", @@ -4006,6 +3907,19 @@ dependencies = [ "untrusted", ] +[[package]] +name = "sec1" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1" +dependencies = [ + "der", + "generic-array 0.14.5", + "pkcs8", + "subtle", + "zeroize", +] + [[package]] name = "secp256k1" version = "0.20.3" @@ -4025,22 +3939,13 @@ dependencies = [ "cc", ] -[[package]] -name = "secrecy" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9182278ed645df3477a9c27bfee0621c621aa16f6972635f7f795dae3d81070f" -dependencies = [ - "serde", - "zeroize", -] - [[package]] name = "secrecy" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" dependencies = [ + "serde", "zeroize", ] @@ -4069,26 +3974,13 @@ dependencies = [ [[package]] name = "semver" -version = "0.9.0" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +checksum = "0486718e92ec9a68fbed73bb5ef687d71103b142595b406835649bebd33f72c7" dependencies = [ - "semver-parser", "serde", ] -[[package]] -name = "semver" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0486718e92ec9a68fbed73bb5ef687d71103b142595b406835649bebd33f72c7" - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - [[package]] name = "serde" version = "1.0.136" @@ -4150,6 +4042,18 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_yaml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a521f2940385c165a24ee286aa8599633d162077a54bdcae2a6fd5a7bfa7a0" +dependencies = [ + "indexmap", + "ryu", + "serde", + "yaml-rust", +] + [[package]] name = "serial_test" version = "0.5.1" @@ -4268,16 +4172,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "signal-hook" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e31d442c16f047a671b5a71e2161d6e68814012b7f5379d269ebd915fac2729" -dependencies = [ - "libc", - "signal-hook-registry", -] - [[package]] name = "signal-hook" version = "0.3.13" @@ -4299,9 +4193,9 @@ dependencies = [ [[package]] name = "signature" -version = "1.3.2" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2807892cfa58e081aa1f1111391c7a0649d4fa127a4ffbe34bcbfb35a1171a4" +checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" dependencies = [ "digest 0.9.0", "rand_core 0.6.3", @@ -4319,15 +4213,6 @@ version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" -[[package]] -name = "smallvec" -version = "0.6.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97fcaeba89edba30f044a10c6a3cc39df9c3f17d7cd829dd1446cab35f890e0" -dependencies = [ - "maybe-uninit", -] - [[package]] name = "smallvec" version = "1.8.0" @@ -4481,7 +4366,7 @@ dependencies = [ "regex", "scale-info", "schnorrkel", - "secrecy 0.8.0", + "secrecy", "serde", "sha2 0.9.9", "sp-debug-derive", @@ -4675,7 +4560,7 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.11.2", "rand 0.7.3", - "smallvec 1.8.0", + "smallvec", "sp-core", "sp-externalities", "sp-panic-handler", @@ -4782,11 +4667,21 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spki" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d01ac02a6ccf3e07db148d2be087da624fea0221a16152ed01f0496a6b0a27" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "ss58-registry" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8cb4b9ce18beb6cb16ecad62d936245cef5212ddc8e094d7417a75e8d0e85f5" +checksum = "2f9799e6d412271cb2414597581128b03f3285f260ea49f5363d07df6a332b3e" dependencies = [ "Inflector", "proc-macro2", @@ -4796,24 +4691,12 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - [[package]] name = "static_assertions" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "strsim" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" - [[package]] name = "strsim" version = "0.10.0" @@ -4905,7 +4788,7 @@ version = "0.2.0" source = "git+https://github.com/octopus-network/substrate-subxt.git?branch=octopus-v0.9.12#950ce7d90a983c02c8d16167a3bf73d2641e5fc0" dependencies = [ "async-trait", - "darling 0.13.1", + "darling", "frame-metadata", "heck 0.3.3", "parity-scale-codec", @@ -4923,7 +4806,7 @@ version = "0.1.0" source = "git+https://github.com/octopus-network/substrate-subxt.git?branch=octopus-v0.9.12#950ce7d90a983c02c8d16167a3bf73d2641e5fc0" dependencies = [ "async-trait", - "darling 0.13.1", + "darling", "frame-metadata", "heck 0.3.3", "parity-scale-codec", @@ -4981,21 +4864,20 @@ dependencies = [ [[package]] name = "tendermint" -version = "0.22.0" -source = "git+https://github.com/informalsystems/tendermint-rs?rev=4f6ef3d6#4f6ef3d67c80fda6df2b9108c4b4a527e110783a" +version = "0.23.5" +source = "git+https://github.com/informalsystems/tendermint-rs?branch=v0.23.x#235480171081fed74de7b3d3c19911304df29831" dependencies = [ "async-trait", "bytes", - "chrono", "ed25519", "ed25519-dalek", "flex-error", "futures 0.3.21", - "informalsystems-prost", - "informalsystems-prost-types", "k256", "num-traits", "once_cell", + "prost", + "prost-types", "ripemd160", "serde", "serde_bytes", @@ -5006,13 +4888,14 @@ dependencies = [ "subtle", "subtle-encoding", "tendermint-proto", + "time", "zeroize", ] [[package]] name = "tendermint-config" -version = "0.22.0" -source = "git+https://github.com/informalsystems/tendermint-rs?rev=4f6ef3d6#4f6ef3d67c80fda6df2b9108c4b4a527e110783a" +version = "0.23.5" +source = "git+https://github.com/informalsystems/tendermint-rs?branch=v0.23.x#235480171081fed74de7b3d3c19911304df29831" dependencies = [ "flex-error", "serde", @@ -5024,10 +4907,9 @@ dependencies = [ [[package]] name = "tendermint-light-client" -version = "0.22.0" -source = "git+https://github.com/informalsystems/tendermint-rs?rev=4f6ef3d6#4f6ef3d67c80fda6df2b9108c4b4a527e110783a" +version = "0.23.5" +source = "git+https://github.com/informalsystems/tendermint-rs?branch=v0.23.x#235480171081fed74de7b3d3c19911304df29831" dependencies = [ - "chrono", "contracts", "crossbeam-channel 0.4.4", "derive_more", @@ -5038,39 +4920,52 @@ dependencies = [ "serde_derive", "static_assertions", "tendermint", + "tendermint-light-client-verifier", "tendermint-rpc", + "time", "tokio", ] +[[package]] +name = "tendermint-light-client-verifier" +version = "0.23.5" +source = "git+https://github.com/informalsystems/tendermint-rs?branch=v0.23.x#235480171081fed74de7b3d3c19911304df29831" +dependencies = [ + "derive_more", + "flex-error", + "serde", + "tendermint", + "time", +] + [[package]] name = "tendermint-proto" -version = "0.22.0" -source = "git+https://github.com/informalsystems/tendermint-rs?rev=4f6ef3d6#4f6ef3d67c80fda6df2b9108c4b4a527e110783a" +version = "0.23.5" +source = "git+https://github.com/informalsystems/tendermint-rs?branch=v0.23.x#235480171081fed74de7b3d3c19911304df29831" dependencies = [ "bytes", - "chrono", "flex-error", - "informalsystems-prost", - "informalsystems-prost-types", "num-derive", "num-traits", + "prost", + "prost-types", "serde", "serde_bytes", "subtle-encoding", + "time", ] [[package]] name = "tendermint-rpc" -version = "0.22.0" -source = "git+https://github.com/informalsystems/tendermint-rs?rev=4f6ef3d6#4f6ef3d67c80fda6df2b9108c4b4a527e110783a" +version = "0.23.5" +source = "git+https://github.com/informalsystems/tendermint-rs?branch=v0.23.x#235480171081fed74de7b3d3c19911304df29831" dependencies = [ "async-trait", "async-tungstenite", "bytes", - "chrono", "flex-error", "futures 0.3.21", - "getrandom 0.1.16", + "getrandom 0.2.4", "http", "hyper", "hyper-proxy", @@ -5085,6 +4980,7 @@ dependencies = [ "tendermint-config", "tendermint-proto", "thiserror", + "time", "tokio", "tracing", "url 2.2.2", @@ -5094,17 +4990,17 @@ dependencies = [ [[package]] name = "tendermint-testgen" -version = "0.22.0" -source = "git+https://github.com/informalsystems/tendermint-rs?rev=4f6ef3d6#4f6ef3d67c80fda6df2b9108c4b4a527e110783a" +version = "0.23.5" +source = "git+https://github.com/informalsystems/tendermint-rs?branch=v0.23.x#235480171081fed74de7b3d3c19911304df29831" dependencies = [ - "chrono", "ed25519-dalek", - "gumdrop 0.8.0", + "gumdrop", "serde", "serde_json", "simple-error", "tempfile", "tendermint", + "time", ] [[package]] @@ -5116,17 +5012,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "test-env-log" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877189d680101869f65ef94168105d6c188b3a143c13a2d42cf8a09c4c704f8a" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "test-log" version = "0.2.8" @@ -5182,16 +5067,6 @@ dependencies = [ "num_cpus", ] -[[package]] -name = "time" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "time" version = "0.3.7" @@ -5200,8 +5075,15 @@ checksum = "004cbc98f30fa233c61a38bc77e96a9106e65c88f2d3bef182ae952027e5753d" dependencies = [ "libc", "num_threads", + "time-macros", ] +[[package]] +name = "time-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25eb0ca3468fc0acc11828786797f6ef9aa1555e4a211a60d64cc8e4d1be47d6" + [[package]] name = "tiny-bip39" version = "0.8.2" @@ -5299,16 +5181,6 @@ dependencies = [ "syn", ] -[[package]] -name = "tokio-native-tls" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" -dependencies = [ - "native-tls", - "tokio", -] - [[package]] name = "tokio-rustls" version = "0.22.0" @@ -5326,7 +5198,7 @@ version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a27d5f2b839802bd8267fa19b0530f5a08b9c08cd417976be2a65d130fe1c11b" dependencies = [ - "rustls 0.20.3", + "rustls 0.20.4", "tokio", "webpki 0.22.0", ] @@ -5380,6 +5252,39 @@ dependencies = [ "serde", ] +[[package]] +name = "tonic" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff08f4649d10a70ffa3522ca559031285d8e421d727ac85c60825761818f5d0a" +dependencies = [ + "async-stream", + "async-trait", + "base64 0.13.0", + "bytes", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-timeout", + "percent-encoding 2.1.0", + "pin-project", + "prost", + "prost-derive", + "rustls-native-certs 0.5.0", + "tokio", + "tokio-rustls 0.22.0", + "tokio-stream", + "tokio-util 0.6.9", + "tower", + "tower-layer", + "tower-service", + "tracing", + "tracing-futures", +] + [[package]] name = "tower" version = "0.4.12" @@ -5448,12 +5353,12 @@ dependencies = [ [[package]] name = "tracing-error" -version = "0.1.2" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4d7c0b83d4a500748fa5879461652b361edf5c9d51ede2a2ac03875ca185e24" +checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" dependencies = [ "tracing", - "tracing-subscriber 0.2.25", + "tracing-subscriber 0.3.9", ] [[package]] @@ -5487,30 +5392,13 @@ dependencies = [ "tracing-core", ] -[[package]] -name = "tracing-subscriber" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "192ca16595cdd0661ce319e8eede9c975f227cdaabc4faaefdc256f43d852e45" -dependencies = [ - "ansi_term 0.11.0", - "chrono", - "lazy_static", - "matchers 0.0.1", - "owning_ref", - "regex", - "smallvec 0.6.14", - "tracing-core", - "tracing-log", -] - [[package]] name = "tracing-subscriber" version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" dependencies = [ - "ansi_term 0.12.1", + "ansi_term", "chrono", "lazy_static", "matchers 0.0.1", @@ -5518,7 +5406,7 @@ dependencies = [ "serde", "serde_json", "sharded-slab", - "smallvec 1.8.0", + "smallvec", "thread_local", "tracing", "tracing-core", @@ -5532,14 +5420,14 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e0ab7bdc962035a87fba73f3acca9b8a8d0034c2e6f60b84aeaaddddc155dce" dependencies = [ - "ansi_term 0.12.1", + "ansi_term", "lazy_static", "matchers 0.1.0", "regex", "serde", "serde_json", "sharded-slab", - "smallvec 1.8.0", + "smallvec", "thread_local", "tracing", "tracing-core", @@ -5557,7 +5445,7 @@ dependencies = [ "hashbrown 0.11.2", "log", "rustc-hex", - "smallvec 1.8.0", + "smallvec", ] [[package]] @@ -5685,7 +5573,7 @@ dependencies = [ "flate2", "log", "once_cell", - "rustls 0.20.3", + "rustls 0.20.4", "url 2.2.2", "webpki 0.22.0", "webpki-roots 0.22.2", @@ -5732,12 +5620,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "version_check" version = "0.9.4" @@ -5849,7 +5731,7 @@ dependencies = [ "downcast-rs", "libc", "memory_units", - "num-rational", + "num-rational 0.2.4", "num-traits", "parity-wasm", "wasmi-validation", @@ -5992,20 +5874,29 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "zeroize" -version = "1.4.3" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d68d9dcec5f9b43a30d38c49f91dfedfaac384cb8f085faca366c26207dd1619" +checksum = "7c88870063c39ee00ec285a2f8d6a966e5b6fb2becc4e8dac77ed0d370ed6006" dependencies = [ "zeroize_derive", ] [[package]] name = "zeroize_derive" -version = "1.3.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81e8f13fef10b63c06356d65d416b070798ddabcadc10d3ece0c5be9b3c7eddb" +checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index bd46bf8e9..5eb08217f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,7 @@ [workspace] +resolver = "2" + members = [ "modules", "relayer", @@ -7,6 +9,7 @@ members = [ "relayer-rest", "telemetry", "proto", + "tools/integration-test", ] exclude = [ @@ -14,12 +17,6 @@ exclude = [ "proto-compiler" ] -# [patch.crates-io] -# tendermint = { git = "https://github.com/informalsystems/tendermint-rs", branch = "master" } -# tendermint-rpc = { git = "https://github.com/informalsystems/tendermint-rs", branch = "master" } -# tendermint-proto = { git = "https://github.com/informalsystems/tendermint-rs", branch = "master" } -# tendermint-light-client = { git = "https://github.com/informalsystems/tendermint-rs", branch = "master" } -# tendermint-testgen = { git = "https://github.com/informalsystems/tendermint-rs", branch = "master" } [patch."https://github.com/paritytech/substrate"] frame-support = { git = "https://github.com/octopus-network/substrate", branch = "polkadot-v0.9.12" } frame-system = { git = "https://github.com/octopus-network/substrate", branch = "polkadot-v0.9.12" } @@ -175,24 +172,14 @@ substrate-build-script-utils = { git = "https://github.com/octopus-network/subst beefy-merkle-tree = { git = "https://github.com/octopus-network/substrate", branch = "polkadot-v0.9.12" } -## for tendermint -#tendermint = { git = "https://github.com/informalsystems/tendermint-rs", branch = "soares/activate-no-std" } -#tendermint-rpc = { git = "https://github.com/informalsystems/tendermint-rs", branch = "soares/activate-no-std" } -#tendermint-proto = { git = "https://github.com/informalsystems/tendermint-rs", branch = "soares/activate-no-std" } -#tendermint-light-client = { git = "https://github.com/informalsystems/tendermint-rs", branch = "soares/activate-no-std" } -#tendermint-testgen = { git = "https://github.com/informalsystems/tendermint-rs", branch = "soares/activate-no-std" } -# ics23 = { git = "https://github.com/informalsystems/ics23.git", branch = "master" } -# tonic = { package = "informalsystems-tonic", git = "https://github.com/informalsystems/tonic.git", branch = "thane/informal-0.5.2" } -tendermint = { git = "https://github.com/informalsystems/tendermint-rs", rev = "4f6ef3d6" } -tendermint-rpc = { git = "https://github.com/informalsystems/tendermint-rs", rev = "4f6ef3d6" } -tendermint-proto = { git = "https://github.com/informalsystems/tendermint-rs", rev = "4f6ef3d6" } -tendermint-light-client = { git = "https://github.com/informalsystems/tendermint-rs", rev = "4f6ef3d6" } -tendermint-testgen = { git = "https://github.com/informalsystems/tendermint-rs", rev = "4f6ef3d6" } -ics23 = { git = "https://github.com/informalsystems/ics23.git", rev = "4461b673" } -tonic = { package = "informalsystems-tonic", git = "https://github.com/informalsystems/tonic.git", rev = "99edfe23" } +tendermint = { git = "https://github.com/informalsystems/tendermint-rs", branch = "v0.23.x" } +tendermint-rpc = { git = "https://github.com/informalsystems/tendermint-rs", branch = "v0.23.x" } +tendermint-proto = { git = "https://github.com/informalsystems/tendermint-rs", branch = "v0.23.x" } +tendermint-light-client = { git = "https://github.com/informalsystems/tendermint-rs", branch = "v0.23.x" } +tendermint-light-client-verifier = { git = "https://github.com/informalsystems/tendermint-rs", branch = "v0.23.x" } +tendermint-testgen = { git = "https://github.com/informalsystems/tendermint-rs", branch = "v0.23.x" } [patch."https://github.com/octopus-network/ibc-rs"] ibc = { path = "./modules" } ibc-proto = { path = "./proto" } - diff --git a/README.md b/README.md index 4aa352763..85e47668b 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,12 @@ # ibc-rs +[![Cosmos ecosystem][cosmos-shield]][cosmos-link] + [![Build Status][build-image]][build-link] [![End to End testing][e2e-image]][e2e-link] [![Apache 2.0 Licensed][license-image]][license-link] ![Rust Stable][rustc-image] -![Rust 1.53+][rustc-version] +![Rust 1.58+][rustc-version] Rust implementation of the Inter-Blockchain Communication (IBC) protocol. @@ -39,8 +41,7 @@ Includes [TLA+ specifications](docs/spec). ## Requirements -Developed with the latest stable version of Rust: `1.53.0`. -(May work with older versions.) +The crates in this project require the latest stable version of Rust: `1.58.0`. ## Hermes Guide @@ -112,4 +113,6 @@ Unless required by applicable law or agreed to in writing, software distributed [license-image]: https://img.shields.io/badge/license-Apache_2.0-blue.svg [license-link]: https://github.com/informalsystems/ibc-rs/blob/master/LICENSE [rustc-image]: https://img.shields.io/badge/rustc-stable-blue.svg -[rustc-version]: https://img.shields.io/badge/rustc-1.53+-blue.svg +[rustc-version]: https://img.shields.io/badge/rustc-1.58+-blue.svg +[cosmos-shield]: https://img.shields.io/static/v1?label=&labelColor=1B1E36&color=1B1E36&message=cosmos%20ecosystem&style=for-the-badge&logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDI0LjMuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCAyNTAwIDI1MDAiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDI1MDAgMjUwMDsiIHhtbDpzcGFjZT0icHJlc2VydmUiPgo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgoJLnN0MHtmaWxsOiM2RjczOTA7fQoJLnN0MXtmaWxsOiNCN0I5Qzg7fQo8L3N0eWxlPgo8cGF0aCBjbGFzcz0ic3QwIiBkPSJNMTI1Mi42LDE1OS41Yy0xMzQuOSwwLTI0NC4zLDQ4OS40LTI0NC4zLDEwOTMuMXMxMDkuNCwxMDkzLjEsMjQ0LjMsMTA5My4xczI0NC4zLTQ4OS40LDI0NC4zLTEwOTMuMQoJUzEzODcuNSwxNTkuNSwxMjUyLjYsMTU5LjV6IE0xMjY5LjQsMjI4NGMtMTUuNCwyMC42LTMwLjksNS4xLTMwLjksNS4xYy02Mi4xLTcyLTkzLjItMjA1LjgtOTMuMi0yMDUuOAoJYy0xMDguNy0zNDkuOC04Mi44LTExMDAuOC04Mi44LTExMDAuOGM1MS4xLTU5Ni4yLDE0NC03MzcuMSwxNzUuNi03NjguNGM2LjctNi42LDE3LjEtNy40LDI0LjctMmM0NS45LDMyLjUsODQuNCwxNjguNSw4NC40LDE2OC41CgljMTEzLjYsNDIxLjgsMTAzLjMsODE3LjksMTAzLjMsODE3LjljMTAuMywzNDQuNy01Ni45LDczMC41LTU2LjksNzMwLjVDMTM0MS45LDIyMjIuMiwxMjY5LjQsMjI4NCwxMjY5LjQsMjI4NHoiLz4KPHBhdGggY2xhc3M9InN0MCIgZD0iTTIyMDAuNyw3MDguNmMtNjcuMi0xMTcuMS01NDYuMSwzMS42LTEwNzAsMzMycy04OTMuNSw2MzguOS04MjYuMyw3NTUuOXM1NDYuMS0zMS42LDEwNzAtMzMyCglTMjI2Ny44LDgyNS42LDIyMDAuNyw3MDguNkwyMjAwLjcsNzA4LjZ6IE0zNjYuNCwxNzgwLjRjLTI1LjctMy4yLTE5LjktMjQuNC0xOS45LTI0LjRjMzEuNi04OS43LDEzMi0xODMuMiwxMzItMTgzLjIKCWMyNDkuNC0yNjguNCw5MTMuOC02MTkuNyw5MTMuOC02MTkuN2M1NDIuNS0yNTIuNCw3MTEuMS0yNDEuOCw3NTMuOC0yMzBjOS4xLDIuNSwxNSwxMS4yLDE0LDIwLjZjLTUuMSw1Ni0xMDQuMiwxNTctMTA0LjIsMTU3CgljLTMwOS4xLDMwOC42LTY1Ny44LDQ5Ni44LTY1Ny44LDQ5Ni44Yy0yOTMuOCwxODAuNS02NjEuOSwzMTQuMS02NjEuOSwzMTQuMUM0NTYsMTgxMi42LDM2Ni40LDE3ODAuNCwzNjYuNCwxNzgwLjRMMzY2LjQsMTc4MC40CglMMzY2LjQsMTc4MC40eiIvPgo8cGF0aCBjbGFzcz0ic3QwIiBkPSJNMjE5OC40LDE4MDAuNGM2Ny43LTExNi44LTMwMC45LTQ1Ni44LTgyMy03NTkuNVMzNzQuNCw1ODcuOCwzMDYuOCw3MDQuN3MzMDAuOSw0NTYuOCw4MjMuMyw3NTkuNQoJUzIxMzAuNywxOTE3LjQsMjE5OC40LDE4MDAuNHogTTM1MS42LDc0OS44Yy0xMC0yMy43LDExLjEtMjkuNCwxMS4xLTI5LjRjOTMuNS0xNy42LDIyNC43LDIyLjYsMjI0LjcsMjIuNgoJYzM1Ny4yLDgxLjMsOTk0LDQ4MC4yLDk5NCw0ODAuMmM0OTAuMywzNDMuMSw1NjUuNSw0OTQuMiw1NzYuOCw1MzcuMWMyLjQsOS4xLTIuMiwxOC42LTEwLjcsMjIuNGMtNTEuMSwyMy40LTE4OC4xLTExLjUtMTg4LjEtMTEuNQoJYy00MjIuMS0xMTMuMi03NTkuNi0zMjAuNS03NTkuNi0zMjAuNWMtMzAzLjMtMTYzLjYtNjAzLjItNDE1LjMtNjAzLjItNDE1LjNjLTIyNy45LTE5MS45LTI0NS0yODUuNC0yNDUtMjg1LjRMMzUxLjYsNzQ5Ljh6Ii8+CjxjaXJjbGUgY2xhc3M9InN0MSIgY3g9IjEyNTAiIGN5PSIxMjUwIiByPSIxMjguNiIvPgo8ZWxsaXBzZSBjbGFzcz0ic3QxIiBjeD0iMTc3Ny4zIiBjeT0iNzU2LjIiIHJ4PSI3NC42IiByeT0iNzcuMiIvPgo8ZWxsaXBzZSBjbGFzcz0ic3QxIiBjeD0iNTUzIiBjeT0iMTAxOC41IiByeD0iNzQuNiIgcnk9Ijc3LjIiLz4KPGVsbGlwc2UgY2xhc3M9InN0MSIgY3g9IjEwOTguMiIgY3k9IjE5NjUiIHJ4PSI3NC42IiByeT0iNzcuMiIvPgo8L3N2Zz4K +[cosmos-link]: https://cosmos.network diff --git a/ci/README.md b/ci/README.md index 6141e171e..93834314a 100644 --- a/ci/README.md +++ b/ci/README.md @@ -211,3 +211,13 @@ And in the relayer service: args: RELEASE: v4.0.0 ``` + +6. Update the CI workflow + +There are currently two CI workflows, for running the E2E tests against two versions of gaiad: + - current release: `.github\workflows\e2e-gaia-current-release.yaml`, and + - future release: `.github\workflows\e2e-gaia-future-release.yaml`. + +Depending on which of the two setups you have upgraded at the prior steps, change the `name` key in the corresponding workflow file to match with the version of the upgraded gaia used, e.g.: + +`name: End to End testing (Gaia - v6.0.0)` diff --git a/ci/build-ibc-chains.sh b/ci/build-ibc-chains.sh index d24470b71..71aedf4b7 100755 --- a/ci/build-ibc-chains.sh +++ b/ci/build-ibc-chains.sh @@ -8,7 +8,12 @@ set -eou pipefail ## After updating the gaia version below, double-check the following (see readme.md also): ## - the new version made it to docker hub, and is available for download, e.g. `docker pull informaldev/ibc-1:v4.0.0` ## - the image versions and the relayer release in `docker-compose.yml` are consistent with the new version -GAIA_BRANCH="v5.0.5" # Requires a version with the `--keyring-backend` option. v2.1 and above. + +# For building current gaia use this +# GAIA_BRANCH="v5.0.8" # Requires a version with the `--keyring-backend` option. v2.1 and above. + +# For future gaia use this +GAIA_BRANCH="v6.0.0" # Requires a version with the `--keyring-backend` option. v2.1 and above. # Check if gaiad is installed and if the versions match if ! [ -x "$(command -v gaiad)" ]; then @@ -16,7 +21,7 @@ if ! [ -x "$(command -v gaiad)" ]; then exit 1 fi -CURRENT_GAIA="$(gaiad version)" +CURRENT_GAIA="$(gaiad version 2>&1)" echo "Current Gaia Version: $CURRENT_GAIA" if [ "$GAIA_BRANCH" != "$CURRENT_GAIA" ]; then diff --git a/ci/chains/gaia/v5.0.8/ibc-0/config/addrbook.json b/ci/chains/gaia/v5.0.8/ibc-0/config/addrbook.json new file mode 100644 index 000000000..2c14bbdc9 --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-0/config/addrbook.json @@ -0,0 +1,4 @@ +{ + "key": "82c133df9d6d66a97fe64ae9", + "addrs": [] +} \ No newline at end of file diff --git a/ci/chains/gaia/v5.0.8/ibc-0/config/app.toml b/ci/chains/gaia/v5.0.8/ibc-0/config/app.toml new file mode 100644 index 000000000..54de73e39 --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-0/config/app.toml @@ -0,0 +1,152 @@ +# This is a TOML config file. +# For more information, see https://github.com/toml-lang/toml + +############################################################################### +### Base Configuration ### +############################################################################### + +# The minimum gas prices a validator is willing to accept for processing a +# transaction. A transaction's fees must meet the minimum of any denomination +# specified in this config (e.g. 0.25token1;0.0001token2). +minimum-gas-prices = "" + +# default: the last 100 states are kept in addition to every 500th state; pruning at 10 block intervals +# nothing: all historic states will be saved, nothing will be deleted (i.e. archiving node) +# everything: all saved states will be deleted, storing only the current state; pruning at 10 block intervals +# custom: allow pruning options to be manually specified through 'pruning-keep-recent', 'pruning-keep-every', and 'pruning-interval' +pruning = "default" + +# These are applied if and only if the pruning strategy is custom. +pruning-keep-recent = "0" +pruning-keep-every = "0" +pruning-interval = "0" + +# HaltHeight contains a non-zero block height at which a node will gracefully +# halt and shutdown that can be used to assist upgrades and testing. +# +# Note: Commitment of state will be attempted on the corresponding block. +halt-height = 0 + +# HaltTime contains a non-zero minimum block time (in Unix seconds) at which +# a node will gracefully halt and shutdown that can be used to assist upgrades +# and testing. +# +# Note: Commitment of state will be attempted on the corresponding block. +halt-time = 0 + +# MinRetainBlocks defines the minimum block height offset from the current +# block being committed, such that all blocks past this offset are pruned +# from Tendermint. It is used as part of the process of determining the +# ResponseCommit.RetainHeight value during ABCI Commit. A value of 0 indicates +# that no blocks should be pruned. +# +# This configuration value is only responsible for pruning Tendermint blocks. +# It has no bearing on application state pruning which is determined by the +# "pruning-*" configurations. +# +# Note: Tendermint block pruning is dependant on this parameter in conunction +# with the unbonding (safety threshold) period, state pruning and state sync +# snapshot parameters to determine the correct minimum value of +# ResponseCommit.RetainHeight. +min-retain-blocks = 0 + +# InterBlockCache enables inter-block caching. +inter-block-cache = true + +# IndexEvents defines the set of events in the form {eventType}.{attributeKey}, +# which informs Tendermint what to index. If empty, all events will be indexed. +# +# Example: +# ["message.sender", "message.recipient"] +index-events = [] + +############################################################################### +### Telemetry Configuration ### +############################################################################### + +[telemetry] + +# Prefixed with keys to separate services. +service-name = "" + +# Enabled enables the application telemetry functionality. When enabled, +# an in-memory sink is also enabled by default. Operators may also enabled +# other sinks such as Prometheus. +enabled = false + +# Enable prefixing gauge values with hostname. +enable-hostname = false + +# Enable adding hostname to labels. +enable-hostname-label = false + +# Enable adding service to labels. +enable-service-label = false + +# PrometheusRetentionTime, when positive, enables a Prometheus metrics sink. +prometheus-retention-time = 0 + +# GlobalLabels defines a global set of name/value label tuples applied to all +# metrics emitted using the wrapper functions defined in telemetry package. +# +# Example: +# [["chain_id", "cosmoshub-1"]] +global-labels = [ +] + +############################################################################### +### API Configuration ### +############################################################################### + +[api] + +# Enable defines if the API server should be enabled. +enable = false + +# Swagger defines if swagger documentation should automatically be registered. +swagger = false + +# Address defines the API server to listen on. +address = "tcp://0.0.0.0:1317" + +# MaxOpenConnections defines the number of maximum open connections. +max-open-connections = 1000 + +# RPCReadTimeout defines the Tendermint RPC read timeout (in seconds). +rpc-read-timeout = 10 + +# RPCWriteTimeout defines the Tendermint RPC write timeout (in seconds). +rpc-write-timeout = 0 + +# RPCMaxBodyBytes defines the Tendermint maximum response body (in bytes). +rpc-max-body-bytes = 1000000 + +# EnableUnsafeCORS defines if CORS should be enabled (unsafe - use it at your own risk). +enabled-unsafe-cors = false + +############################################################################### +### gRPC Configuration ### +############################################################################### + +[grpc] + +# Enable defines if the gRPC server should be enabled. +enable = true + +# Address defines the gRPC server address to bind to. +address = "0.0.0.0:9090" + +############################################################################### +### State Sync Configuration ### +############################################################################### + +# State sync snapshots allow other nodes to rapidly join the network without replaying historical +# blocks, instead downloading and applying a snapshot of the application state at a given height. +[state-sync] + +# snapshot-interval specifies the block interval at which local state sync snapshots are +# taken (0 to disable). Must be a multiple of pruning-keep-every. +snapshot-interval = 0 + +# snapshot-keep-recent specifies the number of recent snapshots to keep and serve (0 to keep all). +snapshot-keep-recent = 2 diff --git a/ci/chains/gaia/v5.0.8/ibc-0/config/client.toml b/ci/chains/gaia/v5.0.8/ibc-0/config/client.toml new file mode 100644 index 000000000..222695a3f --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-0/config/client.toml @@ -0,0 +1,17 @@ +# This is a TOML config file. +# For more information, see https://github.com/toml-lang/toml + +############################################################################### +### Client Configuration ### +############################################################################### + +# The network chain ID +chain-id = "" +# The keyring's backend, where the keys are stored (os|file|kwallet|pass|test|memory) +keyring-backend = "os" +# CLI output format (text|json) +output = "text" +# : to Tendermint RPC interface for this chain +node = "tcp://localhost:26657" +# Transaction broadcasting mode (sync|async|block) +broadcast-mode = "sync" diff --git a/ci/chains/gaia/v5.0.8/ibc-0/config/config.toml b/ci/chains/gaia/v5.0.8/ibc-0/config/config.toml new file mode 100644 index 000000000..eb6f4b295 --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-0/config/config.toml @@ -0,0 +1,401 @@ +# This is a TOML config file. +# For more information, see https://github.com/toml-lang/toml + +# NOTE: Any path below can be absolute (e.g. "/var/myawesomeapp/data") or +# relative to the home directory (e.g. "data"). The home directory is +# "$HOME/.tendermint" by default, but could be changed via $TMHOME env variable +# or --home cmd flag. + +####################################################################### +### Main Base Config Options ### +####################################################################### + +# TCP or UNIX socket address of the ABCI application, +# or the name of an ABCI application compiled in with the Tendermint binary +proxy_app = "tcp://127.0.0.1:26658" + +# A custom human readable name for this node +moniker = "ibc-0" + +# If this node is many blocks behind the tip of the chain, FastSync +# allows them to catchup quickly by downloading blocks in parallel +# and verifying their commits +fast_sync = true + +# Database backend: goleveldb | cleveldb | boltdb | rocksdb | badgerdb +# * goleveldb (github.com/syndtr/goleveldb - most popular implementation) +# - pure go +# - stable +# * cleveldb (uses levigo wrapper) +# - fast +# - requires gcc +# - use cleveldb build tag (go build -tags cleveldb) +# * boltdb (uses etcd's fork of bolt - github.com/etcd-io/bbolt) +# - EXPERIMENTAL +# - may be faster is some use-cases (random reads - indexer) +# - use boltdb build tag (go build -tags boltdb) +# * rocksdb (uses github.com/tecbot/gorocksdb) +# - EXPERIMENTAL +# - requires gcc +# - use rocksdb build tag (go build -tags rocksdb) +# * badgerdb (uses github.com/dgraph-io/badger) +# - EXPERIMENTAL +# - use badgerdb build tag (go build -tags badgerdb) +db_backend = "goleveldb" + +# Database directory +db_dir = "data" + +# Output level for logging, including package level options +log_level = "info" + +# Output format: 'plain' (colored text) or 'json' +log_format = "plain" + +##### additional base config options ##### + +# Path to the JSON file containing the initial validator set and other meta data +genesis_file = "config/genesis.json" + +# Path to the JSON file containing the private key to use as a validator in the consensus protocol +priv_validator_key_file = "config/priv_validator_key.json" + +# Path to the JSON file containing the last sign state of a validator +priv_validator_state_file = "data/priv_validator_state.json" + +# TCP or UNIX socket address for Tendermint to listen on for +# connections from an external PrivValidator process +priv_validator_laddr = "" + +# Path to the JSON file containing the private key to use for node authentication in the p2p protocol +node_key_file = "config/node_key.json" + +# Mechanism to connect to the ABCI application: socket | grpc +abci = "socket" + +# If true, query the ABCI app on connecting to a new peer +# so the app can decide if we should keep the connection or not +filter_peers = false + + +####################################################################### +### Advanced Configuration Options ### +####################################################################### + +####################################################### +### RPC Server Configuration Options ### +####################################################### +[rpc] + +# TCP or UNIX socket address for the RPC server to listen on +laddr = "tcp://0.0.0.0:26657" + +# A list of origins a cross-domain request can be executed from +# Default value '[]' disables cors support +# Use '["*"]' to allow any origin +cors_allowed_origins = [] + +# A list of methods the client is allowed to use with cross-domain requests +cors_allowed_methods = ["HEAD", "GET", "POST", ] + +# A list of non simple headers the client is allowed to use with cross-domain requests +cors_allowed_headers = ["Origin", "Accept", "Content-Type", "X-Requested-With", "X-Server-Time", ] + +# TCP or UNIX socket address for the gRPC server to listen on +# NOTE: This server only supports /broadcast_tx_commit +grpc_laddr = "" + +# Maximum number of simultaneous connections. +# Does not include RPC (HTTP&WebSocket) connections. See max_open_connections +# If you want to accept a larger number than the default, make sure +# you increase your OS limits. +# 0 - unlimited. +# Should be < {ulimit -Sn} - {MaxNumInboundPeers} - {MaxNumOutboundPeers} - {N of wal, db and other open files} +# 1024 - 40 - 10 - 50 = 924 = ~900 +grpc_max_open_connections = 900 + +# Activate unsafe RPC commands like /dial_seeds and /unsafe_flush_mempool +unsafe = false + +# Maximum number of simultaneous connections (including WebSocket). +# Does not include gRPC connections. See grpc_max_open_connections +# If you want to accept a larger number than the default, make sure +# you increase your OS limits. +# 0 - unlimited. +# Should be < {ulimit -Sn} - {MaxNumInboundPeers} - {MaxNumOutboundPeers} - {N of wal, db and other open files} +# 1024 - 40 - 10 - 50 = 924 = ~900 +max_open_connections = 900 + +# Maximum number of unique clientIDs that can /subscribe +# If you're using /broadcast_tx_commit, set to the estimated maximum number +# of broadcast_tx_commit calls per block. +max_subscription_clients = 100 + +# Maximum number of unique queries a given client can /subscribe to +# If you're using GRPC (or Local RPC client) and /broadcast_tx_commit, set to +# the estimated # maximum number of broadcast_tx_commit calls per block. +max_subscriptions_per_client = 5 + +# How long to wait for a tx to be committed during /broadcast_tx_commit. +# WARNING: Using a value larger than 10s will result in increasing the +# global HTTP write timeout, which applies to all connections and endpoints. +# See https://github.com/tendermint/tendermint/issues/3435 +timeout_broadcast_tx_commit = "10s" + +# Maximum size of request body, in bytes +max_body_bytes = 1000000 + +# Maximum size of request header, in bytes +max_header_bytes = 1048576 + +# The path to a file containing certificate that is used to create the HTTPS server. +# Might be either absolute path or path related to Tendermint's config directory. +# If the certificate is signed by a certificate authority, +# the certFile should be the concatenation of the server's certificate, any intermediates, +# and the CA's certificate. +# NOTE: both tls_cert_file and tls_key_file must be present for Tendermint to create HTTPS server. +# Otherwise, HTTP server is run. +tls_cert_file = "" + +# The path to a file containing matching private key that is used to create the HTTPS server. +# Might be either absolute path or path related to Tendermint's config directory. +# NOTE: both tls-cert-file and tls-key-file must be present for Tendermint to create HTTPS server. +# Otherwise, HTTP server is run. +tls_key_file = "" + +# pprof listen address (https://golang.org/pkg/net/http/pprof) +pprof_laddr = "localhost:6060" + +####################################################### +### P2P Configuration Options ### +####################################################### +[p2p] + +# Address to listen for incoming connections +laddr = "tcp://0.0.0.0:26656" + +# Address to advertise to peers for them to dial +# If empty, will use the same port as the laddr, +# and will introspect on the listener or use UPnP +# to figure out the address. ip and port are required +# example: 159.89.10.97:26656 +external_address = "" + +# Comma separated list of seed nodes to connect to +seeds = "" + +# Comma separated list of nodes to keep persistent connections to +persistent_peers = "" + +# UPNP port forwarding +upnp = false + +# Path to address book +addr_book_file = "config/addrbook.json" + +# Set true for strict address routability rules +# Set false for private or local networks +addr_book_strict = true + +# Maximum number of inbound peers +max_num_inbound_peers = 40 + +# Maximum number of outbound peers to connect to, excluding persistent peers +max_num_outbound_peers = 10 + +# List of node IDs, to which a connection will be (re)established ignoring any existing limits +unconditional_peer_ids = "" + +# Maximum pause when redialing a persistent peer (if zero, exponential backoff is used) +persistent_peers_max_dial_period = "0s" + +# Time to wait before flushing messages out on the connection +flush_throttle_timeout = "100ms" + +# Maximum size of a message packet payload, in bytes +max_packet_msg_payload_size = 1024 + +# Rate at which packets can be sent, in bytes/second +send_rate = 5120000 + +# Rate at which packets can be received, in bytes/second +recv_rate = 5120000 + +# Set true to enable the peer-exchange reactor +pex = true + +# Seed mode, in which node constantly crawls the network and looks for +# peers. If another node asks it for addresses, it responds and disconnects. +# +# Does not work if the peer-exchange reactor is disabled. +seed_mode = false + +# Comma separated list of peer IDs to keep private (will not be gossiped to other peers) +private_peer_ids = "" + +# Toggle to disable guard against peers connecting from the same ip. +allow_duplicate_ip = false + +# Peer connection configuration. +handshake_timeout = "20s" +dial_timeout = "3s" + +####################################################### +### Mempool Configuration Option ### +####################################################### +[mempool] + +recheck = true +broadcast = true +wal_dir = "" + +# Maximum number of transactions in the mempool +size = 5000 + +# Limit the total size of all txs in the mempool. +# This only accounts for raw transactions (e.g. given 1MB transactions and +# max_txs_bytes=5MB, mempool will only accept 5 transactions). +max_txs_bytes = 1073741824 + +# Size of the cache (used to filter transactions we saw earlier) in transactions +cache_size = 10000 + +# Do not remove invalid transactions from the cache (default: false) +# Set to true if it's not possible for any invalid transaction to become valid +# again in the future. +keep-invalid-txs-in-cache = false + +# Maximum size of a single transaction. +# NOTE: the max size of a tx transmitted over the network is {max_tx_bytes}. +max_tx_bytes = 1048576 + +# Maximum size of a batch of transactions to send to a peer +# Including space needed by encoding (one varint per transaction). +# XXX: Unused due to https://github.com/tendermint/tendermint/issues/5796 +max_batch_bytes = 0 + +####################################################### +### State Sync Configuration Options ### +####################################################### +[statesync] +# State sync rapidly bootstraps a new node by discovering, fetching, and restoring a state machine +# snapshot from peers instead of fetching and replaying historical blocks. Requires some peers in +# the network to take and serve state machine snapshots. State sync is not attempted if the node +# has any local state (LastBlockHeight > 0). The node will have a truncated block history, +# starting from the height of the snapshot. +enable = false + +# RPC servers (comma-separated) for light client verification of the synced state machine and +# retrieval of state data for node bootstrapping. Also needs a trusted height and corresponding +# header hash obtained from a trusted source, and a period during which validators can be trusted. +# +# For Cosmos SDK-based chains, trust_period should usually be about 2/3 of the unbonding time (~2 +# weeks) during which they can be financially punished (slashed) for misbehavior. +rpc_servers = "" +trust_height = 0 +trust_hash = "" +trust_period = "168h0m0s" + +# Time to spend discovering snapshots before initiating a restore. +discovery_time = "15s" + +# Temporary directory for state sync snapshot chunks, defaults to the OS tempdir (typically /tmp). +# Will create a new, randomly named directory within, and remove it when done. +temp_dir = "" + +# The timeout duration before re-requesting a chunk, possibly from a different +# peer (default: 1 minute). +chunk_request_timeout = "10s" + +# The number of concurrent chunk fetchers to run (default: 1). +chunk_fetchers = "4" + +####################################################### +### Fast Sync Configuration Connections ### +####################################################### +[fastsync] + +# Fast Sync version to use: +# 1) "v0" (default) - the legacy fast sync implementation +# 2) "v1" - refactor of v0 version for better testability +# 2) "v2" - complete redesign of v0, optimized for testability & readability +version = "v0" + +####################################################### +### Consensus Configuration Options ### +####################################################### +[consensus] + +wal_file = "data/cs.wal/wal" + +# How long we wait for a proposal block before prevoting nil +timeout_propose = "1s" +# How much timeout_propose increases with each round +timeout_propose_delta = "500ms" +# How long we wait after receiving +2/3 prevotes for “anything” (ie. not a single block or nil) +timeout_prevote = "1s" +# How much the timeout_prevote increases with each round +timeout_prevote_delta = "500ms" +# How long we wait after receiving +2/3 precommits for “anything” (ie. not a single block or nil) +timeout_precommit = "1s" +# How much the timeout_precommit increases with each round +timeout_precommit_delta = "500ms" +# How long we wait after committing a block, before starting on the new +# height (this gives us a chance to receive some more precommits, even +# though we already have +2/3). +timeout_commit = "1s" + +# How many blocks to look back to check existence of the node's consensus votes before joining consensus +# When non-zero, the node will panic upon restart +# if the same consensus key was used to sign {double_sign_check_height} last blocks. +# So, validators should stop the state machine, wait for some blocks, and then restart the state machine to avoid panic. +double_sign_check_height = 0 + +# Make progress as soon as we have all the precommits (as if TimeoutCommit = 0) +skip_timeout_commit = false + +# EmptyBlocks mode and possible interval between empty blocks +create_empty_blocks = true +create_empty_blocks_interval = "0s" + +# Reactor sleep duration parameters +peer_gossip_sleep_duration = "100ms" +peer_query_maj23_sleep_duration = "2s" + +####################################################### +### Transaction Indexer Configuration Options ### +####################################################### +[tx_index] + +# What indexer to use for transactions +# +# The application will set which txs to index. In some cases a node operator will be able +# to decide which txs to index based on configuration set in the application. +# +# Options: +# 1) "null" +# 2) "kv" (default) - the simplest possible indexer, backed by key-value storage (defaults to levelDB; see DBBackend). +# - When "kv" is chosen "tx.height" and "tx.hash" will always be indexed. +indexer = "kv" + +####################################################### +### Instrumentation Configuration Options ### +####################################################### +[instrumentation] + +# When true, Prometheus metrics are served under /metrics on +# PrometheusListenAddr. +# Check out the documentation for the list of available metrics. +prometheus = false + +# Address to listen for Prometheus collector(s) connections +prometheus_listen_addr = ":26660" + +# Maximum number of simultaneous connections. +# If you want to accept a larger number than the default, make sure +# you increase your OS limits. +# 0 - unlimited. +max_open_connections = 3 + +# Instrumentation namespace +namespace = "tendermint" diff --git a/ci/chains/gaia/v5.0.8/ibc-0/config/genesis.json b/ci/chains/gaia/v5.0.8/ibc-0/config/genesis.json new file mode 100644 index 000000000..e2bdd082e --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-0/config/genesis.json @@ -0,0 +1,342 @@ +{ + "genesis_time": "2021-11-04T15:47:29.231543194Z", + "chain_id": "ibc-0", + "initial_height": "1", + "consensus_params": { + "block": { + "max_bytes": "22020096", + "max_gas": "-1", + "time_iota_ms": "1000" + }, + "evidence": { + "max_age_num_blocks": "100000", + "max_age_duration": "172800000000000", + "max_bytes": "1048576" + }, + "validator": { + "pub_key_types": [ + "ed25519" + ] + }, + "version": {} + }, + "app_hash": "", + "app_state": { + "auth": { + "params": { + "max_memo_characters": "256", + "tx_sig_limit": "7", + "tx_size_cost_per_byte": "10", + "sig_verify_cost_ed25519": "590", + "sig_verify_cost_secp256k1": "1000" + }, + "accounts": [ + { + "@type": "/cosmos.auth.v1beta1.BaseAccount", + "address": "cosmos1exw8hfhy3y09nqfkvvr0y7crd0asmxcmauvuvd", + "pub_key": null, + "account_number": "0", + "sequence": "0" + }, + { + "@type": "/cosmos.auth.v1beta1.BaseAccount", + "address": "cosmos1vnatnf5m0g27uz2lk0dgq4dxg3gcscr7uajmv7", + "pub_key": null, + "account_number": "0", + "sequence": "0" + }, + { + "@type": "/cosmos.auth.v1beta1.BaseAccount", + "address": "cosmos1tgzhx34m3mamgzd5wjuwhhdptzu37crsmle9cz", + "pub_key": null, + "account_number": "0", + "sequence": "0" + } + ] + }, + "bank": { + "params": { + "send_enabled": [], + "default_send_enabled": true + }, + "balances": [ + { + "address": "cosmos1tgzhx34m3mamgzd5wjuwhhdptzu37crsmle9cz", + "coins": [ + { + "denom": "stake", + "amount": "100000000000" + } + ] + }, + { + "address": "cosmos1vnatnf5m0g27uz2lk0dgq4dxg3gcscr7uajmv7", + "coins": [ + { + "denom": "samoleans", + "amount": "100000000000" + }, + { + "denom": "stake", + "amount": "100000000000" + } + ] + }, + { + "address": "cosmos1exw8hfhy3y09nqfkvvr0y7crd0asmxcmauvuvd", + "coins": [ + { + "denom": "samoleans", + "amount": "100000000000" + }, + { + "denom": "stake", + "amount": "100000000000" + } + ] + } + ], + "supply": [ + { + "denom": "samoleans", + "amount": "200000000000" + }, + { + "denom": "stake", + "amount": "300000000000" + } + ], + "denom_metadata": [] + }, + "capability": { + "index": "1", + "owners": [] + }, + "crisis": { + "constant_fee": { + "denom": "stake", + "amount": "1000" + } + }, + "distribution": { + "params": { + "community_tax": "0.020000000000000000", + "base_proposer_reward": "0.010000000000000000", + "bonus_proposer_reward": "0.040000000000000000", + "withdraw_addr_enabled": true + }, + "fee_pool": { + "community_pool": [] + }, + "delegator_withdraw_infos": [], + "previous_proposer": "", + "outstanding_rewards": [], + "validator_accumulated_commissions": [], + "validator_historical_rewards": [], + "validator_current_rewards": [], + "delegator_starting_infos": [], + "validator_slash_events": [] + }, + "evidence": { + "evidence": [] + }, + "genutil": { + "gen_txs": [ + { + "body": { + "messages": [ + { + "@type": "/cosmos.staking.v1beta1.MsgCreateValidator", + "description": { + "moniker": "ibc-0", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "commission": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "min_self_delegation": "1", + "delegator_address": "cosmos1tgzhx34m3mamgzd5wjuwhhdptzu37crsmle9cz", + "validator_address": "cosmosvaloper1tgzhx34m3mamgzd5wjuwhhdptzu37crs7tds53", + "pubkey": { + "@type": "/cosmos.crypto.ed25519.PubKey", + "key": "b0Upk7Jh+8qlBg9/nBABHW57gwE9jRwXcVK2bw9UcWQ=" + }, + "value": { + "denom": "stake", + "amount": "100000000000" + } + } + ], + "memo": "e644f6ada6dc23fa6927484cca6e00183dc3fe0b@192.168.50.214:26656", + "timeout_height": "0", + "extension_options": [], + "non_critical_extension_options": [] + }, + "auth_info": { + "signer_infos": [ + { + "public_key": { + "@type": "/cosmos.crypto.secp256k1.PubKey", + "key": "A50bVFQ0B4TqK6Jf9m0D9NhVEO0HqJFgoIhPpcY/5RAD" + }, + "mode_info": { + "single": { + "mode": "SIGN_MODE_DIRECT" + } + }, + "sequence": "0" + } + ], + "fee": { + "amount": [], + "gas_limit": "200000", + "payer": "", + "granter": "" + } + }, + "signatures": [ + "W0OZ0bf1Hs6gz8vCofrI267vAe8KT+AdaJpH8gTGx7lDK94R+3wwItI9HDak61KZSScQqln0gXjXIpXMu4BkfQ==" + ] + } + ] + }, + "gov": { + "starting_proposal_id": "1", + "deposits": [], + "votes": [], + "proposals": [], + "deposit_params": { + "min_deposit": [ + { + "denom": "stake", + "amount": "10000000" + } + ], + "max_deposit_period": "200s" + }, + "voting_params": { + "voting_period": "200s" + }, + "tally_params": { + "quorum": "0.334000000000000000", + "threshold": "0.500000000000000000", + "veto_threshold": "0.334000000000000000" + } + }, + "ibc": { + "client_genesis": { + "clients": [], + "clients_consensus": [], + "clients_metadata": [], + "params": { + "allowed_clients": [ + "06-solomachine", + "07-tendermint" + ] + }, + "create_localhost": false, + "next_client_sequence": "0" + }, + "connection_genesis": { + "connections": [], + "client_connection_paths": [], + "next_connection_sequence": "0" + }, + "channel_genesis": { + "channels": [], + "acknowledgements": [], + "commitments": [], + "receipts": [], + "send_sequences": [], + "recv_sequences": [], + "ack_sequences": [], + "next_channel_sequence": "0" + } + }, + "liquidity": { + "params": { + "pool_types": [ + { + "id": 1, + "name": "StandardLiquidityPool", + "min_reserve_coin_num": 2, + "max_reserve_coin_num": 2, + "description": "Standard liquidity pool with pool price function X/Y, ESPM constraint, and two kinds of reserve coins" + } + ], + "min_init_deposit_amount": "1000000", + "init_pool_coin_mint_amount": "1000000", + "max_reserve_coin_amount": "0", + "pool_creation_fee": [ + { + "denom": "stake", + "amount": "40000000" + } + ], + "swap_fee_rate": "0.003000000000000000", + "withdraw_fee_rate": "0.000000000000000000", + "max_order_amount_ratio": "0.100000000000000000", + "unit_batch_height": 1, + "circuit_breaker_enabled": false + }, + "pool_records": [] + }, + "mint": { + "minter": { + "inflation": "0.130000000000000000", + "annual_provisions": "0.000000000000000000" + }, + "params": { + "mint_denom": "stake", + "inflation_rate_change": "0.130000000000000000", + "inflation_max": "0.200000000000000000", + "inflation_min": "0.070000000000000000", + "goal_bonded": "0.670000000000000000", + "blocks_per_year": "6311520" + } + }, + "params": null, + "slashing": { + "params": { + "signed_blocks_window": "100", + "min_signed_per_window": "0.500000000000000000", + "downtime_jail_duration": "600s", + "slash_fraction_double_sign": "0.050000000000000000", + "slash_fraction_downtime": "0.010000000000000000" + }, + "signing_infos": [], + "missed_blocks": [] + }, + "staking": { + "params": { + "unbonding_time": "1814400s", + "max_validators": 100, + "max_entries": 7, + "historical_entries": 10000, + "bond_denom": "stake" + }, + "last_total_power": "0", + "last_validator_powers": [], + "validators": [], + "delegations": [], + "unbonding_delegations": [], + "redelegations": [], + "exported": false + }, + "transfer": { + "port_id": "transfer", + "denom_traces": [], + "params": { + "send_enabled": true, + "receive_enabled": true + } + }, + "upgrade": {}, + "vesting": {} + } +} \ No newline at end of file diff --git a/ci/chains/gaia/v5.0.8/ibc-0/config/gentx/gentx-e644f6ada6dc23fa6927484cca6e00183dc3fe0b.json b/ci/chains/gaia/v5.0.8/ibc-0/config/gentx/gentx-e644f6ada6dc23fa6927484cca6e00183dc3fe0b.json new file mode 100644 index 000000000..a5a6bb618 --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-0/config/gentx/gentx-e644f6ada6dc23fa6927484cca6e00183dc3fe0b.json @@ -0,0 +1 @@ +{"body":{"messages":[{"@type":"/cosmos.staking.v1beta1.MsgCreateValidator","description":{"moniker":"ibc-0","identity":"","website":"","security_contact":"","details":""},"commission":{"rate":"0.100000000000000000","max_rate":"0.200000000000000000","max_change_rate":"0.010000000000000000"},"min_self_delegation":"1","delegator_address":"cosmos1tgzhx34m3mamgzd5wjuwhhdptzu37crsmle9cz","validator_address":"cosmosvaloper1tgzhx34m3mamgzd5wjuwhhdptzu37crs7tds53","pubkey":{"@type":"/cosmos.crypto.ed25519.PubKey","key":"b0Upk7Jh+8qlBg9/nBABHW57gwE9jRwXcVK2bw9UcWQ="},"value":{"denom":"stake","amount":"100000000000"}}],"memo":"e644f6ada6dc23fa6927484cca6e00183dc3fe0b@192.168.50.214:26656","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[{"public_key":{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"A50bVFQ0B4TqK6Jf9m0D9NhVEO0HqJFgoIhPpcY/5RAD"},"mode_info":{"single":{"mode":"SIGN_MODE_DIRECT"}},"sequence":"0"}],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":["W0OZ0bf1Hs6gz8vCofrI267vAe8KT+AdaJpH8gTGx7lDK94R+3wwItI9HDak61KZSScQqln0gXjXIpXMu4BkfQ=="]} diff --git a/ci/chains/gaia/v5.0.8/ibc-0/config/node_key.json b/ci/chains/gaia/v5.0.8/ibc-0/config/node_key.json new file mode 100644 index 000000000..65bec3d2d --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-0/config/node_key.json @@ -0,0 +1 @@ +{"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"PnKW6NeBJUMFjHt4zFCFcoODQ6igtYYqMjFp6MJNGKdb7ynzjZlXJoFDdL31vKFVjfqBLTT5J64JFslespTbkw=="}} \ No newline at end of file diff --git a/ci/chains/gaia/v5.0.8/ibc-0/config/priv_validator_key.json b/ci/chains/gaia/v5.0.8/ibc-0/config/priv_validator_key.json new file mode 100644 index 000000000..8b5954526 --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-0/config/priv_validator_key.json @@ -0,0 +1,11 @@ +{ + "address": "A129A9C5DCC0E76B98FEE6CC94007F5A9DD9FFCB", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "b0Upk7Jh+8qlBg9/nBABHW57gwE9jRwXcVK2bw9UcWQ=" + }, + "priv_key": { + "type": "tendermint/PrivKeyEd25519", + "value": "bllmLWHxWHFQecOBGM976AuAN9lD3RFHRTgrcY0au2JvRSmTsmH7yqUGD3+cEAEdbnuDAT2NHBdxUrZvD1RxZA==" + } +} \ No newline at end of file diff --git a/ci/chains/gaia/v5.0.8/ibc-0/keyring-test/5a057346bb8efbb409b474b8ebdda158b91f6070.address b/ci/chains/gaia/v5.0.8/ibc-0/keyring-test/5a057346bb8efbb409b474b8ebdda158b91f6070.address new file mode 100644 index 000000000..f82461c04 --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-0/keyring-test/5a057346bb8efbb409b474b8ebdda158b91f6070.address @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMS0xMS0wNCAxMTo0NzozMC4zMTcyMTgyNDggLTA0MDAgRURUIG09KzAuMDczMzM0NDQxIiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiZkJwSWlqbzZ3UHRMUDRhYiJ9.Xd813npMEw-9lrIGXKwsFu0CejBjnuQlCk5L1_mKs2fCACcHeyeESg.eT2fnPglp8HNTBKd.DBxSUHsnMx08T2rBia1ps1adGRxtH44DscMgTgL-D-xu0cHLLxkziH4U6pK1nD9TTA5p7OnFIv7-QnWpTvVhfbmPlmpmDqM-UkAPhMFIm7mtkBxUq1jf5qqRDHyT-5ikSEn0tIceZHC0cXg0C_son_QpW-LSCh-YUoNKpTBZCTX6u0jrZnQISzU4ztgYKpX5uSCIJLZel-3zqSw50p8HWneex9H5bQBbGItSBxEo6bARvGNCDD3N3rLq.0UVZuIkn97EnR1AL_Yrb7Q \ No newline at end of file diff --git a/ci/chains/gaia/v5.0.8/ibc-0/keyring-test/64fab9a69b7a15ee095fb3da8055a6445188607e.address b/ci/chains/gaia/v5.0.8/ibc-0/keyring-test/64fab9a69b7a15ee095fb3da8055a6445188607e.address new file mode 100644 index 000000000..4e62c6a82 --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-0/keyring-test/64fab9a69b7a15ee095fb3da8055a6445188607e.address @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMS0xMS0wNCAxMTo0NzozMi40ODAzMTc0NjggLTA0MDAgRURUIG09KzAuMDY0ODk5ODA1IiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiaDhIT3drRGw0UnplckxvOCJ9.vTyBa21aNqfLtvvdm0QftogEJQQp2FerqFR9tflolVBcE5-O59FuAQ.lJ6VZ4mXuG5M5K9P.ff22Ek0KiqEvRn1QY1oCKYd2qFPDgnJ3gccM1UWmoh6fIUx8Pbsktrnu45HtwHpnfEn8Gxp24snmRv0ad3Qq_h_j5lSS98mnoss7d1CLhtF7P7DBYwLNMDSNCbMjgD0-Bx0ZhdgTGoBW9_t23aEQH2yBVt6pfkse2Kd9hKvy31-MovUt-WyQ3DzxjyFwH3utdazTnIwyCmCH5fW95VraXeX2-ynI47pYQoZ3vA0StfYawE59CI4.RkuJB1gfEF2wWRwnk-1oKA \ No newline at end of file diff --git a/ci/chains/gaia/v5.0.8/ibc-0/keyring-test/c99c7ba6e4891e5981366306f27b036bfb0d9b1b.address b/ci/chains/gaia/v5.0.8/ibc-0/keyring-test/c99c7ba6e4891e5981366306f27b036bfb0d9b1b.address new file mode 100644 index 000000000..af2a4f474 --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-0/keyring-test/c99c7ba6e4891e5981366306f27b036bfb0d9b1b.address @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMS0xMS0wNCAxMTo0NzozMS40MDI1NjU1MjcgLTA0MDAgRURUIG09KzAuMDcwNTE1NTI0IiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiNjNjVEtlNF9QZi1WNW9CdiJ9.ZnIuGZ7P72EPIxV-hnmbpKNJxNkM23GUizPhBP520TSAQvGY_XsBsw.e4wvOVOnnoNdApXM.Joe1jjxS6ej_zICXtu6WpfcsZdXRqLoXdqK6_dPQslinSSfKKdekMb62zYCNOxeyjXb9RSu3EbYRGq3TAG8OWZaqpbsYuenjAvrlIRYqGY1jxwIFQwK6rTgGrZwzb_KxdB9mI99kGBwLP-T8VsvI-bWtBBri5sIIb-UEf_F4NPfI9vs4Bkco-PV520xPUN8T1e6oycJFYQYy2H99vcFddQ8ENrF2T8xr0v0HLeMd9fbnSQ.NSXG5ji268uoENc0zVHUmA \ No newline at end of file diff --git a/ci/chains/gaia/v5.0.8/ibc-0/keyring-test/user.info b/ci/chains/gaia/v5.0.8/ibc-0/keyring-test/user.info new file mode 100644 index 000000000..ab2114515 --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-0/keyring-test/user.info @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMS0xMS0wNCAxMTo0NzozMS4zOTY1MzkzOTggLTA0MDAgRURUIG09KzAuMDY0NDg5MzkxIiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiZ0t6ZjgtZHNDVktwRHo2ZCJ9.pVu0Mtx4jNLLIDS3pgoN02A3GI1NOyof03z2kQBthJkkLIFn8aoKYg.YV7kj3HXaHRBuaS_.o2ODJ4i0huip-aamiyMiDmuZc9ZOc65R79fKmB46efEl8jcjog7Zql5z0WoKtFh9qfkHAUYnMM1dVZ3O6d_gSZU-r-nEoq4WqZep__zLGJ7ETX-WPz11y-oi4ZeOpXeEh7gCDFb9kZhIzIDvoBv-qYVfOFC33OoN6Bz2OGtC4aIjVPf5vwcTwaRhZMaM_atH5smS18LODhppcSmJAjV9xjsca3KGQtAAYLYuVT3PG36W7p4JAww2m3AeeqHP0tdQQwa6sg8PLOQg9Zxuw9H614ZEgGX7-Ao9iVUkqP8BCOCoS9RnffAkfP0WCR7KNoA5IxJAdk8kKBWJfdsKb7xdyO5RNSIzbuk.xkWnt_f8cV9kh7it2xXK7A \ No newline at end of file diff --git a/ci/chains/gaia/v5.0.8/ibc-0/keyring-test/user2.info b/ci/chains/gaia/v5.0.8/ibc-0/keyring-test/user2.info new file mode 100644 index 000000000..e30f9f7b7 --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-0/keyring-test/user2.info @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMS0xMS0wNCAxMTo0NzozMi40NzQzNDY3MTcgLTA0MDAgRURUIG09KzAuMDU4OTI5MDM3IiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiVmNSTG9SMmhQWFhtM01oNiJ9.qcJz1u3RDq-IFS9eLisFpeU3mKBn4TuQNzr7WcMurqjW5EmNmUEtKA.7RRHagT_GFcnaFxJ.pkLQs5JLngcUu9FIaM6dpx3TIWmw8hMLi9DVq9DjVPdwO-_79CBYAUf5-p62iw7czNl5f5l0YwtE-_d2pwcsS3sl0F6Ez2RsxVCvZrC755XCuFktkWWL-5uXbUpFNyvZs-6ATOxhr0aoAkF5ZGkUUFweTMZrglLGh5HlKymVrSx9MXSqVrZOB3CFhZVxX-EobcxKm4x9Jph7LpDj1JODpDcOawB6zZwMF0bqYPywTfKnrZlB7xlmhcwv_43vh8Yh_EhXeCj4ps4i7PqMiBLg2Wn9Mi8SYL5P-C_J2gi_PvsPU5zKkVDVuqEGrlMCTWEz4s0tAeEwoJFk77MpPK323jXv4U87o4pc.W5JsaLin4N_eJ9rFryQJEQ \ No newline at end of file diff --git a/ci/chains/gaia/v5.0.8/ibc-0/keyring-test/validator.info b/ci/chains/gaia/v5.0.8/ibc-0/keyring-test/validator.info new file mode 100644 index 000000000..5aac0f6eb --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-0/keyring-test/validator.info @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMS0xMS0wNCAxMTo0NzozMC4zMTA4MDQ2NDcgLTA0MDAgRURUIG09KzAuMDY2OTIwODYwIiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiejF4dkoycjE5SjNMXzhCUiJ9.n8QDC3Qcju_iKHP-15BXBPKcAedMbGd6L8MmglKV1gkneTZoFWAIvw.a2J96EcNQ6dLaguQ.2QRIomjZxj5ROCWXfe7wgxnWl0_MncasnkmsbP5yH0m-lmjd_sRFIQ53MpIsFqAHQj1xFBmJRP2GqXQZkQt-QeIrXyzylzmDK9FtlKL-gvCxuoOKync4Il62SmnClMkFGPObebRKIAluQoZ8DzVYWSklWyP51eIBewz2FyONvQkOS5ZTUYcTzqhnK_ZwQM1t_uzBQ9TvP1sUvABRsAwvfWZke8iP4I-uBHlMXO-34bCQCmYRRo9TF49ti0T3tbAt7rDjmhv9N0BrGv4Ir_o81wo-4Zd0xgdtZlu_Nt8_99qnF9hQkAvkUD6u6NyVOGC3Gpppjl6D3KkWxarGkbJFiFVubMLPmkO_3fll7kOsEEFMjcKR.2TUybiWXhefRJJF6cPTGHw \ No newline at end of file diff --git a/ci/chains/gaia/v5.0.8/ibc-0/user2_seed.json b/ci/chains/gaia/v5.0.8/ibc-0/user2_seed.json new file mode 100644 index 000000000..20fa1e475 --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-0/user2_seed.json @@ -0,0 +1 @@ +{"name":"user2","type":"local","address":"cosmos1vnatnf5m0g27uz2lk0dgq4dxg3gcscr7uajmv7","pubkey":"cosmospub1addwnpepqg2wvn5a6kn7yjqqxvchav8g9yz46xywfvn248qvmj56jpxypjvakjqsc3m","mnemonic":"naive early elbow chat model athlete lottery unfold comfort scare portion army era patch yard penalty two time student jazz middle endless execute relax"} diff --git a/ci/chains/gaia/v5.0.8/ibc-0/user_seed.json b/ci/chains/gaia/v5.0.8/ibc-0/user_seed.json new file mode 100644 index 000000000..d99cc314d --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-0/user_seed.json @@ -0,0 +1 @@ +{"name":"user","type":"local","address":"cosmos1exw8hfhy3y09nqfkvvr0y7crd0asmxcmauvuvd","pubkey":"cosmospub1addwnpepq28jx6t5xgfl3pkvgydru2h68pwuqhunkm70hfttqp2esswctdzv6echc75","mnemonic":"lock border during undo menu crouch ticket absurd slight remove sock more nominee ketchup night parrot firm future essence need devote client sugar stadium"} diff --git a/ci/chains/gaia/v5.0.8/ibc-0/validator_seed.json b/ci/chains/gaia/v5.0.8/ibc-0/validator_seed.json new file mode 100644 index 000000000..1c00c62d5 --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-0/validator_seed.json @@ -0,0 +1 @@ +{"name":"validator","type":"local","address":"cosmos1tgzhx34m3mamgzd5wjuwhhdptzu37crsmle9cz","pubkey":"cosmospub1addwnpepqww3k4z5xsrcf63t5f0lvmgr7nv92y8dq75fzc9q3p86t33lu5gqx5vfz4y","mnemonic":"trigger liar blast diesel fall mention quantum vast walnut mail rally there village crop timber assault bachelor scene taste hover top caught concert rather"} diff --git a/ci/chains/gaia/v5.0.8/ibc-1/config/app.toml b/ci/chains/gaia/v5.0.8/ibc-1/config/app.toml new file mode 100644 index 000000000..54de73e39 --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-1/config/app.toml @@ -0,0 +1,152 @@ +# This is a TOML config file. +# For more information, see https://github.com/toml-lang/toml + +############################################################################### +### Base Configuration ### +############################################################################### + +# The minimum gas prices a validator is willing to accept for processing a +# transaction. A transaction's fees must meet the minimum of any denomination +# specified in this config (e.g. 0.25token1;0.0001token2). +minimum-gas-prices = "" + +# default: the last 100 states are kept in addition to every 500th state; pruning at 10 block intervals +# nothing: all historic states will be saved, nothing will be deleted (i.e. archiving node) +# everything: all saved states will be deleted, storing only the current state; pruning at 10 block intervals +# custom: allow pruning options to be manually specified through 'pruning-keep-recent', 'pruning-keep-every', and 'pruning-interval' +pruning = "default" + +# These are applied if and only if the pruning strategy is custom. +pruning-keep-recent = "0" +pruning-keep-every = "0" +pruning-interval = "0" + +# HaltHeight contains a non-zero block height at which a node will gracefully +# halt and shutdown that can be used to assist upgrades and testing. +# +# Note: Commitment of state will be attempted on the corresponding block. +halt-height = 0 + +# HaltTime contains a non-zero minimum block time (in Unix seconds) at which +# a node will gracefully halt and shutdown that can be used to assist upgrades +# and testing. +# +# Note: Commitment of state will be attempted on the corresponding block. +halt-time = 0 + +# MinRetainBlocks defines the minimum block height offset from the current +# block being committed, such that all blocks past this offset are pruned +# from Tendermint. It is used as part of the process of determining the +# ResponseCommit.RetainHeight value during ABCI Commit. A value of 0 indicates +# that no blocks should be pruned. +# +# This configuration value is only responsible for pruning Tendermint blocks. +# It has no bearing on application state pruning which is determined by the +# "pruning-*" configurations. +# +# Note: Tendermint block pruning is dependant on this parameter in conunction +# with the unbonding (safety threshold) period, state pruning and state sync +# snapshot parameters to determine the correct minimum value of +# ResponseCommit.RetainHeight. +min-retain-blocks = 0 + +# InterBlockCache enables inter-block caching. +inter-block-cache = true + +# IndexEvents defines the set of events in the form {eventType}.{attributeKey}, +# which informs Tendermint what to index. If empty, all events will be indexed. +# +# Example: +# ["message.sender", "message.recipient"] +index-events = [] + +############################################################################### +### Telemetry Configuration ### +############################################################################### + +[telemetry] + +# Prefixed with keys to separate services. +service-name = "" + +# Enabled enables the application telemetry functionality. When enabled, +# an in-memory sink is also enabled by default. Operators may also enabled +# other sinks such as Prometheus. +enabled = false + +# Enable prefixing gauge values with hostname. +enable-hostname = false + +# Enable adding hostname to labels. +enable-hostname-label = false + +# Enable adding service to labels. +enable-service-label = false + +# PrometheusRetentionTime, when positive, enables a Prometheus metrics sink. +prometheus-retention-time = 0 + +# GlobalLabels defines a global set of name/value label tuples applied to all +# metrics emitted using the wrapper functions defined in telemetry package. +# +# Example: +# [["chain_id", "cosmoshub-1"]] +global-labels = [ +] + +############################################################################### +### API Configuration ### +############################################################################### + +[api] + +# Enable defines if the API server should be enabled. +enable = false + +# Swagger defines if swagger documentation should automatically be registered. +swagger = false + +# Address defines the API server to listen on. +address = "tcp://0.0.0.0:1317" + +# MaxOpenConnections defines the number of maximum open connections. +max-open-connections = 1000 + +# RPCReadTimeout defines the Tendermint RPC read timeout (in seconds). +rpc-read-timeout = 10 + +# RPCWriteTimeout defines the Tendermint RPC write timeout (in seconds). +rpc-write-timeout = 0 + +# RPCMaxBodyBytes defines the Tendermint maximum response body (in bytes). +rpc-max-body-bytes = 1000000 + +# EnableUnsafeCORS defines if CORS should be enabled (unsafe - use it at your own risk). +enabled-unsafe-cors = false + +############################################################################### +### gRPC Configuration ### +############################################################################### + +[grpc] + +# Enable defines if the gRPC server should be enabled. +enable = true + +# Address defines the gRPC server address to bind to. +address = "0.0.0.0:9090" + +############################################################################### +### State Sync Configuration ### +############################################################################### + +# State sync snapshots allow other nodes to rapidly join the network without replaying historical +# blocks, instead downloading and applying a snapshot of the application state at a given height. +[state-sync] + +# snapshot-interval specifies the block interval at which local state sync snapshots are +# taken (0 to disable). Must be a multiple of pruning-keep-every. +snapshot-interval = 0 + +# snapshot-keep-recent specifies the number of recent snapshots to keep and serve (0 to keep all). +snapshot-keep-recent = 2 diff --git a/ci/chains/gaia/v5.0.8/ibc-1/config/client.toml b/ci/chains/gaia/v5.0.8/ibc-1/config/client.toml new file mode 100644 index 000000000..222695a3f --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-1/config/client.toml @@ -0,0 +1,17 @@ +# This is a TOML config file. +# For more information, see https://github.com/toml-lang/toml + +############################################################################### +### Client Configuration ### +############################################################################### + +# The network chain ID +chain-id = "" +# The keyring's backend, where the keys are stored (os|file|kwallet|pass|test|memory) +keyring-backend = "os" +# CLI output format (text|json) +output = "text" +# : to Tendermint RPC interface for this chain +node = "tcp://localhost:26657" +# Transaction broadcasting mode (sync|async|block) +broadcast-mode = "sync" diff --git a/ci/chains/gaia/v5.0.8/ibc-1/config/config.toml b/ci/chains/gaia/v5.0.8/ibc-1/config/config.toml new file mode 100644 index 000000000..bd592119b --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-1/config/config.toml @@ -0,0 +1,401 @@ +# This is a TOML config file. +# For more information, see https://github.com/toml-lang/toml + +# NOTE: Any path below can be absolute (e.g. "/var/myawesomeapp/data") or +# relative to the home directory (e.g. "data"). The home directory is +# "$HOME/.tendermint" by default, but could be changed via $TMHOME env variable +# or --home cmd flag. + +####################################################################### +### Main Base Config Options ### +####################################################################### + +# TCP or UNIX socket address of the ABCI application, +# or the name of an ABCI application compiled in with the Tendermint binary +proxy_app = "tcp://127.0.0.1:26658" + +# A custom human readable name for this node +moniker = "ibc-1" + +# If this node is many blocks behind the tip of the chain, FastSync +# allows them to catchup quickly by downloading blocks in parallel +# and verifying their commits +fast_sync = true + +# Database backend: goleveldb | cleveldb | boltdb | rocksdb | badgerdb +# * goleveldb (github.com/syndtr/goleveldb - most popular implementation) +# - pure go +# - stable +# * cleveldb (uses levigo wrapper) +# - fast +# - requires gcc +# - use cleveldb build tag (go build -tags cleveldb) +# * boltdb (uses etcd's fork of bolt - github.com/etcd-io/bbolt) +# - EXPERIMENTAL +# - may be faster is some use-cases (random reads - indexer) +# - use boltdb build tag (go build -tags boltdb) +# * rocksdb (uses github.com/tecbot/gorocksdb) +# - EXPERIMENTAL +# - requires gcc +# - use rocksdb build tag (go build -tags rocksdb) +# * badgerdb (uses github.com/dgraph-io/badger) +# - EXPERIMENTAL +# - use badgerdb build tag (go build -tags badgerdb) +db_backend = "goleveldb" + +# Database directory +db_dir = "data" + +# Output level for logging, including package level options +log_level = "info" + +# Output format: 'plain' (colored text) or 'json' +log_format = "plain" + +##### additional base config options ##### + +# Path to the JSON file containing the initial validator set and other meta data +genesis_file = "config/genesis.json" + +# Path to the JSON file containing the private key to use as a validator in the consensus protocol +priv_validator_key_file = "config/priv_validator_key.json" + +# Path to the JSON file containing the last sign state of a validator +priv_validator_state_file = "data/priv_validator_state.json" + +# TCP or UNIX socket address for Tendermint to listen on for +# connections from an external PrivValidator process +priv_validator_laddr = "" + +# Path to the JSON file containing the private key to use for node authentication in the p2p protocol +node_key_file = "config/node_key.json" + +# Mechanism to connect to the ABCI application: socket | grpc +abci = "socket" + +# If true, query the ABCI app on connecting to a new peer +# so the app can decide if we should keep the connection or not +filter_peers = false + + +####################################################################### +### Advanced Configuration Options ### +####################################################################### + +####################################################### +### RPC Server Configuration Options ### +####################################################### +[rpc] + +# TCP or UNIX socket address for the RPC server to listen on +laddr = "tcp://0.0.0.0:26657" + +# A list of origins a cross-domain request can be executed from +# Default value '[]' disables cors support +# Use '["*"]' to allow any origin +cors_allowed_origins = [] + +# A list of methods the client is allowed to use with cross-domain requests +cors_allowed_methods = ["HEAD", "GET", "POST", ] + +# A list of non simple headers the client is allowed to use with cross-domain requests +cors_allowed_headers = ["Origin", "Accept", "Content-Type", "X-Requested-With", "X-Server-Time", ] + +# TCP or UNIX socket address for the gRPC server to listen on +# NOTE: This server only supports /broadcast_tx_commit +grpc_laddr = "" + +# Maximum number of simultaneous connections. +# Does not include RPC (HTTP&WebSocket) connections. See max_open_connections +# If you want to accept a larger number than the default, make sure +# you increase your OS limits. +# 0 - unlimited. +# Should be < {ulimit -Sn} - {MaxNumInboundPeers} - {MaxNumOutboundPeers} - {N of wal, db and other open files} +# 1024 - 40 - 10 - 50 = 924 = ~900 +grpc_max_open_connections = 900 + +# Activate unsafe RPC commands like /dial_seeds and /unsafe_flush_mempool +unsafe = false + +# Maximum number of simultaneous connections (including WebSocket). +# Does not include gRPC connections. See grpc_max_open_connections +# If you want to accept a larger number than the default, make sure +# you increase your OS limits. +# 0 - unlimited. +# Should be < {ulimit -Sn} - {MaxNumInboundPeers} - {MaxNumOutboundPeers} - {N of wal, db and other open files} +# 1024 - 40 - 10 - 50 = 924 = ~900 +max_open_connections = 900 + +# Maximum number of unique clientIDs that can /subscribe +# If you're using /broadcast_tx_commit, set to the estimated maximum number +# of broadcast_tx_commit calls per block. +max_subscription_clients = 100 + +# Maximum number of unique queries a given client can /subscribe to +# If you're using GRPC (or Local RPC client) and /broadcast_tx_commit, set to +# the estimated # maximum number of broadcast_tx_commit calls per block. +max_subscriptions_per_client = 5 + +# How long to wait for a tx to be committed during /broadcast_tx_commit. +# WARNING: Using a value larger than 10s will result in increasing the +# global HTTP write timeout, which applies to all connections and endpoints. +# See https://github.com/tendermint/tendermint/issues/3435 +timeout_broadcast_tx_commit = "10s" + +# Maximum size of request body, in bytes +max_body_bytes = 1000000 + +# Maximum size of request header, in bytes +max_header_bytes = 1048576 + +# The path to a file containing certificate that is used to create the HTTPS server. +# Might be either absolute path or path related to Tendermint's config directory. +# If the certificate is signed by a certificate authority, +# the certFile should be the concatenation of the server's certificate, any intermediates, +# and the CA's certificate. +# NOTE: both tls_cert_file and tls_key_file must be present for Tendermint to create HTTPS server. +# Otherwise, HTTP server is run. +tls_cert_file = "" + +# The path to a file containing matching private key that is used to create the HTTPS server. +# Might be either absolute path or path related to Tendermint's config directory. +# NOTE: both tls-cert-file and tls-key-file must be present for Tendermint to create HTTPS server. +# Otherwise, HTTP server is run. +tls_key_file = "" + +# pprof listen address (https://golang.org/pkg/net/http/pprof) +pprof_laddr = "localhost:6060" + +####################################################### +### P2P Configuration Options ### +####################################################### +[p2p] + +# Address to listen for incoming connections +laddr = "tcp://0.0.0.0:26656" + +# Address to advertise to peers for them to dial +# If empty, will use the same port as the laddr, +# and will introspect on the listener or use UPnP +# to figure out the address. ip and port are required +# example: 159.89.10.97:26656 +external_address = "" + +# Comma separated list of seed nodes to connect to +seeds = "" + +# Comma separated list of nodes to keep persistent connections to +persistent_peers = "" + +# UPNP port forwarding +upnp = false + +# Path to address book +addr_book_file = "config/addrbook.json" + +# Set true for strict address routability rules +# Set false for private or local networks +addr_book_strict = true + +# Maximum number of inbound peers +max_num_inbound_peers = 40 + +# Maximum number of outbound peers to connect to, excluding persistent peers +max_num_outbound_peers = 10 + +# List of node IDs, to which a connection will be (re)established ignoring any existing limits +unconditional_peer_ids = "" + +# Maximum pause when redialing a persistent peer (if zero, exponential backoff is used) +persistent_peers_max_dial_period = "0s" + +# Time to wait before flushing messages out on the connection +flush_throttle_timeout = "100ms" + +# Maximum size of a message packet payload, in bytes +max_packet_msg_payload_size = 1024 + +# Rate at which packets can be sent, in bytes/second +send_rate = 5120000 + +# Rate at which packets can be received, in bytes/second +recv_rate = 5120000 + +# Set true to enable the peer-exchange reactor +pex = true + +# Seed mode, in which node constantly crawls the network and looks for +# peers. If another node asks it for addresses, it responds and disconnects. +# +# Does not work if the peer-exchange reactor is disabled. +seed_mode = false + +# Comma separated list of peer IDs to keep private (will not be gossiped to other peers) +private_peer_ids = "" + +# Toggle to disable guard against peers connecting from the same ip. +allow_duplicate_ip = false + +# Peer connection configuration. +handshake_timeout = "20s" +dial_timeout = "3s" + +####################################################### +### Mempool Configuration Option ### +####################################################### +[mempool] + +recheck = true +broadcast = true +wal_dir = "" + +# Maximum number of transactions in the mempool +size = 5000 + +# Limit the total size of all txs in the mempool. +# This only accounts for raw transactions (e.g. given 1MB transactions and +# max_txs_bytes=5MB, mempool will only accept 5 transactions). +max_txs_bytes = 1073741824 + +# Size of the cache (used to filter transactions we saw earlier) in transactions +cache_size = 10000 + +# Do not remove invalid transactions from the cache (default: false) +# Set to true if it's not possible for any invalid transaction to become valid +# again in the future. +keep-invalid-txs-in-cache = false + +# Maximum size of a single transaction. +# NOTE: the max size of a tx transmitted over the network is {max_tx_bytes}. +max_tx_bytes = 1048576 + +# Maximum size of a batch of transactions to send to a peer +# Including space needed by encoding (one varint per transaction). +# XXX: Unused due to https://github.com/tendermint/tendermint/issues/5796 +max_batch_bytes = 0 + +####################################################### +### State Sync Configuration Options ### +####################################################### +[statesync] +# State sync rapidly bootstraps a new node by discovering, fetching, and restoring a state machine +# snapshot from peers instead of fetching and replaying historical blocks. Requires some peers in +# the network to take and serve state machine snapshots. State sync is not attempted if the node +# has any local state (LastBlockHeight > 0). The node will have a truncated block history, +# starting from the height of the snapshot. +enable = false + +# RPC servers (comma-separated) for light client verification of the synced state machine and +# retrieval of state data for node bootstrapping. Also needs a trusted height and corresponding +# header hash obtained from a trusted source, and a period during which validators can be trusted. +# +# For Cosmos SDK-based chains, trust_period should usually be about 2/3 of the unbonding time (~2 +# weeks) during which they can be financially punished (slashed) for misbehavior. +rpc_servers = "" +trust_height = 0 +trust_hash = "" +trust_period = "168h0m0s" + +# Time to spend discovering snapshots before initiating a restore. +discovery_time = "15s" + +# Temporary directory for state sync snapshot chunks, defaults to the OS tempdir (typically /tmp). +# Will create a new, randomly named directory within, and remove it when done. +temp_dir = "" + +# The timeout duration before re-requesting a chunk, possibly from a different +# peer (default: 1 minute). +chunk_request_timeout = "10s" + +# The number of concurrent chunk fetchers to run (default: 1). +chunk_fetchers = "4" + +####################################################### +### Fast Sync Configuration Connections ### +####################################################### +[fastsync] + +# Fast Sync version to use: +# 1) "v0" (default) - the legacy fast sync implementation +# 2) "v1" - refactor of v0 version for better testability +# 2) "v2" - complete redesign of v0, optimized for testability & readability +version = "v0" + +####################################################### +### Consensus Configuration Options ### +####################################################### +[consensus] + +wal_file = "data/cs.wal/wal" + +# How long we wait for a proposal block before prevoting nil +timeout_propose = "1s" +# How much timeout_propose increases with each round +timeout_propose_delta = "500ms" +# How long we wait after receiving +2/3 prevotes for “anything” (ie. not a single block or nil) +timeout_prevote = "1s" +# How much the timeout_prevote increases with each round +timeout_prevote_delta = "500ms" +# How long we wait after receiving +2/3 precommits for “anything” (ie. not a single block or nil) +timeout_precommit = "1s" +# How much the timeout_precommit increases with each round +timeout_precommit_delta = "500ms" +# How long we wait after committing a block, before starting on the new +# height (this gives us a chance to receive some more precommits, even +# though we already have +2/3). +timeout_commit = "1s" + +# How many blocks to look back to check existence of the node's consensus votes before joining consensus +# When non-zero, the node will panic upon restart +# if the same consensus key was used to sign {double_sign_check_height} last blocks. +# So, validators should stop the state machine, wait for some blocks, and then restart the state machine to avoid panic. +double_sign_check_height = 0 + +# Make progress as soon as we have all the precommits (as if TimeoutCommit = 0) +skip_timeout_commit = false + +# EmptyBlocks mode and possible interval between empty blocks +create_empty_blocks = true +create_empty_blocks_interval = "0s" + +# Reactor sleep duration parameters +peer_gossip_sleep_duration = "100ms" +peer_query_maj23_sleep_duration = "2s" + +####################################################### +### Transaction Indexer Configuration Options ### +####################################################### +[tx_index] + +# What indexer to use for transactions +# +# The application will set which txs to index. In some cases a node operator will be able +# to decide which txs to index based on configuration set in the application. +# +# Options: +# 1) "null" +# 2) "kv" (default) - the simplest possible indexer, backed by key-value storage (defaults to levelDB; see DBBackend). +# - When "kv" is chosen "tx.height" and "tx.hash" will always be indexed. +indexer = "kv" + +####################################################### +### Instrumentation Configuration Options ### +####################################################### +[instrumentation] + +# When true, Prometheus metrics are served under /metrics on +# PrometheusListenAddr. +# Check out the documentation for the list of available metrics. +prometheus = false + +# Address to listen for Prometheus collector(s) connections +prometheus_listen_addr = ":26660" + +# Maximum number of simultaneous connections. +# If you want to accept a larger number than the default, make sure +# you increase your OS limits. +# 0 - unlimited. +max_open_connections = 3 + +# Instrumentation namespace +namespace = "tendermint" diff --git a/ci/chains/gaia/v5.0.8/ibc-1/config/genesis.json b/ci/chains/gaia/v5.0.8/ibc-1/config/genesis.json new file mode 100644 index 000000000..d1177e4ac --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-1/config/genesis.json @@ -0,0 +1,342 @@ +{ + "genesis_time": "2021-11-04T15:47:42.444060916Z", + "chain_id": "ibc-1", + "initial_height": "1", + "consensus_params": { + "block": { + "max_bytes": "22020096", + "max_gas": "-1", + "time_iota_ms": "1000" + }, + "evidence": { + "max_age_num_blocks": "100000", + "max_age_duration": "172800000000000", + "max_bytes": "1048576" + }, + "validator": { + "pub_key_types": [ + "ed25519" + ] + }, + "version": {} + }, + "app_hash": "", + "app_state": { + "auth": { + "params": { + "max_memo_characters": "256", + "tx_sig_limit": "7", + "tx_size_cost_per_byte": "10", + "sig_verify_cost_ed25519": "590", + "sig_verify_cost_secp256k1": "1000" + }, + "accounts": [ + { + "@type": "/cosmos.auth.v1beta1.BaseAccount", + "address": "cosmos1cyy7533l8l3alkmdnqph5rqeu2mdgn9q85ulcx", + "pub_key": null, + "account_number": "0", + "sequence": "0" + }, + { + "@type": "/cosmos.auth.v1beta1.BaseAccount", + "address": "cosmos1j6q82mthnkytmdr63u942g43xkqjcwssw6e2x9", + "pub_key": null, + "account_number": "0", + "sequence": "0" + }, + { + "@type": "/cosmos.auth.v1beta1.BaseAccount", + "address": "cosmos1xaz9g9p9a6lcqznyakd3nc5qu85cz6zuyw5ytv", + "pub_key": null, + "account_number": "0", + "sequence": "0" + } + ] + }, + "bank": { + "params": { + "send_enabled": [], + "default_send_enabled": true + }, + "balances": [ + { + "address": "cosmos1xaz9g9p9a6lcqznyakd3nc5qu85cz6zuyw5ytv", + "coins": [ + { + "denom": "stake", + "amount": "100000000000" + } + ] + }, + { + "address": "cosmos1j6q82mthnkytmdr63u942g43xkqjcwssw6e2x9", + "coins": [ + { + "denom": "samoleans", + "amount": "100000000000" + }, + { + "denom": "stake", + "amount": "100000000000" + } + ] + }, + { + "address": "cosmos1cyy7533l8l3alkmdnqph5rqeu2mdgn9q85ulcx", + "coins": [ + { + "denom": "samoleans", + "amount": "100000000000" + }, + { + "denom": "stake", + "amount": "100000000000" + } + ] + } + ], + "supply": [ + { + "denom": "samoleans", + "amount": "200000000000" + }, + { + "denom": "stake", + "amount": "300000000000" + } + ], + "denom_metadata": [] + }, + "capability": { + "index": "1", + "owners": [] + }, + "crisis": { + "constant_fee": { + "denom": "stake", + "amount": "1000" + } + }, + "distribution": { + "params": { + "community_tax": "0.020000000000000000", + "base_proposer_reward": "0.010000000000000000", + "bonus_proposer_reward": "0.040000000000000000", + "withdraw_addr_enabled": true + }, + "fee_pool": { + "community_pool": [] + }, + "delegator_withdraw_infos": [], + "previous_proposer": "", + "outstanding_rewards": [], + "validator_accumulated_commissions": [], + "validator_historical_rewards": [], + "validator_current_rewards": [], + "delegator_starting_infos": [], + "validator_slash_events": [] + }, + "evidence": { + "evidence": [] + }, + "genutil": { + "gen_txs": [ + { + "body": { + "messages": [ + { + "@type": "/cosmos.staking.v1beta1.MsgCreateValidator", + "description": { + "moniker": "ibc-1", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "commission": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "min_self_delegation": "1", + "delegator_address": "cosmos1xaz9g9p9a6lcqznyakd3nc5qu85cz6zuyw5ytv", + "validator_address": "cosmosvaloper1xaz9g9p9a6lcqznyakd3nc5qu85cz6zup6q38l", + "pubkey": { + "@type": "/cosmos.crypto.ed25519.PubKey", + "key": "Q3lqhqi32SHvUpEqoVMHiRGXbThJ7Sbz98IYFIM+guo=" + }, + "value": { + "denom": "stake", + "amount": "100000000000" + } + } + ], + "memo": "b2617c1100350fcb281cc6749f1f79956222be5a@192.168.50.214:26656", + "timeout_height": "0", + "extension_options": [], + "non_critical_extension_options": [] + }, + "auth_info": { + "signer_infos": [ + { + "public_key": { + "@type": "/cosmos.crypto.secp256k1.PubKey", + "key": "AgfKYVHZJ3hgLBEDTuPJ6yf8akWkCVlsLunRmZ9PVh4w" + }, + "mode_info": { + "single": { + "mode": "SIGN_MODE_DIRECT" + } + }, + "sequence": "0" + } + ], + "fee": { + "amount": [], + "gas_limit": "200000", + "payer": "", + "granter": "" + } + }, + "signatures": [ + "1KY7yzImO543wGvV8kIlxDgUxm6Tcc3ajtLLYV89X/tTX5A12F6IdBBibcU52joSM9eAFg2pUDhWXlFRybqaZA==" + ] + } + ] + }, + "gov": { + "starting_proposal_id": "1", + "deposits": [], + "votes": [], + "proposals": [], + "deposit_params": { + "min_deposit": [ + { + "denom": "stake", + "amount": "10000000" + } + ], + "max_deposit_period": "200s" + }, + "voting_params": { + "voting_period": "200s" + }, + "tally_params": { + "quorum": "0.334000000000000000", + "threshold": "0.500000000000000000", + "veto_threshold": "0.334000000000000000" + } + }, + "ibc": { + "client_genesis": { + "clients": [], + "clients_consensus": [], + "clients_metadata": [], + "params": { + "allowed_clients": [ + "06-solomachine", + "07-tendermint" + ] + }, + "create_localhost": false, + "next_client_sequence": "0" + }, + "connection_genesis": { + "connections": [], + "client_connection_paths": [], + "next_connection_sequence": "0" + }, + "channel_genesis": { + "channels": [], + "acknowledgements": [], + "commitments": [], + "receipts": [], + "send_sequences": [], + "recv_sequences": [], + "ack_sequences": [], + "next_channel_sequence": "0" + } + }, + "liquidity": { + "params": { + "pool_types": [ + { + "id": 1, + "name": "StandardLiquidityPool", + "min_reserve_coin_num": 2, + "max_reserve_coin_num": 2, + "description": "Standard liquidity pool with pool price function X/Y, ESPM constraint, and two kinds of reserve coins" + } + ], + "min_init_deposit_amount": "1000000", + "init_pool_coin_mint_amount": "1000000", + "max_reserve_coin_amount": "0", + "pool_creation_fee": [ + { + "denom": "stake", + "amount": "40000000" + } + ], + "swap_fee_rate": "0.003000000000000000", + "withdraw_fee_rate": "0.000000000000000000", + "max_order_amount_ratio": "0.100000000000000000", + "unit_batch_height": 1, + "circuit_breaker_enabled": false + }, + "pool_records": [] + }, + "mint": { + "minter": { + "inflation": "0.130000000000000000", + "annual_provisions": "0.000000000000000000" + }, + "params": { + "mint_denom": "stake", + "inflation_rate_change": "0.130000000000000000", + "inflation_max": "0.200000000000000000", + "inflation_min": "0.070000000000000000", + "goal_bonded": "0.670000000000000000", + "blocks_per_year": "6311520" + } + }, + "params": null, + "slashing": { + "params": { + "signed_blocks_window": "100", + "min_signed_per_window": "0.500000000000000000", + "downtime_jail_duration": "600s", + "slash_fraction_double_sign": "0.050000000000000000", + "slash_fraction_downtime": "0.010000000000000000" + }, + "signing_infos": [], + "missed_blocks": [] + }, + "staking": { + "params": { + "unbonding_time": "1814400s", + "max_validators": 100, + "max_entries": 7, + "historical_entries": 10000, + "bond_denom": "stake" + }, + "last_total_power": "0", + "last_validator_powers": [], + "validators": [], + "delegations": [], + "unbonding_delegations": [], + "redelegations": [], + "exported": false + }, + "transfer": { + "port_id": "transfer", + "denom_traces": [], + "params": { + "send_enabled": true, + "receive_enabled": true + } + }, + "upgrade": {}, + "vesting": {} + } +} \ No newline at end of file diff --git a/ci/chains/gaia/v5.0.8/ibc-1/config/gentx/gentx-b2617c1100350fcb281cc6749f1f79956222be5a.json b/ci/chains/gaia/v5.0.8/ibc-1/config/gentx/gentx-b2617c1100350fcb281cc6749f1f79956222be5a.json new file mode 100644 index 000000000..f9b223e34 --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-1/config/gentx/gentx-b2617c1100350fcb281cc6749f1f79956222be5a.json @@ -0,0 +1 @@ +{"body":{"messages":[{"@type":"/cosmos.staking.v1beta1.MsgCreateValidator","description":{"moniker":"ibc-1","identity":"","website":"","security_contact":"","details":""},"commission":{"rate":"0.100000000000000000","max_rate":"0.200000000000000000","max_change_rate":"0.010000000000000000"},"min_self_delegation":"1","delegator_address":"cosmos1xaz9g9p9a6lcqznyakd3nc5qu85cz6zuyw5ytv","validator_address":"cosmosvaloper1xaz9g9p9a6lcqznyakd3nc5qu85cz6zup6q38l","pubkey":{"@type":"/cosmos.crypto.ed25519.PubKey","key":"Q3lqhqi32SHvUpEqoVMHiRGXbThJ7Sbz98IYFIM+guo="},"value":{"denom":"stake","amount":"100000000000"}}],"memo":"b2617c1100350fcb281cc6749f1f79956222be5a@192.168.50.214:26656","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[{"public_key":{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"AgfKYVHZJ3hgLBEDTuPJ6yf8akWkCVlsLunRmZ9PVh4w"},"mode_info":{"single":{"mode":"SIGN_MODE_DIRECT"}},"sequence":"0"}],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":["1KY7yzImO543wGvV8kIlxDgUxm6Tcc3ajtLLYV89X/tTX5A12F6IdBBibcU52joSM9eAFg2pUDhWXlFRybqaZA=="]} diff --git a/ci/chains/gaia/v5.0.8/ibc-1/config/node_key.json b/ci/chains/gaia/v5.0.8/ibc-1/config/node_key.json new file mode 100644 index 000000000..1e4f16abf --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-1/config/node_key.json @@ -0,0 +1 @@ +{"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"iEFaFp4baiAkuUQGKLM6cDiEaJ1wNdWKcZmK/vXqmmcDMwlXEQKRIRv/2RDKG75dRAm9vL8oMa448/NUUpJDCA=="}} \ No newline at end of file diff --git a/ci/chains/gaia/v5.0.8/ibc-1/config/priv_validator_key.json b/ci/chains/gaia/v5.0.8/ibc-1/config/priv_validator_key.json new file mode 100644 index 000000000..eec913ba7 --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-1/config/priv_validator_key.json @@ -0,0 +1,11 @@ +{ + "address": "AEC2C6BCE9572CB47610ADE77F3C075DC6B3D717", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "Q3lqhqi32SHvUpEqoVMHiRGXbThJ7Sbz98IYFIM+guo=" + }, + "priv_key": { + "type": "tendermint/PrivKeyEd25519", + "value": "1+GCG7iNUe8caJWcaPhMHxUIcUZPdUo9MIN7UGSv8PZDeWqGqLfZIe9SkSqhUweJEZdtOEntJvP3whgUgz6C6g==" + } +} \ No newline at end of file diff --git a/ci/chains/gaia/v5.0.8/ibc-1/keyring-test/3744541425eebf800a64ed9b19e280e1e981685c.address b/ci/chains/gaia/v5.0.8/ibc-1/keyring-test/3744541425eebf800a64ed9b19e280e1e981685c.address new file mode 100644 index 000000000..518db809e --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-1/keyring-test/3744541425eebf800a64ed9b19e280e1e981685c.address @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMS0xMS0wNCAxMTo0Nzo0My41Mjc4NTQxMTUgLTA0MDAgRURUIG09KzAuMDc0MTQyODI1IiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiT0tGblVsckZOQnBwY1hiOCJ9.v4uS3F3sRZaXHOjSqg7ikPWiPaRcVwlfjvNUFnDhN7ud7ZNn9h29TQ.y3FESL0YTY7Qb198.UBdUf8mh2WtewKbMiDZ1fcw-TvuoMMMkKDyAjhHJRMa0nemizWCyqx_5gdzKkmD00IgZwDKfrT4BCu-axk-Ou6_O__XVerJGVQrgg28gi6dkWWy9Uju3b8KpB-oucibpwffc6JpDMD6KuqhawtzZEHq43yZob-IBIOPJba3MdWaCGgEdf12sHX_ckghjy-ZYExg92M1WID8JwbEfjBp_14FmJcvRICEsfkacs1ceZK0C0Gt63swZ59ue.6saz2fRViVfN_eCAzpS2Iw \ No newline at end of file diff --git a/ci/chains/gaia/v5.0.8/ibc-1/keyring-test/9680756d779d88bdb47a8f0b5522b135812c3a10.address b/ci/chains/gaia/v5.0.8/ibc-1/keyring-test/9680756d779d88bdb47a8f0b5522b135812c3a10.address new file mode 100644 index 000000000..30eb62ba8 --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-1/keyring-test/9680756d779d88bdb47a8f0b5522b135812c3a10.address @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMS0xMS0wNCAxMTo0Nzo0NS42ODk2NDExNiAtMDQwMCBFRFQgbT0rMC4wNjIzMjY4NzEiLCJlbmMiOiJBMjU2R0NNIiwicDJjIjo4MTkyLCJwMnMiOiJnWVV5YlV3b2lLb3lEaGlxIn0.QCgBZNULcfesHuKvVDbDJQDK_LmptOir7iRwtsFlhqe9jvxv2FPNAg.ZuySvpSIgoKLCoRs.cugISI2Y5eEjl2T93YxTy5zZQrK5O5c0FKR-lvlRfiEMd8cDqei4pykU8RiHYKU4H-CPsuLLhRX3S7iooasDoCLdOo9a9MKo861yBx9vayMc0sz-zZN8OCoIyDQ9pa5iHNuzL4kSJOJGUrlQMk3bKNcjALx_-W9qBYQlQ6DN8wnowPL0NqblfdE92aD6cq8DOA1gT8lltMs7Q7psLPKKt18OCyhYi8KSEjQu3HALbPPOiRJHcTE.YSN_T3AQZwJx7k5MMxqhzg \ No newline at end of file diff --git a/ci/chains/gaia/v5.0.8/ibc-1/keyring-test/c109ea463f3fe3dfdb6d98037a0c19e2b6d44ca0.address b/ci/chains/gaia/v5.0.8/ibc-1/keyring-test/c109ea463f3fe3dfdb6d98037a0c19e2b6d44ca0.address new file mode 100644 index 000000000..8c2f468fc --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-1/keyring-test/c109ea463f3fe3dfdb6d98037a0c19e2b6d44ca0.address @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMS0xMS0wNCAxMTo0Nzo0NC42MTM2NzQ5MiAtMDQwMCBFRFQgbT0rMC4wNjg3NjczMTYiLCJlbmMiOiJBMjU2R0NNIiwicDJjIjo4MTkyLCJwMnMiOiJFdFBGZURzSUgzWjlBeE50In0.KwEj3f-Mmxb0t-i5GlKga5zM7jka30UbzYW-Sngyz7jecvjdflkEsw.mTTn8vgmlEJTa9OZ.e3yxoN3gqXU_eUXoeYICL-QcEevYvmp44oOBDTovuQK2jNVJPwLmS0Bp6Pzqe-WHiumBB2OSrA51kHPvj6hWIHRCmO7VQicODLMLSi1o4n3p3jR3pQJepz0JEoc8nMRr-QknJALFNoL1JXR6hSGum2QXFl4u9aBXOwkPStUCJG85UZ36SnXKCRsXvDkC7Z5DLntNxp_WGq2mfh20wJRYcqoPN9o0nVr2YF1JShqIiKfe5g.5e1lpxCz9Fi3pks7vWVFoQ \ No newline at end of file diff --git a/ci/chains/gaia/v5.0.8/ibc-1/keyring-test/user.info b/ci/chains/gaia/v5.0.8/ibc-1/keyring-test/user.info new file mode 100644 index 000000000..7b7f6c3d9 --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-1/keyring-test/user.info @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMS0xMS0wNCAxMTo0Nzo0NC42MDYxNDA1NTggLTA0MDAgRURUIG09KzAuMDYxMjMyOTQzIiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoidTJpNEQ3RmFqZHlXRXFDeCJ9.ylqk8B5MaEwCYmLIukes3XkXxGKkaB6kFMVYNcV0_-5z29vt9WUQ0Q.bvkej9imldLoFWcm.jRKIDMaq2T5grW8s7TtiK8_hMM538Ivi7soGIyDxU3PomUqLlL3ul2L2mgwmcmICm210AToxc3Fx4KIQbf6bB-hesPcfXNQgFsJuTpXAtZ8DrZg22xs_8ZzgllN14LWx6wAGmWsinFUMS_RLslD3CJFddzO39j2UWFJIBKLo8zkfnvIDWbe2Vda0RVrUPiOMbgzqaJM73DDgXxpir-aER2UtSaeBHFbi_DxxNyLrVeS90Lu8A5LfY3WWc681Fv_Cvs8XTIm0VI9dVsq-qFejZNy9dN--jz-x9SJcEMwb_QQ32El7sB1Yo6VfBVWCRvWmGQjDqV68Wg7UNM0biKc4CHzOac2OIHM.Vr8XbTJkkAOAW4cFuZ28OA \ No newline at end of file diff --git a/ci/chains/gaia/v5.0.8/ibc-1/keyring-test/user2.info b/ci/chains/gaia/v5.0.8/ibc-1/keyring-test/user2.info new file mode 100644 index 000000000..45b722ac0 --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-1/keyring-test/user2.info @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMS0xMS0wNCAxMTo0Nzo0NS42ODM2MzI1OTUgLTA0MDAgRURUIG09KzAuMDU2MzE4MzI3IiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiYXgwVTVtZ29sRmxUMEZFNCJ9.yaKh9b08Pi26qhmKuwG2GgMgmDWY_KV6zb1yJ_I8-JZHlg61QN146Q.AFqz4pfoU65bFkza.vHSXUU9ElCcFpHuyOr_lf3FuSfobS6Nn98YXNjOcsj5tcw08zFb3jTeMd90U4b2yVl-g_jUzBwz6tVTsMvKXjEyyQP4zbLK9RiYAvo2d4Qfz6Cqof7lpFE1nrs8hzER7rTkyEoZ37Bfl6D-cHWLZip4Wlv8v1GEGrbQnvRRpUNhBWRNHoR_ZvD47C_KRZH2DdT-ieLJRMB1pIVWMjgATQdhfimBwlfBNFph54ajPnc33nEx5YVwgUXqmZBeJYoiNUO5MmwR1EYHyLtKQUFzvkvj_nzkANbog2xJLYcLuUaw2JLc0faPp5gsUZnUer5ms18FoFKsd80eRaZ4nCXWfvERDRl_812qj.IIfR3WCV_7WYXUbytSzgvA \ No newline at end of file diff --git a/ci/chains/gaia/v5.0.8/ibc-1/keyring-test/validator.info b/ci/chains/gaia/v5.0.8/ibc-1/keyring-test/validator.info new file mode 100644 index 000000000..95b59b0c6 --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-1/keyring-test/validator.info @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMS0xMS0wNCAxMTo0Nzo0My41MTkwMDQyNzIgLTA0MDAgRURUIG09KzAuMDY1MjkyOTkxIiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiVUFZVzROV0NGU0NIMG5fUCJ9.jgdjIazR7B2dqQ-d2G_C8ViJN6jcaVzwSHZJyD4huBtEa7LkpzCxxQ.pgLPbRYyu2l6RUKY.FXQaljl1rrsxyMqjGKyJzN2GQQdrB34LYqQWSSYSnc5TfevEYyc7QwFbgeu-DIAqo_xxmmBTLGftY1X_R5WCpmXqyhOkxVKpPSsrHsSwBdNalxa9AHyQB27RbMOe-gqte3MyUd0XXaTl365nLA7vCPiJnGsNUDjOLbu-lEJWm3bN36daH43Ifb1BACYH7TndPU3c8hOOmyxHVlvYHyZutVfqCh9kr80GIXVTYwWTV5LMcKGtgfc-VmljYGAaI7IqdeiMlsZcr_l8TSeHZHNFGxZXc8jBHezMxr8qnD_p2UKnYylIPTfu4U_Ea0yeWHuIQBCyWTXyf02Bf88foTXGJNiScIWJxLTLdbVtem59pT6OCA5x.IErhLYYhkKMX_UlVlDtXxQ \ No newline at end of file diff --git a/ci/chains/gaia/v5.0.8/ibc-1/user2_seed.json b/ci/chains/gaia/v5.0.8/ibc-1/user2_seed.json new file mode 100644 index 000000000..48cde5610 --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-1/user2_seed.json @@ -0,0 +1 @@ +{"name":"user2","type":"local","address":"cosmos1j6q82mthnkytmdr63u942g43xkqjcwssw6e2x9","pubkey":"cosmospub1addwnpepqdjxwx0t2kj2qyw4q6gj8mr40y6mtljdsa7u6hhhteaw32vshnucj59wprp","mnemonic":"nurse ordinary pulp find square senior club great balcony monster faint glass arrest curve message orange fan syrup pepper smoke medal tent sheriff grocery"} diff --git a/ci/chains/gaia/v5.0.8/ibc-1/user_seed.json b/ci/chains/gaia/v5.0.8/ibc-1/user_seed.json new file mode 100644 index 000000000..4b94f9d06 --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-1/user_seed.json @@ -0,0 +1 @@ +{"name":"user","type":"local","address":"cosmos1cyy7533l8l3alkmdnqph5rqeu2mdgn9q85ulcx","pubkey":"cosmospub1addwnpepqd8rasvzjylp56ezk3ydvrte0k8s9gw3a3au00rdqapu80tqqk66q4sae27","mnemonic":"toddler strategy wine bridge short position animal brown cream slogan merry beach dust exhibit stem wire once offer name van pilot code course observe"} diff --git a/ci/chains/gaia/v5.0.8/ibc-1/validator_seed.json b/ci/chains/gaia/v5.0.8/ibc-1/validator_seed.json new file mode 100644 index 000000000..eeb2b0001 --- /dev/null +++ b/ci/chains/gaia/v5.0.8/ibc-1/validator_seed.json @@ -0,0 +1 @@ +{"name":"validator","type":"local","address":"cosmos1xaz9g9p9a6lcqznyakd3nc5qu85cz6zuyw5ytv","pubkey":"cosmospub1addwnpepqgru5c23mynhscpvzyp5ac7favnlc6j95sy4jmpwa8gen8602c0rqemmd7c","mnemonic":"prepare detect federal maple ability require blood slam hazard universe soon bubble simple canal rapid style proud thing horn warfare galaxy wood exhaust advance"} diff --git a/ci/chains/gaia/v6.0.0/ibc-0/config/addrbook.json b/ci/chains/gaia/v6.0.0/ibc-0/config/addrbook.json new file mode 100644 index 000000000..388c554d6 --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-0/config/addrbook.json @@ -0,0 +1,4 @@ +{ + "key": "abcfca3214aae21d8fb33c29", + "addrs": [] +} \ No newline at end of file diff --git a/ci/chains/gaia/v6.0.0/ibc-0/config/app.toml b/ci/chains/gaia/v6.0.0/ibc-0/config/app.toml new file mode 100644 index 000000000..1fc0b791f --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-0/config/app.toml @@ -0,0 +1,192 @@ +# This is a TOML config file. +# For more information, see https://github.com/toml-lang/toml + +############################################################################### +### Base Configuration ### +############################################################################### + +# The minimum gas prices a validator is willing to accept for processing a +# transaction. A transaction's fees must meet the minimum of any denomination +# specified in this config (e.g. 0.25token1;0.0001token2). +minimum-gas-prices = "" + +# default: the last 100 states are kept in addition to every 500th state; pruning at 10 block intervals +# nothing: all historic states will be saved, nothing will be deleted (i.e. archiving node) +# everything: all saved states will be deleted, storing only the current state; pruning at 10 block intervals +# custom: allow pruning options to be manually specified through 'pruning-keep-recent', 'pruning-keep-every', and 'pruning-interval' +pruning = "default" + +# These are applied if and only if the pruning strategy is custom. +pruning-keep-recent = "0" +pruning-keep-every = "0" +pruning-interval = "0" + +# HaltHeight contains a non-zero block height at which a node will gracefully +# halt and shutdown that can be used to assist upgrades and testing. +# +# Note: Commitment of state will be attempted on the corresponding block. +halt-height = 0 + +# HaltTime contains a non-zero minimum block time (in Unix seconds) at which +# a node will gracefully halt and shutdown that can be used to assist upgrades +# and testing. +# +# Note: Commitment of state will be attempted on the corresponding block. +halt-time = 0 + +# MinRetainBlocks defines the minimum block height offset from the current +# block being committed, such that all blocks past this offset are pruned +# from Tendermint. It is used as part of the process of determining the +# ResponseCommit.RetainHeight value during ABCI Commit. A value of 0 indicates +# that no blocks should be pruned. +# +# This configuration value is only responsible for pruning Tendermint blocks. +# It has no bearing on application state pruning which is determined by the +# "pruning-*" configurations. +# +# Note: Tendermint block pruning is dependant on this parameter in conunction +# with the unbonding (safety threshold) period, state pruning and state sync +# snapshot parameters to determine the correct minimum value of +# ResponseCommit.RetainHeight. +min-retain-blocks = 0 + +# InterBlockCache enables inter-block caching. +inter-block-cache = true + +# IndexEvents defines the set of events in the form {eventType}.{attributeKey}, +# which informs Tendermint what to index. If empty, all events will be indexed. +# +# Example: +# ["message.sender", "message.recipient"] +index-events = [] + +############################################################################### +### Telemetry Configuration ### +############################################################################### + +[telemetry] + +# Prefixed with keys to separate services. +service-name = "" + +# Enabled enables the application telemetry functionality. When enabled, +# an in-memory sink is also enabled by default. Operators may also enabled +# other sinks such as Prometheus. +enabled = false + +# Enable prefixing gauge values with hostname. +enable-hostname = false + +# Enable adding hostname to labels. +enable-hostname-label = false + +# Enable adding service to labels. +enable-service-label = false + +# PrometheusRetentionTime, when positive, enables a Prometheus metrics sink. +prometheus-retention-time = 0 + +# GlobalLabels defines a global set of name/value label tuples applied to all +# metrics emitted using the wrapper functions defined in telemetry package. +# +# Example: +# [["chain_id", "cosmoshub-1"]] +global-labels = [ +] + +############################################################################### +### API Configuration ### +############################################################################### + +[api] + +# Enable defines if the API server should be enabled. +enable = false + +# Swagger defines if swagger documentation should automatically be registered. +swagger = false + +# Address defines the API server to listen on. +address = "tcp://0.0.0.0:1317" + +# MaxOpenConnections defines the number of maximum open connections. +max-open-connections = 1000 + +# RPCReadTimeout defines the Tendermint RPC read timeout (in seconds). +rpc-read-timeout = 10 + +# RPCWriteTimeout defines the Tendermint RPC write timeout (in seconds). +rpc-write-timeout = 0 + +# RPCMaxBodyBytes defines the Tendermint maximum response body (in bytes). +rpc-max-body-bytes = 1000000 + +# EnableUnsafeCORS defines if CORS should be enabled (unsafe - use it at your own risk). +enabled-unsafe-cors = false + +############################################################################### +### Rosetta Configuration ### +############################################################################### + +[rosetta] + +# Enable defines if the Rosetta API server should be enabled. +enable = false + +# Address defines the Rosetta API server to listen on. +address = ":8080" + +# Network defines the name of the blockchain that will be returned by Rosetta. +blockchain = "app" + +# Network defines the name of the network that will be returned by Rosetta. +network = "network" + +# Retries defines the number of retries when connecting to the node before failing. +retries = 3 + +# Offline defines if Rosetta server should run in offline mode. +offline = false + +############################################################################### +### gRPC Configuration ### +############################################################################### + +[grpc] + +# Enable defines if the gRPC server should be enabled. +enable = true + +# Address defines the gRPC server address to bind to. +address = "0.0.0.0:9090" + +############################################################################### +### gRPC Web Configuration ### +############################################################################### + +[grpc-web] + +# GRPCWebEnable defines if the gRPC-web should be enabled. +# NOTE: gRPC must also be enabled, otherwise, this configuration is a no-op. +enable = true + +# Address defines the gRPC-web server address to bind to. +address = "0.0.0.0:9091" + +# EnableUnsafeCORS defines if CORS should be enabled (unsafe - use it at your own risk). +enable-unsafe-cors = false + +############################################################################### +### State Sync Configuration ### +############################################################################### + +# State sync snapshots allow other nodes to rapidly join the network without replaying historical +# blocks, instead downloading and applying a snapshot of the application state at a given height. +[state-sync] + +# snapshot-interval specifies the block interval at which local state sync snapshots are +# taken (0 to disable). Must be a multiple of pruning-keep-every. +snapshot-interval = 0 + +# snapshot-keep-recent specifies the number of recent snapshots to keep and serve (0 to keep all). +snapshot-keep-recent = 2 diff --git a/ci/chains/gaia/v6.0.0/ibc-0/config/client.toml b/ci/chains/gaia/v6.0.0/ibc-0/config/client.toml new file mode 100644 index 000000000..222695a3f --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-0/config/client.toml @@ -0,0 +1,17 @@ +# This is a TOML config file. +# For more information, see https://github.com/toml-lang/toml + +############################################################################### +### Client Configuration ### +############################################################################### + +# The network chain ID +chain-id = "" +# The keyring's backend, where the keys are stored (os|file|kwallet|pass|test|memory) +keyring-backend = "os" +# CLI output format (text|json) +output = "text" +# : to Tendermint RPC interface for this chain +node = "tcp://localhost:26657" +# Transaction broadcasting mode (sync|async|block) +broadcast-mode = "sync" diff --git a/ci/chains/gaia/v6.0.0/ibc-0/config/config.toml b/ci/chains/gaia/v6.0.0/ibc-0/config/config.toml new file mode 100644 index 000000000..eb6f4b295 --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-0/config/config.toml @@ -0,0 +1,401 @@ +# This is a TOML config file. +# For more information, see https://github.com/toml-lang/toml + +# NOTE: Any path below can be absolute (e.g. "/var/myawesomeapp/data") or +# relative to the home directory (e.g. "data"). The home directory is +# "$HOME/.tendermint" by default, but could be changed via $TMHOME env variable +# or --home cmd flag. + +####################################################################### +### Main Base Config Options ### +####################################################################### + +# TCP or UNIX socket address of the ABCI application, +# or the name of an ABCI application compiled in with the Tendermint binary +proxy_app = "tcp://127.0.0.1:26658" + +# A custom human readable name for this node +moniker = "ibc-0" + +# If this node is many blocks behind the tip of the chain, FastSync +# allows them to catchup quickly by downloading blocks in parallel +# and verifying their commits +fast_sync = true + +# Database backend: goleveldb | cleveldb | boltdb | rocksdb | badgerdb +# * goleveldb (github.com/syndtr/goleveldb - most popular implementation) +# - pure go +# - stable +# * cleveldb (uses levigo wrapper) +# - fast +# - requires gcc +# - use cleveldb build tag (go build -tags cleveldb) +# * boltdb (uses etcd's fork of bolt - github.com/etcd-io/bbolt) +# - EXPERIMENTAL +# - may be faster is some use-cases (random reads - indexer) +# - use boltdb build tag (go build -tags boltdb) +# * rocksdb (uses github.com/tecbot/gorocksdb) +# - EXPERIMENTAL +# - requires gcc +# - use rocksdb build tag (go build -tags rocksdb) +# * badgerdb (uses github.com/dgraph-io/badger) +# - EXPERIMENTAL +# - use badgerdb build tag (go build -tags badgerdb) +db_backend = "goleveldb" + +# Database directory +db_dir = "data" + +# Output level for logging, including package level options +log_level = "info" + +# Output format: 'plain' (colored text) or 'json' +log_format = "plain" + +##### additional base config options ##### + +# Path to the JSON file containing the initial validator set and other meta data +genesis_file = "config/genesis.json" + +# Path to the JSON file containing the private key to use as a validator in the consensus protocol +priv_validator_key_file = "config/priv_validator_key.json" + +# Path to the JSON file containing the last sign state of a validator +priv_validator_state_file = "data/priv_validator_state.json" + +# TCP or UNIX socket address for Tendermint to listen on for +# connections from an external PrivValidator process +priv_validator_laddr = "" + +# Path to the JSON file containing the private key to use for node authentication in the p2p protocol +node_key_file = "config/node_key.json" + +# Mechanism to connect to the ABCI application: socket | grpc +abci = "socket" + +# If true, query the ABCI app on connecting to a new peer +# so the app can decide if we should keep the connection or not +filter_peers = false + + +####################################################################### +### Advanced Configuration Options ### +####################################################################### + +####################################################### +### RPC Server Configuration Options ### +####################################################### +[rpc] + +# TCP or UNIX socket address for the RPC server to listen on +laddr = "tcp://0.0.0.0:26657" + +# A list of origins a cross-domain request can be executed from +# Default value '[]' disables cors support +# Use '["*"]' to allow any origin +cors_allowed_origins = [] + +# A list of methods the client is allowed to use with cross-domain requests +cors_allowed_methods = ["HEAD", "GET", "POST", ] + +# A list of non simple headers the client is allowed to use with cross-domain requests +cors_allowed_headers = ["Origin", "Accept", "Content-Type", "X-Requested-With", "X-Server-Time", ] + +# TCP or UNIX socket address for the gRPC server to listen on +# NOTE: This server only supports /broadcast_tx_commit +grpc_laddr = "" + +# Maximum number of simultaneous connections. +# Does not include RPC (HTTP&WebSocket) connections. See max_open_connections +# If you want to accept a larger number than the default, make sure +# you increase your OS limits. +# 0 - unlimited. +# Should be < {ulimit -Sn} - {MaxNumInboundPeers} - {MaxNumOutboundPeers} - {N of wal, db and other open files} +# 1024 - 40 - 10 - 50 = 924 = ~900 +grpc_max_open_connections = 900 + +# Activate unsafe RPC commands like /dial_seeds and /unsafe_flush_mempool +unsafe = false + +# Maximum number of simultaneous connections (including WebSocket). +# Does not include gRPC connections. See grpc_max_open_connections +# If you want to accept a larger number than the default, make sure +# you increase your OS limits. +# 0 - unlimited. +# Should be < {ulimit -Sn} - {MaxNumInboundPeers} - {MaxNumOutboundPeers} - {N of wal, db and other open files} +# 1024 - 40 - 10 - 50 = 924 = ~900 +max_open_connections = 900 + +# Maximum number of unique clientIDs that can /subscribe +# If you're using /broadcast_tx_commit, set to the estimated maximum number +# of broadcast_tx_commit calls per block. +max_subscription_clients = 100 + +# Maximum number of unique queries a given client can /subscribe to +# If you're using GRPC (or Local RPC client) and /broadcast_tx_commit, set to +# the estimated # maximum number of broadcast_tx_commit calls per block. +max_subscriptions_per_client = 5 + +# How long to wait for a tx to be committed during /broadcast_tx_commit. +# WARNING: Using a value larger than 10s will result in increasing the +# global HTTP write timeout, which applies to all connections and endpoints. +# See https://github.com/tendermint/tendermint/issues/3435 +timeout_broadcast_tx_commit = "10s" + +# Maximum size of request body, in bytes +max_body_bytes = 1000000 + +# Maximum size of request header, in bytes +max_header_bytes = 1048576 + +# The path to a file containing certificate that is used to create the HTTPS server. +# Might be either absolute path or path related to Tendermint's config directory. +# If the certificate is signed by a certificate authority, +# the certFile should be the concatenation of the server's certificate, any intermediates, +# and the CA's certificate. +# NOTE: both tls_cert_file and tls_key_file must be present for Tendermint to create HTTPS server. +# Otherwise, HTTP server is run. +tls_cert_file = "" + +# The path to a file containing matching private key that is used to create the HTTPS server. +# Might be either absolute path or path related to Tendermint's config directory. +# NOTE: both tls-cert-file and tls-key-file must be present for Tendermint to create HTTPS server. +# Otherwise, HTTP server is run. +tls_key_file = "" + +# pprof listen address (https://golang.org/pkg/net/http/pprof) +pprof_laddr = "localhost:6060" + +####################################################### +### P2P Configuration Options ### +####################################################### +[p2p] + +# Address to listen for incoming connections +laddr = "tcp://0.0.0.0:26656" + +# Address to advertise to peers for them to dial +# If empty, will use the same port as the laddr, +# and will introspect on the listener or use UPnP +# to figure out the address. ip and port are required +# example: 159.89.10.97:26656 +external_address = "" + +# Comma separated list of seed nodes to connect to +seeds = "" + +# Comma separated list of nodes to keep persistent connections to +persistent_peers = "" + +# UPNP port forwarding +upnp = false + +# Path to address book +addr_book_file = "config/addrbook.json" + +# Set true for strict address routability rules +# Set false for private or local networks +addr_book_strict = true + +# Maximum number of inbound peers +max_num_inbound_peers = 40 + +# Maximum number of outbound peers to connect to, excluding persistent peers +max_num_outbound_peers = 10 + +# List of node IDs, to which a connection will be (re)established ignoring any existing limits +unconditional_peer_ids = "" + +# Maximum pause when redialing a persistent peer (if zero, exponential backoff is used) +persistent_peers_max_dial_period = "0s" + +# Time to wait before flushing messages out on the connection +flush_throttle_timeout = "100ms" + +# Maximum size of a message packet payload, in bytes +max_packet_msg_payload_size = 1024 + +# Rate at which packets can be sent, in bytes/second +send_rate = 5120000 + +# Rate at which packets can be received, in bytes/second +recv_rate = 5120000 + +# Set true to enable the peer-exchange reactor +pex = true + +# Seed mode, in which node constantly crawls the network and looks for +# peers. If another node asks it for addresses, it responds and disconnects. +# +# Does not work if the peer-exchange reactor is disabled. +seed_mode = false + +# Comma separated list of peer IDs to keep private (will not be gossiped to other peers) +private_peer_ids = "" + +# Toggle to disable guard against peers connecting from the same ip. +allow_duplicate_ip = false + +# Peer connection configuration. +handshake_timeout = "20s" +dial_timeout = "3s" + +####################################################### +### Mempool Configuration Option ### +####################################################### +[mempool] + +recheck = true +broadcast = true +wal_dir = "" + +# Maximum number of transactions in the mempool +size = 5000 + +# Limit the total size of all txs in the mempool. +# This only accounts for raw transactions (e.g. given 1MB transactions and +# max_txs_bytes=5MB, mempool will only accept 5 transactions). +max_txs_bytes = 1073741824 + +# Size of the cache (used to filter transactions we saw earlier) in transactions +cache_size = 10000 + +# Do not remove invalid transactions from the cache (default: false) +# Set to true if it's not possible for any invalid transaction to become valid +# again in the future. +keep-invalid-txs-in-cache = false + +# Maximum size of a single transaction. +# NOTE: the max size of a tx transmitted over the network is {max_tx_bytes}. +max_tx_bytes = 1048576 + +# Maximum size of a batch of transactions to send to a peer +# Including space needed by encoding (one varint per transaction). +# XXX: Unused due to https://github.com/tendermint/tendermint/issues/5796 +max_batch_bytes = 0 + +####################################################### +### State Sync Configuration Options ### +####################################################### +[statesync] +# State sync rapidly bootstraps a new node by discovering, fetching, and restoring a state machine +# snapshot from peers instead of fetching and replaying historical blocks. Requires some peers in +# the network to take and serve state machine snapshots. State sync is not attempted if the node +# has any local state (LastBlockHeight > 0). The node will have a truncated block history, +# starting from the height of the snapshot. +enable = false + +# RPC servers (comma-separated) for light client verification of the synced state machine and +# retrieval of state data for node bootstrapping. Also needs a trusted height and corresponding +# header hash obtained from a trusted source, and a period during which validators can be trusted. +# +# For Cosmos SDK-based chains, trust_period should usually be about 2/3 of the unbonding time (~2 +# weeks) during which they can be financially punished (slashed) for misbehavior. +rpc_servers = "" +trust_height = 0 +trust_hash = "" +trust_period = "168h0m0s" + +# Time to spend discovering snapshots before initiating a restore. +discovery_time = "15s" + +# Temporary directory for state sync snapshot chunks, defaults to the OS tempdir (typically /tmp). +# Will create a new, randomly named directory within, and remove it when done. +temp_dir = "" + +# The timeout duration before re-requesting a chunk, possibly from a different +# peer (default: 1 minute). +chunk_request_timeout = "10s" + +# The number of concurrent chunk fetchers to run (default: 1). +chunk_fetchers = "4" + +####################################################### +### Fast Sync Configuration Connections ### +####################################################### +[fastsync] + +# Fast Sync version to use: +# 1) "v0" (default) - the legacy fast sync implementation +# 2) "v1" - refactor of v0 version for better testability +# 2) "v2" - complete redesign of v0, optimized for testability & readability +version = "v0" + +####################################################### +### Consensus Configuration Options ### +####################################################### +[consensus] + +wal_file = "data/cs.wal/wal" + +# How long we wait for a proposal block before prevoting nil +timeout_propose = "1s" +# How much timeout_propose increases with each round +timeout_propose_delta = "500ms" +# How long we wait after receiving +2/3 prevotes for “anything” (ie. not a single block or nil) +timeout_prevote = "1s" +# How much the timeout_prevote increases with each round +timeout_prevote_delta = "500ms" +# How long we wait after receiving +2/3 precommits for “anything” (ie. not a single block or nil) +timeout_precommit = "1s" +# How much the timeout_precommit increases with each round +timeout_precommit_delta = "500ms" +# How long we wait after committing a block, before starting on the new +# height (this gives us a chance to receive some more precommits, even +# though we already have +2/3). +timeout_commit = "1s" + +# How many blocks to look back to check existence of the node's consensus votes before joining consensus +# When non-zero, the node will panic upon restart +# if the same consensus key was used to sign {double_sign_check_height} last blocks. +# So, validators should stop the state machine, wait for some blocks, and then restart the state machine to avoid panic. +double_sign_check_height = 0 + +# Make progress as soon as we have all the precommits (as if TimeoutCommit = 0) +skip_timeout_commit = false + +# EmptyBlocks mode and possible interval between empty blocks +create_empty_blocks = true +create_empty_blocks_interval = "0s" + +# Reactor sleep duration parameters +peer_gossip_sleep_duration = "100ms" +peer_query_maj23_sleep_duration = "2s" + +####################################################### +### Transaction Indexer Configuration Options ### +####################################################### +[tx_index] + +# What indexer to use for transactions +# +# The application will set which txs to index. In some cases a node operator will be able +# to decide which txs to index based on configuration set in the application. +# +# Options: +# 1) "null" +# 2) "kv" (default) - the simplest possible indexer, backed by key-value storage (defaults to levelDB; see DBBackend). +# - When "kv" is chosen "tx.height" and "tx.hash" will always be indexed. +indexer = "kv" + +####################################################### +### Instrumentation Configuration Options ### +####################################################### +[instrumentation] + +# When true, Prometheus metrics are served under /metrics on +# PrometheusListenAddr. +# Check out the documentation for the list of available metrics. +prometheus = false + +# Address to listen for Prometheus collector(s) connections +prometheus_listen_addr = ":26660" + +# Maximum number of simultaneous connections. +# If you want to accept a larger number than the default, make sure +# you increase your OS limits. +# 0 - unlimited. +max_open_connections = 3 + +# Instrumentation namespace +namespace = "tendermint" diff --git a/ci/chains/gaia/v6.0.0/ibc-0/config/genesis.json b/ci/chains/gaia/v6.0.0/ibc-0/config/genesis.json new file mode 100644 index 000000000..caa8b3f63 --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-0/config/genesis.json @@ -0,0 +1,356 @@ +{ + "genesis_time": "2021-11-24T19:33:05.288086182Z", + "chain_id": "ibc-0", + "initial_height": "1", + "consensus_params": { + "block": { + "max_bytes": "22020096", + "max_gas": "-1", + "time_iota_ms": "1000" + }, + "evidence": { + "max_age_num_blocks": "100000", + "max_age_duration": "172800000000000", + "max_bytes": "1048576" + }, + "validator": { + "pub_key_types": [ + "ed25519" + ] + }, + "version": {} + }, + "app_hash": "", + "app_state": { + "auth": { + "params": { + "max_memo_characters": "256", + "tx_sig_limit": "7", + "tx_size_cost_per_byte": "10", + "sig_verify_cost_ed25519": "590", + "sig_verify_cost_secp256k1": "1000" + }, + "accounts": [ + { + "@type": "/cosmos.auth.v1beta1.BaseAccount", + "address": "cosmos1n0gwen2cakk64kk74yguhw3au6rctlyxf5rvmj", + "pub_key": null, + "account_number": "0", + "sequence": "0" + }, + { + "@type": "/cosmos.auth.v1beta1.BaseAccount", + "address": "cosmos1rdy5sg55yp45q3rklpqwhprg5zdlg7tzuxdlhj", + "pub_key": null, + "account_number": "0", + "sequence": "0" + }, + { + "@type": "/cosmos.auth.v1beta1.BaseAccount", + "address": "cosmos1da0qjh7qptrscq59uaqjwtte0ru7mnfp2ndcxu", + "pub_key": null, + "account_number": "0", + "sequence": "0" + } + ] + }, + "authz": { + "authorization": [] + }, + "bank": { + "params": { + "send_enabled": [], + "default_send_enabled": true + }, + "balances": [ + { + "address": "cosmos1rdy5sg55yp45q3rklpqwhprg5zdlg7tzuxdlhj", + "coins": [ + { + "denom": "samoleans", + "amount": "100000000000" + }, + { + "denom": "stake", + "amount": "100000000000" + } + ] + }, + { + "address": "cosmos1da0qjh7qptrscq59uaqjwtte0ru7mnfp2ndcxu", + "coins": [ + { + "denom": "stake", + "amount": "100000000000" + } + ] + }, + { + "address": "cosmos1n0gwen2cakk64kk74yguhw3au6rctlyxf5rvmj", + "coins": [ + { + "denom": "samoleans", + "amount": "100000000000" + }, + { + "denom": "stake", + "amount": "100000000000" + } + ] + } + ], + "supply": [ + { + "denom": "samoleans", + "amount": "200000000000" + }, + { + "denom": "stake", + "amount": "300000000000" + } + ], + "denom_metadata": [] + }, + "capability": { + "index": "1", + "owners": [] + }, + "crisis": { + "constant_fee": { + "denom": "stake", + "amount": "1000" + } + }, + "distribution": { + "params": { + "community_tax": "0.020000000000000000", + "base_proposer_reward": "0.010000000000000000", + "bonus_proposer_reward": "0.040000000000000000", + "withdraw_addr_enabled": true + }, + "fee_pool": { + "community_pool": [] + }, + "delegator_withdraw_infos": [], + "previous_proposer": "", + "outstanding_rewards": [], + "validator_accumulated_commissions": [], + "validator_historical_rewards": [], + "validator_current_rewards": [], + "delegator_starting_infos": [], + "validator_slash_events": [] + }, + "evidence": { + "evidence": [] + }, + "feegrant": { + "allowances": [] + }, + "genutil": { + "gen_txs": [ + { + "body": { + "messages": [ + { + "@type": "/cosmos.staking.v1beta1.MsgCreateValidator", + "description": { + "moniker": "ibc-0", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "commission": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "min_self_delegation": "1", + "delegator_address": "cosmos1da0qjh7qptrscq59uaqjwtte0ru7mnfp2ndcxu", + "validator_address": "cosmosvaloper1da0qjh7qptrscq59uaqjwtte0ru7mnfp08ed20", + "pubkey": { + "@type": "/cosmos.crypto.ed25519.PubKey", + "key": "NYFNoMsPbFYg4H/WodS6spPKJuYsFWOz/uEQMxiA7Mk=" + }, + "value": { + "denom": "stake", + "amount": "100000000000" + } + } + ], + "memo": "f8825df2c406207c64cbc02b1f543a53a46094e3@192.168.50.214:26656", + "timeout_height": "0", + "extension_options": [], + "non_critical_extension_options": [] + }, + "auth_info": { + "signer_infos": [ + { + "public_key": { + "@type": "/cosmos.crypto.secp256k1.PubKey", + "key": "AoMRzDhz5CdelMYvXq/YUvy/pJTub9JJ8SV8yqTlyOmc" + }, + "mode_info": { + "single": { + "mode": "SIGN_MODE_DIRECT" + } + }, + "sequence": "0" + } + ], + "fee": { + "amount": [], + "gas_limit": "200000", + "payer": "", + "granter": "" + } + }, + "signatures": [ + "fo1Cp9mv2cOpF+bpO0z+emIzeALBVhyyslZ29mvP2QJU7kCbq1KPeQ6xrQMJWNo5IiEvs0JBdhRHEC08Fbbp6Q==" + ] + } + ] + }, + "gov": { + "starting_proposal_id": "1", + "deposits": [], + "votes": [], + "proposals": [], + "deposit_params": { + "min_deposit": [ + { + "denom": "stake", + "amount": "10000000" + } + ], + "max_deposit_period": "200s" + }, + "voting_params": { + "voting_period": "200s" + }, + "tally_params": { + "quorum": "0.334000000000000000", + "threshold": "0.500000000000000000", + "veto_threshold": "0.334000000000000000" + } + }, + "ibc": { + "client_genesis": { + "clients": [], + "clients_consensus": [], + "clients_metadata": [], + "params": { + "allowed_clients": [ + "06-solomachine", + "07-tendermint" + ] + }, + "create_localhost": false, + "next_client_sequence": "0" + }, + "connection_genesis": { + "connections": [], + "client_connection_paths": [], + "next_connection_sequence": "0", + "params": { + "max_expected_time_per_block": "30000000000" + } + }, + "channel_genesis": { + "channels": [], + "acknowledgements": [], + "commitments": [], + "receipts": [], + "send_sequences": [], + "recv_sequences": [], + "ack_sequences": [], + "next_channel_sequence": "0" + } + }, + "liquidity": { + "params": { + "pool_types": [ + { + "id": 1, + "name": "StandardLiquidityPool", + "min_reserve_coin_num": 2, + "max_reserve_coin_num": 2, + "description": "Standard liquidity pool with pool price function X/Y, ESPM constraint, and two kinds of reserve coins" + } + ], + "min_init_deposit_amount": "1000000", + "init_pool_coin_mint_amount": "1000000", + "max_reserve_coin_amount": "0", + "pool_creation_fee": [ + { + "denom": "stake", + "amount": "40000000" + } + ], + "swap_fee_rate": "0.003000000000000000", + "withdraw_fee_rate": "0.000000000000000000", + "max_order_amount_ratio": "0.100000000000000000", + "unit_batch_height": 1, + "circuit_breaker_enabled": false + }, + "pool_records": [] + }, + "mint": { + "minter": { + "inflation": "0.130000000000000000", + "annual_provisions": "0.000000000000000000" + }, + "params": { + "mint_denom": "stake", + "inflation_rate_change": "0.130000000000000000", + "inflation_max": "0.200000000000000000", + "inflation_min": "0.070000000000000000", + "goal_bonded": "0.670000000000000000", + "blocks_per_year": "6311520" + } + }, + "packetfowardmiddleware": { + "params": { + "fee_percentage": "0.000000000000000000" + } + }, + "params": null, + "slashing": { + "params": { + "signed_blocks_window": "100", + "min_signed_per_window": "0.500000000000000000", + "downtime_jail_duration": "600s", + "slash_fraction_double_sign": "0.050000000000000000", + "slash_fraction_downtime": "0.010000000000000000" + }, + "signing_infos": [], + "missed_blocks": [] + }, + "staking": { + "params": { + "unbonding_time": "1814400s", + "max_validators": 100, + "max_entries": 7, + "historical_entries": 10000, + "bond_denom": "stake" + }, + "last_total_power": "0", + "last_validator_powers": [], + "validators": [], + "delegations": [], + "unbonding_delegations": [], + "redelegations": [], + "exported": false + }, + "transfer": { + "port_id": "transfer", + "denom_traces": [], + "params": { + "send_enabled": true, + "receive_enabled": true + } + }, + "upgrade": {}, + "vesting": {} + } +} \ No newline at end of file diff --git a/ci/chains/gaia/v6.0.0/ibc-0/config/gentx/gentx-f8825df2c406207c64cbc02b1f543a53a46094e3.json b/ci/chains/gaia/v6.0.0/ibc-0/config/gentx/gentx-f8825df2c406207c64cbc02b1f543a53a46094e3.json new file mode 100644 index 000000000..685abc3ae --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-0/config/gentx/gentx-f8825df2c406207c64cbc02b1f543a53a46094e3.json @@ -0,0 +1 @@ +{"body":{"messages":[{"@type":"/cosmos.staking.v1beta1.MsgCreateValidator","description":{"moniker":"ibc-0","identity":"","website":"","security_contact":"","details":""},"commission":{"rate":"0.100000000000000000","max_rate":"0.200000000000000000","max_change_rate":"0.010000000000000000"},"min_self_delegation":"1","delegator_address":"cosmos1da0qjh7qptrscq59uaqjwtte0ru7mnfp2ndcxu","validator_address":"cosmosvaloper1da0qjh7qptrscq59uaqjwtte0ru7mnfp08ed20","pubkey":{"@type":"/cosmos.crypto.ed25519.PubKey","key":"NYFNoMsPbFYg4H/WodS6spPKJuYsFWOz/uEQMxiA7Mk="},"value":{"denom":"stake","amount":"100000000000"}}],"memo":"f8825df2c406207c64cbc02b1f543a53a46094e3@192.168.50.214:26656","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[{"public_key":{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"AoMRzDhz5CdelMYvXq/YUvy/pJTub9JJ8SV8yqTlyOmc"},"mode_info":{"single":{"mode":"SIGN_MODE_DIRECT"}},"sequence":"0"}],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":["fo1Cp9mv2cOpF+bpO0z+emIzeALBVhyyslZ29mvP2QJU7kCbq1KPeQ6xrQMJWNo5IiEvs0JBdhRHEC08Fbbp6Q=="]} diff --git a/ci/chains/gaia/v6.0.0/ibc-0/config/node_key.json b/ci/chains/gaia/v6.0.0/ibc-0/config/node_key.json new file mode 100644 index 000000000..c5ecc004a --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-0/config/node_key.json @@ -0,0 +1 @@ +{"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"ZMa5+ovMRjEApthUCunbPP4UIS4BkLwrN7ZUYqNsI6mXanUuQ3pszUuvB1YT4uXgQSNRUVVZ+0yITLieUxXSDA=="}} \ No newline at end of file diff --git a/ci/chains/gaia/v6.0.0/ibc-0/config/priv_validator_key.json b/ci/chains/gaia/v6.0.0/ibc-0/config/priv_validator_key.json new file mode 100644 index 000000000..02126f7d9 --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-0/config/priv_validator_key.json @@ -0,0 +1,11 @@ +{ + "address": "858D7DD17C7EF440D4AE4288C5BAA80EAA51D7FD", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "NYFNoMsPbFYg4H/WodS6spPKJuYsFWOz/uEQMxiA7Mk=" + }, + "priv_key": { + "type": "tendermint/PrivKeyEd25519", + "value": "7pxUnNSpT3r1VnjhjgbMBIekqm3HlhqWzj72wp4/VZI1gU2gyw9sViDgf9ah1Lqyk8om5iwVY7P+4RAzGIDsyQ==" + } +} \ No newline at end of file diff --git a/ci/chains/gaia/v6.0.0/ibc-0/keyring-test/1b49482294206b404476f840eb8468a09bf47962.address b/ci/chains/gaia/v6.0.0/ibc-0/keyring-test/1b49482294206b404476f840eb8468a09bf47962.address new file mode 100644 index 000000000..ab43a8127 --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-0/keyring-test/1b49482294206b404476f840eb8468a09bf47962.address @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMS0xMS0yNCAxNDozMzowOC41NTA0NTQxMzMgLTA1MDAgRVNUIG09KzAuMDcxMDg5NDgzIiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiUE1YZkJzdHdtTEZISDFTUCJ9.e2R6TeUCkYqRtQcpeOIZ9MH7LwWmKYsF-9azSTSBBGSkPjEmY49gTA.dzTMUVpONW5lmbuZ.2KL3qYiMBjqzewecmeI8ooDqhYw8nTb2MhBL9CZ3Blm-1PrQR19YQvcrYEzIhydKUNS-tm_vDDxQ7b-FtEWwGuZak7ErpvrKhsZFQiLEyHg0F4UEvWp5W4fY6hvIso8cf5HlIAHvSnffej1WfngiTSV23u2KbgvoiDU7Ctf5uYpBjaruHRbzk738ruKSTRyWPrag5L3IU-5uRNfhxXH-pGa7ftZcmPwMhTxCGojghgSmg9ZkGgQ.2UgcRahsvtKKqlHlNtnZsg \ No newline at end of file diff --git a/ci/chains/gaia/v6.0.0/ibc-0/keyring-test/6f5e095fc00ac70c0285e741272d7978f9edcd21.address b/ci/chains/gaia/v6.0.0/ibc-0/keyring-test/6f5e095fc00ac70c0285e741272d7978f9edcd21.address new file mode 100644 index 000000000..cbd24616a --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-0/keyring-test/6f5e095fc00ac70c0285e741272d7978f9edcd21.address @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMS0xMS0yNCAxNDozMzowNi4zNjMwOTU1NTkgLTA1MDAgRVNUIG09KzAuMDY1Nzg0NzI2IiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoicVFEZXh1UFllT3l2RG95UCJ9.80eJIBA0YgpL8j7mOFmajvU3VwJyv8xSVdhJOIn3KEwOwWIPAdvuZA.JOxBKB717wxiUuEN.VLZqTx5iM7dUvFQ75UbVhz4a-Wz1cgaRmf_-3cUD32-6c84jk8FyDuFlc1Tb1umMf8H1vwIE9higSQFMtZeuzCxIG08a9zTfXPyqWHfs5aodiDi9tDhMH1t2FQz1uHlf0UaAz1_tLyFeY0LuK_pXk_-err9r2ACgjDKnMUI_y5bmfxS1EGOLvylcKea2s1kROzYz_h2avUodhHg3Nx-qNtwlTxr6Hv74E21ZJPEtLe5PAb8Rm2LGrPpO.s7eBd83I848F6Vj-WcS3fQ \ No newline at end of file diff --git a/ci/chains/gaia/v6.0.0/ibc-0/keyring-test/9bd0eccd58edadaadadea911cbba3de68785fc86.address b/ci/chains/gaia/v6.0.0/ibc-0/keyring-test/9bd0eccd58edadaadadea911cbba3de68785fc86.address new file mode 100644 index 000000000..f9bb589ad --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-0/keyring-test/9bd0eccd58edadaadadea911cbba3de68785fc86.address @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMS0xMS0yNCAxNDozMzowNy40NjE0MjQ3NyAtMDUwMCBFU1QgbT0rMC4wODQ4MTQ4MzMiLCJlbmMiOiJBMjU2R0NNIiwicDJjIjo4MTkyLCJwMnMiOiJ6aFh6S0haLVVQOWhnRVFnIn0.xXrGsXcX7D1hn6m_nAwcGfAkdcgjbmLz_UEmlE0W45mFUAyljxjRkQ.KMAJFWKlCnYw4mvX.DyhKx-xyqWKJrUS42VAtNkSWKVqkogh2q-joJOFPJcF6f1IcN73JqZxdYmvsai3dRGs5xiTQsjsiM6tjvDKSFEaT3vYqpPwxTOJu2pvo_vWbNlNzauQyWgNiSiAPvtEWZI6PCTdk7FuyPBfm3dE4SkWuQBUuYZNoUnkkEXWDmqD3lKZ2ZIYcc0hqA4FQVP1A7RL4J16kn2BeXOEBPsUH8JZbplUDXA4UAnCFAtF_JdCgug.6K4vdxOdRJ9rbZa7cKxJwg \ No newline at end of file diff --git a/ci/chains/gaia/v6.0.0/ibc-0/keyring-test/user.info b/ci/chains/gaia/v6.0.0/ibc-0/keyring-test/user.info new file mode 100644 index 000000000..9fb08e779 --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-0/keyring-test/user.info @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMS0xMS0yNCAxNDozMzowNy40NDc4MTY1MDUgLTA1MDAgRVNUIG09KzAuMDcxMjA2NTUyIiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoibl94Mm1fOWVjbzhpeUxvQiJ9.ikzAEDoLYycFQVexbskD1kRzstVFXpR-YNz_kRrLMSUNSgkhhZGZVQ.7zH7erlv7nJbS5gX.xAIev6M3iU17fXOFC4SU8Al5JJp8_M7oaambw5ZxgmFDyajwffxsuXYIW7Y9MLGJNJ8yVHic-iN9HXdbxNIBfMsP138D6VXpksxAlbEWoVRJihwvqF_iqEHcuEyD212WEwIPTY6hH822xZV4l7yQlEHoGlQtUnMuWQz1IzvcKFYESUUavfiiSfP0CFbY5MAd5JremAtH-vN3xJ9pqcL0hOl9hmeKmc5pxZtnrbiTyVYiDJI8zPYeWFKTT_AvKoT9aoa1Ouo4qZ2whbUYufG9dC_DDhCcUATJocFBqNegahBOgegaJxDVzbv2PLqgWTrwpaMi0XiKMo0xt4HYt0LVNtbrpgJjHD4.PK-PK_u4eJmtbGd4y4G5Yg \ No newline at end of file diff --git a/ci/chains/gaia/v6.0.0/ibc-0/keyring-test/user2.info b/ci/chains/gaia/v6.0.0/ibc-0/keyring-test/user2.info new file mode 100644 index 000000000..5f864632e --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-0/keyring-test/user2.info @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMS0xMS0yNCAxNDozMzowOC41NDEyNTcxMTQgLTA1MDAgRVNUIG09KzAuMDYxODkyNDY0IiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiMXU3TFdzdjBZSHdwbkNqciJ9.fMo5HmXetkpNLdBkXlnIZk4ApD-nFYMME6dmdFarg7zhFL7QCFN7KQ._8e7Jva2GXFtzSt8.I2ta6Y6HKwoHkTx8-rPjLcajthmS90-iVMA_0FIup9lNd5LBLQpNAHY2hDbhCUbr3rNBPhTDVz6fD_S3ImfGjg4rQePDvOGgjntteAJ_e4-h1w0PCliyLlUM24Bw83aJmT1tubJ_bLe1Jkowg2FFv7b4QIY4sEslkoM0mMFmjgghZgVYzK_7gHY-KfXzXhEt-7lNypUbm7Te8ZQoZfzqcjwiJuwHKmXA2F5aWlNZK2ry6ivWWgRVUzwS0VWBRaDlx60R4PIrR0kqF_H8H4SDa_yIJsFyoLLliMgUz4N8COs6dHc3rf-jfopVtFriVDF7qRuKvfh4cL2FPiD6A1_kGBG4QxTWytCx.uiXHyY__OXUydn-keVhDyw \ No newline at end of file diff --git a/ci/chains/gaia/v6.0.0/ibc-0/keyring-test/validator.info b/ci/chains/gaia/v6.0.0/ibc-0/keyring-test/validator.info new file mode 100644 index 000000000..cd874c66c --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-0/keyring-test/validator.info @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMS0xMS0yNCAxNDozMzowNi4zNTYxNDUzNjYgLTA1MDAgRVNUIG09KzAuMDU4ODM0NTI0IiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiT1d6Q3h2a2lleHNUUXhXWiJ9.sMP2Opeadzy1NIqSFinrOosc9ueNGl6eoXzSlj1PuyjzKVDNPJBG9w.ymFHLPlxDdlwKchG.v7aqEHKE7zGY0DHDrV80QujgwP0dCVJG8PRsZv30pE_49NxiFjMJF_leVa52oiUN_8HCJsitXTIcs8Kku8eqL1FYPrFG-_pNZduDHM8w3dU40rYRhpEqo3NApemWXYeX5RQdnuXTHqriwIxOAsTbpoHxls7kMGH3AyDxz1yzfeATF6C0wKIUj1sssYg1dNX6PK2Vo2yyVWdmNFFX5UdUZZhSHmHN0t97k-GiYOYSfu92NLy4Nv1QQDchYuTGKdLdxMV_NApAlYUFFijFZthtEdABNzUqiSi296uCj7pw1uR8K9X-bzITkWb3_Yh-ELHbKbLAdF5FBST9Sw76jiqSGAQoZsunDNcnsJSgsAMcnGRtzBa8.FBJD9ZKZOHhaaeO9_y8byw \ No newline at end of file diff --git a/ci/chains/gaia/v6.0.0/ibc-0/user2_seed.json b/ci/chains/gaia/v6.0.0/ibc-0/user2_seed.json new file mode 100644 index 000000000..6a2856a3d --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-0/user2_seed.json @@ -0,0 +1 @@ +{"name":"user2","type":"local","address":"cosmos1rdy5sg55yp45q3rklpqwhprg5zdlg7tzuxdlhj","pubkey":"{\"@type\":\"/cosmos.crypto.secp256k1.PubKey\",\"key\":\"A6qQIsP43N+JyGeXtjYV10mUC3gfk1QcxEredSeNlezv\"}","mnemonic":"response group easily vicious master immense circle flock bridge chest cannon fog acoustic million plastic cinnamon rotate butter minute fatigue seed stick cousin mule"} diff --git a/ci/chains/gaia/v6.0.0/ibc-0/user_seed.json b/ci/chains/gaia/v6.0.0/ibc-0/user_seed.json new file mode 100644 index 000000000..05c5482ef --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-0/user_seed.json @@ -0,0 +1 @@ +{"name":"user","type":"local","address":"cosmos1n0gwen2cakk64kk74yguhw3au6rctlyxf5rvmj","pubkey":"{\"@type\":\"/cosmos.crypto.secp256k1.PubKey\",\"key\":\"ArOL1s7aGOyN+cvnOzf/b+F0aSX0gcNOmo/KKTxFqZ/a\"}","mnemonic":"mass symbol wrap wear typical romance machine cart club famous celery impose fancy chief emotion excess figure wet insane muffin tone awful coconut romance"} diff --git a/ci/chains/gaia/v6.0.0/ibc-0/validator_seed.json b/ci/chains/gaia/v6.0.0/ibc-0/validator_seed.json new file mode 100644 index 000000000..558019b07 --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-0/validator_seed.json @@ -0,0 +1 @@ +{"name":"validator","type":"local","address":"cosmos1da0qjh7qptrscq59uaqjwtte0ru7mnfp2ndcxu","pubkey":"{\"@type\":\"/cosmos.crypto.secp256k1.PubKey\",\"key\":\"AoMRzDhz5CdelMYvXq/YUvy/pJTub9JJ8SV8yqTlyOmc\"}","mnemonic":"dizzy lobster gaze luggage strategy drama negative bright trumpet favorite upset chief month popular hungry potato mad nephew peanut ship city purchase method metal"} diff --git a/ci/chains/gaia/v6.0.0/ibc-1/config/app.toml b/ci/chains/gaia/v6.0.0/ibc-1/config/app.toml new file mode 100644 index 000000000..1fc0b791f --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-1/config/app.toml @@ -0,0 +1,192 @@ +# This is a TOML config file. +# For more information, see https://github.com/toml-lang/toml + +############################################################################### +### Base Configuration ### +############################################################################### + +# The minimum gas prices a validator is willing to accept for processing a +# transaction. A transaction's fees must meet the minimum of any denomination +# specified in this config (e.g. 0.25token1;0.0001token2). +minimum-gas-prices = "" + +# default: the last 100 states are kept in addition to every 500th state; pruning at 10 block intervals +# nothing: all historic states will be saved, nothing will be deleted (i.e. archiving node) +# everything: all saved states will be deleted, storing only the current state; pruning at 10 block intervals +# custom: allow pruning options to be manually specified through 'pruning-keep-recent', 'pruning-keep-every', and 'pruning-interval' +pruning = "default" + +# These are applied if and only if the pruning strategy is custom. +pruning-keep-recent = "0" +pruning-keep-every = "0" +pruning-interval = "0" + +# HaltHeight contains a non-zero block height at which a node will gracefully +# halt and shutdown that can be used to assist upgrades and testing. +# +# Note: Commitment of state will be attempted on the corresponding block. +halt-height = 0 + +# HaltTime contains a non-zero minimum block time (in Unix seconds) at which +# a node will gracefully halt and shutdown that can be used to assist upgrades +# and testing. +# +# Note: Commitment of state will be attempted on the corresponding block. +halt-time = 0 + +# MinRetainBlocks defines the minimum block height offset from the current +# block being committed, such that all blocks past this offset are pruned +# from Tendermint. It is used as part of the process of determining the +# ResponseCommit.RetainHeight value during ABCI Commit. A value of 0 indicates +# that no blocks should be pruned. +# +# This configuration value is only responsible for pruning Tendermint blocks. +# It has no bearing on application state pruning which is determined by the +# "pruning-*" configurations. +# +# Note: Tendermint block pruning is dependant on this parameter in conunction +# with the unbonding (safety threshold) period, state pruning and state sync +# snapshot parameters to determine the correct minimum value of +# ResponseCommit.RetainHeight. +min-retain-blocks = 0 + +# InterBlockCache enables inter-block caching. +inter-block-cache = true + +# IndexEvents defines the set of events in the form {eventType}.{attributeKey}, +# which informs Tendermint what to index. If empty, all events will be indexed. +# +# Example: +# ["message.sender", "message.recipient"] +index-events = [] + +############################################################################### +### Telemetry Configuration ### +############################################################################### + +[telemetry] + +# Prefixed with keys to separate services. +service-name = "" + +# Enabled enables the application telemetry functionality. When enabled, +# an in-memory sink is also enabled by default. Operators may also enabled +# other sinks such as Prometheus. +enabled = false + +# Enable prefixing gauge values with hostname. +enable-hostname = false + +# Enable adding hostname to labels. +enable-hostname-label = false + +# Enable adding service to labels. +enable-service-label = false + +# PrometheusRetentionTime, when positive, enables a Prometheus metrics sink. +prometheus-retention-time = 0 + +# GlobalLabels defines a global set of name/value label tuples applied to all +# metrics emitted using the wrapper functions defined in telemetry package. +# +# Example: +# [["chain_id", "cosmoshub-1"]] +global-labels = [ +] + +############################################################################### +### API Configuration ### +############################################################################### + +[api] + +# Enable defines if the API server should be enabled. +enable = false + +# Swagger defines if swagger documentation should automatically be registered. +swagger = false + +# Address defines the API server to listen on. +address = "tcp://0.0.0.0:1317" + +# MaxOpenConnections defines the number of maximum open connections. +max-open-connections = 1000 + +# RPCReadTimeout defines the Tendermint RPC read timeout (in seconds). +rpc-read-timeout = 10 + +# RPCWriteTimeout defines the Tendermint RPC write timeout (in seconds). +rpc-write-timeout = 0 + +# RPCMaxBodyBytes defines the Tendermint maximum response body (in bytes). +rpc-max-body-bytes = 1000000 + +# EnableUnsafeCORS defines if CORS should be enabled (unsafe - use it at your own risk). +enabled-unsafe-cors = false + +############################################################################### +### Rosetta Configuration ### +############################################################################### + +[rosetta] + +# Enable defines if the Rosetta API server should be enabled. +enable = false + +# Address defines the Rosetta API server to listen on. +address = ":8080" + +# Network defines the name of the blockchain that will be returned by Rosetta. +blockchain = "app" + +# Network defines the name of the network that will be returned by Rosetta. +network = "network" + +# Retries defines the number of retries when connecting to the node before failing. +retries = 3 + +# Offline defines if Rosetta server should run in offline mode. +offline = false + +############################################################################### +### gRPC Configuration ### +############################################################################### + +[grpc] + +# Enable defines if the gRPC server should be enabled. +enable = true + +# Address defines the gRPC server address to bind to. +address = "0.0.0.0:9090" + +############################################################################### +### gRPC Web Configuration ### +############################################################################### + +[grpc-web] + +# GRPCWebEnable defines if the gRPC-web should be enabled. +# NOTE: gRPC must also be enabled, otherwise, this configuration is a no-op. +enable = true + +# Address defines the gRPC-web server address to bind to. +address = "0.0.0.0:9091" + +# EnableUnsafeCORS defines if CORS should be enabled (unsafe - use it at your own risk). +enable-unsafe-cors = false + +############################################################################### +### State Sync Configuration ### +############################################################################### + +# State sync snapshots allow other nodes to rapidly join the network without replaying historical +# blocks, instead downloading and applying a snapshot of the application state at a given height. +[state-sync] + +# snapshot-interval specifies the block interval at which local state sync snapshots are +# taken (0 to disable). Must be a multiple of pruning-keep-every. +snapshot-interval = 0 + +# snapshot-keep-recent specifies the number of recent snapshots to keep and serve (0 to keep all). +snapshot-keep-recent = 2 diff --git a/ci/chains/gaia/v6.0.0/ibc-1/config/client.toml b/ci/chains/gaia/v6.0.0/ibc-1/config/client.toml new file mode 100644 index 000000000..222695a3f --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-1/config/client.toml @@ -0,0 +1,17 @@ +# This is a TOML config file. +# For more information, see https://github.com/toml-lang/toml + +############################################################################### +### Client Configuration ### +############################################################################### + +# The network chain ID +chain-id = "" +# The keyring's backend, where the keys are stored (os|file|kwallet|pass|test|memory) +keyring-backend = "os" +# CLI output format (text|json) +output = "text" +# : to Tendermint RPC interface for this chain +node = "tcp://localhost:26657" +# Transaction broadcasting mode (sync|async|block) +broadcast-mode = "sync" diff --git a/ci/chains/gaia/v6.0.0/ibc-1/config/config.toml b/ci/chains/gaia/v6.0.0/ibc-1/config/config.toml new file mode 100644 index 000000000..bd592119b --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-1/config/config.toml @@ -0,0 +1,401 @@ +# This is a TOML config file. +# For more information, see https://github.com/toml-lang/toml + +# NOTE: Any path below can be absolute (e.g. "/var/myawesomeapp/data") or +# relative to the home directory (e.g. "data"). The home directory is +# "$HOME/.tendermint" by default, but could be changed via $TMHOME env variable +# or --home cmd flag. + +####################################################################### +### Main Base Config Options ### +####################################################################### + +# TCP or UNIX socket address of the ABCI application, +# or the name of an ABCI application compiled in with the Tendermint binary +proxy_app = "tcp://127.0.0.1:26658" + +# A custom human readable name for this node +moniker = "ibc-1" + +# If this node is many blocks behind the tip of the chain, FastSync +# allows them to catchup quickly by downloading blocks in parallel +# and verifying their commits +fast_sync = true + +# Database backend: goleveldb | cleveldb | boltdb | rocksdb | badgerdb +# * goleveldb (github.com/syndtr/goleveldb - most popular implementation) +# - pure go +# - stable +# * cleveldb (uses levigo wrapper) +# - fast +# - requires gcc +# - use cleveldb build tag (go build -tags cleveldb) +# * boltdb (uses etcd's fork of bolt - github.com/etcd-io/bbolt) +# - EXPERIMENTAL +# - may be faster is some use-cases (random reads - indexer) +# - use boltdb build tag (go build -tags boltdb) +# * rocksdb (uses github.com/tecbot/gorocksdb) +# - EXPERIMENTAL +# - requires gcc +# - use rocksdb build tag (go build -tags rocksdb) +# * badgerdb (uses github.com/dgraph-io/badger) +# - EXPERIMENTAL +# - use badgerdb build tag (go build -tags badgerdb) +db_backend = "goleveldb" + +# Database directory +db_dir = "data" + +# Output level for logging, including package level options +log_level = "info" + +# Output format: 'plain' (colored text) or 'json' +log_format = "plain" + +##### additional base config options ##### + +# Path to the JSON file containing the initial validator set and other meta data +genesis_file = "config/genesis.json" + +# Path to the JSON file containing the private key to use as a validator in the consensus protocol +priv_validator_key_file = "config/priv_validator_key.json" + +# Path to the JSON file containing the last sign state of a validator +priv_validator_state_file = "data/priv_validator_state.json" + +# TCP or UNIX socket address for Tendermint to listen on for +# connections from an external PrivValidator process +priv_validator_laddr = "" + +# Path to the JSON file containing the private key to use for node authentication in the p2p protocol +node_key_file = "config/node_key.json" + +# Mechanism to connect to the ABCI application: socket | grpc +abci = "socket" + +# If true, query the ABCI app on connecting to a new peer +# so the app can decide if we should keep the connection or not +filter_peers = false + + +####################################################################### +### Advanced Configuration Options ### +####################################################################### + +####################################################### +### RPC Server Configuration Options ### +####################################################### +[rpc] + +# TCP or UNIX socket address for the RPC server to listen on +laddr = "tcp://0.0.0.0:26657" + +# A list of origins a cross-domain request can be executed from +# Default value '[]' disables cors support +# Use '["*"]' to allow any origin +cors_allowed_origins = [] + +# A list of methods the client is allowed to use with cross-domain requests +cors_allowed_methods = ["HEAD", "GET", "POST", ] + +# A list of non simple headers the client is allowed to use with cross-domain requests +cors_allowed_headers = ["Origin", "Accept", "Content-Type", "X-Requested-With", "X-Server-Time", ] + +# TCP or UNIX socket address for the gRPC server to listen on +# NOTE: This server only supports /broadcast_tx_commit +grpc_laddr = "" + +# Maximum number of simultaneous connections. +# Does not include RPC (HTTP&WebSocket) connections. See max_open_connections +# If you want to accept a larger number than the default, make sure +# you increase your OS limits. +# 0 - unlimited. +# Should be < {ulimit -Sn} - {MaxNumInboundPeers} - {MaxNumOutboundPeers} - {N of wal, db and other open files} +# 1024 - 40 - 10 - 50 = 924 = ~900 +grpc_max_open_connections = 900 + +# Activate unsafe RPC commands like /dial_seeds and /unsafe_flush_mempool +unsafe = false + +# Maximum number of simultaneous connections (including WebSocket). +# Does not include gRPC connections. See grpc_max_open_connections +# If you want to accept a larger number than the default, make sure +# you increase your OS limits. +# 0 - unlimited. +# Should be < {ulimit -Sn} - {MaxNumInboundPeers} - {MaxNumOutboundPeers} - {N of wal, db and other open files} +# 1024 - 40 - 10 - 50 = 924 = ~900 +max_open_connections = 900 + +# Maximum number of unique clientIDs that can /subscribe +# If you're using /broadcast_tx_commit, set to the estimated maximum number +# of broadcast_tx_commit calls per block. +max_subscription_clients = 100 + +# Maximum number of unique queries a given client can /subscribe to +# If you're using GRPC (or Local RPC client) and /broadcast_tx_commit, set to +# the estimated # maximum number of broadcast_tx_commit calls per block. +max_subscriptions_per_client = 5 + +# How long to wait for a tx to be committed during /broadcast_tx_commit. +# WARNING: Using a value larger than 10s will result in increasing the +# global HTTP write timeout, which applies to all connections and endpoints. +# See https://github.com/tendermint/tendermint/issues/3435 +timeout_broadcast_tx_commit = "10s" + +# Maximum size of request body, in bytes +max_body_bytes = 1000000 + +# Maximum size of request header, in bytes +max_header_bytes = 1048576 + +# The path to a file containing certificate that is used to create the HTTPS server. +# Might be either absolute path or path related to Tendermint's config directory. +# If the certificate is signed by a certificate authority, +# the certFile should be the concatenation of the server's certificate, any intermediates, +# and the CA's certificate. +# NOTE: both tls_cert_file and tls_key_file must be present for Tendermint to create HTTPS server. +# Otherwise, HTTP server is run. +tls_cert_file = "" + +# The path to a file containing matching private key that is used to create the HTTPS server. +# Might be either absolute path or path related to Tendermint's config directory. +# NOTE: both tls-cert-file and tls-key-file must be present for Tendermint to create HTTPS server. +# Otherwise, HTTP server is run. +tls_key_file = "" + +# pprof listen address (https://golang.org/pkg/net/http/pprof) +pprof_laddr = "localhost:6060" + +####################################################### +### P2P Configuration Options ### +####################################################### +[p2p] + +# Address to listen for incoming connections +laddr = "tcp://0.0.0.0:26656" + +# Address to advertise to peers for them to dial +# If empty, will use the same port as the laddr, +# and will introspect on the listener or use UPnP +# to figure out the address. ip and port are required +# example: 159.89.10.97:26656 +external_address = "" + +# Comma separated list of seed nodes to connect to +seeds = "" + +# Comma separated list of nodes to keep persistent connections to +persistent_peers = "" + +# UPNP port forwarding +upnp = false + +# Path to address book +addr_book_file = "config/addrbook.json" + +# Set true for strict address routability rules +# Set false for private or local networks +addr_book_strict = true + +# Maximum number of inbound peers +max_num_inbound_peers = 40 + +# Maximum number of outbound peers to connect to, excluding persistent peers +max_num_outbound_peers = 10 + +# List of node IDs, to which a connection will be (re)established ignoring any existing limits +unconditional_peer_ids = "" + +# Maximum pause when redialing a persistent peer (if zero, exponential backoff is used) +persistent_peers_max_dial_period = "0s" + +# Time to wait before flushing messages out on the connection +flush_throttle_timeout = "100ms" + +# Maximum size of a message packet payload, in bytes +max_packet_msg_payload_size = 1024 + +# Rate at which packets can be sent, in bytes/second +send_rate = 5120000 + +# Rate at which packets can be received, in bytes/second +recv_rate = 5120000 + +# Set true to enable the peer-exchange reactor +pex = true + +# Seed mode, in which node constantly crawls the network and looks for +# peers. If another node asks it for addresses, it responds and disconnects. +# +# Does not work if the peer-exchange reactor is disabled. +seed_mode = false + +# Comma separated list of peer IDs to keep private (will not be gossiped to other peers) +private_peer_ids = "" + +# Toggle to disable guard against peers connecting from the same ip. +allow_duplicate_ip = false + +# Peer connection configuration. +handshake_timeout = "20s" +dial_timeout = "3s" + +####################################################### +### Mempool Configuration Option ### +####################################################### +[mempool] + +recheck = true +broadcast = true +wal_dir = "" + +# Maximum number of transactions in the mempool +size = 5000 + +# Limit the total size of all txs in the mempool. +# This only accounts for raw transactions (e.g. given 1MB transactions and +# max_txs_bytes=5MB, mempool will only accept 5 transactions). +max_txs_bytes = 1073741824 + +# Size of the cache (used to filter transactions we saw earlier) in transactions +cache_size = 10000 + +# Do not remove invalid transactions from the cache (default: false) +# Set to true if it's not possible for any invalid transaction to become valid +# again in the future. +keep-invalid-txs-in-cache = false + +# Maximum size of a single transaction. +# NOTE: the max size of a tx transmitted over the network is {max_tx_bytes}. +max_tx_bytes = 1048576 + +# Maximum size of a batch of transactions to send to a peer +# Including space needed by encoding (one varint per transaction). +# XXX: Unused due to https://github.com/tendermint/tendermint/issues/5796 +max_batch_bytes = 0 + +####################################################### +### State Sync Configuration Options ### +####################################################### +[statesync] +# State sync rapidly bootstraps a new node by discovering, fetching, and restoring a state machine +# snapshot from peers instead of fetching and replaying historical blocks. Requires some peers in +# the network to take and serve state machine snapshots. State sync is not attempted if the node +# has any local state (LastBlockHeight > 0). The node will have a truncated block history, +# starting from the height of the snapshot. +enable = false + +# RPC servers (comma-separated) for light client verification of the synced state machine and +# retrieval of state data for node bootstrapping. Also needs a trusted height and corresponding +# header hash obtained from a trusted source, and a period during which validators can be trusted. +# +# For Cosmos SDK-based chains, trust_period should usually be about 2/3 of the unbonding time (~2 +# weeks) during which they can be financially punished (slashed) for misbehavior. +rpc_servers = "" +trust_height = 0 +trust_hash = "" +trust_period = "168h0m0s" + +# Time to spend discovering snapshots before initiating a restore. +discovery_time = "15s" + +# Temporary directory for state sync snapshot chunks, defaults to the OS tempdir (typically /tmp). +# Will create a new, randomly named directory within, and remove it when done. +temp_dir = "" + +# The timeout duration before re-requesting a chunk, possibly from a different +# peer (default: 1 minute). +chunk_request_timeout = "10s" + +# The number of concurrent chunk fetchers to run (default: 1). +chunk_fetchers = "4" + +####################################################### +### Fast Sync Configuration Connections ### +####################################################### +[fastsync] + +# Fast Sync version to use: +# 1) "v0" (default) - the legacy fast sync implementation +# 2) "v1" - refactor of v0 version for better testability +# 2) "v2" - complete redesign of v0, optimized for testability & readability +version = "v0" + +####################################################### +### Consensus Configuration Options ### +####################################################### +[consensus] + +wal_file = "data/cs.wal/wal" + +# How long we wait for a proposal block before prevoting nil +timeout_propose = "1s" +# How much timeout_propose increases with each round +timeout_propose_delta = "500ms" +# How long we wait after receiving +2/3 prevotes for “anything” (ie. not a single block or nil) +timeout_prevote = "1s" +# How much the timeout_prevote increases with each round +timeout_prevote_delta = "500ms" +# How long we wait after receiving +2/3 precommits for “anything” (ie. not a single block or nil) +timeout_precommit = "1s" +# How much the timeout_precommit increases with each round +timeout_precommit_delta = "500ms" +# How long we wait after committing a block, before starting on the new +# height (this gives us a chance to receive some more precommits, even +# though we already have +2/3). +timeout_commit = "1s" + +# How many blocks to look back to check existence of the node's consensus votes before joining consensus +# When non-zero, the node will panic upon restart +# if the same consensus key was used to sign {double_sign_check_height} last blocks. +# So, validators should stop the state machine, wait for some blocks, and then restart the state machine to avoid panic. +double_sign_check_height = 0 + +# Make progress as soon as we have all the precommits (as if TimeoutCommit = 0) +skip_timeout_commit = false + +# EmptyBlocks mode and possible interval between empty blocks +create_empty_blocks = true +create_empty_blocks_interval = "0s" + +# Reactor sleep duration parameters +peer_gossip_sleep_duration = "100ms" +peer_query_maj23_sleep_duration = "2s" + +####################################################### +### Transaction Indexer Configuration Options ### +####################################################### +[tx_index] + +# What indexer to use for transactions +# +# The application will set which txs to index. In some cases a node operator will be able +# to decide which txs to index based on configuration set in the application. +# +# Options: +# 1) "null" +# 2) "kv" (default) - the simplest possible indexer, backed by key-value storage (defaults to levelDB; see DBBackend). +# - When "kv" is chosen "tx.height" and "tx.hash" will always be indexed. +indexer = "kv" + +####################################################### +### Instrumentation Configuration Options ### +####################################################### +[instrumentation] + +# When true, Prometheus metrics are served under /metrics on +# PrometheusListenAddr. +# Check out the documentation for the list of available metrics. +prometheus = false + +# Address to listen for Prometheus collector(s) connections +prometheus_listen_addr = ":26660" + +# Maximum number of simultaneous connections. +# If you want to accept a larger number than the default, make sure +# you increase your OS limits. +# 0 - unlimited. +max_open_connections = 3 + +# Instrumentation namespace +namespace = "tendermint" diff --git a/ci/chains/gaia/v6.0.0/ibc-1/config/genesis.json b/ci/chains/gaia/v6.0.0/ibc-1/config/genesis.json new file mode 100644 index 000000000..2f2a75c35 --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-1/config/genesis.json @@ -0,0 +1,356 @@ +{ + "genesis_time": "2021-11-24T19:33:18.421970195Z", + "chain_id": "ibc-1", + "initial_height": "1", + "consensus_params": { + "block": { + "max_bytes": "22020096", + "max_gas": "-1", + "time_iota_ms": "1000" + }, + "evidence": { + "max_age_num_blocks": "100000", + "max_age_duration": "172800000000000", + "max_bytes": "1048576" + }, + "validator": { + "pub_key_types": [ + "ed25519" + ] + }, + "version": {} + }, + "app_hash": "", + "app_state": { + "auth": { + "params": { + "max_memo_characters": "256", + "tx_sig_limit": "7", + "tx_size_cost_per_byte": "10", + "sig_verify_cost_ed25519": "590", + "sig_verify_cost_secp256k1": "1000" + }, + "accounts": [ + { + "@type": "/cosmos.auth.v1beta1.BaseAccount", + "address": "cosmos1y4e9e3srnuqcul7839cmttc4rjct2gece5y34l", + "pub_key": null, + "account_number": "0", + "sequence": "0" + }, + { + "@type": "/cosmos.auth.v1beta1.BaseAccount", + "address": "cosmos139lr5vxkr94lf85nr4zc4dvmj52qmmn0er2hrf", + "pub_key": null, + "account_number": "0", + "sequence": "0" + }, + { + "@type": "/cosmos.auth.v1beta1.BaseAccount", + "address": "cosmos1zx9v7cdvltsgyzymc6wwd070nzje4duvkzmfem", + "pub_key": null, + "account_number": "0", + "sequence": "0" + } + ] + }, + "authz": { + "authorization": [] + }, + "bank": { + "params": { + "send_enabled": [], + "default_send_enabled": true + }, + "balances": [ + { + "address": "cosmos1zx9v7cdvltsgyzymc6wwd070nzje4duvkzmfem", + "coins": [ + { + "denom": "stake", + "amount": "100000000000" + } + ] + }, + { + "address": "cosmos1y4e9e3srnuqcul7839cmttc4rjct2gece5y34l", + "coins": [ + { + "denom": "samoleans", + "amount": "100000000000" + }, + { + "denom": "stake", + "amount": "100000000000" + } + ] + }, + { + "address": "cosmos139lr5vxkr94lf85nr4zc4dvmj52qmmn0er2hrf", + "coins": [ + { + "denom": "samoleans", + "amount": "100000000000" + }, + { + "denom": "stake", + "amount": "100000000000" + } + ] + } + ], + "supply": [ + { + "denom": "samoleans", + "amount": "200000000000" + }, + { + "denom": "stake", + "amount": "300000000000" + } + ], + "denom_metadata": [] + }, + "capability": { + "index": "1", + "owners": [] + }, + "crisis": { + "constant_fee": { + "denom": "stake", + "amount": "1000" + } + }, + "distribution": { + "params": { + "community_tax": "0.020000000000000000", + "base_proposer_reward": "0.010000000000000000", + "bonus_proposer_reward": "0.040000000000000000", + "withdraw_addr_enabled": true + }, + "fee_pool": { + "community_pool": [] + }, + "delegator_withdraw_infos": [], + "previous_proposer": "", + "outstanding_rewards": [], + "validator_accumulated_commissions": [], + "validator_historical_rewards": [], + "validator_current_rewards": [], + "delegator_starting_infos": [], + "validator_slash_events": [] + }, + "evidence": { + "evidence": [] + }, + "feegrant": { + "allowances": [] + }, + "genutil": { + "gen_txs": [ + { + "body": { + "messages": [ + { + "@type": "/cosmos.staking.v1beta1.MsgCreateValidator", + "description": { + "moniker": "ibc-1", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "commission": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "min_self_delegation": "1", + "delegator_address": "cosmos1zx9v7cdvltsgyzymc6wwd070nzje4duvkzmfem", + "validator_address": "cosmosvaloper1zx9v7cdvltsgyzymc6wwd070nzje4duvnk0u4g", + "pubkey": { + "@type": "/cosmos.crypto.ed25519.PubKey", + "key": "3v9tEIBIsTBYs45lfoaBa1DtropTwNPjxWRKNyh1unI=" + }, + "value": { + "denom": "stake", + "amount": "100000000000" + } + } + ], + "memo": "bb5010f06487a9d315952e3e57c6dadac4ac425b@192.168.50.214:26656", + "timeout_height": "0", + "extension_options": [], + "non_critical_extension_options": [] + }, + "auth_info": { + "signer_infos": [ + { + "public_key": { + "@type": "/cosmos.crypto.secp256k1.PubKey", + "key": "AobtY30Q9FSuaB83i0DaK8gMU89R5BF9D5EiQZxltYj9" + }, + "mode_info": { + "single": { + "mode": "SIGN_MODE_DIRECT" + } + }, + "sequence": "0" + } + ], + "fee": { + "amount": [], + "gas_limit": "200000", + "payer": "", + "granter": "" + } + }, + "signatures": [ + "xpbYGwOWxrHHn45537a7C3wJJPs/I5Ccx3uq9ZzoEHMyOssoynjbqPsNVNj9ymcLqy4OYVMojbfqmSbMJuVe/Q==" + ] + } + ] + }, + "gov": { + "starting_proposal_id": "1", + "deposits": [], + "votes": [], + "proposals": [], + "deposit_params": { + "min_deposit": [ + { + "denom": "stake", + "amount": "10000000" + } + ], + "max_deposit_period": "200s" + }, + "voting_params": { + "voting_period": "200s" + }, + "tally_params": { + "quorum": "0.334000000000000000", + "threshold": "0.500000000000000000", + "veto_threshold": "0.334000000000000000" + } + }, + "ibc": { + "client_genesis": { + "clients": [], + "clients_consensus": [], + "clients_metadata": [], + "params": { + "allowed_clients": [ + "06-solomachine", + "07-tendermint" + ] + }, + "create_localhost": false, + "next_client_sequence": "0" + }, + "connection_genesis": { + "connections": [], + "client_connection_paths": [], + "next_connection_sequence": "0", + "params": { + "max_expected_time_per_block": "30000000000" + } + }, + "channel_genesis": { + "channels": [], + "acknowledgements": [], + "commitments": [], + "receipts": [], + "send_sequences": [], + "recv_sequences": [], + "ack_sequences": [], + "next_channel_sequence": "0" + } + }, + "liquidity": { + "params": { + "pool_types": [ + { + "id": 1, + "name": "StandardLiquidityPool", + "min_reserve_coin_num": 2, + "max_reserve_coin_num": 2, + "description": "Standard liquidity pool with pool price function X/Y, ESPM constraint, and two kinds of reserve coins" + } + ], + "min_init_deposit_amount": "1000000", + "init_pool_coin_mint_amount": "1000000", + "max_reserve_coin_amount": "0", + "pool_creation_fee": [ + { + "denom": "stake", + "amount": "40000000" + } + ], + "swap_fee_rate": "0.003000000000000000", + "withdraw_fee_rate": "0.000000000000000000", + "max_order_amount_ratio": "0.100000000000000000", + "unit_batch_height": 1, + "circuit_breaker_enabled": false + }, + "pool_records": [] + }, + "mint": { + "minter": { + "inflation": "0.130000000000000000", + "annual_provisions": "0.000000000000000000" + }, + "params": { + "mint_denom": "stake", + "inflation_rate_change": "0.130000000000000000", + "inflation_max": "0.200000000000000000", + "inflation_min": "0.070000000000000000", + "goal_bonded": "0.670000000000000000", + "blocks_per_year": "6311520" + } + }, + "packetfowardmiddleware": { + "params": { + "fee_percentage": "0.000000000000000000" + } + }, + "params": null, + "slashing": { + "params": { + "signed_blocks_window": "100", + "min_signed_per_window": "0.500000000000000000", + "downtime_jail_duration": "600s", + "slash_fraction_double_sign": "0.050000000000000000", + "slash_fraction_downtime": "0.010000000000000000" + }, + "signing_infos": [], + "missed_blocks": [] + }, + "staking": { + "params": { + "unbonding_time": "1814400s", + "max_validators": 100, + "max_entries": 7, + "historical_entries": 10000, + "bond_denom": "stake" + }, + "last_total_power": "0", + "last_validator_powers": [], + "validators": [], + "delegations": [], + "unbonding_delegations": [], + "redelegations": [], + "exported": false + }, + "transfer": { + "port_id": "transfer", + "denom_traces": [], + "params": { + "send_enabled": true, + "receive_enabled": true + } + }, + "upgrade": {}, + "vesting": {} + } +} \ No newline at end of file diff --git a/ci/chains/gaia/v6.0.0/ibc-1/config/gentx/gentx-bb5010f06487a9d315952e3e57c6dadac4ac425b.json b/ci/chains/gaia/v6.0.0/ibc-1/config/gentx/gentx-bb5010f06487a9d315952e3e57c6dadac4ac425b.json new file mode 100644 index 000000000..74f5f9455 --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-1/config/gentx/gentx-bb5010f06487a9d315952e3e57c6dadac4ac425b.json @@ -0,0 +1 @@ +{"body":{"messages":[{"@type":"/cosmos.staking.v1beta1.MsgCreateValidator","description":{"moniker":"ibc-1","identity":"","website":"","security_contact":"","details":""},"commission":{"rate":"0.100000000000000000","max_rate":"0.200000000000000000","max_change_rate":"0.010000000000000000"},"min_self_delegation":"1","delegator_address":"cosmos1zx9v7cdvltsgyzymc6wwd070nzje4duvkzmfem","validator_address":"cosmosvaloper1zx9v7cdvltsgyzymc6wwd070nzje4duvnk0u4g","pubkey":{"@type":"/cosmos.crypto.ed25519.PubKey","key":"3v9tEIBIsTBYs45lfoaBa1DtropTwNPjxWRKNyh1unI="},"value":{"denom":"stake","amount":"100000000000"}}],"memo":"bb5010f06487a9d315952e3e57c6dadac4ac425b@192.168.50.214:26656","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[{"public_key":{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"AobtY30Q9FSuaB83i0DaK8gMU89R5BF9D5EiQZxltYj9"},"mode_info":{"single":{"mode":"SIGN_MODE_DIRECT"}},"sequence":"0"}],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":["xpbYGwOWxrHHn45537a7C3wJJPs/I5Ccx3uq9ZzoEHMyOssoynjbqPsNVNj9ymcLqy4OYVMojbfqmSbMJuVe/Q=="]} diff --git a/ci/chains/gaia/v6.0.0/ibc-1/config/node_key.json b/ci/chains/gaia/v6.0.0/ibc-1/config/node_key.json new file mode 100644 index 000000000..4649f6565 --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-1/config/node_key.json @@ -0,0 +1 @@ +{"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"aqiLE2A0F5uKvpi0NoZTd+SN0hU1sJdb/ZecNbkmv9q6yo1iuGVhveMMsAnzrPmox4lyLlgINPny0nOhizn2Zw=="}} \ No newline at end of file diff --git a/ci/chains/gaia/v6.0.0/ibc-1/config/priv_validator_key.json b/ci/chains/gaia/v6.0.0/ibc-1/config/priv_validator_key.json new file mode 100644 index 000000000..807e3970c --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-1/config/priv_validator_key.json @@ -0,0 +1,11 @@ +{ + "address": "8B39C329C83C7DE2A2F345C384B36F05A84F2AC0", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "3v9tEIBIsTBYs45lfoaBa1DtropTwNPjxWRKNyh1unI=" + }, + "priv_key": { + "type": "tendermint/PrivKeyEd25519", + "value": "GBxwdlqDA1bc4mgTEtS/+NMxRXOucVfeOlFtaheA6YXe/20QgEixMFizjmV+hoFrUO2uilPA0+PFZEo3KHW6cg==" + } +} \ No newline at end of file diff --git a/ci/chains/gaia/v6.0.0/ibc-1/keyring-test/118acf61acfae082089bc69ce6bfcf98a59ab78c.address b/ci/chains/gaia/v6.0.0/ibc-1/keyring-test/118acf61acfae082089bc69ce6bfcf98a59ab78c.address new file mode 100644 index 000000000..723041596 --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-1/keyring-test/118acf61acfae082089bc69ce6bfcf98a59ab78c.address @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMS0xMS0yNCAxNDozMzoxOS41MDEyNDE5ODMgLTA1MDAgRVNUIG09KzAuMDY5NzExMzQzIiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiU25yZDdpRkliTkpYZ1c5RyJ9.lZtxW-Goo8loYIEykGq-NVYIohLZxK2FeO3jlQnon1I3HVi_3UCTGw.JPk6bE9slrEzRd1Y.DbE0LNFkwPCjhaIpHiVYywZRMkR5cs1Q1ma9L_bc1dqflzYG2ZtdkPpgE02e92zdkjRCaOz-U2l4k4AH95Li6rzP7p61XiR-RFo7qt-YIaOZvRoAyNfoCdZyO26JrzAX2b1hcP3re_WYxPz3k8hArJE_hNOdR6hxC2EopEC5CbCfXqilaPkEgLePCJKrqbMVW3vzcAVO1fjbn8pxVxvld3H26BB31ZVuDHR_e6upKg7XDyFq6F9cpbWG.I9JzJS5586b9eQyGVEmHbg \ No newline at end of file diff --git a/ci/chains/gaia/v6.0.0/ibc-1/keyring-test/25725cc6039f018e7fc78971b5af151cb0b52338.address b/ci/chains/gaia/v6.0.0/ibc-1/keyring-test/25725cc6039f018e7fc78971b5af151cb0b52338.address new file mode 100644 index 000000000..74a2a9c79 --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-1/keyring-test/25725cc6039f018e7fc78971b5af151cb0b52338.address @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMS0xMS0yNCAxNDozMzoyMC41Nzc2NjE0IC0wNTAwIEVTVCBtPSswLjA2MjE1NTkzMCIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjgxOTIsInAycyI6IjdVMmFaa01mZmlDazJWVlUifQ._Eam3zPOJ_9z31QMf2vGarrSCy-8OO6R8V3oiFPoPLJWs9kDLZs4KQ.G1a_5-gTtaFLTzNe.8e8vQWKINIYpXRg2sEW2QNrh2AhiyM39U5lqDQoLmeaozfle33Yyl2b-0eRYvOxUL9KoeUpLGtOa6ZoWAjla94TdUfWbUzHegNkP8-ibRD-u1LoHizRzIBHsTi5QoVdQGVJqxW22vb23t3OVjH2VVrzsQDrwGliFMR-nQT3GccTO6LowDGa7atVjJnc0qyEsrZ9NqvBJRM0A1N3ns0_MTCVIFlRCQr2mQ8j4NZmr8e-4Ww.wsvyHcDA3JyxpHTO9El4kA \ No newline at end of file diff --git a/ci/chains/gaia/v6.0.0/ibc-1/keyring-test/897e3a30d6196bf49e931d458ab59b95140dee6f.address b/ci/chains/gaia/v6.0.0/ibc-1/keyring-test/897e3a30d6196bf49e931d458ab59b95140dee6f.address new file mode 100644 index 000000000..47b98bfec --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-1/keyring-test/897e3a30d6196bf49e931d458ab59b95140dee6f.address @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMS0xMS0yNCAxNDozMzoyMS42NjQ0NTUxOTMgLTA1MDAgRVNUIG09KzAuMDczNjg5OTMxIiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiM09NSHpGS2ZzcnRZcUpiaCJ9.JKnoJPHUxymhduvxIJ9Y3uIpjlDXAhdzM0s6h2V2YwkL1PKPr0MJWA.MVCYrgojv-yJgZe8.r_z_gW4tANrbjpRj4k37TOxYrm3mHs7aJAwHtW6iVgOHhLljrcVJP0JdoqzvRYZpDxpayIovEFlEXpnopVjgZV0XpqJZoLmjFfaP2yOqbsrSOk7j86CEZPoGxLZqThL7IUQ1Fji3jYoplTSoOfaYQS40fBQgoLBgv4ZD_Vh2FEa45fP6-PEzHWo0-_kMyWxWXMM6KbzGDaN02aU8AAThF98iUo1GHHGCzjuRGW1OyvuHBR198nk.x1JgVMjEXbH5qEZf1-tNfg \ No newline at end of file diff --git a/ci/chains/gaia/v6.0.0/ibc-1/keyring-test/user.info b/ci/chains/gaia/v6.0.0/ibc-1/keyring-test/user.info new file mode 100644 index 000000000..e53db9c69 --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-1/keyring-test/user.info @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMS0xMS0yNCAxNDozMzoyMC41NzIwMjI0MzggLTA1MDAgRVNUIG09KzAuMDU2NTE2OTY2IiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiNmhYeVNDaXNFNDRmYU50NSJ9.yXnz86KYtSpKGF9_xqy80tu_X3j9azA50Gy0IlYUkDFJzhOBt8J85w.hWiGnawDFEJ21SRW.Pmkw-7YANEweAfCoO4cwwiiuaRvUcRReXkk3MYqoSctKKJc5M1STXIYhxKq8R1nxhMeX6bzdRpJwmVcWU6wEUPBgNnJENykxDwxpxisMsZn1orL3ySc1r60Yh7-AgriYoLXfdyBcHM3xi0wglQV9cRqxNhp6cB6qM0YP3WIfuW48yh5k-1Ke3SDrEOLHbAHMLR_KjCnI7NuyPFvrL-FbcyNsYNkI3NIJ8uDyMtaVxNwB-8C2WuIBmPae47iqAG4YXhAxVG7XXYmYKmQH08EvGsHiXB4IL6Omr2VHYKvSZIVIvzWX9W1UwlYpCIu_hf1yPEbBE0287_3Ymd06J2ZUB5R9Gz7wP8w.6dnU167tXcmROvvJnZWNxw \ No newline at end of file diff --git a/ci/chains/gaia/v6.0.0/ibc-1/keyring-test/user2.info b/ci/chains/gaia/v6.0.0/ibc-1/keyring-test/user2.info new file mode 100644 index 000000000..097d150a7 --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-1/keyring-test/user2.info @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMS0xMS0yNCAxNDozMzoyMS42NTM4MzY1MDkgLTA1MDAgRVNUIG09KzAuMDYzMDcxMjMyIiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiUHJqSDV5OFFueHQwRDRpaSJ9.jcO3HbJ7y45QeK4grQ5oET_W8LMAwcCAhjuji_MH4b7a8gwVGhNdiQ.AncSbV6zoozvh9B2._VmB-1kpDhTFQkcj3p4vYjO4r8PP_hUBAiaTKA9MMWDhc6wJgUbZe4ETgAic8KpVsD6MRIEwtaUPZQ5A6OJILNsojKpEOw1bZlWGVCugvOvX_yn6bGwjDWd3hQ6m1NB7Pq9AqL7LMQ4Vq5PhoHyKqprJVeIVnq8emTMQsnM3jF5xJEnVNRixAhaA7UJQkXZrKyfmsUmDSLyCS647TNLnjltQLx_wBO08gggYSkEavsWs9klWyqNF7_Yil8GNKnCtOV1EDJfJBUW7k3bDb9KkNtqVRgmQLBdrQUQKQHeKyR9ufIXasjsuF_uuwyRYZfEcRGu-4JaL1WDkbkBBQCCAebeZfCyxYHSa.IUZFTm6h9sgvk8enEW-7Lw \ No newline at end of file diff --git a/ci/chains/gaia/v6.0.0/ibc-1/keyring-test/validator.info b/ci/chains/gaia/v6.0.0/ibc-1/keyring-test/validator.info new file mode 100644 index 000000000..5284d5847 --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-1/keyring-test/validator.info @@ -0,0 +1 @@ +eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjcmVhdGVkIjoiMjAyMS0xMS0yNCAxNDozMzoxOS40OTM2MzgxNDUgLTA1MDAgRVNUIG09KzAuMDYyMTA3NTAxIiwiZW5jIjoiQTI1NkdDTSIsInAyYyI6ODE5MiwicDJzIjoiM3k0NDJvdU5PemotQmtaaCJ9.AypJs2QRWNAionV2YbpSj4iMUlXK6ve5AbW6dnqsKw_J_CHcjqWzig.WDpu5XC5HpWC43r4._f8eYLRJEFjyYTrAZS0N6dCyeEwpz-is9_1kjHmfWgVw5PYZxVrdI83S4t12Lh_jRhk2REPDVMbiG5-E0dEXNuV6o1tymAWZT1Vkw9EbzS-J51hzeDt4b-SvIe7XUJqwE67smbK22_o6dW8AcEd10p96jIqzO9jjoJQ_KXkWmYKgOv561K40wLew8thC3bdyMpwB50z0aywSTPHmfzBcI_ugni_RyIqtvLREraDHBcTAq9gwQTESKDbhtmOdvSUez9GBHhbHHf-95qz0d7VnuJXTg4h6dOwo2IF5dK5KENw9Ry_61nTvHTV3-tkh826gWWg4MkXjZGdQ5H-a0age-wN8N8oiJeIiE6WZXrHL9UpdwGX8.d7VnQTd1I5Ct5IcwkXbYEg \ No newline at end of file diff --git a/ci/chains/gaia/v6.0.0/ibc-1/user2_seed.json b/ci/chains/gaia/v6.0.0/ibc-1/user2_seed.json new file mode 100644 index 000000000..44a4a4ab3 --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-1/user2_seed.json @@ -0,0 +1 @@ +{"name":"user2","type":"local","address":"cosmos139lr5vxkr94lf85nr4zc4dvmj52qmmn0er2hrf","pubkey":"{\"@type\":\"/cosmos.crypto.secp256k1.PubKey\",\"key\":\"AquM1jLXtEDMVXLMvXr8Ny/lDySZ8GbJdQemhfRewpnA\"}","mnemonic":"cousin group crucial ready save drama piece time ordinary language one mind begin sound clever express broom limb foil size choose salute lazy gold"} diff --git a/ci/chains/gaia/v6.0.0/ibc-1/user_seed.json b/ci/chains/gaia/v6.0.0/ibc-1/user_seed.json new file mode 100644 index 000000000..6c2ad9277 --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-1/user_seed.json @@ -0,0 +1 @@ +{"name":"user","type":"local","address":"cosmos1y4e9e3srnuqcul7839cmttc4rjct2gece5y34l","pubkey":"{\"@type\":\"/cosmos.crypto.secp256k1.PubKey\",\"key\":\"A8c8vRcad30nDg3JJV8Iczt5Jz+wmaJYAwHJ3R18whn+\"}","mnemonic":"horn wait grace stool course spot one inject gloom fat crime usual horn kitten canoe glove foam cake reopen oblige silver favorite uniform cry"} diff --git a/ci/chains/gaia/v6.0.0/ibc-1/validator_seed.json b/ci/chains/gaia/v6.0.0/ibc-1/validator_seed.json new file mode 100644 index 000000000..13fe0a134 --- /dev/null +++ b/ci/chains/gaia/v6.0.0/ibc-1/validator_seed.json @@ -0,0 +1 @@ +{"name":"validator","type":"local","address":"cosmos1zx9v7cdvltsgyzymc6wwd070nzje4duvkzmfem","pubkey":"{\"@type\":\"/cosmos.crypto.secp256k1.PubKey\",\"key\":\"AobtY30Q9FSuaB83i0DaK8gMU89R5BF9D5EiQZxltYj9\"}","mnemonic":"latin trial chronic shadow sugar raw clay village face hurry world melody choose escape post angry casino scale unit emotion beyond cheese shiver addict"} diff --git a/ci/docker-compose.yml b/ci/docker-compose-gaia-current.yml similarity index 89% rename from ci/docker-compose.yml rename to ci/docker-compose-gaia-current.yml index 9c3127177..105086e78 100644 --- a/ci/docker-compose.yml +++ b/ci/docker-compose-gaia-current.yml @@ -4,7 +4,7 @@ services: ibc-0: container_name: ibc-0 - image: "informaldev/ibc-0:v5.0.5" + image: "informaldev/ibc-0:v5.0.8" stdin_open: true tty: true entrypoint: "/chain/gaia/run-gaiad.sh" @@ -16,7 +16,7 @@ services: ibc-1: container_name: ibc-1 - image: "informaldev/ibc-1:v5.0.5" + image: "informaldev/ibc-1:v5.0.8" stdin_open: true tty: true entrypoint: "/chain/gaia/run-gaiad.sh" @@ -37,7 +37,7 @@ services: context: ../ dockerfile: ci/relayer.Dockerfile args: - RELEASE: v5.0.5 + RELEASE: v5.0.8 environment: - CHAIN_A=ibc-0 - CHAIN_A_HOME=/data/ibc-0 @@ -47,7 +47,7 @@ services: - CHAIN_B_PORT=26657 - CONFIG=simple_config.toml - RELAYER_DIR=/relayer - - RELEASE=v5.0.5 + - RELEASE=v5.0.8 networks: relaynet: ipv4_address: 172.25.0.12 diff --git a/ci/docker-compose-gaia-future.yml b/ci/docker-compose-gaia-future.yml new file mode 100644 index 000000000..c9743f7e2 --- /dev/null +++ b/ci/docker-compose-gaia-future.yml @@ -0,0 +1,61 @@ +version: '3' + +services: + + ibc-0: + container_name: ibc-0 + image: "informaldev/ibc-0:v6.0.0" + stdin_open: true + tty: true + entrypoint: "/chain/gaia/run-gaiad.sh" + networks: + relaynet: + ipv4_address: 172.25.0.10 + environment: + - CHAIN_ID=ibc-0 + + ibc-1: + container_name: ibc-1 + image: "informaldev/ibc-1:v6.0.0" + stdin_open: true + tty: true + entrypoint: "/chain/gaia/run-gaiad.sh" + networks: + relaynet: + ipv4_address: 172.25.0.11 + environment: + - CHAIN_ID=ibc-1 + + relayer: + depends_on: + - ibc-0 + - ibc-1 + container_name: relayer + stdin_open: true + tty: true + build: + context: ../ + dockerfile: ci/relayer.Dockerfile + args: + RELEASE: v6.0.0 + environment: + - CHAIN_A=ibc-0 + - CHAIN_A_HOME=/data/ibc-0 + - CHAIN_A_PORT=26657 + - CHAIN_B=ibc-1 + - CHAIN_B_HOME=/data/ibc-1 + - CHAIN_B_PORT=26657 + - CONFIG=simple_config.toml + - RELAYER_DIR=/relayer + - RELEASE=v6.0.0 + networks: + relaynet: + ipv4_address: 172.25.0.12 + +networks: + relaynet: + driver: bridge + ipam: + driver: default + config: + - subnet: 172.25.0.0/16 diff --git a/ci/hermes.Dockerfile b/ci/hermes.Dockerfile index a4e58a906..cbee1188d 100644 --- a/ci/hermes.Dockerfile +++ b/ci/hermes.Dockerfile @@ -25,3 +25,4 @@ ENTRYPOINT ["/usr/bin/hermes"] COPY --chown=0:0 --from=build-env /usr/lib/x86_64-linux-gnu/libssl.so.1.1 /usr/lib/x86_64-linux-gnu/libssl.so.1.1 COPY --chown=0:0 --from=build-env /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 COPY --chown=0:0 --from=build-env /root/ibc-rs/target/release/hermes /usr/bin/hermes +COPY --chown=0:0 --from=build-env /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt diff --git a/ci/no-std-check/Cargo.lock b/ci/no-std-check/Cargo.lock deleted file mode 100644 index 2521b418a..000000000 --- a/ci/no-std-check/Cargo.lock +++ /dev/null @@ -1,1177 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "Inflector" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" -dependencies = [ - "lazy_static", - "regex", -] - -[[package]] -name = "aho-corasick" -version = "0.7.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" -dependencies = [ - "memchr", -] - -[[package]] -name = "anyhow" -version = "1.0.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1" - -[[package]] -name = "arrayvec" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4dc07131ffa69b8072d35f5007352af944213cde02545e2103680baed38fcd" - -[[package]] -name = "async-trait" -version = "0.1.51" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "autocfg" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" - -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "block-padding", - "generic-array", -] - -[[package]] -name = "block-padding" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" - -[[package]] -name = "byte-slice-cast" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca0796d76a983651b4a0ddda16203032759f2fd9103d9181f7c65c06ee8872e6" - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "bytes" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" -dependencies = [ - "num-integer", - "num-traits", - "serde", -] - -[[package]] -name = "cpufeatures" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" -dependencies = [ - "libc", -] - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "curve25519-dalek" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" -dependencies = [ - "byteorder", - "digest", - "rand_core", - "subtle", - "zeroize", -] - -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", -] - -[[package]] -name = "ed25519" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4620d40f6d2601794401d6dd95a5cf69b6c157852539470eeda433a99b3c0efc" -dependencies = [ - "signature", -] - -[[package]] -name = "ed25519-dalek" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" -dependencies = [ - "curve25519-dalek", - "ed25519", - "sha2", - "zeroize", -] - -[[package]] -name = "either" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" - -[[package]] -name = "fixed-hash" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" -dependencies = [ - "static_assertions", -] - -[[package]] -name = "flex-error" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e8de6bf49fb8856ee814e288a518e0d45598b6f78a95c1233b96eedba8bc06a" -dependencies = [ - "paste", -] - -[[package]] -name = "futures" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" - -[[package]] -name = "futures-io" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" - -[[package]] -name = "futures-sink" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11" - -[[package]] -name = "futures-task" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" - -[[package]] -name = "futures-util" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" -dependencies = [ - "autocfg", - "futures-core", - "futures-sink", - "futures-task", - "pin-project-lite", - "pin-utils", -] - -[[package]] -name = "generic-array" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "hash-db" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d23bd4e7b5eda0d0f3a307e8b381fdc8ba9000f26fbe912250c0a4cc3956364a" - -[[package]] -name = "hash256-std-hasher" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92c171d55b98633f4ed3860808f004099b36c1cc29c42cfc53aa8591b21efcf2" -dependencies = [ - "crunchy", -] - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "ibc" -version = "0.7.3" -dependencies = [ - "bytes", - "chrono", - "flex-error", - "ibc-proto", - "ics23", - "informalsystems-prost", - "informalsystems-prost-types", - "safe-regex", - "serde", - "serde_derive", - "serde_json", - "subtle-encoding", - "tendermint", - "tendermint-proto", - "tracing", -] - -[[package]] -name = "ibc-proto" -version = "0.11.0" -dependencies = [ - "bytes", - "informalsystems-prost", - "informalsystems-prost-types", - "tendermint-proto", -] - -[[package]] -name = "ics23" -version = "0.6.5" -source = "git+https://github.com/informalsystems/ics23.git?branch=master#4461b67382341af6bc6fab9c991ccc5d49a6e83e" -dependencies = [ - "anyhow", - "bytes", - "hex", - "informalsystems-prost", - "informalsystems-prost-types", - "ripemd160", - "sha2", - "sha3", - "sp-std", -] - -[[package]] -name = "impl-codec" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "161ebdfec3c8e3b52bf61c4f3550a1eea4f9579d10dc1b936f3171ebdcd6c443" -dependencies = [ - "parity-scale-codec", -] - -[[package]] -name = "impl-trait-for-tuples" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5dacb10c5b3bb92d46ba347505a9041e676bb20ad220101326bffb0c93031ee" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "informalsystems-prost" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5620e41d3653c27671bee3e07822407365cae5d97f4a391a1c87cb2a4caf647b" -dependencies = [ - "bytes", - "informalsystems-prost-derive", -] - -[[package]] -name = "informalsystems-prost-derive" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c6af6594ef5bc7f879ba098055e084bf3562077b6dc83fcc96b579cdd319eba" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "informalsystems-prost-types" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41b094d80f1836c54e192146a58ef1ef1803b1a50a055ab6303ec757e034431a" -dependencies = [ - "bytes", - "informalsystems-prost", -] - -[[package]] -name = "integer-sqrt" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "276ec31bcb4a9ee45f58bec6f9ec700ae4cf4f4f8f2fa7e06cb406bd5ffdd770" -dependencies = [ - "num-traits", -] - -[[package]] -name = "itertools" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - -[[package]] -name = "keccak" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6" - -[[package]] -name = "log" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "max-encoded-len" -version = "3.0.0" -source = "git+https://github.com/octopus-network/substrate?branch=polkadot-v0.9.8#74101dc21cfffb4c2d014fcc28edc166d5ca1b16" -dependencies = [ - "impl-trait-for-tuples", - "max-encoded-len-derive", - "parity-scale-codec", - "primitive-types", -] - -[[package]] -name = "max-encoded-len-derive" -version = "3.0.0" -source = "git+https://github.com/octopus-network/substrate?branch=polkadot-v0.9.8#74101dc21cfffb4c2d014fcc28edc166d5ca1b16" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "memchr" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" - -[[package]] -name = "no-std-check" -version = "0.1.0" -dependencies = [ - "ibc", - "ibc-proto", - "sp-core", - "sp-io", - "sp-runtime", - "sp-runtime-interface", - "sp-std", - "tendermint", - "tendermint-proto", -] - -[[package]] -name = "num-derive" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "num-integer" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" - -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - -[[package]] -name = "parity-scale-codec" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373b1a4c1338d9cd3d1fa53b3a11bdab5ab6bd80a20f7f7becd76953ae2be909" -dependencies = [ - "arrayvec", - "byte-slice-cast", - "impl-trait-for-tuples", - "parity-scale-codec-derive", -] - -[[package]] -name = "parity-scale-codec-derive" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1557010476e0595c9b568d16dcfb81b93cdeb157612726f5170d31aa707bed27" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "parity-util-mem" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "664a8c6b8e62d8f9f2f937e391982eb433ab285b4cd9545b342441e04a906e42" -dependencies = [ - "cfg-if", - "impl-trait-for-tuples", - "parity-util-mem-derive", - "primitive-types", - "winapi", -] - -[[package]] -name = "parity-util-mem-derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f557c32c6d268a07c921471619c0295f5efad3a0e76d4f97a05c091a51d110b2" -dependencies = [ - "proc-macro2", - "syn", - "synstructure", -] - -[[package]] -name = "paste" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf547ad0c65e31259204bd90935776d1c693cec2f4ff7abb7a1bbbd40dfe58" - -[[package]] -name = "pin-project-lite" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "primitive-types" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06345ee39fbccfb06ab45f3a1a5798d9dafa04cb8921a76d227040003a234b0e" -dependencies = [ - "fixed-hash", - "impl-codec", - "uint", -] - -[[package]] -name = "proc-macro-crate" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ebace6889caf889b4d3f76becee12e90353f2b8c7d875534a71e5742f8f6f83" -dependencies = [ - "thiserror", - "toml", -] - -[[package]] -name = "proc-macro2" -version = "1.0.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "quote" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" - -[[package]] -name = "ref-cast" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "300f2a835d808734ee295d45007adacb9ebb29dd3ae2424acfa17930cae541da" -dependencies = [ - "ref-cast-impl", -] - -[[package]] -name = "ref-cast-impl" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c38e3aecd2b21cb3959637b883bb3714bc7e43f0268b9a29d3743ee3e55cdd2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "regex" -version = "1.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" - -[[package]] -name = "ripemd160" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eca4ecc81b7f313189bf73ce724400a07da2a6dac19588b03c8bd76a2dcc251" -dependencies = [ - "block-buffer", - "digest", - "opaque-debug", -] - -[[package]] -name = "ryu" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" - -[[package]] -name = "safe-proc-macro2" -version = "1.0.24" -source = "git+https://github.com/informalsystems/safe-regex.git?branch=main#842d31f5acdcd66dd60481632baaae511c29f0fd" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "safe-quote" -version = "1.0.9" -source = "git+https://github.com/informalsystems/safe-regex.git?branch=main#842d31f5acdcd66dd60481632baaae511c29f0fd" -dependencies = [ - "safe-proc-macro2", -] - -[[package]] -name = "safe-regex" -version = "0.2.4" -source = "git+https://github.com/informalsystems/safe-regex.git?branch=main#842d31f5acdcd66dd60481632baaae511c29f0fd" -dependencies = [ - "safe-regex-macro", -] - -[[package]] -name = "safe-regex-compiler" -version = "0.2.4" -source = "git+https://github.com/informalsystems/safe-regex.git?branch=main#842d31f5acdcd66dd60481632baaae511c29f0fd" -dependencies = [ - "safe-proc-macro2", - "safe-quote", -] - -[[package]] -name = "safe-regex-macro" -version = "0.2.3" -source = "git+https://github.com/informalsystems/safe-regex.git?branch=main#842d31f5acdcd66dd60481632baaae511c29f0fd" -dependencies = [ - "safe-proc-macro2", - "safe-regex-compiler", -] - -[[package]] -name = "secrecy" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0673d6a6449f5e7d12a1caf424fd9363e2af3a4953023ed455e3c4beef4597c0" -dependencies = [ - "zeroize", -] - -[[package]] -name = "serde" -version = "1.0.130" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_bytes" -version = "0.11.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16ae07dd2f88a366f15bd0632ba725227018c69a1c8550a927324f8eb8368bb9" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_derive" -version = "1.0.130" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.68" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_repr" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98d0516900518c29efa217c298fa1f4e6c6ffc85ae29fd7f4ee48f176e1a9ed5" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "sha2" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" -dependencies = [ - "block-buffer", - "cfg-if", - "cpufeatures", - "digest", - "opaque-debug", -] - -[[package]] -name = "sha3" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" -dependencies = [ - "block-buffer", - "digest", - "keccak", - "opaque-debug", -] - -[[package]] -name = "signature" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19772be3c4dd2ceaacf03cb41d5885f2a02c4d8804884918e3a258480803335" - -[[package]] -name = "sp-application-crypto" -version = "3.0.0" -source = "git+https://github.com/octopus-network/substrate?branch=polkadot-v0.9.8#74101dc21cfffb4c2d014fcc28edc166d5ca1b16" -dependencies = [ - "max-encoded-len", - "parity-scale-codec", - "sp-core", - "sp-io", - "sp-std", -] - -[[package]] -name = "sp-arithmetic" -version = "3.0.0" -source = "git+https://github.com/octopus-network/substrate?branch=polkadot-v0.9.8#74101dc21cfffb4c2d014fcc28edc166d5ca1b16" -dependencies = [ - "integer-sqrt", - "num-traits", - "parity-scale-codec", - "sp-debug-derive", - "sp-std", - "static_assertions", -] - -[[package]] -name = "sp-core" -version = "3.0.0" -source = "git+https://github.com/octopus-network/substrate?branch=polkadot-v0.9.8#74101dc21cfffb4c2d014fcc28edc166d5ca1b16" -dependencies = [ - "byteorder", - "hash-db", - "hash256-std-hasher", - "log", - "max-encoded-len", - "num-traits", - "parity-scale-codec", - "parity-util-mem", - "primitive-types", - "secrecy", - "sp-debug-derive", - "sp-runtime-interface", - "sp-std", - "sp-storage", - "zeroize", -] - -[[package]] -name = "sp-debug-derive" -version = "3.0.0" -source = "git+https://github.com/octopus-network/substrate?branch=polkadot-v0.9.8#74101dc21cfffb4c2d014fcc28edc166d5ca1b16" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "sp-io" -version = "3.0.0" -source = "git+https://github.com/octopus-network/substrate?branch=polkadot-v0.9.8#74101dc21cfffb4c2d014fcc28edc166d5ca1b16" -dependencies = [ - "hash-db", - "parity-scale-codec", - "sp-core", - "sp-runtime-interface", - "sp-std", - "sp-tracing", - "sp-wasm-interface", - "tracing", - "tracing-core", -] - -[[package]] -name = "sp-runtime" -version = "3.0.0" -source = "git+https://github.com/octopus-network/substrate?branch=polkadot-v0.9.8#74101dc21cfffb4c2d014fcc28edc166d5ca1b16" -dependencies = [ - "either", - "hash256-std-hasher", - "impl-trait-for-tuples", - "log", - "max-encoded-len", - "parity-scale-codec", - "parity-util-mem", - "paste", - "sp-application-crypto", - "sp-arithmetic", - "sp-core", - "sp-io", - "sp-std", -] - -[[package]] -name = "sp-runtime-interface" -version = "3.0.0" -source = "git+https://github.com/octopus-network/substrate?branch=polkadot-v0.9.8#74101dc21cfffb4c2d014fcc28edc166d5ca1b16" -dependencies = [ - "impl-trait-for-tuples", - "parity-scale-codec", - "primitive-types", - "sp-runtime-interface-proc-macro", - "sp-std", - "sp-storage", - "sp-tracing", - "sp-wasm-interface", - "static_assertions", -] - -[[package]] -name = "sp-runtime-interface-proc-macro" -version = "3.0.0" -source = "git+https://github.com/octopus-network/substrate?branch=polkadot-v0.9.8#74101dc21cfffb4c2d014fcc28edc166d5ca1b16" -dependencies = [ - "Inflector", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "sp-std" -version = "3.0.0" -source = "git+https://github.com/octopus-network/substrate?branch=polkadot-v0.9.8#74101dc21cfffb4c2d014fcc28edc166d5ca1b16" - -[[package]] -name = "sp-storage" -version = "3.0.0" -source = "git+https://github.com/octopus-network/substrate?branch=polkadot-v0.9.8#74101dc21cfffb4c2d014fcc28edc166d5ca1b16" -dependencies = [ - "parity-scale-codec", - "ref-cast", - "sp-debug-derive", - "sp-std", -] - -[[package]] -name = "sp-tracing" -version = "3.0.0" -source = "git+https://github.com/octopus-network/substrate?branch=polkadot-v0.9.8#74101dc21cfffb4c2d014fcc28edc166d5ca1b16" -dependencies = [ - "parity-scale-codec", - "sp-std", - "tracing", - "tracing-core", -] - -[[package]] -name = "sp-wasm-interface" -version = "3.0.0" -source = "git+https://github.com/octopus-network/substrate?branch=polkadot-v0.9.8#74101dc21cfffb4c2d014fcc28edc166d5ca1b16" -dependencies = [ - "impl-trait-for-tuples", - "parity-scale-codec", - "sp-std", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "subtle" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" - -[[package]] -name = "subtle-encoding" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dcb1ed7b8330c5eed5441052651dd7a12c75e2ed88f2ec024ae1fa3a5e59945" -dependencies = [ - "zeroize", -] - -[[package]] -name = "syn" -version = "1.0.80" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "synstructure" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "474aaa926faa1603c40b7885a9eaea29b444d1cb2850cb7c0e37bb1a4182f4fa" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "unicode-xid", -] - -[[package]] -name = "tendermint" -version = "0.22.0" -source = "git+https://github.com/informalsystems/tendermint-rs?branch=soares/activate-no-std#553dd0eb98af6a9cd5b0bd3732bb9ac10fa6f79d" -dependencies = [ - "async-trait", - "bytes", - "chrono", - "ed25519", - "ed25519-dalek", - "flex-error", - "futures", - "informalsystems-prost", - "informalsystems-prost-types", - "num-traits", - "once_cell", - "serde", - "serde_bytes", - "serde_json", - "serde_repr", - "sha2", - "signature", - "subtle", - "subtle-encoding", - "tendermint-proto", - "zeroize", -] - -[[package]] -name = "tendermint-proto" -version = "0.22.0" -source = "git+https://github.com/informalsystems/tendermint-rs?branch=soares/activate-no-std#553dd0eb98af6a9cd5b0bd3732bb9ac10fa6f79d" -dependencies = [ - "bytes", - "chrono", - "flex-error", - "informalsystems-prost", - "informalsystems-prost-types", - "num-derive", - "num-traits", - "serde", - "serde_bytes", - "subtle-encoding", -] - -[[package]] -name = "thiserror" -version = "1.0.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "toml" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" -dependencies = [ - "serde", -] - -[[package]] -name = "tracing" -version = "0.1.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" -dependencies = [ - "cfg-if", - "pin-project-lite", - "tracing-core", -] - -[[package]] -name = "tracing-core" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" - -[[package]] -name = "typenum" -version = "1.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" - -[[package]] -name = "uint" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6470ab50f482bde894a037a57064480a246dbfdd5960bd65a44824693f08da5f" -dependencies = [ - "byteorder", - "crunchy", - "hex", - "static_assertions", -] - -[[package]] -name = "unicode-xid" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" - -[[package]] -name = "version_check" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "zeroize" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf68b08513768deaa790264a7fac27a58cbf2705cfcdc9448362229217d7e970" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdff2024a851a322b08f179173ae2ba620445aef1e838f0c196820eade4ae0c7" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] diff --git a/ci/no-std-check/Cargo.toml b/ci/no-std-check/Cargo.toml index 1ee6017c4..0ad8a4922 100644 --- a/ci/no-std-check/Cargo.toml +++ b/ci/no-std-check/Cargo.toml @@ -1,50 +1,38 @@ [package] name = "no-std-check" version = "0.1.0" -edition = "2018" +edition = "2021" resolver = "2" [dependencies] ibc = { path = "../../modules", default-features = false } ibc-proto = { path = "../../proto", default-features = false } -tendermint = { version = "0.22", default-features = false } -tendermint-proto = { version = "0.22", default-features = false } -sp-core = { version = "3.0.0", default-features = false, optional = true } -sp-io = { version = "3.0.0", default-features = false, optional = true } -sp-runtime = { version = "3.0.0", default-features = false, optional = true } -sp-std = { version = "3.0.0", default-features = false, optional = true } -sp-runtime-interface = { version = "3.0.0", default-features = false, optional = true} +tendermint = { version = "0.23.5", default-features = false } +tendermint-proto = { version = "0.23.5", default-features = false } +tendermint-light-client-verifier = { version = "0.23.5", default-features = false } + +sp-core = { version = "5.0.0", default-features = false, optional = true } +sp-io = { version = "5.0.0", default-features = false, optional = true } +sp-runtime = { version = "5.0.0", default-features = false, optional = true } +sp-std = { version = "4.0.0", default-features = false, optional = true } [features] -default = [] +panic-handler = [] use-substrate = [ "sp-core", "sp-io", "sp-runtime", "sp-std", - "sp-runtime-interface", ] - -[profile.dev] -panic = "abort" - -[profile.release] -panic = "abort" +substrate-std = [ + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", +] [patch.crates-io] -tendermint = { git = "https://github.com/informalsystems/tendermint-rs", branch = "soares/activate-no-std" } -tendermint-proto = { git = "https://github.com/informalsystems/tendermint-rs", branch = "soares/activate-no-std" } -ics23 = { git = "https://github.com/informalsystems/ics23.git", branch = "master" } -safe-regex = { git = "https://github.com/informalsystems/safe-regex.git", branch = "main" } -safe-regex-macro = { git = "https://github.com/informalsystems/safe-regex.git", branch = "main" } -safe-regex-compiler = { git = "https://github.com/informalsystems/safe-regex.git", branch = "main" } -safe-quote = { git = "https://github.com/informalsystems/safe-regex.git", branch = "main" } -safe-proc-macro2 = { git = "https://github.com/informalsystems/safe-regex.git", branch = "main" } - - -sp-runtime-interface = { git = "https://github.com/octopus-network/substrate", branch = "polkadot-v0.9.8" } -sp-core = { git = "https://github.com/octopus-network/substrate", branch = "polkadot-v0.9.8" } -sp-runtime = { git = "https://github.com/octopus-network/substrate", branch = "polkadot-v0.9.8" } -sp-std = { git = "https://github.com/octopus-network/substrate", branch = "polkadot-v0.9.8" } -sp-io = { git = "https://github.com/octopus-network/substrate", branch = "polkadot-v0.9.8" } \ No newline at end of file +tendermint = { git = "https://github.com/informalsystems/tendermint-rs", branch = "v0.23.x" } +tendermint-proto = { git = "https://github.com/informalsystems/tendermint-rs", branch = "v0.23.x" } +tendermint-light-client-verifier = { git = "https://github.com/informalsystems/tendermint-rs", branch = "v0.23.x" } diff --git a/ci/no-std-check/Makefile b/ci/no-std-check/Makefile index dfb02e68a..2ff087436 100644 --- a/ci/no-std-check/Makefile +++ b/ci/no-std-check/Makefile @@ -1,22 +1,29 @@ -#NIGHTLY_VERSION=nightly-2021-09-01 NIGHTLY_VERSION=nightly setup: rustup install $(NIGHTLY_VERSION) rustup target add wasm32-unknown-unknown --toolchain $(NIGHTLY_VERSION) +build-substrate: + cargo build \ + --no-default-features \ + --features use-substrate,substrate-std + check-panic-conflict: cargo build \ - --no-default-features + --no-default-features \ + --features panic-handler check-cargo-build-std: rustup run $(NIGHTLY_VERSION) -- \ cargo build -Z build-std=core,alloc \ + --no-default-features \ --target x86_64-unknown-linux-gnu check-wasm: rustup run $(NIGHTLY_VERSION) -- \ cargo build \ + --features panic-handler \ --target wasm32-unknown-unknown check-substrate: diff --git a/ci/no-std-check/src/lib.rs b/ci/no-std-check/src/lib.rs index 03f072adf..c45dffb89 100644 --- a/ci/no-std-check/src/lib.rs +++ b/ci/no-std-check/src/lib.rs @@ -10,6 +10,7 @@ use ibc; use ibc_proto; use tendermint; use tendermint_proto; +use tendermint_light_client_verifier; #[cfg(feature = "sp-core")] use sp_core; @@ -43,7 +44,7 @@ error[E0152]: found duplicate lang item `panic_impl` ``` */ -#[cfg(not(feature = "use-substrate"))] +#[cfg(feature="panic-handler")] #[panic_handler] #[no_mangle] fn panic(_info: &PanicInfo) -> ! { diff --git a/ci/simple_config.toml b/ci/simple_config.toml index fd4736f55..0eea92af7 100644 --- a/ci/simple_config.toml +++ b/ci/simple_config.toml @@ -1,8 +1,24 @@ [global] -strategy = 'all' log_level = 'trace' -filter = false -clear_packets_interval = 100 + +[mode] + +[mode.clients] +enabled = true +refresh = true +misbehaviour = true + +[mode.connections] +enabled = false + +[mode.channels] +enabled = false + +[mode.packets] +enabled = true +clear_interval = 100 +clear_on_start = true +tx_confirmation = true [telemetry] enabled = false @@ -41,4 +57,4 @@ max_tx_size = 2097152 gas_price = { price = 0.001, denom = 'stake' } clock_drift = '5s' trusting_period = '14days' -trust_threshold = { numerator = '1', denominator = '3' } \ No newline at end of file +trust_threshold = { numerator = '1', denominator = '3' } diff --git a/clippy.toml b/clippy.toml new file mode 100644 index 000000000..482041017 --- /dev/null +++ b/clippy.toml @@ -0,0 +1 @@ +msrv = "1.58.0" diff --git a/config.toml b/config.toml index 34efe8c3f..5894d03e0 100644 --- a/config.toml +++ b/config.toml @@ -1,42 +1,63 @@ # The global section has parameters that apply globally to the relayer operation. [global] -# Specify the strategy to be used by the relayer. Default: 'packets' -# Two options are currently supported: -# - 'all': Relay packets and perform channel and connection handshakes. -# - 'packets': Relay packets only. -strategy = 'all' - -# Enable or disable the filtering mechanism. Default: 'false' -# Valid options are 'true', 'false'. -# Currently Hermes supports two filters: -# 1. Packet filtering on a per-chain basis; see the chain-specific -# filter specification below in [chains.packet_filter]. -# 2. Filter for all activities based on client state trust threshold; this filter -# is parametrized with (numerator = 1, denominator = 3), so that clients with -# thresholds different than this will be ignored. -# If set to 'true', both of the above filters will be enabled. -filter = false - # Specify the verbosity for the relayer logging output. Default: 'info' # Valid options are 'error', 'warn', 'info', 'debug', 'trace'. log_level = 'debug' + +# Specify the mode to be used by the relayer. [Required] +[mode] + +# Specify the client mode. +[mode.clients] + +# Whether or not to enable the client workers. [Required] +enabled = true + +# Whether or not to enable periodic refresh of clients. [Default: true] +# Note: Even if this is disabled, clients will be refreshed automatically if +# there is activity on a connection or channel they are involved with. +refresh = true + +# Whether or not to enable misbehaviour detection for clients. [Default: false] +misbehaviour = true + +# Specify the connections mode. +[mode.connections] + +# Whether or not to enable the connection workers for handshake completion. [Required] +enabled = false + +# Specify the channels mode. +[mode.channels] + +# Whether or not to enable the channel workers for handshake completion. [Required] +enabled = false + +# Specify the packets mode. +[mode.packets] + +# Whether or not to enable the packet workers. [Required] +enabled = true + # Parametrize the periodic packet clearing feature. # Interval (in number of blocks) at which pending packets # should be eagerly cleared. A value of '0' will disable -# periodic packet clearing. Default: 100 -clear_packets_interval = 100 +# periodic packet clearing. [Default: 100] +clear_interval = 100 + +# Whether or not to clear packets on start. [Default: false] +clear_on_start = true # Toggle the transaction confirmation mechanism. # The tx confirmation mechanism periodically queries the `/tx_search` RPC # endpoint to check that previously-submitted transactions # (to any chain in this config file) have delivered successfully. # Experimental feature. Affects telemetry if set to false. -# Default: true. +# [Default: true] tx_confirmation = true - # The REST section defines parameters for Hermes' built-in RESTful API. # https://hermes.informal.systems/rest.html [rest] @@ -88,6 +109,8 @@ websocket_addr = 'ws://127.0.0.1:9944/websocket' # Specify the maximum amount of time (duration) that the RPC requests should # take before timing out. Default: 10s (10 seconds) +# Note: Hermes uses this parameter _only_ in `start` mode; for all other CLIs, +# Hermes uses a large preconfigured timeout (on the order of minutes). rpc_timeout = '10s' # Specify the prefix used by the chain. Required @@ -104,11 +127,11 @@ key_name = 'testkey' # 3) the message signing method. # The current configuration options are for Cosmos SDK and Ethermint. # -# Example configuration for Ethermint: +# Example configuration for chains based on Ethermint library: # # address_type = { derivation = 'ethermint', proto_type = { pk_type = '/injective.crypto.v1beta1.ethsecp256k1.PubKey' } } # -# Default: { derivation = 'cosmos' }, i.e. address derivation as in Cosmos SDK +# Default: { derivation = 'cosmos' }, i.e. address derivation as in Cosmos SDK. # Warning: This is an advanced feature! Modify with caution. address_type = { derivation = 'cosmos' } @@ -116,17 +139,23 @@ address_type = { derivation = 'cosmos' } # Recommended value for Cosmos SDK: 'ibc' store_prefix = 'ibc' +# Specify the default amount of gas to be used in case the tx simulation fails, +# and Hermes cannot estimate the amount of gas needed. +# Default: 100 000 +default_gas = 100000 + # Specify the maximum amount of gas to be used as the gas limit for a transaction. -# Default: 300000 -max_gas = 3000000 +# Default: 400 000 +max_gas = 400000 # Specify the price per gas used of the fee to submit a transaction and # the denomination of the fee. Required gas_price = { price = 0.001, denom = 'stake' } -# Specify by ratio to increase the gas estimate used to compute the fee, +# Specify the ratio by which to increase the gas estimate used to compute the fee, # to account for potential estimation error. Default: 0.1, ie. 10%. -gas_adjustment = 0.1 +# Valid range: 0.0 to 1.0 (inclusive) +gas_adjustment = 1.0 # Specify how many IBC messages at most to include in a single transaction. # Default: 30 @@ -141,6 +170,12 @@ max_tx_size = 2097152 # can drift into the future. Default: 5s clock_drift = '5s' +# Specify the maximum time per block for this chain. +# The block time together with the clock drift are added to the source drift to estimate +# the maximum clock drift when creating a client on this chain. Default: 10s +# For cosmos-SDK chains a good approximation is `timeout_propose` + `timeout_commit` +max_block_time = '10s' + # Specify the amount of time to be used as the light client trusting period. # It should be significantly less than the unbonding period # (e.g. unbonding period = 3 weeks, trusting period = 2 weeks). @@ -153,10 +188,16 @@ trusting_period = '14days' # Warning: This is an advanced feature! Modify with caution. trust_threshold = { numerator = '1', denominator = '3' } +# Specify a string that Hermes will use as a memo for each transaction it submits +# to this chain. The string is limited to 50 characters. Default: '' (empty). +# Note: Hermes will append to the string defined here additional +# operational debugging information, e.g., relayer build version. +memo_prefix = '' + # This section specifies the filters for policy based relaying. -# Default: no policy/ filters -# The section is ignored if the global 'filter' option is set to 'false'. -# If the global 'filter' option is set to 'true' and this section is missing then no filtering is performed for this chain. +# +# Default: no policy / filters, allow all packets on all channels. +# # Only packet filtering based on channel identifier can be specified. # A channel filter has two fields: # 1. `policy` - one of two types are supported: @@ -172,6 +213,11 @@ trust_threshold = { numerator = '1', denominator = '3' } # ['transfer', 'channel-0'], # ] +# Specify that the transaction fees should be payed from this fee granter's account. +# Optional. If unspecified (the default behavior), then no fee granter is used, and +# the account specified in `key_name` will pay the tx fees for all transactions +# submitted to this chain. +# fee_granter = '' [[chains]] id = 'ibc-1' @@ -183,12 +229,14 @@ rpc_timeout = '10s' account_prefix = 'substrate' key_name = 'testkey' store_prefix = 'ibc' -max_gas = 3000000 +default_gas = 100000 +max_gas = 400000 gas_price = { price = 0.001, denom = 'stake' } gas_adjustment = 0.1 max_msg_num = 30 max_tx_size = 2097152 clock_drift = '5s' +max_block_time = '10s' trusting_period = '14days' trust_threshold = { numerator = '1', denominator = '3' } address_type = { derivation = 'cosmos' } diff --git a/docs/architecture/adr-002-ibc-relayer.md b/docs/architecture/adr-002-ibc-relayer.md index e2aa1cec9..394725140 100644 --- a/docs/architecture/adr-002-ibc-relayer.md +++ b/docs/architecture/adr-002-ibc-relayer.md @@ -117,9 +117,27 @@ Below is an example of a configuration file. ```toml [global] -strategy = "packets" log_level = "error" +[mode] + +[mode.clients] +enabled = true +refresh = true +misbehaviour = true + +[mode.connections] +enabled = false + +[mode.channels] +enabled = false + +[mode.packets] +enabled = true +clear_interval = 100 +clear_on_start = true +tx_confirmation = true + [[chains]] id = "chain_A" rpc_addr = "http://localhost:26657" @@ -172,14 +190,7 @@ pub struct Config { pub connections: Option>, } -pub enum Strategy { - Packets, - HandshakeAndPackets, -} - pub struct GlobalConfig { - pub strategy: Strategy, - /// All valid log levels, as defined in tracing: /// https://docs.rs/tracing-core/0.1.17/tracing_core/struct.Level.html pub log_level: String, diff --git a/docs/architecture/adr-006-hermes-v0.2-usecases.md b/docs/architecture/adr-006-hermes-v0.2-usecases.md index 7a9b361f6..bbbabc559 100644 --- a/docs/architecture/adr-006-hermes-v0.2-usecases.md +++ b/docs/architecture/adr-006-hermes-v0.2-usecases.md @@ -252,7 +252,6 @@ of the config file will look as follows: ```toml [global] -strategy = 'packets' log_level = 'error' log_json = 'false' ``` diff --git a/docs/architecture/adr-007-error.md b/docs/architecture/adr-007-error.md index 95d072fc6..2faf45cd2 100644 --- a/docs/architecture/adr-007-error.md +++ b/docs/architecture/adr-007-error.md @@ -7,7 +7,7 @@ ## Context This document describes the reason behind the switch from using -[`anomaly`](https://docs.rs/anomaly) for error handling to +`anomaly` for error handling to the [`flex-error`](https://docs.rs/flex-error/) crate that is developed in-house. ## Decision diff --git a/docs/architecture/architecture.md b/docs/architecture/architecture.md new file mode 100644 index 000000000..ea549cfd8 --- /dev/null +++ b/docs/architecture/architecture.md @@ -0,0 +1,130 @@ +# Architecture + +This document describes the architecture of `ibc-rs`. If you're looking for a high-level overview of the code base, you've come to the right place! + +## Terms + +Some important terms and acronyms that are commonly used include: + + * **IBC**: Refers to the **I**nter**B**lockchain **C**ommunication protocol, a distributed protocol that allows different sovereign blockchains to communicate with one another. The protocol has both on-chain and off-chain components. + * **ICS**: Refers to **I**nter**C**hain **S**tandards, which are stadardization documents that capture the specifications of the IBC protocol across multiple documents. For example, ICS02 captures the client abstraction of the IBC protocol. + * **IBC module**: Refers to a piece of on-chain logic on an IBC-enabled chain. + * **Relayer**: Refers to an off-chain process that is responsible for relaying packets between chains. + * **Hermes**: Refers to the `ibc-rs` crate's particular relayer implementation. + +## Bird's Eye View + +![][layout-image] + +At its highest level, `ibc-rs` implements the InterBlockchain Communication protocol which is captured in [specifications in a separate repository][ibc-specs]. `ibc-rs` exposes modules that implement the specified protocol logic. The IBC protocol can be understood as having two separate components: on-chain and off-chain logic. The relayer, which is the main off-chain component, is a standalone process, of which Hermes is an implementation. On-chain components can be thought of as modules or smart contracts that run as part of a chain. The main on-chain components deal with the abstractions of clients, connections, and channels. + +## Code Map + +This section talks briefly about the various directories and modules in `ibc-rs`. + +### `modules`/`ibc` + +> Note: While the name of the directory is `modules`, the name of the crate is `ibc`. + +This crate contains the main data structures and on-chain logic of the IBC protocol; the fundamental pieces. There is the conceptual notion of 'handlers', which are pieces of code that each handle a particular type of message. The most notable handlers are the [client][ibc-client], [connection][ibc-connection], and [channel][ibc-channel] handlers. + +> Note: The naming of directories in the `ibc` crate follow a slightly different convention compared to the other crates in `ibc-rs`. This is because this crate implements the [ICS standards][ics-standards]. Modules in the `ibc` crate that implement a piece of the ICS standard are prefixed with the standard's designation. For example, the `modules/src/ics02_client` implements [ICS 02][ics02], which specifies the Client abstraction. These prefixes may be removed in the future. + +#### Core + +Consists of the designs and logic pertaining to the transport, authentication, and ordering layers of the IBC protocol, the fundamental pieces. + +##### ICS 02 - Client + +Clients encapsulate all of the verification methods of another IBC-enabled chain in order to ensure that the other chain adheres to the IBC protocol and does not exhibit misbehaviour. Clients "track" the metadata of the other chain's blocks, and each chain has a client for every other chain that it communicates with. + +##### ICS 03 - Connection + +Connections associate a chain with another chain by connecting a client on the local chain with a client on the remote chain. This association is pair-wise unique and is established between two chains following a 4-step handshake process. + +##### ICS 04 - Channel + +Channels are an abstraction layer that facilitate communication between applications and the chains those applications are built upon. One important function that channels can fulfill is guaranteeing that data packets sent between an application and its chain are well-ordered. + +##### ICS 05 - Port + +The port standard specifies an allocation scheme by which modules can bind to uniquely-named ports allocated by the IBC handler in order to facilitate module-to-module traffic. These ports are used to open channels and can be transferred or released by the module which originally bound them. + +##### ICS 23 - Commitment + +Commitments (sometimes called _vector commitments_) define an efficient cryptographic construction to prove inclusion or non-inclusion of values in at particular paths in state. This scheme provides a guarantee of a particular state transition that has occurred on one chain which can be verified on another chain. + +#### Applications + +Consists of various packet encoding and processing semantics which underpin the various types of transactions that users can perform on any IBC-compliant chain. + +##### ICS 20 - Fungible Token Transfer + +Specifies the packet data structure, state machine handling logic, and encoding details used for transferring fungible tokens between IBC chains. This process preserves asset fungibility and ownership while limiting the impact of Byzantine faults. + +#### Clients + +Consists of implementations of client verification algorithms (following the base client interface that is defined in `Core`) for specific types of chains. A chain uses these verification algorithms to verify the state of a remote chain. + +##### ICS 07 - Tendermint + +The Tendermint client implements a client verification algorithm for blockchains which use the Tendermint consensus algorithm. This enables state machines of various sorts replicated using the Tendermint consensus algorithm to interface with other replicated state machines or solo machines over IBC. + +#### Relayer + +Contains utilities for testing the `ibc` crate against the Hermes IBC relayer. It acts as scaffolding for gluing the `ibc` crate with Hermes for testing purposes. + +##### ICS 18 - Relayer + +Relayer algorithms are the "physical" connection layer of IBC — off-chain processes responsible for relaying data between two chains running the IBC protocol by scanning the state of each chain, constructing appropriate datagrams, and executing them on the opposite chain as allowed by the protocol. + +### `relayer` + +This crate provides the logic for relaying datagrams between chains. The process of relaying packets is an off-chain process that is kicked off by submitting transactions to read from or write to an IBC-enabled chain's state. More broadly, a relayer enables a chain to ascertain another chain's state by accessing its clients, connections, channels, or anything that is IBC-related. + +### `relayer-cli` + +A CLI wrapper around the `relayer` crate for running and issuing commands to a chain via a relayer. This crate exposes the Hermes binary. + +### `relayer-rest` + +An add-on to the CLI mainly for exposing some internal runtime details of Hermes for debugging and observability reasons. + +### `proto` + +Depends on the `proto-compiler` crate's generated proto files. + +Consists of protobuf-generated Rust types which are necessary for interacting with the Cosmos SDK. Also contains client and server methods that the relayer library includes for accessing the gRPC calls of a chain. + +### `proto-compiler` + +CLI tool to automate the compilation of proto buffers, which allows Hermes developers to go from a type specified in proto files to generate client gRPC code or server gRPC code. + +### `telemetry` + +Used by Hermes to gather telemetry data and expose it via a Prometheus endpoint. + +## Cross-Cutting Concerns + +### Testing + +Most of the components in the `ibc` crate (i.e. the `modules` directory) have basic unit testing coverage. These unit tests make use of mocked up chain components in order to ensure that message payloads are being sent and received as expected. + +We also run end-to-end tests to more thoroughly test IBC modules in a more heterogenous fashion. + +### Error Handling + +Most errors occur within the relayer as a result of either I/O operations or user misconfiguration. I/O-related errors can be sub-categorized into web socket errors and chain RPC errors. The latter occur when full nodes are out of sync with the rest of the network, which result in transactions that are based off of conflicting chain states. Such errors are usually either resolved by retrying the transaction, or might require operator intervention in order to flush the transaction from the mempool in conjunction with restarting the full node. + +The [flex-error][flex-error] library is the main tool used to handle errors in the code. This [demo][flex-error-demo] showcases some of the main patterns of how `flex-error` is used. For a more real-world example, [this][relayer-errors] file defines all of the possible errors for the relayer. + +[flex-error]: https://github.com/informalsystems/flex-error +[flex-error-demo]: https://github.com/informalsystems/flex-error/blob/master/flex-error-demo-full/src/main.rs +[ibc-specs]: https://github.com/cosmos/ibc#interchain-standards +[ics-standards]: https://github.com/cosmos/ibc#standardisation +[ibc-client]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/core/ics02_client +[ibc-connection]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/core/ics03_connection +[ibc-channel]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/core/ics04_channel +[ics02]: https://github.com/cosmos/ibc/blob/master/spec/core/ics-002-client-semantics/README.md +[layout-image]: assets/ibc-rs-layout.png +[relayer-errors]: https://github.com/informalsystems/ibc-rs/blob/master/relayer/src/error.rs diff --git a/docs/architecture/assets/ibc-rs-layout.png b/docs/architecture/assets/ibc-rs-layout.png new file mode 100644 index 000000000..9e68bae5f Binary files /dev/null and b/docs/architecture/assets/ibc-rs-layout.png differ diff --git a/e2e/e2e/channel.py b/e2e/e2e/channel.py index 960d20695..90921aff7 100644 --- a/e2e/e2e/channel.py +++ b/e2e/e2e/channel.py @@ -553,10 +553,14 @@ def verify_state(c: Config, ibc1: ChainId, ibc0: ChainId, ibc1_chan_id: ChannelId, port_id: PortId): - strategy = toml.load(c.config_file)['global']['strategy'] - # verify channel state on both chains, should be 'Open' for 'all' strategy, 'Init' otherwise - - if strategy == 'all': + mode = toml.load(c.config_file)['mode'] + clients_enabled = mode['clients']['enabled'] + conn_enabled = mode['connections']['enabled'] + chan_enabled = mode['channels']['enabled'] + packets_enabled = mode['packets']['enabled'] + + # verify connection state on both chains, should be 'Open' or 'Init' depending on config 'mode' + if clients_enabled and conn_enabled and chan_enabled and packets_enabled: sleep(10.0) for i in range(20): sleep(2.0) @@ -569,7 +573,7 @@ def verify_state(c: Config, assert (ibc0_chan_end.state == 'Open'), (ibc0_chan_end, "state is not Open") assert (ibc1_chan_end.state == 'Open'), (ibc1_chan_end, "state is not Open") - elif strategy == 'packets': + else: sleep(5.0) ibc1_chan_end = query_channel_end(c, ibc1, port_id, ibc1_chan_id) assert (ibc1_chan_end.state == 'Init'), (ibc1_chan_end, "state is not Init") diff --git a/e2e/e2e/client.py b/e2e/e2e/client.py index e1819f8fe..fd71a5ae1 100644 --- a/e2e/e2e/client.py +++ b/e2e/e2e/client.py @@ -60,7 +60,7 @@ class AllowUpdate: @dataclass class ClientState: chain_id: ChainId - frozen_height: Height + frozen_height: Optional[Height] latest_height: Height max_clock_drift: Duration trust_level: TrustLevel diff --git a/e2e/e2e/connection.py b/e2e/e2e/connection.py index 34248cb4f..834cfb644 100644 --- a/e2e/e2e/connection.py +++ b/e2e/e2e/connection.py @@ -263,14 +263,17 @@ def verify_state(c: Config, ibc1: ChainId, ibc0: ChainId, ibc1_conn_id: ConnectionId): - strategy = toml.load(c.config_file)['global']['strategy'] - l.debug(f'Using strategy: {strategy}') - - # verify connection state on both chains, should be 'Open' for 'all' strategy, 'Init' otherwise - if strategy == 'all': + mode = toml.load(c.config_file)['mode'] + clients_enabled = mode['clients']['enabled'] + conn_enabled = mode['connections']['enabled'] + chan_enabled = mode['channels']['enabled'] + packets_enabled = mode['packets']['enabled'] + + # verify connection state on both chains, should be 'Open' or 'Init' depending on config 'mode' + if clients_enabled and conn_enabled and chan_enabled and packets_enabled: sleep(10.0) for i in range(20): - sleep(2.0) + sleep(5.0) ibc1_conn_end = query_connection_end(c, ibc1, ibc1_conn_id) ibc0_conn_id = ibc1_conn_end.counterparty.connection_id ibc0_conn_end = query_connection_end(c, ibc0, ibc0_conn_id) @@ -280,7 +283,7 @@ def verify_state(c: Config, assert (ibc0_conn_end.state == 'Open'), (ibc0_conn_end, "state is not Open") assert (ibc1_conn_end.state == 'Open'), (ibc1_conn_end, "state is not Open") - elif strategy == 'packets': + else: sleep(5.0) ibc1_conn_end = query_connection_end(c, ibc1, ibc1_conn_id) assert (ibc1_conn_end.state == 'Init'), (ibc1_conn_end, "state is not Init") @@ -313,7 +316,7 @@ def passive_connection_init_then_start(c: Config, # 2. start hermes proc = relayer.start(c) - sleep(2.0) + sleep(10.0) # 3. wait for connection handshake to finish and verify connection state on both chains verify_state(c, ibc1, ibc0, ibc1_conn_id_a) @@ -334,7 +337,7 @@ def passive_connection_try_then_start(c: Config, # 2. start hermes proc = relayer.start(c) - sleep(2.0) + sleep(10.0) # 3. wait for connection handshake to finish and verify connection state on both chains verify_state(c, ibc1, ibc0, ibc1_conn_id_a) diff --git a/e2e/run.py b/e2e/run.py index e62d156c8..12aceb43d 100755 --- a/e2e/run.py +++ b/e2e/run.py @@ -22,11 +22,11 @@ def passive_packets( # 1. create some unreceived acks - # hermes tx raw ft-transfer ibc-1 ibc-0 transfer channel-0 10000 1000 -n 2 + # hermes tx raw ft-transfer ibc-1 ibc-0 transfer channel-0 10000 -o 1000 -n 2 packet.packet_send(c, src=ibc0, dst=ibc1, src_port=port_id, src_channel=ibc0_channel_id, amount=10000, height_offset=1000, number_msgs=2) - # hermes tx raw ft-transfer ibc-0 ibc-1 transfer channel-1 10000 1000 -n 2 + # hermes tx raw ft-transfer ibc-0 ibc-1 transfer channel-1 10000 -o 1000 -n 2 packet.packet_send(c, src=ibc1, dst=ibc0, src_port=port_id, src_channel=ibc1_channel_id, amount=10000, height_offset=1000, number_msgs=2) sleep(5.0) @@ -41,11 +41,11 @@ def passive_packets( # 2. create some unreceived packets - # hermes tx raw ft-transfer ibc-0 ibc-1 transfer channel-1 10000 1000 -n 3 + # hermes tx raw ft-transfer ibc-0 ibc-1 transfer channel-1 10000 -o 1000 -n 3 packet.packet_send(c, src=ibc1, dst=ibc0, src_port=port_id, src_channel=ibc1_channel_id, amount=10000, height_offset=1000, number_msgs=3) - # hermes tx raw ft-transfer ibc-1 ibc-0 transfer channel-0 10000 1000 -n 4 + # hermes tx raw ft-transfer ibc-1 ibc-0 transfer channel-0 10000 -o 1000 -n 4 packet.packet_send(c, src=ibc0, dst=ibc1, src_port=port_id, src_channel=ibc0_channel_id, amount=10000, height_offset=1000, number_msgs=4) diff --git a/guide/README.md b/guide/README.md index f85820e3e..4c98a7872 100644 --- a/guide/README.md +++ b/guide/README.md @@ -1,6 +1,6 @@ # Hermes Guide -Hermes is the name of the binary that comes packaged with +Hermes is the name of the binary that comes packaged with [IBC Relayer CLI](https://crates.io/crates/ibc-relayer-cli) crate. This directory comprises a comprehensive guide to Hermes. @@ -8,10 +8,10 @@ In order to build and view this guide you need to install [`mdBook`] (https://github.com/rust-lang/mdBook). mdBook is a utility to create modern online books from Markdown files. -This guide should be permanently deployed at its latest stable version at +This guide should be permanently deployed at its latest stable version at [hermes.informal.systems](https://hermes.informal.systems). -Current version: `0.7.3`. +Current version: `0.11.1`. The version of this guide is aligned with the [versioning of the ibc crates](../README.md). @@ -64,7 +64,7 @@ http://localhost:3000 ## Adding or editing new content to the guide -Please check the [mdBook documentation](https://rust-lang.github.io/mdBook/index.html) for additional information on how to add new content to the guide. +Please check the [mdBook documentation](https://rust-lang.github.io/mdBook/index.html) for additional information on how to add new content to the guide. Basically if you want to add new content to the guide, just add an entry to the `SUMMARY.md` Markdown file which is the TOC page. Then create a page for the entry you've added to the `SUMMARY.md` page. If you don't create the page, but save the `SUMMARY.md` file and build again, `mdBook` will create the page automatically for you. diff --git a/guide/src/SUMMARY.md b/guide/src/SUMMARY.md index 5283c013f..f4713b5d6 100644 --- a/guide/src/SUMMARY.md +++ b/guide/src/SUMMARY.md @@ -1,6 +1,6 @@ # Summary -# Hermes (v0.7.3) +# Hermes (v0.11.1) --- - [Introduction](./index.md) @@ -29,7 +29,7 @@ - [Commands Reference](./commands/index.md) - [Global options and JSON output](./commands/global.md) - [Keys](./commands/keys/index.md) - - [Config](./commands/config.md) + - [Config](./commands/config.md) - [Path setup](./commands/path-setup/index.md) - [Clients](./commands/path-setup/clients.md) - [Connections](./commands/path-setup/connections.md) diff --git a/guide/src/commands/global.md b/guide/src/commands/global.md index 166c255eb..7573da6c7 100644 --- a/guide/src/commands/global.md +++ b/guide/src/commands/global.md @@ -3,7 +3,7 @@ Hermes accepts global options which affect all commands. ```shell -hermes 0.7.3 +hermes 0.11.1 Informal Systems Implementation of `hermes`, an IBC Relayer developed in Rust. diff --git a/guide/src/commands/keys/index.md b/guide/src/commands/keys/index.md index 6c9c185d3..843736cf8 100644 --- a/guide/src/commands/keys/index.md +++ b/guide/src/commands/keys/index.md @@ -122,6 +122,15 @@ To restore a key from its mnemonic: hermes -c config.toml keys restore [CHAIN_ID] -m "[MNEMONIC]" ``` +or using an explicit [derivation path](https://github.com/satoshilabs/slips/blob/master/slip-0044.md), for example +an Ethereum coin type (used for Evmos, Injective, Umee, Cronos, and +possibly other networks): + +```shell +hermes -c config.toml keys restore --mnemonic --hd-path "m/44'/60'/0'/0/0" +``` + + If the command is successful a message similar to the one below will be displayed: ```json diff --git a/guide/src/commands/path-setup/channels.md b/guide/src/commands/path-setup/channels.md index 0f96e8ab1..4b44dd9e8 100644 --- a/guide/src/commands/path-setup/channels.md +++ b/guide/src/commands/path-setup/channels.md @@ -24,7 +24,7 @@ FLAGS: --port-a PORT-A identifier of the side `a` port for the new channel --port-b PORT-B identifier of the side `b` port for the new channel -o, --order ORDER the channel ordering, valid options 'unordered' (default) and 'ordered' - -v, --version VERSION the version for the new channel + -v, --channel-version VERSION the version for the new channel ``` ## Examples diff --git a/guide/src/commands/path-setup/clients.md b/guide/src/commands/path-setup/clients.md index 5e0c43b2d..0f79a0cb8 100644 --- a/guide/src/commands/path-setup/clients.md +++ b/guide/src/commands/path-setup/clients.md @@ -67,7 +67,7 @@ POSITIONAL ARGUMENTS: dst_client_id identifier of the client to be updated on destination chain FLAGS: - -h, --target-height TARGET-HEIGHT + -H, --target-height TARGET-HEIGHT -t, --trusted-height TRUSTED-HEIGHT ``` diff --git a/guide/src/commands/queries/channel.md b/guide/src/commands/queries/channel.md index 670ddbc8e..54c731f12 100644 --- a/guide/src/commands/queries/channel.md +++ b/guide/src/commands/queries/channel.md @@ -79,7 +79,7 @@ POSITIONAL ARGUMENTS: channel_id identifier of the channel to query FLAGS: - -h, --height HEIGHT height of the state to query + -H, --height HEIGHT height of the state to query ``` __Example__ @@ -131,7 +131,7 @@ POSITIONAL ARGUMENTS: channel_id identifier of the channel to query FLAGS: - -h, --height HEIGHT height of the state to query + -H, --height HEIGHT height of the state to query -v, --verbose enable verbose output, displaying all details of channels, connections & clients ``` @@ -181,4 +181,4 @@ Success: ChannelEndsSummary { ``` Passing the `-v` flag will additionally print all the details of the -channel, connection, and client on both ends. \ No newline at end of file +channel, connection, and client on both ends. diff --git a/guide/src/commands/queries/client.md b/guide/src/commands/queries/client.md index 85001ab55..1603f8332 100644 --- a/guide/src/commands/queries/client.md +++ b/guide/src/commands/queries/client.md @@ -100,7 +100,7 @@ POSITIONAL ARGUMENTS: client_id identifier of the client to query FLAGS: - -h, --height HEIGHT the chain height which this query should reflect + -H, --height HEIGHT the chain height which this query should reflect ``` __Example__ @@ -159,7 +159,7 @@ POSITIONAL ARGUMENTS: FLAGS: -c, --consensus-height CONSENSUS-HEIGHT -s, --heights-only show only consensus heights - -h, --height HEIGHT the chain height context to be used, applicable only to a specific height + -H, --height HEIGHT the chain height context to be used, applicable only to a specific height ``` __Example__ @@ -235,7 +235,7 @@ POSITIONAL ARGUMENTS: client_id identifier of the client to query FLAGS: - -h, --height HEIGHT the chain height which this query should reflect + -H, --height HEIGHT the chain height which this query should reflect ``` __Example__ @@ -268,7 +268,7 @@ POSITIONAL ARGUMENTS: consensus_height height of header to query FLAGS: - -h, --height HEIGHT the chain height context for the query + -H, --height HEIGHT the chain height context for the query ``` __Example__ diff --git a/guide/src/commands/queries/connection.md b/guide/src/commands/queries/connection.md index 8529218eb..2f2c4ad61 100644 --- a/guide/src/commands/queries/connection.md +++ b/guide/src/commands/queries/connection.md @@ -68,7 +68,7 @@ POSITIONAL ARGUMENTS: connection_id identifier of the connection to query FLAGS: - -h, --height HEIGHT height of the state to query + -H, --height HEIGHT height of the state to query ``` __Example__ diff --git a/guide/src/commands/queries/packet.md b/guide/src/commands/queries/packet.md index 62ad310a5..6d76ade40 100644 --- a/guide/src/commands/queries/packet.md +++ b/guide/src/commands/queries/packet.md @@ -82,7 +82,7 @@ POSITIONAL ARGUMENTS: sequence sequence of packet to query FLAGS: - -h, --height HEIGHT height of the state to query + -H, --height HEIGHT height of the state to query ``` __Example__ @@ -154,7 +154,7 @@ POSITIONAL ARGUMENTS: sequence sequence of packet to query FLAGS: - -h, --height HEIGHT height of the state to query + -H, --height HEIGHT height of the state to query ``` __Example__ diff --git a/guide/src/commands/raw/client.md b/guide/src/commands/raw/client.md index 4be3bc69f..b0041246e 100644 --- a/guide/src/commands/raw/client.md +++ b/guide/src/commands/raw/client.md @@ -63,7 +63,7 @@ POSITIONAL ARGUMENTS: dst_client_id identifier of the client to be updated on destination chain FLAGS: - -h, --target-height TARGET-HEIGHT + -H, --target-height TARGET-HEIGHT -t, --trusted-height TRUSTED-HEIGHT ``` diff --git a/guide/src/commands/relaying/handshakes.md b/guide/src/commands/relaying/handshakes.md index e99f3bf0b..a504cffaf 100644 --- a/guide/src/commands/relaying/handshakes.md +++ b/guide/src/commands/relaying/handshakes.md @@ -5,11 +5,26 @@ for connections and channels. ## The `start` Command -To relay packets and handshake messages use `all` as strategy in the `global` section of the configuration file: +To relay packets and handshake messages configure the `mode` section of the configuration file like so: ```toml [global] -strategy = 'all' log_level = 'info' + +[mode] + +[mode.clients] +enabled = true +# ... + +[mode.connections] +enabled = true + +[mode.channels] +enabled = true + +[mode.packets] +enabled = true +# ... ``` Then start hermes using the start command: @@ -28,15 +43,15 @@ the configured chains. Assuming the events are coming from a `source` chain, the relayer determines the `destination` chain and builds the handshake messages based on these events. These are then sent to the `destination` chain. -In addition to the events described in [Packet Relaying](packets.md#packet-relaying), in the `all` strategy mode the following IBC events are handled: +In addition to the events described in [Packet Relaying](packets.md#packet-relaying), the following IBC events may be handled: -- Channels: +- Channels (if `mode.channels.enabled=true`): - `chan_open_init`: the relayer builds a `MsgChannelOpenTry` message - `chan_open_try`: the relayer builds a `MsgChannelOpenAck` message - `chan_open_ack`: the relayer builds a `MsgChannelOpenConfirm` message - `chan_open_confirm`: no message is sent out, channel opening is finished -- Connections: +- Connections (if `mode.connections.enabled=true`): - `conn_open_init`: the relayer builds a `MsgConnOpenTry` message - `conn_open_try`: the relayer builds a `MsgConnOpenAck` message - `conn_open_ack`: the relayer builds a `MsgConnOpenConfirm` message diff --git a/guide/src/commands/relaying/packets.md b/guide/src/commands/relaying/packets.md index 8ee0a6925..88644dcaf 100644 --- a/guide/src/commands/relaying/packets.md +++ b/guide/src/commands/relaying/packets.md @@ -9,11 +9,26 @@ This section describes the configuration and commands that can be used to start ## The `start` Command -To relay packets only use `packets` as strategy in the `global` section of the configuration file: +To relay packets only configure the `mode` section of the configuration file like so: ```toml [global] -strategy = 'packets' log_level = 'info' + +[mode] + +[mode.clients] +enabled = true +# ... + +[mode.connections] +enabled = false + +[mode.channels] +enabled = false + +[mode.packets] +enabled = true +# ... ``` Then start hermes using the start command: diff --git a/guide/src/config.md b/guide/src/config.md index 80e76ec95..8c2491b2c 100644 --- a/guide/src/config.md +++ b/guide/src/config.md @@ -20,154 +20,65 @@ hermes [-c CONFIG_FILE] COMMAND -## Configuration format +## Configuration The configuration file must have one `global` section, and one `chains` section for each chain. > **Note:** As of 0.6.0, the Hermes configuration file is self-documented. -> This section of the guide which discusses each parameter in turn is no -> longer maintained, and we may remove it soon. Please read the configuration -> file [`config.toml`](https://github.com/informalsystems/ibc-rs/blob/v0.7.3/config.toml) itself for the most up-to-date documentation of parameters. +> Please read the configuration file [`config.toml`](https://github.com/informalsystems/ibc-rs/blob/v0.11.1/config.toml) +> itself for the most up-to-date documentation of parameters. -### `[global]` +By default, Hermes will relay on all channels available between all the configured chains. +In this way, every configured chain will act as a source (in the sense that Hermes listens for events) +and as a destination (to relay packets that others chains have sent). -The `global` section has parameters that apply globally to the relayer operation. +For example, if there are only two chains configured, then Hermes will only relay packets between those two, +i.e. the two chains will serve as a source for each other, and likewise as a destination for each other's relevant events. +Hermes will ignore all events that pertain to chains which are unknown (ie. not present in config.toml). -#### Parameters +To restrict relaying on specific channels, or uni-directionally, you can use [packet filtering policies](https://github.com/informalsystems/ibc-rs/blob/v0.11.1/config.toml#L207-L224). -* __strategy__: *(string)* Specify the strategy to be used by the relayer. Default: `packets` - Two options are currently supported: - - `all`: Relay packets and perform channel and connection handshakes. - - `packets`: Relay packets only. +## Adding private keys -* __log_level__: *(string)* Specify the verbosity for the relayer logging output. Valid options are 'error', 'warn', 'info', 'debug', 'trace'. Default: `info`. - For more information on parametrizing the log output, see the section [help/log-level][log-level]. +For each chain configured you need to add a private key for that chain in order to submit [transactions](./commands/raw/index.md), +please refer to the [Keys](./commands/keys/index.md) sections in order to learn how to add the private keys that are used by the relayer. -Here is an example for the `global` section: +## Example configuration file + +Here is a full example of a configuration file with two chains configured: ```toml [global] -strategy = 'packets' log_level = 'info' -``` - -### `[telemetry]` - -The `telemetry` section defines parameters for Hermes' built-in [telemetry](telemetry.md) capabilities. - -#### Parameters - -* __enabled__: *(boolean)* Whether or not to enable the telemetry service. Default: `false`. -* __host__: *(string)* Specify the IPv4/6 host over which the built-in HTTP server will serve the metrics gathered by the telemetry service. Default: `127.0.0.1` +[mode] -* __port__: *(u16)* Specify the port over which the built-in HTTP server will serve the metrics gathered by the telemetry service. Default: `3001` - -Here is an example for the `telemetry` section: - -```toml -[telemetry] +[mode.clients] enabled = true -host = '127.0.0.1' -port = 3001 -``` - -### `[rest]` - -The `rest` section defines parameters for Hermes' built-in [REST API](rest-api.md).. - -#### Parameters - -* __enabled__: *(boolean)* Whether or not to enable the built-in REST server. Default: `false`. +refresh = true +misbehaviour = true -* __host__: *(string)* Specify the IPv4/6 host over which the built-in HTTP server will be listening. Default: `127.0.0.1` +[mode.connections] +enabled = false -* __port__: *(u16)* Specify the port over which the built-in HTTP server will be listening. Default: `3000` +[mode.channels] +enabled = false -Here is an example for the `rest` section: +[mode.packets] +enabled = true +clear_interval = 100 +clear_on_start = true +tx_confirmation = true -```toml [rest] enabled = true -host = '127.0.0.1' -port = 3000 -``` - -### `[[chains]]` - -A `chains` section includes parameters related to a chain and the full node to which the relayer can send transactions and queries. - -#### Parameters - -* __id__: *(string)* Specify the chain ID. For example `ibc-0` - -* __rpc_addr__: *(string)* Specify the RPC address and port where the chain RPC server listens on. For example `http://localhost:26657` - -* __grpc_addr__: *(string)* Specify the GRPC address and port where the chain GRPC server listens on. For example `http://localhost:9090` - -* __websocket_addr__: *(string)* Specify the WebSocket address and port where the chain WebSocket server listens on. For example `ws://localhost:26657/websocket` - -* __rpc_timeout__: *(string)* Specify the maximum amount of time (duration) that the RPC requests should take before timing out. Default: `10s` (10 seconds). - -* __account_prefix__: *(string)* Specify the prefix used by the chain. For example `cosmos` - -* __key_name__: *(string)* Specify the name of the private key to use for signing transactions. See the [Adding Keys](commands/keys/index.md#adding-keys) chapter for for more information about managing signing keys. - -* __store_prefix__: *(string)* Specify the store prefix used by the on-chain IBC modules. For example `ibc`. - -* __max_gas__: *(u64)* Specify the maximum amount of gas to be used as the gas limit for a transaction. Default: `300000` - -* __gas_price__: *(table)* - * __price__: *(f64)* Specify the price per gas used of the fee to submit a transaction. - * __denom__: *(string)* Specify the denomination of the fee. - -* __gas_adjustment__: *(f64)* Specify by what percentage to increase the gas estimate used to compute the fee, to account for potential estimation error. Default: `0.1`, ie. 10%. - -* __max_msg_num__: *(u64)* Specify how many IBC messages at most to include in a single transaction. Default: `30` +host = '127.0.0.1' +port = 3000 -* __max_tx_size__: *(u64)* Specify the maximum size, in bytes, of each transaction that Hermes will submit. Default: `2097152` (2 MiB) - -* __clock_drift__: *(string)* Specify the maximum amount of time to tolerate a clock drift. The clock drift parameter defines how much new (untrusted) header's Time can drift into the future. Default: `5s` - -* __trusting_period__: *(string)* Specify the amount of time to be used as the light client trusting period. It should be significantly less than the unbonding period (e.g. unbonding period = 3 weeks, trusting period = 2 weeks). Default: `14days` (336 hours) - -* __trust_threshold__ (advanced): *(table)* Specify the trust threshold for the light client, ie. the maximum fraction of validators which have changed between two blocks. Default: `{ numerator = '1', denominator = '3' }`, ie. 1/3. - * __numerator__: *(string)* The numerator of the fraction (must parse to a `u64`). - * __denominator__: *(string)* The denominator of the fraction (must parse to a `u64`). - - __Warning__ - _This is an advanced feature! Modify with caution._ - -For example if you want to add a configuration for a chain named `ibc-0`: - -```toml -[[chains]] -id = 'ibc-0' -rpc_addr = 'http://127.0.0.1:26657' -grpc_addr = 'http://127.0.0.1:9090' -websocket_addr = 'ws://localhost:26657/websocket' -rpc_timeout = '10s' -account_prefix = 'cosmos' -key_name = 'testkey' -store_prefix = 'ibc' -max_gas = 2000000 -gas_price = { price = 0.001, denom = 'stake' } -gas_adjustment = 0.1 -clock_drift = '5s' -trusting_period = '14days' -``` - -## Adding private keys - -For each chain configured you need to add a private key for that chain in order to submit [transactions](./commands/raw/index.md), please refer to the [Keys](./commands/keys/index.md) sections in order to learn how to add the private keys that are used by the relayer. - -## Example configuration file - -Here is a full example of a configuration file with two chains configured: - -```toml -[global] -strategy = 'packets' -log_level = 'info' +[telemetry] +enabled = true +host = '127.0.0.1' +port = 3001 [[chains]] id = 'ibc-0' @@ -179,6 +90,7 @@ account_prefix = 'cosmos' key_name = 'testkey' store_prefix = 'ibc' max_gas = 2000000 +fee_granter = '' gas_price = { price = 0.001, denom = 'stake' } gas_adjustment = 0.1 clock_drift = '5s' diff --git a/guide/src/features.md b/guide/src/features.md index 9680e75db..5dcb606a2 100644 --- a/guide/src/features.md +++ b/guide/src/features.md @@ -4,11 +4,11 @@ This section includes a summary of the supported and planned features. A feature matrix and comparison between the Rust and Go relayer implementations can be found in the [Feature Matrix](./features/matrix.md) > **Cosmos SDK compatibility:** -> Hermes supports Cosmos SDK chains implementing the [IBC v1.0][ibcv1] protocol specification. -> Cosmos SDK versions `0.41.3` to `0.44.0` are officially supported. +> Hermes supports Cosmos SDK chains implementing the [IBC v1.1][ibcv1] protocol specification. +> Cosmos SDK versions `0.41.3` to `0.44.x` are officially supported. > In case Hermes finds an incompatible SDK version, it will output a log warning. -[ibcv1]: https://github.com/cosmos/ibc-go/tree/main/proto/ibc +[ibcv1]: https://github.com/cosmos/ibc-go ## Supported Features diff --git a/guide/src/help.md b/guide/src/help.md index 93f2426c5..a228816b8 100644 --- a/guide/src/help.md +++ b/guide/src/help.md @@ -74,10 +74,11 @@ FLAGS: --port-a PORT-A identifier of the side `a` port for the new channel --port-b PORT-B identifier of the side `b` port for the new channel -o, --order ORDER the channel ordering, valid options 'unordered' (default) and 'ordered' - -v, --version VERSION the version for the new channel + -v, --channel-version VERSION the version for the new channel ``` -The `help` command is a replacement of the familiar `-h`/ `--help` flag typical for CLI applications. +Additionally, the `-h`/`--help` flags typical for CLI applications work on +all commands. ## Parametrizing the log output level @@ -89,7 +90,6 @@ Relevant snippet: ```toml [global] -strategy = 'packets' log_level = 'error' ``` diff --git a/guide/src/index.md b/guide/src/index.md index cb19f9d9c..962b98e3b 100644 --- a/guide/src/index.md +++ b/guide/src/index.md @@ -1,7 +1,11 @@ -# Hermes Guide (v0.7.3) +# Hermes Guide (v0.11.1) + + +Hermes is a an open-source Rust implementation of a relayer for the +[Inter-Blockchain Communication protocol](https://ibcprotocol.org) (IBC). This guide can help you setup, configure, and operate Hermes to transfer -packets between two IBC enabled chains. +packets between two or more IBC-enabled chains. ## Sections @@ -47,4 +51,3 @@ packets between two IBC enabled chains. ## Disclaimer This project is undergoing heavy development, use at your own risk. - diff --git a/guide/src/installation.md b/guide/src/installation.md index ddbff872f..8c492a394 100644 --- a/guide/src/installation.md +++ b/guide/src/installation.md @@ -14,11 +14,11 @@ There are two main approaches for obtaining Hermes: Simply head to the GitHub [Releases][releases] page and download the latest version of Hermes binary matching your platform: -- MacOS: `hermes-v0.7.3-x86_64-apple-darwin.tar.gz` (or .zip), -- Linux: `hermes-v0.7.3-x86_64-unknown-linux-gnu.tar.gz` (or .zip). +- MacOS: `hermes-v0.11.1-x86_64-apple-darwin.tar.gz` (or .zip), +- Linux: `hermes-v0.11.1-x86_64-unknown-linux-gnu.tar.gz` (or .zip). The step-by-step instruction below should carry you through the whole process: - + 1. Make the directory where we'll place the binary: ```shell mkdir -p $HOME/.hermes/bin @@ -47,7 +47,7 @@ hermes version ``` ``` -hermes 0.7.3 +hermes 0.11.1 ``` ## Install via Cargo @@ -62,7 +62,7 @@ To install the latest release of Hermes, run the following command in a terminal cargo install ibc-relayer-cli --bin hermes --locked ``` -This will download and build the crate `ibc-relayer-cli`, and install the +This will download and build the crate `ibc-relayer-cli`, and install the `hermes` binary in `$HOME/.cargo/bin`. > If you have not installed Rust and Cargo via [rustup.rs](https://rustup.rs), you may need to @@ -81,7 +81,7 @@ hermes version ``` ``` -hermes 0.7.3 +hermes 0.11.1 ``` ## Build from source @@ -103,10 +103,10 @@ cd ibc-rs Go to the [ibc-rs releases](https://github.com/informalsystems/ibc-rs/releases) page to see what is the most recent release. -Then checkout the release, for example if the most recent release is `v0.7.3` then execute the command: +Then checkout the release, for example if the most recent release is `v0.11.1` then execute the command: ```shell -git checkout v0.7.3 +git checkout v0.11.1 ``` ### Building with `cargo build` @@ -151,7 +151,7 @@ If you run the `hermes` without any additional parameters you should see the usa ``` ``` -hermes 0.7.3 +hermes 0.11.1 Informal Systems USAGE: @@ -180,7 +180,41 @@ It might be easier to create an alias for `hermes` so you can just run it by spe alias hermes='cargo run --release --bin hermes --' ``` -### Next Steps +## Shell auto-completions + +The `completions` subcommand of Hermes can be used to output a completion script +for a choice of widely used command-line shells. +Refer to `hermes completions --help` for the list. Some shell-specific examples +of setting up auto-completion with this command are provided below; check your +shell configuration to decide on the suitable directory in which to install the script +and any further necessary modifications to the shell's startup files. + +### Bash + +```sh +hermes completions bash > ~/.local/share/bash-completion/completions/hermes +``` + +On a MacOS installation with Homebrew `bash-completion` formula installed, use + +```sh +hermes completions bash > $(brew --prefix)/etc/bash_completion.d/hermes.bash-completion +``` + +### Zsh + +```sh +hermes completions zsh > ~/.zfunc/_hermes +``` + +To make the shell load the script on initialization, add the directory to `fpath` +in your `~/.zshrc` before `compinit`: + +``` +fpath+=~/.zfunc +``` + +## Next Steps Go to the [`Configuration`](./config.md) section to learn how to create a configuration file to be used by Hermes. diff --git a/guide/src/pre_requisites.md b/guide/src/pre_requisites.md index c4ee4bc57..a03dd6296 100644 --- a/guide/src/pre_requisites.md +++ b/guide/src/pre_requisites.md @@ -12,7 +12,7 @@ The provided instructions will install all the Rust toolchain including `rustc`, ### Version requirements -Hermes is developed and tested using the latest version of Rust, `1.52` at +Hermes is developed and tested using the latest version of Rust, `1.58` at the moment. To check that your toolchain is up-to-date run: ```shell diff --git a/guide/src/relayer.md b/guide/src/relayer.md index 515fe5da3..ef9e2ff32 100644 --- a/guide/src/relayer.md +++ b/guide/src/relayer.md @@ -1,6 +1,7 @@ # What is Hermes? -Hermes is a an open-source Rust implementation of a relayer for the [Inter-Blockchain Communication protocol](https://cosmos.network/ibc) (IBC), +Hermes is a an open-source Rust implementation of a relayer for the +[Inter-Blockchain Communication protocol](https://ibcprotocol.org) (IBC), released under the [ibc-relayer-cli](https://crates.io/crates/ibc-relayer-cli) crate. The **Inter-Blockchain Communication protocol** is an end-to-end, connection-oriented, diff --git a/guide/src/rest-api.md b/guide/src/rest-api.md index 1bd129a20..40c046475 100644 --- a/guide/src/rest-api.md +++ b/guide/src/rest-api.md @@ -39,7 +39,7 @@ as the version of the REST server itself (under the `ibc-relayer-rest` key). [ { "name": "ibc-relayer", - "version": "0.7.3" + "version": "0.11.1" }, { "name": "ibc-relayer-rest", @@ -175,4 +175,3 @@ of all the workers which are currently active. } } ``` - diff --git a/guide/src/tutorials/local-chains/relay-paths/multiple-paths.md b/guide/src/tutorials/local-chains/relay-paths/multiple-paths.md index 0c0839e1c..c24d738ab 100644 --- a/guide/src/tutorials/local-chains/relay-paths/multiple-paths.md +++ b/guide/src/tutorials/local-chains/relay-paths/multiple-paths.md @@ -8,9 +8,27 @@ Follow the steps below to connect three chains together and relay packets betwee ```toml [global] - strategy = 'packets' log_level = 'info' + [mode] + + [mode.clients] + enabled = true + refresh = true + misbehaviour = true + + [mode.connections] + enabled = false + + [mode.channels] + enabled = false + + [mode.packets] + enabled = true + clear_interval = 100 + clear_on_start = true + tx_confirmation = true + [[chains]] id = 'ibc-0' rpc_addr = 'http://127.0.0.1:26657' diff --git a/guide/src/tutorials/local-chains/start.md b/guide/src/tutorials/local-chains/start.md index fb3e064df..530cfb98b 100644 --- a/guide/src/tutorials/local-chains/start.md +++ b/guide/src/tutorials/local-chains/start.md @@ -8,7 +8,7 @@ To this end, clone the `ibc-rs` repository and check out the current version: ```bash git clone git@github.com:informalsystems/ibc-rs.git cd ibc-rs -git checkout v0.7.3 +git checkout v0.11.1 ``` ### Stop existing `gaiad` processes diff --git a/modules/Cargo.toml b/modules/Cargo.toml index c2111cfda..fa809778e 100644 --- a/modules/Cargo.toml +++ b/modules/Cargo.toml @@ -1,66 +1,52 @@ [package] -name = "ibc" -version = "0.7.3" -edition = "2018" -license = "Apache-2.0" -readme = "README.md" -keywords = ["blockchain", "consensus", "cosmos", "ibc", "tendermint"] -repository = "https://github.com/informalsystems/ibc-rs" -authors = ["Informal Systems "] - -description = """ +name = "ibc" +version = "0.11.1" +edition = "2021" +license = "Apache-2.0" +readme = "README.md" +keywords = ["blockchain", "consensus", "cosmos", "ibc", "tendermint"] +repository = "https://github.com/informalsystems/ibc-rs" +authors = ["Informal Systems "] +rust-version = "1.58" +description = """ Implementation of the Inter-Blockchain Communication Protocol (IBC). This crate comprises the main data structures and on-chain logic. """ +[package.metadata.docs.rs] +all-features = true + [features] -default = ["std", "eyre_tracer"] -std = [ - "flex-error/std", - "ibc-proto/std", - "ics23/std", - "chrono/std", - "serde/std", - "serde_json/std", - "tracing/std", - "prost/std", - "prost-types/std", - "bytes/std", - "subtle-encoding/std", - "sha2/std", - "tendermint/std", - "tendermint-proto/std", - "beefy-merkle-tree/std", - "codec/std", - "beefy-light-client/std", - "sp-core/std", - "sp-runtime/std", - "sp-trie/std", - "sp-std/std", - "frame-system/std" -# "tendermint-testgen/std", +default = ["std"] +std = ["flex-error/std", "flex-error/eyre_tracer", "ibc-proto/std", "clock"] +clock = [ + "tendermint/clock", + "time/std" ] -eyre_tracer = ["flex-error/eyre_tracer"] + # This feature grants access to development-time mocking libraries, such as `MockContext` or `MockHeader`. # Depends on the `testgen` suite for generating Tendermint light blocks. -mocks = [ "tendermint-testgen", "sha2" ] +mocks = ["tendermint-testgen", "clock", "std"] [dependencies] # Proto definitions for all IBC-related interfaces, e.g., connections or channels. -ibc-proto = { version = "0.11.0", path = "../proto", default-features = false } -ics23 = { version = "0.6.5", default-features = false } -chrono = { version = "0.4.19", default-features = false } -serde_derive = { version = "1.0.104" } -serde = { version = "1.0.130", default-features = false } +ibc-proto = { version = "0.15.0", path = "../proto", default-features = false } +ics23 = { version = "0.6.7", default-features = false } +time = { version = "0.3", default-features = false } +serde_derive = { version = "1.0.104", default-features = false } +serde = { version = "1.0", default-features = false } serde_json = { version = "1", default-features = false } -tracing = { version = "0.1.28", default-features = false } -prost = { package = "informalsystems-prost", version = "0.8.1", default-features = false } -prost-types = { package = "informalsystems-prost-types", version = "0.8.1", default-features = false } +tracing = { version = "0.1.30", default-features = false } +prost = { version = "0.9", default-features = false } +prost-types = { version = "0.9", default-features = false } bytes = { version = "1.1.0", default-features = false } -safe-regex = { version = "0.2.4" } +safe-regex = { version = "0.2.5", default-features = false } subtle-encoding = { version = "0.5", default-features = false } -sha2 = { version = "0.9.8", default-features = false, optional = true } -flex-error = { version = "0.4.3", default-features = false } +sha2 = { version = "0.10.1", default-features = false } +flex-error = { version = "0.4.4", default-features = false } +num-traits = { version = "0.2.14", default-features = false } +derive_more = { version = "0.99.17", default-features = false, features = ["from", "display"] } + beefy-light-client = { git = "https://github.com/octopus-network/beefy-light-client.git", default-features = false } codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] } beefy-merkle-tree = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.12", features = ["keccak"], default-features = false } @@ -74,30 +60,33 @@ frame-support = { git = "https://github.com/paritytech/substrate", branch = "pol frame-system = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.12", default-features = false } [dependencies.tendermint] -version = "=0.22.0" +version = "=0.23.5" default-features = false [dependencies.tendermint-proto] -version = "=0.22.0" +version = "=0.23.5" +default-features = false + +[dependencies.tendermint-light-client-verifier] +version = "=0.23.5" default-features = false [dependencies.tendermint-testgen] -version = "=0.22.0" +version = "=0.23.5" optional = true default-features = false [dev-dependencies] env_logger = "0.9.0" -tracing-subscriber = { version = "0.3.6", features = ["fmt", "env-filter", "json"]} -test-env-log = { version = "0.2.7", features = ["trace"] } +tracing-subscriber = { version = "0.3.8", features = ["fmt", "env-filter", "json"]} test-log = { version = "0.2.8", features = ["trace"] } modelator = "0.4.2" sha2 = { version = "0.10.1" } +tendermint-rpc = { version = "=0.23.5", features = ["http-client", "websocket-client"] } +tendermint-testgen = { version = "=0.23.5" } # Needed for generating (synthetic) light blocks. codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"] } -tendermint-rpc = { version = "=0.22.0", features = ["http-client", "websocket-client"] } -tendermint-testgen = { version = "=0.22.0" } # Needed for generating (synthetic) light blocks. hex-literal = "0.3.1" -octopusxt = { git = "https://github.com/octopus-network/octopusxt.git", branch = "main", version = "0.1.0" } +#octopusxt = { git = "https://github.com/octopus-network/octopusxt.git", branch = "main", version = "0.1.0" } tokio = { version = "1.0", features = ["rt-multi-thread", "time", "sync"] } subxt = { version = "0.15.0", git = "https://github.com/octopus-network/substrate-subxt.git", branch = 'octopus-v0.9.12' } diff --git a/modules/src/application/ics20_fungible_token_transfer/context.rs b/modules/src/application/ics20_fungible_token_transfer/context.rs deleted file mode 100644 index a39773d0b..000000000 --- a/modules/src/application/ics20_fungible_token_transfer/context.rs +++ /dev/null @@ -1,5 +0,0 @@ -use crate::ics04_channel::context::{ChannelKeeper, ChannelReader}; - -/// Captures all the dependencies which the ICS20 module requires to be able to dispatch and -/// process IBC messages. -pub trait Ics20Context: ChannelReader + ChannelKeeper + Clone {} diff --git a/modules/src/application/ics20_fungible_token_transfer/mod.rs b/modules/src/application/ics20_fungible_token_transfer/mod.rs deleted file mode 100644 index 9987bb891..000000000 --- a/modules/src/application/ics20_fungible_token_transfer/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -//! ICS 20: IBC Transfer implementation -pub mod context; -pub mod error; -pub mod msgs; -pub mod relay_application_logic; diff --git a/modules/src/application/mod.rs b/modules/src/application/mod.rs deleted file mode 100644 index c3eb98a34..000000000 --- a/modules/src/application/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub mod ics20_fungible_token_transfer; - -// TODO: These consts should move into the ICS27 namespace -pub const ICS27_BANK_SEND_TYPE_URL: &str = "/cosmos.bank.v1beta1.MsgSend"; -pub const ICS27_SEND_TYPE_URL: &str = "/intertx.MsgSend"; -pub const ICS27_REGISTER_TYPE_URL: &str = "/intertx.MsgRegister"; diff --git a/modules/src/applications/ics20_fungible_token_transfer/context.rs b/modules/src/applications/ics20_fungible_token_transfer/context.rs new file mode 100644 index 000000000..58b7e6aac --- /dev/null +++ b/modules/src/applications/ics20_fungible_token_transfer/context.rs @@ -0,0 +1,5 @@ +use crate::core::ics04_channel::context::{ChannelKeeper, ChannelReader}; + +/// Captures all the dependencies which the ICS20 module requires to be able to dispatch and +/// process IBC messages. +pub trait Ics20Context: ChannelReader + ChannelKeeper {} diff --git a/modules/src/applications/ics20_fungible_token_transfer/denom.rs b/modules/src/applications/ics20_fungible_token_transfer/denom.rs new file mode 100644 index 000000000..542e25f00 --- /dev/null +++ b/modules/src/applications/ics20_fungible_token_transfer/denom.rs @@ -0,0 +1,28 @@ +use sha2::{Digest, Sha256}; +use subtle_encoding::hex; + +use crate::core::ics24_host::identifier::{ChannelId, PortId}; +use crate::prelude::*; + +use super::error::Error; + +pub fn derive_ibc_denom( + port_id: &PortId, + channel_id: &ChannelId, + denom: &str, +) -> Result { + let transfer_path = format!("{}/{}/{}", port_id, channel_id, denom); + derive_ibc_denom_with_path(&transfer_path) +} + +/// Derive the transferred token denomination using +/// +pub fn derive_ibc_denom_with_path(transfer_path: &str) -> Result { + let mut hasher = Sha256::new(); + hasher.update(transfer_path.as_bytes()); + + let denom_bytes = hasher.finalize(); + let denom_hex = String::from_utf8(hex::encode_upper(denom_bytes)).map_err(Error::utf8)?; + + Ok(format!("ibc/{}", denom_hex)) +} diff --git a/modules/src/application/ics20_fungible_token_transfer/error.rs b/modules/src/applications/ics20_fungible_token_transfer/error.rs similarity index 76% rename from modules/src/application/ics20_fungible_token_transfer/error.rs rename to modules/src/applications/ics20_fungible_token_transfer/error.rs index ab4c4525e..a7cb6a81b 100644 --- a/modules/src/application/ics20_fungible_token_transfer/error.rs +++ b/modules/src/applications/ics20_fungible_token_transfer/error.rs @@ -1,8 +1,10 @@ -use crate::ics04_channel::error as channel_error; -use crate::ics24_host::error::ValidationError; -use crate::ics24_host::identifier::{ChannelId, PortId}; +use crate::core::ics04_channel::error as channel_error; +use crate::core::ics24_host::error::ValidationError; +use crate::core::ics24_host::identifier::{ChannelId, PortId}; use crate::prelude::*; -use flex_error::define_error; + +use alloc::string::FromUtf8Error; +use flex_error::{define_error, DisplayOnly}; define_error! { #[derive(Debug, PartialEq, Eq)] @@ -36,5 +38,9 @@ define_error! { InvalidPacketTimeoutTimestamp { timestamp: u64 } | _ | { "invalid packet timeout timestamp value" }, + + Utf8 + [ DisplayOnly ] + | _ | { "utf8 decoding error" }, } } diff --git a/modules/src/applications/ics20_fungible_token_transfer/mod.rs b/modules/src/applications/ics20_fungible_token_transfer/mod.rs new file mode 100644 index 000000000..e28b4e7c5 --- /dev/null +++ b/modules/src/applications/ics20_fungible_token_transfer/mod.rs @@ -0,0 +1,17 @@ +//! ICS 20: Token Transfer implementation allows for multi-chain denomination handling, which +//! constitutes a "fungible token transfer bridge module" between the IBC routing module and an +//! asset tracking module. +pub mod context; +pub mod error; +pub mod msgs; +pub mod relay_application_logic; + +mod denom; +pub use denom::*; + +/// The port identifier that the ICS20 applications +/// typically bind with. +pub const PORT_ID: &str = "transfer"; + +/// ICS20 application current version. +pub const VERSION: &str = "ics20-1"; diff --git a/modules/src/application/ics20_fungible_token_transfer/msgs.rs b/modules/src/applications/ics20_fungible_token_transfer/msgs.rs similarity index 100% rename from modules/src/application/ics20_fungible_token_transfer/msgs.rs rename to modules/src/applications/ics20_fungible_token_transfer/msgs.rs diff --git a/modules/src/application/ics20_fungible_token_transfer/msgs/transfer.rs b/modules/src/applications/ics20_fungible_token_transfer/msgs/transfer.rs similarity index 88% rename from modules/src/application/ics20_fungible_token_transfer/msgs/transfer.rs rename to modules/src/applications/ics20_fungible_token_transfer/msgs/transfer.rs index d5eec5c87..60170d2c7 100644 --- a/modules/src/application/ics20_fungible_token_transfer/msgs/transfer.rs +++ b/modules/src/applications/ics20_fungible_token_transfer/msgs/transfer.rs @@ -1,23 +1,21 @@ //! This is the definition of a transfer messages that an application submits to a chain. use crate::prelude::*; -use core::convert::{TryFrom, TryInto}; + use tendermint_proto::Protobuf; use ibc_proto::ibc::apps::transfer::v1::MsgTransfer as RawMsgTransfer; -use crate::application::ics20_fungible_token_transfer::error::Error; -use crate::ics02_client::height::Height; -use crate::ics24_host::identifier::{ChannelId, PortId}; +use crate::applications::ics20_fungible_token_transfer::error::Error; +use crate::core::ics02_client::height::Height; +use crate::core::ics24_host::identifier::{ChannelId, PortId}; use crate::signer::Signer; use crate::timestamp::Timestamp; use crate::tx_msg::Msg; pub const TYPE_URL: &str = "/ibc.applications.transfer.v1.MsgTransfer"; -/// /// Message definition for the "packet receiving" datagram. -/// #[derive(Clone, Debug, PartialEq)] pub struct MsgTransfer { /// the port on which the packet will be sent @@ -94,21 +92,24 @@ impl From for RawMsgTransfer { sender: domain_msg.sender.to_string(), receiver: domain_msg.receiver.to_string(), timeout_height: Some(domain_msg.timeout_height.into()), - timeout_timestamp: domain_msg.timeout_timestamp.as_nanoseconds(), + timeout_timestamp: domain_msg.timeout_timestamp.nanoseconds(), } } } #[cfg(test)] pub mod test_util { + use core::ops::Add; + use core::time::Duration; + use crate::{ - ics24_host::identifier::{ChannelId, PortId}, + core::ics24_host::identifier::{ChannelId, PortId}, test_utils::get_dummy_account_id, + timestamp::Timestamp, Height, }; use super::MsgTransfer; - use crate::timestamp::Timestamp; // Returns a dummy `RawMsgTransfer`, for testing only! pub fn get_dummy_msg_transfer(height: u64) -> MsgTransfer { @@ -120,7 +121,7 @@ pub mod test_util { token: None, sender: id.clone(), receiver: id, - timeout_timestamp: Timestamp::from_nanoseconds(1).unwrap(), + timeout_timestamp: Timestamp::now().add(Duration::from_secs(10)).unwrap(), timeout_height: Height { revision_number: 0, revision_height: height, diff --git a/modules/src/application/ics20_fungible_token_transfer/relay_application_logic.rs b/modules/src/applications/ics20_fungible_token_transfer/relay_application_logic.rs similarity index 100% rename from modules/src/application/ics20_fungible_token_transfer/relay_application_logic.rs rename to modules/src/applications/ics20_fungible_token_transfer/relay_application_logic.rs diff --git a/modules/src/application/ics20_fungible_token_transfer/relay_application_logic/send_transfer.rs b/modules/src/applications/ics20_fungible_token_transfer/relay_application_logic/send_transfer.rs similarity index 78% rename from modules/src/application/ics20_fungible_token_transfer/relay_application_logic/send_transfer.rs rename to modules/src/applications/ics20_fungible_token_transfer/relay_application_logic/send_transfer.rs index 7224a4fa9..e4cd744f4 100644 --- a/modules/src/application/ics20_fungible_token_transfer/relay_application_logic/send_transfer.rs +++ b/modules/src/applications/ics20_fungible_token_transfer/relay_application_logic/send_transfer.rs @@ -1,10 +1,10 @@ -use crate::application::ics20_fungible_token_transfer::context::Ics20Context; -use crate::application::ics20_fungible_token_transfer::error::Error; -use crate::application::ics20_fungible_token_transfer::msgs::transfer::MsgTransfer; +use crate::applications::ics20_fungible_token_transfer::context::Ics20Context; +use crate::applications::ics20_fungible_token_transfer::error::Error; +use crate::applications::ics20_fungible_token_transfer::msgs::transfer::MsgTransfer; +use crate::core::ics04_channel::handler::send_packet::send_packet; +use crate::core::ics04_channel::packet::Packet; +use crate::core::ics04_channel::packet::PacketResult; use crate::handler::HandlerOutput; -use crate::ics04_channel::handler::send_packet::send_packet; -use crate::ics04_channel::packet::Packet; -use crate::ics04_channel::packet::PacketResult; use crate::prelude::*; pub(crate) fn send_transfer( diff --git a/modules/src/applications/mod.rs b/modules/src/applications/mod.rs new file mode 100644 index 000000000..9e6905bb3 --- /dev/null +++ b/modules/src/applications/mod.rs @@ -0,0 +1,3 @@ +//! Various packet encoding semantics which underpin the various types of transactions. + +pub mod ics20_fungible_token_transfer; diff --git a/modules/src/clients/ics07_tendermint/client_def.rs b/modules/src/clients/ics07_tendermint/client_def.rs new file mode 100644 index 000000000..a52835825 --- /dev/null +++ b/modules/src/clients/ics07_tendermint/client_def.rs @@ -0,0 +1,483 @@ +use core::convert::TryInto; + +use ibc_proto::ibc::core::commitment::v1::MerkleProof as RawMerkleProof; +use prost::Message; +use tendermint_light_client_verifier::types::{TrustedBlockState, UntrustedBlockState}; +use tendermint_light_client_verifier::{ProdVerifier, Verdict, Verifier}; +use tendermint_proto::Protobuf; + +use crate::clients::ics07_tendermint::client_state::ClientState; +use crate::clients::ics07_tendermint::consensus_state::ConsensusState; +use crate::clients::ics07_tendermint::error::Error; +use crate::clients::ics07_tendermint::header::Header; +use crate::core::ics02_client::client_consensus::AnyConsensusState; +use crate::core::ics02_client::client_def::ClientDef; +use crate::core::ics02_client::client_state::AnyClientState; +use crate::core::ics02_client::client_type::ClientType; +use crate::core::ics02_client::context::ClientReader; +use crate::core::ics02_client::error::Error as Ics02Error; +use crate::core::ics03_connection::connection::ConnectionEnd; +use crate::core::ics04_channel::channel::ChannelEnd; +use crate::core::ics04_channel::context::ChannelReader; +use crate::core::ics04_channel::packet::Sequence; + +use crate::core::ics23_commitment::commitment::{ + CommitmentPrefix, CommitmentProofBytes, CommitmentRoot, +}; +use crate::core::ics23_commitment::merkle::{apply_prefix, MerkleProof}; +use crate::core::ics24_host::identifier::ConnectionId; +use crate::core::ics24_host::identifier::{ChannelId, ClientId, PortId}; +use crate::core::ics24_host::Path; +use crate::prelude::*; +use crate::Height; + +use crate::core::ics24_host::path::{ + AcksPath, ChannelEndsPath, ClientConsensusStatePath, ClientStatePath, CommitmentsPath, + ConnectionsPath, ReceiptsPath, SeqRecvsPath, +}; +use crate::downcast; + +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct TendermintClient { + verifier: ProdVerifier, +} + +impl ClientDef for TendermintClient { + type Header = Header; + type ClientState = ClientState; + type ConsensusState = ConsensusState; + + fn check_header_and_update_state( + &self, + ctx: &dyn ClientReader, + client_id: ClientId, + client_state: Self::ClientState, + header: Self::Header, + ) -> Result<(Self::ClientState, Self::ConsensusState), Ics02Error> { + if header.height().revision_number != client_state.chain_id.version() { + return Err(Ics02Error::tendermint_handler_error( + Error::mismatched_revisions( + client_state.chain_id.version(), + header.height().revision_number, + ), + )); + } + + // Check if a consensus state is already installed; if so it should + // match the untrusted header. + let header_consensus_state = ConsensusState::from(header.clone()); + let existing_consensus_state = + match ctx.maybe_consensus_state(&client_id, header.height())? { + Some(cs) => { + let cs = downcast_consensus_state(cs)?; + // If this consensus state matches, skip verification + // (optimization) + if cs == header_consensus_state { + // Header is already installed and matches the incoming + // header (already verified) + return Ok((client_state, cs)); + } + Some(cs) + } + None => None, + }; + + let trusted_consensus_state = + downcast_consensus_state(ctx.consensus_state(&client_id, header.trusted_height)?)?; + + let trusted_state = TrustedBlockState { + header_time: trusted_consensus_state.timestamp, + height: header + .trusted_height + .revision_height + .try_into() + .map_err(|_| { + Ics02Error::tendermint_handler_error(Error::invalid_header_height( + header.trusted_height, + )) + })?, + next_validators: &header.trusted_validator_set, + next_validators_hash: trusted_consensus_state.next_validators_hash, + }; + + let untrusted_state = UntrustedBlockState { + signed_header: &header.signed_header, + validators: &header.validator_set, + // NB: This will skip the + // VerificationPredicates::next_validators_match check for the + // untrusted state. + next_validators: None, + }; + + let options = client_state.as_light_client_options()?; + + let verdict = self.verifier.verify( + untrusted_state, + trusted_state, + &options, + ctx.host_timestamp().into_tm_time().unwrap(), + ); + + match verdict { + Verdict::Success => {} + Verdict::NotEnoughTrust(voting_power_tally) => { + return Err(Error::not_enough_trusted_vals_signed(format!( + "voting power tally: {}", + voting_power_tally + )) + .into()) + } + Verdict::Invalid(detail) => { + return Err(Ics02Error::tendermint_handler_error( + Error::verification_error(detail), + )) + } + } + + // If the header has verified, but its corresponding consensus state + // differs from the existing consensus state for that height, freeze the + // client and return the installed consensus state. + if let Some(cs) = existing_consensus_state { + if cs != header_consensus_state { + return Ok((client_state.with_frozen_height(header.height())?, cs)); + } + } + + // Monotonicity checks for timestamps for in-the-middle updates + // (cs-new, cs-next, cs-latest) + if header.height() < client_state.latest_height() { + let maybe_next_cs = ctx + .next_consensus_state(&client_id, header.height())? + .map(downcast_consensus_state) + .transpose()?; + + if let Some(next_cs) = maybe_next_cs { + // New (untrusted) header timestamp cannot occur after next + // consensus state's height + if header.signed_header.header().time > next_cs.timestamp { + return Err(Ics02Error::tendermint_handler_error( + Error::header_timestamp_too_high( + header.signed_header.header().time.to_string(), + next_cs.timestamp.to_string(), + ), + )); + } + } + } + // (cs-trusted, cs-prev, cs-new) + if header.trusted_height < header.height() { + let maybe_prev_cs = ctx + .prev_consensus_state(&client_id, header.height())? + .map(downcast_consensus_state) + .transpose()?; + + if let Some(prev_cs) = maybe_prev_cs { + // New (untrusted) header timestamp cannot occur before the + // previous consensus state's height + if header.signed_header.header().time < prev_cs.timestamp { + return Err(Ics02Error::tendermint_handler_error( + Error::header_timestamp_too_low( + header.signed_header.header().time.to_string(), + prev_cs.timestamp.to_string(), + ), + )); + } + } + } + + Ok(( + client_state.with_header(header.clone()), + ConsensusState::from(header), + )) + } + + fn verify_client_consensus_state( + &self, + client_state: &Self::ClientState, + height: Height, + prefix: &CommitmentPrefix, + proof: &CommitmentProofBytes, + root: &CommitmentRoot, + client_id: &ClientId, + consensus_height: Height, + expected_consensus_state: &AnyConsensusState, + ) -> Result<(), Ics02Error> { + client_state.verify_height(height)?; + + let path = ClientConsensusStatePath { + client_id: client_id.clone(), + epoch: consensus_height.revision_number, + height: consensus_height.revision_height, + }; + let value = expected_consensus_state.encode_vec().unwrap(); + verify_membership(client_state, prefix, proof, root, path, value) + } + + fn verify_connection_state( + &self, + client_state: &Self::ClientState, + height: Height, + prefix: &CommitmentPrefix, + proof: &CommitmentProofBytes, + root: &CommitmentRoot, + connection_id: &ConnectionId, + expected_connection_end: &ConnectionEnd, + ) -> Result<(), Ics02Error> { + client_state.verify_height(height)?; + + let path = ConnectionsPath(connection_id.clone()); + let value = expected_connection_end.encode_vec().unwrap(); + verify_membership(client_state, prefix, proof, root, path, value) + } + + fn verify_channel_state( + &self, + client_state: &Self::ClientState, + height: Height, + prefix: &CommitmentPrefix, + proof: &CommitmentProofBytes, + root: &CommitmentRoot, + port_id: &PortId, + channel_id: &ChannelId, + expected_channel_end: &ChannelEnd, + ) -> Result<(), Ics02Error> { + client_state.verify_height(height)?; + + let path = ChannelEndsPath(port_id.clone(), channel_id.clone()); + let value = expected_channel_end.encode_vec().unwrap(); + verify_membership(client_state, prefix, proof, root, path, value) + } + + fn verify_client_full_state( + &self, + client_state: &Self::ClientState, + height: Height, + prefix: &CommitmentPrefix, + proof: &CommitmentProofBytes, + root: &CommitmentRoot, + client_id: &ClientId, + expected_client_state: &AnyClientState, + ) -> Result<(), Ics02Error> { + client_state.verify_height(height)?; + + let path = ClientStatePath(client_id.clone()); + let value = expected_client_state.encode_vec().unwrap(); + verify_membership(client_state, prefix, proof, root, path, value) + } + + fn verify_packet_data( + &self, + ctx: &dyn ChannelReader, + client_state: &Self::ClientState, + height: Height, + connection_end: &ConnectionEnd, + proof: &CommitmentProofBytes, + root: &CommitmentRoot, + port_id: &PortId, + channel_id: &ChannelId, + sequence: Sequence, + commitment: String, + ) -> Result<(), Ics02Error> { + client_state.verify_height(height)?; + verify_delay_passed(ctx, height, connection_end)?; + + let commitment_path = CommitmentsPath { + port_id: port_id.clone(), + channel_id: channel_id.clone(), + sequence, + }; + + let mut commitment_bytes = Vec::new(); + commitment + .encode(&mut commitment_bytes) + .expect("buffer size too small"); + + verify_membership( + client_state, + connection_end.counterparty().prefix(), + proof, + root, + commitment_path, + commitment_bytes, + ) + } + + fn verify_packet_acknowledgement( + &self, + ctx: &dyn ChannelReader, + client_state: &Self::ClientState, + height: Height, + connection_end: &ConnectionEnd, + proof: &CommitmentProofBytes, + root: &CommitmentRoot, + port_id: &PortId, + channel_id: &ChannelId, + sequence: Sequence, + ack: Vec, + ) -> Result<(), Ics02Error> { + client_state.verify_height(height)?; + verify_delay_passed(ctx, height, connection_end)?; + + let ack_path = AcksPath { + port_id: port_id.clone(), + channel_id: channel_id.clone(), + sequence, + }; + verify_membership( + client_state, + connection_end.counterparty().prefix(), + proof, + root, + ack_path, + ack, + ) + } + + fn verify_next_sequence_recv( + &self, + ctx: &dyn ChannelReader, + client_state: &Self::ClientState, + height: Height, + connection_end: &ConnectionEnd, + proof: &CommitmentProofBytes, + root: &CommitmentRoot, + port_id: &PortId, + channel_id: &ChannelId, + sequence: Sequence, + ) -> Result<(), Ics02Error> { + client_state.verify_height(height)?; + verify_delay_passed(ctx, height, connection_end)?; + + let mut seq_bytes = Vec::new(); + u64::from(sequence) + .encode(&mut seq_bytes) + .expect("buffer size too small"); + + let seq_path = SeqRecvsPath(port_id.clone(), channel_id.clone()); + verify_membership( + client_state, + connection_end.counterparty().prefix(), + proof, + root, + seq_path, + seq_bytes, + ) + } + + fn verify_packet_receipt_absence( + &self, + ctx: &dyn ChannelReader, + client_state: &Self::ClientState, + height: Height, + connection_end: &ConnectionEnd, + proof: &CommitmentProofBytes, + root: &CommitmentRoot, + port_id: &PortId, + channel_id: &ChannelId, + sequence: Sequence, + ) -> Result<(), Ics02Error> { + client_state.verify_height(height)?; + verify_delay_passed(ctx, height, connection_end)?; + + let receipt_path = ReceiptsPath { + port_id: port_id.clone(), + channel_id: channel_id.clone(), + sequence, + }; + verify_non_membership( + client_state, + connection_end.counterparty().prefix(), + proof, + root, + receipt_path, + ) + } + + fn verify_upgrade_and_update_state( + &self, + _client_state: &Self::ClientState, + _consensus_state: &Self::ConsensusState, + _proof_upgrade_client: RawMerkleProof, + _proof_upgrade_consensus_state: RawMerkleProof, + ) -> Result<(Self::ClientState, Self::ConsensusState), Ics02Error> { + todo!() + } +} + +fn verify_membership( + client_state: &ClientState, + prefix: &CommitmentPrefix, + proof: &CommitmentProofBytes, + root: &CommitmentRoot, + path: impl Into, + value: Vec, +) -> Result<(), Ics02Error> { + let merkle_path = apply_prefix(prefix, vec![path.into().to_string()]); + let merkle_proof: MerkleProof = RawMerkleProof::try_from(proof.clone()) + .map_err(Ics02Error::invalid_commitment_proof)? + .into(); + + merkle_proof + .verify_membership( + &client_state.proof_specs, + root.clone().into(), + merkle_path, + value, + 0, + ) + .map_err(|e| Ics02Error::tendermint(Error::ics23_error(e))) +} + +fn verify_non_membership( + client_state: &ClientState, + prefix: &CommitmentPrefix, + proof: &CommitmentProofBytes, + root: &CommitmentRoot, + path: impl Into, +) -> Result<(), Ics02Error> { + let merkle_path = apply_prefix(prefix, vec![path.into().to_string()]); + let merkle_proof: MerkleProof = RawMerkleProof::try_from(proof.clone()) + .map_err(Ics02Error::invalid_commitment_proof)? + .into(); + + merkle_proof + .verify_non_membership(&client_state.proof_specs, root.clone().into(), merkle_path) + .map_err(|e| Ics02Error::tendermint(Error::ics23_error(e))) +} + +fn verify_delay_passed( + ctx: &dyn ChannelReader, + height: Height, + connection_end: &ConnectionEnd, +) -> Result<(), Ics02Error> { + let current_timestamp = ctx.host_timestamp(); + let current_height = ctx.host_height(); + + let client_id = connection_end.client_id(); + let processed_time = ctx + .client_update_time(client_id, height) + .map_err(|_| Error::processed_time_not_found(client_id.clone(), height))?; + let processed_height = ctx + .client_update_height(client_id, height) + .map_err(|_| Error::processed_height_not_found(client_id.clone(), height))?; + + let delay_period_time = connection_end.delay_period(); + let delay_period_height = ctx.block_delay(delay_period_time); + + ClientState::verify_delay_passed( + current_timestamp, + current_height, + processed_time, + processed_height, + delay_period_time, + delay_period_height, + ) + .map_err(|e| e.into()) +} + +fn downcast_consensus_state(cs: AnyConsensusState) -> Result { + downcast!( + cs => AnyConsensusState::Tendermint + ) + .ok_or_else(|| Ics02Error::client_args_type_mismatch(ClientType::Tendermint)) +} diff --git a/modules/src/ics07_tendermint/client_state.rs b/modules/src/clients/ics07_tendermint/client_state.rs similarity index 60% rename from modules/src/ics07_tendermint/client_state.rs rename to modules/src/clients/ics07_tendermint/client_state.rs index eff7d5e5d..196872dec 100644 --- a/modules/src/ics07_tendermint/client_state.rs +++ b/modules/src/clients/ics07_tendermint/client_state.rs @@ -1,21 +1,23 @@ use crate::prelude::*; + use core::convert::{TryFrom, TryInto}; -use core::str::FromStr; use core::time::Duration; use serde::{Deserialize, Serialize}; +use tendermint_light_client_verifier::options::Options; use tendermint_proto::Protobuf; use ibc_proto::ibc::lightclients::tendermint::v1::ClientState as RawClientState; -use crate::ics02_client::client_state::AnyClientState; -use crate::ics02_client::client_type::ClientType; -use crate::ics02_client::trust_threshold::TrustThreshold; -use crate::ics07_tendermint::error::Error; -use crate::ics07_tendermint::header::Header; -use crate::ics23_commitment::specs::ProofSpecs; -use crate::ics24_host::identifier::ChainId; -use crate::timestamp::ZERO_DURATION; +use crate::clients::ics07_tendermint::error::Error; +use crate::clients::ics07_tendermint::header::Header; +use crate::core::ics02_client::client_state::AnyClientState; +use crate::core::ics02_client::client_type::ClientType; +use crate::core::ics02_client::error::Error as Ics02Error; +use crate::core::ics02_client::trust_threshold::TrustThreshold; +use crate::core::ics23_commitment::specs::ProofSpecs; +use crate::core::ics24_host::identifier::ChainId; +use crate::timestamp::{Timestamp, ZERO_DURATION}; use crate::Height; #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] @@ -25,11 +27,11 @@ pub struct ClientState { pub trusting_period: Duration, pub unbonding_period: Duration, pub max_clock_drift: Duration, - pub frozen_height: Height, pub latest_height: Height, - // pub proof_specs: ::core::vec::Vec, + pub proof_specs: ProofSpecs, pub upgrade_path: Vec, pub allow_update: AllowUpdate, + pub frozen_height: Option, } #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] @@ -49,37 +51,51 @@ impl ClientState { unbonding_period: Duration, max_clock_drift: Duration, latest_height: Height, - frozen_height: Height, + proof_specs: ProofSpecs, upgrade_path: Vec, allow_update: AllowUpdate, ) -> Result { // Basic validation of trusting period and unbonding period: each should be non-zero. if trusting_period <= Duration::new(0, 0) { - return Err(Error::invalid_trusting_period( - "ClientState trusting period must be greater than zero".to_string(), - )); + return Err(Error::invalid_trusting_period(format!( + "ClientState trusting period ({:?}) must be greater than zero", + trusting_period + ))); } + if unbonding_period <= Duration::new(0, 0) { - return Err(Error::invalid_unbounding_period( - "ClientState unbonding period must be greater than zero".to_string(), - )); + return Err(Error::invalid_unbonding_period(format!( + "ClientState unbonding period ({:?}) must be greater than zero", + unbonding_period + ))); } + if trusting_period >= unbonding_period { - return Err(Error::invalid_unbounding_period( - "ClientState trusting period must be smaller than unbonding period".to_string(), + return Err(Error::invalid_trusting_period(format!( + "ClientState trusting period ({:?}) must be smaller than unbonding period ({:?})", + trusting_period, unbonding_period, + ))); + } + + // Basic validation for the latest_height parameter. + if latest_height <= Height::zero() { + return Err(Error::validation( + "ClientState latest height must be greater than zero".to_string(), )); } - // Basic validation for the frozen_height parameter. - if !frozen_height.is_zero() { + // `TrustThreshold` is guaranteed to be in the range `[0, 1)`, but a `TrustThreshold::ZERO` + // value is invalid in this context + if trust_level == TrustThreshold::ZERO { return Err(Error::validation( - "ClientState cannot be frozen at creation time".to_string(), + "ClientState trust-level cannot be zero".to_string(), )); } - // Basic validation for the latest_height parameter. - if latest_height <= Height::zero() { + + // Disallow empty proof-specs + if proof_specs.is_empty() { return Err(Error::validation( - "ClientState latest height cannot be smaller or equal than zero".to_string(), + "ClientState proof-specs cannot be empty".to_string(), )); } @@ -89,10 +105,11 @@ impl ClientState { trusting_period, unbonding_period, max_clock_drift, - frozen_height, latest_height, + proof_specs, upgrade_path, allow_update, + frozen_height: None, }) } @@ -110,16 +127,16 @@ impl ClientState { } } - /// Helper function for the upgrade chain & client procedures. - /// Resets all fields except the blockchain-specific ones. - pub fn zero_custom_fields(mut client_state: Self) -> Self { - client_state.trusting_period = ZERO_DURATION; - client_state.trust_level = TrustThreshold::ZERO; - client_state.allow_update.after_expiry = false; - client_state.allow_update.after_misbehaviour = false; - client_state.frozen_height = Height::zero(); - client_state.max_clock_drift = ZERO_DURATION; - client_state + pub fn with_frozen_height(self, h: Height) -> Result { + if h == Height::zero() { + return Err(Error::validation( + "ClientState frozen height must be greater than zero".to_string(), + )); + } + Ok(Self { + frozen_height: Some(h), + ..self + }) } /// Get the refresh time to ensure the state does not expire @@ -132,9 +149,69 @@ impl ClientState { pub fn expired(&self, elapsed: Duration) -> bool { elapsed > self.trusting_period } + + /// Helper method to produce a [`Options`] struct for use in + /// Tendermint-specific light client verification. + pub fn as_light_client_options(&self) -> Result { + Ok(Options { + trust_threshold: self + .trust_level + .try_into() + .map_err(|e: Ics02Error| Error::invalid_trust_threshold(e.to_string()))?, + trusting_period: self.trusting_period, + clock_drift: self.max_clock_drift, + }) + } + + /// Verify the time and height delays + pub fn verify_delay_passed( + current_time: Timestamp, + current_height: Height, + processed_time: Timestamp, + processed_height: Height, + delay_period_time: Duration, + delay_period_blocks: u64, + ) -> Result<(), Error> { + let earliest_time = + (processed_time + delay_period_time).map_err(Error::timestamp_overflow)?; + if !(current_time == earliest_time || current_time.after(&earliest_time)) { + return Err(Error::not_enough_time_elapsed(current_time, earliest_time)); + } + + let earliest_height = processed_height.add(delay_period_blocks); + if current_height < earliest_height { + return Err(Error::not_enough_blocks_elapsed( + current_height, + earliest_height, + )); + } + + Ok(()) + } + + /// Verify that the client is at a sufficient height and unfrozen at the given height + pub fn verify_height(&self, height: Height) -> Result<(), Error> { + if self.latest_height < height { + return Err(Error::insufficient_height(self.latest_height(), height)); + } + + match self.frozen_height { + Some(frozen_height) if frozen_height <= height => { + Err(Error::client_frozen(frozen_height, height)) + } + _ => Ok(()), + } + } } -impl crate::ics02_client::client_state::ClientState for ClientState { +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct UpgradeOptions { + pub unbonding_period: Duration, +} + +impl crate::core::ics02_client::client_state::ClientState for ClientState { + type UpgradeOptions = UpgradeOptions; + fn chain_id(&self) -> ChainId { self.chain_id.clone() } @@ -147,9 +224,30 @@ impl crate::ics02_client::client_state::ClientState for ClientState { self.latest_height } - fn is_frozen(&self) -> bool { - // If 'frozen_height' is set to a non-zero value, then the client state is frozen. - !self.frozen_height.is_zero() + fn frozen_height(&self) -> Option { + self.frozen_height + } + + fn upgrade( + mut self, + upgrade_height: Height, + upgrade_options: UpgradeOptions, + chain_id: ChainId, + ) -> Self { + // Reset custom fields to zero values + self.trusting_period = ZERO_DURATION; + self.trust_level = TrustThreshold::ZERO; + self.allow_update.after_expiry = false; + self.allow_update.after_misbehaviour = false; + self.frozen_height = None; + self.max_clock_drift = ZERO_DURATION; + + // Upgrade the client state + self.latest_height = upgrade_height; + self.unbonding_period = upgrade_options.unbonding_period; + self.chain_id = chain_id; + + self } fn wrap_any(self) -> AnyClientState { @@ -166,9 +264,17 @@ impl TryFrom for ClientState { .clone() .ok_or_else(Error::missing_trusting_period)?; + let frozen_height = raw.frozen_height.and_then(|raw_height| { + let height = raw_height.into(); + if height == Height::zero() { + None + } else { + Some(height) + } + }); + Ok(Self { - chain_id: ChainId::from_str(raw.chain_id.as_str()) - .map_err(Error::invalid_chain_identifier)?, + chain_id: ChainId::from_string(raw.chain_id.as_str()), trust_level: trust_level .try_into() .map_err(|e| Error::invalid_trust_threshold(format!("{}", e)))?, @@ -191,15 +297,13 @@ impl TryFrom for ClientState { .latest_height .ok_or_else(Error::missing_latest_height)? .into(), - frozen_height: raw - .frozen_height - .ok_or_else(Error::missing_frozen_height)? - .into(), + frozen_height, upgrade_path: raw.upgrade_path, allow_update: AllowUpdate { after_expiry: raw.allow_update_after_expiry, after_misbehaviour: raw.allow_update_after_misbehaviour, }, + proof_specs: raw.proof_specs.into(), }) } } @@ -212,9 +316,9 @@ impl From for RawClientState { trusting_period: Some(value.trusting_period.into()), unbonding_period: Some(value.unbonding_period.into()), max_clock_drift: Some(value.max_clock_drift.into()), - frozen_height: Some(value.frozen_height.into()), + frozen_height: Some(value.frozen_height.unwrap_or_else(Height::zero).into()), latest_height: Some(value.latest_height.into()), - proof_specs: ProofSpecs::cosmos().into(), + proof_specs: value.proof_specs.into(), allow_update_after_expiry: value.allow_update.after_expiry, allow_update_after_misbehaviour: value.allow_update.after_misbehaviour, upgrade_path: value.upgrade_path, @@ -226,30 +330,29 @@ impl From for RawClientState { mod tests { use crate::prelude::*; use core::time::Duration; - use std::println; - use test_env_log::test; + use test_log::test; use tendermint_rpc::endpoint::abci_query::AbciQuery; - use crate::ics02_client::trust_threshold::TrustThreshold; - use crate::ics07_tendermint::client_state::{AllowUpdate, ClientState}; - use crate::ics24_host::identifier::ChainId; + use crate::clients::ics07_tendermint::client_state::{AllowUpdate, ClientState}; + use crate::core::ics02_client::trust_threshold::TrustThreshold; + use crate::core::ics23_commitment::specs::ProofSpecs; + use crate::core::ics24_host::identifier::ChainId; use crate::test::test_serialization_roundtrip; use crate::timestamp::ZERO_DURATION; use crate::Height; #[test] fn serialization_roundtrip_no_proof() { - let json_data = include_str!("../../tests/support/query/serialization/client_state.json"); - println!("json_data: {:?}", json_data); + let json_data = + include_str!("../../../tests/support/query/serialization/client_state.json"); test_serialization_roundtrip::(json_data); } #[test] fn serialization_roundtrip_with_proof() { let json_data = - include_str!("../../tests/support/query/serialization/client_state_proof.json"); - println!("json_data: {:?}", json_data); + include_str!("../../../tests/support/query/serialization/client_state_proof.json"); test_serialization_roundtrip::(json_data); } @@ -263,7 +366,7 @@ mod tests { unbonding_period: Duration, max_clock_drift: Duration, latest_height: Height, - frozen_height: Height, + proof_specs: ProofSpecs, upgrade_path: Vec, allow_update: AllowUpdate, } @@ -276,7 +379,7 @@ mod tests { unbonding_period: Duration::new(128000, 0), max_clock_drift: Duration::new(3, 0), latest_height: Height::new(0, 10), - frozen_height: Height::default(), + proof_specs: ProofSpecs::default(), upgrade_path: vec!["".to_string()], allow_update: AllowUpdate { after_expiry: false, @@ -296,14 +399,6 @@ mod tests { params: default_params.clone(), want_pass: true, }, - Test { - name: "Invalid frozen height parameter (should be 0)".to_string(), - params: ClientStateParams { - frozen_height: Height::new(0, 1), - ..default_params.clone() - }, - want_pass: false, - }, Test { name: "Invalid unbonding period".to_string(), params: ClientStateParams { @@ -343,7 +438,7 @@ mod tests { p.unbonding_period, p.max_clock_drift, p.latest_height, - p.frozen_height, + p.proof_specs, p.upgrade_path, p.allow_update, ); @@ -367,10 +462,10 @@ pub mod test_util { use tendermint::block::Header; - use crate::ics02_client::client_state::AnyClientState; - use crate::ics02_client::height::Height; - use crate::ics07_tendermint::client_state::{AllowUpdate, ClientState}; - use crate::ics24_host::identifier::ChainId; + use crate::clients::ics07_tendermint::client_state::{AllowUpdate, ClientState}; + use crate::core::ics02_client::client_state::AnyClientState; + use crate::core::ics02_client::height::Height; + use crate::core::ics24_host::identifier::ChainId; pub fn get_dummy_tendermint_client_state(tm_header: Header) -> AnyClientState { AnyClientState::Tendermint( @@ -384,7 +479,7 @@ pub mod test_util { ChainId::chain_version(tm_header.chain_id.as_str()), u64::from(tm_header.height), ), - Height::zero(), + Default::default(), vec!["".to_string()], AllowUpdate { after_expiry: false, diff --git a/modules/src/ics07_tendermint/consensus_state.rs b/modules/src/clients/ics07_tendermint/consensus_state.rs similarity index 68% rename from modules/src/ics07_tendermint/consensus_state.rs rename to modules/src/clients/ics07_tendermint/consensus_state.rs index 2e218a735..c7d0c4f4d 100644 --- a/modules/src/ics07_tendermint/consensus_state.rs +++ b/modules/src/clients/ics07_tendermint/consensus_state.rs @@ -1,20 +1,19 @@ use crate::prelude::*; + use core::convert::Infallible; -use core::convert::{TryFrom, TryInto}; -use chrono::{TimeZone, Utc}; -use prost_types::Timestamp; use serde::Serialize; use tendermint::{hash::Algorithm, time::Time, Hash}; +use tendermint_proto::google::protobuf as tpb; use tendermint_proto::Protobuf; use ibc_proto::ibc::lightclients::tendermint::v1::ConsensusState as RawConsensusState; -use crate::ics02_client::client_consensus::AnyConsensusState; -use crate::ics02_client::client_type::ClientType; -use crate::ics07_tendermint::error::Error; -use crate::ics07_tendermint::header::Header; -use crate::ics23_commitment::commitment::CommitmentRoot; +use crate::clients::ics07_tendermint::error::Error; +use crate::clients::ics07_tendermint::header::Header; +use crate::core::ics02_client::client_consensus::AnyConsensusState; +use crate::core::ics02_client::client_type::ClientType; +use crate::core::ics23_commitment::commitment::CommitmentRoot; #[derive(Clone, Debug, PartialEq, Eq, Serialize)] pub struct ConsensusState { @@ -33,7 +32,7 @@ impl ConsensusState { } } -impl crate::ics02_client::client_consensus::ConsensusState for ConsensusState { +impl crate::core::ics02_client::client_consensus::ConsensusState for ConsensusState { type Error = Infallible; fn client_type(&self) -> ClientType { @@ -44,10 +43,6 @@ impl crate::ics02_client::client_consensus::ConsensusState for ConsensusState { &self.root } - fn validate_basic(&self) -> Result<(), Infallible> { - unimplemented!() - } - fn wrap_any(self) -> AnyConsensusState { AnyConsensusState::Tendermint(self) } @@ -59,9 +54,15 @@ impl TryFrom for ConsensusState { type Error = Error; fn try_from(raw: RawConsensusState) -> Result { - let proto_timestamp = raw + let prost_types::Timestamp { seconds, nanos } = raw .timestamp .ok_or_else(|| Error::invalid_raw_consensus_state("missing timestamp".into()))?; + // FIXME: shunts like this are necessary due to + // https://github.com/informalsystems/tendermint-rs/issues/1053 + let proto_timestamp = tpb::Timestamp { seconds, nanos }; + let timestamp = proto_timestamp + .try_into() + .map_err(|e| Error::invalid_raw_consensus_state(format!("invalid timestamp: {}", e)))?; Ok(Self { root: raw @@ -71,9 +72,7 @@ impl TryFrom for ConsensusState { })? .hash .into(), - timestamp: Utc - .timestamp(proto_timestamp.seconds, proto_timestamp.nanos as u32) - .into(), + timestamp, next_validators_hash: Hash::from_bytes(Algorithm::Sha256, &raw.next_validators_hash) .map_err(|e| Error::invalid_raw_consensus_state(e.to_string()))?, }) @@ -82,18 +81,13 @@ impl TryFrom for ConsensusState { impl From for RawConsensusState { fn from(value: ConsensusState) -> Self { - let nanos = value - .timestamp - .0 - .timestamp_subsec_nanos() - .try_into() - .unwrap_or(0); + // FIXME: shunts like this are necessary due to + // https://github.com/informalsystems/tendermint-rs/issues/1053 + let tpb::Timestamp { seconds, nanos } = value.timestamp.into(); + let timestamp = prost_types::Timestamp { seconds, nanos }; RawConsensusState { - timestamp: Some(Timestamp { - seconds: value.timestamp.0.timestamp(), - nanos, - }), + timestamp: Some(timestamp), root: Some(ibc_proto::ibc::core::commitment::v1::MerkleRoot { hash: value.root.into_vec(), }), @@ -120,25 +114,22 @@ impl From
for ConsensusState { #[cfg(test)] mod tests { - use std::println; use tendermint_rpc::endpoint::abci_query::AbciQuery; - use test_env_log::test; + use test_log::test; use crate::test::test_serialization_roundtrip; #[test] fn serialization_roundtrip_no_proof() { let json_data = - include_str!("../../tests/support/query/serialization/consensus_state.json"); - println!("json_data: {:?}", json_data); + include_str!("../../../tests/support/query/serialization/consensus_state.json"); test_serialization_roundtrip::(json_data); } #[test] fn serialization_roundtrip_with_proof() { let json_data = - include_str!("../../tests/support/query/serialization/consensus_state_proof.json"); - println!("json_data: {:?}", json_data); + include_str!("../../../tests/support/query/serialization/consensus_state_proof.json"); test_serialization_roundtrip::(json_data); } } diff --git a/modules/src/clients/ics07_tendermint/error.rs b/modules/src/clients/ics07_tendermint/error.rs new file mode 100644 index 000000000..54966531f --- /dev/null +++ b/modules/src/clients/ics07_tendermint/error.rs @@ -0,0 +1,290 @@ +use crate::prelude::*; + +use flex_error::{define_error, TraceError}; + +use crate::core::ics23_commitment::error::Error as Ics23Error; +use crate::core::ics24_host::error::ValidationError; +use crate::core::ics24_host::identifier::ClientId; +use crate::timestamp::{Timestamp, TimestampOverflowError}; + +use crate::Height; +use tendermint::account::Id; +use tendermint::hash::Hash; +use tendermint::Error as TendermintError; +use tendermint_light_client_verifier::errors::VerificationErrorDetail as LightClientErrorDetail; + +define_error! { + #[derive(Debug, PartialEq, Eq)] + Error { + InvalidTrustingPeriod + { reason: String } + |e| { format_args!("invalid trusting period: {}", e.reason) }, + + InvalidUnbondingPeriod + { reason: String } + |e| { format_args!("invalid unbonding period: {}", e.reason) }, + + InvalidAddress + |_| { "invalid address" }, + + InvalidHeader + { reason: String } + [ TendermintError ] + |e| { format_args!("invalid header, failed basic validation: {}", e.reason) }, + + InvalidTrustThreshold + { reason: String } + |e| { format_args!("invalid client state trust threshold: {}", e.reason) }, + + MissingSignedHeader + |_| { "missing signed header" }, + + Validation + { reason: String } + |e| { format_args!("invalid header, failed basic validation: {}", e.reason) }, + + InvalidRawClientState + { reason: String } + |e| { format_args!("invalid raw client state: {}", e.reason) }, + + MissingValidatorSet + |_| { "missing validator set" }, + + MissingTrustedValidatorSet + |_| { "missing trusted validator set" }, + + MissingTrustedHeight + |_| { "missing trusted height" }, + + MissingTrustingPeriod + |_| { "missing trusting period" }, + + MissingUnbondingPeriod + |_| { "missing unbonding period" }, + + InvalidChainIdentifier + [ ValidationError ] + |_| { "invalid chain identifier" }, + + NegativeTrustingPeriod + |_| { "negative trusting period" }, + + NegativeUnbondingPeriod + |_| { "negative unbonding period" }, + + MissingMaxClockDrift + |_| { "missing max clock drift" }, + + NegativeMaxClockDrift + |_| { "negative max clock drift" }, + + MissingLatestHeight + |_| { "missing latest height" }, + + MissingFrozenHeight + |_| { "missing frozen height" }, + + InvalidChainId + { raw_value: String } + [ ValidationError ] + |e| { format_args!("invalid chain identifier: {}", e.raw_value) }, + + InvalidRawHeight + { raw_height: u64 } + |e| { format_args!("invalid raw height: {}", e.raw_height) }, + + InvalidRawConsensusState + { reason: String } + | e | { format_args!("invalid raw client consensus state: {}", e.reason) }, + + InvalidRawHeader + [ TendermintError ] + | _ | { "invalid raw header" }, + + InvalidRawMisbehaviour + { reason: String } + | e | { format_args!("invalid raw misbehaviour: {}", e.reason) }, + + Decode + [ TraceError ] + | _ | { "decode error" }, + + InsufficientVotingPower + { reason: String } + | e | { + format_args!("insufficient overlap: {}", e.reason) + }, + + LowUpdateTimestamp + { + low: String, + high: String + } + | e | { + format_args!("header timestamp {0} must be greater than current client consensus state timestamp {1}", e.low, e.high) + }, + + HeaderTimestampOutsideTrustingTime + { + low: String, + high: String + } + | e | { + format_args!("header timestamp {0} is outside the trusting period w.r.t. consensus state timestamp {1}", e.low, e.high) + }, + + HeaderTimestampTooHigh + { + actual: String, + max: String, + } + | e | { + format_args!("given other previous updates, header timestamp should be at most {0}, but was {1}", e.max, e.actual) + }, + + HeaderTimestampTooLow + { + actual: String, + min: String, + } + | e | { + format_args!("given other previous updates, header timestamp should be at least {0}, but was {1}", e.min, e.actual) + }, + + TimestampOverflow + [ TimestampOverflowError ] + |_| { "timestamp overflowed" }, + + NotEnoughTimeElapsed + { + current_time: Timestamp, + earliest_time: Timestamp, + } + |_| { "not enough time elapsed, current timestamp {0} is still less than earliest acceptable timestamp {1}" }, + + NotEnoughBlocksElapsed + { + current_height: Height, + earliest_height: Height, + } + |_| { "not enough blocks elapsed, current height {0} is still less than earliest acceptable height {1}" }, + + InvalidHeaderHeight + { height: Height } + | e | { + format_args!("header height = {0} is invalid", e.height) + }, + + InvalidTrustedHeaderHeight + { + trusted_header_height: Height, + height_header: Height + } + | e | { + format_args!("header height is {0} and is lower than the trusted header height, which is {1} ", e.height_header, e.trusted_header_height) + }, + + LowUpdateHeight + { + low: Height, + high: Height + } + | e | { + format_args!("header height is {0} but it must be greater than the current client height which is {1}", e.low, e.high) + }, + + MismatchedRevisions + { + current_revision: u64, + update_revision: u64, + } + | e | { + format_args!("the header's current/trusted revision number ({0}) and the update's revision number ({1}) should be the same", e.current_revision, e.update_revision) + }, + + InvalidValidatorSet + { + hash1: Hash, + hash2: Hash, + } + | e | { + format_args!("invalid validator set: header_validators_hash={} and validators_hash={}", e.hash1, e.hash2) + }, + + NotEnoughTrustedValsSigned + { reason: String } + | e | { + format_args!("not enough trust because insufficient validators overlap: {}", e.reason) + }, + + VerificationError + { detail: LightClientErrorDetail } + | e | { + format_args!("verification failed: {}", e.detail) + }, + + ProcessedTimeNotFound + { + client_id: ClientId, + height: Height, + } + | e | { + format_args!( + "Processed time for the client {0} at height {1} not found", + e.client_id, e.height) + }, + + ProcessedHeightNotFound + { + client_id: ClientId, + height: Height, + } + | e | { + format_args!( + "Processed height for the client {0} at height {1} not found", + e.client_id, e.height) + }, + + Ics23Error + [ Ics23Error ] + | _ | { "ics23 commitment error" }, + + InsufficientHeight + { + latest_height: Height, + target_height: Height, + } + | e | { + format_args!("the height is insufficient: latest_height={0} target_height={1}", e.latest_height, e.target_height) + }, + + ClientFrozen + { + frozen_height: Height, + target_height: Height, + } + | e | { + format_args!("the client is frozen: frozen_height={0} target_height={1}", e.frozen_height, e.target_height) + }, + } +} + +define_error! { + #[derive(Debug, PartialEq, Eq)] + VerificationError { + InvalidSignature + | _ | { "couldn't verify validator signature" }, + + DuplicateValidator + { id: Id } + | e | { + format_args!("duplicate validator in commit signatures with address {}", e.id) + }, + + InsufficientOverlap + { q1: u64, q2: u64 } + | e | { + format_args!("insufficient signers overlap between {0} and {1}", e.q1, e.q2) + }, + } +} diff --git a/modules/src/ics07_tendermint/header.rs b/modules/src/clients/ics07_tendermint/header.rs similarity index 83% rename from modules/src/ics07_tendermint/header.rs rename to modules/src/clients/ics07_tendermint/header.rs index abe865405..8fe32105a 100644 --- a/modules/src/ics07_tendermint/header.rs +++ b/modules/src/clients/ics07_tendermint/header.rs @@ -1,29 +1,30 @@ -use crate::prelude::*; -use core::convert::{TryFrom, TryInto}; +use core::cmp::Ordering; use bytes::Buf; use prost::Message; use serde_derive::{Deserialize, Serialize}; use tendermint::block::signed_header::SignedHeader; use tendermint::validator::Set as ValidatorSet; -use tendermint::Time; use tendermint_proto::Protobuf; +use crate::alloc::string::ToString; + use ibc_proto::ibc::lightclients::tendermint::v1::Header as RawHeader; -use crate::ics02_client::client_type::ClientType; -use crate::ics02_client::header::AnyHeader; -use crate::ics07_tendermint::error::Error; -use crate::ics24_host::identifier::ChainId; +use crate::clients::ics07_tendermint::error::Error; +use crate::core::ics02_client::client_type::ClientType; +use crate::core::ics02_client::header::AnyHeader; +use crate::core::ics24_host::identifier::ChainId; +use crate::timestamp::Timestamp; use crate::Height; -use core::cmp::Ordering; /// Tendermint consensus header -#[derive(Clone, PartialEq, Deserialize, Serialize)] // TODO: Add Eq bound once present in tendermint-rs +#[derive(Clone, PartialEq, Eq, Deserialize, Serialize)] pub struct Header { pub signed_header: SignedHeader, // contains the commitment root pub validator_set: ValidatorSet, // the validator set that signed Header pub trusted_height: Height, // the height of a trusted header seen by client less than or equal to Header + // TODO(thane): Rename this to trusted_next_validator_set? pub trusted_validator_set: ValidatorSet, // the last trusted validator set at trusted height } @@ -41,10 +42,6 @@ impl Header { ) } - pub fn time(&self) -> Time { - self.signed_header.header.time - } - pub fn compatible_with(&self, other_header: &Header) -> bool { headers_compatible(&self.signed_header, &other_header.signed_header) } @@ -70,7 +67,7 @@ pub fn headers_compatible(header: &SignedHeader, other: &SignedHeader) -> bool { } } -impl crate::ics02_client::header::Header for Header { +impl crate::core::ics02_client::header::Header for Header { fn client_type(&self) -> ClientType { ClientType::Tendermint } @@ -79,6 +76,10 @@ impl crate::ics02_client::header::Header for Header { self.height() } + fn timestamp(&self) -> Timestamp { + self.signed_header.header.time.into() + } + fn wrap_any(self) -> AnyHeader { AnyHeader::Tendermint(self) } @@ -90,7 +91,7 @@ impl TryFrom for Header { type Error = Error; fn try_from(raw: RawHeader) -> Result { - Ok(Self { + let header = Self { signed_header: raw .signed_header .ok_or_else(Error::missing_signed_header)? @@ -110,7 +111,16 @@ impl TryFrom for Header { .ok_or_else(Error::missing_trusted_validator_set)? .try_into() .map_err(Error::invalid_raw_header)?, - }) + }; + + if header.height().revision_number != header.trusted_height.revision_number { + return Err(Error::mismatched_revisions( + header.trusted_height.revision_number, + header.height().revision_number, + )); + } + + Ok(header) } } @@ -131,8 +141,7 @@ impl From
for RawHeader { #[cfg(test)] pub mod test_util { - use crate::prelude::*; - use core::convert::TryInto; + use alloc::vec; use subtle_encoding::hex; use tendermint::block::signed_header::SignedHeader; @@ -140,13 +149,15 @@ pub mod test_util { use tendermint::validator::Set as ValidatorSet; use tendermint::PublicKey; - use crate::ics07_tendermint::header::Header; + use crate::clients::ics07_tendermint::header::Header; use crate::Height; pub fn get_dummy_tendermint_header() -> tendermint::block::Header { - serde_json::from_str::(include_str!("../../tests/support/signed_header.json")) - .unwrap() - .header + serde_json::from_str::(include_str!( + "../../../tests/support/signed_header.json" + )) + .unwrap() + .header } // TODO: This should be replaced with a ::default() or ::produce(). @@ -166,7 +177,7 @@ pub mod test_util { pub fn get_dummy_ics07_header() -> Header { // Build a SignedHeader from a JSON file. let shdr = serde_json::from_str::(include_str!( - "../../tests/support/signed_header.json" + "../../../tests/support/signed_header.json" )) .unwrap(); diff --git a/modules/src/ics07_tendermint/misbehaviour.rs b/modules/src/clients/ics07_tendermint/misbehaviour.rs similarity index 86% rename from modules/src/ics07_tendermint/misbehaviour.rs rename to modules/src/clients/ics07_tendermint/misbehaviour.rs index aba35476d..016c3fde3 100644 --- a/modules/src/ics07_tendermint/misbehaviour.rs +++ b/modules/src/clients/ics07_tendermint/misbehaviour.rs @@ -1,13 +1,13 @@ use crate::prelude::*; -use core::convert::{TryFrom, TryInto}; + use tendermint_proto::Protobuf; use ibc_proto::ibc::lightclients::tendermint::v1::Misbehaviour as RawMisbehaviour; -use crate::ics02_client::misbehaviour::AnyMisbehaviour; -use crate::ics07_tendermint::error::Error; -use crate::ics07_tendermint::header::Header; -use crate::ics24_host::identifier::ClientId; +use crate::clients::ics07_tendermint::error::Error; +use crate::clients::ics07_tendermint::header::Header; +use crate::core::ics02_client::misbehaviour::AnyMisbehaviour; +use crate::core::ics24_host::identifier::ClientId; use crate::Height; #[derive(Clone, Debug, PartialEq)] @@ -17,7 +17,7 @@ pub struct Misbehaviour { pub header2: Header, } -impl crate::ics02_client::misbehaviour::Misbehaviour for Misbehaviour { +impl crate::core::ics02_client::misbehaviour::Misbehaviour for Misbehaviour { fn client_id(&self) -> &ClientId { &self.client_id } diff --git a/modules/src/clients/ics07_tendermint/mod.rs b/modules/src/clients/ics07_tendermint/mod.rs new file mode 100644 index 000000000..3b32d8e62 --- /dev/null +++ b/modules/src/clients/ics07_tendermint/mod.rs @@ -0,0 +1,9 @@ +//! ICS 07: Tendermint Client implements a client verification algorithm for blockchains which use +//! the Tendermint consensus algorithm. + +pub mod client_def; +pub mod client_state; +pub mod consensus_state; +pub mod error; +pub mod header; +pub mod misbehaviour; diff --git a/modules/src/ics10_grandpa/client_def.rs b/modules/src/clients/ics10_grandpa/client_def.rs similarity index 67% rename from modules/src/ics10_grandpa/client_def.rs rename to modules/src/clients/ics10_grandpa/client_def.rs index 4ad1fbc72..bf8360d44 100644 --- a/modules/src/ics10_grandpa/client_def.rs +++ b/modules/src/clients/ics10_grandpa/client_def.rs @@ -8,19 +8,21 @@ use tendermint_proto::Protobuf; use ibc_proto::ibc::core::commitment::v1::MerkleProof; -use crate::ics02_client::client_consensus::AnyConsensusState; -use crate::ics02_client::client_def::ClientDef; -use crate::ics02_client::client_state::AnyClientState; -use crate::ics02_client::error::Error; -use crate::ics03_connection::connection::ConnectionEnd; -use crate::ics04_channel::channel::ChannelEnd; -use crate::ics04_channel::packet::Sequence; -use crate::ics10_grandpa::client_state::ClientState; -use crate::ics10_grandpa::consensus_state::ConsensusState; -use crate::ics10_grandpa::header::Header; -use crate::ics23_commitment::commitment::{CommitmentPrefix, CommitmentProofBytes, CommitmentRoot}; -use crate::ics24_host::identifier::ConnectionId; -use crate::ics24_host::identifier::{ChannelId, ClientId, PortId}; +use crate::core::ics02_client::client_consensus::AnyConsensusState; +use crate::core::ics02_client::client_def::ClientDef; +use crate::core::ics02_client::client_state::AnyClientState; +use crate::core::ics02_client::error::Error; +use crate::core::ics03_connection::connection::ConnectionEnd; +use crate::core::ics04_channel::channel::ChannelEnd; +use crate::core::ics04_channel::packet::Sequence; +use crate::clients::ics10_grandpa::client_state::ClientState; +use crate::clients::ics10_grandpa::consensus_state::ConsensusState; +use crate::clients::ics10_grandpa::header::Header; +use crate::core::ics02_client::context::ClientReader; +use crate::core::ics04_channel::context::ChannelReader; +use crate::core::ics23_commitment::commitment::{CommitmentPrefix, CommitmentProofBytes, CommitmentRoot}; +use crate::core::ics24_host::identifier::ConnectionId; +use crate::core::ics24_host::identifier::{ChannelId, ClientId, PortId}; use crate::Height; #[derive(Clone, Debug, PartialEq, Eq)] @@ -33,265 +35,304 @@ impl ClientDef for GrandpaClient { fn check_header_and_update_state( &self, + ctx: &dyn ClientReader, + client_id: ClientId, client_state: Self::ClientState, header: Self::Header, ) -> Result<(Self::ClientState, Self::ConsensusState), Error> { - tracing::info!("in ics10 client_def [check_header_and_update_state]"); - tracing::info!("in ics10 client_def [check_header_and_update_state] >> Header block_header block_number\ - = {:?}, ClientState latest_commitment block_number = {:?}", header.block_header.block_number, client_state.latest_commitment.block_number); - tracing::info!( - "in client_def: [check_header_and_update_state] >> client_state = {:?}", - client_state - ); - tracing::info!( - "in client_def: [check_header_and_update_state] >> header = {:?}", - header - ); + tracing::info!("in ics10 client_def [check_header_and_update_state]"); + tracing::info!("in ics10 client_def [check_header_and_update_state] >> Header block_header block_number\ + = {:?}, ClientState latest_commitment block_number = {:?}", header.block_header.block_number, client_state.latest_commitment.block_number); + tracing::info!( + "in client_def: [check_header_and_update_state] >> client_state = {:?}", + client_state + ); + tracing::info!( + "in client_def: [check_header_and_update_state] >> header = {:?}", + header + ); - // if client_state.latest_height() >= header.height() { - // return Err(Error::low_header_height( - // header.height(), - // client_state.latest_height(), - // )); - // } + // if client_state.latest_height() >= header.height() { + // return Err(Error::low_header_height( + // header.height(), + // client_state.latest_height(), + // )); + // } + + if header.block_header.block_number > client_state.latest_commitment.block_number { + return Err(Error::invalid_mmr_root_height( + client_state.latest_commitment.block_number, + header.block_header.block_number, + )); + } - if header.block_header.block_number > client_state.latest_commitment.block_number { - return Err(Error::invalid_mmr_root_height( - client_state.latest_commitment.block_number, - header.block_header.block_number, - )); - } + if client_state.latest_commitment.payload.is_empty() { + return Err(Error::empty_mmr_root()); + } - if client_state.latest_commitment.payload.is_empty() { - return Err(Error::empty_mmr_root()); - } + let mut mmr_root = [0u8; 32]; + mmr_root.copy_from_slice(&client_state.latest_commitment.payload); - let mut mmr_root = [0u8; 32]; - mmr_root.copy_from_slice(&client_state.latest_commitment.payload); + let mmr_proof = header.clone().mmr_leaf_proof; + let mmr_proof = beefy_light_client::mmr::MmrLeafProof::from(mmr_proof); - let mmr_proof = header.clone().mmr_leaf_proof; - let mmr_proof = beefy_light_client::mmr::MmrLeafProof::from(mmr_proof); + let mmr_leaf_encode = + beefy_light_client::mmr::MmrLeaf::from(header.clone().mmr_leaf).encode(); + let mmr_leaf_hash = beefy_merkle_tree::Keccak256::hash(&mmr_leaf_encode[..]); + let mmr_leaf = beefy_light_client::mmr::MmrLeaf::from(header.clone().mmr_leaf); - let mmr_leaf_encode = - beefy_light_client::mmr::MmrLeaf::from(header.clone().mmr_leaf).encode(); - let mmr_leaf_hash = beefy_merkle_tree::Keccak256::hash(&mmr_leaf_encode[..]); - let mmr_leaf = beefy_light_client::mmr::MmrLeaf::from(header.clone().mmr_leaf); + let header_hash = header.hash(); - let header_hash = header.hash(); + if mmr_leaf.parent_number_and_hash.1.is_empty() { + return Err(Error::empty_mmr_leaf_parent_hash_mmr_root()); + } + tracing::info!( + "ics1 client_def :[check_header_and_update_state] >> header_hash = {:?}", + header_hash + ); + tracing::info!( + "ics1 client_def :[check_header_and_update_state] >> parent_mmr_root = {:?}", + mmr_leaf.parent_number_and_hash.1 + ); - if mmr_leaf.parent_number_and_hash.1.is_empty() { - return Err(Error::empty_mmr_leaf_parent_hash_mmr_root()); - } - tracing::info!( - "ics1 client_def :[check_header_and_update_state] >> header_hash = {:?}", - header_hash - ); - tracing::info!( - "ics1 client_def :[check_header_and_update_state] >> parent_mmr_root = {:?}", - mmr_leaf.parent_number_and_hash.1 - ); + if header_hash != mmr_leaf.parent_number_and_hash.1 { + return Err(Error::header_hash_not_match()); + } - if header_hash != mmr_leaf.parent_number_and_hash.1 { - return Err(Error::header_hash_not_match()); - } + tracing::info!( + "in client_def: [check_header_and_update_state] >> mmr_root = {:?}", + mmr_root.clone() + ); + tracing::info!( + "in client_def: [check_header_and_update_state] >> mmr_leaf_hash = {:?}", + mmr_leaf_hash.clone() + ); + tracing::info!( + "in client_def: [check_header_and_update_state] >> mmr_proof = {:?}", + mmr_proof.clone() + ); + let result = beefy_light_client::mmr::verify_leaf_proof(mmr_root, mmr_leaf_hash, mmr_proof) + .map_err(|_| Error::invalid_mmr_leaf_proof())?; - tracing::info!( - "in client_def: [check_header_and_update_state] >> mmr_root = {:?}", - mmr_root.clone() - ); - tracing::info!( - "in client_def: [check_header_and_update_state] >> mmr_leaf_hash = {:?}", - mmr_leaf_hash.clone() - ); - tracing::info!( - "in client_def: [check_header_and_update_state] >> mmr_proof = {:?}", - mmr_proof.clone() - ); - let result = beefy_light_client::mmr::verify_leaf_proof(mmr_root, mmr_leaf_hash, mmr_proof) - .map_err(|_| Error::invalid_mmr_leaf_proof())?; + if !result { + return Err(Error::invalid_mmr_leaf_proof()); + } - if !result { - return Err(Error::invalid_mmr_leaf_proof()); - } + let client_state = ClientState { + block_header: header.clone().block_header, + block_number: header.clone().block_header.block_number, + ..client_state + }; - let client_state = ClientState { - block_header: header.clone().block_header, - block_number: header.clone().block_header.block_number, - ..client_state - }; + tracing::info!( + "in client_def: [check_header_and_update_state] >> client_state = {:?}", + client_state + ); + tracing::info!( + "in client_def: [check_header_and_update_state] >> consensus_state = {:?}", + ConsensusState::from(header.clone()) + ); - tracing::info!( - "in client_def: [check_header_and_update_state] >> client_state = {:?}", - client_state - ); - tracing::info!( - "in client_def: [check_header_and_update_state] >> consensus_state = {:?}", - ConsensusState::from(header.clone()) - ); + Ok((client_state, ConsensusState::from(header.clone()))) + } - Ok((client_state, ConsensusState::from(header.clone()))) + /// TODO + fn verify_upgrade_and_update_state( + &self, + client_state: &Self::ClientState, + consensus_state: &Self::ConsensusState, + proof_upgrade_client: MerkleProof, + proof_upgrade_consensus_state: MerkleProof, + ) -> Result<(Self::ClientState, Self::ConsensusState), Error> { + Ok((client_state.clone(), consensus_state.clone())) } + /// Verification functions as specified in: + /// + /// + /// Verify a `proof` that the consensus state of a given client (at height `consensus_height`) + /// matches the input `consensus_state`. The parameter `counterparty_height` represent the + /// height of the counterparty chain that this proof assumes (i.e., the height at which this + /// proof was computed). + #[allow(clippy::too_many_arguments)] fn verify_client_consensus_state( &self, - _client_state: &Self::ClientState, - _height: Height, - _prefix: &CommitmentPrefix, - _proof: &CommitmentProofBytes, - _client_id: &ClientId, - _consensus_height: Height, - _expected_consensus_state: &AnyConsensusState, + client_state: &Self::ClientState, + height: Height, + prefix: &CommitmentPrefix, + proof: &CommitmentProofBytes, + root: &CommitmentRoot, + client_id: &ClientId, + consensus_height: Height, + expected_consensus_state: &AnyConsensusState, ) -> Result<(), Error> { Ok(()) } + /// Verify a `proof` that a connection state matches that of the input `connection_end`. + #[allow(clippy::too_many_arguments)] fn verify_connection_state( &self, - _client_state: &Self::ClientState, - _height: Height, - _prefix: &CommitmentPrefix, - _proof: &CommitmentProofBytes, - _connection_id: Option<&ConnectionId>, - _expected_connection_end: &ConnectionEnd, + client_state: &Self::ClientState, + height: Height, + prefix: &CommitmentPrefix, + proof: &CommitmentProofBytes, + root: &CommitmentRoot, + connection_id: &ConnectionId, + expected_connection_end: &ConnectionEnd, ) -> Result<(), Error> { - // Todo: the _connection_id is None in `tx raw conn-ack`, as the _connection_id is not set in `tx raw conn-init` - // https://github.com/octopus-network/ibc-rs/blob/b98094a57620d0b3d9f8d2caced09abfc14ab00f/modules/src/ics03_connection/handler/conn_open_init.rs?_pjax=%23js-repo-pjax-container%2C%20div%5Bitemtype%3D%22http%3A%2F%2Fschema.org%2FSoftwareSourceCode%22%5D%20main%2C%20%5Bdata-pjax-container%5D#L33 - // let keys: Vec> = vec![_connection_id.unwrap().as_bytes().to_vec()]; - let keys: Vec> = vec!["connection-0".as_bytes().to_vec()]; - let storage_result = - Self::get_storage_via_proof(_client_state, _height, _proof, keys, "Connections") - .unwrap(); - let connection_end = ConnectionEnd::decode_vec(&storage_result).unwrap(); - tracing::info!( - "In ics10-client_def.rs: [verify_connection_state] >> connection_end: {:?}", - connection_end - ); + // Todo: the _connection_id is None in `tx raw conn-ack`, as the _connection_id is not set in `tx raw conn-init` + // https://github.com/octopus-network/ibc-rs/blob/b98094a57620d0b3d9f8d2caced09abfc14ab00f/modules/src/ics03_connection/handler/conn_open_init.rs?_pjax=%23js-repo-pjax-container%2C%20div%5Bitemtype%3D%22http%3A%2F%2Fschema.org%2FSoftwareSourceCode%22%5D%20main%2C%20%5Bdata-pjax-container%5D#L33 + // let keys: Vec> = vec![_connection_id.unwrap().as_bytes().to_vec()]; + let keys: Vec> = vec!["connection-0".as_bytes().to_vec()]; + let storage_result = + Self::get_storage_via_proof(client_state, height, proof, keys, "Connections") + .unwrap(); + let connection_end = ConnectionEnd::decode_vec(&storage_result).unwrap(); + tracing::info!( + "In ics10-client_def.rs: [verify_connection_state] >> connection_end: {:?}", + connection_end + ); - if !(connection_end.encode_vec().unwrap() == _expected_connection_end.encode_vec().unwrap()) - { - return Err(Error::invalid_connection_state()); - } - Ok(()) + if !(connection_end.encode_vec().unwrap() == expected_connection_end.encode_vec().unwrap()) + { + return Err(Error::invalid_connection_state()); + } + Ok(()) } + /// Verify a `proof` that a channel state matches that of the input `channel_end`. + #[allow(clippy::too_many_arguments)] fn verify_channel_state( &self, - _client_state: &Self::ClientState, - _height: Height, - _prefix: &CommitmentPrefix, - _proof: &CommitmentProofBytes, - _port_id: &PortId, - _channel_id: &ChannelId, - _expected_channel_end: &ChannelEnd, + client_state: &Self::ClientState, + height: Height, + prefix: &CommitmentPrefix, + proof: &CommitmentProofBytes, + root: &CommitmentRoot, + port_id: &PortId, + channel_id: &ChannelId, + expected_channel_end: &ChannelEnd, ) -> Result<(), Error> { - let keys: Vec> = vec![ - _port_id.as_bytes().to_vec(), - _channel_id.as_bytes().to_vec(), - ]; - let storage_result = - Self::get_storage_via_proof(_client_state, _height, _proof, keys, "Channels").unwrap(); - let channel_end = ChannelEnd::decode_vec(&storage_result).unwrap(); - tracing::info!( - "In ics10-client_def.rs: [verify_connection_state] >> channel_end: {:?}", - channel_end - ); + let keys: Vec> = vec![ + port_id.as_bytes().to_vec(), + channel_id.as_bytes().to_vec(), + ]; + let storage_result = + Self::get_storage_via_proof(client_state, height, proof, keys, "Channels").unwrap(); + let channel_end = ChannelEnd::decode_vec(&storage_result).unwrap(); + tracing::info!( + "In ics10-client_def.rs: [verify_connection_state] >> channel_end: {:?}", + channel_end + ); - if !(channel_end.encode_vec().unwrap() == _expected_channel_end.encode_vec().unwrap()) { - return Err(Error::invalid_connection_state()); - } - Ok(()) + if !(channel_end.encode_vec().unwrap() == expected_channel_end.encode_vec().unwrap()) { + return Err(Error::invalid_connection_state()); + } + Ok(()) } + /// Verify the client state for this chain that it is stored on the counterparty chain. + #[allow(clippy::too_many_arguments)] fn verify_client_full_state( &self, - _client_state: &Self::ClientState, - _height: Height, - _root: &CommitmentRoot, - _prefix: &CommitmentPrefix, - _client_id: &ClientId, - _proof: &CommitmentProofBytes, - _expected_client_state: &AnyClientState, + client_state: &Self::ClientState, + height: Height, + prefix: &CommitmentPrefix, + proof: &CommitmentProofBytes, + root: &CommitmentRoot, + client_id: &ClientId, + expected_client_state: &AnyClientState, ) -> Result<(), Error> { - let keys: Vec> = vec![_client_id.as_bytes().to_vec()]; - let storage_result = - Self::get_storage_via_proof(_client_state, _height, _proof, keys, "ClientStates") - .unwrap(); - let any_client_state = AnyClientState::decode_vec(&storage_result).unwrap(); - tracing::info!( - "In ics10-client_def.rs: [verify_client_full_state] >> decoded client_state: {:?}", - any_client_state - ); - tracing::info!( - "In ics10-client_def.rs: [verify_client_full_state] >> _expected_client_state: {:?}", - _expected_client_state - ); + let keys: Vec> = vec![client_id.as_bytes().to_vec()]; + let storage_result = + Self::get_storage_via_proof(client_state, height, proof, keys, "ClientStates") + .unwrap(); + let any_client_state = AnyClientState::decode_vec(&storage_result).unwrap(); + tracing::info!( + "In ics10-client_def.rs: [verify_client_full_state] >> decoded client_state: {:?}", + any_client_state + ); + tracing::info!( + "In ics10-client_def.rs: [verify_client_full_state] >> _expected_client_state: {:?}", + expected_client_state + ); - if !(any_client_state.encode_vec().unwrap() == _expected_client_state.encode_vec().unwrap()) - { - return Err(Error::invalid_client_state()); - } - Ok(()) + if !(any_client_state.encode_vec().unwrap() == expected_client_state.encode_vec().unwrap()) + { + return Err(Error::invalid_client_state()); + } + Ok(()) } + /// Verify a `proof` that a packet has been commited. + #[allow(clippy::too_many_arguments)] fn verify_packet_data( &self, - _client_state: &Self::ClientState, - _height: Height, - _proof: &CommitmentProofBytes, - _port_id: &PortId, - _channel_id: &ChannelId, - _seq: &Sequence, - _data: String, + ctx: &dyn ChannelReader, + client_state: &Self::ClientState, + height: Height, + connection_end: &ConnectionEnd, + proof: &CommitmentProofBytes, + root: &CommitmentRoot, + port_id: &PortId, + channel_id: &ChannelId, + sequence: Sequence, + commitment: String, ) -> Result<(), Error> { - Ok(()) // Todo: + Ok(()) } + /// Verify a `proof` that a packet has been commited. + #[allow(clippy::too_many_arguments)] fn verify_packet_acknowledgement( &self, - _client_state: &Self::ClientState, - _height: Height, - _proof: &CommitmentProofBytes, - _port_id: &PortId, - _channel_id: &ChannelId, - _seq: &Sequence, - _data: Vec, + ctx: &dyn ChannelReader, + client_state: &Self::ClientState, + height: Height, + connection_end: &ConnectionEnd, + proof: &CommitmentProofBytes, + root: &CommitmentRoot, + port_id: &PortId, + channel_id: &ChannelId, + sequence: Sequence, + ack: Vec, ) -> Result<(), Error> { - Ok(()) // todo!() + Ok(()) } + /// Verify a `proof` that of the next_seq_received. + #[allow(clippy::too_many_arguments)] fn verify_next_sequence_recv( &self, - _client_state: &Self::ClientState, - _height: Height, - _proof: &CommitmentProofBytes, - _port_id: &PortId, - _channel_id: &ChannelId, - _seq: &Sequence, + ctx: &dyn ChannelReader, + client_state: &Self::ClientState, + height: Height, + connection_end: &ConnectionEnd, + proof: &CommitmentProofBytes, + root: &CommitmentRoot, + port_id: &PortId, + channel_id: &ChannelId, + sequence: Sequence, ) -> Result<(), Error> { - Ok(()) // todo!() + Ok(()) } + /// Verify a `proof` that a packet has not been received. + #[allow(clippy::too_many_arguments)] fn verify_packet_receipt_absence( &self, - _client_state: &Self::ClientState, - _height: Height, - _proof: &CommitmentProofBytes, - _port_id: &PortId, - _channel_id: &ChannelId, - _seq: &Sequence, - ) -> Result<(), Error> { - Ok(()) // todo: - } - - fn verify_upgrade_and_update_state( - &self, + ctx: &dyn ChannelReader, client_state: &Self::ClientState, - consensus_state: &Self::ConsensusState, - _proof_upgrade_client: MerkleProof, - _proof_upgrade_consensus_state: MerkleProof, - ) -> Result<(Self::ClientState, Self::ConsensusState), Error> { - // TODO - Ok((client_state.clone(), consensus_state.clone())) + height: Height, + connection_end: &ConnectionEnd, + proof: &CommitmentProofBytes, + root: &CommitmentRoot, + port_id: &PortId, + channel_id: &ChannelId, + sequence: Sequence, + ) -> Result<(), Error> { + Ok(()) } } @@ -307,7 +348,7 @@ impl GrandpaClient { tracing::info!("In ics10-client_def.rs: [extract_verify_beefy_proof] >> _client_state: {:?}, _height: {:?}, _keys: {:?}, _storage_name: {:?}", _client_state, _height, _keys, _storage_name); - use crate::ics10_grandpa::state_machine::read_proof_check; + use crate::clients::ics10_grandpa::state_machine::read_proof_check; use core::convert::TryFrom; use ibc_proto::ibc::core::commitment::v1::MerkleProof as RawMerkleProof; use ibc_proto::ics23::commitment_proof::Proof::Exist; @@ -353,7 +394,7 @@ impl GrandpaClient { state_root ); - let mut storage_result = read_proof_check::( + let storage_result = read_proof_check::( sp_core::H256::from(state_root), StorageProof::new(storage_proof.proof), &_storage_keys, @@ -411,14 +452,14 @@ fn vector_to_array(v: Vec) -> [T; N] { #[cfg(test)] mod tests { use super::GrandpaClient; - use crate::ics02_client::client_def::ClientDef; - use crate::ics02_client::height::Height; - use crate::ics10_grandpa::client_state::ClientState; - use crate::ics10_grandpa::header::Header; - use crate::ics10_grandpa::help::{ + use crate::core::ics02_client::client_def::ClientDef; + use crate::core::ics02_client::height::Height; + use crate::clients::ics10_grandpa::client_state::ClientState; + use crate::clients::ics10_grandpa::header::Header; + use crate::clients::ics10_grandpa::help::{ BlockHeader, Commitment, MmrLeaf, MmrLeafProof, ValidatorSet, }; - use crate::ics24_host::identifier::ChainId; + use crate::core::ics24_host::identifier::ChainId; use alloc::boxed::Box; use beefy_merkle_tree::Keccak256; use codec::{Decode, Encode}; @@ -485,7 +526,7 @@ mod tests { println!("beefy_light_client header = {:?}", header); println!("beefy_light_client header hash = {:?}", header.hash()); - let ics10_header = crate::ics10_grandpa::help::BlockHeader::from(header_1); + let ics10_header = crate::clients::ics10_grandpa::help::BlockHeader::from(header_1); println!("grandpa_header = {:?}", ics10_header); println!("ics10_header hash = {:?}", ics10_header.hash()); diff --git a/modules/src/ics10_grandpa/client_state.rs b/modules/src/clients/ics10_grandpa/client_state.rs similarity index 77% rename from modules/src/ics10_grandpa/client_state.rs rename to modules/src/clients/ics10_grandpa/client_state.rs index e4efa19d5..0ced43d26 100644 --- a/modules/src/ics10_grandpa/client_state.rs +++ b/modules/src/clients/ics10_grandpa/client_state.rs @@ -11,11 +11,11 @@ use super::help::BlockHeader; use super::help::Commitment; use super::help::ValidatorSet; -use crate::ics02_client::client_state::AnyClientState; -use crate::ics02_client::client_type::ClientType; -use crate::ics10_grandpa::error::Error; -use crate::ics10_grandpa::header::Header; -use crate::ics24_host::identifier::ChainId; +use crate::core::ics02_client::client_state::AnyClientState; +use crate::core::ics02_client::client_type::ClientType; +use crate::clients::ics10_grandpa::error::Error; +use crate::clients::ics10_grandpa::header::Header; +use crate::core::ics24_host::identifier::ChainId; use crate::Height; use serde::{Deserialize, Serialize}; use tendermint_proto::Protobuf; @@ -26,7 +26,7 @@ pub struct ClientState { /// block_number is height? pub block_number: u32, /// Block height when the client was frozen due to a misbehaviour - pub frozen_height: Height, + pub frozen_height: Option, pub block_header: BlockHeader, pub latest_commitment: Commitment, pub validator_set: ValidatorSet, @@ -37,7 +37,7 @@ impl Default for ClientState { Self { chain_id: ChainId::default(), block_number: u32::default(), - frozen_height: Height::default(), + frozen_height: None, block_header: BlockHeader::default(), latest_commitment: Commitment::default(), validator_set: ValidatorSet::default(), @@ -49,7 +49,6 @@ impl ClientState { pub fn new( chain_id: ChainId, block_number: u32, - frozen_height: Height, block_header: BlockHeader, latest_commitment: Commitment, validator_set: ValidatorSet, @@ -57,10 +56,10 @@ impl ClientState { let client_state = ClientState { chain_id, block_number, - frozen_height, block_header, latest_commitment, validator_set, + frozen_height: None, }; Ok(client_state) @@ -95,7 +94,9 @@ impl ClientState { impl Protobuf for ClientState {} -impl crate::ics02_client::client_state::ClientState for ClientState { +impl crate::core::ics02_client::client_state::ClientState for ClientState { + type UpgradeOptions = (); + fn chain_id(&self) -> ChainId { self.chain_id.clone() } @@ -108,9 +109,12 @@ impl crate::ics02_client::client_state::ClientState for ClientState { Height::new(0, self.block_number as u64) } - fn is_frozen(&self) -> bool { - // If 'frozen_height' is set to a non-zero value, then the client state is frozen. - !self.frozen_height.is_zero() + fn frozen_height(&self) -> Option { + self.frozen_height + } + + fn upgrade(self, upgrade_height: Height, upgrade_options: Self::UpgradeOptions, chain_id: ChainId) -> Self { + todo!() } fn wrap_any(self) -> AnyClientState { @@ -122,10 +126,19 @@ impl TryFrom for ClientState { type Error = Error; fn try_from(raw: RawClientState) -> Result { + let frozen_height = raw.frozen_height.and_then(|raw_height| { + let height = raw_height.into(); + if height == Height::zero() { + None + } else { + Some(height) + } + }); + Ok(Self { chain_id: ChainId::from_str(raw.chain_id.as_str()).unwrap(), block_number: raw.block_number, - frozen_height: Height::new(0, raw.frozen_height as u64), + frozen_height, block_header: raw.block_header.unwrap().into(), latest_commitment: raw.latest_commitment.unwrap().into(), validator_set: raw.validator_set.unwrap().into(), @@ -138,7 +151,7 @@ impl From for RawClientState { Self { chain_id: value.chain_id.to_string(), block_number: value.block_number, - frozen_height: value.frozen_height.revision_height as u32, + frozen_height: Some(value.frozen_height.unwrap_or_else(Height::zero).into()), block_header: Some(value.block_header.into()), latest_commitment: Some(value.latest_commitment.into()), validator_set: Some(value.validator_set.into()), diff --git a/modules/src/ics10_grandpa/consensus_state.rs b/modules/src/clients/ics10_grandpa/consensus_state.rs similarity index 89% rename from modules/src/ics10_grandpa/consensus_state.rs rename to modules/src/clients/ics10_grandpa/consensus_state.rs index 81667e773..2eb4b95d1 100644 --- a/modules/src/ics10_grandpa/consensus_state.rs +++ b/modules/src/clients/ics10_grandpa/consensus_state.rs @@ -9,12 +9,12 @@ use serde::Serialize; use ibc_proto::ibc::lightclients::grandpa::v1::ConsensusState as RawConsensusState; use super::help::Commitment; -use crate::ics02_client::client_consensus::AnyConsensusState; -use crate::ics02_client::client_type::ClientType; -use crate::ics10_grandpa::error::Error; -use crate::ics10_grandpa::header::Header; -use crate::ics10_grandpa::help::BlockHeader; -use crate::ics23_commitment::commitment::CommitmentRoot; +use crate::core::ics02_client::client_consensus::AnyConsensusState; +use crate::core::ics02_client::client_type::ClientType; +use crate::clients::ics10_grandpa::error::Error; +use crate::clients::ics10_grandpa::header::Header; +use crate::clients::ics10_grandpa::help::BlockHeader; +use crate::core::ics23_commitment::commitment::CommitmentRoot; use tendermint_proto::Protobuf; #[derive(Clone, Debug, PartialEq, Eq, Serialize)] @@ -71,7 +71,7 @@ impl Default for ConsensusState { } impl Protobuf for ConsensusState {} -impl crate::ics02_client::client_consensus::ConsensusState for ConsensusState { +impl crate::core::ics02_client::client_consensus::ConsensusState for ConsensusState { type Error = Infallible; fn client_type(&self) -> ClientType { @@ -82,10 +82,6 @@ impl crate::ics02_client::client_consensus::ConsensusState for ConsensusState { &self.root } - fn validate_basic(&self) -> Result<(), Self::Error> { - unimplemented!() - } - fn wrap_any(self) -> AnyConsensusState { AnyConsensusState::Grandpa(self) } diff --git a/modules/src/ics10_grandpa/error.rs b/modules/src/clients/ics10_grandpa/error.rs similarity index 96% rename from modules/src/ics10_grandpa/error.rs rename to modules/src/clients/ics10_grandpa/error.rs index 15e54a40e..0c792c950 100644 --- a/modules/src/ics10_grandpa/error.rs +++ b/modules/src/clients/ics10_grandpa/error.rs @@ -1,6 +1,6 @@ use alloc::string::String; -use crate::ics24_host::error::ValidationError; +use crate::core::ics24_host::error::ValidationError; use flex_error::{define_error, DisplayOnly, TraceError}; define_error! { diff --git a/modules/src/ics10_grandpa/header.rs b/modules/src/clients/ics10_grandpa/header.rs similarity index 83% rename from modules/src/ics10_grandpa/header.rs rename to modules/src/clients/ics10_grandpa/header.rs index 9435c98a0..f085c6554 100644 --- a/modules/src/ics10_grandpa/header.rs +++ b/modules/src/clients/ics10_grandpa/header.rs @@ -9,10 +9,10 @@ use super::help::MmrLeaf; use super::help::MmrLeafProof; use super::help::SignedCommitment; use super::help::ValidatorMerkleProof; -use crate::ics02_client::client_type::ClientType; -use crate::ics02_client::header::AnyHeader; -use crate::ics10_grandpa::error::Error; -use crate::ics24_host::identifier::ChainId; +use crate::core::ics02_client::client_type::ClientType; +use crate::core::ics02_client::header::AnyHeader; +use crate::clients::ics10_grandpa::error::Error; +use crate::core::ics24_host::identifier::ChainId; use crate::Height; use beefy_merkle_tree::Hash; use bytes::Buf; @@ -20,9 +20,10 @@ use codec::{Decode, Encode}; use prost::Message; use serde::{Deserialize, Serialize}; use tendermint_proto::Protobuf; +use crate::timestamp::Timestamp; /// block header -#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Encode, Decode)] +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Encode, Decode)] pub struct Header { pub block_header: BlockHeader, pub mmr_leaf: MmrLeaf, @@ -57,7 +58,7 @@ impl Header { } } -impl crate::ics02_client::header::Header for Header { +impl crate::core::ics02_client::header::Header for Header { fn client_type(&self) -> ClientType { ClientType::Grandpa } @@ -66,6 +67,10 @@ impl crate::ics02_client::header::Header for Header { self.height() } + fn timestamp(&self) -> Timestamp { + Timestamp::none() + } + fn wrap_any(self) -> AnyHeader { AnyHeader::Grandpa(self) } diff --git a/modules/src/ics10_grandpa/help.rs b/modules/src/clients/ics10_grandpa/help.rs similarity index 99% rename from modules/src/ics10_grandpa/help.rs rename to modules/src/clients/ics10_grandpa/help.rs index 5e74db6d0..8d58c3a13 100644 --- a/modules/src/ics10_grandpa/help.rs +++ b/modules/src/clients/ics10_grandpa/help.rs @@ -1,4 +1,4 @@ -use crate::ics10_grandpa::error::Error; +use crate::clients::ics10_grandpa::error::Error; use alloc::vec; use alloc::vec::Vec; use beefy_light_client::mmr::MmrLeafVersion; diff --git a/modules/src/ics10_grandpa/misbehaviour.rs b/modules/src/clients/ics10_grandpa/misbehaviour.rs similarity index 85% rename from modules/src/ics10_grandpa/misbehaviour.rs rename to modules/src/clients/ics10_grandpa/misbehaviour.rs index 127c20dcc..27bc1b06a 100644 --- a/modules/src/ics10_grandpa/misbehaviour.rs +++ b/modules/src/clients/ics10_grandpa/misbehaviour.rs @@ -4,10 +4,10 @@ use core::fmt; use ibc_proto::ibc::lightclients::grandpa::v1::Misbehaviour as RawMisbehaviour; -use crate::ics02_client::misbehaviour::AnyMisbehaviour; -use crate::ics10_grandpa::error::Error; -use crate::ics10_grandpa::header::Header; -use crate::ics24_host::identifier::ClientId; +use crate::core::ics02_client::misbehaviour::AnyMisbehaviour; +use crate::clients::ics10_grandpa::error::Error; +use crate::clients::ics10_grandpa::header::Header; +use crate::core::ics24_host::identifier::ClientId; use crate::Height; use tendermint_proto::Protobuf; @@ -18,7 +18,7 @@ pub struct Misbehaviour { pub header2: Header, } -impl crate::ics02_client::misbehaviour::Misbehaviour for Misbehaviour { +impl crate::core::ics02_client::misbehaviour::Misbehaviour for Misbehaviour { fn client_id(&self) -> &ClientId { &self.client_id } diff --git a/modules/src/ics10_grandpa/mod.rs b/modules/src/clients/ics10_grandpa/mod.rs similarity index 100% rename from modules/src/ics10_grandpa/mod.rs rename to modules/src/clients/ics10_grandpa/mod.rs diff --git a/modules/src/ics10_grandpa/state_machine.rs b/modules/src/clients/ics10_grandpa/state_machine.rs similarity index 100% rename from modules/src/ics10_grandpa/state_machine.rs rename to modules/src/clients/ics10_grandpa/state_machine.rs diff --git a/modules/src/clients/mod.rs b/modules/src/clients/mod.rs new file mode 100644 index 000000000..05fec021a --- /dev/null +++ b/modules/src/clients/mod.rs @@ -0,0 +1,4 @@ +//! Implementations of client verification algorithms for specific types of chains. + +pub mod ics07_tendermint; +pub mod ics10_grandpa; diff --git a/modules/src/ics02_client/client_consensus.rs b/modules/src/core/ics02_client/client_consensus.rs similarity index 79% rename from modules/src/ics02_client/client_consensus.rs rename to modules/src/core/ics02_client/client_consensus.rs index b16633905..773845dd8 100644 --- a/modules/src/ics02_client/client_consensus.rs +++ b/modules/src/core/ics02_client/client_consensus.rs @@ -1,21 +1,22 @@ use crate::prelude::*; -use chrono::{DateTime, Utc}; + use core::convert::Infallible; -use core::convert::TryFrom; use core::marker::{Send, Sync}; + use ibc_proto::ibc::core::client::v1::ConsensusStateWithHeight; use prost_types::Any; use serde::Serialize; use tendermint_proto::Protobuf; -use crate::events::IbcEventType; -use crate::ics02_client::client_type::ClientType; -use crate::ics02_client::error::Error; -use crate::ics02_client::height::Height; -use crate::ics07_tendermint::consensus_state; -use crate::ics10_grandpa; -use crate::ics23_commitment::commitment::CommitmentRoot; -use crate::ics24_host::identifier::ClientId; +use crate::clients::ics10_grandpa; +use crate::clients::ics07_tendermint::consensus_state; +use crate::core::ics02_client::client_type::ClientType; +use crate::core::ics02_client::error::Error; +use crate::core::ics02_client::height::Height; +use crate::core::ics23_commitment::commitment::CommitmentRoot; +use crate::core::ics24_host::identifier::ClientId; +use crate::events::WithBlockDataType; + use crate::timestamp::Timestamp; #[cfg(any(test, feature = "mocks"))] @@ -24,9 +25,11 @@ use crate::mock::client_state::MockConsensusState; pub const TENDERMINT_CONSENSUS_STATE_TYPE_URL: &str = "/ibc.lightclients.tendermint.v1.ConsensusState"; -pub const GRANDPA_CONSENSUS_STATE_TYPE_URL: &str = "/ibc.lightclients.grandpa.v1.ConsensusState"; +pub const GRANDPA_CONSENSUS_STATE_TYPE_URL: &str = + "/ibc.lightclients.grandpa.v1.ConsensusState"; -pub const MOCK_CONSENSUS_STATE_TYPE_URL: &str = "/ibc.mock.ConsensusState"; +pub const MOCK_CONSENSUS_STATE_TYPE_URL: &str = + "/ibc.mock.ConsensusState"; pub trait ConsensusState: Clone + core::fmt::Debug + Send + Sync { type Error; @@ -37,9 +40,6 @@ pub trait ConsensusState: Clone + core::fmt::Debug + Send + Sync { /// Commitment root of the consensus state, which is used for key-value pair verification. fn root(&self) -> &CommitmentRoot; - /// Performs basic validation of the consensus state - fn validate_basic(&self) -> Result<(), Self::Error>; - /// Wrap into an `AnyConsensusState` fn wrap_any(self) -> AnyConsensusState; } @@ -57,15 +57,8 @@ pub enum AnyConsensusState { impl AnyConsensusState { pub fn timestamp(&self) -> Timestamp { match self { - Self::Tendermint(cs_state) => { - let date: DateTime = cs_state.timestamp.into(); - Timestamp::from_datetime(date) - } - - Self::Grandpa(cs_state) => { - // TODO ibc02 MUST - Timestamp::none() - } + Self::Tendermint(cs_state) => cs_state.timestamp.into(), + Self::Grandpa(_cs_state) => Timestamp::from_nanoseconds(1_000).unwrap(), #[cfg(any(test, feature = "mocks"))] Self::Mock(mock_state) => mock_state.timestamp(), @@ -98,7 +91,7 @@ impl TryFrom for AnyConsensusState { )), GRANDPA_CONSENSUS_STATE_TYPE_URL => Ok(AnyConsensusState::Grandpa( - crate::ics10_grandpa::consensus_state::ConsensusState::decode_vec(&value.value) + crate::clients::ics10_grandpa::consensus_state::ConsensusState::decode_vec(&value.value) .map_err(Error::decode_raw_client_state)?, )), @@ -191,16 +184,6 @@ impl ConsensusState for AnyConsensusState { } } - fn validate_basic(&self) -> Result<(), Infallible> { - match self { - Self::Tendermint(cs_state) => cs_state.validate_basic(), - Self::Grandpa(cs_state) => cs_state.validate_basic(), - - #[cfg(any(test, feature = "mocks"))] - Self::Mock(mock_state) => mock_state.validate_basic(), - } - } - fn wrap_any(self) -> AnyConsensusState { self } @@ -210,7 +193,7 @@ impl ConsensusState for AnyConsensusState { #[derive(Clone, Debug)] pub struct QueryClientEventRequest { pub height: crate::Height, - pub event_id: IbcEventType, + pub event_id: WithBlockDataType, pub client_id: ClientId, pub consensus_height: crate::Height, } diff --git a/modules/src/ics02_client/client_def.rs b/modules/src/core/ics02_client/client_def.rs similarity index 84% rename from modules/src/ics02_client/client_def.rs rename to modules/src/core/ics02_client/client_def.rs index df845cc48..bbfee0655 100644 --- a/modules/src/ics02_client/client_def.rs +++ b/modules/src/core/ics02_client/client_def.rs @@ -1,18 +1,22 @@ use ibc_proto::ibc::core::commitment::v1::MerkleProof; +use crate::clients::ics10_grandpa::client_def::GrandpaClient; +use crate::clients::ics07_tendermint::client_def::TendermintClient; +use crate::core::ics02_client::client_consensus::{AnyConsensusState, ConsensusState}; +use crate::core::ics02_client::client_state::{AnyClientState, ClientState}; +use crate::core::ics02_client::client_type::ClientType; +use crate::core::ics02_client::context::ClientReader; +use crate::core::ics02_client::error::Error; +use crate::core::ics02_client::header::{AnyHeader, Header}; +use crate::core::ics03_connection::connection::ConnectionEnd; +use crate::core::ics04_channel::channel::ChannelEnd; +use crate::core::ics04_channel::context::ChannelReader; +use crate::core::ics04_channel::packet::Sequence; +use crate::core::ics23_commitment::commitment::{ + CommitmentPrefix, CommitmentProofBytes, CommitmentRoot, +}; +use crate::core::ics24_host::identifier::{ChannelId, ClientId, ConnectionId, PortId}; use crate::downcast; -use crate::ics02_client::client_consensus::{AnyConsensusState, ConsensusState}; -use crate::ics02_client::client_state::{AnyClientState, ClientState}; -use crate::ics02_client::client_type::ClientType; -use crate::ics02_client::error::Error; -use crate::ics02_client::header::{AnyHeader, Header}; -use crate::ics03_connection::connection::ConnectionEnd; -use crate::ics04_channel::channel::ChannelEnd; -use crate::ics04_channel::packet::Sequence; -use crate::ics07_tendermint::client_def::TendermintClient; -use crate::ics10_grandpa::client_def::GrandpaClient; -use crate::ics23_commitment::commitment::{CommitmentPrefix, CommitmentProofBytes, CommitmentRoot}; -use crate::ics24_host::identifier::{ChannelId, ClientId, ConnectionId, PortId}; use crate::prelude::*; use crate::Height; @@ -24,13 +28,15 @@ pub trait ClientDef: Clone { type ClientState: ClientState; type ConsensusState: ConsensusState; - /// TODO fn check_header_and_update_state( &self, + ctx: &dyn ClientReader, + client_id: ClientId, client_state: Self::ClientState, header: Self::Header, ) -> Result<(Self::ClientState, Self::ConsensusState), Error>; + /// TODO fn verify_upgrade_and_update_state( &self, client_state: &Self::ClientState, @@ -53,19 +59,22 @@ pub trait ClientDef: Clone { height: Height, prefix: &CommitmentPrefix, proof: &CommitmentProofBytes, + root: &CommitmentRoot, client_id: &ClientId, consensus_height: Height, expected_consensus_state: &AnyConsensusState, ) -> Result<(), Error>; /// Verify a `proof` that a connection state matches that of the input `connection_end`. + #[allow(clippy::too_many_arguments)] fn verify_connection_state( &self, client_state: &Self::ClientState, height: Height, prefix: &CommitmentPrefix, proof: &CommitmentProofBytes, - connection_id: Option<&ConnectionId>, + root: &CommitmentRoot, + connection_id: &ConnectionId, expected_connection_end: &ConnectionEnd, ) -> Result<(), Error>; @@ -77,6 +86,7 @@ pub trait ClientDef: Clone { height: Height, prefix: &CommitmentPrefix, proof: &CommitmentProofBytes, + root: &CommitmentRoot, port_id: &PortId, channel_id: &ChannelId, expected_channel_end: &ChannelEnd, @@ -86,25 +96,28 @@ pub trait ClientDef: Clone { #[allow(clippy::too_many_arguments)] fn verify_client_full_state( &self, - _client_state: &Self::ClientState, + client_state: &Self::ClientState, height: Height, - root: &CommitmentRoot, prefix: &CommitmentPrefix, - client_id: &ClientId, proof: &CommitmentProofBytes, - client_state: &AnyClientState, + root: &CommitmentRoot, + client_id: &ClientId, + expected_client_state: &AnyClientState, ) -> Result<(), Error>; /// Verify a `proof` that a packet has been commited. #[allow(clippy::too_many_arguments)] fn verify_packet_data( &self, + ctx: &dyn ChannelReader, client_state: &Self::ClientState, height: Height, + connection_end: &ConnectionEnd, proof: &CommitmentProofBytes, + root: &CommitmentRoot, port_id: &PortId, channel_id: &ChannelId, - seq: &Sequence, + sequence: Sequence, commitment: String, ) -> Result<(), Error>; @@ -112,12 +125,15 @@ pub trait ClientDef: Clone { #[allow(clippy::too_many_arguments)] fn verify_packet_acknowledgement( &self, + ctx: &dyn ChannelReader, client_state: &Self::ClientState, height: Height, + connection_end: &ConnectionEnd, proof: &CommitmentProofBytes, + root: &CommitmentRoot, port_id: &PortId, channel_id: &ChannelId, - seq: &Sequence, + sequence: Sequence, ack: Vec, ) -> Result<(), Error>; @@ -125,24 +141,30 @@ pub trait ClientDef: Clone { #[allow(clippy::too_many_arguments)] fn verify_next_sequence_recv( &self, + ctx: &dyn ChannelReader, client_state: &Self::ClientState, height: Height, + connection_end: &ConnectionEnd, proof: &CommitmentProofBytes, + root: &CommitmentRoot, port_id: &PortId, channel_id: &ChannelId, - seq: &Sequence, + sequence: Sequence, ) -> Result<(), Error>; /// Verify a `proof` that a packet has not been received. #[allow(clippy::too_many_arguments)] fn verify_packet_receipt_absence( &self, + ctx: &dyn ChannelReader, client_state: &Self::ClientState, height: Height, + connection_end: &ConnectionEnd, proof: &CommitmentProofBytes, + root: &CommitmentRoot, port_id: &PortId, channel_id: &ChannelId, - seq: &Sequence, + sequence: Sequence, ) -> Result<(), Error>; } @@ -158,7 +180,7 @@ pub enum AnyClient { impl AnyClient { pub fn from_client_type(client_type: ClientType) -> AnyClient { match client_type { - ClientType::Tendermint => Self::Tendermint(TendermintClient), + ClientType::Tendermint => Self::Tendermint(TendermintClient::default()), ClientType::Grandpa => Self::Grandpa(GrandpaClient), #[cfg(any(test, feature = "mocks"))] @@ -176,6 +198,8 @@ impl ClientDef for AnyClient { /// Validates an incoming `header` against the latest consensus state of this client. fn check_header_and_update_state( &self, + ctx: &dyn ClientReader, + client_id: ClientId, client_state: AnyClientState, header: AnyHeader, ) -> Result<(AnyClientState, AnyConsensusState), Error> { @@ -188,7 +212,7 @@ impl ClientDef for AnyClient { .ok_or_else(|| Error::client_args_type_mismatch(ClientType::Tendermint))?; let (new_state, new_consensus) = - client.check_header_and_update_state(client_state, header)?; + client.check_header_and_update_state(ctx, client_id, client_state, header)?; Ok(( AnyClientState::Tendermint(new_state), @@ -203,7 +227,7 @@ impl ClientDef for AnyClient { .ok_or_else(|| Error::client_args_type_mismatch(ClientType::Grandpa))?; let (new_state, new_consensus) = - client.check_header_and_update_state(client_state, header)?; + client.check_header_and_update_state(ctx, client_id, client_state, header)?; Ok(( AnyClientState::Grandpa(new_state), @@ -220,7 +244,7 @@ impl ClientDef for AnyClient { .ok_or_else(|| Error::client_args_type_mismatch(ClientType::Mock))?; let (new_state, new_consensus) = - client.check_header_and_update_state(client_state, header)?; + client.check_header_and_update_state(ctx, client_id, client_state, header)?; Ok(( AnyClientState::Mock(new_state), @@ -236,6 +260,7 @@ impl ClientDef for AnyClient { height: Height, prefix: &CommitmentPrefix, proof: &CommitmentProofBytes, + root: &CommitmentRoot, client_id: &ClientId, consensus_height: Height, expected_consensus_state: &AnyConsensusState, @@ -252,6 +277,7 @@ impl ClientDef for AnyClient { height, prefix, proof, + root, client_id, consensus_height, expected_consensus_state, @@ -269,6 +295,7 @@ impl ClientDef for AnyClient { height, prefix, proof, + root, client_id, consensus_height, expected_consensus_state, @@ -287,6 +314,7 @@ impl ClientDef for AnyClient { height, prefix, proof, + root, client_id, consensus_height, expected_consensus_state, @@ -301,7 +329,8 @@ impl ClientDef for AnyClient { height: Height, prefix: &CommitmentPrefix, proof: &CommitmentProofBytes, - connection_id: Option<&ConnectionId>, + root: &CommitmentRoot, + connection_id: &ConnectionId, expected_connection_end: &ConnectionEnd, ) -> Result<(), Error> { match self { @@ -314,6 +343,7 @@ impl ClientDef for AnyClient { height, prefix, proof, + root, connection_id, expected_connection_end, ) @@ -327,6 +357,7 @@ impl ClientDef for AnyClient { height, prefix, proof, + root, connection_id, expected_connection_end, ) @@ -342,6 +373,7 @@ impl ClientDef for AnyClient { height, prefix, proof, + root, connection_id, expected_connection_end, ) @@ -355,6 +387,7 @@ impl ClientDef for AnyClient { height: Height, prefix: &CommitmentPrefix, proof: &CommitmentProofBytes, + root: &CommitmentRoot, port_id: &PortId, channel_id: &ChannelId, expected_channel_end: &ChannelEnd, @@ -369,6 +402,7 @@ impl ClientDef for AnyClient { height, prefix, proof, + root, port_id, channel_id, expected_channel_end, @@ -383,6 +417,7 @@ impl ClientDef for AnyClient { height, prefix, proof, + root, port_id, channel_id, expected_channel_end, @@ -399,6 +434,7 @@ impl ClientDef for AnyClient { height, prefix, proof, + root, port_id, channel_id, expected_channel_end, @@ -411,10 +447,10 @@ impl ClientDef for AnyClient { &self, client_state: &Self::ClientState, height: Height, - root: &CommitmentRoot, prefix: &CommitmentPrefix, - client_id: &ClientId, proof: &CommitmentProofBytes, + root: &CommitmentRoot, + client_id: &ClientId, client_state_on_counterparty: &AnyClientState, ) -> Result<(), Error> { match self { @@ -427,10 +463,10 @@ impl ClientDef for AnyClient { client.verify_client_full_state( client_state, height, - root, prefix, - client_id, proof, + root, + client_id, client_state_on_counterparty, ) } @@ -443,10 +479,10 @@ impl ClientDef for AnyClient { client.verify_client_full_state( client_state, height, - root, prefix, - client_id, proof, + root, + client_id, client_state_on_counterparty, ) } @@ -461,10 +497,10 @@ impl ClientDef for AnyClient { client.verify_client_full_state( client_state, height, - root, prefix, - client_id, proof, + root, + client_id, client_state_on_counterparty, ) } @@ -472,12 +508,15 @@ impl ClientDef for AnyClient { } fn verify_packet_data( &self, + ctx: &dyn ChannelReader, client_state: &Self::ClientState, height: Height, + connection_end: &ConnectionEnd, proof: &CommitmentProofBytes, + root: &CommitmentRoot, port_id: &PortId, channel_id: &ChannelId, - seq: &Sequence, + sequence: Sequence, commitment: String, ) -> Result<(), Error> { match self { @@ -488,12 +527,15 @@ impl ClientDef for AnyClient { .ok_or_else(|| Error::client_args_type_mismatch(ClientType::Tendermint))?; client.verify_packet_data( + ctx, client_state, height, + connection_end, proof, + root, port_id, channel_id, - seq, + sequence, commitment, ) } @@ -504,12 +546,15 @@ impl ClientDef for AnyClient { .ok_or_else(|| Error::client_args_type_mismatch(ClientType::Grandpa))?; client.verify_packet_data( + ctx, client_state, height, + connection_end, proof, + root, port_id, channel_id, - seq, + sequence, commitment, ) } @@ -522,12 +567,15 @@ impl ClientDef for AnyClient { .ok_or_else(|| Error::client_args_type_mismatch(ClientType::Mock))?; client.verify_packet_data( + ctx, client_state, height, + connection_end, proof, + root, port_id, channel_id, - seq, + sequence, commitment, ) } @@ -536,12 +584,15 @@ impl ClientDef for AnyClient { fn verify_packet_acknowledgement( &self, + ctx: &dyn ChannelReader, client_state: &Self::ClientState, height: Height, + connection_end: &ConnectionEnd, proof: &CommitmentProofBytes, + root: &CommitmentRoot, port_id: &PortId, channel_id: &ChannelId, - seq: &Sequence, + sequence: Sequence, ack: Vec, ) -> Result<(), Error> { match self { @@ -552,12 +603,15 @@ impl ClientDef for AnyClient { .ok_or_else(|| Error::client_args_type_mismatch(ClientType::Tendermint))?; client.verify_packet_acknowledgement( + ctx, client_state, height, + connection_end, proof, + root, port_id, channel_id, - seq, + sequence, ack, ) } @@ -568,12 +622,15 @@ impl ClientDef for AnyClient { .ok_or_else(|| Error::client_args_type_mismatch(ClientType::Grandpa))?; client.verify_packet_acknowledgement( + ctx, client_state, height, + connection_end, proof, + root, port_id, channel_id, - seq, + sequence, ack, ) } @@ -586,12 +643,15 @@ impl ClientDef for AnyClient { .ok_or_else(|| Error::client_args_type_mismatch(ClientType::Mock))?; client.verify_packet_acknowledgement( + ctx, client_state, height, + connection_end, proof, + root, port_id, channel_id, - seq, + sequence, ack, ) } @@ -600,12 +660,15 @@ impl ClientDef for AnyClient { fn verify_next_sequence_recv( &self, + ctx: &dyn ChannelReader, client_state: &Self::ClientState, height: Height, + connection_end: &ConnectionEnd, proof: &CommitmentProofBytes, + root: &CommitmentRoot, port_id: &PortId, channel_id: &ChannelId, - seq: &Sequence, + sequence: Sequence, ) -> Result<(), Error> { match self { Self::Tendermint(client) => { @@ -615,12 +678,15 @@ impl ClientDef for AnyClient { .ok_or_else(|| Error::client_args_type_mismatch(ClientType::Tendermint))?; client.verify_next_sequence_recv( + ctx, client_state, height, + connection_end, proof, + root, port_id, channel_id, - seq, + sequence, ) } @@ -631,12 +697,15 @@ impl ClientDef for AnyClient { .ok_or_else(|| Error::client_args_type_mismatch(ClientType::Grandpa))?; client.verify_next_sequence_recv( + ctx, client_state, height, + connection_end, proof, + root, port_id, channel_id, - seq, + sequence, ) } @@ -648,24 +717,30 @@ impl ClientDef for AnyClient { .ok_or_else(|| Error::client_args_type_mismatch(ClientType::Mock))?; client.verify_next_sequence_recv( + ctx, client_state, height, + connection_end, proof, + root, port_id, channel_id, - seq, + sequence, ) } } } fn verify_packet_receipt_absence( &self, + ctx: &dyn ChannelReader, client_state: &Self::ClientState, height: Height, + connection_end: &ConnectionEnd, proof: &CommitmentProofBytes, + root: &CommitmentRoot, port_id: &PortId, channel_id: &ChannelId, - seq: &Sequence, + sequence: Sequence, ) -> Result<(), Error> { match self { Self::Tendermint(client) => { @@ -675,12 +750,15 @@ impl ClientDef for AnyClient { .ok_or_else(|| Error::client_args_type_mismatch(ClientType::Tendermint))?; client.verify_packet_receipt_absence( + ctx, client_state, height, + connection_end, proof, + root, port_id, channel_id, - seq, + sequence, ) } Self::Grandpa(client) => { @@ -690,12 +768,15 @@ impl ClientDef for AnyClient { .ok_or_else(|| Error::client_args_type_mismatch(ClientType::Grandpa))?; client.verify_packet_receipt_absence( + ctx, client_state, height, + connection_end, proof, + root, port_id, channel_id, - seq, + sequence, ) } @@ -707,12 +788,15 @@ impl ClientDef for AnyClient { .ok_or_else(|| Error::client_args_type_mismatch(ClientType::Mock))?; client.verify_packet_receipt_absence( + ctx, client_state, height, + connection_end, proof, + root, port_id, channel_id, - seq, + sequence, ) } } diff --git a/modules/src/ics02_client/client_state.rs b/modules/src/core/ics02_client/client_state.rs similarity index 70% rename from modules/src/ics02_client/client_state.rs rename to modules/src/core/ics02_client/client_state.rs index cd2734e18..c1b9a669e 100644 --- a/modules/src/ics02_client/client_state.rs +++ b/modules/src/core/ics02_client/client_state.rs @@ -1,5 +1,3 @@ -use crate::prelude::*; -use core::convert::{TryFrom, TryInto}; use core::marker::{Send, Sync}; use core::time::Duration; @@ -9,15 +7,16 @@ use tendermint_proto::Protobuf; use ibc_proto::ibc::core::client::v1::IdentifiedClientState; -use crate::ics02_client::client_type::ClientType; -use crate::ics02_client::error::Error; -use crate::ics02_client::trust_threshold::TrustThreshold; -use crate::ics07_tendermint::client_state; -use crate::ics10_grandpa; -use crate::ics24_host::error::ValidationError; -use crate::ics24_host::identifier::{ChainId, ClientId}; +use crate::clients::ics10_grandpa; +use crate::clients::ics07_tendermint::client_state; +use crate::core::ics02_client::client_type::ClientType; +use crate::core::ics02_client::error::Error; +use crate::core::ics02_client::trust_threshold::TrustThreshold; +use crate::core::ics24_host::error::ValidationError; +use crate::core::ics24_host::identifier::{ChainId, ClientId}; #[cfg(any(test, feature = "mocks"))] use crate::mock::client_state::MockClientState; +use crate::prelude::*; use crate::Height; pub const TENDERMINT_CLIENT_STATE_TYPE_URL: &str = "/ibc.lightclients.tendermint.v1.ClientState"; @@ -26,6 +25,9 @@ pub const GRANDPA_CLIENT_STATE_TYPE_URL: &str = "/ibc.lightclients.grandpa.v1.Cl pub const MOCK_CLIENT_STATE_TYPE_URL: &str = "/ibc.mock.ClientState"; pub trait ClientState: Clone + core::fmt::Debug + Send + Sync { + /// Client-specific options for upgrading the client + type UpgradeOptions; + /// Return the chain identifier which this client is serving (i.e., the client is verifying /// consensus states from this chain). fn chain_id(&self) -> ChainId; @@ -37,12 +39,49 @@ pub trait ClientState: Clone + core::fmt::Debug + Send + Sync { fn latest_height(&self) -> Height; /// Freeze status of the client - fn is_frozen(&self) -> bool; + fn is_frozen(&self) -> bool { + self.frozen_height().is_some() + } + + /// Frozen height of the client + fn frozen_height(&self) -> Option; + + /// Helper function to verify the upgrade client procedure. + /// Resets all fields except the blockchain-specific ones, + /// and updates the given fields. + fn upgrade( + self, + upgrade_height: Height, + upgrade_options: Self::UpgradeOptions, + chain_id: ChainId, + ) -> Self; /// Wrap into an `AnyClientState` fn wrap_any(self) -> AnyClientState; } +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(tag = "type")] +pub enum AnyUpgradeOptions { + Tendermint(client_state::UpgradeOptions), + + #[cfg(any(test, feature = "mocks"))] + Mock(()), +} + +impl AnyUpgradeOptions { + fn into_tendermint(self) -> client_state::UpgradeOptions { + match self { + Self::Tendermint(options) => options, + + #[cfg(any(test, feature = "mocks"))] + Self::Mock(_) => { + panic!("cannot downcast AnyUpgradeOptions::Mock to Tendermint::UpgradeOptions") + } + } + } +} + #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(tag = "type")] pub enum AnyClientState { @@ -64,6 +103,16 @@ impl AnyClientState { } } + pub fn frozen_height(&self) -> Option { + match self { + Self::Tendermint(tm_state) => tm_state.frozen_height(), + Self::Grandpa(gp_state) => gp_state.frozen_height(), + + #[cfg(any(test, feature = "mocks"))] + Self::Mock(mock_state) => mock_state.frozen_height(), + } + } + pub fn trust_threshold(&self) -> Option { match self { AnyClientState::Tendermint(state) => Some(state.trust_level), @@ -74,6 +123,16 @@ impl AnyClientState { } } + pub fn max_clock_drift(&self) -> Duration { + match self { + AnyClientState::Tendermint(state) => state.max_clock_drift, + AnyClientState::Grandpa(state) => Duration::new(0, 0), + + #[cfg(any(test, feature = "mocks"))] + AnyClientState::Mock(_) => Duration::new(0, 0), + } + } + pub fn client_type(&self) -> ClientType { match self { Self::Tendermint(state) => state.client_type(), @@ -120,7 +179,7 @@ impl TryFrom for AnyClientState { )), GRANDPA_CLIENT_STATE_TYPE_URL => Ok(AnyClientState::Grandpa( - crate::ics10_grandpa::client_state::ClientState::decode_vec(&raw.value) + crate::clients::ics10_grandpa::client_state::ClientState::decode_vec(&raw.value) .map_err(Error::decode_raw_client_state)?, )), @@ -163,6 +222,8 @@ impl From for Any { } impl ClientState for AnyClientState { + type UpgradeOptions = AnyUpgradeOptions; + fn chain_id(&self) -> ChainId { match self { AnyClientState::Tendermint(tm_state) => tm_state.chain_id(), @@ -181,13 +242,26 @@ impl ClientState for AnyClientState { self.latest_height() } - fn is_frozen(&self) -> bool { + fn frozen_height(&self) -> Option { + self.frozen_height() + } + + fn upgrade( + self, + upgrade_height: Height, + upgrade_options: Self::UpgradeOptions, + chain_id: ChainId, + ) -> Self { match self { - AnyClientState::Tendermint(tm_state) => tm_state.is_frozen(), - AnyClientState::Grandpa(tm_state) => tm_state.is_frozen(), + AnyClientState::Tendermint(tm_state) => tm_state + .upgrade(upgrade_height, upgrade_options.into_tendermint(), chain_id) + .wrap_any(), + AnyClientState::Grandpa(gp_state) => todo!(), #[cfg(any(test, feature = "mocks"))] - AnyClientState::Mock(mock_state) => mock_state.is_frozen(), + AnyClientState::Mock(mock_state) => { + mock_state.upgrade(upgrade_height, (), chain_id).wrap_any() + } } } @@ -241,14 +315,13 @@ impl From for IdentifiedClientState { #[cfg(test)] mod tests { - use core::convert::TryFrom; - use test_env_log::test; use prost_types::Any; + use test_log::test; - use crate::ics02_client::client_state::AnyClientState; - use crate::ics07_tendermint::client_state::test_util::get_dummy_tendermint_client_state; - use crate::ics07_tendermint::header::test_util::get_dummy_tendermint_header; + use crate::clients::ics07_tendermint::client_state::test_util::get_dummy_tendermint_client_state; + use crate::clients::ics07_tendermint::header::test_util::get_dummy_tendermint_header; + use crate::core::ics02_client::client_state::AnyClientState; #[test] fn any_client_state_serialization() { diff --git a/modules/src/ics02_client/client_type.rs b/modules/src/core/ics02_client/client_type.rs similarity index 97% rename from modules/src/ics02_client/client_type.rs rename to modules/src/core/ics02_client/client_type.rs index 6edba1974..7218ed186 100644 --- a/modules/src/ics02_client/client_type.rs +++ b/modules/src/core/ics02_client/client_type.rs @@ -58,10 +58,10 @@ impl core::str::FromStr for ClientType { #[cfg(test)] mod tests { use core::str::FromStr; - use test_env_log::test; + use test_log::test; use super::ClientType; - use crate::ics02_client::error::{Error, ErrorDetail}; + use crate::core::ics02_client::error::{Error, ErrorDetail}; #[test] fn parse_tendermint_client_type() { diff --git a/modules/src/core/ics02_client/context.rs b/modules/src/core/ics02_client/context.rs new file mode 100644 index 000000000..508f8d9c7 --- /dev/null +++ b/modules/src/core/ics02_client/context.rs @@ -0,0 +1,194 @@ +//! ICS2 (client) context. The two traits `ClientReader` and `ClientKeeper` define the interface +//! that any host chain must implement to be able to process any `ClientMsg`. See +//! "ADR 003: IBC protocol implementation" for more details. + +use crate::core::ics02_client::client_consensus::AnyConsensusState; +use crate::core::ics02_client::client_state::AnyClientState; +use crate::core::ics02_client::client_type::ClientType; +use crate::core::ics02_client::error::{Error, ErrorDetail}; +use crate::core::ics02_client::handler::ClientResult::{self, Create, Update, Upgrade, Misbehaviour}; +use crate::core::ics24_host::identifier::ClientId; +use crate::timestamp::Timestamp; +use crate::Height; + +/// Defines the read-only part of ICS2 (client functions) context. +pub trait ClientReader { + fn client_type(&self, client_id: &ClientId) -> Result; + fn client_state(&self, client_id: &ClientId) -> Result; + + /// Retrieve the consensus state for the given client ID at the specified + /// height. + /// + /// Returns an error if no such state exists. + fn consensus_state( + &self, + client_id: &ClientId, + height: Height, + ) -> Result; + + /// Similar to `consensus_state`, attempt to retrieve the consensus state, + /// but return `None` if no state exists at the given height. + fn maybe_consensus_state( + &self, + client_id: &ClientId, + height: Height, + ) -> Result, Error> { + match self.consensus_state(client_id, height) { + Ok(cs) => Ok(Some(cs)), + Err(e) => match e.detail() { + ErrorDetail::ConsensusStateNotFound(_) => Ok(None), + _ => Err(e), + }, + } + } + + /// Search for the lowest consensus state higher than `height`. + fn next_consensus_state( + &self, + client_id: &ClientId, + height: Height, + ) -> Result, Error>; + + /// Search for the highest consensus state lower than `height`. + fn prev_consensus_state( + &self, + client_id: &ClientId, + height: Height, + ) -> Result, Error>; + + /// Returns the current height of the local chain. + fn host_height(&self) -> Height; + + /// Returns the current timestamp of the local chain. + fn host_timestamp(&self) -> Timestamp { + let pending_consensus_state = self + .pending_host_consensus_state() + .expect("host must have pending consensus state"); + pending_consensus_state.timestamp() + } + + /// Returns the `ConsensusState` of the host (local) chain at a specific height. + fn host_consensus_state(&self, height: Height) -> Result; + + /// Returns the pending `ConsensusState` of the host (local) chain. + fn pending_host_consensus_state(&self) -> Result; + + /// Returns a natural number, counting how many clients have been created thus far. + /// The value of this counter should increase only via method `ClientKeeper::increase_client_counter`. + fn client_counter(&self) -> Result; +} + +/// Defines the write-only part of ICS2 (client functions) context. +pub trait ClientKeeper { + fn store_client_result(&mut self, handler_res: ClientResult) -> Result<(), Error> { + match handler_res { + Create(res) => { + let client_id = res.client_id.clone(); + + self.store_client_type(client_id.clone(), res.client_type)?; + self.store_client_state(client_id.clone(), res.client_state.clone())?; + self.store_consensus_state( + client_id, + res.client_state.latest_height(), + res.consensus_state, + )?; + self.increase_client_counter(); + self.store_update_time( + res.client_id.clone(), + res.client_state.latest_height(), + res.processed_time, + )?; + self.store_update_height( + res.client_id, + res.client_state.latest_height(), + res.processed_height, + )?; + Ok(()) + } + Update(res) => { + self.store_client_state(res.client_id.clone(), res.client_state.clone())?; + self.store_consensus_state( + res.client_id.clone(), + res.client_state.latest_height(), + res.consensus_state, + )?; + self.store_update_time( + res.client_id.clone(), + res.client_state.latest_height(), + res.processed_time, + )?; + self.store_update_height( + res.client_id, + res.client_state.latest_height(), + res.processed_height, + )?; + Ok(()) + } + Upgrade(res) => { + self.store_client_state(res.client_id.clone(), res.client_state.clone())?; + self.store_consensus_state( + res.client_id.clone(), + res.client_state.latest_height(), + res.consensus_state, + )?; + Ok(()) + } + Misbehaviour(res) => { + self.store_client_state(res.client_id.clone(), res.client_state.clone())?; + self.store_consensus_state( + res.client_id.clone(), + res.client_state.latest_height(), + res.consensus_state, + )?; + Ok(()) + } + } + } + + /// Called upon successful client creation + fn store_client_type( + &mut self, + client_id: ClientId, + client_type: ClientType, + ) -> Result<(), Error>; + + /// Called upon successful client creation and update + fn store_client_state( + &mut self, + client_id: ClientId, + client_state: AnyClientState, + ) -> Result<(), Error>; + + /// Called upon successful client creation and update + fn store_consensus_state( + &mut self, + client_id: ClientId, + height: Height, + consensus_state: AnyConsensusState, + ) -> Result<(), Error>; + + /// Called upon client creation. + /// Increases the counter which keeps track of how many clients have been created. + /// Should never fail. + fn increase_client_counter(&mut self); + + /// Called upon successful client update. + /// Implementations are expected to use this to record the specified time as the time at which + /// this update (or header) was processed. + fn store_update_time( + &mut self, + client_id: ClientId, + height: Height, + timestamp: Timestamp, + ) -> Result<(), Error>; + + /// Called upon successful client update. + /// Implementations are expected to use this to record the specified height as the height at + /// at which this update (or header) was processed. + fn store_update_height( + &mut self, + client_id: ClientId, + height: Height, + host_height: Height, + ) -> Result<(), Error>; +} diff --git a/modules/src/ics02_client/error.rs b/modules/src/core/ics02_client/error.rs similarity index 76% rename from modules/src/ics02_client/error.rs rename to modules/src/core/ics02_client/error.rs index 2bd988c63..3364de319 100644 --- a/modules/src/ics02_client/error.rs +++ b/modules/src/core/ics02_client/error.rs @@ -1,17 +1,21 @@ use crate::prelude::*; -use core::num::TryFromIntError; - use flex_error::{define_error, TraceError}; -use crate::ics02_client::client_type::ClientType; -use crate::ics07_tendermint::error::Error as Ics07Error; -use crate::ics10_grandpa::error::Error as Ics10Error; -use crate::ics23_commitment::error::Error as Ics23Error; -use crate::ics24_host::error::ValidationError; -use crate::ics24_host::identifier::ClientId; + +use crate::clients::ics10_grandpa::error::Error as Ics10Error; +use crate::clients::ics07_tendermint::error::Error as Ics07Error; +use crate::core::ics02_client::client_type::ClientType; +use crate::core::ics02_client::height::HeightError; +use crate::core::ics23_commitment::error::Error as Ics23Error; +use crate::core::ics24_host::error::ValidationError; +use crate::core::ics24_host::identifier::ClientId; +use crate::timestamp::Timestamp; use crate::Height; +use tendermint::Error as TendermintError; +use tendermint_proto::Error as TendermintProtoError; + define_error! { #[derive(Debug, PartialEq, Eq)] Error { @@ -59,7 +63,7 @@ define_error! { FailedTrustThresholdConversion { numerator: u64, denominator: u64 } - [ tendermint::Error ] + [ TendermintError ] | e | { format_args!("failed to build Tendermint domain type trust threshold from fraction: {}/{}", e.numerator, e.denominator) }, UnknownClientStateType @@ -70,7 +74,6 @@ define_error! { | _ | { "the client state was not found" }, EmptyPrefix - { source: crate::ics23_commitment::merkle::EmptyPrefixError } | _ | { "empty prefix" }, UnknownConsensusStateType @@ -81,7 +84,7 @@ define_error! { }, EmptyConsensusStateResponse - | _ | { "the client state was not found" }, + | _ | { "the client consensus state was not found" }, UnknownHeaderType { header_type: String } @@ -106,14 +109,14 @@ define_error! { }, DecodeRawClientState - [ TraceError ] + [ TraceError ] | _ | { "error decoding raw client state" }, MissingRawClientState | _ | { "missing raw client state" }, InvalidRawConsensusState - [ TraceError ] + [ TraceError ] | _ | { "invalid raw client consensus state" }, MissingRawConsensusState @@ -135,14 +138,14 @@ define_error! { | _ | { "invalid client identifier" }, InvalidRawHeader - [ TraceError ] + [ TraceError ] | _ | { "invalid raw header" }, MissingRawHeader | _ | { "missing raw header" }, DecodeRawMisbehaviour - [ TraceError ] + [ TraceError ] | _ | { "invalid raw misbehaviour" }, InvalidRawMisbehaviour @@ -152,6 +155,11 @@ define_error! { MissingRawMisbehaviour | _ | { "missing raw misbehaviour" }, + InvalidStringAsHeight + { value: String } + [ HeightError ] + | e | { format_args!("String {0} cannnot be converted to height", e.value) }, + InvalidHeightResult | _ | { "height cannot end up zero or negative" }, @@ -166,6 +174,10 @@ define_error! { [ Ics23Error ] | _ | { "invalid proof for the upgraded consensus state" }, + InvalidCommitmentProof + [ Ics23Error ] + | _ | { "invalid commitment proof bytes" }, + Tendermint [ Ics07Error ] | _ | { "tendermint error" }, @@ -175,7 +187,7 @@ define_error! { | _ | { "grandpa error" }, InvalidPacketTimestamp - [ TraceError ] + [ crate::timestamp::ParseTimestampError ] | _ | { "invalid packet timeout timestamp value" }, ClientArgsTypeMismatch @@ -185,6 +197,12 @@ define_error! { e.client_type) }, + InsufficientVotingPower + { reason: String } + | e | { + format_args!("Insufficient overlap {}", e.reason) + }, + RawClientAndConsensusStateTypesMismatch { state_type: ClientType, @@ -211,10 +229,11 @@ define_error! { client_height: Height, } | e | { - format_args!("upgraded client height {0} must be at greater than current client height {1}", + format_args!("upgraded client height {} must be at greater than current client height {}", e.upgraded_height, e.client_height) }, + CantDecodeMmrProof | _ | { "cant decode Mmr Proof" }, @@ -276,6 +295,39 @@ define_error! { } | e | { format!("invalid Mmr Root height, it's not can verify header, header height ({0})> mmr root height ({1})", e.header_height, e.mmr_root_height) + }, + + InvalidConsensusStateTimestamp + { + time1: Timestamp, + time2: Timestamp, } + | e | { + format_args!("timestamp is invalid or missing, timestamp={0}, now={1}", e.time1, e.time2) + }, + + HeaderNotWithinTrustPeriod + { + latest_time:Timestamp, + update_time: Timestamp, + } + | e | { + format_args!("header not withing trusting period: expires_at={0} now={1}", e.latest_time, e.update_time) + }, + + TendermintHandlerError + [ Ics07Error ] + | _ | { format_args!("Tendermint-specific handler error") }, + + MissingLocalConsensusState + { height: Height } + | e | { format_args!("the local consensus state could not be retrieved for height {}", e.height) }, + + } +} + +impl From for Error { + fn from(e: Ics07Error) -> Error { + Error::tendermint_handler_error(e) } } diff --git a/modules/src/core/ics02_client/events.rs b/modules/src/core/ics02_client/events.rs new file mode 100644 index 000000000..75ff3954f --- /dev/null +++ b/modules/src/core/ics02_client/events.rs @@ -0,0 +1,403 @@ +//! Types for the IBC events emitted from Tendermint Websocket by the client module. + +use serde_derive::{Deserialize, Serialize}; +use tendermint::abci::tag::Tag; +use tendermint::abci::Event as AbciEvent; + +use crate::core::ics02_client::client_type::ClientType; +use crate::core::ics02_client::error::Error; +use crate::core::ics02_client::header::AnyHeader; +use crate::core::ics02_client::height::Height; +use crate::core::ics24_host::identifier::ClientId; +use crate::events::{IbcEvent, IbcEventType}; +use crate::prelude::*; + +/// The content of the `key` field for the attribute containing the height. +const HEIGHT_ATTRIBUTE_KEY: &str = "height"; + +/// The content of the `key` field for the attribute containing the client identifier. +const CLIENT_ID_ATTRIBUTE_KEY: &str = "client_id"; + +/// The content of the `key` field for the attribute containing the client type. +const CLIENT_TYPE_ATTRIBUTE_KEY: &str = "client_type"; + +/// The content of the `key` field for the attribute containing the height. +const CONSENSUS_HEIGHT_ATTRIBUTE_KEY: &str = "consensus_height"; + +/// The content of the `key` field for the header in update client event. +const HEADER_ATTRIBUTE_KEY: &str = "header"; + +pub fn try_from_tx(event: &AbciEvent) -> Option { + match event.type_str.parse() { + Ok(IbcEventType::CreateClient) => extract_attributes_from_tx(event) + .map(CreateClient) + .map(IbcEvent::CreateClient) + .ok(), + Ok(IbcEventType::UpdateClient) => match extract_attributes_from_tx(event) { + Ok(attributes) => Some(IbcEvent::UpdateClient(UpdateClient { + common: attributes, + header: extract_header_from_tx(event).ok(), + })), + Err(_) => None, + }, + Ok(IbcEventType::ClientMisbehaviour) => extract_attributes_from_tx(event) + .map(ClientMisbehaviour) + .map(IbcEvent::ClientMisbehaviour) + .ok(), + Ok(IbcEventType::UpgradeClient) => extract_attributes_from_tx(event) + .map(UpgradeClient) + .map(IbcEvent::UpgradeClient) + .ok(), + _ => None, + } +} + +fn extract_attributes_from_tx(event: &AbciEvent) -> Result { + let mut attr = Attributes::default(); + + for tag in &event.attributes { + let key = tag.key.as_ref(); + let value = tag.value.as_ref(); + match key { + HEIGHT_ATTRIBUTE_KEY => { + attr.height = value + .parse() + .map_err(|e| Error::invalid_string_as_height(value.to_string(), e))? + } + CLIENT_ID_ATTRIBUTE_KEY => { + attr.client_id = value.parse().map_err(Error::invalid_client_identifier)? + } + CLIENT_TYPE_ATTRIBUTE_KEY => { + attr.client_type = value + .parse() + .map_err(|_| Error::unknown_client_type(value.to_string()))? + } + CONSENSUS_HEIGHT_ATTRIBUTE_KEY => { + attr.consensus_height = value + .parse() + .map_err(|e| Error::invalid_string_as_height(value.to_string(), e))? + } + _ => {} + } + } + + Ok(attr) +} + +pub fn extract_header_from_tx(event: &AbciEvent) -> Result { + for tag in &event.attributes { + let key = tag.key.as_ref(); + let value = tag.value.as_ref(); + if key == HEADER_ATTRIBUTE_KEY { + return AnyHeader::decode_from_string(value); + } + } + Err(Error::missing_raw_header()) +} + +/// NewBlock event signals the committing & execution of a new block. +// TODO - find a better place for NewBlock +#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq)] +pub struct NewBlock { + pub height: Height, +} + +impl NewBlock { + pub fn new(h: Height) -> NewBlock { + NewBlock { height: h } + } + pub fn set_height(&mut self, height: Height) { + self.height = height; + } + pub fn height(&self) -> Height { + self.height + } +} + +impl From for IbcEvent { + fn from(v: NewBlock) -> Self { + IbcEvent::NewBlock(v) + } +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Attributes { + pub height: Height, + pub client_id: ClientId, + pub client_type: ClientType, + pub consensus_height: Height, +} + +impl Default for Attributes { + fn default() -> Self { + Attributes { + height: Height::default(), + client_id: Default::default(), + client_type: ClientType::Tendermint, + consensus_height: Height::default(), + } + } +} + +/// Convert attributes to Tendermint ABCI tags +/// +/// # Note +/// The parsing of `Key`s and `Value`s never fails, because the +/// `FromStr` instance of `tendermint::abci::tag::{Key, Value}` +/// is infallible, even if it is not represented in the error type. +/// Once tendermint-rs improves the API of the `Key` and `Value` types, +/// we will be able to remove the `.parse().unwrap()` calls. +impl From for Vec { + fn from(a: Attributes) -> Self { + let height = Tag { + key: HEIGHT_ATTRIBUTE_KEY.parse().unwrap(), + value: a.height.to_string().parse().unwrap(), + }; + let client_id = Tag { + key: CLIENT_ID_ATTRIBUTE_KEY.parse().unwrap(), + value: a.client_id.to_string().parse().unwrap(), + }; + let client_type = Tag { + key: CLIENT_TYPE_ATTRIBUTE_KEY.parse().unwrap(), + value: a.client_type.as_str().parse().unwrap(), + }; + let consensus_height = Tag { + key: CONSENSUS_HEIGHT_ATTRIBUTE_KEY.parse().unwrap(), + value: a.height.to_string().parse().unwrap(), + }; + vec![height, client_id, client_type, consensus_height] + } +} + +impl core::fmt::Display for Attributes { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + write!( + f, + "h: {}, cs_h: {}({})", + self.height, self.client_id, self.consensus_height + ) + } +} + +/// CreateClient event signals the creation of a new on-chain client (IBC client). +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +pub struct CreateClient(pub Attributes); + +impl CreateClient { + pub fn client_id(&self) -> &ClientId { + &self.0.client_id + } + pub fn height(&self) -> Height { + self.0.height + } + pub fn set_height(&mut self, height: Height) { + self.0.height = height; + } +} + +impl From for CreateClient { + fn from(attrs: Attributes) -> Self { + CreateClient(attrs) + } +} + +impl From for IbcEvent { + fn from(v: CreateClient) -> Self { + IbcEvent::CreateClient(v) + } +} + +impl From for AbciEvent { + fn from(v: CreateClient) -> Self { + let attributes = Vec::::from(v.0); + AbciEvent { + type_str: IbcEventType::CreateClient.as_str().to_string(), + attributes, + } + } +} + +impl core::fmt::Display for CreateClient { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + write!(f, "{}", self.0) + } +} + +/// UpdateClient event signals a recent update of an on-chain client (IBC Client). +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +pub struct UpdateClient { + pub common: Attributes, + pub header: Option, +} + +impl UpdateClient { + pub fn client_id(&self) -> &ClientId { + &self.common.client_id + } + pub fn client_type(&self) -> ClientType { + self.common.client_type + } + + pub fn height(&self) -> Height { + self.common.height + } + + pub fn set_height(&mut self, height: Height) { + self.common.height = height; + } + + pub fn consensus_height(&self) -> Height { + self.common.consensus_height + } +} + +impl From for UpdateClient { + fn from(attrs: Attributes) -> Self { + UpdateClient { + common: attrs, + header: None, + } + } +} + +impl From for IbcEvent { + fn from(v: UpdateClient) -> Self { + IbcEvent::UpdateClient(v) + } +} + +impl From for AbciEvent { + fn from(v: UpdateClient) -> Self { + let mut attributes = Vec::::from(v.common); + if let Some(h) = v.header { + let header = Tag { + key: HEADER_ATTRIBUTE_KEY.parse().unwrap(), + value: h.encode_to_string().parse().unwrap(), + }; + attributes.push(header); + } + AbciEvent { + type_str: IbcEventType::UpdateClient.as_str().to_string(), + attributes, + } + } +} + +impl core::fmt::Display for UpdateClient { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + write!(f, "{}", self.common) + } +} + +/// ClientMisbehaviour event signals the update of an on-chain client (IBC Client) with evidence of +/// misbehaviour. +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +pub struct ClientMisbehaviour(pub Attributes); + +impl ClientMisbehaviour { + pub fn client_id(&self) -> &ClientId { + &self.0.client_id + } + pub fn height(&self) -> Height { + self.0.height + } + pub fn set_height(&mut self, height: Height) { + self.0.height = height; + } +} + +impl From for ClientMisbehaviour { + fn from(attrs: Attributes) -> Self { + ClientMisbehaviour(attrs) + } +} + +impl From for IbcEvent { + fn from(v: ClientMisbehaviour) -> Self { + IbcEvent::ClientMisbehaviour(v) + } +} + +impl From for AbciEvent { + fn from(v: ClientMisbehaviour) -> Self { + let attributes = Vec::::from(v.0); + AbciEvent { + type_str: IbcEventType::ClientMisbehaviour.as_str().to_string(), + attributes, + } + } +} + +/// Signals a recent upgrade of an on-chain client (IBC Client). +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)] +pub struct UpgradeClient(pub Attributes); + +impl UpgradeClient { + pub fn set_height(&mut self, height: Height) { + self.0.height = height; + } + pub fn client_id(&self) -> &ClientId { + &self.0.client_id + } +} + +impl From for UpgradeClient { + fn from(attrs: Attributes) -> Self { + UpgradeClient(attrs) + } +} + +impl From for AbciEvent { + fn from(v: UpgradeClient) -> Self { + let attributes = Vec::::from(v.0); + AbciEvent { + type_str: IbcEventType::UpgradeClient.as_str().to_string(), + attributes, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::core::ics02_client::header::Header; + use crate::mock::header::MockHeader; + + #[test] + fn client_event_to_abci_event() { + let height = Height::new(1, 1); + let attributes = Attributes { + height, + client_id: "test_client".parse().unwrap(), + client_type: ClientType::Tendermint, + consensus_height: height, + }; + let mut abci_events = vec![]; + let create_client = CreateClient::from(attributes.clone()); + abci_events.push(AbciEvent::from(create_client.clone())); + let client_misbehaviour = ClientMisbehaviour::from(attributes.clone()); + abci_events.push(AbciEvent::from(client_misbehaviour.clone())); + let upgrade_client = UpgradeClient::from(attributes.clone()); + abci_events.push(AbciEvent::from(upgrade_client.clone())); + let mut update_client = UpdateClient::from(attributes); + let header = MockHeader::new(height).wrap_any(); + update_client.header = Some(header); + abci_events.push(AbciEvent::from(update_client.clone())); + + for event in abci_events { + match try_from_tx(&event) { + Some(e) => match e { + IbcEvent::CreateClient(e) => assert_eq!(e.0, create_client.0), + IbcEvent::ClientMisbehaviour(e) => assert_eq!(e.0, client_misbehaviour.0), + IbcEvent::UpgradeClient(e) => assert_eq!(e.0, upgrade_client.0), + IbcEvent::UpdateClient(e) => { + assert_eq!(e.common, update_client.common); + assert_eq!(e.header, update_client.header); + } + _ => panic!("unexpected event type"), + }, + None => panic!("converted event was wrong"), + } + } + } +} diff --git a/modules/src/ics02_client/handler.rs b/modules/src/core/ics02_client/handler.rs similarity index 85% rename from modules/src/ics02_client/handler.rs rename to modules/src/core/ics02_client/handler.rs index dd74f0d30..b9a48d08a 100644 --- a/modules/src/ics02_client/handler.rs +++ b/modules/src/core/ics02_client/handler.rs @@ -1,9 +1,9 @@ //! This module implements the processing logic for ICS2 (client abstractions and functions) msgs. +use crate::core::ics02_client::context::ClientReader; +use crate::core::ics02_client::error::Error; +use crate::core::ics02_client::msgs::ClientMsg; use crate::handler::HandlerOutput; -use crate::ics02_client::context::ClientReader; -use crate::ics02_client::error::Error; -use crate::ics02_client::msgs::ClientMsg; pub mod create_client; pub mod misbehavior; @@ -28,6 +28,5 @@ where ClientMsg::UpdateClient(msg) => update_client::process(ctx, msg), ClientMsg::UpgradeClient(msg) => upgrade_client::process(ctx, msg), ClientMsg::Misbehaviour(msg) => misbehavior::process(ctx, msg), - _ => unimplemented!(), } } diff --git a/modules/src/ics02_client/handler/create_client.rs b/modules/src/core/ics02_client/handler/create_client.rs similarity index 75% rename from modules/src/ics02_client/handler/create_client.rs rename to modules/src/core/ics02_client/handler/create_client.rs index 491ebf7aa..f239b327b 100644 --- a/modules/src/ics02_client/handler/create_client.rs +++ b/modules/src/core/ics02_client/handler/create_client.rs @@ -1,17 +1,21 @@ //! Protocol logic specific to processing ICS2 messages of type `MsgCreateAnyClient`. + use crate::prelude::*; +use crate::core::ics02_client::client_consensus::AnyConsensusState; +use crate::core::ics02_client::client_state::AnyClientState; +use crate::core::ics02_client::client_type::ClientType; +use crate::core::ics02_client::context::ClientReader; +use crate::core::ics02_client::error::Error; +use crate::core::ics02_client::events::Attributes; +use crate::core::ics02_client::handler::ClientResult; +use crate::core::ics02_client::height::Height; +use crate::core::ics02_client::msgs::create_client::MsgCreateAnyClient; +use crate::core::ics24_host::identifier::ClientId; use crate::events::IbcEvent; use crate::handler::{HandlerOutput, HandlerResult}; -use crate::ics02_client::client_consensus::AnyConsensusState; -use crate::ics02_client::client_state::AnyClientState; -use crate::ics02_client::client_type::ClientType; -use crate::ics02_client::context::ClientReader; -use crate::ics02_client::error::Error; -use crate::ics02_client::events::Attributes; -use crate::ics02_client::handler::ClientResult; -use crate::ics02_client::msgs::create_client::MsgCreateAnyClient; -use crate::ics24_host::identifier::ClientId; +use crate::timestamp::Timestamp; + /// The result following the successful processing of a `MsgCreateAnyClient` message. Preferably /// this data type should be used with a qualified name `create_client::Result` to avoid ambiguity. #[derive(Clone, Debug, PartialEq, Eq)] @@ -20,6 +24,8 @@ pub struct Result { pub client_type: ClientType, pub client_state: AnyClientState, pub consensus_state: AnyConsensusState, + pub processed_time: Timestamp, + pub processed_height: Height, } pub fn process( @@ -30,8 +36,8 @@ pub fn process( // Construct this client's identifier let id_counter = ctx.client_counter()?; - let client_id = ClientId::new(msg.client_state().client_type(), id_counter).map_err(|e| { - Error::client_identifier_constructor(msg.client_state().client_type(), id_counter, e) + let client_id = ClientId::new(msg.client_state.client_type(), id_counter).map_err(|e| { + Error::client_identifier_constructor(msg.client_state.client_type(), id_counter, e) })?; let client_type = msg.client_state.client_type(); @@ -42,9 +48,11 @@ pub fn process( let result = ClientResult::Create(Result { client_id: client_id.clone(), - client_type: msg.client_state().client_type(), - client_state: msg.client_state(), - consensus_state: msg.consensus_state(), + client_type: msg.client_state.client_type(), + client_state: msg.client_state.clone(), + consensus_state: msg.consensus_state, + processed_time: ctx.host_timestamp(), + processed_height: ctx.host_height(), }); tracing::info!("in ics02_client : [create_client] >> result: {:?}", result); @@ -63,22 +71,25 @@ pub fn process( #[cfg(test)] mod tests { use crate::prelude::*; - use core::convert::TryInto; + use core::time::Duration; - use test_env_log::test; + use test_log::test; + use crate::clients::ics07_tendermint::client_state::{ + AllowUpdate, ClientState as TendermintClientState, + }; + use crate::clients::ics07_tendermint::header::test_util::get_dummy_tendermint_header; + use crate::core::ics02_client::client_consensus::AnyConsensusState; + use crate::core::ics02_client::client_state::ClientState; + use crate::core::ics02_client::client_type::ClientType; + use crate::core::ics02_client::handler::{dispatch, ClientResult}; + use crate::core::ics02_client::msgs::create_client::MsgCreateAnyClient; + use crate::core::ics02_client::msgs::ClientMsg; + use crate::core::ics02_client::trust_threshold::TrustThreshold; + use crate::core::ics23_commitment::specs::ProofSpecs; + use crate::core::ics24_host::identifier::ClientId; use crate::events::IbcEvent; use crate::handler::HandlerOutput; - use crate::ics02_client::client_consensus::AnyConsensusState; - use crate::ics02_client::client_state::AnyClientState; - use crate::ics02_client::client_type::ClientType; - use crate::ics02_client::handler::{dispatch, ClientResult}; - use crate::ics02_client::msgs::create_client::MsgCreateAnyClient; - use crate::ics02_client::msgs::ClientMsg; - use crate::ics02_client::trust_threshold::TrustThreshold; - use crate::ics07_tendermint::client_state::{AllowUpdate, ClientState}; - use crate::ics07_tendermint::header::test_util::get_dummy_tendermint_header; - use crate::ics24_host::identifier::ClientId; use crate::mock::client_state::{MockClientState, MockConsensusState}; use crate::mock::context::MockContext; use crate::mock::header::MockHeader; @@ -92,7 +103,7 @@ mod tests { let height = Height::new(0, 42); let msg = MsgCreateAnyClient::new( - MockClientState(MockHeader::new(height)).into(), + MockClientState::new(MockHeader::new(height)).into(), MockConsensusState::new(MockHeader::new(height)).into(), signer, ) @@ -114,8 +125,8 @@ mod tests { ClientResult::Create(create_result) => { assert_eq!(create_result.client_type, ClientType::Mock); assert_eq!(create_result.client_id, expected_client_id); - assert_eq!(create_result.client_state, msg.client_state()); - assert_eq!(create_result.consensus_state, msg.consensus_state()); + assert_eq!(create_result.client_state, msg.client_state); + assert_eq!(create_result.consensus_state, msg.consensus_state); } _ => { panic!("unexpected result type: expected ClientResult::CreateResult!"); @@ -138,7 +149,7 @@ mod tests { let create_client_msgs: Vec = vec![ MsgCreateAnyClient::new( - MockClientState(MockHeader::new(Height { + MockClientState::new(MockHeader::new(Height { revision_height: 42, ..height })) @@ -152,7 +163,7 @@ mod tests { ) .unwrap(), MsgCreateAnyClient::new( - MockClientState(MockHeader::new(Height { + MockClientState::new(MockHeader::new(Height { revision_height: 42, ..height })) @@ -166,7 +177,7 @@ mod tests { ) .unwrap(), MsgCreateAnyClient::new( - MockClientState(MockHeader::new(Height { + MockClientState::new(MockHeader::new(Height { revision_height: 50, ..height })) @@ -202,10 +213,10 @@ mod tests { ); match result { ClientResult::Create(create_res) => { - assert_eq!(create_res.client_type, msg.client_state().client_type()); + assert_eq!(create_res.client_type, msg.client_state.client_type()); assert_eq!(create_res.client_id, expected_client_id); - assert_eq!(create_res.client_state, msg.client_state()); - assert_eq!(create_res.consensus_state, msg.consensus_state()); + assert_eq!(create_res.client_state, msg.client_state); + assert_eq!(create_res.consensus_state, msg.consensus_state); } _ => { panic!("expected result of type ClientResult::CreateResult"); @@ -227,20 +238,22 @@ mod tests { let tm_header = get_dummy_tendermint_header(); - let tm_client_state = AnyClientState::Tendermint(ClientState { - chain_id: tm_header.chain_id.clone().into(), - trust_level: TrustThreshold::ONE_THIRD, - trusting_period: Duration::from_secs(64000), - unbonding_period: Duration::from_secs(128000), - max_clock_drift: Duration::from_millis(3000), - latest_height: Height::new(0, u64::from(tm_header.height)), - frozen_height: Height::zero(), - allow_update: AllowUpdate { + let tm_client_state = TendermintClientState::new( + tm_header.chain_id.clone().into(), + TrustThreshold::ONE_THIRD, + Duration::from_secs(64000), + Duration::from_secs(128000), + Duration::from_millis(3000), + Height::new(0, u64::from(tm_header.height)), + ProofSpecs::default(), + vec!["".to_string()], + AllowUpdate { after_expiry: false, after_misbehaviour: false, }, - upgrade_path: vec!["".to_string()], - }); + ) + .unwrap() + .wrap_any(); let msg = MsgCreateAnyClient::new( tm_client_state, @@ -265,8 +278,8 @@ mod tests { ClientResult::Create(create_res) => { assert_eq!(create_res.client_type, ClientType::Tendermint); assert_eq!(create_res.client_id, expected_client_id); - assert_eq!(create_res.client_state, msg.client_state()); - assert_eq!(create_res.consensus_state, msg.consensus_state()); + assert_eq!(create_res.client_state, msg.client_state); + assert_eq!(create_res.consensus_state, msg.consensus_state); } _ => { panic!("expected result of type ClientResult::CreateResult"); diff --git a/modules/src/ics02_client/handler/misbehavior.rs b/modules/src/core/ics02_client/handler/misbehavior.rs similarity index 78% rename from modules/src/ics02_client/handler/misbehavior.rs rename to modules/src/core/ics02_client/handler/misbehavior.rs index 1ec0c6c92..1ba4b056c 100644 --- a/modules/src/ics02_client/handler/misbehavior.rs +++ b/modules/src/core/ics02_client/handler/misbehavior.rs @@ -2,17 +2,17 @@ use crate::events::IbcEvent; use crate::handler::{HandlerOutput, HandlerResult}; -use crate::ics02_client::client_consensus::AnyConsensusState; -use crate::ics02_client::client_def::{AnyClient, ClientDef}; -use crate::ics02_client::client_state::AnyClientState; -use crate::ics02_client::client_type::ClientType; -use crate::ics02_client::context::ClientReader; -use crate::ics02_client::error::Error; -use crate::ics02_client::events::Attributes; -use crate::ics02_client::handler::ClientResult; -use crate::ics02_client::msgs::misbehavior::MsgSubmitAnyMisbehaviour; -use crate::ics10_grandpa::client_state::ClientState; -use crate::ics24_host::identifier::ClientId; +use crate::core::ics02_client::client_consensus::AnyConsensusState; +use crate::core::ics02_client::client_def::{AnyClient, ClientDef}; +use crate::core::ics02_client::client_state::AnyClientState; +use crate::core::ics02_client::client_type::ClientType; +use crate::core::ics02_client::context::ClientReader; +use crate::core::ics02_client::error::Error; +use crate::core::ics02_client::events::Attributes; +use crate::core::ics02_client::handler::ClientResult; +use crate::core::ics02_client::msgs::misbehavior::MsgSubmitAnyMisbehaviour; +use crate::clients::ics10_grandpa::client_state::ClientState; +use crate::core::ics24_host::identifier::ClientId; /// The result following the successful processing of a `MsgCreateAnyClient` message. Preferably /// this data type should be used with a qualified name `create_client::Result` to avoid ambiguity. diff --git a/modules/src/core/ics02_client/handler/update_client.rs b/modules/src/core/ics02_client/handler/update_client.rs new file mode 100644 index 000000000..0f8c34f19 --- /dev/null +++ b/modules/src/core/ics02_client/handler/update_client.rs @@ -0,0 +1,538 @@ +//! Protocol logic specific to processing ICS2 messages of type `MsgUpdateAnyClient`. + +use tracing::debug; + +use crate::core::ics02_client::client_consensus::AnyConsensusState; +use crate::core::ics02_client::client_def::{AnyClient, ClientDef}; +use crate::core::ics02_client::client_state::{AnyClientState, ClientState}; +use crate::core::ics02_client::context::ClientReader; +use crate::core::ics02_client::error::Error; +use crate::core::ics02_client::events::Attributes; +use crate::core::ics02_client::handler::ClientResult; +use crate::core::ics02_client::header::Header; +use crate::core::ics02_client::height::Height; +use crate::core::ics02_client::msgs::update_client::MsgUpdateAnyClient; +use crate::core::ics24_host::identifier::ClientId; +use crate::events::IbcEvent; +use crate::handler::{HandlerOutput, HandlerResult}; +use crate::prelude::*; +use crate::timestamp::Timestamp; + +/// The result following the successful processing of a `MsgUpdateAnyClient` message. Preferably +/// this data type should be used with a qualified name `update_client::Result` to avoid ambiguity. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Result { + pub client_id: ClientId, + pub client_state: AnyClientState, + pub consensus_state: AnyConsensusState, + pub processed_time: Timestamp, + pub processed_height: Height, +} + +pub fn process( + ctx: &dyn ClientReader, + msg: MsgUpdateAnyClient, +) -> HandlerResult { + let mut output = HandlerOutput::builder(); + + let MsgUpdateAnyClient { + client_id, + header, + signer: _, + } = msg; + + // Read client type from the host chain store. The client should already exist. + let client_type = ctx.client_type(&client_id)?; + + let client_def = AnyClient::from_client_type(client_type); + + // Read client state from the host chain store. + let client_state = ctx.client_state(&client_id)?; + + if client_state.is_frozen() { + return Err(Error::client_frozen(client_id)); + } + + // Read consensus state from the host chain store. + let latest_consensus_state = ctx + .consensus_state(&client_id, client_state.latest_height()) + .map_err(|_| { + Error::consensus_state_not_found(client_id.clone(), client_state.latest_height()) + })?; + + debug!("latest consensus state: {:?}", latest_consensus_state); + + let now = ctx.host_timestamp(); + let duration = now + .duration_since(&latest_consensus_state.timestamp()) + .ok_or_else(|| { + Error::invalid_consensus_state_timestamp(latest_consensus_state.timestamp(), now) + })?; + + if client_state.expired(duration) { + return Err(Error::header_not_within_trust_period( + latest_consensus_state.timestamp(), + header.timestamp(), + )); + } + + // Use client_state to validate the new header against the latest consensus_state. + // This function will return the new client_state (its latest_height changed) and a + // consensus_state obtained from header. These will be later persisted by the keeper. + let (new_client_state, new_consensus_state) = client_def + .check_header_and_update_state(ctx, client_id.clone(), client_state, header) + .map_err(|e| Error::header_verification_failure(e.to_string()))?; + + let result = ClientResult::Update(Result { + client_id: client_id.clone(), + client_state: new_client_state, + consensus_state: new_consensus_state, + processed_time: ctx.host_timestamp(), + processed_height: ctx.host_height(), + }); + + let event_attributes = Attributes { + client_id, + ..Default::default() + }; + output.emit(IbcEvent::UpdateClient(event_attributes.into())); + + Ok(output.with_result(result)) +} + +#[cfg(test)] +mod tests { + use core::str::FromStr; + use test_log::test; + + use crate::core::ics02_client::client_consensus::AnyConsensusState; + use crate::core::ics02_client::client_state::{AnyClientState, ClientState}; + use crate::core::ics02_client::client_type::ClientType; + use crate::core::ics02_client::error::{Error, ErrorDetail}; + use crate::core::ics02_client::handler::dispatch; + use crate::core::ics02_client::handler::ClientResult::Update; + use crate::core::ics02_client::header::{AnyHeader, Header}; + use crate::core::ics02_client::msgs::update_client::MsgUpdateAnyClient; + use crate::core::ics02_client::msgs::ClientMsg; + use crate::core::ics24_host::identifier::{ChainId, ClientId}; + use crate::events::IbcEvent; + use crate::handler::HandlerOutput; + use crate::mock::client_state::MockClientState; + use crate::mock::context::MockContext; + use crate::mock::header::MockHeader; + use crate::mock::host::HostType; + use crate::prelude::*; + use crate::test_utils::get_dummy_account_id; + use crate::timestamp::Timestamp; + use crate::Height; + + #[test] + fn test_update_client_ok() { + let client_id = ClientId::default(); + let signer = get_dummy_account_id(); + + let timestamp = Timestamp::now(); + + let ctx = MockContext::default().with_client(&client_id, Height::new(0, 42)); + let msg = MsgUpdateAnyClient { + client_id: client_id.clone(), + header: MockHeader::new(Height::new(0, 46)) + .with_timestamp(timestamp) + .into(), + signer, + }; + + let output = dispatch(&ctx, ClientMsg::UpdateClient(msg.clone())); + + match output { + Ok(HandlerOutput { + result, + mut events, + log, + }) => { + assert_eq!(events.len(), 1); + let event = events.pop().unwrap(); + assert!( + matches!(event, IbcEvent::UpdateClient(e) if e.client_id() == &msg.client_id) + ); + assert!(log.is_empty()); + // Check the result + match result { + Update(upd_res) => { + assert_eq!(upd_res.client_id, client_id); + assert_eq!( + upd_res.client_state, + AnyClientState::Mock(MockClientState::new( + MockHeader::new(msg.header.height()).with_timestamp(timestamp) + )) + ) + } + _ => panic!("update handler result has incorrect type"), + } + } + Err(err) => { + panic!("unexpected error: {}", err); + } + } + } + + #[test] + fn test_update_nonexisting_client() { + let client_id = ClientId::from_str("mockclient1").unwrap(); + let signer = get_dummy_account_id(); + + let ctx = MockContext::default().with_client(&client_id, Height::new(0, 42)); + + let msg = MsgUpdateAnyClient { + client_id: ClientId::from_str("nonexistingclient").unwrap(), + header: MockHeader::new(Height::new(0, 46)).into(), + signer, + }; + + let output = dispatch(&ctx, ClientMsg::UpdateClient(msg.clone())); + + match output { + Err(Error(ErrorDetail::ClientNotFound(e), _)) => { + assert_eq!(e.client_id, msg.client_id); + } + _ => { + panic!("expected ClientNotFound error, instead got {:?}", output) + } + } + } + + #[test] + fn test_update_client_ok_multiple() { + let client_ids = vec![ + ClientId::from_str("mockclient1").unwrap(), + ClientId::from_str("mockclient2").unwrap(), + ClientId::from_str("mockclient3").unwrap(), + ]; + let signer = get_dummy_account_id(); + let initial_height = Height::new(0, 45); + let update_height = Height::new(0, 49); + + let mut ctx = MockContext::default(); + + for cid in &client_ids { + ctx = ctx.with_client(cid, initial_height); + } + + for cid in &client_ids { + let msg = MsgUpdateAnyClient { + client_id: cid.clone(), + header: MockHeader::new(update_height).into(), + signer: signer.clone(), + }; + + let output = dispatch(&ctx, ClientMsg::UpdateClient(msg.clone())); + + match output { + Ok(HandlerOutput { + result: _, + mut events, + log, + }) => { + assert_eq!(events.len(), 1); + let event = events.pop().unwrap(); + assert!( + matches!(event, IbcEvent::UpdateClient(e) if e.client_id() == &msg.client_id) + ); + assert!(log.is_empty()); + } + Err(err) => { + panic!("unexpected error: {}", err); + } + } + } + } + + #[test] + fn test_update_synthetic_tendermint_client_adjacent_ok() { + let client_id = ClientId::new(ClientType::Tendermint, 0).unwrap(); + let client_height = Height::new(1, 20); + let update_height = Height::new(1, 21); + + let ctx = MockContext::new( + ChainId::new("mockgaiaA".to_string(), 1), + HostType::Mock, + 5, + Height::new(1, 1), + ) + .with_client_parametrized( + &client_id, + client_height, + Some(ClientType::Tendermint), // The target host chain (B) is synthetic TM. + Some(client_height), + ); + + let ctx_b = MockContext::new( + ChainId::new("mockgaiaB".to_string(), 1), + HostType::SyntheticTendermint, + 5, + update_height, + ); + + let signer = get_dummy_account_id(); + + let block_ref = ctx_b.host_block(update_height); + let mut latest_header: AnyHeader = block_ref.cloned().map(Into::into).unwrap(); + + latest_header = match latest_header { + AnyHeader::Tendermint(mut theader) => { + theader.trusted_height = client_height; + AnyHeader::Tendermint(theader) + } + AnyHeader::Mock(m) => AnyHeader::Mock(m), + }; + + let msg = MsgUpdateAnyClient { + client_id: client_id.clone(), + header: latest_header, + signer, + }; + + let output = dispatch(&ctx, ClientMsg::UpdateClient(msg.clone())); + + match output { + Ok(HandlerOutput { + result, + mut events, + log, + }) => { + assert_eq!(events.len(), 1); + let event = events.pop().unwrap(); + assert!( + matches!(event, IbcEvent::UpdateClient(e) if e.client_id() == &msg.client_id) + ); + assert!(log.is_empty()); + // Check the result + match result { + Update(upd_res) => { + assert_eq!(upd_res.client_id, client_id); + assert!(!upd_res.client_state.is_frozen()); + assert_eq!(upd_res.client_state.latest_height(), msg.header.height(),) + } + _ => panic!("update handler result has incorrect type"), + } + } + Err(err) => { + panic!("unexpected error: {}", err); + } + } + } + + #[test] + fn test_update_synthetic_tendermint_client_non_adjacent_ok() { + let client_id = ClientId::new(ClientType::Tendermint, 0).unwrap(); + let client_height = Height::new(1, 20); + let update_height = Height::new(1, 21); + + let ctx = MockContext::new( + ChainId::new("mockgaiaA".to_string(), 1), + HostType::Mock, + 5, + Height::new(1, 1), + ) + .with_client_parametrized_history( + &client_id, + client_height, + Some(ClientType::Tendermint), // The target host chain (B) is synthetic TM. + Some(client_height), + ); + + let ctx_b = MockContext::new( + ChainId::new("mockgaiaB".to_string(), 1), + HostType::SyntheticTendermint, + 5, + update_height, + ); + + let signer = get_dummy_account_id(); + + let block_ref = ctx_b.host_block(update_height); + let mut latest_header: AnyHeader = block_ref.cloned().map(Into::into).unwrap(); + + let trusted_height = client_height.clone().sub(1).unwrap_or_default(); + + latest_header = match latest_header { + AnyHeader::Tendermint(mut theader) => { + theader.trusted_height = trusted_height; + AnyHeader::Tendermint(theader) + } + AnyHeader::Mock(m) => AnyHeader::Mock(m), + }; + + let msg = MsgUpdateAnyClient { + client_id: client_id.clone(), + header: latest_header, + signer, + }; + + let output = dispatch(&ctx, ClientMsg::UpdateClient(msg.clone())); + + match output { + Ok(HandlerOutput { + result, + mut events, + log, + }) => { + assert_eq!(events.len(), 1); + let event = events.pop().unwrap(); + assert!( + matches!(event, IbcEvent::UpdateClient(e) if e.client_id() == &msg.client_id) + ); + assert!(log.is_empty()); + // Check the result + match result { + Update(upd_res) => { + assert_eq!(upd_res.client_id, client_id); + assert!(!upd_res.client_state.is_frozen()); + assert_eq!(upd_res.client_state.latest_height(), msg.header.height(),) + } + _ => panic!("update handler result has incorrect type"), + } + } + Err(err) => { + panic!("unexpected error: {}", err); + } + } + } + + #[test] + fn test_update_synthetic_tendermint_client_duplicate_ok() { + let client_id = ClientId::new(ClientType::Tendermint, 0).unwrap(); + let client_height = Height::new(1, 20); + + let chain_start_height = Height::new(1, 11); + + let ctx = MockContext::new( + ChainId::new("mockgaiaA".to_string(), 1), + HostType::Mock, + 5, + chain_start_height, + ) + .with_client_parametrized( + &client_id, + client_height, + Some(ClientType::Tendermint), // The target host chain (B) is synthetic TM. + Some(client_height), + ); + + let ctx_b = MockContext::new( + ChainId::new("mockgaiaB".to_string(), 1), + HostType::SyntheticTendermint, + 5, + client_height, + ); + + let signer = get_dummy_account_id(); + + let block_ref = ctx_b.host_block(client_height); + let latest_header: AnyHeader = match block_ref.cloned().map(Into::into).unwrap() { + AnyHeader::Tendermint(mut theader) => { + let cons_state = ctx + .latest_consensus_states(&client_id, &client_height) + .clone(); + if let AnyConsensusState::Tendermint(tcs) = cons_state { + theader.signed_header.header.time = tcs.timestamp; + theader.trusted_height = Height::new(1, 11) + } + AnyHeader::Tendermint(theader) + } + AnyHeader::Mock(header) => AnyHeader::Mock(header), + }; + + let msg = MsgUpdateAnyClient { + client_id: client_id.clone(), + header: latest_header, + signer, + }; + + let output = dispatch(&ctx, ClientMsg::UpdateClient(msg.clone())); + + match output { + Ok(HandlerOutput { + result, + mut events, + log, + }) => { + assert_eq!(events.len(), 1); + let event = events.pop().unwrap(); + assert!( + matches!(event, IbcEvent::UpdateClient(e) if e.client_id() == &msg.client_id) + ); + assert!(log.is_empty()); + // Check the result + match result { + Update(upd_res) => { + assert_eq!(upd_res.client_id, client_id); + assert!(!upd_res.client_state.is_frozen()); + assert_eq!( + upd_res.client_state, + ctx.latest_client_states(&client_id).clone() + ); + assert_eq!(upd_res.client_state.latest_height(), msg.header.height(),) + } + _ => panic!("update handler result has incorrect type"), + } + } + Err(err) => { + panic!("unexpected error: {:?}", err); + } + } + } + + #[test] + fn test_update_synthetic_tendermint_client_lower_height() { + let client_id = ClientId::new(ClientType::Tendermint, 0).unwrap(); + let client_height = Height::new(1, 20); + + let client_update_height = Height::new(1, 19); + + let chain_start_height = Height::new(1, 11); + + let ctx = MockContext::new( + ChainId::new("mockgaiaA".to_string(), 1), + HostType::Mock, + 5, + chain_start_height, + ) + .with_client_parametrized( + &client_id, + client_height, + Some(ClientType::Tendermint), // The target host chain (B) is synthetic TM. + Some(client_height), + ); + + let ctx_b = MockContext::new( + ChainId::new("mockgaiaB".to_string(), 1), + HostType::SyntheticTendermint, + 5, + client_height, + ); + + let signer = get_dummy_account_id(); + + let block_ref = ctx_b.host_block(client_update_height); + let latest_header: AnyHeader = block_ref.cloned().map(Into::into).unwrap(); + + let msg = MsgUpdateAnyClient { + client_id, + header: latest_header, + signer, + }; + + let output = dispatch(&ctx, ClientMsg::UpdateClient(msg)); + + match output { + Ok(_) => { + panic!("update handler result has incorrect type"); + } + Err(err) => match err.detail() { + ErrorDetail::HeaderVerificationFailure(_) => {} + _ => panic!("unexpected error: {:?}", err), + }, + } + } +} diff --git a/modules/src/ics02_client/handler/upgrade_client.rs b/modules/src/core/ics02_client/handler/upgrade_client.rs similarity index 71% rename from modules/src/ics02_client/handler/upgrade_client.rs rename to modules/src/core/ics02_client/handler/upgrade_client.rs index 5ca5dcade..4bea94df2 100644 --- a/modules/src/ics02_client/handler/upgrade_client.rs +++ b/modules/src/core/ics02_client/handler/upgrade_client.rs @@ -1,16 +1,16 @@ //! Protocol logic specific to processing ICS2 messages of type `MsgUpgradeAnyClient`. //! +use crate::core::ics02_client::client_consensus::AnyConsensusState; +use crate::core::ics02_client::client_def::{AnyClient, ClientDef}; +use crate::core::ics02_client::client_state::{AnyClientState, ClientState}; +use crate::core::ics02_client::context::ClientReader; +use crate::core::ics02_client::error::Error; +use crate::core::ics02_client::events::Attributes; +use crate::core::ics02_client::handler::ClientResult; +use crate::core::ics02_client::msgs::upgrade_client::MsgUpgradeAnyClient; +use crate::core::ics24_host::identifier::ClientId; use crate::events::IbcEvent; use crate::handler::{HandlerOutput, HandlerResult}; -use crate::ics02_client::client_consensus::AnyConsensusState; -use crate::ics02_client::client_def::{AnyClient, ClientDef}; -use crate::ics02_client::client_state::{AnyClientState, ClientState}; -use crate::ics02_client::context::ClientReader; -use crate::ics02_client::error::Error; -use crate::ics02_client::events::Attributes; -use crate::ics02_client::handler::ClientResult; -use crate::ics02_client::msgs::upgrade_client::MsgUpgradeAnyClient; -use crate::ics24_host::identifier::ClientId; use crate::prelude::*; /// The result following the successful processing of a `MsgUpgradeAnyClient` message. @@ -78,24 +78,22 @@ pub fn process( #[cfg(test)] mod tests { use crate::prelude::*; - use core::convert::TryFrom; + use core::str::FromStr; + use crate::core::ics02_client::error::{Error, ErrorDetail}; + use crate::core::ics02_client::handler::dispatch; + use crate::core::ics02_client::handler::ClientResult::Upgrade; + use crate::core::ics02_client::msgs::upgrade_client::MsgUpgradeAnyClient; + use crate::core::ics02_client::msgs::ClientMsg; + use crate::core::ics24_host::identifier::ClientId; use crate::events::IbcEvent; use crate::handler::HandlerOutput; - use crate::ics02_client::error::{Error, ErrorDetail}; - use crate::ics02_client::handler::dispatch; - use crate::ics02_client::handler::ClientResult::Upgrade; - use crate::ics02_client::msgs::upgrade_client::MsgUpgradeAnyClient; - use crate::ics02_client::msgs::ClientMsg; - use crate::ics23_commitment::commitment::CommitmentProofBytes; - use crate::ics24_host::identifier::ClientId; use crate::mock::client_state::{MockClientState, MockConsensusState}; use crate::mock::context::MockContext; use crate::mock::header::MockHeader; use crate::test_utils::get_dummy_account_id; use crate::Height; - use ibc_proto::ibc::core::commitment::v1::MerkleProof; #[test] fn test_upgrade_client_ok() { @@ -104,18 +102,12 @@ mod tests { let ctx = MockContext::default().with_client(&client_id, Height::new(0, 42)); - let buf: Vec = Vec::new(); - let buf2: Vec = Vec::new(); - - let c_bytes = CommitmentProofBytes::from(buf); - let cs_bytes = CommitmentProofBytes::from(buf2); - let msg = MsgUpgradeAnyClient { client_id: client_id.clone(), - client_state: MockClientState(MockHeader::new(Height::new(1, 26))).into(), + client_state: MockClientState::new(MockHeader::new(Height::new(1, 26))).into(), consensus_state: MockConsensusState::new(MockHeader::new(Height::new(1, 26))).into(), - proof_upgrade_client: MerkleProof::try_from(c_bytes).unwrap(), - proof_upgrade_consensus_state: MerkleProof::try_from(cs_bytes).unwrap(), + proof_upgrade_client: Default::default(), + proof_upgrade_consensus_state: Default::default(), signer, }; @@ -155,18 +147,12 @@ mod tests { let ctx = MockContext::default().with_client(&client_id, Height::new(0, 42)); - let buf: Vec = Vec::new(); - let buf2: Vec = Vec::new(); - - let c_bytes = CommitmentProofBytes::from(buf); - let cs_bytes = CommitmentProofBytes::from(buf2); - let msg = MsgUpgradeAnyClient { client_id: ClientId::from_str("nonexistingclient").unwrap(), - client_state: MockClientState(MockHeader::new(Height::new(1, 26))).into(), + client_state: MockClientState::new(MockHeader::new(Height::new(1, 26))).into(), consensus_state: MockConsensusState::new(MockHeader::new(Height::new(1, 26))).into(), - proof_upgrade_client: MerkleProof::try_from(c_bytes).unwrap(), - proof_upgrade_consensus_state: MerkleProof::try_from(cs_bytes).unwrap(), + proof_upgrade_client: Default::default(), + proof_upgrade_consensus_state: Default::default(), signer, }; @@ -189,18 +175,12 @@ mod tests { let ctx = MockContext::default().with_client(&client_id, Height::new(0, 42)); - let buf: Vec = Vec::new(); - let buf2: Vec = Vec::new(); - - let c_bytes = CommitmentProofBytes::from(buf); - let cs_bytes = CommitmentProofBytes::from(buf2); - let msg = MsgUpgradeAnyClient { client_id, - client_state: MockClientState(MockHeader::new(Height::new(0, 26))).into(), + client_state: MockClientState::new(MockHeader::new(Height::new(0, 26))).into(), consensus_state: MockConsensusState::new(MockHeader::new(Height::new(0, 26))).into(), - proof_upgrade_client: MerkleProof::try_from(c_bytes).unwrap(), - proof_upgrade_consensus_state: MerkleProof::try_from(cs_bytes).unwrap(), + proof_upgrade_client: Default::default(), + proof_upgrade_consensus_state: Default::default(), signer, }; diff --git a/modules/src/ics02_client/header.rs b/modules/src/core/ics02_client/header.rs similarity index 71% rename from modules/src/ics02_client/header.rs rename to modules/src/core/ics02_client/header.rs index 54f40cde8..38cc27180 100644 --- a/modules/src/ics02_client/header.rs +++ b/modules/src/core/ics02_client/header.rs @@ -1,16 +1,19 @@ -use crate::prelude::*; -use core::convert::TryFrom; use core::ops::Deref; + use prost_types::Any; use serde_derive::{Deserialize, Serialize}; +use serde_json::to_string; +use subtle_encoding::hex; use tendermint_proto::Protobuf; -use crate::ics02_client::client_type::ClientType; -use crate::ics02_client::error::Error; -use crate::ics07_tendermint::header::{decode_header, Header as TendermintHeader}; -use crate::ics10_grandpa::header::Header as GrandpaHeader; +use crate::clients::ics10_grandpa::header::Header as GrandpaHeader; +use crate::clients::ics07_tendermint::header::{decode_header, Header as TendermintHeader}; +use crate::core::ics02_client::client_type::ClientType; +use crate::core::ics02_client::error::Error; #[cfg(any(test, feature = "mocks"))] use crate::mock::header::MockHeader; +use crate::prelude::*; +use crate::timestamp::Timestamp; use crate::Height; pub const TENDERMINT_HEADER_TYPE_URL: &str = "/ibc.lightclients.tendermint.v1.Header"; @@ -25,11 +28,14 @@ pub trait Header: Clone + core::fmt::Debug + Send + Sync { /// The height of the consensus state fn height(&self) -> Height; + /// The timestamp of the consensus state + fn timestamp(&self) -> Timestamp; + /// Wrap into an `AnyHeader` fn wrap_any(self) -> AnyHeader; } -#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] // TODO: Add Eq bound once possible +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] #[allow(clippy::large_enum_variant)] pub enum AnyHeader { Tendermint(TendermintHeader), @@ -60,11 +66,34 @@ impl Header for AnyHeader { } } + fn timestamp(&self) -> Timestamp { + match self { + Self::Tendermint(header) => header.timestamp(), + Self::Grandpa(header) => header.timestamp(), + + #[cfg(any(test, feature = "mocks"))] + Self::Mock(header) => header.timestamp(), + } + } + fn wrap_any(self) -> AnyHeader { self } } +impl AnyHeader { + pub fn encode_to_string(&self) -> String { + let buf = Protobuf::encode_vec(self).expect("encoding shouldn't fail"); + let encoded = hex::encode(buf); + String::from_utf8(encoded).expect("hex-encoded string should always be valid UTF-8") + } + + pub fn decode_from_string(s: &str) -> Result { + let header_bytes = hex::decode(s).unwrap(); + Protobuf::decode(header_bytes.as_ref()).map_err(Error::invalid_raw_header) + } +} + impl Protobuf for AnyHeader {} impl TryFrom for AnyHeader { @@ -78,7 +107,7 @@ impl TryFrom for AnyHeader { Ok(AnyHeader::Tendermint(val)) } GRANDPA_HEADER_TYPE_URL => { - let val = crate::ics10_grandpa::header::decode_header(raw.value.deref()) + let val = crate::clients::ics10_grandpa::header::decode_header(raw.value.deref()) .map_err(Error::grandpa)?; Ok(AnyHeader::Grandpa(val)) diff --git a/modules/src/ics02_client/height.rs b/modules/src/core/ics02_client/height.rs similarity index 98% rename from modules/src/ics02_client/height.rs rename to modules/src/core/ics02_client/height.rs index 576985c1d..e7feae202 100644 --- a/modules/src/ics02_client/height.rs +++ b/modules/src/core/ics02_client/height.rs @@ -1,6 +1,6 @@ use crate::prelude::*; use core::cmp::Ordering; -use core::convert::TryFrom; + use core::num::ParseIntError; use core::str::FromStr; @@ -10,7 +10,7 @@ use tendermint_proto::Protobuf; use ibc_proto::ibc::core::client::v1::Height as RawHeight; -use crate::ics02_client::error::Error; +use crate::core::ics02_client::error::Error; #[derive(Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Height { @@ -139,6 +139,7 @@ impl core::fmt::Display for Height { } define_error! { + #[derive(Debug, PartialEq, Eq)] HeightError { HeightConversion { height: String } diff --git a/modules/src/ics02_client/misbehaviour.rs b/modules/src/core/ics02_client/misbehaviour.rs similarity index 94% rename from modules/src/ics02_client/misbehaviour.rs rename to modules/src/core/ics02_client/misbehaviour.rs index d8fec339d..a06173301 100644 --- a/modules/src/ics02_client/misbehaviour.rs +++ b/modules/src/core/ics02_client/misbehaviour.rs @@ -1,17 +1,16 @@ use crate::prelude::*; -use core::convert::TryFrom; use prost_types::Any; use tendermint_proto::Protobuf; -use crate::ics02_client::error::Error; -use crate::ics07_tendermint::misbehaviour::Misbehaviour as TmMisbehaviour; -use crate::ics10_grandpa::misbehaviour::Misbehaviour as GpMisbehaviour; +use crate::clients::ics10_grandpa::misbehaviour::Misbehaviour as GpMisbehaviour; +use crate::clients::ics07_tendermint::misbehaviour::Misbehaviour as TmMisbehaviour; +use crate::core::ics02_client::error::Error; #[cfg(any(test, feature = "mocks"))] use crate::mock::misbehaviour::Misbehaviour as MockMisbehaviour; -use crate::ics24_host::identifier::ClientId; +use crate::core::ics24_host::identifier::ClientId; use crate::Height; use super::header::AnyHeader; diff --git a/modules/src/ics02_client/mod.rs b/modules/src/core/ics02_client/mod.rs similarity index 76% rename from modules/src/ics02_client/mod.rs rename to modules/src/core/ics02_client/mod.rs index ca2713d6a..9c25ef479 100644 --- a/modules/src/ics02_client/mod.rs +++ b/modules/src/core/ics02_client/mod.rs @@ -1,4 +1,4 @@ -//! ICS 02: IBC Client implementation +//! ICS 02: Client implementation for verifying remote IBC-enabled chains. pub mod client_consensus; pub mod client_def; diff --git a/modules/src/ics02_client/msgs.rs b/modules/src/core/ics02_client/msgs.rs similarity index 73% rename from modules/src/ics02_client/msgs.rs rename to modules/src/core/ics02_client/msgs.rs index e0fe425b7..020e79445 100644 --- a/modules/src/ics02_client/msgs.rs +++ b/modules/src/core/ics02_client/msgs.rs @@ -4,10 +4,10 @@ //! subsequently calls into the chain-specific (e.g., ICS 07) client handler. See: //! . -use crate::ics02_client::msgs::create_client::MsgCreateAnyClient; -use crate::ics02_client::msgs::misbehavior::MsgSubmitAnyMisbehaviour; -use crate::ics02_client::msgs::update_client::MsgUpdateAnyClient; -use crate::ics02_client::msgs::upgrade_client::MsgUpgradeAnyClient; +use crate::core::ics02_client::msgs::create_client::MsgCreateAnyClient; +use crate::core::ics02_client::msgs::misbehavior::MsgSubmitAnyMisbehaviour; +use crate::core::ics02_client::msgs::update_client::MsgUpdateAnyClient; +use crate::core::ics02_client::msgs::upgrade_client::MsgUpgradeAnyClient; pub mod create_client; pub mod misbehavior; diff --git a/modules/src/ics02_client/msgs/create_client.rs b/modules/src/core/ics02_client/msgs/create_client.rs similarity index 79% rename from modules/src/ics02_client/msgs/create_client.rs rename to modules/src/core/ics02_client/msgs/create_client.rs index 566a9765a..5e9e53198 100644 --- a/modules/src/ics02_client/msgs/create_client.rs +++ b/modules/src/core/ics02_client/msgs/create_client.rs @@ -1,15 +1,14 @@ //! Definition of domain type message `MsgCreateAnyClient`. use crate::prelude::*; -use core::convert::TryFrom; use tendermint_proto::Protobuf; use ibc_proto::ibc::core::client::v1::MsgCreateClient as RawMsgCreateClient; -use crate::ics02_client::client_consensus::AnyConsensusState; -use crate::ics02_client::client_state::AnyClientState; -use crate::ics02_client::error::Error; +use crate::core::ics02_client::client_consensus::AnyConsensusState; +use crate::core::ics02_client::client_state::AnyClientState; +use crate::core::ics02_client::error::Error; use crate::signer::Signer; use crate::tx_msg::Msg; @@ -41,18 +40,10 @@ impl MsgCreateAnyClient { signer, }) } - - pub fn client_state(&self) -> AnyClientState { - self.client_state.clone() - } - - pub fn consensus_state(&self) -> AnyConsensusState { - self.consensus_state.clone() - } } impl Msg for MsgCreateAnyClient { - type ValidationError = crate::ics24_host::error::ValidationError; + type ValidationError = crate::core::ics24_host::error::ValidationError; type Raw = RawMsgCreateClient; fn route(&self) -> String { @@ -98,15 +89,15 @@ impl From for RawMsgCreateClient { #[cfg(test)] mod tests { - use core::convert::{TryFrom, TryInto}; - use test_env_log::test; + + use test_log::test; use ibc_proto::ibc::core::client::v1::MsgCreateClient; - use crate::ics02_client::client_consensus::AnyConsensusState; - use crate::ics02_client::msgs::MsgCreateAnyClient; - use crate::ics07_tendermint::client_state::test_util::get_dummy_tendermint_client_state; - use crate::ics07_tendermint::header::test_util::get_dummy_tendermint_header; + use crate::clients::ics07_tendermint::client_state::test_util::get_dummy_tendermint_client_state; + use crate::clients::ics07_tendermint::header::test_util::get_dummy_tendermint_header; + use crate::core::ics02_client::client_consensus::AnyConsensusState; + use crate::core::ics02_client::msgs::MsgCreateAnyClient; use crate::test_utils::get_dummy_account_id; #[test] diff --git a/modules/src/ics02_client/msgs/misbehavior.rs b/modules/src/core/ics02_client/msgs/misbehavior.rs similarity index 88% rename from modules/src/ics02_client/msgs/misbehavior.rs rename to modules/src/core/ics02_client/msgs/misbehavior.rs index d28536666..6f0ff000e 100644 --- a/modules/src/ics02_client/msgs/misbehavior.rs +++ b/modules/src/core/ics02_client/msgs/misbehavior.rs @@ -1,13 +1,12 @@ use crate::prelude::*; -use core::convert::TryFrom; use tendermint_proto::Protobuf; use ibc_proto::ibc::core::client::v1::MsgSubmitMisbehaviour as RawMsgSubmitMisbehaviour; -use crate::ics02_client::error::Error; -use crate::ics02_client::misbehaviour::AnyMisbehaviour; -use crate::ics24_host::identifier::ClientId; +use crate::core::ics02_client::error::Error; +use crate::core::ics02_client::misbehaviour::AnyMisbehaviour; +use crate::core::ics24_host::identifier::ClientId; use crate::signer::Signer; use crate::tx_msg::Msg; @@ -25,7 +24,7 @@ pub struct MsgSubmitAnyMisbehaviour { } impl Msg for MsgSubmitAnyMisbehaviour { - type ValidationError = crate::ics24_host::error::ValidationError; + type ValidationError = crate::core::ics24_host::error::ValidationError; type Raw = RawMsgSubmitMisbehaviour; fn route(&self) -> String { diff --git a/modules/src/ics02_client/msgs/update_client.rs b/modules/src/core/ics02_client/msgs/update_client.rs similarity index 83% rename from modules/src/ics02_client/msgs/update_client.rs rename to modules/src/core/ics02_client/msgs/update_client.rs index 7efdf8ed8..dc98b90af 100644 --- a/modules/src/ics02_client/msgs/update_client.rs +++ b/modules/src/core/ics02_client/msgs/update_client.rs @@ -1,14 +1,16 @@ //! Definition of domain type message `MsgUpdateAnyClient`. use crate::prelude::*; -use core::convert::TryFrom; + use tendermint_proto::Protobuf; use ibc_proto::ibc::core::client::v1::MsgUpdateClient as RawMsgUpdateClient; -use crate::ics02_client::error::Error; -use crate::ics02_client::header::AnyHeader; -use crate::ics24_host::identifier::ClientId; + +use crate::core::ics02_client::error::Error; +use crate::core::ics02_client::header::AnyHeader; +use crate::core::ics24_host::error::ValidationError; +use crate::core::ics24_host::identifier::ClientId; use crate::signer::Signer; use crate::tx_msg::Msg; @@ -33,7 +35,7 @@ impl MsgUpdateAnyClient { } impl Msg for MsgUpdateAnyClient { - type ValidationError = crate::ics24_host::error::ValidationError; + type ValidationError = ValidationError; type Raw = RawMsgUpdateClient; fn route(&self) -> String { @@ -76,15 +78,15 @@ impl From for RawMsgUpdateClient { #[cfg(test)] mod tests { - use core::convert::TryFrom; - use test_env_log::test; + + use test_log::test; use ibc_proto::ibc::core::client::v1::MsgUpdateClient; - use crate::ics02_client::header::AnyHeader; - use crate::ics02_client::msgs::MsgUpdateAnyClient; - use crate::ics07_tendermint::header::test_util::get_dummy_ics07_header; - use crate::ics24_host::identifier::ClientId; + use crate::clients::ics07_tendermint::header::test_util::get_dummy_ics07_header; + use crate::core::ics02_client::header::AnyHeader; + use crate::core::ics02_client::msgs::MsgUpdateAnyClient; + use crate::core::ics24_host::identifier::ClientId; use crate::test_utils::get_dummy_account_id; #[test] diff --git a/modules/src/ics02_client/msgs/upgrade_client.rs b/modules/src/core/ics02_client/msgs/upgrade_client.rs similarity index 74% rename from modules/src/ics02_client/msgs/upgrade_client.rs rename to modules/src/core/ics02_client/msgs/upgrade_client.rs index daafdd562..162e630d0 100644 --- a/modules/src/ics02_client/msgs/upgrade_client.rs +++ b/modules/src/core/ics02_client/msgs/upgrade_client.rs @@ -1,18 +1,19 @@ //! Definition of domain type msg `MsgUpgradeAnyClient`. use crate::prelude::*; -use core::convert::TryFrom; + use core::str::FromStr; use tendermint_proto::Protobuf; use ibc_proto::ibc::core::client::v1::MsgUpgradeClient as RawMsgUpgradeClient; use ibc_proto::ibc::core::commitment::v1::MerkleProof as RawMerkleProof; -use crate::ics02_client::client_consensus::AnyConsensusState; -use crate::ics02_client::client_state::AnyClientState; -use crate::ics02_client::error::Error; -use crate::ics23_commitment::commitment::CommitmentProofBytes; -use crate::ics24_host::identifier::ClientId; +use crate::core::ics02_client::client_consensus::AnyConsensusState; +use crate::core::ics02_client::client_state::AnyClientState; +use crate::core::ics02_client::error::Error; +use crate::core::ics23_commitment::commitment::CommitmentProofBytes; +use crate::core::ics23_commitment::error::Error as Ics23Error; +use crate::core::ics24_host::identifier::ClientId; use crate::signer::Signer; use crate::tx_msg::Msg; @@ -49,7 +50,7 @@ impl MsgUpgradeAnyClient { } impl Msg for MsgUpgradeAnyClient { - type ValidationError = crate::ics24_host::error::ValidationError; + type ValidationError = crate::core::ics24_host::error::ValidationError; type Raw = RawMsgUpgradeClient; fn route(&self) -> String { @@ -65,15 +66,17 @@ impl Protobuf for MsgUpgradeAnyClient {} impl From for RawMsgUpgradeClient { fn from(dm_msg: MsgUpgradeAnyClient) -> RawMsgUpgradeClient { - let c_bytes: CommitmentProofBytes = dm_msg.proof_upgrade_client.into(); - let cs_bytes: CommitmentProofBytes = dm_msg.proof_upgrade_consensus_state.into(); + let c_bytes = CommitmentProofBytes::try_from(dm_msg.proof_upgrade_client) + .map_or(vec![], |c| c.into()); + let cs_bytes = CommitmentProofBytes::try_from(dm_msg.proof_upgrade_consensus_state) + .map_or(vec![], |c| c.into()); RawMsgUpgradeClient { client_id: dm_msg.client_id.to_string(), client_state: Some(dm_msg.client_state.into()), consensus_state: Some(dm_msg.consensus_state.into()), - proof_upgrade_client: c_bytes.into(), - proof_upgrade_consensus_state: cs_bytes.into(), + proof_upgrade_client: c_bytes, + proof_upgrade_consensus_state: cs_bytes, signer: dm_msg.signer.to_string(), } } @@ -91,8 +94,12 @@ impl TryFrom for MsgUpgradeAnyClient { .consensus_state .ok_or_else(Error::missing_raw_client_state)?; - let c_bytes = CommitmentProofBytes::from(proto_msg.proof_upgrade_client); - let cs_bytes = CommitmentProofBytes::from(proto_msg.proof_upgrade_consensus_state); + let c_bytes = CommitmentProofBytes::try_from(proto_msg.proof_upgrade_client) + .map_err(|_| Error::invalid_upgrade_client_proof(Ics23Error::empty_merkle_proof()))?; + let cs_bytes = CommitmentProofBytes::try_from(proto_msg.proof_upgrade_consensus_state) + .map_err(|_| { + Error::invalid_upgrade_consensus_state_proof(Ics23Error::empty_merkle_proof()) + })?; Ok(MsgUpgradeAnyClient { client_id: ClientId::from_str(&proto_msg.client_id) @@ -113,10 +120,12 @@ pub mod test_util { use ibc_proto::ibc::core::client::v1::MsgUpgradeClient as RawMsgUpgradeClient; use crate::{ - ics02_client::{ - client_consensus::AnyConsensusState, client_state::AnyClientState, height::Height, + core::{ + ics02_client::{ + client_consensus::AnyConsensusState, client_state::AnyClientState, height::Height, + }, + ics24_host::identifier::ClientId, }, - ics24_host::identifier::ClientId, mock::{ client_state::{MockClientState, MockConsensusState}, header::MockHeader, @@ -139,7 +148,7 @@ pub mod test_util { RawMsgUpgradeClient { client_id: "tendermint".parse().unwrap(), client_state: Some( - AnyClientState::Mock(MockClientState(MockHeader::new(height))).into(), + AnyClientState::Mock(MockClientState::new(MockHeader::new(height))).into(), ), consensus_state: Some( AnyConsensusState::Mock(MockConsensusState::new(MockHeader::new(height))).into(), @@ -153,17 +162,18 @@ pub mod test_util { #[cfg(test)] mod tests { - use core::convert::TryFrom; use ibc_proto::ibc::core::client::v1::MsgUpgradeClient as RawMsgUpgradeClient; use crate::{ - ics02_client::{ - client_consensus::AnyConsensusState, client_state::AnyClientState, height::Height, - msgs::upgrade_client::MsgUpgradeAnyClient, + core::{ + ics02_client::{ + client_consensus::AnyConsensusState, client_state::AnyClientState, height::Height, + msgs::upgrade_client::MsgUpgradeAnyClient, + }, + ics23_commitment::commitment::test_util::get_dummy_merkle_proof, + ics24_host::identifier::ClientId, }, - ics23_commitment::commitment::test_util::get_dummy_merkle_proof, - ics24_host::identifier::ClientId, mock::{ client_state::{MockClientState, MockConsensusState}, header::MockHeader, @@ -178,7 +188,7 @@ mod tests { let height = Height::new(1, 1); - let client_state = AnyClientState::Mock(MockClientState(MockHeader::new(height))); + let client_state = AnyClientState::Mock(MockClientState::new(MockHeader::new(height))); let consensus_state = AnyConsensusState::Mock(MockConsensusState::new(MockHeader::new(height))); diff --git a/modules/src/ics02_client/trust_threshold.rs b/modules/src/core/ics02_client/trust_threshold.rs similarity index 98% rename from modules/src/ics02_client/trust_threshold.rs rename to modules/src/core/ics02_client/trust_threshold.rs index af4235f3c..ca5db5e2f 100644 --- a/modules/src/ics02_client/trust_threshold.rs +++ b/modules/src/core/ics02_client/trust_threshold.rs @@ -10,7 +10,7 @@ use tendermint_proto::Protobuf; use ibc_proto::ibc::lightclients::tendermint::v1::Fraction; use tendermint::trust_threshold::TrustThresholdFraction; -use crate::ics02_client::error::Error; +use crate::core::ics02_client::error::Error; /// [`TrustThreshold`] defines the level of trust that a client has /// towards a set of validators of a chain. diff --git a/modules/src/ics03_connection/connection.rs b/modules/src/core/ics03_connection/connection.rs similarity index 91% rename from modules/src/ics03_connection/connection.rs rename to modules/src/core/ics03_connection/connection.rs index 134a041c9..af4184436 100644 --- a/modules/src/ics03_connection/connection.rs +++ b/modules/src/core/ics03_connection/connection.rs @@ -1,8 +1,8 @@ use crate::prelude::*; -use core::convert::{TryFrom, TryInto}; + use core::str::FromStr; use core::time::Duration; -use core::u64; +use core::{fmt, u64}; use serde::{Deserialize, Serialize}; use tendermint_proto::Protobuf; @@ -12,11 +12,12 @@ use ibc_proto::ibc::core::connection::v1::{ IdentifiedConnection as RawIdentifiedConnection, }; -use crate::ics03_connection::error::Error; -use crate::ics03_connection::version::Version; -use crate::ics23_commitment::commitment::CommitmentPrefix; -use crate::ics24_host::error::ValidationError; -use crate::ics24_host::identifier::{ClientId, ConnectionId}; +use crate::core::ics02_client::error::Error as ClientError; +use crate::core::ics03_connection::error::Error; +use crate::core::ics03_connection::version::Version; +use crate::core::ics23_commitment::commitment::CommitmentPrefix; +use crate::core::ics24_host::error::ValidationError; +use crate::core::ics24_host::identifier::{ClientId, ConnectionId}; use crate::timestamp::ZERO_DURATION; #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] @@ -195,10 +196,12 @@ impl ConnectionEnd { self.client_id.eq(other) } + /// Helper function to determine whether the connection is open. pub fn is_open(&self) -> bool { self.state_matches(&State::Open) } + /// Helper function to determine whether the connection is uninitialized. pub fn is_uninitialized(&self) -> bool { self.state_matches(&State::Uninitialized) } @@ -214,8 +217,8 @@ impl ConnectionEnd { } /// Getter for the list of versions in this connection end. - pub fn versions(&self) -> Vec { - self.versions.clone() + pub fn versions(&self) -> &[Version] { + &self.versions } /// Getter for the counterparty. @@ -235,23 +238,13 @@ impl ConnectionEnd { } } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Counterparty { pub client_id: ClientId, pub connection_id: Option, prefix: CommitmentPrefix, } -impl Default for Counterparty { - fn default() -> Self { - Counterparty { - client_id: Default::default(), - connection_id: None, - prefix: Default::default(), - } - } -} - impl Protobuf for Counterparty {} // Converts from the wire format RawCounterparty. Typically used from the relayer side @@ -272,7 +265,8 @@ impl TryFrom for Counterparty { .prefix .ok_or_else(Error::missing_counterparty)? .key_prefix - .into(), + .try_into() + .map_err(|_| Error::ics02_client(ClientError::empty_prefix()))?, )) } } @@ -333,7 +327,7 @@ pub enum State { impl State { /// Yields the State as a string. - pub fn as_string(&self) -> &'static str { + pub fn as_str(&self) -> &'static str { match self { Self::Uninitialized => "UNINITIALIZED", Self::Init => "INIT", @@ -341,7 +335,8 @@ impl State { Self::Open => "OPEN", } } - // Parses the State out from a i32. + + /// Parses the State out from a i32. pub fn from_i32(s: i32) -> Result { match s { 0 => Ok(Self::Uninitialized), @@ -371,6 +366,12 @@ impl State { } } +impl fmt::Display for State { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.as_str()) + } +} + impl TryFrom for State { type Error = Error; fn try_from(value: i32) -> Result { diff --git a/modules/src/ics03_connection/context.rs b/modules/src/core/ics03_connection/context.rs similarity index 88% rename from modules/src/ics03_connection/context.rs rename to modules/src/core/ics03_connection/context.rs index 2b506cea6..50abb4324 100644 --- a/modules/src/ics03_connection/context.rs +++ b/modules/src/core/ics03_connection/context.rs @@ -2,14 +2,14 @@ //! the interface that any host chain must implement to be able to process any `ConnectionMsg`. //! See "ADR 003: IBC protocol implementation" for more details. -use crate::ics02_client::client_consensus::AnyConsensusState; -use crate::ics02_client::client_state::AnyClientState; -use crate::ics03_connection::connection::ConnectionEnd; -use crate::ics03_connection::error::Error; -use crate::ics03_connection::handler::{ConnectionIdState, ConnectionResult}; -use crate::ics03_connection::version::{get_compatible_versions, pick_version, Version}; -use crate::ics23_commitment::commitment::CommitmentPrefix; -use crate::ics24_host::identifier::{ClientId, ConnectionId}; +use crate::core::ics02_client::client_consensus::AnyConsensusState; +use crate::core::ics02_client::client_state::AnyClientState; +use crate::core::ics03_connection::connection::ConnectionEnd; +use crate::core::ics03_connection::error::Error; +use crate::core::ics03_connection::handler::{ConnectionIdState, ConnectionResult}; +use crate::core::ics03_connection::version::{get_compatible_versions, pick_version, Version}; +use crate::core::ics23_commitment::commitment::CommitmentPrefix; +use crate::core::ics24_host::identifier::{ClientId, ConnectionId}; use crate::prelude::*; use crate::Height; diff --git a/modules/src/ics03_connection/error.rs b/modules/src/core/ics03_connection/error.rs similarity index 96% rename from modules/src/ics03_connection/error.rs rename to modules/src/core/ics03_connection/error.rs index d5e07c48a..2a0d687e0 100644 --- a/modules/src/ics03_connection/error.rs +++ b/modules/src/core/ics03_connection/error.rs @@ -1,6 +1,6 @@ -use crate::ics02_client::error as client_error; -use crate::ics24_host::error::ValidationError; -use crate::ics24_host::identifier::{ClientId, ConnectionId}; +use crate::core::ics02_client::error as client_error; +use crate::core::ics24_host::error::ValidationError; +use crate::core::ics24_host::identifier::{ClientId, ConnectionId}; use crate::proofs::ProofError; use crate::Height; use flex_error::define_error; diff --git a/modules/src/core/ics03_connection/events.rs b/modules/src/core/ics03_connection/events.rs new file mode 100644 index 000000000..1ab4dbdcd --- /dev/null +++ b/modules/src/core/ics03_connection/events.rs @@ -0,0 +1,324 @@ +//! Types for the IBC events emitted from Tendermint Websocket by the connection module. + +use serde_derive::{Deserialize, Serialize}; +use tendermint::abci::tag::Tag; +use tendermint::abci::Event as AbciEvent; + +use crate::core::ics02_client::error::Error as Ics02Error; +use crate::core::ics02_client::height::Height; +use crate::core::ics03_connection::error::Error; +use crate::core::ics24_host::identifier::{ClientId, ConnectionId}; +use crate::events::{IbcEvent, IbcEventType}; +use crate::prelude::*; + +/// The content of the `key` field for the attribute containing the connection identifier. +const HEIGHT_ATTRIBUTE_KEY: &str = "height"; +const CONN_ID_ATTRIBUTE_KEY: &str = "connection_id"; +const CLIENT_ID_ATTRIBUTE_KEY: &str = "client_id"; +const COUNTERPARTY_CONN_ID_ATTRIBUTE_KEY: &str = "counterparty_connection_id"; +const COUNTERPARTY_CLIENT_ID_ATTRIBUTE_KEY: &str = "counterparty_client_id"; + +pub fn try_from_tx(event: &tendermint::abci::Event) -> Option { + match event.type_str.parse() { + Ok(IbcEventType::OpenInitConnection) => extract_attributes_from_tx(event) + .map(OpenInit::from) + .map(IbcEvent::OpenInitConnection) + .ok(), + Ok(IbcEventType::OpenTryConnection) => extract_attributes_from_tx(event) + .map(OpenTry::from) + .map(IbcEvent::OpenTryConnection) + .ok(), + Ok(IbcEventType::OpenAckConnection) => extract_attributes_from_tx(event) + .map(OpenAck::from) + .map(IbcEvent::OpenAckConnection) + .ok(), + Ok(IbcEventType::OpenConfirmConnection) => extract_attributes_from_tx(event) + .map(OpenConfirm::from) + .map(IbcEvent::OpenConfirmConnection) + .ok(), + _ => None, + } +} + +fn extract_attributes_from_tx(event: &tendermint::abci::Event) -> Result { + let mut attr = Attributes::default(); + + for tag in &event.attributes { + let key = tag.key.as_ref(); + let value = tag.value.as_ref(); + match key { + HEIGHT_ATTRIBUTE_KEY => { + attr.height = value.parse().map_err(|e| { + Error::ics02_client(Ics02Error::invalid_string_as_height(value.to_string(), e)) + })?; + } + CONN_ID_ATTRIBUTE_KEY => { + attr.connection_id = value.parse().ok(); + } + CLIENT_ID_ATTRIBUTE_KEY => { + attr.client_id = value.parse().map_err(Error::invalid_identifier)?; + } + COUNTERPARTY_CONN_ID_ATTRIBUTE_KEY => { + attr.counterparty_connection_id = value.parse().ok(); + } + COUNTERPARTY_CLIENT_ID_ATTRIBUTE_KEY => { + attr.counterparty_client_id = value.parse().map_err(Error::invalid_identifier)?; + } + _ => {} + } + } + + Ok(attr) +} + +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Attributes { + pub height: Height, + pub connection_id: Option, + pub client_id: ClientId, + pub counterparty_connection_id: Option, + pub counterparty_client_id: ClientId, +} + +/// Convert attributes to Tendermint ABCI tags +/// +/// # Note +/// The parsing of `Key`s and `Value`s never fails, because the +/// `FromStr` instance of `tendermint::abci::tag::{Key, Value}` +/// is infallible, even if it is not represented in the error type. +/// Once tendermint-rs improves the API of the `Key` and `Value` types, +/// we will be able to remove the `.parse().unwrap()` calls. +impl From for Vec { + fn from(a: Attributes) -> Self { + let mut attributes = vec![]; + let height = Tag { + key: HEIGHT_ATTRIBUTE_KEY.parse().unwrap(), + value: a.height.to_string().parse().unwrap(), + }; + attributes.push(height); + if let Some(conn_id) = a.connection_id { + let conn_id = Tag { + key: CONN_ID_ATTRIBUTE_KEY.parse().unwrap(), + value: conn_id.to_string().parse().unwrap(), + }; + attributes.push(conn_id); + } + let client_id = Tag { + key: CLIENT_ID_ATTRIBUTE_KEY.parse().unwrap(), + value: a.client_id.to_string().parse().unwrap(), + }; + attributes.push(client_id); + if let Some(conn_id) = a.counterparty_connection_id { + let conn_id = Tag { + key: COUNTERPARTY_CONN_ID_ATTRIBUTE_KEY.parse().unwrap(), + value: conn_id.to_string().parse().unwrap(), + }; + attributes.push(conn_id); + } + let counterparty_client_id = Tag { + key: COUNTERPARTY_CLIENT_ID_ATTRIBUTE_KEY.parse().unwrap(), + value: a.counterparty_client_id.to_string().parse().unwrap(), + }; + attributes.push(counterparty_client_id); + attributes + } +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +pub struct OpenInit(Attributes); + +impl OpenInit { + pub fn attributes(&self) -> &Attributes { + &self.0 + } + pub fn connection_id(&self) -> &Option { + &self.0.connection_id + } + pub fn height(&self) -> Height { + self.0.height + } + pub fn set_height(&mut self, height: Height) { + self.0.height = height; + } +} + +impl From for OpenInit { + fn from(attrs: Attributes) -> Self { + OpenInit(attrs) + } +} + +impl From for IbcEvent { + fn from(v: OpenInit) -> Self { + IbcEvent::OpenInitConnection(v) + } +} + +impl From for AbciEvent { + fn from(v: OpenInit) -> Self { + let attributes = Vec::::from(v.0); + AbciEvent { + type_str: IbcEventType::OpenInitConnection.as_str().to_string(), + attributes, + } + } +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +pub struct OpenTry(Attributes); + +impl OpenTry { + pub fn attributes(&self) -> &Attributes { + &self.0 + } + pub fn connection_id(&self) -> &Option { + &self.0.connection_id + } + pub fn height(&self) -> Height { + self.0.height + } + pub fn set_height(&mut self, height: Height) { + self.0.height = height; + } +} + +impl From for OpenTry { + fn from(attrs: Attributes) -> Self { + OpenTry(attrs) + } +} + +impl From for IbcEvent { + fn from(v: OpenTry) -> Self { + IbcEvent::OpenTryConnection(v) + } +} + +impl From for AbciEvent { + fn from(v: OpenTry) -> Self { + let attributes = Vec::::from(v.0); + AbciEvent { + type_str: IbcEventType::OpenTryConnection.as_str().to_string(), + attributes, + } + } +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +pub struct OpenAck(Attributes); + +impl OpenAck { + pub fn attributes(&self) -> &Attributes { + &self.0 + } + pub fn connection_id(&self) -> &Option { + &self.0.connection_id + } + pub fn height(&self) -> Height { + self.0.height + } + pub fn set_height(&mut self, height: Height) { + self.0.height = height; + } +} + +impl From for OpenAck { + fn from(attrs: Attributes) -> Self { + OpenAck(attrs) + } +} + +impl From for IbcEvent { + fn from(v: OpenAck) -> Self { + IbcEvent::OpenAckConnection(v) + } +} + +impl From for AbciEvent { + fn from(v: OpenAck) -> Self { + let attributes = Vec::::from(v.0); + AbciEvent { + type_str: IbcEventType::OpenAckConnection.as_str().to_string(), + attributes, + } + } +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +pub struct OpenConfirm(Attributes); + +impl OpenConfirm { + pub fn attributes(&self) -> &Attributes { + &self.0 + } + pub fn connection_id(&self) -> &Option { + &self.0.connection_id + } + pub fn height(&self) -> Height { + self.0.height + } + pub fn set_height(&mut self, height: Height) { + self.0.height = height; + } +} + +impl From for OpenConfirm { + fn from(attrs: Attributes) -> Self { + OpenConfirm(attrs) + } +} + +impl From for IbcEvent { + fn from(v: OpenConfirm) -> Self { + IbcEvent::OpenConfirmConnection(v) + } +} + +impl From for AbciEvent { + fn from(v: OpenConfirm) -> Self { + let attributes = Vec::::from(v.0); + AbciEvent { + type_str: IbcEventType::OpenConfirmConnection.as_str().to_string(), + attributes, + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn connection_event_to_abci_event() { + let height = Height::new(1, 1); + let attributes = Attributes { + height, + connection_id: Some("test_connection".parse().unwrap()), + client_id: "test_client".parse().unwrap(), + counterparty_connection_id: Some("counterparty_test_conn".parse().unwrap()), + counterparty_client_id: "counterparty_test_client".parse().unwrap(), + }; + let mut abci_events = vec![]; + let open_init = OpenInit::from(attributes.clone()); + abci_events.push(AbciEvent::from(open_init.clone())); + let open_try = OpenTry::from(attributes.clone()); + abci_events.push(AbciEvent::from(open_try.clone())); + let open_ack = OpenAck::from(attributes.clone()); + abci_events.push(AbciEvent::from(open_ack.clone())); + let open_confirm = OpenConfirm::from(attributes); + abci_events.push(AbciEvent::from(open_confirm.clone())); + + for event in abci_events { + match try_from_tx(&event) { + Some(e) => match e { + IbcEvent::OpenInitConnection(e) => assert_eq!(e.0, open_init.0), + IbcEvent::OpenTryConnection(e) => assert_eq!(e.0, open_try.0), + IbcEvent::OpenAckConnection(e) => assert_eq!(e.0, open_ack.0), + IbcEvent::OpenConfirmConnection(e) => assert_eq!(e.0, open_confirm.0), + _ => panic!("unexpected event type"), + }, + None => panic!("converted event was wrong"), + } + } + } +} diff --git a/modules/src/ics03_connection/handler.rs b/modules/src/core/ics03_connection/handler.rs similarity index 87% rename from modules/src/ics03_connection/handler.rs rename to modules/src/core/ics03_connection/handler.rs index 28213649b..b096c32e1 100644 --- a/modules/src/ics03_connection/handler.rs +++ b/modules/src/core/ics03_connection/handler.rs @@ -1,11 +1,11 @@ //! This module implements the processing logic for ICS3 (connection open handshake) messages. +use crate::core::ics03_connection::connection::ConnectionEnd; +use crate::core::ics03_connection::context::ConnectionReader; +use crate::core::ics03_connection::error::Error; +use crate::core::ics03_connection::msgs::ConnectionMsg; +use crate::core::ics24_host::identifier::ConnectionId; use crate::handler::HandlerOutput; -use crate::ics03_connection::connection::ConnectionEnd; -use crate::ics03_connection::context::ConnectionReader; -use crate::ics03_connection::error::Error; -use crate::ics03_connection::msgs::ConnectionMsg; -use crate::ics24_host::identifier::ConnectionId; pub mod conn_open_ack; pub mod conn_open_confirm; diff --git a/modules/src/ics03_connection/handler/conn_open_ack.rs b/modules/src/core/ics03_connection/handler/conn_open_ack.rs similarity index 58% rename from modules/src/ics03_connection/handler/conn_open_ack.rs rename to modules/src/core/ics03_connection/handler/conn_open_ack.rs index 2bc565526..8d1c11c52 100644 --- a/modules/src/ics03_connection/handler/conn_open_ack.rs +++ b/modules/src/core/ics03_connection/handler/conn_open_ack.rs @@ -1,14 +1,16 @@ //! Protocol logic specific to processing ICS3 messages of type `MsgConnectionOpenAck`. +use crate::core::ics03_connection::connection::{ConnectionEnd, Counterparty, State}; +use crate::core::ics03_connection::context::ConnectionReader; +use crate::core::ics03_connection::error::Error; +use crate::core::ics03_connection::events::Attributes; +use crate::core::ics03_connection::handler::verify::{ + check_client_consensus_height, verify_proofs, +}; +use crate::core::ics03_connection::handler::{ConnectionIdState, ConnectionResult}; +use crate::core::ics03_connection::msgs::conn_open_ack::MsgConnectionOpenAck; use crate::events::IbcEvent; use crate::handler::{HandlerOutput, HandlerResult}; -use crate::ics03_connection::connection::{ConnectionEnd, Counterparty, State}; -use crate::ics03_connection::context::ConnectionReader; -use crate::ics03_connection::error::Error; -use crate::ics03_connection::events::Attributes; -use crate::ics03_connection::handler::verify::{check_client_consensus_height, verify_proofs}; -use crate::ics03_connection::handler::{ConnectionIdState, ConnectionResult}; -use crate::ics03_connection::msgs::conn_open_ack::MsgConnectionOpenAck; use crate::prelude::*; pub(crate) fn process( @@ -22,63 +24,59 @@ pub(crate) fn process( // check_client_consensus_height(ctx, msg.consensus_height())?; // Validate the connection end. - let mut conn_end = ctx.connection_end(msg.connection_id())?; + let mut conn_end = ctx.connection_end(&msg.connection_id)?; // A connection end must be Init or TryOpen; otherwise we return an error. let state_is_consistent = conn_end.state_matches(&State::Init) - && conn_end.versions().contains(msg.version()) + && conn_end.versions().contains(&msg.version) || conn_end.state_matches(&State::TryOpen) - && conn_end.versions().get(0).eq(&Some(msg.version())); - // Check that, if we have a counterparty connection id, then it matches the one in the message. - let counterparty_matches = - if let Some(counterparty_connection_id) = conn_end.counterparty().connection_id() { - &msg.counterparty_connection_id == counterparty_connection_id - } else { - true - }; + && conn_end.versions().get(0).eq(&Some(&msg.version)); - if !state_is_consistent || !counterparty_matches { + if !state_is_consistent { // Old connection end is in incorrect state, propagate the error. - return Err(Error::connection_mismatch(msg.connection_id().clone())); + return Err(Error::connection_mismatch(msg.connection_id)); } + // Set the connection ID of the counterparty + let prev_counterparty = conn_end.counterparty(); + let counterparty = Counterparty::new( + prev_counterparty.client_id().clone(), + Some(msg.connection_id.clone()), + prev_counterparty.prefix().clone(), + ); + conn_end.set_state(State::Open); + conn_end.set_version(msg.version.clone()); + conn_end.set_counterparty(counterparty); + + // The counterparty is the local chain. + let counterparty = Counterparty::new( + conn_end.client_id().clone(), // The local client identifier. + Some(msg.counterparty_connection_id.clone()), // This chain's connection id as known on counterparty. + ctx.commitment_prefix(), // Local commitment prefix. + ); + // Proof verification. let expected_conn = ConnectionEnd::new( State::TryOpen, conn_end.counterparty().client_id().clone(), - Counterparty::new( - // The counterparty is the local chain. - conn_end.client_id().clone(), // The local client identifier. - Some(msg.counterparty_connection_id().clone()), // This chain's connection id as known on counterparty. - ctx.commitment_prefix(), // Local commitment prefix. - ), - vec![msg.version().clone()], + counterparty, + vec![msg.version.clone()], conn_end.delay_period(), ); // 2. Pass the details to the verification function. verify_proofs( ctx, - msg.client_state(), + msg.client_state.clone(), + msg.proofs.height(), &conn_end, &expected_conn, - msg.proofs(), + &msg.proofs, )?; output.log("success: connection verification passed"); - conn_end.set_state(State::Open); - conn_end.set_version(msg.version().clone()); - - // TODO! after need to remove - let counterparty = Counterparty::new( - conn_end.counterparty().client_id().clone(), - Some(msg.counterparty_connection_id().clone()), - ctx.commitment_prefix(), - ); - conn_end.set_counterparty(counterparty); - let result = ConnectionResult { - connection_id: msg.connection_id().clone(), + connection_id: msg.connection_id.clone(), connection_id_state: ConnectionIdState::Reused, connection_end: conn_end.clone(), }; @@ -89,7 +87,7 @@ pub(crate) fn process( let event_attributes = Attributes { height: ctx.host_current_height().clone(), - connection_id: Some(msg.connection_id().clone()), + connection_id: Some(msg.connection_id), client_id: conn_end.client_id().clone(), counterparty_client_id: conn_end.counterparty().client_id.clone(), counterparty_connection_id: conn_end.counterparty().connection_id.clone(), @@ -102,19 +100,19 @@ pub(crate) fn process( #[cfg(test)] mod tests { use crate::prelude::*; - use core::convert::TryFrom; + use core::str::FromStr; - use test_env_log::test; + use test_log::test; + use crate::core::ics03_connection::connection::{ConnectionEnd, Counterparty, State}; + use crate::core::ics03_connection::error; + use crate::core::ics03_connection::handler::{dispatch, ConnectionResult}; + use crate::core::ics03_connection::msgs::conn_open_ack::test_util::get_dummy_raw_msg_conn_open_ack; + use crate::core::ics03_connection::msgs::conn_open_ack::MsgConnectionOpenAck; + use crate::core::ics03_connection::msgs::ConnectionMsg; + use crate::core::ics23_commitment::commitment::CommitmentPrefix; + use crate::core::ics24_host::identifier::{ChainId, ClientId}; use crate::events::IbcEvent; - use crate::ics03_connection::connection::{ConnectionEnd, Counterparty, State}; - use crate::ics03_connection::error; - use crate::ics03_connection::handler::{dispatch, ConnectionResult}; - use crate::ics03_connection::msgs::conn_open_ack::test_util::get_dummy_raw_msg_conn_open_ack; - use crate::ics03_connection::msgs::conn_open_ack::MsgConnectionOpenAck; - use crate::ics03_connection::msgs::ConnectionMsg; - use crate::ics23_commitment::commitment::CommitmentPrefix; - use crate::ics24_host::identifier::{ChainId, ClientId}; use crate::mock::context::MockContext; use crate::mock::host::HostType; use crate::timestamp::ZERO_DURATION; @@ -154,10 +152,10 @@ mod tests { client_id.clone(), Counterparty::new( client_id.clone(), - Some(msg_ack.counterparty_connection_id().clone()), - CommitmentPrefix::from(b"ibc".to_vec()), + Some(msg_ack.counterparty_connection_id.clone()), + CommitmentPrefix::try_from(b"ibc".to_vec()).unwrap(), ), - vec![msg_ack.version().clone()], + vec![msg_ack.version.clone()], ZERO_DURATION, ); @@ -165,16 +163,6 @@ mod tests { let mut conn_end_open = default_conn_end.clone(); conn_end_open.set_state(State::Open); // incorrect field - // A connection end with correct state, but incorrect prefix for the - // counterparty; will be part of the context to exercise unsuccessful path. - let mut conn_end_prefix = conn_end_open.clone(); - conn_end_prefix.set_state(State::Init); - conn_end_prefix.set_counterparty(Counterparty::new( - client_id.clone(), - Some(msg_ack.counterparty_connection_id().clone()), - CommitmentPrefix::from(Vec::new()), // incorrect field - )); - let tests: Vec = vec![ Test { name: "Successful processing of an Ack message".to_string(), @@ -184,70 +172,46 @@ mod tests { .with_connection(conn_id.clone(), default_conn_end), msg: ConnectionMsg::ConnectionOpenAck(Box::new(msg_ack.clone())), want_pass: true, - match_error: Box::new(|_| { - panic!("should not have error") - }), + match_error: Box::new(|_| panic!("should not have error")), }, Test { - name: "Processing fails because the connection does not exist in the context".to_string(), + name: "Processing fails because the connection does not exist in the context" + .to_string(), ctx: default_context.clone(), msg: ConnectionMsg::ConnectionOpenAck(Box::new(msg_ack.clone())), want_pass: false, match_error: { let connection_id = conn_id.clone(); - Box::new(move |e| { - match e.detail() { - error::ErrorDetail::ConnectionNotFound(e) => { - assert_eq!(e.connection_id, connection_id) - } - _ => { - panic!("Expected ConnectionNotFound error"); - } + Box::new(move |e| match e.detail() { + error::ErrorDetail::ConnectionNotFound(e) => { + assert_eq!(e.connection_id, connection_id) + } + _ => { + panic!("Expected ConnectionNotFound error"); } }) }, }, Test { - name: "Processing fails due to connections mismatch (incorrect 'open' state)".to_string(), + name: "Processing fails due to connections mismatch (incorrect 'open' state)" + .to_string(), ctx: default_context - .clone() .with_client(&client_id, proof_height) .with_connection(conn_id.clone(), conn_end_open), - msg: ConnectionMsg::ConnectionOpenAck(Box::new(msg_ack.clone())), + msg: ConnectionMsg::ConnectionOpenAck(Box::new(msg_ack)), want_pass: false, match_error: { - let connection_id = conn_id.clone(); - Box::new(move |e| { - match e.detail() { - error::ErrorDetail::ConnectionMismatch(e) => { - assert_eq!(e.connection_id, connection_id); - } - _ => { - panic!("Expected ConnectionMismatch error"); - } + let connection_id = conn_id; + Box::new(move |e| match e.detail() { + error::ErrorDetail::ConnectionMismatch(e) => { + assert_eq!(e.connection_id, connection_id); + } + _ => { + panic!("Expected ConnectionMismatch error"); } }) }, }, - Test { - name: "Processing fails: ConsensusStateVerificationFailure due to empty counterparty prefix".to_string(), - ctx: default_context - .with_client(&client_id, proof_height) - .with_connection(conn_id, conn_end_prefix), - msg: ConnectionMsg::ConnectionOpenAck(Box::new(msg_ack)), - want_pass: false, - match_error: - Box::new(move |e| { - match e.detail() { - error::ErrorDetail::ConsensusStateVerificationFailure(e) => { - assert_eq!(e.height, proof_height) - } - _ => { - panic!("Expected ConsensusStateVerificationFailure error"); - } - } - }), - }, /* Test { name: "Processing fails due to MissingLocalConsensusState".to_string(), diff --git a/modules/src/ics03_connection/handler/conn_open_confirm.rs b/modules/src/core/ics03_connection/handler/conn_open_confirm.rs similarity index 74% rename from modules/src/ics03_connection/handler/conn_open_confirm.rs rename to modules/src/core/ics03_connection/handler/conn_open_confirm.rs index 2567833cf..4f2f91370 100644 --- a/modules/src/ics03_connection/handler/conn_open_confirm.rs +++ b/modules/src/core/ics03_connection/handler/conn_open_confirm.rs @@ -1,14 +1,14 @@ //! Protocol logic specific to processing ICS3 messages of type `MsgConnectionOpenConfirm`. +use crate::core::ics03_connection::connection::{ConnectionEnd, Counterparty, State}; +use crate::core::ics03_connection::context::ConnectionReader; +use crate::core::ics03_connection::error::Error; +use crate::core::ics03_connection::events::Attributes; +use crate::core::ics03_connection::handler::verify::verify_proofs; +use crate::core::ics03_connection::handler::{ConnectionIdState, ConnectionResult}; +use crate::core::ics03_connection::msgs::conn_open_confirm::MsgConnectionOpenConfirm; use crate::events::IbcEvent; use crate::handler::{HandlerOutput, HandlerResult}; -use crate::ics03_connection::connection::{ConnectionEnd, Counterparty, State}; -use crate::ics03_connection::context::ConnectionReader; -use crate::ics03_connection::error::Error; -use crate::ics03_connection::events::Attributes; -use crate::ics03_connection::handler::verify::verify_proofs; -use crate::ics03_connection::handler::{ConnectionIdState, ConnectionResult}; -use crate::ics03_connection::msgs::conn_open_confirm::MsgConnectionOpenConfirm; use crate::prelude::*; pub(crate) fn process( @@ -18,11 +18,11 @@ pub(crate) fn process( let mut output = HandlerOutput::builder(); // Validate the connection end. - let mut conn_end = ctx.connection_end(msg.connection_id())?; + let mut conn_end = ctx.connection_end(&msg.connection_id)?; // A connection end must be in TryOpen state; otherwise return error. if !conn_end.state_matches(&State::TryOpen) { // Old connection end is in incorrect state, propagate the error. - return Err(Error::connection_mismatch(msg.connection_id().clone())); + return Err(Error::connection_mismatch(msg.connection_id)); } // Verify proofs. Assemble the connection end as we expect to find it on the counterparty. @@ -32,15 +32,22 @@ pub(crate) fn process( Counterparty::new( // The counterparty is the local chain. conn_end.client_id().clone(), // The local client identifier. - Some(msg.connection_id().clone()), // Local connection id. + Some(msg.connection_id.clone()), // Local connection id. ctx.commitment_prefix(), // Local commitment prefix. ), - conn_end.versions(), + conn_end.versions().to_vec(), conn_end.delay_period(), ); // 2. Pass the details to the verification function. - verify_proofs(ctx, None, &conn_end, &expected_conn, msg.proofs())?; + verify_proofs( + ctx, + None, + msg.proofs.height(), + &conn_end, + &expected_conn, + &msg.proofs, + )?; output.log("success: connection verification passed"); @@ -48,7 +55,7 @@ pub(crate) fn process( conn_end.set_state(State::Open); let result = ConnectionResult { - connection_id: msg.connection_id().clone(), + connection_id: msg.connection_id.clone(), connection_id_state: ConnectionIdState::Reused, connection_end: conn_end.clone(), }; @@ -59,7 +66,7 @@ pub(crate) fn process( let event_attributes = Attributes { height: ctx.host_current_height().clone(), - connection_id: Some(msg.connection_id().clone()), + connection_id: Some(msg.connection_id), client_id: conn_end.client_id().clone(), counterparty_client_id: conn_end.counterparty().client_id.clone(), counterparty_connection_id: conn_end.counterparty().connection_id.clone(), @@ -72,19 +79,19 @@ pub(crate) fn process( #[cfg(test)] mod tests { use crate::prelude::*; - use core::convert::TryFrom; - use core::str::FromStr; - use test_env_log::test; + use core::str::FromStr; + use test_log::test; + + use crate::core::ics03_connection::connection::{ConnectionEnd, Counterparty, State}; + use crate::core::ics03_connection::context::ConnectionReader; + use crate::core::ics03_connection::handler::{dispatch, ConnectionResult}; + use crate::core::ics03_connection::msgs::conn_open_confirm::test_util::get_dummy_raw_msg_conn_open_confirm; + use crate::core::ics03_connection::msgs::conn_open_confirm::MsgConnectionOpenConfirm; + use crate::core::ics03_connection::msgs::ConnectionMsg; + use crate::core::ics23_commitment::commitment::CommitmentPrefix; + use crate::core::ics24_host::identifier::ClientId; use crate::events::IbcEvent; - use crate::ics03_connection::connection::{ConnectionEnd, Counterparty, State}; - use crate::ics03_connection::context::ConnectionReader; - use crate::ics03_connection::handler::{dispatch, ConnectionResult}; - use crate::ics03_connection::msgs::conn_open_confirm::test_util::get_dummy_raw_msg_conn_open_confirm; - use crate::ics03_connection::msgs::conn_open_confirm::MsgConnectionOpenConfirm; - use crate::ics03_connection::msgs::ConnectionMsg; - use crate::ics23_commitment::commitment::CommitmentPrefix; - use crate::ics24_host::identifier::ClientId; use crate::mock::context::MockContext; use crate::timestamp::ZERO_DURATION; use crate::Height; @@ -103,8 +110,8 @@ mod tests { MsgConnectionOpenConfirm::try_from(get_dummy_raw_msg_conn_open_confirm()).unwrap(); let counterparty = Counterparty::new( client_id.clone(), - Some(msg_confirm.connection_id().clone()), - CommitmentPrefix::from(Vec::new()), + Some(msg_confirm.connection_id.clone()), + CommitmentPrefix::try_from(b"ibc".to_vec()).unwrap(), ); let context = MockContext::default(); @@ -132,10 +139,7 @@ mod tests { ctx: context .clone() .with_client(&client_id, Height::new(0, 10)) - .with_connection( - msg_confirm.connection_id().clone(), - incorrect_conn_end_state, - ), + .with_connection(msg_confirm.connection_id.clone(), incorrect_conn_end_state), msg: ConnectionMsg::ConnectionOpenConfirm(msg_confirm.clone()), want_pass: false, }, @@ -143,8 +147,8 @@ mod tests { name: "Processing successful".to_string(), ctx: context .with_client(&client_id, Height::new(0, 10)) - .with_connection(msg_confirm.connection_id().clone(), correct_conn_end), - msg: ConnectionMsg::ConnectionOpenConfirm(msg_confirm.clone()), + .with_connection(msg_confirm.connection_id.clone(), correct_conn_end), + msg: ConnectionMsg::ConnectionOpenConfirm(msg_confirm), want_pass: true, }, ] diff --git a/modules/src/ics03_connection/handler/conn_open_init.rs b/modules/src/core/ics03_connection/handler/conn_open_init.rs similarity index 79% rename from modules/src/ics03_connection/handler/conn_open_init.rs rename to modules/src/core/ics03_connection/handler/conn_open_init.rs index 0917d17e3..4822feec1 100644 --- a/modules/src/ics03_connection/handler/conn_open_init.rs +++ b/modules/src/core/ics03_connection/handler/conn_open_init.rs @@ -1,14 +1,14 @@ //! Protocol logic specific to ICS3 messages of type `MsgConnectionOpenInit`. +use crate::core::ics03_connection::connection::{ConnectionEnd, State}; +use crate::core::ics03_connection::context::ConnectionReader; +use crate::core::ics03_connection::error::Error; +use crate::core::ics03_connection::events::Attributes; +use crate::core::ics03_connection::handler::{ConnectionIdState, ConnectionResult}; +use crate::core::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; +use crate::core::ics24_host::identifier::ConnectionId; use crate::events::IbcEvent; use crate::handler::{HandlerOutput, HandlerResult}; -use crate::ics03_connection::connection::{ConnectionEnd, State}; -use crate::ics03_connection::context::ConnectionReader; -use crate::ics03_connection::error::Error; -use crate::ics03_connection::events::Attributes; -use crate::ics03_connection::handler::{ConnectionIdState, ConnectionResult}; -use crate::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; -use crate::ics24_host::identifier::ConnectionId; use crate::prelude::*; pub(crate) fn process( @@ -18,12 +18,12 @@ pub(crate) fn process( let mut output = HandlerOutput::builder(); // An IBC client running on the local (host) chain should exist. - ctx.client_state(msg.client_id())?; + ctx.client_state(&msg.client_id)?; let new_connection_end = ConnectionEnd::new( State::Init, - msg.client_id().clone(), - msg.counterparty().clone(), + msg.client_id.clone(), + msg.counterparty.clone(), ctx.get_compatible_versions(), msg.delay_period, ); @@ -62,15 +62,15 @@ pub(crate) fn process( #[cfg(test)] mod tests { use crate::prelude::*; - use core::convert::TryFrom; - use test_env_log::test; + use test_log::test; + + use crate::core::ics03_connection::connection::State; + use crate::core::ics03_connection::handler::{dispatch, ConnectionResult}; + use crate::core::ics03_connection::msgs::conn_open_init::test_util::get_dummy_raw_msg_conn_open_init; + use crate::core::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; + use crate::core::ics03_connection::msgs::ConnectionMsg; use crate::events::IbcEvent; - use crate::ics03_connection::connection::State; - use crate::ics03_connection::handler::{dispatch, ConnectionResult}; - use crate::ics03_connection::msgs::conn_open_init::test_util::get_dummy_raw_msg_conn_open_init; - use crate::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; - use crate::ics03_connection::msgs::ConnectionMsg; use crate::mock::context::MockContext; use crate::Height; @@ -96,7 +96,7 @@ mod tests { }, Test { name: "Good parameters".to_string(), - ctx: context.with_client(msg_conn_init.client_id(), Height::new(0, 10)), + ctx: context.with_client(&msg_conn_init.client_id, Height::new(0, 10)), msg: ConnectionMsg::ConnectionOpenInit(msg_conn_init.clone()), want_pass: true, }, diff --git a/modules/src/ics03_connection/handler/conn_open_try.rs b/modules/src/core/ics03_connection/handler/conn_open_try.rs similarity index 80% rename from modules/src/ics03_connection/handler/conn_open_try.rs rename to modules/src/core/ics03_connection/handler/conn_open_try.rs index afa4d040b..74ec304ab 100644 --- a/modules/src/ics03_connection/handler/conn_open_try.rs +++ b/modules/src/core/ics03_connection/handler/conn_open_try.rs @@ -1,15 +1,17 @@ //! Protocol logic specific to processing ICS3 messages of type `MsgConnectionOpenTry`. +use crate::core::ics03_connection::connection::{ConnectionEnd, Counterparty, State}; +use crate::core::ics03_connection::context::ConnectionReader; +use crate::core::ics03_connection::error::Error; +use crate::core::ics03_connection::events::Attributes; +use crate::core::ics03_connection::handler::verify::{ + check_client_consensus_height, verify_proofs, +}; +use crate::core::ics03_connection::handler::{ConnectionIdState, ConnectionResult}; +use crate::core::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; +use crate::core::ics24_host::identifier::ConnectionId; use crate::events::IbcEvent; use crate::handler::{HandlerOutput, HandlerResult}; -use crate::ics03_connection::connection::{ConnectionEnd, Counterparty, State}; -use crate::ics03_connection::context::ConnectionReader; -use crate::ics03_connection::error::Error; -use crate::ics03_connection::events::Attributes; -use crate::ics03_connection::handler::verify::{check_client_consensus_height, verify_proofs}; -use crate::ics03_connection::handler::{ConnectionIdState, ConnectionResult}; -use crate::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; -use crate::ics24_host::identifier::ConnectionId; use crate::prelude::*; pub(crate) fn process( @@ -23,15 +25,15 @@ pub(crate) fn process( // check_client_consensus_height(ctx, msg.consensus_height())?; // Unwrap the old connection end (if any) and its identifier. - let (mut new_connection_end, conn_id) = match msg.previous_connection_id() { + let (mut new_connection_end, conn_id) = match &msg.previous_connection_id { // A connection with this id should already exist. Search & validate. Some(prev_id) => { let old_connection_end = ctx.connection_end(prev_id)?; // Validate that existing connection end matches with the one we're trying to establish. if old_connection_end.state_matches(&State::Init) - && old_connection_end.counterparty_matches(&msg.counterparty()) - && old_connection_end.client_id_matches(msg.client_id()) + && old_connection_end.counterparty_matches(&msg.counterparty) + && old_connection_end.client_id_matches(&msg.client_id) && old_connection_end.delay_period() == msg.delay_period { // A ConnectionEnd already exists and all validation passed. @@ -50,9 +52,9 @@ pub(crate) fn process( // Build a new connection end as well as an identifier. let conn_end = ConnectionEnd::new( State::Init, - msg.client_id().clone(), - msg.counterparty(), - msg.counterparty_versions(), + msg.client_id.clone(), + msg.counterparty.clone(), + msg.counterparty_versions.clone(), msg.delay_period, ); let id_counter = ctx.connection_counter()?; @@ -70,27 +72,30 @@ pub(crate) fn process( // 1. Setup: build the ConnectionEnd as we expect to find it on the other party. let expected_conn = ConnectionEnd::new( State::Init, - msg.counterparty().client_id().clone(), - Counterparty::new(msg.client_id().clone(), None, ctx.commitment_prefix()), - msg.counterparty_versions(), + msg.counterparty.client_id().clone(), + Counterparty::new(msg.client_id.clone(), None, ctx.commitment_prefix()), + msg.counterparty_versions.clone(), msg.delay_period, ); // 2. Pass the details to the verification function. verify_proofs( ctx, - msg.client_state(), + msg.client_state.clone(), + msg.proofs.height(), &new_connection_end, &expected_conn, - msg.proofs(), + &msg.proofs, )?; // Transition the connection end to the new state & pick a version. new_connection_end.set_state(State::TryOpen); // Pick the version. - new_connection_end - .set_version(ctx.pick_version(ctx.get_compatible_versions(), msg.counterparty_versions())?); + new_connection_end.set_version(ctx.pick_version( + ctx.get_compatible_versions(), + msg.counterparty_versions.clone(), + )?); assert_eq!(new_connection_end.versions().len(), 1); @@ -122,16 +127,16 @@ pub(crate) fn process( #[cfg(test)] mod tests { use crate::prelude::*; - use core::convert::TryFrom; - use test_env_log::test; + use test_log::test; + + use crate::core::ics03_connection::connection::State; + use crate::core::ics03_connection::handler::{dispatch, ConnectionResult}; + use crate::core::ics03_connection::msgs::conn_open_try::test_util::get_dummy_raw_msg_conn_open_try; + use crate::core::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; + use crate::core::ics03_connection::msgs::ConnectionMsg; + use crate::core::ics24_host::identifier::ChainId; use crate::events::IbcEvent; - use crate::ics03_connection::connection::State; - use crate::ics03_connection::handler::{dispatch, ConnectionResult}; - use crate::ics03_connection::msgs::conn_open_try::test_util::get_dummy_raw_msg_conn_open_try; - use crate::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; - use crate::ics03_connection::msgs::ConnectionMsg; - use crate::ics24_host::identifier::ChainId; use crate::mock::context::MockContext; use crate::mock::host::HostType; use crate::Height; @@ -207,19 +212,19 @@ mod tests { }, Test { name: "Processing fails because the client misses the consensus state targeted by the proof".to_string(), - ctx: context.clone().with_client(msg_proof_height_missing.client_id(), Height::new(0, client_consensus_state_height)), + ctx: context.clone().with_client(&msg_proof_height_missing.client_id, Height::new(0, client_consensus_state_height)), msg: ConnectionMsg::ConnectionOpenTry(Box::new(msg_proof_height_missing)), want_pass: false, }, Test { name: "Good parameters but has previous_connection_id".to_string(), - ctx: context.clone().with_client(msg_conn_try.client_id(), Height::new(0, client_consensus_state_height)), + ctx: context.clone().with_client(&msg_conn_try.client_id, Height::new(0, client_consensus_state_height)), msg: ConnectionMsg::ConnectionOpenTry(Box::new(msg_conn_try.clone())), want_pass: false, }, Test { name: "Good parameters".to_string(), - ctx: context.with_client(msg_conn_try.client_id(), Height::new(0, client_consensus_state_height)), + ctx: context.with_client(&msg_conn_try.client_id, Height::new(0, client_consensus_state_height)), msg: ConnectionMsg::ConnectionOpenTry(Box::new(msg_conn_try.with_previous_connection_id(None))), want_pass: true, }, diff --git a/modules/src/ics03_connection/handler/verify.rs b/modules/src/core/ics03_connection/handler/verify.rs similarity index 84% rename from modules/src/ics03_connection/handler/verify.rs rename to modules/src/core/ics03_connection/handler/verify.rs index f3ce3a726..71e6ee65d 100644 --- a/modules/src/ics03_connection/handler/verify.rs +++ b/modules/src/core/ics03_connection/handler/verify.rs @@ -1,12 +1,12 @@ //! ICS3 verification functions, common across all four handlers of ICS3. -use crate::ics02_client::client_consensus::ConsensusState; -use crate::ics02_client::client_state::{AnyClientState, ClientState}; -use crate::ics02_client::{client_def::AnyClient, client_def::ClientDef}; -use crate::ics03_connection::connection::ConnectionEnd; -use crate::ics03_connection::context::ConnectionReader; -use crate::ics03_connection::error::Error; -use crate::ics23_commitment::commitment::CommitmentProofBytes; +use crate::core::ics02_client::client_consensus::ConsensusState; +use crate::core::ics02_client::client_state::{AnyClientState, ClientState}; +use crate::core::ics02_client::{client_def::AnyClient, client_def::ClientDef}; +use crate::core::ics03_connection::connection::ConnectionEnd; +use crate::core::ics03_connection::context::ConnectionReader; +use crate::core::ics03_connection::error::Error; +use crate::core::ics23_commitment::commitment::CommitmentProofBytes; use crate::proofs::{ConsensusProof, Proofs}; use crate::Height; @@ -14,12 +14,14 @@ use crate::Height; pub fn verify_proofs( ctx: &dyn ConnectionReader, client_state: Option, + height: Height, connection_end: &ConnectionEnd, expected_conn: &ConnectionEnd, proofs: &Proofs, ) -> Result<(), Error> { verify_connection_proof( ctx, + height, connection_end, expected_conn, proofs.height(), @@ -30,6 +32,7 @@ pub fn verify_proofs( if let Some(expected_client_state) = client_state { verify_client_proof( ctx, + height, connection_end, expected_client_state, proofs.height(), @@ -42,12 +45,7 @@ pub fn verify_proofs( // If a consensus proof is attached to the message, then verify it. if let Some(proof) = proofs.consensus_proof() { - Ok(verify_consensus_proof( - ctx, - connection_end, - proofs.height(), - &proof, - )?) + Ok(verify_consensus_proof(ctx, height, connection_end, &proof)?) } else { Ok(()) } @@ -58,6 +56,7 @@ pub fn verify_proofs( /// which created this proof). This object must match the state of `expected_conn`. pub fn verify_connection_proof( ctx: &dyn ConnectionReader, + height: Height, connection_end: &ConnectionEnd, expected_conn: &ConnectionEnd, proof_height: Height, @@ -72,20 +71,26 @@ pub fn verify_connection_proof( } // The client must have the consensus state for the height where this proof was created. - ctx.client_consensus_state(connection_end.client_id(), proof_height)?; + let consensus_state = ctx.client_consensus_state(connection_end.client_id(), proof_height)?; + + // A counterparty connection id of None causes `unwrap()` below and indicates an internal + // error as this is the connection id on the counterparty chain that must always be present. + let connection_id = connection_end + .counterparty() + .connection_id() + .ok_or_else(Error::invalid_counterparty)?; let client_def = AnyClient::from_client_type(client_state.client_type()); // Verify the proof for the connection state against the expected connection end. - // A counterparty connection id of None causes `unwrap()` below and indicates an internal - // error as this is the connection id on the counterparty chain that must always be present. client_def .verify_connection_state( &client_state, - proof_height, + height, connection_end.counterparty().prefix(), proof, - connection_end.counterparty().connection_id(), + consensus_state.root(), + connection_id, expected_conn, ) .map_err(Error::verify_connection_state) @@ -100,6 +105,7 @@ pub fn verify_connection_proof( /// `proof` is correct. pub fn verify_client_proof( ctx: &dyn ConnectionReader, + height: Height, connection_end: &ConnectionEnd, expected_client_state: AnyClientState, proof_height: Height, @@ -119,11 +125,11 @@ pub fn verify_client_proof( client_def .verify_client_full_state( &client_state, - proof_height, - consensus_state.root(), + height, connection_end.counterparty().prefix(), - connection_end.counterparty().client_id(), proof, + consensus_state.root(), + connection_end.counterparty().client_id(), &expected_client_state, ) .map_err(|e| { @@ -133,8 +139,8 @@ pub fn verify_client_proof( pub fn verify_consensus_proof( ctx: &dyn ConnectionReader, + height: Height, connection_end: &ConnectionEnd, - proof_height: Height, proof: &ConsensusProof, ) -> Result<(), Error> { // Fetch the client state (IBC client on the local chain). @@ -147,14 +153,17 @@ pub fn verify_consensus_proof( // Fetch the expected consensus state from the historical (local) header data. let expected_consensus = ctx.host_consensus_state(proof.height())?; + let consensus_state = ctx.client_consensus_state(connection_end.client_id(), height)?; + let client = AnyClient::from_client_type(client_state.client_type()); client .verify_client_consensus_state( &client_state, - proof_height, + height, connection_end.counterparty().prefix(), proof.proof(), + consensus_state.root(), connection_end.counterparty().client_id(), proof.height(), &expected_consensus, diff --git a/modules/src/ics03_connection/mod.rs b/modules/src/core/ics03_connection/mod.rs similarity index 65% rename from modules/src/ics03_connection/mod.rs rename to modules/src/core/ics03_connection/mod.rs index 696f43e07..b3e9cf77c 100644 --- a/modules/src/ics03_connection/mod.rs +++ b/modules/src/core/ics03_connection/mod.rs @@ -1,4 +1,5 @@ -//! ICS 03: IBC Connection implementation +//! ICS 03: Connection implementation for connecting a client +//! on the local chain with a client on a remote chain. pub mod connection; /// Context definitions (dependencies for the protocol). diff --git a/modules/src/ics03_connection/msgs.rs b/modules/src/core/ics03_connection/msgs.rs similarity index 82% rename from modules/src/ics03_connection/msgs.rs rename to modules/src/core/ics03_connection/msgs.rs index 1eac2293c..9fd860b36 100644 --- a/modules/src/ics03_connection/msgs.rs +++ b/modules/src/core/ics03_connection/msgs.rs @@ -12,10 +12,10 @@ //! Another difference to ICS3 specs is that each message comprises an additional field called //! `signer` which is specific to Cosmos-SDK. -use crate::ics03_connection::msgs::conn_open_ack::MsgConnectionOpenAck; -use crate::ics03_connection::msgs::conn_open_confirm::MsgConnectionOpenConfirm; -use crate::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; -use crate::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; +use crate::core::ics03_connection::msgs::conn_open_ack::MsgConnectionOpenAck; +use crate::core::ics03_connection::msgs::conn_open_confirm::MsgConnectionOpenConfirm; +use crate::core::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; +use crate::core::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; use alloc::boxed::Box; pub mod conn_open_ack; @@ -35,7 +35,7 @@ pub enum ConnectionMsg { #[cfg(test)] pub mod test_util { - use crate::ics24_host::identifier::{ClientId, ConnectionId}; + use crate::core::ics24_host::identifier::{ClientId, ConnectionId}; use crate::prelude::*; use ibc_proto::ibc::core::commitment::v1::MerklePrefix; use ibc_proto::ibc::core::connection::v1::Counterparty as RawCounterparty; diff --git a/modules/src/ics03_connection/msgs/conn_open_ack.rs b/modules/src/core/ics03_connection/msgs/conn_open_ack.rs similarity index 81% rename from modules/src/ics03_connection/msgs/conn_open_ack.rs rename to modules/src/core/ics03_connection/msgs/conn_open_ack.rs index e8bdaf062..d27efc33c 100644 --- a/modules/src/ics03_connection/msgs/conn_open_ack.rs +++ b/modules/src/core/ics03_connection/msgs/conn_open_ack.rs @@ -1,13 +1,13 @@ use crate::prelude::*; -use core::convert::{TryFrom, TryInto}; + use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenAck as RawMsgConnectionOpenAck; use tendermint_proto::Protobuf; -use crate::ics02_client::client_state::AnyClientState; -use crate::ics03_connection::error::Error; -use crate::ics03_connection::version::Version; -use crate::ics23_commitment::commitment::CommitmentProofBytes; -use crate::ics24_host::identifier::ConnectionId; +use crate::core::ics02_client::client_state::AnyClientState; +use crate::core::ics03_connection::error::Error; +use crate::core::ics03_connection::version::Version; +use crate::core::ics23_commitment::commitment::CommitmentProofBytes; +use crate::core::ics24_host::identifier::ConnectionId; use crate::proofs::{ConsensusProof, Proofs}; use crate::signer::Signer; use crate::tx_msg::Msg; @@ -27,31 +27,6 @@ pub struct MsgConnectionOpenAck { } impl MsgConnectionOpenAck { - /// Getter for accessing the connection identifier of this message. - pub fn connection_id(&self) -> &ConnectionId { - &self.connection_id - } - - /// Getter for accessing the counterparty's connection identifier from this message. - pub fn counterparty_connection_id(&self) -> &ConnectionId { - &self.counterparty_connection_id - } - - /// Getter for accessing the client state. - pub fn client_state(&self) -> Option { - self.client_state.clone() - } - - /// Getter for accessing (borrow) the proofs in this message. - pub fn proofs(&self) -> &Proofs { - &self.proofs - } - - /// Getter for the version field. - pub fn version(&self) -> &Version { - &self.version - } - /// Getter for accessing the `consensus_height` field from this message. Returns the special /// value `Height(0)` if this field is not set. pub fn consensus_height(&self) -> Height { @@ -85,17 +60,21 @@ impl TryFrom for MsgConnectionOpenAck { .consensus_height .ok_or_else(Error::missing_consensus_height)? .into(); - let consensus_proof_obj = ConsensusProof::new(msg.proof_consensus.into(), consensus_height) - .map_err(Error::invalid_proof)?; + let consensus_proof_obj = ConsensusProof::new( + msg.proof_consensus + .try_into() + .map_err(Error::invalid_proof)?, + consensus_height, + ) + .map_err(Error::invalid_proof)?; let proof_height = msg .proof_height .ok_or_else(Error::missing_proof_height)? .into(); - let client_proof = Some(msg.proof_client) - .filter(|x| !x.is_empty()) - .map(CommitmentProofBytes::from); + let client_proof = + CommitmentProofBytes::try_from(msg.proof_client).map_err(Error::invalid_proof)?; Ok(Self { connection_id: msg @@ -113,8 +92,8 @@ impl TryFrom for MsgConnectionOpenAck { .map_err(Error::ics02_client)?, version: msg.version.ok_or_else(Error::empty_versions)?.try_into()?, proofs: Proofs::new( - msg.proof_try.into(), - client_proof, + msg.proof_try.try_into().map_err(Error::invalid_proof)?, + Some(client_proof), Option::from(consensus_proof_obj), None, proof_height, @@ -160,8 +139,8 @@ pub mod test_util { use ibc_proto::ibc::core::client::v1::Height; use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenAck as RawMsgConnectionOpenAck; - use crate::ics03_connection::version::Version; - use crate::ics24_host::identifier::ConnectionId; + use crate::core::ics03_connection::version::Version; + use crate::core::ics24_host::identifier::ConnectionId; use crate::test_utils::{get_dummy_bech32_account, get_dummy_proof}; pub fn get_dummy_raw_msg_conn_open_ack( @@ -182,7 +161,7 @@ pub mod test_util { revision_height: consensus_height, }), client_state: None, - proof_client: Vec::new(), + proof_client: get_dummy_proof(), version: Some(Version::default().into()), signer: get_dummy_bech32_account(), } @@ -192,14 +171,14 @@ pub mod test_util { #[cfg(test)] mod tests { use crate::prelude::*; - use core::convert::TryFrom; - use test_env_log::test; + + use test_log::test; use ibc_proto::ibc::core::client::v1::Height; use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenAck as RawMsgConnectionOpenAck; - use crate::ics03_connection::msgs::conn_open_ack::test_util::get_dummy_raw_msg_conn_open_ack; - use crate::ics03_connection::msgs::conn_open_ack::MsgConnectionOpenAck; + use crate::core::ics03_connection::msgs::conn_open_ack::test_util::get_dummy_raw_msg_conn_open_ack; + use crate::core::ics03_connection::msgs::conn_open_ack::MsgConnectionOpenAck; #[test] fn parse_connection_open_ack_msg() { diff --git a/modules/src/ics03_connection/msgs/conn_open_confirm.rs b/modules/src/core/ics03_connection/msgs/conn_open_confirm.rs similarity index 85% rename from modules/src/ics03_connection/msgs/conn_open_confirm.rs rename to modules/src/core/ics03_connection/msgs/conn_open_confirm.rs index c174670b7..3044a6b8f 100644 --- a/modules/src/ics03_connection/msgs/conn_open_confirm.rs +++ b/modules/src/core/ics03_connection/msgs/conn_open_confirm.rs @@ -1,12 +1,11 @@ use crate::prelude::*; -use core::convert::TryFrom; use tendermint_proto::Protobuf; use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenConfirm as RawMsgConnectionOpenConfirm; -use crate::ics03_connection::error::Error; -use crate::ics24_host::identifier::ConnectionId; +use crate::core::ics03_connection::error::Error; +use crate::core::ics24_host::identifier::ConnectionId; use crate::proofs::Proofs; use crate::signer::Signer; use crate::tx_msg::Msg; @@ -23,18 +22,6 @@ pub struct MsgConnectionOpenConfirm { pub signer: Signer, } -impl MsgConnectionOpenConfirm { - /// Getter for accessing the connection identifier of this message. - pub fn connection_id(&self) -> &ConnectionId { - &self.connection_id - } - - /// Getter for accessing (borrow) the proofs in this message. - pub fn proofs(&self) -> &Proofs { - &self.proofs - } -} - impl Msg for MsgConnectionOpenConfirm { type ValidationError = Error; type Raw = RawMsgConnectionOpenConfirm; @@ -64,8 +51,14 @@ impl TryFrom for MsgConnectionOpenConfirm { .connection_id .parse() .map_err(Error::invalid_identifier)?, - proofs: Proofs::new(msg.proof_ack.into(), None, None, None, proof_height) - .map_err(Error::invalid_proof)?, + proofs: Proofs::new( + msg.proof_ack.try_into().map_err(Error::invalid_proof)?, + None, + None, + None, + proof_height, + ) + .map_err(Error::invalid_proof)?, signer: msg.signer.into(), }) } @@ -106,14 +99,14 @@ pub mod test_util { #[cfg(test)] mod tests { use crate::prelude::*; - use core::convert::TryFrom; - use test_env_log::test; + + use test_log::test; use ibc_proto::ibc::core::client::v1::Height; use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenConfirm as RawMsgConnectionOpenConfirm; - use crate::ics03_connection::msgs::conn_open_confirm::test_util::get_dummy_raw_msg_conn_open_confirm; - use crate::ics03_connection::msgs::conn_open_confirm::MsgConnectionOpenConfirm; + use crate::core::ics03_connection::msgs::conn_open_confirm::test_util::get_dummy_raw_msg_conn_open_confirm; + use crate::core::ics03_connection::msgs::conn_open_confirm::MsgConnectionOpenConfirm; #[test] fn parse_connection_open_confirm_msg() { diff --git a/modules/src/ics03_connection/msgs/conn_open_init.rs b/modules/src/core/ics03_connection/msgs/conn_open_init.rs similarity index 80% rename from modules/src/ics03_connection/msgs/conn_open_init.rs rename to modules/src/core/ics03_connection/msgs/conn_open_init.rs index 18757f67f..1efdf95d1 100644 --- a/modules/src/ics03_connection/msgs/conn_open_init.rs +++ b/modules/src/core/ics03_connection/msgs/conn_open_init.rs @@ -1,14 +1,14 @@ use crate::prelude::*; -use core::convert::{TryFrom, TryInto}; + use core::time::Duration; use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenInit as RawMsgConnectionOpenInit; use tendermint_proto::Protobuf; -use crate::ics03_connection::connection::Counterparty; -use crate::ics03_connection::error::Error; -use crate::ics03_connection::version::Version; -use crate::ics24_host::identifier::ClientId; +use crate::core::ics03_connection::connection::Counterparty; +use crate::core::ics03_connection::error::Error; +use crate::core::ics03_connection::version::Version; +use crate::core::ics24_host::identifier::ClientId; use crate::signer::Signer; use crate::tx_msg::Msg; @@ -26,34 +26,6 @@ pub struct MsgConnectionOpenInit { pub signer: Signer, } -impl MsgConnectionOpenInit { - pub fn new( - client_id: ClientId, - counterparty: Counterparty, - version: Version, - delay_period: Duration, - signer: Signer, - ) -> Self { - Self { - client_id, - counterparty, - version, - delay_period, - signer, - } - } - - /// Getter: borrow the `client_id` from this message. - pub fn client_id(&self) -> &ClientId { - &self.client_id - } - - /// Getter: borrow the `counterparty` from this message. - pub fn counterparty(&self) -> &Counterparty { - &self.counterparty - } -} - impl Msg for MsgConnectionOpenInit { type ValidationError = Error; type Raw = RawMsgConnectionOpenInit; @@ -103,10 +75,10 @@ pub mod test_util { use crate::prelude::*; use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenInit as RawMsgConnectionOpenInit; - use crate::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; - use crate::ics03_connection::msgs::test_util::get_dummy_raw_counterparty; - use crate::ics03_connection::version::Version; - use crate::ics24_host::identifier::ClientId; + use crate::core::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; + use crate::core::ics03_connection::msgs::test_util::get_dummy_raw_counterparty; + use crate::core::ics03_connection::version::Version; + use crate::core::ics24_host::identifier::ClientId; use crate::test_utils::get_dummy_bech32_account; /// Extends the implementation with additional helper methods. @@ -133,15 +105,15 @@ pub mod test_util { #[cfg(test)] mod tests { use crate::prelude::*; - use core::convert::TryFrom; - use test_env_log::test; + + use test_log::test; use ibc_proto::ibc::core::connection::v1::Counterparty as RawCounterparty; use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenInit as RawMsgConnectionOpenInit; use super::MsgConnectionOpenInit; - use crate::ics03_connection::msgs::conn_open_init::test_util::get_dummy_raw_msg_conn_open_init; - use crate::ics03_connection::msgs::test_util::get_dummy_raw_counterparty; + use crate::core::ics03_connection::msgs::conn_open_init::test_util::get_dummy_raw_msg_conn_open_init; + use crate::core::ics03_connection::msgs::test_util::get_dummy_raw_counterparty; #[test] fn parse_connection_open_init_msg() { diff --git a/modules/src/ics03_connection/msgs/conn_open_try.rs b/modules/src/core/ics03_connection/msgs/conn_open_try.rs similarity index 84% rename from modules/src/ics03_connection/msgs/conn_open_try.rs rename to modules/src/core/ics03_connection/msgs/conn_open_try.rs index 7c8e583ed..3bdad32bb 100644 --- a/modules/src/ics03_connection/msgs/conn_open_try.rs +++ b/modules/src/core/ics03_connection/msgs/conn_open_try.rs @@ -9,12 +9,12 @@ use tendermint_proto::Protobuf; use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenTry as RawMsgConnectionOpenTry; -use crate::ics02_client::client_state::AnyClientState; -use crate::ics03_connection::connection::Counterparty; -use crate::ics03_connection::error::Error; -use crate::ics03_connection::version::Version; -use crate::ics23_commitment::commitment::CommitmentProofBytes; -use crate::ics24_host::identifier::{ClientId, ConnectionId}; +use crate::core::ics02_client::client_state::AnyClientState; +use crate::core::ics03_connection::connection::Counterparty; +use crate::core::ics03_connection::error::Error; +use crate::core::ics03_connection::version::Version; +use crate::core::ics23_commitment::commitment::CommitmentProofBytes; +use crate::core::ics24_host::identifier::{ClientId, ConnectionId}; use crate::proofs::{ConsensusProof, Proofs}; use crate::signer::Signer; use crate::tx_msg::Msg; @@ -38,36 +38,6 @@ pub struct MsgConnectionOpenTry { } impl MsgConnectionOpenTry { - /// Getter for accessing the previous connection identifier of this message. - pub fn previous_connection_id(&self) -> &Option { - &self.previous_connection_id - } - - /// Getter for accessing the client identifier from this message. - pub fn client_id(&self) -> &ClientId { - &self.client_id - } - - /// Getter for accessing the client state. - pub fn client_state(&self) -> Option { - self.client_state.clone() - } - - /// Getter for accesing the whole counterparty of this message. Returns a `clone()`. - pub fn counterparty(&self) -> Counterparty { - self.counterparty.clone() - } - - /// Getter for accessing the versions from this message. Returns a `clone()`. - pub fn counterparty_versions(&self) -> Vec { - self.counterparty_versions.clone() - } - - /// Getter for accessing the proofs in this message. - pub fn proofs(&self) -> &Proofs { - &self.proofs - } - /// Getter for accessing the `consensus_height` field from this message. Returns the special /// value `0` if this field is not set. pub fn consensus_height(&self) -> Height { @@ -108,17 +78,21 @@ impl TryFrom for MsgConnectionOpenTry { .ok_or_else(Error::missing_consensus_height)? .into(); - let consensus_proof_obj = ConsensusProof::new(msg.proof_consensus.into(), consensus_height) - .map_err(Error::invalid_proof)?; + let consensus_proof_obj = ConsensusProof::new( + msg.proof_consensus + .try_into() + .map_err(Error::invalid_proof)?, + consensus_height, + ) + .map_err(Error::invalid_proof)?; let proof_height = msg .proof_height .ok_or_else(Error::missing_proof_height)? .into(); - let client_proof = Some(msg.proof_client) - .filter(|x| !x.is_empty()) - .map(CommitmentProofBytes::from); + let client_proof = + CommitmentProofBytes::try_from(msg.proof_client).map_err(Error::invalid_proof)?; let counterparty_versions = msg .counterparty_versions @@ -144,8 +118,8 @@ impl TryFrom for MsgConnectionOpenTry { .try_into()?, counterparty_versions, proofs: Proofs::new( - msg.proof_init.into(), - client_proof, + msg.proof_init.try_into().map_err(Error::invalid_proof)?, + Some(client_proof), Some(consensus_proof_obj), None, proof_height, @@ -200,10 +174,10 @@ pub mod test_util { use ibc_proto::ibc::core::client::v1::Height; use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenTry as RawMsgConnectionOpenTry; - use crate::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; - use crate::ics03_connection::msgs::test_util::get_dummy_raw_counterparty; - use crate::ics03_connection::version::get_compatible_versions; - use crate::ics24_host::identifier::{ClientId, ConnectionId}; + use crate::core::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; + use crate::core::ics03_connection::msgs::test_util::get_dummy_raw_counterparty; + use crate::core::ics03_connection::version::get_compatible_versions; + use crate::core::ics24_host::identifier::{ClientId, ConnectionId}; use crate::test_utils::{get_dummy_bech32_account, get_dummy_proof}; /// Testing-specific helper methods. @@ -253,7 +227,7 @@ pub mod test_util { revision_number: 0, revision_height: consensus_height, }), - proof_client: Vec::new(), + proof_client: get_dummy_proof(), signer: get_dummy_bech32_account(), } } @@ -262,16 +236,16 @@ pub mod test_util { #[cfg(test)] mod tests { use crate::prelude::*; - use core::convert::TryFrom; - use test_env_log::test; + + use test_log::test; use ibc_proto::ibc::core::client::v1::Height; use ibc_proto::ibc::core::connection::v1::Counterparty as RawCounterparty; use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenTry as RawMsgConnectionOpenTry; - use crate::ics03_connection::msgs::conn_open_try::test_util::get_dummy_raw_msg_conn_open_try; - use crate::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; - use crate::ics03_connection::msgs::test_util::get_dummy_raw_counterparty; + use crate::core::ics03_connection::msgs::conn_open_try::test_util::get_dummy_raw_msg_conn_open_try; + use crate::core::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; + use crate::core::ics03_connection::msgs::test_util::get_dummy_raw_counterparty; #[test] fn parse_connection_open_try_msg() { diff --git a/modules/src/ics03_connection/version.rs b/modules/src/core/ics03_connection/version.rs similarity index 96% rename from modules/src/ics03_connection/version.rs rename to modules/src/core/ics03_connection/version.rs index c5dcf8c20..e9ad1a433 100644 --- a/modules/src/ics03_connection/version.rs +++ b/modules/src/core/ics03_connection/version.rs @@ -1,11 +1,10 @@ use crate::prelude::*; -use core::convert::TryFrom; use ibc_proto::ibc::core::connection::v1::Version as RawVersion; use serde::{Deserialize, Serialize}; use tendermint_proto::Protobuf; -use crate::ics03_connection::error::Error; +use crate::core::ics03_connection::error::Error; /// Stores the identifier and the features supported by a version #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] @@ -95,13 +94,13 @@ pub fn pick_version( #[cfg(test)] mod tests { use crate::prelude::*; - use core::convert::{TryFrom, TryInto}; - use test_env_log::test; + + use test_log::test; use ibc_proto::ibc::core::connection::v1::Version as RawVersion; - use crate::ics03_connection::error::Error; - use crate::ics03_connection::version::{get_compatible_versions, pick_version, Version}; + use crate::core::ics03_connection::error::Error; + use crate::core::ics03_connection::version::{get_compatible_versions, pick_version, Version}; fn good_versions() -> Vec { vec![ diff --git a/modules/src/ics04_channel/channel.rs b/modules/src/core/ics04_channel/channel.rs similarity index 90% rename from modules/src/ics04_channel/channel.rs rename to modules/src/core/ics04_channel/channel.rs index 8145d039e..492755e9a 100644 --- a/modules/src/ics04_channel/channel.rs +++ b/modules/src/core/ics04_channel/channel.rs @@ -1,5 +1,5 @@ use crate::prelude::*; -use core::convert::{TryFrom, TryInto}; + use core::fmt; use core::str::FromStr; @@ -11,10 +11,10 @@ use ibc_proto::ibc::core::channel::v1::{ IdentifiedChannel as RawIdentifiedChannel, }; -use crate::events::IbcEventType; -use crate::ics02_client::height::Height; -use crate::ics04_channel::{error::Error, packet::Sequence}; -use crate::ics24_host::identifier::{ChannelId, ConnectionId, PortId}; +use crate::core::ics02_client::height::Height; +use crate::core::ics04_channel::{error::Error, packet::Sequence, Version}; +use crate::core::ics24_host::identifier::{ChannelId, ConnectionId, PortId}; +use crate::events::WithBlockDataType; #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct IdentifiedChannelEnd { @@ -67,7 +67,7 @@ impl From for RawIdentifiedChannel { .iter() .map(|v| v.as_str().to_string()) .collect(), - version: value.channel_end.version, + version: value.channel_end.version.into(), port_id: value.port_id.to_string(), channel_id: value.channel_id.to_string(), } @@ -80,7 +80,7 @@ pub struct ChannelEnd { pub ordering: Order, pub remote: Counterparty, pub connection_hops: Vec, - pub version: String, + pub version: Version, } impl Default for ChannelEnd { @@ -90,7 +90,7 @@ impl Default for ChannelEnd { ordering: Default::default(), remote: Counterparty::default(), connection_hops: Vec::new(), - version: "".to_string(), + version: Version::default(), } } } @@ -123,7 +123,7 @@ impl TryFrom for ChannelEnd { .collect::, _>>() .map_err(Error::identifier)?; - let version = validate_version(value.version)?; + let version = value.version.into(); Ok(ChannelEnd::new( chan_state, @@ -146,7 +146,7 @@ impl From for RawChannel { .iter() .map(|v| v.as_str().to_string()) .collect(), - version: value.version, + version: value.version.into(), } } } @@ -158,7 +158,7 @@ impl ChannelEnd { ordering: Order, remote: Counterparty, connection_hops: Vec, - version: String, + version: Version, ) -> Self { Self { state, @@ -174,7 +174,7 @@ impl ChannelEnd { self.state = s; } - pub fn set_version(&mut self, v: String) { + pub fn set_version(&mut self, v: Version) { self.version = v; } @@ -203,8 +203,8 @@ impl ChannelEnd { &self.connection_hops } - pub fn version(&self) -> String { - self.version.parse().unwrap() + pub fn version(&self) -> &Version { + &self.version } pub fn validate_basic(&self) -> Result<(), Error> { @@ -214,9 +214,6 @@ impl ChannelEnd { self.connection_hops.len(), )); } - if self.version().trim() == "" { - return Err(Error::empty_version()); - } self.counterparty().validate_basic() } @@ -239,26 +236,17 @@ impl ChannelEnd { self.counterparty().eq(other) } - pub fn version_matches(&self, other: &str) -> bool { + pub fn version_matches(&self, other: &Version) -> bool { self.version().eq(other) } } -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] pub struct Counterparty { pub port_id: PortId, pub channel_id: Option, } -impl Default for Counterparty { - fn default() -> Self { - Counterparty { - port_id: Default::default(), - channel_id: None, - } - } -} - impl Counterparty { pub fn new(port_id: PortId, channel_id: Option) -> Self { Self { @@ -312,8 +300,8 @@ impl From for RawCounterparty { #[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)] pub enum Order { None = 0, - Unordered, - Ordered, + Unordered = 1, + Ordered = 2, } impl Default for Order { @@ -353,7 +341,7 @@ impl FromStr for Order { type Err = Error; fn from_str(s: &str) -> Result { - match s.to_lowercase().as_str() { + match s.to_lowercase().trim_start_matches("order_") { "uninitialized" => Ok(Self::None), "unordered" => Ok(Self::Unordered), "ordered" => Ok(Self::Ordered), @@ -425,7 +413,7 @@ impl core::fmt::Display for State { /// The query is preformed for the chain context at `height`. #[derive(Clone, Debug)] pub struct QueryPacketEventDataRequest { - pub event_id: IbcEventType, + pub event_id: WithBlockDataType, pub source_channel_id: ChannelId, pub source_port_id: PortId, pub destination_channel_id: ChannelId, @@ -434,16 +422,9 @@ pub struct QueryPacketEventDataRequest { pub height: Height, } -/// Version validation, specific for channel (ICS4) opening handshake protocol. -/// This field is supposed to be opaque to the core IBC protocol. No explicit validation necessary, -/// and empty version is currently allowed by the specification (cf. ICS 004, v1). -pub fn validate_version(version: String) -> Result { - Ok(version) -} - #[cfg(test)] pub mod test_util { - use crate::ics24_host::identifier::{ChannelId, ConnectionId, PortId}; + use crate::core::ics24_host::identifier::{ChannelId, ConnectionId, PortId}; use crate::prelude::*; use ibc_proto::ibc::core::channel::v1::Channel as RawChannel; use ibc_proto::ibc::core::channel::v1::Counterparty as RawCounterparty; @@ -472,14 +453,14 @@ pub mod test_util { #[cfg(test)] mod tests { use crate::prelude::*; - use core::convert::TryFrom; + use core::str::FromStr; - use test_env_log::test; + use test_log::test; use ibc_proto::ibc::core::channel::v1::Channel as RawChannel; - use crate::ics04_channel::channel::test_util::get_dummy_raw_channel_end; - use crate::ics04_channel::channel::ChannelEnd; + use crate::core::ics04_channel::channel::test_util::get_dummy_raw_channel_end; + use crate::core::ics04_channel::channel::ChannelEnd; #[test] fn channel_end_try_from_raw() { diff --git a/modules/src/ics04_channel/context.rs b/modules/src/core/ics04_channel/context.rs similarity index 79% rename from modules/src/ics04_channel/context.rs rename to modules/src/core/ics04_channel/context.rs index f307f40a8..165cf688a 100644 --- a/modules/src/ics04_channel/context.rs +++ b/modules/src/core/ics04_channel/context.rs @@ -1,15 +1,17 @@ //! ICS4 (channel) context. The two traits `ChannelReader ` and `ChannelKeeper` define //! the interface that any host chain must implement to be able to process any `ChannelMsg`. //! - -use crate::ics02_client::client_consensus::AnyConsensusState; -use crate::ics02_client::client_state::AnyClientState; -use crate::ics03_connection::connection::ConnectionEnd; -use crate::ics04_channel::channel::ChannelEnd; -use crate::ics04_channel::handler::{ChannelIdState, ChannelResult}; -use crate::ics04_channel::{error::Error, packet::Receipt}; -use crate::ics05_port::capabilities::Capability; -use crate::ics24_host::identifier::{ChannelId, ClientId, ConnectionId, PortId}; +use core::time::Duration; +use num_traits::float::FloatCore; + +use crate::core::ics02_client::client_consensus::AnyConsensusState; +use crate::core::ics02_client::client_state::AnyClientState; +use crate::core::ics03_connection::connection::ConnectionEnd; +use crate::core::ics04_channel::channel::ChannelEnd; +use crate::core::ics04_channel::handler::{ChannelIdState, ChannelResult}; +use crate::core::ics04_channel::{error::Error, packet::Receipt}; +use crate::core::ics05_port::capabilities::Capability; +use crate::core::ics24_host::identifier::{ChannelId, ClientId, ConnectionId, PortId}; use crate::prelude::*; use crate::timestamp::Timestamp; use crate::Height; @@ -69,12 +71,42 @@ pub trait ChannelReader { fn host_height(&self) -> Height; /// Returns the current timestamp of the local chain. - fn host_timestamp(&self) -> Timestamp; + fn host_timestamp(&self) -> Timestamp { + let pending_consensus_state = self + .pending_host_consensus_state() + .expect("host must have pending consensus state"); + pending_consensus_state.timestamp() + } + + /// Returns the `ConsensusState` of the host (local) chain at a specific height. + fn host_consensus_state(&self, height: Height) -> Result; + + /// Returns the pending `ConsensusState` of the host (local) chain. + fn pending_host_consensus_state(&self) -> Result; + + /// Returns the time when the client state for the given [`ClientId`] was updated with a header for the given [`Height`] + fn client_update_time(&self, client_id: &ClientId, height: Height) -> Result; + + /// Returns the height when the client state for the given [`ClientId`] was updated with a header for the given [`Height`] + fn client_update_height(&self, client_id: &ClientId, height: Height) -> Result; /// Returns a counter on the number of channel ids have been created thus far. /// The value of this counter should increase only via method /// `ChannelKeeper::increase_channel_counter`. fn channel_counter(&self) -> Result; + + /// Returns the maximum expected time per block + fn max_expected_time_per_block(&self) -> Duration; + + fn block_delay(&self, delay_period_time: Duration) -> u64 { + let expected_time_per_block = self.max_expected_time_per_block(); + if expected_time_per_block.is_zero() { + return 0; + } + + FloatCore::ceil(delay_period_time.as_secs_f64() / expected_time_per_block.as_secs_f64()) + as u64 + } } /// A context supplying all the necessary write-only dependencies (i.e., storage writing facility) @@ -159,7 +191,7 @@ pub trait ChannelKeeper { self.store_next_sequence_ack((res.port_id.clone(), res.channel_id), s)?; } None => { - //Unordered Channel, https://github.com/informalsystems/ibc-rs/issues/1573 + //Unordered Channel self.delete_packet_commitment(( res.port_id.clone(), res.channel_id.clone(), diff --git a/modules/src/ics04_channel/error.rs b/modules/src/core/ics04_channel/error.rs similarity index 91% rename from modules/src/ics04_channel/error.rs rename to modules/src/core/ics04_channel/error.rs index efbb1ac09..202521a5e 100644 --- a/modules/src/ics04_channel/error.rs +++ b/modules/src/core/ics04_channel/error.rs @@ -1,9 +1,9 @@ use super::packet::Sequence; -use crate::ics02_client::error as client_error; -use crate::ics03_connection::error as connection_error; -use crate::ics04_channel::channel::State; -use crate::ics24_host::error::ValidationError; -use crate::ics24_host::identifier::{ChannelId, ClientId, ConnectionId, PortId}; +use crate::core::ics02_client::error as client_error; +use crate::core::ics03_connection::error as connection_error; +use crate::core::ics04_channel::channel::State; +use crate::core::ics24_host::error::ValidationError; +use crate::core::ics24_host::identifier::{ChannelId, ClientId, ConnectionId, PortId}; use crate::prelude::*; use crate::proofs::ProofError; use crate::timestamp::Timestamp; @@ -51,9 +51,6 @@ define_error! { [ TraceError ] | _ | { "invalid version" }, - EmptyVersion - | _ | { "empty version string" }, - InvalidSigner | _ | { "invalid signer address" }, @@ -247,7 +244,7 @@ define_error! { | _ | { "Receiving chain block timestamp >= packet timeout timestamp" }, InvalidPacketTimestamp - [ TraceError ] + [ crate::timestamp::ParseTimestampError ] | _ | { "Invalid packet timeout timestamp value" }, ErrorInvalidConsensusState @@ -324,6 +321,28 @@ define_error! { e.port_channel_id.1) }, + ProcessedTimeNotFound + { + client_id: ClientId, + height: Height, + } + | e | { + format_args!( + "Processed time for the client {0} at height {1} not found", + e.client_id, e.height) + }, + + ProcessedHeightNotFound + { + client_id: ClientId, + height: Height, + } + | e | { + format_args!( + "Processed height for the client {0} at height {1} not found", + e.client_id, e.height) + }, + ImplementationSpecific | _ | { "implementation specific error" }, } diff --git a/modules/src/core/ics04_channel/events.rs b/modules/src/core/ics04_channel/events.rs new file mode 100644 index 000000000..43e22d02c --- /dev/null +++ b/modules/src/core/ics04_channel/events.rs @@ -0,0 +1,1089 @@ +//! Types for the IBC events emitted from Tendermint Websocket by the channels module. + +use serde_derive::{Deserialize, Serialize}; +use tendermint::abci::tag::Tag; +use tendermint::abci::Event as AbciEvent; + +use crate::core::ics02_client::height::Height; +use crate::core::ics04_channel::error::Error; +use crate::core::ics04_channel::packet::Packet; +use crate::core::ics24_host::identifier::{ChannelId, ConnectionId, PortId}; +use crate::events::{ + extract_attribute, maybe_extract_attribute, Error as EventError, IbcEvent, IbcEventType, + RawObject, +}; +use crate::prelude::*; + +/// Channel event attribute keys +const HEIGHT_ATTRIBUTE_KEY: &str = "height"; +const CONNECTION_ID_ATTRIBUTE_KEY: &str = "connection_id"; +const CHANNEL_ID_ATTRIBUTE_KEY: &str = "channel_id"; +const PORT_ID_ATTRIBUTE_KEY: &str = "port_id"; +const COUNTERPARTY_CHANNEL_ID_ATTRIBUTE_KEY: &str = "counterparty_channel_id"; +const COUNTERPARTY_PORT_ID_ATTRIBUTE_KEY: &str = "counterparty_port_id"; + +/// Packet event attribute keys +const PKT_SEQ_ATTRIBUTE_KEY: &str = "packet_sequence"; +const PKT_DATA_ATTRIBUTE_KEY: &str = "packet_data"; +const PKT_SRC_PORT_ATTRIBUTE_KEY: &str = "packet_src_port"; +const PKT_SRC_CHANNEL_ATTRIBUTE_KEY: &str = "packet_src_channel"; +const PKT_DST_PORT_ATTRIBUTE_KEY: &str = "packet_dst_port"; +const PKT_DST_CHANNEL_ATTRIBUTE_KEY: &str = "packet_dst_channel"; +const PKT_TIMEOUT_HEIGHT_ATTRIBUTE_KEY: &str = "packet_timeout_height"; +const PKT_TIMEOUT_TIMESTAMP_ATTRIBUTE_KEY: &str = "packet_timeout_timestamp"; +const PKT_ACK_ATTRIBUTE_KEY: &str = "packet_ack"; + +pub fn try_from_tx(event: &tendermint::abci::Event) -> Option { + match event.type_str.parse() { + Ok(IbcEventType::OpenInitChannel) => extract_attributes_from_tx(event) + .map(OpenInit::from) + .map(IbcEvent::OpenInitChannel) + .ok(), + Ok(IbcEventType::OpenTryChannel) => extract_attributes_from_tx(event) + .map(OpenTry::from) + .map(IbcEvent::OpenTryChannel) + .ok(), + Ok(IbcEventType::OpenAckChannel) => extract_attributes_from_tx(event) + .map(OpenAck::from) + .map(IbcEvent::OpenAckChannel) + .ok(), + Ok(IbcEventType::OpenConfirmChannel) => extract_attributes_from_tx(event) + .map(OpenConfirm::from) + .map(IbcEvent::OpenConfirmChannel) + .ok(), + Ok(IbcEventType::CloseInitChannel) => extract_attributes_from_tx(event) + .map(CloseInit::from) + .map(IbcEvent::CloseInitChannel) + .ok(), + Ok(IbcEventType::CloseConfirmChannel) => extract_attributes_from_tx(event) + .map(CloseConfirm::from) + .map(IbcEvent::CloseConfirmChannel) + .ok(), + Ok(IbcEventType::SendPacket) => { + extract_packet_and_write_ack_from_tx(event) + .map(|(packet, write_ack)| { + // This event should not have a write ack. + debug_assert_eq!(write_ack.len(), 0); + IbcEvent::SendPacket(SendPacket { + height: Default::default(), + packet, + }) + }) + .ok() + } + Ok(IbcEventType::WriteAck) => extract_packet_and_write_ack_from_tx(event) + .map(|(packet, write_ack)| { + IbcEvent::WriteAcknowledgement(WriteAcknowledgement { + height: Default::default(), + packet, + ack: write_ack, + }) + }) + .ok(), + Ok(IbcEventType::AckPacket) => { + extract_packet_and_write_ack_from_tx(event) + .map(|(packet, write_ack)| { + // This event should not have a write ack. + debug_assert_eq!(write_ack.len(), 0); + IbcEvent::AcknowledgePacket(AcknowledgePacket { + height: Default::default(), + packet, + }) + }) + .ok() + } + Ok(IbcEventType::Timeout) => { + extract_packet_and_write_ack_from_tx(event) + .map(|(packet, write_ack)| { + // This event should not have a write ack. + debug_assert_eq!(write_ack.len(), 0); + IbcEvent::TimeoutPacket(TimeoutPacket { + height: Default::default(), + packet, + }) + }) + .ok() + } + _ => None, + } +} + +fn extract_attributes_from_tx(event: &tendermint::abci::Event) -> Result { + let mut attr = Attributes::default(); + + for tag in &event.attributes { + let key = tag.key.as_ref(); + let value = tag.value.as_ref(); + match key { + PORT_ID_ATTRIBUTE_KEY => attr.port_id = value.parse().map_err(Error::identifier)?, + CHANNEL_ID_ATTRIBUTE_KEY => { + attr.channel_id = value.parse().ok(); + } + CONNECTION_ID_ATTRIBUTE_KEY => { + attr.connection_id = value.parse().map_err(Error::identifier)?; + } + COUNTERPARTY_PORT_ID_ATTRIBUTE_KEY => { + attr.counterparty_port_id = value.parse().map_err(Error::identifier)?; + } + COUNTERPARTY_CHANNEL_ID_ATTRIBUTE_KEY => { + attr.counterparty_channel_id = value.parse().ok(); + } + _ => {} + } + } + + Ok(attr) +} + +fn extract_packet_and_write_ack_from_tx( + event: &tendermint::abci::Event, +) -> Result<(Packet, Vec), Error> { + let mut packet = Packet::default(); + let mut write_ack: Vec = Vec::new(); + for tag in &event.attributes { + let key = tag.key.as_ref(); + let value = tag.value.as_ref(); + match key { + PKT_SRC_PORT_ATTRIBUTE_KEY => { + packet.source_port = value.parse().map_err(Error::identifier)?; + } + PKT_SRC_CHANNEL_ATTRIBUTE_KEY => { + packet.source_channel = value.parse().map_err(Error::identifier)?; + } + PKT_DST_PORT_ATTRIBUTE_KEY => { + packet.destination_port = value.parse().map_err(Error::identifier)?; + } + PKT_DST_CHANNEL_ATTRIBUTE_KEY => { + packet.destination_channel = value.parse().map_err(Error::identifier)?; + } + PKT_SEQ_ATTRIBUTE_KEY => { + packet.sequence = value + .parse::() + .map_err(|e| Error::invalid_string_as_sequence(value.to_string(), e))? + .into() + } + PKT_TIMEOUT_HEIGHT_ATTRIBUTE_KEY => { + packet.timeout_height = + value.parse().map_err(|_| Error::invalid_timeout_height())?; + } + PKT_TIMEOUT_TIMESTAMP_ATTRIBUTE_KEY => { + packet.timeout_timestamp = value.parse().unwrap(); + } + PKT_DATA_ATTRIBUTE_KEY => { + packet.data = Vec::from(value.as_bytes()); + } + PKT_ACK_ATTRIBUTE_KEY => { + write_ack = Vec::from(value.as_bytes()); + } + _ => {} + } + } + + Ok((packet, write_ack)) +} + +fn extract_attributes(object: &RawObject<'_>, namespace: &str) -> Result { + Ok(Attributes { + height: object.height, + port_id: extract_attribute(object, &format!("{}.port_id", namespace))? + .parse() + .map_err(EventError::parse)?, + channel_id: maybe_extract_attribute(object, &format!("{}.channel_id", namespace)) + .and_then(|v| v.parse().ok()), + connection_id: extract_attribute(object, &format!("{}.connection_id", namespace))? + .parse() + .map_err(EventError::parse)?, + counterparty_port_id: extract_attribute( + object, + &format!("{}.counterparty_port_id", namespace), + )? + .parse() + .map_err(EventError::parse)?, + counterparty_channel_id: maybe_extract_attribute( + object, + &format!("{}.counterparty_channel_id", namespace), + ) + .and_then(|v| v.parse().ok()), + }) +} + +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Attributes { + pub height: Height, + pub port_id: PortId, + pub channel_id: Option, + pub connection_id: ConnectionId, + pub counterparty_port_id: PortId, + pub counterparty_channel_id: Option, +} + +impl Attributes { + pub fn port_id(&self) -> &PortId { + &self.port_id + } + pub fn channel_id(&self) -> Option<&ChannelId> { + self.channel_id.as_ref() + } +} + +/// Convert attributes to Tendermint ABCI tags +/// +/// # Note +/// The parsing of `Key`s and `Value`s never fails, because the +/// `FromStr` instance of `tendermint::abci::tag::{Key, Value}` +/// is infallible, even if it is not represented in the error type. +/// Once tendermint-rs improves the API of the `Key` and `Value` types, +/// we will be able to remove the `.parse().unwrap()` calls. +impl From for Vec { + fn from(a: Attributes) -> Self { + let mut attributes = vec![]; + let height = Tag { + key: HEIGHT_ATTRIBUTE_KEY.parse().unwrap(), + value: a.height.to_string().parse().unwrap(), + }; + attributes.push(height); + let port_id = Tag { + key: PORT_ID_ATTRIBUTE_KEY.parse().unwrap(), + value: a.port_id.to_string().parse().unwrap(), + }; + attributes.push(port_id); + if let Some(channel_id) = a.channel_id { + let channel_id = Tag { + key: CHANNEL_ID_ATTRIBUTE_KEY.parse().unwrap(), + value: channel_id.as_str().parse().unwrap(), + }; + attributes.push(channel_id); + } + let connection_id = Tag { + key: CONNECTION_ID_ATTRIBUTE_KEY.parse().unwrap(), + value: a.connection_id.to_string().parse().unwrap(), + }; + attributes.push(connection_id); + let counterparty_port_id = Tag { + key: COUNTERPARTY_PORT_ID_ATTRIBUTE_KEY.parse().unwrap(), + value: a.counterparty_port_id.to_string().parse().unwrap(), + }; + attributes.push(counterparty_port_id); + if let Some(channel_id) = a.counterparty_channel_id { + let channel_id = Tag { + key: COUNTERPARTY_CHANNEL_ID_ATTRIBUTE_KEY.parse().unwrap(), + value: channel_id.as_str().parse().unwrap(), + }; + attributes.push(channel_id); + } + attributes + } +} + +/// Convert attributes to Tendermint ABCI tags +/// +/// # Note +/// The parsing of `Key`s and `Value`s never fails, because the +/// `FromStr` instance of `tendermint::abci::tag::{Key, Value}` +/// is infallible, even if it is not represented in the error type. +/// Once tendermint-rs improves the API of the `Key` and `Value` types, +/// we will be able to remove the `.parse().unwrap()` calls. +impl TryFrom for Vec { + type Error = Error; + fn try_from(p: Packet) -> Result { + let mut attributes = vec![]; + let src_port = Tag { + key: PKT_SRC_PORT_ATTRIBUTE_KEY.parse().unwrap(), + value: p.source_port.to_string().parse().unwrap(), + }; + attributes.push(src_port); + let src_channel = Tag { + key: PKT_SRC_CHANNEL_ATTRIBUTE_KEY.parse().unwrap(), + value: p.source_channel.to_string().parse().unwrap(), + }; + attributes.push(src_channel); + let dst_port = Tag { + key: PKT_DST_PORT_ATTRIBUTE_KEY.parse().unwrap(), + value: p.destination_port.to_string().parse().unwrap(), + }; + attributes.push(dst_port); + let dst_channel = Tag { + key: PKT_DST_CHANNEL_ATTRIBUTE_KEY.parse().unwrap(), + value: p.destination_channel.to_string().parse().unwrap(), + }; + attributes.push(dst_channel); + let sequence = Tag { + key: PKT_SEQ_ATTRIBUTE_KEY.parse().unwrap(), + value: p.sequence.to_string().parse().unwrap(), + }; + attributes.push(sequence); + let timeout_height = Tag { + key: PKT_TIMEOUT_HEIGHT_ATTRIBUTE_KEY.parse().unwrap(), + value: p.timeout_height.to_string().parse().unwrap(), + }; + attributes.push(timeout_height); + let timeout_timestamp = Tag { + key: PKT_TIMEOUT_TIMESTAMP_ATTRIBUTE_KEY.parse().unwrap(), + value: p + .timeout_timestamp + .nanoseconds() + .to_string() + .parse() + .unwrap(), + }; + attributes.push(timeout_timestamp); + let val = + String::from_utf8(p.data).expect("hex-encoded string should always be valid UTF-8"); + let packet_data = Tag { + key: PKT_DATA_ATTRIBUTE_KEY.parse().unwrap(), + value: val.parse().unwrap(), + }; + attributes.push(packet_data); + let ack = Tag { + key: PKT_ACK_ATTRIBUTE_KEY.parse().unwrap(), + value: "".parse().unwrap(), + }; + attributes.push(ack); + Ok(attributes) + } +} + +trait EventType { + fn event_type() -> IbcEventType; +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +pub struct OpenInit(pub Attributes); + +impl OpenInit { + pub fn attributes(&self) -> &Attributes { + &self.0 + } + pub fn channel_id(&self) -> Option<&ChannelId> { + self.0.channel_id.as_ref() + } + pub fn port_id(&self) -> &PortId { + &self.0.port_id + } + pub fn height(&self) -> Height { + self.0.height + } + pub fn set_height(&mut self, height: Height) { + self.0.height = height; + } +} + +impl From for OpenInit { + fn from(attrs: Attributes) -> Self { + OpenInit(attrs) + } +} + +impl From for IbcEvent { + fn from(v: OpenInit) -> Self { + IbcEvent::OpenInitChannel(v) + } +} + +impl EventType for OpenInit { + fn event_type() -> IbcEventType { + IbcEventType::OpenInitChannel + } +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +pub struct OpenTry(pub Attributes); + +impl OpenTry { + pub fn attributes(&self) -> &Attributes { + &self.0 + } + pub fn channel_id(&self) -> Option<&ChannelId> { + self.0.channel_id.as_ref() + } + pub fn port_id(&self) -> &PortId { + &self.0.port_id + } + pub fn height(&self) -> Height { + self.0.height + } + pub fn set_height(&mut self, height: Height) { + self.0.height = height; + } +} + +impl From for OpenTry { + fn from(attrs: Attributes) -> Self { + OpenTry(attrs) + } +} + +impl From for IbcEvent { + fn from(v: OpenTry) -> Self { + IbcEvent::OpenTryChannel(v) + } +} + +impl EventType for OpenTry { + fn event_type() -> IbcEventType { + IbcEventType::OpenTryChannel + } +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +pub struct OpenAck(pub Attributes); + +impl OpenAck { + pub fn attributes(&self) -> &Attributes { + &self.0 + } + pub fn channel_id(&self) -> Option<&ChannelId> { + self.0.channel_id.as_ref() + } + pub fn port_id(&self) -> &PortId { + &self.0.port_id + } + pub fn height(&self) -> Height { + self.0.height + } + pub fn set_height(&mut self, height: Height) { + self.0.height = height; + } + + pub fn counterparty_channel_id(&self) -> Option<&ChannelId> { + self.0.counterparty_channel_id.as_ref() + } +} + +impl From for OpenAck { + fn from(attrs: Attributes) -> Self { + OpenAck(attrs) + } +} + +impl From for IbcEvent { + fn from(v: OpenAck) -> Self { + IbcEvent::OpenAckChannel(v) + } +} + +impl EventType for OpenAck { + fn event_type() -> IbcEventType { + IbcEventType::OpenAckChannel + } +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +pub struct OpenConfirm(pub Attributes); + +impl OpenConfirm { + pub fn attributes(&self) -> &Attributes { + &self.0 + } + pub fn channel_id(&self) -> Option<&ChannelId> { + self.0.channel_id.as_ref() + } + pub fn port_id(&self) -> &PortId { + &self.0.port_id + } + pub fn height(&self) -> Height { + self.0.height + } + pub fn set_height(&mut self, height: Height) { + self.0.height = height; + } +} + +impl From for OpenConfirm { + fn from(attrs: Attributes) -> Self { + OpenConfirm(attrs) + } +} + +impl From for IbcEvent { + fn from(v: OpenConfirm) -> Self { + IbcEvent::OpenConfirmChannel(v) + } +} + +impl EventType for OpenConfirm { + fn event_type() -> IbcEventType { + IbcEventType::OpenConfirmChannel + } +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +pub struct CloseInit(pub Attributes); + +impl CloseInit { + pub fn port_id(&self) -> &PortId { + &self.0.port_id + } + + pub fn channel_id(&self) -> &ChannelId { + // FIXME(romac): Rework encoding of IbcEvents which use `Attributes` + self.0 + .channel_id + .as_ref() + .expect("CloseInit should always have a channel_id") + } + + pub fn counterparty_port_id(&self) -> &PortId { + &self.0.counterparty_port_id + } + + pub fn counterparty_channel_id(&self) -> Option<&ChannelId> { + self.0.counterparty_channel_id.as_ref() + } + + pub fn height(&self) -> Height { + self.0.height + } + + pub fn set_height(&mut self, height: Height) { + self.0.height = height; + } +} + +impl From for CloseInit { + fn from(attrs: Attributes) -> Self { + CloseInit(attrs) + } +} + +impl From for IbcEvent { + fn from(v: CloseInit) -> Self { + IbcEvent::CloseInitChannel(v) + } +} + +impl core::fmt::Display for CloseInit { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + write!( + f, + "{} {} {:?}", + self.height(), + IbcEventType::CloseInitChannel.as_str(), + self.0 + ) + } +} + +impl EventType for CloseInit { + fn event_type() -> IbcEventType { + IbcEventType::CloseInitChannel + } +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +pub struct CloseConfirm(pub Attributes); + +impl CloseConfirm { + pub fn channel_id(&self) -> Option<&ChannelId> { + self.0.channel_id.as_ref() + } + pub fn height(&self) -> Height { + self.0.height + } + pub fn set_height(&mut self, height: Height) { + self.0.height = height; + } +} + +impl From for CloseConfirm { + fn from(attrs: Attributes) -> Self { + CloseConfirm(attrs) + } +} + +impl From for IbcEvent { + fn from(v: CloseConfirm) -> Self { + IbcEvent::CloseConfirmChannel(v) + } +} + +impl EventType for CloseConfirm { + fn event_type() -> IbcEventType { + IbcEventType::CloseConfirmChannel + } +} + +macro_rules! impl_from_ibc_to_abci_event { + ($($event:ty),+) => { + $(impl From<$event> for AbciEvent { + fn from(v: $event) -> Self { + let attributes = Vec::::from(v.0); + let type_str = <$event>::event_type().as_str().to_string(); + AbciEvent { + type_str, + attributes, + } + } + })+ + }; +} + +impl_from_ibc_to_abci_event!( + OpenInit, + OpenTry, + OpenAck, + OpenConfirm, + CloseInit, + CloseConfirm +); + +macro_rules! impl_try_from_raw_obj_for_event { + ($($event:ty),+) => { + $(impl TryFrom> for $event { + type Error = EventError; + + fn try_from(obj: RawObject<'_>) -> Result { + Ok(Self(extract_attributes(&obj, Self::event_type().as_str())?)) + } + })+ + }; +} + +impl_try_from_raw_obj_for_event!( + OpenInit, + OpenTry, + OpenAck, + OpenConfirm, + CloseInit, + CloseConfirm +); + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +pub struct SendPacket { + pub height: Height, + pub packet: Packet, +} + +impl SendPacket { + pub fn height(&self) -> Height { + self.height + } + pub fn set_height(&mut self, height: Height) { + self.height = height; + } + pub fn src_port_id(&self) -> &PortId { + &self.packet.source_port + } + pub fn src_channel_id(&self) -> &ChannelId { + &self.packet.source_channel + } + pub fn dst_port_id(&self) -> &PortId { + &self.packet.destination_port + } + pub fn dst_channel_id(&self) -> &ChannelId { + &self.packet.destination_channel + } +} + +impl From for IbcEvent { + fn from(v: SendPacket) -> Self { + IbcEvent::SendPacket(v) + } +} + +impl TryFrom for AbciEvent { + type Error = Error; + + fn try_from(v: SendPacket) -> Result { + let attributes = Vec::::try_from(v.packet)?; + Ok(AbciEvent { + type_str: IbcEventType::SendPacket.as_str().to_string(), + attributes, + }) + } +} + +impl core::fmt::Display for SendPacket { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + write!(f, "SendPacket - h:{}, {}", self.height, self.packet) + } +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +pub struct ReceivePacket { + pub height: Height, + pub packet: Packet, +} + +impl ReceivePacket { + pub fn height(&self) -> Height { + self.height + } + pub fn set_height(&mut self, height: Height) { + self.height = height; + } + pub fn src_port_id(&self) -> &PortId { + &self.packet.source_port + } + pub fn src_channel_id(&self) -> &ChannelId { + &self.packet.source_channel + } + pub fn dst_port_id(&self) -> &PortId { + &self.packet.destination_port + } + pub fn dst_channel_id(&self) -> &ChannelId { + &self.packet.destination_channel + } +} + +impl From for IbcEvent { + fn from(v: ReceivePacket) -> Self { + IbcEvent::ReceivePacket(v) + } +} + +impl core::fmt::Display for ReceivePacket { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + write!(f, "ReceivePacket - h:{}, {}", self.height, self.packet) + } +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +pub struct WriteAcknowledgement { + pub height: Height, + pub packet: Packet, + #[serde(serialize_with = "crate::serializers::ser_hex_upper")] + pub ack: Vec, +} + +impl WriteAcknowledgement { + pub fn height(&self) -> Height { + self.height + } + pub fn set_height(&mut self, height: Height) { + self.height = height; + } + pub fn src_port_id(&self) -> &PortId { + &self.packet.source_port + } + pub fn src_channel_id(&self) -> &ChannelId { + &self.packet.source_channel + } + pub fn dst_port_id(&self) -> &PortId { + &self.packet.destination_port + } + pub fn dst_channel_id(&self) -> &ChannelId { + &self.packet.destination_channel + } +} + +impl From for IbcEvent { + fn from(v: WriteAcknowledgement) -> Self { + IbcEvent::WriteAcknowledgement(v) + } +} + +impl TryFrom for AbciEvent { + type Error = Error; + + fn try_from(v: WriteAcknowledgement) -> Result { + let mut attributes = Vec::::try_from(v.packet)?; + let val = + String::from_utf8(v.ack).expect("hex-encoded string should always be valid UTF-8"); + // No actual conversion from string to `Tag::Key` or `Tag::Value` + let ack = Tag { + key: PKT_ACK_ATTRIBUTE_KEY.parse().unwrap(), + value: val.parse().unwrap(), + }; + attributes.push(ack); + Ok(AbciEvent { + type_str: IbcEventType::WriteAck.as_str().to_string(), + attributes, + }) + } +} + +impl core::fmt::Display for WriteAcknowledgement { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + write!( + f, + "WriteAcknowledgement - h:{}, {}", + self.height, self.packet + ) + } +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +pub struct AcknowledgePacket { + pub height: Height, + pub packet: Packet, +} + +impl AcknowledgePacket { + pub fn height(&self) -> Height { + self.height + } + pub fn set_height(&mut self, height: Height) { + self.height = height; + } + pub fn src_port_id(&self) -> &PortId { + &self.packet.source_port + } + pub fn src_channel_id(&self) -> &ChannelId { + &self.packet.source_channel + } +} + +impl From for IbcEvent { + fn from(v: AcknowledgePacket) -> Self { + IbcEvent::AcknowledgePacket(v) + } +} + +impl TryFrom for AbciEvent { + type Error = Error; + + fn try_from(v: AcknowledgePacket) -> Result { + let attributes = Vec::::try_from(v.packet)?; + Ok(AbciEvent { + type_str: IbcEventType::AckPacket.as_str().to_string(), + attributes, + }) + } +} + +impl core::fmt::Display for AcknowledgePacket { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + write!(f, "h:{}, {}", self.height, self.packet) + } +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +pub struct TimeoutPacket { + pub height: Height, + pub packet: Packet, +} + +impl TimeoutPacket { + pub fn height(&self) -> Height { + self.height + } + pub fn set_height(&mut self, height: Height) { + self.height = height; + } + pub fn src_port_id(&self) -> &PortId { + &self.packet.source_port + } + pub fn src_channel_id(&self) -> &ChannelId { + &self.packet.source_channel + } + pub fn dst_port_id(&self) -> &PortId { + &self.packet.destination_port + } + pub fn dst_channel_id(&self) -> &ChannelId { + &self.packet.destination_channel + } +} + +impl From for IbcEvent { + fn from(v: TimeoutPacket) -> Self { + IbcEvent::TimeoutPacket(v) + } +} + +impl TryFrom for AbciEvent { + type Error = Error; + + fn try_from(v: TimeoutPacket) -> Result { + let attributes = Vec::::try_from(v.packet)?; + Ok(AbciEvent { + type_str: IbcEventType::Timeout.as_str().to_string(), + attributes, + }) + } +} + +impl core::fmt::Display for TimeoutPacket { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + write!(f, "TimeoutPacket - h:{}, {}", self.height, self.packet) + } +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +pub struct TimeoutOnClosePacket { + pub height: Height, + pub packet: Packet, +} + +impl TimeoutOnClosePacket { + pub fn height(&self) -> Height { + self.height + } + pub fn set_height(&mut self, height: Height) { + self.height = height; + } + pub fn src_port_id(&self) -> &PortId { + &self.packet.source_port + } + pub fn src_channel_id(&self) -> &ChannelId { + &self.packet.source_channel + } + pub fn dst_port_id(&self) -> &PortId { + &self.packet.destination_port + } + pub fn dst_channel_id(&self) -> &ChannelId { + &self.packet.destination_channel + } +} + +impl From for IbcEvent { + fn from(v: TimeoutOnClosePacket) -> Self { + IbcEvent::TimeoutOnClosePacket(v) + } +} + +impl core::fmt::Display for TimeoutOnClosePacket { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + write!( + f, + "TimeoutOnClosePacket - h:{}, {}", + self.height, self.packet + ) + } +} + +macro_rules! impl_try_from_raw_obj_for_packet { + ($($packet:ty),+) => { + $(impl TryFrom> for $packet { + type Error = EventError; + + fn try_from(obj: RawObject<'_>) -> Result { + let height = obj.height; + let data_str: String = extract_attribute(&obj, &format!("{}.{}", obj.action, PKT_DATA_ATTRIBUTE_KEY))?; + + let mut packet = Packet::try_from(obj)?; + packet.data = Vec::from(data_str.as_str().as_bytes()); + + Ok(Self { height, packet }) + } + })+ + }; +} + +impl_try_from_raw_obj_for_packet!( + SendPacket, + ReceivePacket, + AcknowledgePacket, + TimeoutPacket, + TimeoutOnClosePacket +); + +impl TryFrom> for WriteAcknowledgement { + type Error = EventError; + + fn try_from(obj: RawObject<'_>) -> Result { + let height = obj.height; + let data_str: String = + extract_attribute(&obj, &format!("{}.{}", obj.action, PKT_DATA_ATTRIBUTE_KEY))?; + let ack = extract_attribute(&obj, &format!("{}.{}", obj.action, PKT_ACK_ATTRIBUTE_KEY))? + .into_bytes(); + + let mut packet = Packet::try_from(obj)?; + packet.data = Vec::from(data_str.as_str().as_bytes()); + + Ok(Self { + height, + packet, + ack, + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::core::ics04_channel::packet::Sequence; + use crate::timestamp::Timestamp; + + #[test] + fn channel_event_to_abci_event() { + let attributes = Attributes { + height: Height::default(), + port_id: "test_port".parse().unwrap(), + channel_id: Some("test_channel".parse().unwrap()), + connection_id: "test_connection".parse().unwrap(), + counterparty_port_id: "counterparty_test_port".parse().unwrap(), + counterparty_channel_id: Some("counterparty_test_channel".parse().unwrap()), + }; + let mut abci_events = vec![]; + let open_init = OpenInit::from(attributes.clone()); + abci_events.push(AbciEvent::from(open_init.clone())); + let open_try = OpenTry::from(attributes.clone()); + abci_events.push(AbciEvent::from(open_try.clone())); + let open_ack = OpenAck::from(attributes.clone()); + abci_events.push(AbciEvent::from(open_ack.clone())); + let open_confirm = OpenConfirm::from(attributes.clone()); + abci_events.push(AbciEvent::from(open_confirm.clone())); + let close_init = CloseInit::from(attributes.clone()); + abci_events.push(AbciEvent::from(close_init.clone())); + let close_confirm = CloseConfirm::from(attributes); + abci_events.push(AbciEvent::from(close_confirm.clone())); + + for event in abci_events { + match try_from_tx(&event) { + Some(e) => match e { + IbcEvent::OpenInitChannel(e) => assert_eq!(e.0, open_init.0), + IbcEvent::OpenTryChannel(e) => assert_eq!(e.0, open_try.0), + IbcEvent::OpenAckChannel(e) => assert_eq!(e.0, open_ack.0), + IbcEvent::OpenConfirmChannel(e) => assert_eq!(e.0, open_confirm.0), + IbcEvent::CloseInitChannel(e) => assert_eq!(e.0, close_init.0), + IbcEvent::CloseConfirmChannel(e) => assert_eq!(e.0, close_confirm.0), + _ => panic!("unexpected event type"), + }, + None => panic!("converted event was wrong"), + } + } + } + + #[test] + fn packet_event_to_abci_event() { + let packet = Packet { + sequence: Sequence::from(10), + source_port: "a_test_port".parse().unwrap(), + source_channel: "a_test_channel".parse().unwrap(), + destination_port: "b_test_port".parse().unwrap(), + destination_channel: "b_test_channel".parse().unwrap(), + data: "test_data".as_bytes().to_vec(), + timeout_height: Height::new(1, 10), + timeout_timestamp: Timestamp::now(), + }; + let mut abci_events = vec![]; + let send_packet = SendPacket { + height: Height::default(), + packet: packet.clone(), + }; + abci_events.push(AbciEvent::try_from(send_packet.clone()).unwrap()); + let write_ack = WriteAcknowledgement { + height: Height::default(), + packet: packet.clone(), + ack: "test_ack".as_bytes().to_vec(), + }; + abci_events.push(AbciEvent::try_from(write_ack.clone()).unwrap()); + let ack_packet = AcknowledgePacket { + height: Height::default(), + packet: packet.clone(), + }; + abci_events.push(AbciEvent::try_from(ack_packet.clone()).unwrap()); + let timeout_packet = TimeoutPacket { + height: Height::default(), + packet, + }; + abci_events.push(AbciEvent::try_from(timeout_packet.clone()).unwrap()); + + for event in abci_events { + match try_from_tx(&event) { + Some(e) => match e { + IbcEvent::SendPacket(e) => assert_eq!(e.packet, send_packet.packet), + IbcEvent::WriteAcknowledgement(e) => { + assert_eq!(e.packet, write_ack.packet); + assert_eq!(e.ack, write_ack.ack); + } + IbcEvent::AcknowledgePacket(e) => assert_eq!(e.packet, ack_packet.packet), + IbcEvent::TimeoutPacket(e) => assert_eq!(e.packet, timeout_packet.packet), + _ => panic!("unexpected event type"), + }, + None => panic!("converted event was wrong"), + } + } + } +} diff --git a/modules/src/ics04_channel/handler.rs b/modules/src/core/ics04_channel/handler.rs similarity index 88% rename from modules/src/ics04_channel/handler.rs rename to modules/src/core/ics04_channel/handler.rs index bc4a5bb39..eca6c1f1a 100644 --- a/modules/src/ics04_channel/handler.rs +++ b/modules/src/core/ics04_channel/handler.rs @@ -1,15 +1,15 @@ //! This module implements the processing logic for ICS4 (channel) messages. -use crate::handler::{HandlerOutput, HandlerResult}; -use crate::ics04_channel::channel::ChannelEnd; -use crate::ics04_channel::context::ChannelReader; -use crate::ics04_channel::error::Error; -use crate::ics04_channel::msgs::ChannelMsg; -use crate::ics04_channel::{msgs::PacketMsg, packet::PacketResult}; -use crate::ics05_port::capabilities::Capability; -use crate::ics24_host::identifier::{ChannelId, PortId}; -use crate::ics26_routing::context::Ics26Context; -use crate::prelude::*; + +use crate::core::ics04_channel::channel::ChannelEnd; +use crate::core::ics04_channel::context::ChannelReader; +use crate::core::ics04_channel::error::Error; +use crate::core::ics04_channel::msgs::ChannelMsg; +use crate::core::ics04_channel::{msgs::PacketMsg, packet::PacketResult}; +use crate::core::ics05_port::capabilities::Capability; +use crate::core::ics24_host::identifier::{ChannelId, PortId}; +use crate::core::ics26_routing::context::Ics26Context; +use crate::handler::HandlerOutput; pub mod acknowledgement; pub mod chan_close_confirm; @@ -74,6 +74,7 @@ where { match msg { PacketMsg::RecvPacket(msg) => { + use alloc::vec; let recv_handler_out = recv_packet::process(ctx, msg.clone())?; // store_packet_result not really unimploment! ctx.store_packet_result(recv_handler_out.result)?; diff --git a/modules/src/ics04_channel/handler/acknowledgement.rs b/modules/src/core/ics04_channel/handler/acknowledgement.rs similarity index 82% rename from modules/src/ics04_channel/handler/acknowledgement.rs rename to modules/src/core/ics04_channel/handler/acknowledgement.rs index 2495b3183..cc239b610 100644 --- a/modules/src/ics04_channel/handler/acknowledgement.rs +++ b/modules/src/core/ics04_channel/handler/acknowledgement.rs @@ -1,15 +1,15 @@ +use crate::core::ics02_client::height::Height; +use crate::core::ics03_connection::connection::State as ConnectionState; +use crate::core::ics04_channel::channel::State; +use crate::core::ics04_channel::channel::{Counterparty, Order}; +use crate::core::ics04_channel::events::AcknowledgePacket; +use crate::core::ics04_channel::handler::verify::verify_packet_acknowledgement_proofs; +use crate::core::ics04_channel::msgs::acknowledgement::MsgAcknowledgement; +use crate::core::ics04_channel::packet::{PacketResult, Sequence}; +use crate::core::ics04_channel::{context::ChannelReader, error::Error}; +use crate::core::ics24_host::identifier::{ChannelId, PortId}; use crate::events::IbcEvent; use crate::handler::{HandlerOutput, HandlerResult}; -use crate::ics02_client::height::Height; -use crate::ics03_connection::connection::State as ConnectionState; -use crate::ics04_channel::channel::State; -use crate::ics04_channel::channel::{Counterparty, Order}; -use crate::ics04_channel::events::AcknowledgePacket; -use crate::ics04_channel::handler::verify::verify_packet_acknowledgement_proofs; -use crate::ics04_channel::msgs::acknowledgement::MsgAcknowledgement; -use crate::ics04_channel::packet::{PacketResult, Sequence}; -use crate::ics04_channel::{context::ChannelReader, error::Error}; -use crate::ics24_host::identifier::{ChannelId, PortId}; use crate::prelude::*; #[derive(Clone, Debug)] @@ -57,8 +57,6 @@ pub fn process( )); } - let client_id = connection_end.client_id().clone(); - // Verify packet commitment let packet_commitment = ctx.get_packet_commitment(&( packet.source_port.clone(), @@ -78,10 +76,11 @@ pub fn process( // Verify the acknowledgement proof verify_packet_acknowledgement_proofs( ctx, + msg.proofs.height(), packet, - msg.acknowledgement().clone(), - client_id, - msg.proofs(), + msg.acknowledgement.clone(), + &connection_end, + &msg.proofs, )?; let result = if source_channel_end.order_matches(&Order::Ordered) { @@ -122,24 +121,24 @@ pub fn process( #[cfg(test)] mod tests { + use test_log::test; + + use crate::core::ics02_client::height::Height; + use crate::core::ics03_connection::connection::ConnectionEnd; + use crate::core::ics03_connection::connection::Counterparty as ConnectionCounterparty; + use crate::core::ics03_connection::connection::State as ConnectionState; + use crate::core::ics03_connection::version::get_compatible_versions; + use crate::core::ics04_channel::channel::{ChannelEnd, Counterparty, Order, State}; + use crate::core::ics04_channel::context::ChannelReader; + use crate::core::ics04_channel::handler::acknowledgement::process; + use crate::core::ics04_channel::msgs::acknowledgement::test_util::get_dummy_raw_msg_acknowledgement; + use crate::core::ics04_channel::msgs::acknowledgement::MsgAcknowledgement; + use crate::core::ics04_channel::Version; + use crate::core::ics24_host::identifier::{ChannelId, ClientId, ConnectionId, PortId}; use crate::events::IbcEvent; - use crate::ics02_client::height::Height; - use crate::ics03_connection::connection::ConnectionEnd; - use crate::ics03_connection::connection::Counterparty as ConnectionCounterparty; - use crate::ics03_connection::connection::State as ConnectionState; - use crate::ics03_connection::version::get_compatible_versions; - use crate::ics04_channel::channel::{ChannelEnd, Counterparty, Order, State}; - use crate::ics04_channel::context::ChannelReader; - use crate::ics04_channel::handler::acknowledgement::process; - use crate::ics04_channel::msgs::acknowledgement::test_util::get_dummy_raw_msg_acknowledgement; - use crate::ics04_channel::msgs::acknowledgement::MsgAcknowledgement; - use crate::ics24_host::identifier::{ChannelId, ClientId, ConnectionId, PortId}; use crate::mock::context::MockContext; use crate::prelude::*; use crate::timestamp::ZERO_DURATION; - use test_env_log::test; - - use core::convert::TryFrom; #[test] fn ack_packet_processing() { @@ -176,7 +175,7 @@ mod tests { Some(packet.destination_channel.clone()), ), vec![ConnectionId::default()], - "ics20".to_string(), + Version::ics20(), ); let connection_end = ConnectionEnd::new( diff --git a/modules/src/ics04_channel/handler/chan_close_confirm.rs b/modules/src/core/ics04_channel/handler/chan_close_confirm.rs similarity index 69% rename from modules/src/ics04_channel/handler/chan_close_confirm.rs rename to modules/src/core/ics04_channel/handler/chan_close_confirm.rs index 08f5531d6..2f86e13e5 100644 --- a/modules/src/ics04_channel/handler/chan_close_confirm.rs +++ b/modules/src/core/ics04_channel/handler/chan_close_confirm.rs @@ -1,14 +1,14 @@ //! Protocol logic specific to ICS4 messages of type `MsgChannelCloseConfirm`. +use crate::core::ics03_connection::connection::State as ConnectionState; +use crate::core::ics04_channel::channel::{ChannelEnd, Counterparty, State}; +use crate::core::ics04_channel::context::ChannelReader; +use crate::core::ics04_channel::error::Error; +use crate::core::ics04_channel::events::Attributes; +use crate::core::ics04_channel::handler::verify::verify_channel_proofs; +use crate::core::ics04_channel::handler::{ChannelIdState, ChannelResult}; +use crate::core::ics04_channel::msgs::chan_close_confirm::MsgChannelCloseConfirm; use crate::events::IbcEvent; use crate::handler::{HandlerOutput, HandlerResult}; -use crate::ics03_connection::connection::State as ConnectionState; -use crate::ics04_channel::channel::{ChannelEnd, Counterparty, State}; -use crate::ics04_channel::context::ChannelReader; -use crate::ics04_channel::error::Error; -use crate::ics04_channel::events::Attributes; -use crate::ics04_channel::handler::verify::verify_channel_proofs; -use crate::ics04_channel::handler::{ChannelIdState, ChannelResult}; -use crate::ics04_channel::msgs::chan_close_confirm::MsgChannelCloseConfirm; use crate::prelude::*; pub(crate) fn process( @@ -18,15 +18,15 @@ pub(crate) fn process( let mut output = HandlerOutput::builder(); // Retrieve the old channel end and validate it against the message. - let mut channel_end = ctx.channel_end(&(msg.port_id().clone(), msg.channel_id().clone()))?; + let mut channel_end = ctx.channel_end(&(msg.port_id.clone(), msg.channel_id.clone()))?; // Validate that the channel end is in a state where it can be closed. if channel_end.state_matches(&State::Closed) { - return Err(Error::channel_closed(msg.channel_id().clone())); + return Err(Error::channel_closed(msg.channel_id)); } // Channel capabilities - let channel_cap = ctx.authenticated_capability(&msg.port_id().clone())?; + let channel_cap = ctx.authenticated_capability(&msg.port_id)?; // An OPEN IBC connection running on the local (host) chain should exist. if channel_end.connection_hops().len() != 1 { @@ -48,7 +48,7 @@ pub(crate) fn process( // 1. Setup: build the Channel as we expect to find it on the other party. let expected_counterparty = - Counterparty::new(msg.port_id().clone(), Some(msg.channel_id().clone())); + Counterparty::new(msg.port_id.clone(), Some(msg.channel_id.clone())); let counterparty = conn.counterparty(); let ccid = counterparty.connection_id().ok_or_else(|| { @@ -62,15 +62,16 @@ pub(crate) fn process( *channel_end.ordering(), expected_counterparty, expected_connection_hops, - channel_end.version(), + channel_end.version().clone(), ); verify_channel_proofs( ctx, + msg.proofs.height(), &channel_end, &conn, &expected_channel_end, - msg.proofs(), + &msg.proofs, )?; output.log("success: channel close confirm "); @@ -79,8 +80,8 @@ pub(crate) fn process( channel_end.set_state(State::Closed); let result = ChannelResult { - port_id: msg.port_id().clone(), - channel_id: msg.channel_id().clone(), + port_id: msg.port_id.clone(), + channel_id: msg.channel_id.clone(), channel_id_state: ChannelIdState::Reused, channel_cap, channel_end, @@ -88,8 +89,8 @@ pub(crate) fn process( let event_attributes = Attributes { height: ctx.host_height().clone(), - port_id: msg.port_id.clone(), - channel_id: Some(msg.channel_id().clone()), + port_id: msg.port_id, + channel_id: Some(msg.channel_id), ..Default::default() }; output.emit(IbcEvent::CloseConfirmChannel(event_attributes.into())); diff --git a/modules/src/ics04_channel/handler/chan_close_init.rs b/modules/src/core/ics04_channel/handler/chan_close_init.rs similarity index 70% rename from modules/src/ics04_channel/handler/chan_close_init.rs rename to modules/src/core/ics04_channel/handler/chan_close_init.rs index 24ed11c98..986948e4c 100644 --- a/modules/src/ics04_channel/handler/chan_close_init.rs +++ b/modules/src/core/ics04_channel/handler/chan_close_init.rs @@ -1,13 +1,13 @@ //! Protocol logic specific to ICS4 messages of type `MsgChannelCloseInit`. +use crate::core::ics03_connection::connection::State as ConnectionState; +use crate::core::ics04_channel::channel::State; +use crate::core::ics04_channel::context::ChannelReader; +use crate::core::ics04_channel::error::Error; +use crate::core::ics04_channel::events::Attributes; +use crate::core::ics04_channel::handler::{ChannelIdState, ChannelResult}; +use crate::core::ics04_channel::msgs::chan_close_init::MsgChannelCloseInit; use crate::events::IbcEvent; use crate::handler::{HandlerOutput, HandlerResult}; -use crate::ics03_connection::connection::State as ConnectionState; -use crate::ics04_channel::channel::State; -use crate::ics04_channel::context::ChannelReader; -use crate::ics04_channel::error::Error; -use crate::ics04_channel::events::Attributes; -use crate::ics04_channel::handler::{ChannelIdState, ChannelResult}; -use crate::ics04_channel::msgs::chan_close_init::MsgChannelCloseInit; pub(crate) fn process( ctx: &dyn ChannelReader, @@ -16,18 +16,18 @@ pub(crate) fn process( let mut output = HandlerOutput::builder(); // Unwrap the old channel end and validate it against the message. - let mut channel_end = ctx.channel_end(&(msg.port_id().clone(), msg.channel_id().clone()))?; + let mut channel_end = ctx.channel_end(&(msg.port_id.clone(), msg.channel_id.clone()))?; // Validate that the channel end is in a state where it can be closed. if channel_end.state_matches(&State::Closed) { return Err(Error::invalid_channel_state( - msg.channel_id().clone(), + msg.channel_id, channel_end.state, )); } // Channel capabilities - let channel_cap = ctx.authenticated_capability(&msg.port_id().clone())?; + let channel_cap = ctx.authenticated_capability(&msg.port_id)?; // An OPEN IBC connection running on the local (host) chain should exist. if channel_end.connection_hops().len() != 1 { @@ -51,8 +51,8 @@ pub(crate) fn process( channel_end.set_state(State::Closed); let result = ChannelResult { - port_id: msg.port_id().clone(), - channel_id: msg.channel_id().clone(), + port_id: msg.port_id.clone(), + channel_id: msg.channel_id.clone(), channel_id_state: ChannelIdState::Reused, channel_cap, channel_end, @@ -60,8 +60,8 @@ pub(crate) fn process( let event_attributes = Attributes { height: ctx.host_height().clone(), - port_id: msg.port_id.clone(), - channel_id: Some(msg.channel_id().clone()), + port_id: msg.port_id, + channel_id: Some(msg.channel_id), ..Default::default() }; output.emit(IbcEvent::CloseInitChannel(event_attributes.into())); diff --git a/modules/src/ics04_channel/handler/chan_open_ack.rs b/modules/src/core/ics04_channel/handler/chan_open_ack.rs similarity index 70% rename from modules/src/ics04_channel/handler/chan_open_ack.rs rename to modules/src/core/ics04_channel/handler/chan_open_ack.rs index f824b4f32..633e9a0ac 100644 --- a/modules/src/ics04_channel/handler/chan_open_ack.rs +++ b/modules/src/core/ics04_channel/handler/chan_open_ack.rs @@ -1,15 +1,14 @@ //! Protocol logic specific to ICS4 messages of type `MsgChannelOpenAck`. +use crate::core::ics03_connection::connection::State as ConnectionState; +use crate::core::ics04_channel::channel::{ChannelEnd, Counterparty, State}; +use crate::core::ics04_channel::context::ChannelReader; +use crate::core::ics04_channel::error::Error; +use crate::core::ics04_channel::events::Attributes; +use crate::core::ics04_channel::handler::verify::verify_channel_proofs; +use crate::core::ics04_channel::handler::{ChannelIdState, ChannelResult}; +use crate::core::ics04_channel::msgs::chan_open_ack::MsgChannelOpenAck; use crate::events::IbcEvent; use crate::handler::{HandlerOutput, HandlerResult}; -use crate::ics02_client::height::Height; -use crate::ics03_connection::connection::State as ConnectionState; -use crate::ics04_channel::channel::{ChannelEnd, Counterparty, State}; -use crate::ics04_channel::context::ChannelReader; -use crate::ics04_channel::error::Error; -use crate::ics04_channel::events::Attributes; -use crate::ics04_channel::handler::verify::verify_channel_proofs; -use crate::ics04_channel::handler::{ChannelIdState, ChannelResult}; -use crate::ics04_channel::msgs::chan_open_ack::MsgChannelOpenAck; use crate::prelude::*; pub(crate) fn process( @@ -18,24 +17,19 @@ pub(crate) fn process( ) -> HandlerResult { let mut output = HandlerOutput::builder(); - // Unwrap the old channel end and validate it against the message. - - let mut channel_end = ctx.channel_end(&(msg.port_id().clone(), msg.channel_id().clone()))?; + // Unwrap the old channel end and validate it against the message.= + let mut channel_end = ctx.channel_end(&(msg.port_id.clone(), msg.channel_id.clone()))?; // Validate that the channel end is in a state where it can be ack. if !channel_end.state_matches(&State::Init) && !channel_end.state_matches(&State::TryOpen) { return Err(Error::invalid_channel_state( - msg.channel_id().clone(), + msg.channel_id, channel_end.state, )); } // Channel capabilities - let channel_cap = ctx.authenticated_capability(&msg.port_id().clone())?; - tracing::info!( - "in ics04_channel: [channel_open_ack] >> channel_cap: {:?}", - channel_cap - ); + let channel_cap = ctx.authenticated_capability(&msg.port_id)?; // An OPEN IBC connection running on the local (host) chain should exist. @@ -58,7 +52,7 @@ pub(crate) fn process( // 1. Setup: build the Channel as we expect to find it on the other party. let expected_counterparty = - Counterparty::new(msg.port_id().clone(), Some(msg.channel_id().clone())); + Counterparty::new(msg.port_id.clone(), Some(msg.channel_id.clone())); let counterparty = conn.counterparty(); tracing::info!( @@ -80,30 +74,31 @@ pub(crate) fn process( *channel_end.ordering(), expected_counterparty, expected_connection_hops, - msg.counterparty_version().clone(), + msg.counterparty_version.clone(), ); - // TODO! after must modify + + // set the counterparty channel id to verify against it channel_end.set_counterparty_channel_id(msg.counterparty_channel_id.clone()); //2. Verify proofs verify_channel_proofs( ctx, + msg.proofs.height(), &channel_end, &conn, &expected_channel_end, - msg.proofs(), + &msg.proofs, )?; output.log("success: channel open ack "); // Transition the channel end to the new state & pick a version. channel_end.set_state(State::Open); - channel_end.set_version(msg.counterparty_version().clone()); - channel_end.set_counterparty_channel_id(msg.counterparty_channel_id.clone()); + channel_end.set_version(msg.counterparty_version.clone()); let result = ChannelResult { - port_id: msg.port_id().clone(), - channel_id: msg.channel_id().clone(), + port_id: msg.port_id.clone(), + channel_id: msg.channel_id.clone(), channel_id_state: ChannelIdState::Reused, channel_cap, channel_end, @@ -111,8 +106,8 @@ pub(crate) fn process( let event_attributes = Attributes { height: ctx.host_height().clone(), - port_id: msg.port_id.clone(), - channel_id: Some(msg.channel_id().clone()), + port_id: msg.port_id, + channel_id: Some(msg.channel_id), ..Default::default() }; output.emit(IbcEvent::OpenAckChannel(event_attributes.into())); @@ -122,29 +117,29 @@ pub(crate) fn process( #[cfg(test)] mod tests { - use crate::prelude::*; - use core::convert::TryFrom; use core::str::FromStr; - use test_env_log::test; + use test_log::test; + + use crate::core::ics03_connection::connection::ConnectionEnd; + use crate::core::ics03_connection::connection::Counterparty as ConnectionCounterparty; + use crate::core::ics03_connection::connection::State as ConnectionState; + use crate::core::ics03_connection::msgs::conn_open_init::test_util::get_dummy_raw_msg_conn_open_init; + use crate::core::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; + use crate::core::ics03_connection::msgs::conn_open_try::test_util::get_dummy_raw_msg_conn_open_try; + use crate::core::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; + use crate::core::ics03_connection::version::get_compatible_versions; + use crate::core::ics04_channel::channel::{ChannelEnd, Counterparty, State}; + use crate::core::ics04_channel::handler::{channel_dispatch, ChannelResult}; + use crate::core::ics04_channel::msgs::chan_open_ack::test_util::get_dummy_raw_msg_chan_open_ack; + use crate::core::ics04_channel::msgs::chan_open_ack::MsgChannelOpenAck; + use crate::core::ics04_channel::msgs::chan_open_try::test_util::get_dummy_raw_msg_chan_open_try; + use crate::core::ics04_channel::msgs::chan_open_try::MsgChannelOpenTry; + use crate::core::ics04_channel::msgs::ChannelMsg; + use crate::core::ics24_host::identifier::ConnectionId; use crate::events::IbcEvent; - use crate::ics03_connection::connection::ConnectionEnd; - use crate::ics03_connection::connection::Counterparty as ConnectionCounterparty; - use crate::ics03_connection::connection::State as ConnectionState; - use crate::ics03_connection::msgs::conn_open_init::test_util::get_dummy_raw_msg_conn_open_init; - use crate::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; - use crate::ics03_connection::msgs::conn_open_try::test_util::get_dummy_raw_msg_conn_open_try; - use crate::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; - use crate::ics03_connection::version::get_compatible_versions; - use crate::ics04_channel::channel::{ChannelEnd, Counterparty, State}; - use crate::ics04_channel::handler::{channel_dispatch, ChannelResult}; - use crate::ics04_channel::msgs::chan_open_ack::test_util::get_dummy_raw_msg_chan_open_ack; - use crate::ics04_channel::msgs::chan_open_ack::MsgChannelOpenAck; - use crate::ics04_channel::msgs::chan_open_try::test_util::get_dummy_raw_msg_chan_open_try; - use crate::ics04_channel::msgs::chan_open_try::MsgChannelOpenTry; - use crate::ics04_channel::msgs::ChannelMsg; - use crate::ics24_host::identifier::ConnectionId; use crate::mock::context::MockContext; + use crate::prelude::*; use crate::Height; // TODO: The tests here are very fragile and complex. @@ -168,11 +163,11 @@ mod tests { let conn_end = ConnectionEnd::new( ConnectionState::Open, - msg_conn_init.client_id().clone(), + msg_conn_init.client_id.clone(), ConnectionCounterparty::new( - msg_conn_init.counterparty().client_id().clone(), + msg_conn_init.counterparty.client_id().clone(), Some(ConnectionId::from_str("defaultConnection-1").unwrap()), - msg_conn_init.counterparty().prefix().clone(), + msg_conn_init.counterparty.prefix().clone(), ), get_compatible_versions(), msg_conn_init.delay_period, @@ -209,22 +204,22 @@ mod tests { State::Init, *msg_chan_try.channel.ordering(), Counterparty::new( - msg_chan_ack.port_id().clone(), - Some(msg_chan_ack.channel_id().clone()), + msg_chan_ack.port_id.clone(), + Some(msg_chan_ack.channel_id.clone()), ), connection_vec0.clone(), - msg_chan_try.channel.version(), + msg_chan_try.channel.version().clone(), ); let failed_chan_end = ChannelEnd::new( State::Open, *msg_chan_try.channel.ordering(), Counterparty::new( - msg_chan_ack.port_id().clone(), - Some(msg_chan_ack.channel_id().clone()), + msg_chan_ack.port_id.clone(), + Some(msg_chan_ack.channel_id.clone()), ), connection_vec0, - msg_chan_try.channel.version(), + msg_chan_try.channel.version().clone(), ); let tests: Vec = vec![ @@ -239,13 +234,13 @@ mod tests { ctx: context .clone() .with_client( - msg_conn_try.client_id(), + &msg_conn_try.client_id, Height::new(0, client_consensus_state_height), ) - .with_port_capability(msg_chan_ack.port_id().clone()) + .with_port_capability(msg_chan_ack.port_id.clone()) .with_channel( - msg_chan_ack.port_id().clone(), - msg_chan_ack.channel_id().clone(), + msg_chan_ack.port_id.clone(), + msg_chan_ack.channel_id.clone(), failed_chan_end, ), msg: ChannelMsg::ChannelOpenAck(msg_chan_ack.clone()), @@ -257,13 +252,13 @@ mod tests { ctx: context .clone() .with_client( - msg_conn_try.client_id(), + &msg_conn_try.client_id, Height::new(0, client_consensus_state_height), ) .with_connection(cid.clone(), conn_end.clone()) .with_channel( - msg_chan_ack.port_id().clone(), - msg_chan_ack.channel_id().clone(), + msg_chan_ack.port_id.clone(), + msg_chan_ack.channel_id.clone(), chan_end.clone(), ), msg: ChannelMsg::ChannelOpenAck(msg_chan_ack.clone()), @@ -274,13 +269,13 @@ mod tests { ctx: context .clone() .with_client( - msg_conn_try.client_id(), + &msg_conn_try.client_id, Height::new(0, client_consensus_state_height), ) - .with_port_capability(msg_chan_ack.port_id().clone()) + .with_port_capability(msg_chan_ack.port_id.clone()) .with_channel( - msg_chan_ack.port_id().clone(), - msg_chan_ack.channel_id().clone(), + msg_chan_ack.port_id.clone(), + msg_chan_ack.channel_id.clone(), chan_end.clone(), ), msg: ChannelMsg::ChannelOpenAck(msg_chan_ack.clone()), @@ -291,10 +286,10 @@ mod tests { ctx: context .clone() .with_connection(cid.clone(), conn_end.clone()) - .with_port_capability(msg_chan_ack.port_id().clone()) + .with_port_capability(msg_chan_ack.port_id.clone()) .with_channel( - msg_chan_ack.port_id().clone(), - msg_chan_ack.channel_id().clone(), + msg_chan_ack.port_id.clone(), + msg_chan_ack.channel_id.clone(), chan_end.clone(), ), msg: ChannelMsg::ChannelOpenAck(msg_chan_ack.clone()), @@ -304,14 +299,14 @@ mod tests { name: "Good parameters".to_string(), ctx: context // .clone() .with_client( - msg_conn_try.client_id(), + &msg_conn_try.client_id, Height::new(0, client_consensus_state_height), ) .with_connection(cid, conn_end) - .with_port_capability(msg_chan_ack.port_id().clone()) + .with_port_capability(msg_chan_ack.port_id.clone()) .with_channel( - msg_chan_ack.port_id().clone(), - msg_chan_ack.channel_id().clone(), + msg_chan_ack.port_id.clone(), + msg_chan_ack.channel_id.clone(), chan_end, ), msg: ChannelMsg::ChannelOpenAck(msg_chan_ack), diff --git a/modules/src/ics04_channel/handler/chan_open_confirm.rs b/modules/src/core/ics04_channel/handler/chan_open_confirm.rs similarity index 71% rename from modules/src/ics04_channel/handler/chan_open_confirm.rs rename to modules/src/core/ics04_channel/handler/chan_open_confirm.rs index 56cb75c92..4724cd670 100644 --- a/modules/src/ics04_channel/handler/chan_open_confirm.rs +++ b/modules/src/core/ics04_channel/handler/chan_open_confirm.rs @@ -1,14 +1,14 @@ //! Protocol logic specific to ICS4 messages of type `MsgChannelOpenConfirm`. +use crate::core::ics03_connection::connection::State as ConnectionState; +use crate::core::ics04_channel::channel::{ChannelEnd, Counterparty, State}; +use crate::core::ics04_channel::context::ChannelReader; +use crate::core::ics04_channel::error::Error; +use crate::core::ics04_channel::events::Attributes; +use crate::core::ics04_channel::handler::verify::verify_channel_proofs; +use crate::core::ics04_channel::handler::{ChannelIdState, ChannelResult}; +use crate::core::ics04_channel::msgs::chan_open_confirm::MsgChannelOpenConfirm; use crate::events::IbcEvent; use crate::handler::{HandlerOutput, HandlerResult}; -use crate::ics03_connection::connection::State as ConnectionState; -use crate::ics04_channel::channel::{ChannelEnd, Counterparty, State}; -use crate::ics04_channel::context::ChannelReader; -use crate::ics04_channel::error::Error; -use crate::ics04_channel::events::Attributes; -use crate::ics04_channel::handler::verify::verify_channel_proofs; -use crate::ics04_channel::handler::{ChannelIdState, ChannelResult}; -use crate::ics04_channel::msgs::chan_open_confirm::MsgChannelOpenConfirm; use crate::prelude::*; pub(crate) fn process( @@ -18,18 +18,18 @@ pub(crate) fn process( let mut output = HandlerOutput::builder(); // Unwrap the old channel end and validate it against the message. - let mut channel_end = ctx.channel_end(&(msg.port_id().clone(), msg.channel_id().clone()))?; + let mut channel_end = ctx.channel_end(&(msg.port_id.clone(), msg.channel_id.clone()))?; // Validate that the channel end is in a state where it can be confirmed. if !channel_end.state_matches(&State::TryOpen) { return Err(Error::invalid_channel_state( - msg.channel_id().clone(), + msg.channel_id, channel_end.state, )); } // Channel capabilities - let channel_cap = ctx.authenticated_capability(&msg.port_id().clone())?; + let channel_cap = ctx.authenticated_capability(&msg.port_id)?; // An OPEN IBC connection running on the local (host) chain should exist. if channel_end.connection_hops().len() != 1 { @@ -51,7 +51,7 @@ pub(crate) fn process( // 1. Setup: build the Channel as we expect to find it on the other party. let expected_counterparty = - Counterparty::new(msg.port_id().clone(), Some(msg.channel_id().clone())); + Counterparty::new(msg.port_id.clone(), Some(msg.channel_id.clone())); let connection_counterparty = conn.counterparty(); let ccid = connection_counterparty.connection_id().ok_or_else(|| { @@ -65,15 +65,16 @@ pub(crate) fn process( *channel_end.ordering(), expected_counterparty, expected_connection_hops, - channel_end.version(), + channel_end.version().clone(), ); //2. Verify proofs verify_channel_proofs( ctx, + msg.proofs.height(), &channel_end, &conn, &expected_channel_end, - msg.proofs(), + &msg.proofs, ) .map_err(Error::chan_open_confirm_proof_verification)?; @@ -83,8 +84,8 @@ pub(crate) fn process( channel_end.set_state(State::Open); let result = ChannelResult { - port_id: msg.port_id().clone(), - channel_id: msg.channel_id().clone(), + port_id: msg.port_id.clone(), + channel_id: msg.channel_id.clone(), channel_id_state: ChannelIdState::Reused, channel_cap, channel_end: channel_end.clone(), @@ -92,8 +93,8 @@ pub(crate) fn process( let event_attributes = Attributes { height: ctx.host_height().clone(), - port_id: msg.port_id.clone(), - channel_id: Some(msg.channel_id.clone()), + port_id: msg.port_id, + channel_id: Some(msg.channel_id), ..Default::default() }; output.emit(IbcEvent::OpenConfirmChannel(event_attributes.into())); @@ -104,23 +105,24 @@ pub(crate) fn process( #[cfg(test)] mod tests { use crate::prelude::*; - use core::convert::TryFrom; - use test_env_log::test; + use test_log::test; + + use crate::core::ics02_client::client_type::ClientType; + use crate::core::ics03_connection::connection::ConnectionEnd; + use crate::core::ics03_connection::connection::Counterparty as ConnectionCounterparty; + use crate::core::ics03_connection::connection::State as ConnectionState; + use crate::core::ics03_connection::context::ConnectionReader; + use crate::core::ics03_connection::msgs::test_util::get_dummy_raw_counterparty; + use crate::core::ics03_connection::version::get_compatible_versions; + use crate::core::ics04_channel::channel::{ChannelEnd, Counterparty, Order, State}; + use crate::core::ics04_channel::handler::{channel_dispatch, ChannelResult}; + use crate::core::ics04_channel::msgs::chan_open_confirm::test_util::get_dummy_raw_msg_chan_open_confirm; + use crate::core::ics04_channel::msgs::chan_open_confirm::MsgChannelOpenConfirm; + use crate::core::ics04_channel::msgs::ChannelMsg; + use crate::core::ics04_channel::Version; + use crate::core::ics24_host::identifier::{ClientId, ConnectionId}; use crate::events::IbcEvent; - use crate::ics02_client::client_type::ClientType; - use crate::ics03_connection::connection::ConnectionEnd; - use crate::ics03_connection::connection::Counterparty as ConnectionCounterparty; - use crate::ics03_connection::connection::State as ConnectionState; - use crate::ics03_connection::context::ConnectionReader; - use crate::ics03_connection::msgs::test_util::get_dummy_raw_counterparty; - use crate::ics03_connection::version::get_compatible_versions; - use crate::ics04_channel::channel::{ChannelEnd, Counterparty, Order, State}; - use crate::ics04_channel::handler::{channel_dispatch, ChannelResult}; - use crate::ics04_channel::msgs::chan_open_confirm::test_util::get_dummy_raw_msg_chan_open_confirm; - use crate::ics04_channel::msgs::chan_open_confirm::MsgChannelOpenConfirm; - use crate::ics04_channel::msgs::ChannelMsg; - use crate::ics24_host::identifier::{ClientId, ConnectionId}; use crate::mock::context::MockContext; use crate::timestamp::ZERO_DURATION; use crate::Height; @@ -157,11 +159,11 @@ mod tests { State::TryOpen, Order::default(), Counterparty::new( - msg_chan_confirm.port_id().clone(), - Some(msg_chan_confirm.channel_id().clone()), + msg_chan_confirm.port_id.clone(), + Some(msg_chan_confirm.channel_id.clone()), ), vec![conn_id.clone()], - "".to_string(), + Version::default(), ); let tests: Vec = vec![Test { @@ -169,10 +171,10 @@ mod tests { ctx: context .with_client(&client_id, Height::new(0, client_consensus_state_height)) .with_connection(conn_id, conn_end) - .with_port_capability(msg_chan_confirm.port_id().clone()) + .with_port_capability(msg_chan_confirm.port_id.clone()) .with_channel( - msg_chan_confirm.port_id().clone(), - msg_chan_confirm.channel_id().clone(), + msg_chan_confirm.port_id.clone(), + msg_chan_confirm.channel_id.clone(), chan_end, ), msg: ChannelMsg::ChannelOpenConfirm(msg_chan_confirm), diff --git a/modules/src/ics04_channel/handler/chan_open_init.rs b/modules/src/core/ics04_channel/handler/chan_open_init.rs similarity index 69% rename from modules/src/ics04_channel/handler/chan_open_init.rs rename to modules/src/core/ics04_channel/handler/chan_open_init.rs index a3c4668b8..f0fa2559b 100644 --- a/modules/src/ics04_channel/handler/chan_open_init.rs +++ b/modules/src/core/ics04_channel/handler/chan_open_init.rs @@ -1,15 +1,14 @@ //! Protocol logic specific to ICS4 messages of type `MsgChannelOpenInit`. +use crate::core::ics04_channel::channel::{ChannelEnd, State}; +use crate::core::ics04_channel::context::ChannelReader; +use crate::core::ics04_channel::error::Error; +use crate::core::ics04_channel::events::Attributes; +use crate::core::ics04_channel::handler::{ChannelIdState, ChannelResult}; +use crate::core::ics04_channel::msgs::chan_open_init::MsgChannelOpenInit; +use crate::core::ics24_host::identifier::ChannelId; use crate::events::IbcEvent; use crate::handler::{HandlerOutput, HandlerResult}; -use crate::ics02_client::height::Height; -use crate::ics04_channel::channel::{ChannelEnd, State}; -use crate::ics04_channel::context::ChannelReader; -use crate::ics04_channel::error::Error; -use crate::ics04_channel::events::Attributes; -use crate::ics04_channel::handler::{ChannelIdState, ChannelResult}; -use crate::ics04_channel::msgs::chan_open_init::MsgChannelOpenInit; -use crate::ics24_host::identifier::ChannelId; use crate::prelude::*; pub(crate) fn process( @@ -19,33 +18,28 @@ pub(crate) fn process( let mut output = HandlerOutput::builder(); // Channel capabilities - let channel_cap = ctx.authenticated_capability(&msg.port_id().clone())?; + let channel_cap = ctx.authenticated_capability(&msg.port_id)?; - if msg.channel().connection_hops().len() != 1 { + if msg.channel.connection_hops().len() != 1 { return Err(Error::invalid_connection_hops_length( 1, - msg.channel().connection_hops().len(), + msg.channel.connection_hops().len(), )); } // An IBC connection running on the local (host) chain should exist. - let conn = ctx.connection_end(&msg.channel().connection_hops()[0])?; + let conn = ctx.connection_end(&msg.channel.connection_hops()[0])?; let get_versions = conn.versions(); - let version = match get_versions.as_slice() { + let version = match get_versions { [version] => version, _ => return Err(Error::invalid_version_length_connection()), }; - let channel_feature = msg.channel().ordering().to_string(); + let channel_feature = msg.channel.ordering().to_string(); if !version.is_supported_feature(channel_feature) { return Err(Error::channel_feature_not_suported_by_connection()); } - // TODO: Check that `version` is non empty but not necessary coherent - if msg.channel().version().is_empty() { - return Err(Error::empty_version()); - } - // Channel identifier construction. let id_counter = ctx.channel_counter()?; let chan_id = ChannelId::new(id_counter); @@ -57,33 +51,25 @@ pub(crate) fn process( let new_channel_end = ChannelEnd::new( State::Init, - *msg.channel().ordering(), - msg.channel().counterparty().clone(), - msg.channel().connection_hops().clone(), - msg.channel().version(), + *msg.channel.ordering(), + msg.channel.counterparty().clone(), + msg.channel.connection_hops().clone(), + msg.channel.version().clone(), ); output.log("success: no channel found"); let result = ChannelResult { - port_id: msg.port_id().clone(), + port_id: msg.port_id.clone(), channel_id: chan_id.clone(), channel_end: new_channel_end, channel_id_state: ChannelIdState::Generated, channel_cap, }; - // pub struct Attributes { - // pub height: Height, - // pub port_id: PortId, - // pub channel_id: Option, - // pub connection_id: ConnectionId, - // pub counterparty_port_id: PortId, - // pub counterparty_channel_id: Option, - // } let event_attributes = Attributes { height: ctx.host_height().clone(), - port_id: msg.port_id.clone(), + port_id: msg.port_id, channel_id: Some(chan_id), connection_id: msg.channel.connection_hops[0].clone(), counterparty_port_id: msg.channel.counterparty().port_id.clone(), @@ -97,21 +83,21 @@ pub(crate) fn process( #[cfg(test)] mod tests { use crate::prelude::*; - use core::convert::TryFrom; - use test_env_log::test; + use test_log::test; + + use crate::core::ics03_connection::connection::ConnectionEnd; + use crate::core::ics03_connection::connection::State as ConnectionState; + use crate::core::ics03_connection::msgs::conn_open_init::test_util::get_dummy_raw_msg_conn_open_init; + use crate::core::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; + use crate::core::ics03_connection::version::get_compatible_versions; + use crate::core::ics04_channel::channel::State; + use crate::core::ics04_channel::handler::{channel_dispatch, ChannelResult}; + use crate::core::ics04_channel::msgs::chan_open_init::test_util::get_dummy_raw_msg_chan_open_init; + use crate::core::ics04_channel::msgs::chan_open_init::MsgChannelOpenInit; + use crate::core::ics04_channel::msgs::ChannelMsg; + use crate::core::ics24_host::identifier::ConnectionId; use crate::events::IbcEvent; - use crate::ics03_connection::connection::ConnectionEnd; - use crate::ics03_connection::connection::State as ConnectionState; - use crate::ics03_connection::msgs::conn_open_init::test_util::get_dummy_raw_msg_conn_open_init; - use crate::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; - use crate::ics03_connection::version::get_compatible_versions; - use crate::ics04_channel::channel::State; - use crate::ics04_channel::handler::{channel_dispatch, ChannelResult}; - use crate::ics04_channel::msgs::chan_open_init::test_util::get_dummy_raw_msg_chan_open_init; - use crate::ics04_channel::msgs::chan_open_init::MsgChannelOpenInit; - use crate::ics04_channel::msgs::ChannelMsg; - use crate::ics24_host::identifier::ConnectionId; use crate::mock::context::MockContext; #[test] @@ -133,8 +119,8 @@ mod tests { let init_conn_end = ConnectionEnd::new( ConnectionState::Init, - msg_conn_init.client_id().clone(), - msg_conn_init.counterparty().clone(), + msg_conn_init.client_id.clone(), + msg_conn_init.counterparty.clone(), get_compatible_versions(), msg_conn_init.delay_period, ); @@ -164,8 +150,7 @@ mod tests { .with_port_capability( MsgChannelOpenInit::try_from(get_dummy_raw_msg_chan_open_init()) .unwrap() - .port_id() - .clone(), + .port_id, ), msg: ChannelMsg::ChannelOpenInit(msg_chan_init), want_pass: true, @@ -195,7 +180,7 @@ mod tests { let msg_init = test.msg.clone(); if let ChannelMsg::ChannelOpenInit(msg_init) = msg_init { - assert_eq!(res.port_id.clone(), msg_init.port_id().clone()); + assert_eq!(res.port_id.clone(), msg_init.port_id.clone()); } for e in proto_output.events.iter() { diff --git a/modules/src/ics04_channel/handler/chan_open_try.rs b/modules/src/core/ics04_channel/handler/chan_open_try.rs similarity index 85% rename from modules/src/ics04_channel/handler/chan_open_try.rs rename to modules/src/core/ics04_channel/handler/chan_open_try.rs index 6f4f7fa53..4f81e8d61 100644 --- a/modules/src/ics04_channel/handler/chan_open_try.rs +++ b/modules/src/core/ics04_channel/handler/chan_open_try.rs @@ -1,16 +1,16 @@ //! Protocol logic specific to ICS4 messages of type `MsgChannelOpenTry`. +use crate::core::ics03_connection::connection::State as ConnectionState; +use crate::core::ics04_channel::channel::{ChannelEnd, Counterparty, State}; +use crate::core::ics04_channel::context::ChannelReader; +use crate::core::ics04_channel::error::Error; +use crate::core::ics04_channel::events::Attributes; +use crate::core::ics04_channel::handler::verify::verify_channel_proofs; +use crate::core::ics04_channel::handler::{ChannelIdState, ChannelResult}; +use crate::core::ics04_channel::msgs::chan_open_try::MsgChannelOpenTry; +use crate::core::ics24_host::identifier::ChannelId; use crate::events::IbcEvent; use crate::handler::{HandlerOutput, HandlerResult}; -use crate::ics03_connection::connection::State as ConnectionState; -use crate::ics04_channel::channel::{ChannelEnd, Counterparty, State}; -use crate::ics04_channel::context::ChannelReader; -use crate::ics04_channel::error::Error; -use crate::ics04_channel::events::Attributes; -use crate::ics04_channel::handler::verify::verify_channel_proofs; -use crate::ics04_channel::handler::{ChannelIdState, ChannelResult}; -use crate::ics04_channel::msgs::chan_open_try::MsgChannelOpenTry; -use crate::ics24_host::identifier::ChannelId; use crate::prelude::*; pub(crate) fn process( @@ -20,16 +20,16 @@ pub(crate) fn process( let mut output = HandlerOutput::builder(); // Unwrap the old channel end (if any) and validate it against the message. - let (mut new_channel_end, channel_id) = match msg.previous_channel_id() { + let (mut new_channel_end, channel_id) = match &msg.previous_channel_id { Some(prev_id) => { - let old_channel_end = ctx.channel_end(&(msg.port_id().clone(), prev_id.clone()))?; + let old_channel_end = ctx.channel_end(&(msg.port_id.clone(), prev_id.clone()))?; // Validate that existing channel end matches with the one we're trying to establish. if old_channel_end.state_matches(&State::Init) && old_channel_end.order_matches(msg.channel.ordering()) && old_channel_end.connection_hops_matches(msg.channel.connection_hops()) && old_channel_end.counterparty_matches(msg.channel.counterparty()) - && old_channel_end.version_matches(&msg.channel.version()) + && old_channel_end.version_matches(msg.channel.version()) { // A ChannelEnd already exists and all validation passed. Ok((old_channel_end, prev_id.clone())) @@ -45,7 +45,7 @@ pub(crate) fn process( *msg.channel.ordering(), msg.channel.counterparty().clone(), msg.channel.connection_hops().clone(), - msg.counterparty_version().clone(), + msg.counterparty_version.clone(), ); // Channel identifier construction. @@ -69,7 +69,7 @@ pub(crate) fn process( )); } - let conn = ctx.connection_end(&msg.channel().connection_hops()[0])?; + let conn = ctx.connection_end(&msg.channel.connection_hops()[0])?; if !conn.state_matches(&ConnectionState::Open) { return Err(Error::connection_not_open( msg.channel.connection_hops()[0].clone(), @@ -77,31 +77,27 @@ pub(crate) fn process( } let get_versions = conn.versions(); - let version = match get_versions.as_slice() { + let version = match get_versions { [version] => version, _ => return Err(Error::invalid_version_length_connection()), }; - let channel_feature = msg.channel().ordering().to_string(); + let channel_feature = msg.channel.ordering().to_string(); if !version.is_supported_feature(channel_feature) { return Err(Error::channel_feature_not_suported_by_connection()); } // Channel capabilities - let channel_cap = ctx.authenticated_capability(&msg.port_id().clone())?; - - if msg.channel().version().is_empty() { - return Err(Error::empty_version()); - } + let channel_cap = ctx.authenticated_capability(&msg.port_id)?; // Proof verification in two steps: // 1. Setup: build the Channel as we expect to find it on the other party. // the port should be identical with the port we're using; the channel id should not be set // since the counterparty cannot know yet which ID did we choose. - let expected_counterparty = Counterparty::new(msg.port_id().clone(), None); + let expected_counterparty = Counterparty::new(msg.port_id.clone(), None); let counterparty = conn.counterparty(); let ccid = counterparty.connection_id().ok_or_else(|| { - Error::undefined_connection_counterparty(msg.channel().connection_hops()[0].clone()) + Error::undefined_connection_counterparty(msg.channel.connection_hops()[0].clone()) })?; let expected_connection_hops = vec![ccid.clone()]; @@ -111,16 +107,17 @@ pub(crate) fn process( *msg.channel.ordering(), expected_counterparty, expected_connection_hops, - msg.counterparty_version().clone(), + msg.counterparty_version.clone(), ); // 2. Actual proofs are verified now. verify_channel_proofs( ctx, + msg.proofs.height(), &new_channel_end, &conn, &expected_channel_end, - msg.proofs(), + &msg.proofs, )?; output.log("success: channel open try "); @@ -129,7 +126,7 @@ pub(crate) fn process( new_channel_end.set_state(State::TryOpen); let result = ChannelResult { - port_id: msg.port_id().clone(), + port_id: msg.port_id.clone(), channel_cap, channel_id_state: if matches!(msg.previous_channel_id, None) { ChannelIdState::Generated @@ -156,25 +153,25 @@ pub(crate) fn process( #[cfg(test)] mod tests { use crate::prelude::*; - use core::convert::TryFrom; - use test_env_log::test; + use test_log::test; + + use crate::core::ics02_client::client_type::ClientType; + use crate::core::ics02_client::error as ics02_error; + use crate::core::ics03_connection::connection::ConnectionEnd; + use crate::core::ics03_connection::connection::Counterparty as ConnectionCounterparty; + use crate::core::ics03_connection::connection::State as ConnectionState; + use crate::core::ics03_connection::error as ics03_error; + use crate::core::ics03_connection::msgs::test_util::get_dummy_raw_counterparty; + use crate::core::ics03_connection::version::get_compatible_versions; + use crate::core::ics04_channel::channel::{ChannelEnd, State}; + use crate::core::ics04_channel::handler::{channel_dispatch, ChannelResult}; + use crate::core::ics04_channel::msgs::chan_open_try::test_util::get_dummy_raw_msg_chan_open_try; + use crate::core::ics04_channel::msgs::chan_open_try::MsgChannelOpenTry; + use crate::core::ics04_channel::msgs::ChannelMsg; + use crate::core::ics04_channel::{error, Version}; + use crate::core::ics24_host::identifier::{ChannelId, ClientId, ConnectionId}; use crate::events::IbcEvent; - use crate::ics02_client::client_type::ClientType; - use crate::ics02_client::error as ics02_error; - use crate::ics03_connection::connection::ConnectionEnd; - use crate::ics03_connection::connection::Counterparty as ConnectionCounterparty; - use crate::ics03_connection::connection::State as ConnectionState; - use crate::ics03_connection::error as ics03_error; - use crate::ics03_connection::msgs::test_util::get_dummy_raw_counterparty; - use crate::ics03_connection::version::get_compatible_versions; - use crate::ics04_channel::channel::{ChannelEnd, State}; - use crate::ics04_channel::error; - use crate::ics04_channel::handler::{channel_dispatch, ChannelResult}; - use crate::ics04_channel::msgs::chan_open_try::test_util::get_dummy_raw_msg_chan_open_try; - use crate::ics04_channel::msgs::chan_open_try::MsgChannelOpenTry; - use crate::ics04_channel::msgs::ChannelMsg; - use crate::ics24_host::identifier::{ChannelId, ClientId, ConnectionId}; use crate::mock::context::MockContext; use crate::timestamp::ZERO_DURATION; use crate::Height; @@ -228,12 +225,12 @@ mod tests { *msg.channel.ordering(), msg.channel.counterparty().clone(), msg.channel.connection_hops().clone(), - msg.channel.version(), + msg.channel.version().clone(), ); // A preloaded channel end that resides in the context. This is constructed so as to be // __inconsistent__ with the incoming ChanOpenTry message `msg` due to its version field. - let version = format!("{}-", msg.channel.version()); + let version = Version::from(format!("{}-", msg.channel.version())); let incorrect_chan_end_ver = ChannelEnd::new( State::Init, *msg.channel.ordering(), @@ -250,7 +247,7 @@ mod tests { *msg.channel.ordering(), msg.channel.counterparty().clone(), hops, - msg.channel.version(), + msg.channel.version().clone(), ); let tests: Vec = vec![ @@ -279,7 +276,7 @@ mod tests { msg: ChannelMsg::ChannelOpenTry(msg_vanilla.clone()), want_pass: false, match_error: { - let connection_id = msg.channel().connection_hops()[0].clone(); + let connection_id = msg.channel.connection_hops()[0].clone(); Box::new(move |e| match e { error::ErrorDetail::Ics03Connection(e) => { assert_eq!( diff --git a/modules/src/ics04_channel/handler/recv_packet.rs b/modules/src/core/ics04_channel/handler/recv_packet.rs similarity index 84% rename from modules/src/ics04_channel/handler/recv_packet.rs rename to modules/src/core/ics04_channel/handler/recv_packet.rs index cd04e820e..e7e1cd213 100644 --- a/modules/src/ics04_channel/handler/recv_packet.rs +++ b/modules/src/core/ics04_channel/handler/recv_packet.rs @@ -1,15 +1,15 @@ +use crate::core::ics02_client::height::Height; +use crate::core::ics03_connection::connection::State as ConnectionState; +use crate::core::ics04_channel::channel::{Counterparty, Order, State}; +use crate::core::ics04_channel::context::ChannelReader; +use crate::core::ics04_channel::error::Error; +use crate::core::ics04_channel::events::ReceivePacket; +use crate::core::ics04_channel::handler::verify::verify_packet_recv_proofs; +use crate::core::ics04_channel::msgs::recv_packet::MsgRecvPacket; +use crate::core::ics04_channel::packet::{PacketResult, Receipt, Sequence}; +use crate::core::ics24_host::identifier::{ChannelId, PortId}; use crate::events::IbcEvent; use crate::handler::{HandlerOutput, HandlerResult}; -use crate::ics02_client::height::Height; -use crate::ics03_connection::connection::State as ConnectionState; -use crate::ics04_channel::channel::{Counterparty, Order, State}; -use crate::ics04_channel::context::ChannelReader; -use crate::ics04_channel::error::Error; -use crate::ics04_channel::events::ReceivePacket; -use crate::ics04_channel::handler::verify::verify_packet_recv_proofs; -use crate::ics04_channel::msgs::recv_packet::MsgRecvPacket; -use crate::ics04_channel::packet::{PacketResult, Receipt, Sequence}; -use crate::ics24_host::identifier::{ChannelId, PortId}; use crate::timestamp::Expiry; #[derive(Clone, Debug)] @@ -60,8 +60,6 @@ pub fn process(ctx: &dyn ChannelReader, msg: MsgRecvPacket) -> HandlerResult HandlerResult HandlerResult HandlerResult HandlerResult HandlerResult HandlerResult Result<(), Error> { - let client_state = ctx.client_state(&client_id)?; + let client_id = connection_end.client_id(); + let client_state = ctx.client_state(client_id)?; // The client must not be frozen. if client_state.is_frozen() { - return Err(Error::frozen_client(client_id)); + return Err(Error::frozen_client(client_id.clone())); } - ctx.client_consensus_state(&client_id, proofs.height())?; + let consensus_state = ctx.client_consensus_state(client_id, proofs.height())?; let client_def = AnyClient::from_client_type(client_state.client_type()); @@ -73,12 +78,15 @@ pub fn verify_packet_recv_proofs( // Verify the proof for the packet against the chain store. client_def .verify_packet_data( + ctx, &client_state, - proofs.height(), + height, + connection_end, proofs.object_proof(), + consensus_state.root(), &packet.source_port, &packet.source_channel, - &packet.sequence, + packet.sequence, commitment, ) .map_err(|e| Error::packet_verification_failed(packet.sequence, e))?; @@ -89,29 +97,36 @@ pub fn verify_packet_recv_proofs( /// Entry point for verifying all proofs bundled in an ICS4 packet ack message. pub fn verify_packet_acknowledgement_proofs( ctx: &dyn ChannelReader, + height: Height, packet: &Packet, acknowledgement: Vec, - client_id: ClientId, + connection_end: &ConnectionEnd, proofs: &Proofs, ) -> Result<(), Error> { - let client_state = ctx.client_state(&client_id)?; + let client_id = connection_end.client_id(); + let client_state = ctx.client_state(client_id)?; // The client must not be frozen. if client_state.is_frozen() { - return Err(Error::frozen_client(client_id)); + return Err(Error::frozen_client(client_id.clone())); } + let consensus_state = ctx.client_consensus_state(client_id, proofs.height())?; + let client_def = AnyClient::from_client_type(client_state.client_type()); // Verify the proof for the packet against the chain store. client_def .verify_packet_acknowledgement( + ctx, &client_state, - proofs.height(), + height, + connection_end, proofs.object_proof(), - &packet.source_port, - &packet.source_channel, - &packet.sequence, + consensus_state.root(), + &packet.destination_port, + &packet.destination_channel, + packet.sequence, acknowledgement, ) .map_err(|e| Error::packet_verification_failed(packet.sequence, e))?; @@ -122,29 +137,36 @@ pub fn verify_packet_acknowledgement_proofs( /// Entry point for verifying all timeout proofs. pub fn verify_next_sequence_recv( ctx: &dyn ChannelReader, - client_id: ClientId, + height: Height, + connection_end: &ConnectionEnd, packet: Packet, seq: Sequence, proofs: &Proofs, ) -> Result<(), Error> { - let client_state = ctx.client_state(&client_id)?; + let client_id = connection_end.client_id(); + let client_state = ctx.client_state(client_id)?; // The client must not be frozen. if client_state.is_frozen() { - return Err(Error::frozen_client(client_id)); + return Err(Error::frozen_client(client_id.clone())); } + let consensus_state = ctx.client_consensus_state(client_id, proofs.height())?; + let client_def = AnyClient::from_client_type(client_state.client_type()); // Verify the proof for the packet against the chain store. client_def .verify_next_sequence_recv( + ctx, &client_state, - proofs.height(), + height, + connection_end, proofs.object_proof(), + consensus_state.root(), &packet.destination_port, &packet.destination_channel, - &seq, + packet.sequence, ) .map_err(|e| Error::packet_verification_failed(seq, e))?; @@ -153,28 +175,35 @@ pub fn verify_next_sequence_recv( pub fn verify_packet_receipt_absence( ctx: &dyn ChannelReader, - client_id: ClientId, + height: Height, + connection_end: &ConnectionEnd, packet: Packet, proofs: &Proofs, ) -> Result<(), Error> { - let client_state = ctx.client_state(&client_id)?; + let client_id = connection_end.client_id(); + let client_state = ctx.client_state(client_id)?; // The client must not be frozen. if client_state.is_frozen() { - return Err(Error::frozen_client(client_id)); + return Err(Error::frozen_client(client_id.clone())); } + let consensus_state = ctx.client_consensus_state(client_id, proofs.height())?; + let client_def = AnyClient::from_client_type(client_state.client_type()); // Verify the proof for the packet against the chain store. client_def .verify_packet_receipt_absence( + ctx, &client_state, - proofs.height(), + height, + connection_end, proofs.object_proof(), + consensus_state.root(), &packet.destination_port, &packet.destination_channel, - &packet.sequence, + packet.sequence, ) .map_err(|e| Error::packet_verification_failed(packet.sequence, e))?; diff --git a/modules/src/ics04_channel/handler/write_acknowledgement.rs b/modules/src/core/ics04_channel/handler/write_acknowledgement.rs similarity index 84% rename from modules/src/ics04_channel/handler/write_acknowledgement.rs rename to modules/src/core/ics04_channel/handler/write_acknowledgement.rs index 8eef25b08..38555ab55 100644 --- a/modules/src/ics04_channel/handler/write_acknowledgement.rs +++ b/modules/src/core/ics04_channel/handler/write_acknowledgement.rs @@ -1,8 +1,8 @@ -use crate::ics04_channel::channel::State; -use crate::ics04_channel::events::WriteAcknowledgement; -use crate::ics04_channel::packet::{Packet, PacketResult, Sequence}; -use crate::ics04_channel::{context::ChannelReader, error::Error}; -use crate::ics24_host::identifier::{ChannelId, PortId}; +use crate::core::ics04_channel::channel::State; +use crate::core::ics04_channel::events::WriteAcknowledgement; +use crate::core::ics04_channel::packet::{Packet, PacketResult, Sequence}; +use crate::core::ics04_channel::{context::ChannelReader, error::Error}; +use crate::core::ics24_host::identifier::{ChannelId, PortId}; use crate::prelude::*; use crate::{ events::IbcEvent, @@ -77,21 +77,22 @@ pub fn process( #[cfg(test)] mod tests { use crate::prelude::*; - use core::convert::TryInto; - use test_env_log::test; - - use crate::ics02_client::height::Height; - use crate::ics03_connection::connection::ConnectionEnd; - use crate::ics03_connection::connection::Counterparty as ConnectionCounterparty; - use crate::ics03_connection::connection::State as ConnectionState; - use crate::ics03_connection::version::get_compatible_versions; - use crate::ics04_channel::channel::{ChannelEnd, Counterparty, Order, State}; - use crate::ics04_channel::handler::write_acknowledgement::process; - use crate::ics04_channel::packet::test_utils::get_dummy_raw_packet; - use crate::ics24_host::identifier::{ChannelId, ClientId, ConnectionId, PortId}; + + use test_log::test; + + use crate::core::ics02_client::height::Height; + use crate::core::ics03_connection::connection::ConnectionEnd; + use crate::core::ics03_connection::connection::Counterparty as ConnectionCounterparty; + use crate::core::ics03_connection::connection::State as ConnectionState; + use crate::core::ics03_connection::version::get_compatible_versions; + use crate::core::ics04_channel::channel::{ChannelEnd, Counterparty, Order, State}; + use crate::core::ics04_channel::handler::write_acknowledgement::process; + use crate::core::ics04_channel::packet::test_utils::get_dummy_raw_packet; + use crate::core::ics04_channel::Version; + use crate::core::ics24_host::identifier::{ChannelId, ClientId, ConnectionId, PortId}; use crate::mock::context::MockContext; use crate::timestamp::ZERO_DURATION; - use crate::{events::IbcEvent, ics04_channel::packet::Packet}; + use crate::{core::ics04_channel::packet::Packet, events::IbcEvent}; #[test] fn write_ack_packet_processing() { @@ -122,7 +123,7 @@ mod tests { Some(packet.source_channel.clone()), ), vec![ConnectionId::default()], - "ics20".to_string(), + Version::ics20(), ); let connection_end = ConnectionEnd::new( diff --git a/modules/src/core/ics04_channel/mod.rs b/modules/src/core/ics04_channel/mod.rs new file mode 100644 index 000000000..33a0ace96 --- /dev/null +++ b/modules/src/core/ics04_channel/mod.rs @@ -0,0 +1,14 @@ +//! ICS 04: Channel implementation that facilitates communication between +//! applications and the chains those applications are built upon. + +pub mod channel; +pub mod context; +pub mod error; +pub mod events; + +pub mod handler; +pub mod msgs; +pub mod packet; + +mod version; +pub use version::Version; diff --git a/modules/src/ics04_channel/msgs.rs b/modules/src/core/ics04_channel/msgs.rs similarity index 72% rename from modules/src/ics04_channel/msgs.rs rename to modules/src/core/ics04_channel/msgs.rs index 74f30b9ed..3028f19f2 100644 --- a/modules/src/ics04_channel/msgs.rs +++ b/modules/src/core/ics04_channel/msgs.rs @@ -3,12 +3,12 @@ use acknowledgement::MsgAcknowledgement; -use crate::ics04_channel::msgs::chan_close_confirm::MsgChannelCloseConfirm; -use crate::ics04_channel::msgs::chan_close_init::MsgChannelCloseInit; -use crate::ics04_channel::msgs::chan_open_ack::MsgChannelOpenAck; -use crate::ics04_channel::msgs::chan_open_confirm::MsgChannelOpenConfirm; -use crate::ics04_channel::msgs::chan_open_init::MsgChannelOpenInit; -use crate::ics04_channel::msgs::chan_open_try::MsgChannelOpenTry; +use crate::core::ics04_channel::msgs::chan_close_confirm::MsgChannelCloseConfirm; +use crate::core::ics04_channel::msgs::chan_close_init::MsgChannelCloseInit; +use crate::core::ics04_channel::msgs::chan_open_ack::MsgChannelOpenAck; +use crate::core::ics04_channel::msgs::chan_open_confirm::MsgChannelOpenConfirm; +use crate::core::ics04_channel::msgs::chan_open_init::MsgChannelOpenInit; +use crate::core::ics04_channel::msgs::chan_open_try::MsgChannelOpenTry; use self::{recv_packet::MsgRecvPacket, timeout::MsgTimeout, timeout_on_close::MsgTimeoutOnClose}; diff --git a/modules/src/ics04_channel/msgs/acknowledgement.rs b/modules/src/core/ics04_channel/msgs/acknowledgement.rs similarity index 89% rename from modules/src/ics04_channel/msgs/acknowledgement.rs rename to modules/src/core/ics04_channel/msgs/acknowledgement.rs index 1d2086631..2c1736272 100644 --- a/modules/src/ics04_channel/msgs/acknowledgement.rs +++ b/modules/src/core/ics04_channel/msgs/acknowledgement.rs @@ -1,12 +1,11 @@ use crate::prelude::*; -use core::convert::{TryFrom, TryInto}; use tendermint_proto::Protobuf; use ibc_proto::ibc::core::channel::v1::MsgAcknowledgement as RawMsgAcknowledgement; -use crate::ics04_channel::error::Error; -use crate::ics04_channel::packet::Packet; +use crate::core::ics04_channel::error::Error; +use crate::core::ics04_channel::packet::Packet; use crate::proofs::Proofs; use crate::signer::Signer; use crate::tx_msg::Msg; @@ -38,14 +37,6 @@ impl MsgAcknowledgement { signer, } } - - pub fn acknowledgement(&self) -> &Vec { - &self.acknowledgement - } - - pub fn proofs(&self) -> &Proofs { - &self.proofs - } } impl Msg for MsgAcknowledgement { @@ -68,7 +59,10 @@ impl TryFrom for MsgAcknowledgement { fn try_from(raw_msg: RawMsgAcknowledgement) -> Result { let proofs = Proofs::new( - raw_msg.proof_acked.into(), + raw_msg + .proof_acked + .try_into() + .map_err(Error::invalid_proof)?, None, None, None, @@ -108,7 +102,7 @@ pub mod test_util { use ibc_proto::ibc::core::channel::v1::MsgAcknowledgement as RawMsgAcknowledgement; use ibc_proto::ibc::core::client::v1::Height as RawHeight; - use crate::ics04_channel::packet::test_utils::get_dummy_raw_packet; + use crate::core::ics04_channel::packet::test_utils::get_dummy_raw_packet; use crate::test_utils::{get_dummy_bech32_account, get_dummy_proof}; /// Returns a dummy `RawMsgAcknowledgement`, for testing only! @@ -130,14 +124,14 @@ pub mod test_util { #[cfg(test)] mod test { use crate::prelude::*; - use core::convert::TryInto; - use test_env_log::test; + + use test_log::test; use ibc_proto::ibc::core::channel::v1::MsgAcknowledgement as RawMsgAcknowledgement; - use crate::ics04_channel::error::Error; - use crate::ics04_channel::msgs::acknowledgement::test_util::get_dummy_raw_msg_acknowledgement; - use crate::ics04_channel::msgs::acknowledgement::MsgAcknowledgement; + use crate::core::ics04_channel::error::Error; + use crate::core::ics04_channel::msgs::acknowledgement::test_util::get_dummy_raw_msg_acknowledgement; + use crate::core::ics04_channel::msgs::acknowledgement::MsgAcknowledgement; #[test] fn msg_acknowledgment_try_from_raw() { diff --git a/modules/src/ics04_channel/msgs/chan_close_confirm.rs b/modules/src/core/ics04_channel/msgs/chan_close_confirm.rs similarity index 90% rename from modules/src/ics04_channel/msgs/chan_close_confirm.rs rename to modules/src/core/ics04_channel/msgs/chan_close_confirm.rs index 35849c506..b1e15c149 100644 --- a/modules/src/ics04_channel/msgs/chan_close_confirm.rs +++ b/modules/src/core/ics04_channel/msgs/chan_close_confirm.rs @@ -1,12 +1,11 @@ use crate::prelude::*; -use core::convert::TryFrom; use tendermint_proto::Protobuf; use ibc_proto::ibc::core::channel::v1::MsgChannelCloseConfirm as RawMsgChannelCloseConfirm; -use crate::ics04_channel::error::Error; -use crate::ics24_host::identifier::{ChannelId, PortId}; +use crate::core::ics04_channel::error::Error; +use crate::core::ics24_host::identifier::{ChannelId, PortId}; use crate::proofs::Proofs; use crate::signer::Signer; use crate::tx_msg::Msg; @@ -34,17 +33,6 @@ impl MsgChannelCloseConfirm { signer, } } - - /// Getter: borrow the `port_id` from this message. - pub fn port_id(&self) -> &PortId { - &self.port_id - } - pub fn channel_id(&self) -> &ChannelId { - &self.channel_id - } - pub fn proofs(&self) -> &Proofs { - &self.proofs - } } impl Msg for MsgChannelCloseConfirm { @@ -67,7 +55,10 @@ impl TryFrom for MsgChannelCloseConfirm { fn try_from(raw_msg: RawMsgChannelCloseConfirm) -> Result { let proofs = Proofs::new( - raw_msg.proof_init.into(), + raw_msg + .proof_init + .try_into() + .map_err(Error::invalid_proof)?, None, None, None, @@ -105,7 +96,7 @@ pub mod test_util { use ibc_proto::ibc::core::channel::v1::MsgChannelCloseConfirm as RawMsgChannelCloseConfirm; use ibc_proto::ibc::core::client::v1::Height; - use crate::ics24_host::identifier::{ChannelId, PortId}; + use crate::core::ics24_host::identifier::{ChannelId, PortId}; use crate::test_utils::{get_dummy_bech32_account, get_dummy_proof}; /// Returns a dummy `RawMsgChannelCloseConfirm`, for testing only! @@ -126,13 +117,12 @@ pub mod test_util { #[cfg(test)] mod tests { use crate::prelude::*; - use core::convert::TryFrom; use ibc_proto::ibc::core::channel::v1::MsgChannelCloseConfirm as RawMsgChannelCloseConfirm; use ibc_proto::ibc::core::client::v1::Height; - use crate::ics04_channel::msgs::chan_close_confirm::test_util::get_dummy_raw_msg_chan_close_confirm; - use crate::ics04_channel::msgs::chan_close_confirm::MsgChannelCloseConfirm; + use crate::core::ics04_channel::msgs::chan_close_confirm::test_util::get_dummy_raw_msg_chan_close_confirm; + use crate::core::ics04_channel::msgs::chan_close_confirm::MsgChannelCloseConfirm; #[test] fn parse_channel_close_confirm_msg() { @@ -171,7 +161,7 @@ mod tests { name: "Bad port, name too long".to_string(), raw: RawMsgChannelCloseConfirm { port_id: - "abcdefghijklmnsdfasdfasdfasdfasdgafgadsfasdfasdfasdasfdasdfsadfopqrstu" + "abcdefghijklmnsdfasdfasdfasdfasdgafgadsfasdfasdfasdasfdasdfsadfopqrstuabcdefghijklmnsdfasdfasdfasdfasdgafgadsfasdfasdfasdasfdasdfsadfopqrstu" .to_string(), ..default_raw_msg.clone() }, diff --git a/modules/src/ics04_channel/msgs/chan_close_init.rs b/modules/src/core/ics04_channel/msgs/chan_close_init.rs similarity index 89% rename from modules/src/ics04_channel/msgs/chan_close_init.rs rename to modules/src/core/ics04_channel/msgs/chan_close_init.rs index ebbc40a52..107723924 100644 --- a/modules/src/ics04_channel/msgs/chan_close_init.rs +++ b/modules/src/core/ics04_channel/msgs/chan_close_init.rs @@ -1,11 +1,11 @@ use crate::prelude::*; -use core::convert::TryFrom; + use tendermint_proto::Protobuf; use ibc_proto::ibc::core::channel::v1::MsgChannelCloseInit as RawMsgChannelCloseInit; -use crate::ics04_channel::error::Error; -use crate::ics24_host::identifier::{ChannelId, PortId}; +use crate::core::ics04_channel::error::Error; +use crate::core::ics24_host::identifier::{ChannelId, PortId}; use crate::signer::Signer; use crate::tx_msg::Msg; @@ -29,14 +29,6 @@ impl MsgChannelCloseInit { signer, } } - - /// Getter: borrow the `port_id` from this message. - pub fn port_id(&self) -> &PortId { - &self.port_id - } - pub fn channel_id(&self) -> &ChannelId { - &self.channel_id - } } impl Msg for MsgChannelCloseInit { @@ -81,7 +73,7 @@ pub mod test_util { use crate::prelude::*; use ibc_proto::ibc::core::channel::v1::MsgChannelCloseInit as RawMsgChannelCloseInit; - use crate::ics24_host::identifier::{ChannelId, PortId}; + use crate::core::ics24_host::identifier::{ChannelId, PortId}; use crate::test_utils::get_dummy_bech32_account; /// Returns a dummy `RawMsgChannelCloseInit`, for testing only! @@ -97,13 +89,13 @@ pub mod test_util { #[cfg(test)] mod tests { use crate::prelude::*; - use core::convert::TryFrom; - use test_env_log::test; + + use test_log::test; use ibc_proto::ibc::core::channel::v1::MsgChannelCloseInit as RawMsgChannelCloseInit; - use crate::ics04_channel::msgs::chan_close_init::test_util::get_dummy_raw_msg_chan_close_init; - use crate::ics04_channel::msgs::chan_close_init::MsgChannelCloseInit; + use crate::core::ics04_channel::msgs::chan_close_init::test_util::get_dummy_raw_msg_chan_close_init; + use crate::core::ics04_channel::msgs::chan_close_init::MsgChannelCloseInit; #[test] fn parse_channel_close_init_msg() { @@ -140,7 +132,7 @@ mod tests { Test { name: "Bad port, name too long".to_string(), raw: RawMsgChannelCloseInit { - port_id: "abcdefsdfasdfasdfasdfasdfasdfadsfasdgafsgadfasdfasdfasdfsdfasdfaghijklmnopqrstu".to_string(), + port_id: "abcdefsdfasdfasdfasdfasdfasdfadsfasdgafsgadfasdfasdfasdfsdfasdfaghijklmnopqrstuabcdefsdfasdfasdfasdfasdfasdfadsfasdgafsgadfasdfasdfasdfsdfasdfaghijklmnopqrstu".to_string(), ..default_raw_msg.clone() }, want_pass: false, diff --git a/modules/src/ics04_channel/msgs/chan_open_ack.rs b/modules/src/core/ics04_channel/msgs/chan_open_ack.rs similarity index 88% rename from modules/src/ics04_channel/msgs/chan_open_ack.rs rename to modules/src/core/ics04_channel/msgs/chan_open_ack.rs index 961669f34..7a1b73893 100644 --- a/modules/src/ics04_channel/msgs/chan_open_ack.rs +++ b/modules/src/core/ics04_channel/msgs/chan_open_ack.rs @@ -1,13 +1,11 @@ -use crate::ics04_channel::channel::validate_version; -use crate::ics04_channel::error::Error; -use crate::ics24_host::identifier::{ChannelId, PortId}; +use crate::core::ics04_channel::error::Error; +use crate::core::ics04_channel::Version; +use crate::core::ics24_host::identifier::{ChannelId, PortId}; use crate::prelude::*; use crate::proofs::Proofs; use crate::signer::Signer; use crate::tx_msg::Msg; -use core::convert::TryFrom; - use ibc_proto::ibc::core::channel::v1::MsgChannelOpenAck as RawMsgChannelOpenAck; use tendermint_proto::Protobuf; @@ -21,7 +19,7 @@ pub struct MsgChannelOpenAck { pub port_id: PortId, pub channel_id: ChannelId, pub counterparty_channel_id: ChannelId, - pub counterparty_version: String, // FIXME(romac): Introduce newtype for versions + pub counterparty_version: Version, pub proofs: Proofs, pub signer: Signer, } @@ -31,7 +29,7 @@ impl MsgChannelOpenAck { port_id: PortId, channel_id: ChannelId, counterparty_channel_id: ChannelId, - counterparty_version: String, + counterparty_version: Version, proofs: Proofs, signer: Signer, ) -> Self { @@ -44,26 +42,6 @@ impl MsgChannelOpenAck { signer, } } - - /// Getter: borrow the `port_id` from this message. - pub fn port_id(&self) -> &PortId { - &self.port_id - } - pub fn channel_id(&self) -> &ChannelId { - &self.channel_id - } - - pub fn counterparty_channel_id(&self) -> &ChannelId { - &self.counterparty_channel_id - } - - pub fn counterparty_version(&self) -> &String { - &self.counterparty_version - } - - pub fn proofs(&self) -> &Proofs { - &self.proofs - } } impl Msg for MsgChannelOpenAck { @@ -86,7 +64,7 @@ impl TryFrom for MsgChannelOpenAck { fn try_from(raw_msg: RawMsgChannelOpenAck) -> Result { let proofs = Proofs::new( - raw_msg.proof_try.into(), + raw_msg.proof_try.try_into().map_err(Error::invalid_proof)?, None, None, None, @@ -104,7 +82,7 @@ impl TryFrom for MsgChannelOpenAck { .counterparty_channel_id .parse() .map_err(Error::identifier)?, - counterparty_version: validate_version(raw_msg.counterparty_version)?, + counterparty_version: raw_msg.counterparty_version.into(), proofs, signer: raw_msg.signer.into(), }) @@ -117,7 +95,7 @@ impl From for RawMsgChannelOpenAck { port_id: domain_msg.port_id.to_string(), channel_id: domain_msg.channel_id.to_string(), counterparty_channel_id: domain_msg.counterparty_channel_id.to_string(), - counterparty_version: domain_msg.counterparty_version.to_string(), + counterparty_version: domain_msg.counterparty_version.into(), proof_try: domain_msg.proofs.object_proof().clone().into(), proof_height: Some(domain_msg.proofs.height().into()), signer: domain_msg.signer.to_string(), @@ -130,7 +108,7 @@ pub mod test_util { use crate::prelude::*; use ibc_proto::ibc::core::channel::v1::MsgChannelOpenAck as RawMsgChannelOpenAck; - use crate::ics24_host::identifier::{ChannelId, PortId}; + use crate::core::ics24_host::identifier::{ChannelId, PortId}; use crate::test_utils::{get_dummy_bech32_account, get_dummy_proof}; use ibc_proto::ibc::core::client::v1::Height; @@ -155,11 +133,11 @@ pub mod test_util { mod tests { use crate::prelude::*; use ibc_proto::ibc::core::channel::v1::MsgChannelOpenAck as RawMsgChannelOpenAck; - use test_env_log::test; + use test_log::test; + + use crate::core::ics04_channel::msgs::chan_open_ack::test_util::get_dummy_raw_msg_chan_open_ack; + use crate::core::ics04_channel::msgs::chan_open_ack::MsgChannelOpenAck; - use crate::ics04_channel::msgs::chan_open_ack::test_util::get_dummy_raw_msg_chan_open_ack; - use crate::ics04_channel::msgs::chan_open_ack::MsgChannelOpenAck; - use core::convert::TryFrom; use ibc_proto::ibc::core::client::v1::Height; #[test] @@ -198,7 +176,7 @@ mod tests { Test { name: "Bad port, name too long".to_string(), raw: RawMsgChannelOpenAck { - port_id: "abcdezdfDfsdfgfddsfsfdsdfdfvxcvzxcvsgdfsdfwefwvsdfdsfdasgagadgsadgsdffghijklmnopqrstu".to_string(), + port_id: "abcdezdfDfsdfgfddsfsfdsdfdfvxcvzxcvsgdfsdfwefwvsdfdsfdasgagadgsadgsdffghijklmnopqrstuabcdezdfDfsdfgfddsfsfdsdfdfvxcvzxcvsgdfsdfwefwvsdfdsfdasgagadgsadgsdffghijklmnopqrstu".to_string(), ..default_raw_msg.clone() }, want_pass: false, diff --git a/modules/src/ics04_channel/msgs/chan_open_confirm.rs b/modules/src/core/ics04_channel/msgs/chan_open_confirm.rs similarity index 89% rename from modules/src/ics04_channel/msgs/chan_open_confirm.rs rename to modules/src/core/ics04_channel/msgs/chan_open_confirm.rs index 014356fac..57342c818 100644 --- a/modules/src/ics04_channel/msgs/chan_open_confirm.rs +++ b/modules/src/core/ics04_channel/msgs/chan_open_confirm.rs @@ -1,11 +1,10 @@ -use crate::ics04_channel::error::Error; -use crate::ics24_host::identifier::{ChannelId, PortId}; +use crate::core::ics04_channel::error::Error; +use crate::core::ics24_host::identifier::{ChannelId, PortId}; use crate::prelude::*; use crate::proofs::Proofs; use crate::signer::Signer; use crate::tx_msg::Msg; -use core::convert::TryFrom; use ibc_proto::ibc::core::channel::v1::MsgChannelOpenConfirm as RawMsgChannelOpenConfirm; use tendermint_proto::Protobuf; @@ -34,19 +33,6 @@ impl MsgChannelOpenConfirm { } } -impl MsgChannelOpenConfirm { - /// Getter: borrow the `port_id` from this message. - pub fn port_id(&self) -> &PortId { - &self.port_id - } - pub fn channel_id(&self) -> &ChannelId { - &self.channel_id - } - pub fn proofs(&self) -> &Proofs { - &self.proofs - } -} - impl Msg for MsgChannelOpenConfirm { type ValidationError = Error; type Raw = RawMsgChannelOpenConfirm; @@ -67,7 +53,7 @@ impl TryFrom for MsgChannelOpenConfirm { fn try_from(raw_msg: RawMsgChannelOpenConfirm) -> Result { let proofs = Proofs::new( - raw_msg.proof_ack.into(), + raw_msg.proof_ack.try_into().map_err(Error::invalid_proof)?, None, None, None, @@ -104,7 +90,7 @@ pub mod test_util { use crate::prelude::*; use ibc_proto::ibc::core::channel::v1::MsgChannelOpenConfirm as RawMsgChannelOpenConfirm; - use crate::ics24_host::identifier::{ChannelId, PortId}; + use crate::core::ics24_host::identifier::{ChannelId, PortId}; use crate::test_utils::{get_dummy_bech32_account, get_dummy_proof}; use ibc_proto::ibc::core::client::v1::Height; @@ -127,11 +113,11 @@ pub mod test_util { mod tests { use crate::prelude::*; use ibc_proto::ibc::core::channel::v1::MsgChannelOpenConfirm as RawMsgChannelOpenConfirm; - use test_env_log::test; + use test_log::test; + + use crate::core::ics04_channel::msgs::chan_open_confirm::test_util::get_dummy_raw_msg_chan_open_confirm; + use crate::core::ics04_channel::msgs::chan_open_confirm::MsgChannelOpenConfirm; - use crate::ics04_channel::msgs::chan_open_confirm::test_util::get_dummy_raw_msg_chan_open_confirm; - use crate::ics04_channel::msgs::chan_open_confirm::MsgChannelOpenConfirm; - use core::convert::TryFrom; use ibc_proto::ibc::core::client::v1::Height; #[test] @@ -170,7 +156,7 @@ mod tests { Test { name: "Bad port, name too long".to_string(), raw: RawMsgChannelOpenConfirm { - port_id: "abcdesdfasdsdffasdfasdfasfasdgasdfgasdfasdfasdfasdfasdfasdffghijklmnopqrstu".to_string(), + port_id: "abcdesdfasdsdffasdfasdfasfasdgasdfgasdfasdfasdfasdfasdfasdffghijklmnopqrstuabcdesdfasdsdffasdfasdfasfasdgasdfgasdfasdfasdfasdfasdfasdffghijklmnopqrstu".to_string(), ..default_raw_msg.clone() }, want_pass: false, diff --git a/modules/src/ics04_channel/msgs/chan_open_init.rs b/modules/src/core/ics04_channel/msgs/chan_open_init.rs similarity index 84% rename from modules/src/ics04_channel/msgs/chan_open_init.rs rename to modules/src/core/ics04_channel/msgs/chan_open_init.rs index a22276c98..c95dd2cbb 100644 --- a/modules/src/ics04_channel/msgs/chan_open_init.rs +++ b/modules/src/core/ics04_channel/msgs/chan_open_init.rs @@ -1,6 +1,6 @@ -use crate::ics04_channel::channel::ChannelEnd; -use crate::ics04_channel::error::Error; -use crate::ics24_host::identifier::PortId; +use crate::core::ics04_channel::channel::ChannelEnd; +use crate::core::ics04_channel::error::Error; +use crate::core::ics24_host::identifier::PortId; use crate::prelude::*; use crate::signer::Signer; use crate::tx_msg::Msg; @@ -8,8 +8,6 @@ use crate::tx_msg::Msg; use ibc_proto::ibc::core::channel::v1::MsgChannelOpenInit as RawMsgChannelOpenInit; use tendermint_proto::Protobuf; -use core::convert::{TryFrom, TryInto}; - pub const TYPE_URL: &str = "/ibc.core.channel.v1.MsgChannelOpenInit"; /// @@ -30,16 +28,6 @@ impl MsgChannelOpenInit { signer, } } - - /// Getter: borrow the `port_id` from this message. - pub fn port_id(&self) -> &PortId { - &self.port_id - } - - /// Getter: borrow the `channelEnd` from this message. - pub fn channel(&self) -> &ChannelEnd { - &self.channel - } } impl Msg for MsgChannelOpenInit { @@ -87,8 +75,8 @@ pub mod test_util { use crate::prelude::*; use ibc_proto::ibc::core::channel::v1::MsgChannelOpenInit as RawMsgChannelOpenInit; - use crate::ics04_channel::channel::test_util::get_dummy_raw_channel_end; - use crate::ics24_host::identifier::PortId; + use crate::core::ics04_channel::channel::test_util::get_dummy_raw_channel_end; + use crate::core::ics24_host::identifier::PortId; use crate::test_utils::get_dummy_bech32_account; /// Returns a dummy `RawMsgChannelOpenInit`, for testing only! @@ -103,12 +91,12 @@ pub mod test_util { #[cfg(test)] mod tests { - use crate::ics04_channel::msgs::chan_open_init::test_util::get_dummy_raw_msg_chan_open_init; - use crate::ics04_channel::msgs::chan_open_init::MsgChannelOpenInit; + use crate::core::ics04_channel::msgs::chan_open_init::test_util::get_dummy_raw_msg_chan_open_init; + use crate::core::ics04_channel::msgs::chan_open_init::MsgChannelOpenInit; use crate::prelude::*; - use core::convert::TryFrom; + use ibc_proto::ibc::core::channel::v1::MsgChannelOpenInit as RawMsgChannelOpenInit; - use test_env_log::test; + use test_log::test; #[test] fn channel_open_init_from_raw() { diff --git a/modules/src/ics04_channel/msgs/chan_open_try.rs b/modules/src/core/ics04_channel/msgs/chan_open_try.rs similarity index 86% rename from modules/src/ics04_channel/msgs/chan_open_try.rs rename to modules/src/core/ics04_channel/msgs/chan_open_try.rs index 8f1ab40c3..cd87f5715 100644 --- a/modules/src/ics04_channel/msgs/chan_open_try.rs +++ b/modules/src/core/ics04_channel/msgs/chan_open_try.rs @@ -1,7 +1,8 @@ -use crate::ics04_channel::channel::{validate_version, ChannelEnd}; -use crate::ics04_channel::error::Error as ChannelError; -use crate::ics24_host::error::ValidationError; -use crate::ics24_host::identifier::{ChannelId, PortId}; +use crate::core::ics04_channel::channel::ChannelEnd; +use crate::core::ics04_channel::error::Error as ChannelError; +use crate::core::ics04_channel::Version; +use crate::core::ics24_host::error::ValidationError; +use crate::core::ics24_host::identifier::{ChannelId, PortId}; use crate::prelude::*; use crate::proofs::Proofs; use crate::signer::Signer; @@ -10,7 +11,6 @@ use crate::tx_msg::Msg; use ibc_proto::ibc::core::channel::v1::MsgChannelOpenTry as RawMsgChannelOpenTry; use tendermint_proto::Protobuf; -use core::convert::{TryFrom, TryInto}; use core::str::FromStr; pub const TYPE_URL: &str = "/ibc.core.channel.v1.MsgChannelOpenTry"; @@ -23,7 +23,7 @@ pub struct MsgChannelOpenTry { pub port_id: PortId, pub previous_channel_id: Option, pub channel: ChannelEnd, - pub counterparty_version: String, // TODO(romac): newtype this + pub counterparty_version: Version, pub proofs: Proofs, pub signer: Signer, } @@ -33,7 +33,7 @@ impl MsgChannelOpenTry { port_id: PortId, previous_channel_id: Option, channel: ChannelEnd, - counterparty_version: String, + counterparty_version: Version, proofs: Proofs, signer: Signer, ) -> Self { @@ -46,24 +46,8 @@ impl MsgChannelOpenTry { signer, } } - - /// Getter: borrow the `port_id` from this message. - pub fn port_id(&self) -> &PortId { - &self.port_id - } - pub fn previous_channel_id(&self) -> &Option { - &self.previous_channel_id - } - pub fn counterparty_version(&self) -> &String { - &self.counterparty_version - } - pub fn channel(&self) -> &ChannelEnd { - &self.channel - } - pub fn proofs(&self) -> &Proofs { - &self.proofs - } } + impl Msg for MsgChannelOpenTry { type ValidationError = ChannelError; type Raw = RawMsgChannelOpenTry; @@ -77,7 +61,7 @@ impl Msg for MsgChannelOpenTry { } fn validate_basic(&self) -> Result<(), ValidationError> { - match self.channel().counterparty().channel_id() { + match self.channel.counterparty().channel_id() { None => Err(ValidationError::invalid_counterparty_channel_id()), Some(_c) => Ok(()), } @@ -91,7 +75,10 @@ impl TryFrom for MsgChannelOpenTry { fn try_from(raw_msg: RawMsgChannelOpenTry) -> Result { let proofs = Proofs::new( - raw_msg.proof_init.into(), + raw_msg + .proof_init + .try_into() + .map_err(ChannelError::invalid_proof)?, None, None, None, @@ -115,7 +102,7 @@ impl TryFrom for MsgChannelOpenTry { .channel .ok_or_else(ChannelError::missing_channel)? .try_into()?, - counterparty_version: validate_version(raw_msg.counterparty_version)?, + counterparty_version: raw_msg.counterparty_version.into(), proofs, signer: raw_msg.signer.into(), }; @@ -135,7 +122,7 @@ impl From for RawMsgChannelOpenTry { .previous_channel_id .map_or_else(|| "".to_string(), |v| v.as_str().to_string()), channel: Some(domain_msg.channel.into()), - counterparty_version: domain_msg.counterparty_version, + counterparty_version: domain_msg.counterparty_version.into(), proof_init: domain_msg.proofs.object_proof().clone().into(), proof_height: Some(domain_msg.proofs.height().into()), signer: domain_msg.signer.to_string(), @@ -148,8 +135,8 @@ pub mod test_util { use crate::prelude::*; use ibc_proto::ibc::core::channel::v1::MsgChannelOpenTry as RawMsgChannelOpenTry; - use crate::ics04_channel::channel::test_util::get_dummy_raw_channel_end; - use crate::ics24_host::identifier::{ChannelId, PortId}; + use crate::core::ics04_channel::channel::test_util::get_dummy_raw_channel_end; + use crate::core::ics24_host::identifier::{ChannelId, PortId}; use crate::test_utils::{get_dummy_bech32_account, get_dummy_proof}; use ibc_proto::ibc::core::client::v1::Height; @@ -172,13 +159,13 @@ pub mod test_util { #[cfg(test)] mod tests { - use crate::ics04_channel::msgs::chan_open_try::test_util::get_dummy_raw_msg_chan_open_try; - use crate::ics04_channel::msgs::chan_open_try::MsgChannelOpenTry; + use crate::core::ics04_channel::msgs::chan_open_try::test_util::get_dummy_raw_msg_chan_open_try; + use crate::core::ics04_channel::msgs::chan_open_try::MsgChannelOpenTry; use crate::prelude::*; - use core::convert::TryFrom; + use ibc_proto::ibc::core::channel::v1::MsgChannelOpenTry as RawMsgChannelOpenTry; use ibc_proto::ibc::core::client::v1::Height; - use test_env_log::test; + use test_log::test; #[test] fn channel_open_try_from_raw() { @@ -216,7 +203,7 @@ mod tests { Test { name: "Bad port, name too long".to_string(), raw: RawMsgChannelOpenTry { - port_id: "abcdefghijasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfadgasgasdfasdfasdfasdfaklmnopqrstu".to_string(), + port_id: "abcdefghijasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfadgasgasdfasdfaabcdefghijasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfadgasgasdfasdfa".to_string(), ..default_raw_msg.clone() }, want_pass: false, diff --git a/modules/src/ics04_channel/msgs/recv_packet.rs b/modules/src/core/ics04_channel/msgs/recv_packet.rs similarity index 85% rename from modules/src/ics04_channel/msgs/recv_packet.rs rename to modules/src/core/ics04_channel/msgs/recv_packet.rs index 9c826bdd0..076fd079f 100644 --- a/modules/src/ics04_channel/msgs/recv_packet.rs +++ b/modules/src/core/ics04_channel/msgs/recv_packet.rs @@ -1,11 +1,11 @@ use crate::prelude::*; -use core::convert::{TryFrom, TryInto}; + use tendermint_proto::Protobuf; use ibc_proto::ibc::core::channel::v1::MsgRecvPacket as RawMsgRecvPacket; -use crate::ics04_channel::error::Error; -use crate::ics04_channel::packet::Packet; +use crate::core::ics04_channel::error::Error; +use crate::core::ics04_channel::packet::Packet; use crate::proofs::Proofs; use crate::signer::Signer; use crate::tx_msg::Msg; @@ -52,7 +52,10 @@ impl TryFrom for MsgRecvPacket { fn try_from(raw_msg: RawMsgRecvPacket) -> Result { let proofs = Proofs::new( - raw_msg.proof_commitment.into(), + raw_msg + .proof_commitment + .try_into() + .map_err(Error::invalid_proof)?, None, None, None, @@ -90,14 +93,21 @@ pub mod test_util { use ibc_proto::ibc::core::channel::v1::MsgRecvPacket as RawMsgRecvPacket; use ibc_proto::ibc::core::client::v1::Height as RawHeight; - use crate::ics04_channel::packet::test_utils::get_dummy_raw_packet; + use crate::core::ics04_channel::packet::test_utils::get_dummy_raw_packet; use crate::test_utils::{get_dummy_bech32_account, get_dummy_proof}; + use crate::timestamp::Timestamp; + use core::ops::Add; + use core::time::Duration; /// Returns a dummy `RawMsgRecvPacket`, for testing only! The `height` parametrizes both the /// proof height as well as the timeout height. pub fn get_dummy_raw_msg_recv_packet(height: u64) -> RawMsgRecvPacket { + let timestamp = Timestamp::now().add(Duration::from_secs(9)); RawMsgRecvPacket { - packet: Some(get_dummy_raw_packet(height, 9)), + packet: Some(get_dummy_raw_packet( + height, + timestamp.unwrap().nanoseconds(), + )), proof_commitment: get_dummy_proof(), proof_height: Some(RawHeight { revision_number: 0, @@ -111,14 +121,14 @@ pub mod test_util { #[cfg(test)] mod test { use crate::prelude::*; - use core::convert::{TryFrom, TryInto}; - use test_env_log::test; + + use test_log::test; use ibc_proto::ibc::core::channel::v1::MsgRecvPacket as RawMsgRecvPacket; - use crate::ics04_channel::error::Error; - use crate::ics04_channel::msgs::recv_packet::test_util::get_dummy_raw_msg_recv_packet; - use crate::ics04_channel::msgs::recv_packet::MsgRecvPacket; + use crate::core::ics04_channel::error::Error; + use crate::core::ics04_channel::msgs::recv_packet::test_util::get_dummy_raw_msg_recv_packet; + use crate::core::ics04_channel::msgs::recv_packet::MsgRecvPacket; #[test] fn msg_recv_packet_try_from_raw() { diff --git a/modules/src/ics04_channel/msgs/timeout.rs b/modules/src/core/ics04_channel/msgs/timeout.rs similarity index 91% rename from modules/src/ics04_channel/msgs/timeout.rs rename to modules/src/core/ics04_channel/msgs/timeout.rs index c20dba3d6..74efc8dd0 100644 --- a/modules/src/ics04_channel/msgs/timeout.rs +++ b/modules/src/core/ics04_channel/msgs/timeout.rs @@ -1,11 +1,11 @@ use crate::prelude::*; -use core::convert::{TryFrom, TryInto}; + use tendermint_proto::Protobuf; use ibc_proto::ibc::core::channel::v1::MsgTimeout as RawMsgTimeout; -use crate::ics04_channel::error::Error; -use crate::ics04_channel::packet::{Packet, Sequence}; +use crate::core::ics04_channel::error::Error; +use crate::core::ics04_channel::packet::{Packet, Sequence}; use crate::proofs::Proofs; use crate::signer::Signer; use crate::tx_msg::Msg; @@ -59,7 +59,10 @@ impl TryFrom for MsgTimeout { fn try_from(raw_msg: RawMsgTimeout) -> Result { let proofs = Proofs::new( - raw_msg.proof_unreceived.into(), + raw_msg + .proof_unreceived + .try_into() + .map_err(Error::invalid_proof)?, None, None, None, @@ -101,7 +104,7 @@ pub mod test_util { use ibc_proto::ibc::core::channel::v1::MsgTimeout as RawMsgTimeout; use ibc_proto::ibc::core::client::v1::Height as RawHeight; - use crate::ics04_channel::packet::test_utils::get_dummy_raw_packet; + use crate::core::ics04_channel::packet::test_utils::get_dummy_raw_packet; use crate::test_utils::{get_dummy_bech32_account, get_dummy_proof}; /// Returns a dummy `RawMsgTimeout`, for testing only! @@ -123,14 +126,14 @@ pub mod test_util { #[cfg(test)] mod test { use crate::prelude::*; - use core::convert::{TryFrom, TryInto}; - use test_env_log::test; + + use test_log::test; use ibc_proto::ibc::core::channel::v1::MsgTimeout as RawMsgTimeout; - use crate::ics04_channel::error::Error; - use crate::ics04_channel::msgs::timeout::test_util::get_dummy_raw_msg_timeout; - use crate::ics04_channel::msgs::timeout::MsgTimeout; + use crate::core::ics04_channel::error::Error; + use crate::core::ics04_channel::msgs::timeout::test_util::get_dummy_raw_msg_timeout; + use crate::core::ics04_channel::msgs::timeout::MsgTimeout; #[test] fn msg_timeout_try_from_raw() { diff --git a/modules/src/ics04_channel/msgs/timeout_on_close.rs b/modules/src/core/ics04_channel/msgs/timeout_on_close.rs similarity index 91% rename from modules/src/ics04_channel/msgs/timeout_on_close.rs rename to modules/src/core/ics04_channel/msgs/timeout_on_close.rs index 50e57f92b..64ef629cf 100644 --- a/modules/src/ics04_channel/msgs/timeout_on_close.rs +++ b/modules/src/core/ics04_channel/msgs/timeout_on_close.rs @@ -1,10 +1,10 @@ use crate::prelude::*; -use core::convert::{TryFrom, TryInto}; + use ibc_proto::ibc::core::channel::v1::MsgTimeoutOnClose as RawMsgTimeoutOnClose; use tendermint_proto::Protobuf; -use crate::ics04_channel::error::Error; -use crate::ics04_channel::packet::{Packet, Sequence}; +use crate::core::ics04_channel::error::Error; +use crate::core::ics04_channel::packet::{Packet, Sequence}; use crate::proofs::Proofs; use crate::signer::Signer; use crate::tx_msg::Msg; @@ -58,7 +58,10 @@ impl TryFrom for MsgTimeoutOnClose { fn try_from(raw_msg: RawMsgTimeoutOnClose) -> Result { let proofs = Proofs::new( - raw_msg.proof_unreceived.into(), + raw_msg + .proof_unreceived + .try_into() + .map_err(Error::invalid_proof)?, None, None, None, @@ -105,7 +108,7 @@ pub mod test_util { use ibc_proto::ibc::core::channel::v1::MsgTimeoutOnClose as RawMsgTimeoutOnClose; use ibc_proto::ibc::core::client::v1::Height as RawHeight; - use crate::ics04_channel::packet::test_utils::get_dummy_raw_packet; + use crate::core::ics04_channel::packet::test_utils::get_dummy_raw_packet; use crate::test_utils::{get_dummy_bech32_account, get_dummy_proof}; /// Returns a dummy `RawMsgTimeoutOnClose`, for testing only! diff --git a/modules/src/ics04_channel/packet.rs b/modules/src/core/ics04_channel/packet.rs similarity index 77% rename from modules/src/ics04_channel/packet.rs rename to modules/src/core/ics04_channel/packet.rs index db97efe21..2bc191860 100644 --- a/modules/src/ics04_channel/packet.rs +++ b/modules/src/core/ics04_channel/packet.rs @@ -1,5 +1,5 @@ use crate::prelude::*; -use core::convert::TryFrom; + use core::str::FromStr; use serde_derive::{Deserialize, Serialize}; @@ -7,8 +7,9 @@ use serde_derive::{Deserialize, Serialize}; use ibc_proto::ibc::core::channel::v1::Packet as RawPacket; use tendermint_proto::Protobuf; -use crate::ics04_channel::error::Error; -use crate::ics24_host::identifier::{ChannelId, PortId}; +use crate::core::ics04_channel::error::Error; +use crate::core::ics24_host::identifier::{ChannelId, PortId}; +use crate::events::{extract_attribute, Error as EventError, RawObject}; use crate::timestamp::{Expiry::Expired, Timestamp}; use crate::Height; @@ -54,14 +55,10 @@ impl core::fmt::Display for PacketMsgType { } /// The sequence number of a packet enforces ordering among packets from the same source. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Deserialize, Serialize, PartialOrd, Ord)] -pub struct Sequence(pub u64); - -impl Default for Sequence { - fn default() -> Self { - Sequence(0) - } -} +#[derive( + Copy, Clone, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord, Deserialize, Serialize, +)] +pub struct Sequence(u64); impl FromStr for Sequence { type Err = Error; @@ -101,7 +98,7 @@ impl core::fmt::Display for Sequence { } } -#[derive(PartialEq, Deserialize, Serialize, Hash, Clone)] +#[derive(Clone, Debug, Default, Hash, PartialEq, Eq, Deserialize, Serialize)] pub struct Packet { pub sequence: Sequence, pub source_port: PortId, @@ -115,20 +112,23 @@ pub struct Packet { } impl Packet { - pub fn timed_out(&self, now: &Timestamp, dst_chain_height: Height) -> bool { + /// Checks whether a packet from a + /// [`SendPacket`](crate::core::ics04_channel::events::SendPacket) + /// event is timed-out relative to the current state of the + /// destination chain. + /// + /// Checks both for time-out relative to the destination chain's + /// current timestamp `dst_chain_ts` as well as relative to + /// the height `dst_chain_height`. + /// + /// Note: a timed-out packet should result in a + /// [`MsgTimeout`](crate::core::ics04_channel::msgs::timeout::MsgTimeout), + /// instead of the common-case where it results in + /// [`MsgRecvPacket`](crate::core::ics04_channel::msgs::recv_packet::MsgRecvPacket). + pub fn timed_out(&self, dst_chain_ts: &Timestamp, dst_chain_height: Height) -> bool { (self.timeout_height != Height::zero() && self.timeout_height < dst_chain_height) || (self.timeout_timestamp != Timestamp::none() - && now.check_expiry(&self.timeout_timestamp) == Expired) - } -} - -impl core::fmt::Debug for Packet { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - write!( - f, - "{:?} {:?} {:?}", - self.source_port, self.source_channel, self.sequence - ) + && dst_chain_ts.check_expiry(&self.timeout_timestamp) == Expired) } } @@ -149,23 +149,10 @@ impl core::fmt::Display for Packet { } } -impl Default for Packet { - fn default() -> Self { - Packet { - sequence: Sequence(0), - source_port: Default::default(), - source_channel: Default::default(), - destination_port: Default::default(), - destination_channel: Default::default(), - data: Vec::new(), - timeout_height: Default::default(), - timeout_timestamp: Default::default(), - } - } -} impl Protobuf for Packet {} + impl TryFrom for Packet { type Error = Error; @@ -207,6 +194,45 @@ impl TryFrom for Packet { } } +impl TryFrom> for Packet { + type Error = EventError; + fn try_from(obj: RawObject<'_>) -> Result { + Ok(Packet { + sequence: extract_attribute(&obj, &format!("{}.packet_sequence", obj.action))? + .parse() + .map_err(EventError::channel)?, + source_port: extract_attribute(&obj, &format!("{}.packet_src_port", obj.action))? + .parse() + .map_err(EventError::parse)?, + source_channel: extract_attribute(&obj, &format!("{}.packet_src_channel", obj.action))? + .parse() + .map_err(EventError::parse)?, + destination_port: extract_attribute(&obj, &format!("{}.packet_dst_port", obj.action))? + .parse() + .map_err(EventError::parse)?, + destination_channel: extract_attribute( + &obj, + &format!("{}.packet_dst_channel", obj.action), + )? + .parse() + .map_err(EventError::parse)?, + data: vec![], + timeout_height: extract_attribute( + &obj, + &format!("{}.packet_timeout_height", obj.action), + )? + .parse() + .map_err(EventError::height)?, + timeout_timestamp: extract_attribute( + &obj, + &format!("{}.packet_timeout_timestamp", obj.action), + )? + .parse() + .map_err(EventError::timestamp)?, + }) + } +} + impl From for RawPacket { fn from(packet: Packet) -> Self { RawPacket { @@ -217,7 +243,7 @@ impl From for RawPacket { destination_channel: packet.destination_channel.to_string(), data: packet.data, timeout_height: Some(packet.timeout_height.into()), - timeout_timestamp: packet.timeout_timestamp.as_nanoseconds(), + timeout_timestamp: packet.timeout_timestamp.nanoseconds(), } } } @@ -228,7 +254,7 @@ pub mod test_utils { use ibc_proto::ibc::core::channel::v1::Packet as RawPacket; use ibc_proto::ibc::core::client::v1::Height as RawHeight; - use crate::ics24_host::identifier::{ChannelId, PortId}; + use crate::core::ics24_host::identifier::{ChannelId, PortId}; /// Returns a dummy `RawPacket`, for testing only! pub fn get_dummy_raw_packet(timeout_height: u64, timeout_timestamp: u64) -> RawPacket { @@ -251,13 +277,13 @@ pub mod test_utils { #[cfg(test)] mod tests { use crate::prelude::*; - use core::convert::TryFrom; - use test_env_log::test; + + use test_log::test; use ibc_proto::ibc::core::channel::v1::Packet as RawPacket; - use crate::ics04_channel::packet::test_utils::get_dummy_raw_packet; - use crate::ics04_channel::packet::Packet; + use crate::core::ics04_channel::packet::test_utils::get_dummy_raw_packet; + use crate::core::ics04_channel::packet::Packet; #[test] fn packet_try_from_raw() { @@ -274,7 +300,7 @@ mod tests { Test { name: "Good parameters".to_string(), raw: default_raw_msg.clone(), - want_pass: true + want_pass: true, }, Test { name: "Src port validation: correct".to_string(), @@ -295,7 +321,7 @@ mod tests { Test { name: "Bad src port, name too long".to_string(), raw: RawPacket { - source_port: "abcdefghijasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfadgasgasdfasdfasdfasdfaklmnopqrstu".to_string(), + source_port: "abcdefghijasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfadgasgasdfasdfasdfasdfaklmnopqrstuabcdefghijasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfadgasgasdfasdfasdfasdfaklmnopqrstu".to_string(), ..default_raw_msg.clone() }, want_pass: false, @@ -319,7 +345,7 @@ mod tests { Test { name: "Bad dst port, name too long".to_string(), raw: RawPacket { - destination_port: "abcdefghijasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfadgasgasdfasdfasdfasdfaklmnopqrstu".to_string(), + destination_port: "abcdefghijasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfadgasgasdfasdfasdfasdfaklmnopqrstuabcdefghijasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfadgasgasdfas".to_string(), ..default_raw_msg.clone() }, want_pass: false, diff --git a/modules/src/core/ics04_channel/version.rs b/modules/src/core/ics04_channel/version.rs new file mode 100644 index 000000000..9dca9facf --- /dev/null +++ b/modules/src/core/ics04_channel/version.rs @@ -0,0 +1,61 @@ +//! Data type definition and utilities for the +//! version field of a channel end. +//! + +use core::fmt; +use serde_derive::{Deserialize, Serialize}; + +use crate::applications::ics20_fungible_token_transfer; +use crate::prelude::*; + +/// The version field for a `ChannelEnd`. +/// +/// This field is opaque to the core IBC protocol. +/// No explicit validation is necessary, and the +/// spec (v1) currently allows empty strings. +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] +pub struct Version(String); + +impl Version { + pub fn ics20() -> Self { + Self(ics20_fungible_token_transfer::VERSION.to_string()) + } + + pub fn empty() -> Self { + Self("".to_string()) + } +} + +impl From for String { + fn from(domain_version: Version) -> Self { + domain_version.0 + } +} + +impl From for Version { + fn from(raw_version: String) -> Self { + // Version validation: nothing specific. + Self(raw_version) + } +} + +impl From<&str> for Version { + fn from(raw_version: &str) -> Self { + Self { + 0: raw_version.into(), + } + } +} + +/// The default version is empty (unspecified). +impl Default for Version { + fn default() -> Self { + Version::empty() + } +} + +impl fmt::Display for Version { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} diff --git a/modules/src/core/ics05_port/capabilities.rs b/modules/src/core/ics05_port/capabilities.rs new file mode 100644 index 000000000..4cd3d09ea --- /dev/null +++ b/modules/src/core/ics05_port/capabilities.rs @@ -0,0 +1,62 @@ +//! Capabilities: this is a placeholder. + +use crate::prelude::*; +use core::{fmt, str::FromStr}; + +#[derive(Clone, Debug, PartialEq)] +pub struct Capability { + index: u64, +} + +impl Capability { + pub fn new() -> Capability { + Self { index: 0x0 } + } + + pub fn index(&self) -> u64 { + self.index + } +} + +impl Default for Capability { + fn default() -> Self { + Self::new() + } +} + +impl From for Capability { + fn from(index: u64) -> Self { + Self { index } + } +} + +#[derive(Debug, PartialEq)] +pub struct InvalidCapabilityName; + +#[derive(Clone, Debug, PartialEq)] +pub struct CapabilityName(String); + +impl CapabilityName { + pub fn new(s: impl AsRef) -> Result { + let s = s.as_ref().trim(); + if !s.is_empty() { + Ok(Self(s.to_owned())) + } else { + Err(InvalidCapabilityName) + } + } +} + +impl fmt::Display for CapabilityName { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +impl FromStr for CapabilityName { + type Err = InvalidCapabilityName; + + fn from_str(s: &str) -> Result { + Self::new(s) + } +} diff --git a/modules/src/core/ics05_port/context.rs b/modules/src/core/ics05_port/context.rs new file mode 100644 index 000000000..11ae6e46d --- /dev/null +++ b/modules/src/core/ics05_port/context.rs @@ -0,0 +1,74 @@ +use crate::core::ics05_port::capabilities::{Capability, CapabilityName}; +use crate::core::ics05_port::error::Error; +use crate::core::ics24_host::identifier::PortId; +use crate::core::ics24_host::path::PortsPath; +use crate::prelude::*; + +/// A context supplying all the necessary read-only dependencies for processing any information regarding a port. +pub trait PortReader: CapabilityReader { + /// Module Id type that can be mapped to an ICS26 router callback module + type ModuleId; + + /// Return the module_id along with the capability associated with a given port_id + fn lookup_module_by_port( + &self, + port_id: &PortId, + ) -> Result<(Self::ModuleId, Capability), Error>; + + /// Check if the specified port_id is already bounded + fn is_bound(&self, port_id: PortId) -> bool { + self.get_capability(&Self::port_capability_name(port_id)) + .is_ok() + } + + /// Authenticate a capability key against a port_id by checking if the capability was previously + /// generated and bound to the specified port + fn authenticate(&self, port_id: PortId, capability: &Capability) -> bool { + self.authenticate_capability(&Self::port_capability_name(port_id), capability) + .is_ok() + } + + fn port_capability_name(port_id: PortId) -> CapabilityName { + PortsPath(port_id) + .to_string() + .parse() + .expect("PortsPath cannot be empty string") + } +} + +pub trait PortKeeper: CapabilityKeeper + PortReader { + /// Binds to a port and returns the associated capability + fn bind_port(&mut self, port_id: PortId) -> Result { + if self.is_bound(port_id.clone()) { + Err(Error::port_already_bound(port_id)) + } else { + self.new_capability(Self::port_capability_name(port_id)) + } + } +} + +pub trait CapabilityKeeper { + /// Create a new capability with the given name. + /// Return an error if the capability was already taken. + fn new_capability(&mut self, name: CapabilityName) -> Result; + + /// Claim the specified capability using the specified name. + /// Return an error if the capability was already taken. + fn claim_capability(&mut self, name: CapabilityName, capability: Capability); + + /// Release a previously claimed or created capability + fn release_capability(&mut self, name: CapabilityName, capability: Capability); +} + +pub trait CapabilityReader { + /// Fetch a capability which was previously claimed by specified name + fn get_capability(&self, name: &CapabilityName) -> Result; + + /// Authenticate a given capability and name. Lookup the capability from the internal store and + /// check against the provided name. + fn authenticate_capability( + &self, + name: &CapabilityName, + capability: &Capability, + ) -> Result<(), Error>; +} diff --git a/modules/src/core/ics05_port/error.rs b/modules/src/core/ics05_port/error.rs new file mode 100644 index 000000000..ff09a4d32 --- /dev/null +++ b/modules/src/core/ics05_port/error.rs @@ -0,0 +1,18 @@ +use crate::core::ics24_host::identifier::PortId; +use flex_error::define_error; + +define_error! { + #[derive(Debug, PartialEq)] + Error { + UnknownPort + { port_id: PortId } + | e | { format_args!("port '{0}' is unknown", e.port_id) }, + + PortAlreadyBound + { port_id: PortId } + | e | { format_args!("port '{0}' is already bound", e.port_id) }, + + ImplementationSpecific + | _ | { "implementation specific error" }, + } +} diff --git a/modules/src/core/ics05_port/mod.rs b/modules/src/core/ics05_port/mod.rs new file mode 100644 index 000000000..015cdced9 --- /dev/null +++ b/modules/src/core/ics05_port/mod.rs @@ -0,0 +1,6 @@ +//! ICS 05: Port implementation specifies the allocation scheme used by modules to +//! bind to uniquely named ports. + +pub mod capabilities; +pub mod context; +pub mod error; diff --git a/modules/src/ics23_commitment/commitment.rs b/modules/src/core/ics23_commitment/commitment.rs similarity index 76% rename from modules/src/ics23_commitment/commitment.rs rename to modules/src/core/ics23_commitment/commitment.rs index af3a2fefd..569f2963f 100644 --- a/modules/src/ics23_commitment/commitment.rs +++ b/modules/src/core/ics23_commitment/commitment.rs @@ -1,5 +1,6 @@ -use crate::ics23_commitment::error::Error; +use crate::core::ics23_commitment::error::Error; use crate::prelude::*; +use crate::proofs::ProofError; use core::{convert::TryFrom, fmt}; use ibc_proto::ibc::core::commitment::v1::MerkleProof as RawMerkleProof; @@ -59,15 +60,15 @@ impl fmt::Debug for CommitmentProofBytes { } } -impl CommitmentProofBytes { - pub fn is_empty(&self) -> bool { - self.bytes.len() == 0 - } -} +impl TryFrom> for CommitmentProofBytes { + type Error = ProofError; -impl From> for CommitmentProofBytes { - fn from(bytes: Vec) -> Self { - Self { bytes } + fn try_from(bytes: Vec) -> Result { + if bytes.is_empty() { + Err(Self::Error::empty_proof()) + } else { + Ok(Self { bytes }) + } } } @@ -77,18 +78,13 @@ impl From for Vec { } } -// impl From for CommitmentProofBytes { -// fn from(proof: MerkleProof) -> Self { -// let raw_proof: RawMerkleProof = proof.into(); -// raw_proof.into() -// } -// } +impl TryFrom for CommitmentProofBytes { + type Error = ProofError; -impl From for CommitmentProofBytes { - fn from(proof: RawMerkleProof) -> Self { + fn try_from(proof: RawMerkleProof) -> Result { let mut buf = Vec::new(); prost::Message::encode(&proof, &mut buf).unwrap(); - buf.into() + buf.try_into() } } @@ -109,16 +105,6 @@ pub struct CommitmentPrefix { } impl CommitmentPrefix { - pub fn from_bytes(bytes: &[u8]) -> Self { - Self { - bytes: Vec::from(bytes), - } - } - - pub fn is_empty(&self) -> bool { - self.bytes.len() == 0 - } - pub fn as_bytes(&self) -> &[u8] { &self.bytes } @@ -128,9 +114,15 @@ impl CommitmentPrefix { } } -impl From> for CommitmentPrefix { - fn from(bytes: Vec) -> Self { - Self { bytes } +impl TryFrom> for CommitmentPrefix { + type Error = Error; + + fn try_from(bytes: Vec) -> Result { + if bytes.is_empty() { + Err(Self::Error::empty_commitment_prefix()) + } else { + Ok(Self { bytes }) + } } } @@ -157,11 +149,12 @@ impl Serialize for CommitmentPrefix { pub mod test_util { use crate::prelude::*; use ibc_proto::ibc::core::commitment::v1::MerkleProof as RawMerkleProof; + use ibc_proto::ics23::CommitmentProof; /// Returns a dummy `RawMerkleProof`, for testing only! pub fn get_dummy_merkle_proof() -> RawMerkleProof { - let parsed = ibc_proto::ics23::CommitmentProof { proof: None }; - let mproofs: Vec = vec![parsed]; + let parsed = CommitmentProof { proof: None }; + let mproofs: Vec = vec![parsed]; RawMerkleProof { proofs: mproofs } } } diff --git a/modules/src/core/ics23_commitment/error.rs b/modules/src/core/ics23_commitment/error.rs new file mode 100644 index 000000000..260c9557b --- /dev/null +++ b/modules/src/core/ics23_commitment/error.rs @@ -0,0 +1,39 @@ +use flex_error::{define_error, TraceError}; +use prost::DecodeError; + +define_error! { + #[derive(Debug, PartialEq, Eq)] + Error { + InvalidRawMerkleProof + [ TraceError ] + |_| { "invalid raw merkle proof" }, + + CommitmentProofDecodingFailed + [ TraceError ] + |_| { "failed to decode commitment proof" }, + + EmptyCommitmentPrefix + |_| { "empty commitment prefix" }, + + EmptyMerkleProof + |_| { "empty merkle proof" }, + + EmptyMerkleRoot + |_| { "empty merkle root" }, + + EmptyVerifiedValue + |_| { "empty verified value" }, + + NumberOfSpecsMismatch + |_| { "mismatch between the number of proofs with that of specs" }, + + NumberOfKeysMismatch + |_| { "mismatch between the number of proofs with that of keys" }, + + InvalidMerkleProof + |_| { "invalid merkle proof" }, + + VerificationFailure + |_| { "proof verification failed" } + } +} diff --git a/modules/src/core/ics23_commitment/merkle.rs b/modules/src/core/ics23_commitment/merkle.rs new file mode 100644 index 000000000..ef882811d --- /dev/null +++ b/modules/src/core/ics23_commitment/merkle.rs @@ -0,0 +1,231 @@ +use crate::prelude::*; +use tendermint::merkle::proof::Proof as TendermintProof; + +use ibc_proto::ibc::core::commitment::v1::MerklePath; +use ibc_proto::ibc::core::commitment::v1::MerkleProof as RawMerkleProof; +use ibc_proto::ibc::core::commitment::v1::MerkleRoot; +use ics23::commitment_proof::Proof; +use ics23::{ + calculate_existence_root, verify_membership, verify_non_membership, CommitmentProof, + NonExistenceProof, +}; + +use crate::core::ics23_commitment::commitment::{CommitmentPrefix, CommitmentRoot}; +use crate::core::ics23_commitment::error::Error; +use crate::core::ics23_commitment::specs::ProofSpecs; + +pub fn apply_prefix(prefix: &CommitmentPrefix, mut path: Vec) -> MerklePath { + let mut key_path: Vec = vec![format!("{:?}", prefix)]; + key_path.append(&mut path); + MerklePath { key_path } +} + +impl From for MerkleRoot { + fn from(root: CommitmentRoot) -> Self { + Self { + hash: root.into_vec(), + } + } +} + +#[derive(Clone, Debug, PartialEq)] +pub struct MerkleProof { + pub proofs: Vec, +} + +/// Convert to ics23::CommitmentProof +/// The encoding and decoding shouldn't fail since ics23::CommitmentProof and ibc_proto::ics23::CommitmentProof should be the same +/// Ref. +impl From for MerkleProof { + fn from(proof: RawMerkleProof) -> Self { + let proofs: Vec = proof + .proofs + .into_iter() + .map(|p| { + let mut encoded = Vec::new(); + prost::Message::encode(&p, &mut encoded).unwrap(); + prost::Message::decode(&*encoded).unwrap() + }) + .collect(); + Self { proofs } + } +} + +impl MerkleProof { + pub fn verify_membership( + &self, + specs: &ProofSpecs, + root: MerkleRoot, + keys: MerklePath, + value: Vec, + start_index: usize, + ) -> Result<(), Error> { + // validate arguments + if self.proofs.is_empty() { + return Err(Error::empty_merkle_proof()); + } + if root.hash.is_empty() { + return Err(Error::empty_merkle_root()); + } + let num = self.proofs.len(); + let ics23_specs = Vec::::from(specs.clone()); + if ics23_specs.len() != num { + return Err(Error::number_of_specs_mismatch()); + } + if keys.key_path.len() != num { + return Err(Error::number_of_keys_mismatch()); + } + if value.is_empty() { + return Err(Error::empty_verified_value()); + } + + let mut subroot = value.clone(); + let mut value = value; + // keys are represented from root-to-leaf + for ((proof, spec), key) in self + .proofs + .iter() + .zip(ics23_specs.iter()) + .zip(keys.key_path.iter().rev()) + .skip(start_index) + { + match &proof.proof { + Some(Proof::Exist(existence_proof)) => { + subroot = calculate_existence_root(existence_proof) + .map_err(|_| Error::invalid_merkle_proof())?; + if !verify_membership(proof, spec, &subroot, key.as_bytes(), &value) { + return Err(Error::verification_failure()); + } + value = subroot.clone(); + } + _ => return Err(Error::invalid_merkle_proof()), + } + } + + if root.hash != subroot { + return Err(Error::verification_failure()); + } + + Ok(()) + } + + pub fn verify_non_membership( + &self, + specs: &ProofSpecs, + root: MerkleRoot, + keys: MerklePath, + ) -> Result<(), Error> { + // validate arguments + if self.proofs.is_empty() { + return Err(Error::empty_merkle_proof()); + } + if root.hash.is_empty() { + return Err(Error::empty_merkle_root()); + } + let num = self.proofs.len(); + let ics23_specs = Vec::::from(specs.clone()); + if ics23_specs.len() != num { + return Err(Error::number_of_specs_mismatch()); + } + if keys.key_path.len() != num { + return Err(Error::number_of_keys_mismatch()); + } + + // verify the absence of key in lowest subtree + let proof = self.proofs.get(0).ok_or_else(Error::invalid_merkle_proof)?; + let spec = ics23_specs.get(0).ok_or_else(Error::invalid_merkle_proof)?; + // keys are represented from root-to-leaf + let key = keys + .key_path + .get(num - 1) + .ok_or_else(Error::invalid_merkle_proof)?; + match &proof.proof { + Some(Proof::Nonexist(non_existence_proof)) => { + let subroot = calculate_non_existence_root(non_existence_proof)?; + if !verify_non_membership(proof, spec, &subroot, key.as_bytes()) { + return Err(Error::verification_failure()); + } + // verify membership proofs starting from index 1 with value = subroot + self.verify_membership(specs, root, keys, subroot, 1) + } + _ => Err(Error::invalid_merkle_proof()), + } + } +} + +// TODO move to ics23 +fn calculate_non_existence_root(proof: &NonExistenceProof) -> Result, Error> { + if let Some(left) = &proof.left { + calculate_existence_root(left).map_err(|_| Error::invalid_merkle_proof()) + } else if let Some(right) = &proof.right { + calculate_existence_root(right).map_err(|_| Error::invalid_merkle_proof()) + } else { + Err(Error::invalid_merkle_proof()) + } +} + +// Merkle Proof serialization notes: +// "Proof" id currently defined in a number of forms and included in a number of places +// - TmProof: in tendermint-rs/src/merkle/proof.rs:Proof +// - RawProofOps: in tendermint-proto/tendermint.cyrpto.rs:ProofOps +// - RawMerkleProof: in ibc-proto/ibc.core.commitment.v1.rs:MerkleProof +// - structure that includes a RawProofOps in its only `proof` field. +// #[derive(Clone, PartialEq, ::prost::Message)] +// pub struct MerkleProof { +// #[prost(message, optional, tag="1")] +// pub proof: ::core::option::Option<::tendermint_proto::crypto::ProofOps>, +// } +// - Vec: RawMerkleProof is not explicitly used but, serialized as Vec, it is +// included in all handshake messages that require proofs (i.e. all except the two `OpenInit`), +// and also in all queries that require proofs +// - MerkleProof: Domain type for RawMerkleProof, currently not used and identical to RawMerkleProof. +// This will change with verification implementation. +// - CommitmentProof: Defined in ibc-rs as Vec and currently used in all its messages +// +// Here are a couple of flows that illustrate the different conversions: +// IBC Messages and Handlers: sink happens in the handle verification +// Vec -> CommitmentProof -> RawMerkleProof -> MerkleProof +// +// Relayer: from the proof in the query response to the proof being included in a message +// TmProof -> RawProofOps => RawMerkleProof -> MerkleProof -> verify() +// -> MerkleProof -> RawMerkleProof -> CommitmentProof -> Vec +// Note: current implementation for ^ is simplified since verification is not yet implemented: +// TmProof -> RawProofOps => RawMerkleProof -> CommitmentProof -> Vec +// +// Implementations of (de)serializers and conversions: +// - commitment.rs: +// Vec <-> CommitmentProof +// CommitmentProof <-> RawMerkleProof +// - merkle.rs: +// RawMerkleProof <-> MerkleProof +// - tendermint-rs/src/merkle/proof.rs: +// TmProof <-> RawProofOps +// - cosmos.rs:abci_query() converts from query proof to Merkle proof: +// RawProofOps => RawMerkleProof +// +// impl TryFrom for MerkleProof { +// type Error = Error; +// fn try_from(value: RawMerkleProof) -> Result { +// Ok(MerkleProof { proof: value.proofs.into_iter().map(|v| v.into()).collect() }) +// } +// } +// +// impl From for RawMerkleProof { +// fn from(value: MerkleProof) -> Self { +// RawMerkleProof { proof: value.proof } +// } +// } + +pub fn convert_tm_to_ics_merkle_proof(tm_proof: &TendermintProof) -> Result { + let mut proofs = Vec::new(); + + for op in &tm_proof.ops { + let mut parsed = ibc_proto::ics23::CommitmentProof { proof: None }; + prost::Message::merge(&mut parsed, op.data.as_slice()) + .map_err(Error::commitment_proof_decoding_failed)?; + + proofs.push(parsed); + } + + Ok(RawMerkleProof { proofs }) +} diff --git a/modules/src/ics23_commitment/mock.rs b/modules/src/core/ics23_commitment/mock.rs similarity index 100% rename from modules/src/ics23_commitment/mock.rs rename to modules/src/core/ics23_commitment/mock.rs diff --git a/modules/src/core/ics23_commitment/mod.rs b/modules/src/core/ics23_commitment/mod.rs new file mode 100644 index 000000000..e3806ad77 --- /dev/null +++ b/modules/src/core/ics23_commitment/mod.rs @@ -0,0 +1,8 @@ +//! ICS 23: Commitment implementation of a cryptographic scheme that verifies +//! state transitions between chains. + +pub mod commitment; +pub mod error; +pub mod merkle; +pub mod mock; +pub mod specs; diff --git a/modules/src/core/ics23_commitment/specs.rs b/modules/src/core/ics23_commitment/specs.rs new file mode 100644 index 000000000..53e45a591 --- /dev/null +++ b/modules/src/core/ics23_commitment/specs.rs @@ -0,0 +1,148 @@ +use crate::prelude::*; +use ibc_proto::ics23::{InnerSpec as IbcInnerSpec, LeafOp as IbcLeafOp, ProofSpec as IbcProofSpec}; +use ics23::{InnerSpec as Ics23InnerSpec, LeafOp as Ics23LeafOp, ProofSpec as Ics23ProofSpec}; +use serde::{Deserialize, Serialize}; + +/// An array of proof specifications. +/// +/// This type encapsulates different types of proof specifications, mostly predefined, e.g., for +/// Cosmos-SDK. +/// Additionally, this type also aids in the conversion from `ProofSpec` types from crate `ics23` +/// into proof specifications as represented in the `ibc_proto` type; see the +/// `From` trait(s) below. +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] +pub struct ProofSpecs(Vec); + +impl ProofSpecs { + /// Returns the specification for Cosmos-SDK proofs + pub fn cosmos() -> Self { + vec![ + ics23::iavl_spec(), // Format of proofs-iavl (iavl merkle proofs) + ics23::tendermint_spec(), // Format of proofs-tendermint (crypto/ merkle SimpleProof) + ] + .into() + } + + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } +} + +impl Default for ProofSpecs { + fn default() -> Self { + Self::cosmos() + } +} + +impl From> for ProofSpecs { + fn from(ibc_specs: Vec) -> Self { + Self(ibc_specs.into_iter().map(ProofSpec).collect()) + } +} + +impl From> for ProofSpecs { + fn from(ics23_specs: Vec) -> Self { + Self( + ics23_specs + .into_iter() + .map(|ics23_spec| ics23_spec.into()) + .collect(), + ) + } +} + +impl From for Vec { + fn from(specs: ProofSpecs) -> Self { + specs.0.into_iter().map(|spec| spec.into()).collect() + } +} + +impl From for Vec { + fn from(specs: ProofSpecs) -> Self { + specs.0.into_iter().map(|spec| spec.0).collect() + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] +struct ProofSpec(IbcProofSpec); + +impl From for ProofSpec { + fn from(spec: Ics23ProofSpec) -> Self { + Self(IbcProofSpec { + leaf_spec: spec.leaf_spec.map(|lop| LeafOp::from(lop).0), + inner_spec: spec.inner_spec.map(|ispec| InnerSpec::from(ispec).0), + max_depth: spec.max_depth, + min_depth: spec.min_depth, + }) + } +} + +impl From for Ics23ProofSpec { + fn from(spec: ProofSpec) -> Self { + let spec = spec.0; + Ics23ProofSpec { + leaf_spec: spec.leaf_spec.map(|lop| LeafOp(lop).into()), + inner_spec: spec.inner_spec.map(|ispec| InnerSpec(ispec).into()), + max_depth: spec.max_depth, + min_depth: spec.min_depth, + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] +struct LeafOp(IbcLeafOp); + +impl From for LeafOp { + fn from(leaf_op: Ics23LeafOp) -> Self { + Self(IbcLeafOp { + hash: leaf_op.hash, + prehash_key: leaf_op.prehash_key, + prehash_value: leaf_op.prehash_value, + length: leaf_op.length, + prefix: leaf_op.prefix, + }) + } +} + +impl From for Ics23LeafOp { + fn from(leaf_op: LeafOp) -> Self { + let leaf_op = leaf_op.0; + Ics23LeafOp { + hash: leaf_op.hash, + prehash_key: leaf_op.prehash_key, + prehash_value: leaf_op.prehash_value, + length: leaf_op.length, + prefix: leaf_op.prefix, + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] +struct InnerSpec(IbcInnerSpec); + +impl From for InnerSpec { + fn from(inner_spec: Ics23InnerSpec) -> Self { + Self(IbcInnerSpec { + child_order: inner_spec.child_order, + child_size: inner_spec.child_size, + min_prefix_length: inner_spec.min_prefix_length, + max_prefix_length: inner_spec.max_prefix_length, + empty_child: inner_spec.empty_child, + hash: inner_spec.hash, + }) + } +} + +impl From for Ics23InnerSpec { + fn from(inner_spec: InnerSpec) -> Self { + let inner_spec = inner_spec.0; + Ics23InnerSpec { + child_order: inner_spec.child_order, + child_size: inner_spec.child_size, + min_prefix_length: inner_spec.min_prefix_length, + max_prefix_length: inner_spec.max_prefix_length, + empty_child: inner_spec.empty_child, + hash: inner_spec.hash, + } + } +} diff --git a/modules/src/ics24_host/error.rs b/modules/src/core/ics24_host/error.rs similarity index 100% rename from modules/src/ics24_host/error.rs rename to modules/src/core/ics24_host/error.rs diff --git a/modules/src/ics24_host/identifier.rs b/modules/src/core/ics24_host/identifier.rs similarity index 90% rename from modules/src/ics24_host/identifier.rs rename to modules/src/core/ics24_host/identifier.rs index d9518aebf..25389ca8a 100644 --- a/modules/src/ics24_host/identifier.rs +++ b/modules/src/core/ics24_host/identifier.rs @@ -1,12 +1,13 @@ use crate::alloc::string::ToString; use crate::prelude::*; -use core::convert::TryFrom; + +use core::convert::{From, Infallible}; use core::fmt::{self, Display, Formatter}; use core::str::FromStr; use serde::{Deserialize, Serialize}; -use crate::ics02_client::client_type::ClientType; -use crate::ics24_host::error::ValidationError; +use crate::core::ics02_client::client_type::ClientType; +use crate::core::ics24_host::error::ValidationError; use super::validate::*; @@ -29,7 +30,7 @@ impl ChainId { /// /// The returned `ChainId` will have the format: `{chain name}-{epoch number}`. /// ``` - /// use ibc::ics24_host::identifier::ChainId; + /// use ibc::core::ics24_host::identifier::ChainId; /// /// let epoch_number = 10; /// let id = ChainId::new("chainA".to_string(), epoch_number); @@ -42,6 +43,19 @@ impl ChainId { } } + pub fn from_string(id: &str) -> Self { + let version = if Self::is_epoch_format(id) { + Self::chain_version(id) + } else { + 0 + }; + + Self { + id: id.to_string(), + version, + } + } + /// Get a reference to the underlying string. pub fn as_str(&self) -> &str { &self.id @@ -55,7 +69,7 @@ impl ChainId { /// Extract the version from the given chain identifier. /// ``` - /// use ibc::ics24_host::identifier::ChainId; + /// use ibc::core::ics24_host::identifier::ChainId; /// /// assert_eq!(ChainId::chain_version("chain--a-0"), 0); /// assert_eq!(ChainId::chain_version("ibc-10"), 10); @@ -78,7 +92,7 @@ impl ChainId { /// is_epoch_format() checks if a chain_id is in the format required for parsing epochs /// The chainID must be in the form: `{chainID}-{version}` /// ``` - /// use ibc::ics24_host::identifier::ChainId; + /// use ibc::core::ics24_host::identifier::ChainId; /// assert_eq!(ChainId::is_epoch_format("chainA-0"), false); /// assert_eq!(ChainId::is_epoch_format("chainA"), false); /// assert_eq!(ChainId::is_epoch_format("chainA-1"), true); @@ -90,19 +104,10 @@ impl ChainId { } impl FromStr for ChainId { - type Err = ValidationError; + type Err = Infallible; fn from_str(id: &str) -> Result { - let version = if Self::is_epoch_format(id) { - Self::chain_version(id) - } else { - 0 - }; - - Ok(Self { - id: id.to_string(), - version, - }) + Ok(Self::from_string(id)) } } @@ -130,11 +135,9 @@ impl Default for ChainId { } } -impl TryFrom for ChainId { - type Error = ValidationError; - - fn try_from(value: String) -> Result { - Self::from_str(value.as_str()) +impl From for ChainId { + fn from(value: String) -> Self { + Self::from_string(&value) } } @@ -147,8 +150,8 @@ impl ClientId { /// `counter`; these are separated by a dash "-". /// /// ``` - /// # use ibc::ics24_host::identifier::ClientId; - /// # use ibc::ics02_client::client_type::ClientType; + /// # use ibc::core::ics24_host::identifier::ClientId; + /// # use ibc::core::ics02_client::client_type::ClientType; /// let tm_client_id = ClientId::new(ClientType::Tendermint, 0); /// assert!(tm_client_id.is_ok()); /// tm_client_id.map(|id| { assert_eq!(&id, "07-tendermint-0") }); @@ -207,7 +210,7 @@ impl Default for ClientId { /// Equality check against string literal (satisfies &ClientId == &str). /// ``` /// use core::str::FromStr; -/// use ibc::ics24_host::identifier::ClientId; +/// use ibc::core::ics24_host::identifier::ClientId; /// let client_id = ClientId::from_str("clientidtwo"); /// assert!(client_id.is_ok()); /// client_id.map(|id| {assert_eq!(&id, "clientidtwo")}); @@ -235,7 +238,7 @@ impl ConnectionId { /// `ConnectionId::prefix()`) so this method accepts a single argument, the `counter`. /// /// ``` - /// # use ibc::ics24_host::identifier::ConnectionId; + /// # use ibc::core::ics24_host::identifier::ConnectionId; /// let conn_id = ConnectionId::new(11); /// assert_eq!(&conn_id, "connection-11"); /// ``` @@ -284,7 +287,7 @@ impl Default for ConnectionId { /// Equality check against string literal (satisfies &ConnectionId == &str). /// ``` /// use core::str::FromStr; -/// use ibc::ics24_host::identifier::ConnectionId; +/// use ibc::core::ics24_host::identifier::ConnectionId; /// let conn_id = ConnectionId::from_str("connectionId-0"); /// assert!(conn_id.is_ok()); /// conn_id.map(|id| {assert_eq!(&id, "connectionId-0")}); @@ -299,6 +302,11 @@ impl PartialEq for ConnectionId { pub struct PortId(pub String); impl PortId { + /// Infallible creation of the well-known transfer port + pub fn transfer() -> Self { + Self("transfer".to_string()) + } + /// Get this identifier as a borrowed `&str` pub fn as_str(&self) -> &str { &self.0 @@ -342,7 +350,7 @@ impl ChannelId { /// accepts a single argument, the `counter`. /// /// ``` - /// # use ibc::ics24_host::identifier::ChannelId; + /// # use ibc::core::ics24_host::identifier::ChannelId; /// let chan_id = ChannelId::new(27); /// assert_eq!(&chan_id, "channel-27"); /// ``` @@ -401,6 +409,15 @@ pub struct PortChannelId { pub port_id: PortId, } +impl PortChannelId { + pub fn new(channel_id: ChannelId, port_id: PortId) -> Self { + Self { + channel_id, + port_id, + } + } +} + impl Display for PortChannelId { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> { write!(f, "{}/{}", self.port_id, self.channel_id) diff --git a/modules/src/core/ics24_host/mod.rs b/modules/src/core/ics24_host/mod.rs new file mode 100644 index 000000000..23be43fb7 --- /dev/null +++ b/modules/src/core/ics24_host/mod.rs @@ -0,0 +1,9 @@ +//! ICS 24: Host defines the minimal set of interfaces that a +//! state machine hosting an IBC-enabled chain must implement. + +pub use path::{ClientUpgradePath, Path, IBC_QUERY_PATH, SDK_UPGRADE_QUERY_PATH}; + +pub mod error; +pub mod identifier; +pub mod path; +pub mod validate; diff --git a/modules/src/core/ics24_host/path.rs b/modules/src/core/ics24_host/path.rs new file mode 100644 index 000000000..262d75cb4 --- /dev/null +++ b/modules/src/core/ics24_host/path.rs @@ -0,0 +1,1017 @@ +use crate::prelude::*; + +/// Path-space as listed in ICS-024 +/// https://github.com/cosmos/ibc/tree/master/spec/ics-024-host-requirements#path-space +/// Some of these are implemented in other ICSs, but ICS-024 has a nice summary table. +/// +use core::str::FromStr; + +use crate::core::ics04_channel::packet::Sequence; +use crate::core::ics24_host::identifier::{ChannelId, ClientId, ConnectionId, PortId}; + +use derive_more::{Display, From}; +use flex_error::define_error; + +/// ABCI Query path for the IBC sub-store +pub const IBC_QUERY_PATH: &str = "store/ibc/key"; + +/// ABCI Query path for the upgrade sub-store +/// ## Note: This is SDK/Tendermint specific! +pub const SDK_UPGRADE_QUERY_PATH: &str = "store/upgrade/key"; + +/// ABCI client upgrade keys +/// - The key identifying the upgraded IBC state within the upgrade sub-store +const UPGRADED_IBC_STATE: &str = "upgradedIBCState"; +///- The key identifying the upgraded client state +const UPGRADED_CLIENT_STATE: &str = "upgradedClient"; +/// - The key identifying the upgraded consensus state +const UPGRADED_CLIENT_CONSENSUS_STATE: &str = "upgradedConsState"; + +/// The Path enum abstracts out the different sub-paths. +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, From, Display)] +pub enum Path { + ClientType(ClientTypePath), + ClientState(ClientStatePath), + ClientConsensusState(ClientConsensusStatePath), + ClientConnections(ClientConnectionsPath), + Connections(ConnectionsPath), + Ports(PortsPath), + ChannelEnds(ChannelEndsPath), + SeqSends(SeqSendsPath), + SeqRecvs(SeqRecvsPath), + SeqAcks(SeqAcksPath), + Commitments(CommitmentsPath), + Acks(AcksPath), + Receipts(ReceiptsPath), + Upgrade(ClientUpgradePath), +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] +#[display(fmt = "clients/{}/clientType", _0)] +pub struct ClientTypePath(pub ClientId); + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] +#[display(fmt = "clients/{}/clientState", _0)] +pub struct ClientStatePath(pub ClientId); + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] +#[display( + fmt = "clients/{}/consensusStates/{}-{}", + "client_id", + "epoch", + "height" +)] +pub struct ClientConsensusStatePath { + pub client_id: ClientId, + pub epoch: u64, + pub height: u64, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] +#[display(fmt = "clients/{}/connections", _0)] +pub struct ClientConnectionsPath(pub ClientId); + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] +#[display(fmt = "connections/{}", _0)] +pub struct ConnectionsPath(pub ConnectionId); + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] +#[display(fmt = "ports/{}", _0)] +pub struct PortsPath(pub PortId); + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] +#[display(fmt = "channelEnds/ports/{}/channels/{}", _0, _1)] +pub struct ChannelEndsPath(pub PortId, pub ChannelId); + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] +#[display(fmt = "nextSequenceSend/ports/{}/channels/{}", _0, _1)] +pub struct SeqSendsPath(pub PortId, pub ChannelId); + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] +#[display(fmt = "nextSequenceRecv/ports/{}/channels/{}", _0, _1)] +pub struct SeqRecvsPath(pub PortId, pub ChannelId); + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] +#[display(fmt = "nextSequenceAck/ports/{}/channels/{}", _0, _1)] +pub struct SeqAcksPath(pub PortId, pub ChannelId); + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] +#[display( + fmt = "commitments/ports/{}/channels/{}/sequences/{}", + "port_id", + "channel_id", + "sequence" +)] +pub struct CommitmentsPath { + pub port_id: PortId, + pub channel_id: ChannelId, + pub sequence: Sequence, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] +#[display( + fmt = "acks/ports/{}/channels/{}/sequences/{}", + "port_id", + "channel_id", + "sequence" +)] +pub struct AcksPath { + pub port_id: PortId, + pub channel_id: ChannelId, + pub sequence: Sequence, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] +#[display( + fmt = "receipts/ports/{}/channels/{}/sequences/{}", + "port_id", + "channel_id", + "sequence" +)] +pub struct ReceiptsPath { + pub port_id: PortId, + pub channel_id: ChannelId, + pub sequence: Sequence, +} + +/// Paths that are specific for client upgrades. +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] +pub enum ClientUpgradePath { + #[display(fmt = "{}/{}/{}", UPGRADED_IBC_STATE, _0, UPGRADED_CLIENT_STATE)] + UpgradedClientState(u64), + #[display( + fmt = "{}/{}/{}", + UPGRADED_IBC_STATE, + _0, + UPGRADED_CLIENT_CONSENSUS_STATE + )] + UpgradedClientConsensusState(u64), +} + +/// Sub-paths which are not part of the specification, but are still +/// useful to represent for parsing purposes. +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +enum SubPath { + Channels(ChannelId), + Sequences(Sequence), +} + +impl Path { + /// Indication if the path is provable. + pub fn is_provable(&self) -> bool { + !matches!(&self, Path::ClientConnections(_) | Path::Ports(_)) + } + + /// into_bytes implementation + pub fn into_bytes(self) -> Vec { + self.to_string().into_bytes() + } +} + +define_error! { + #[derive(Eq, PartialEq)] + PathError { + ParseFailure + { path: String } + | e | { format!("'{}' could not be parsed into a Path", e.path) }, + } +} + +/// The FromStr trait allows paths encoded as strings to be parsed into Paths. +impl FromStr for Path { + type Err = PathError; + + fn from_str(s: &str) -> Result { + let components: Vec<&str> = s.split('/').collect(); + + parse_client_paths(&components) + .or_else(|| parse_connections(&components)) + .or_else(|| parse_ports(&components)) + .or_else(|| parse_channel_ends(&components)) + .or_else(|| parse_seqs(&components)) + .or_else(|| parse_commitments(&components)) + .or_else(|| parse_acks(&components)) + .or_else(|| parse_receipts(&components)) + .or_else(|| parse_upgrades(&components)) + .ok_or_else(|| PathError::parse_failure(s.to_string())) + } +} + +fn parse_client_paths(components: &[&str]) -> Option { + let first = match components.first() { + Some(f) => *f, + None => return None, + }; + + if first != "clients" { + return None; + } + + let client_id = match ClientId::from_str(components[1]) { + Ok(s) => s, + Err(_) => return None, + }; + + if components.len() == 3 { + match components[2] { + "clientType" => Some(ClientTypePath(client_id).into()), + "clientState" => Some(ClientStatePath(client_id).into()), + "connections" => Some(ClientConnectionsPath(client_id).into()), + _ => None, + } + } else if components.len() == 4 { + if "consensusStates" != components[2] { + return None; + } + + let epoch_height = match components.last() { + Some(eh) => *eh, + None => return None, + }; + + let epoch_height: Vec<&str> = epoch_height.split('-').collect(); + + if epoch_height.len() != 2 { + return None; + } + + let epoch = epoch_height[0]; + let height = epoch_height[1]; + + let epoch = match epoch.parse::() { + Ok(ep) => ep, + Err(_) => return None, + }; + + let height = match height.parse::() { + Ok(h) => h, + Err(_) => return None, + }; + + Some( + ClientConsensusStatePath { + client_id, + epoch, + height, + } + .into(), + ) + } else { + None + } +} + +fn parse_connections(components: &[&str]) -> Option { + if components.len() != 2 { + return None; + } + + let first = match components.first() { + Some(f) => *f, + None => return None, + }; + + if first != "connections" { + return None; + } + + let connection_id = match components.last() { + Some(c) => *c, + None => return None, + }; + + let connection_id = match ConnectionId::from_str(connection_id) { + Ok(c) => c, + Err(_) => return None, + }; + + Some(ConnectionsPath(connection_id).into()) +} + +fn parse_ports(components: &[&str]) -> Option { + if components.len() != 2 { + return None; + } + + let first = match components.first() { + Some(f) => *f, + None => return None, + }; + + if first != "ports" { + return None; + } + + let port_id = match components.last() { + Some(p) => *p, + None => return None, + }; + + let port_id = match PortId::from_str(port_id) { + Ok(p) => p, + Err(_) => return None, + }; + + Some(PortsPath(port_id).into()) +} + +fn parse_channels(components: &[&str]) -> Option { + if components.len() != 2 { + return None; + } + + let first = match components.first() { + Some(f) => *f, + None => return None, + }; + + if first != "channels" { + return None; + } + + let channel_id = match components.last() { + Some(c) => *c, + None => return None, + }; + + let channel_id = match ChannelId::from_str(channel_id) { + Ok(c) => c, + Err(_) => return None, + }; + + Some(SubPath::Channels(channel_id)) +} + +fn parse_sequences(components: &[&str]) -> Option { + if components.len() != 2 { + return None; + } + + let first = match components.first() { + Some(f) => *f, + None => return None, + }; + + if first != "sequences" { + return None; + } + + let sequence_number = match components.last() { + Some(s) => *s, + None => return None, + }; + + match Sequence::from_str(sequence_number) { + Ok(seq) => Some(SubPath::Sequences(seq)), + Err(_) => None, + } +} + +fn parse_channel_ends(components: &[&str]) -> Option { + if components.len() != 5 { + return None; + } + + let first = match components.first() { + Some(f) => *f, + None => return None, + }; + + if first != "channelEnds" { + return None; + } + + let port = parse_ports(&components[1..=2]); + let channel = parse_channels(&components[3..=4]); + + let port_id = if let Some(Path::Ports(PortsPath(port_id))) = port { + port_id + } else { + return None; + }; + + let channel_id = if let Some(SubPath::Channels(channel_id)) = channel { + channel_id + } else { + return None; + }; + + Some(ChannelEndsPath(port_id, channel_id).into()) +} + +fn parse_seqs(components: &[&str]) -> Option { + if components.len() != 5 { + return None; + } + + let first = match components.first() { + Some(f) => *f, + None => return None, + }; + + let port = parse_ports(&components[1..=2]); + let channel = parse_channels(&components[3..=4]); + + let port_id = if let Some(Path::Ports(PortsPath(port_id))) = port { + port_id + } else { + return None; + }; + + let channel_id = if let Some(SubPath::Channels(channel_id)) = channel { + channel_id + } else { + return None; + }; + + match first { + "nextSequenceSend" => Some(SeqSendsPath(port_id, channel_id).into()), + "nextSequenceRecv" => Some(SeqRecvsPath(port_id, channel_id).into()), + "nextSequenceAck" => Some(SeqAcksPath(port_id, channel_id).into()), + _ => None, + } +} + +fn parse_commitments(components: &[&str]) -> Option { + if components.len() != 7 { + return None; + } + + let first = match components.first() { + Some(f) => *f, + None => return None, + }; + + if first != "commitments" { + return None; + } + + let port = parse_ports(&components[1..=2]); + let channel = parse_channels(&components[3..=4]); + let sequence = parse_sequences(&components[5..]); + + let port_id = if let Some(Path::Ports(PortsPath(port_id))) = port { + port_id + } else { + return None; + }; + + let channel_id = if let Some(SubPath::Channels(channel_id)) = channel { + channel_id + } else { + return None; + }; + + let sequence = if let Some(SubPath::Sequences(seq)) = sequence { + seq + } else { + return None; + }; + + Some( + CommitmentsPath { + port_id, + channel_id, + sequence, + } + .into(), + ) +} + +fn parse_acks(components: &[&str]) -> Option { + if components.len() != 7 { + return None; + } + + let first = match components.first() { + Some(f) => *f, + None => return None, + }; + + if first != "acks" { + return None; + } + + let port = parse_ports(&components[1..=2]); + let channel = parse_channels(&components[3..=4]); + let sequence = parse_sequences(&components[5..]); + + let port_id = if let Some(Path::Ports(PortsPath(port_id))) = port { + port_id + } else { + return None; + }; + + let channel_id = if let Some(SubPath::Channels(channel_id)) = channel { + channel_id + } else { + return None; + }; + + let sequence = if let Some(SubPath::Sequences(seq)) = sequence { + seq + } else { + return None; + }; + + Some( + AcksPath { + port_id, + channel_id, + sequence, + } + .into(), + ) +} + +fn parse_receipts(components: &[&str]) -> Option { + if components.len() != 7 { + return None; + } + + let first = match components.first() { + Some(f) => *f, + None => return None, + }; + + if first != "receipts" { + return None; + } + + let port = parse_ports(&components[1..=2]); + let channel = parse_channels(&components[3..=4]); + let sequence = parse_sequences(&components[5..]); + + let port_id = if let Some(Path::Ports(PortsPath(port_id))) = port { + port_id + } else { + return None; + }; + + let channel_id = if let Some(SubPath::Channels(channel_id)) = channel { + channel_id + } else { + return None; + }; + + let sequence = if let Some(SubPath::Sequences(seq)) = sequence { + seq + } else { + return None; + }; + + Some( + ReceiptsPath { + port_id, + channel_id, + sequence, + } + .into(), + ) +} + +fn parse_upgrades(components: &[&str]) -> Option { + if components.len() != 3 { + return None; + } + + let first = match components.first() { + Some(f) => *f, + None => return None, + }; + + if first != UPGRADED_IBC_STATE { + return None; + } + + let last = match components.last() { + Some(l) => *l, + None => return None, + }; + + let height = match components[1].parse::() { + Ok(h) => h, + Err(_) => return None, + }; + + match last { + UPGRADED_CLIENT_STATE => Some(ClientUpgradePath::UpgradedClientState(height).into()), + UPGRADED_CLIENT_CONSENSUS_STATE => { + Some(ClientUpgradePath::UpgradedClientConsensusState(height).into()) + } + _ => None, + } +} + +#[cfg(test)] +mod tests { + use super::*; + use core::str::FromStr; + + #[test] + fn invalid_path_doesnt_parse() { + let invalid_path = Path::from_str("clients/clientType"); + + assert!(invalid_path.is_err()); + } + + #[test] + fn test_parse_client_paths_fn() { + let path = "clients/07-tendermint-0/clientType"; + let components: Vec<&str> = path.split('/').collect(); + + assert_eq!( + parse_client_paths(&components), + Some(Path::ClientType(ClientTypePath(ClientId::default()))) + ); + + let path = "clients/07-tendermint-0/clientState"; + let components: Vec<&str> = path.split('/').collect(); + + assert_eq!( + parse_client_paths(&components), + Some(Path::ClientState(ClientStatePath(ClientId::default()))) + ); + + let path = "clients/07-tendermint-0/consensusStates/15-31"; + let components: Vec<&str> = path.split('/').collect(); + + assert_eq!( + parse_client_paths(&components), + Some(Path::ClientConsensusState(ClientConsensusStatePath { + client_id: ClientId::default(), + epoch: 15, + height: 31, + })) + ); + } + + #[test] + fn client_type_path_parses() { + let path = "clients/07-tendermint-0/clientType"; + let path = Path::from_str(path); + + assert!(path.is_ok()); + assert_eq!( + path.unwrap(), + Path::ClientType(ClientTypePath(ClientId::default())) + ); + } + + #[test] + fn client_state_path_parses() { + let path = "clients/07-tendermint-0/clientState"; + let path = Path::from_str(path); + + assert!(path.is_ok()); + assert_eq!( + path.unwrap(), + Path::ClientState(ClientStatePath(ClientId::default())) + ); + } + + #[test] + fn client_consensus_state_path_parses() { + let path = "clients/07-tendermint-0/consensusStates/15-31"; + let path = Path::from_str(path); + + assert!(path.is_ok()); + assert_eq!( + path.unwrap(), + Path::ClientConsensusState(ClientConsensusStatePath { + client_id: ClientId::default(), + epoch: 15, + height: 31, + }) + ); + } + + #[test] + fn client_connections_path_parses() { + let path = "clients/07-tendermint-0/connections"; + let path = Path::from_str(path); + + assert!(path.is_ok()); + assert_eq!( + path.unwrap(), + Path::ClientConnections(ClientConnectionsPath(ClientId::default())) + ); + } + + #[test] + fn test_parse_connections_fn() { + let path = "connections/connection-0"; + let components: Vec<&str> = path.split('/').collect(); + + assert_eq!( + parse_connections(&components), + Some(Path::Connections(ConnectionsPath(ConnectionId::new(0)))), + ); + } + + #[test] + fn connections_path_parses() { + let path = "connections/connection-0"; + let path = Path::from_str(path); + + assert!(path.is_ok()); + assert_eq!( + path.unwrap(), + Path::Connections(ConnectionsPath(ConnectionId::new(0))) + ); + } + + #[test] + fn test_parse_ports_fn() { + let path = "ports/defaultPort"; + let components: Vec<&str> = path.split('/').collect(); + + assert_eq!( + parse_ports(&components), + Some(Path::Ports(PortsPath(PortId::default()))), + ); + } + + #[test] + fn ports_path_parses() { + let path = "ports/defaultPort"; + let path = Path::from_str(path); + + assert!(path.is_ok()); + assert_eq!(path.unwrap(), Path::Ports(PortsPath(PortId::default()))); + } + + #[test] + fn test_parse_channels_fn() { + let path = "channels/channel-0"; + let components: Vec<&str> = path.split('/').collect(); + + assert_eq!( + parse_channels(&components), + Some(SubPath::Channels(ChannelId::default())), + ); + } + + #[test] + fn channels_path_doesnt_parse() { + let path = "channels/channel-0"; + let path = Path::from_str(path); + + assert!(path.is_err()); + } + + #[test] + fn test_parse_sequences_fn() { + let path = "sequences/0"; + let components: Vec<&str> = path.split('/').collect(); + + assert_eq!( + parse_sequences(&components), + Some(SubPath::Sequences(Sequence::default())) + ); + } + + #[test] + fn sequences_path_doesnt_parse() { + let path = "sequences/0"; + let path = Path::from_str(path); + + assert!(path.is_err()); + } + + #[test] + fn test_parse_channel_ends_fn() { + let path = "channelEnds/ports/defaultPort/channels/channel-0"; + let components: Vec<&str> = path.split('/').collect(); + + assert_eq!( + parse_channel_ends(&components), + Some(Path::ChannelEnds(ChannelEndsPath( + PortId::default(), + ChannelId::default() + ))), + ); + } + + #[test] + fn channel_ends_path_parses() { + let path = "channelEnds/ports/defaultPort/channels/channel-0"; + let path = Path::from_str(path); + + assert!(path.is_ok()); + assert_eq!( + path.unwrap(), + Path::ChannelEnds(ChannelEndsPath(PortId::default(), ChannelId::default())), + ); + } + + #[test] + fn test_parse_seqs_fn() { + let path = "nextSequenceSend/ports/defaultPort/channels/channel-0"; + let components: Vec<&str> = path.split('/').collect(); + + assert_eq!( + parse_seqs(&components), + Some(Path::SeqSends(SeqSendsPath( + PortId::default(), + ChannelId::default() + ))), + ); + + let path = "nextSequenceRecv/ports/defaultPort/channels/channel-0"; + let components: Vec<&str> = path.split('/').collect(); + + assert_eq!( + parse_seqs(&components), + Some(Path::SeqRecvs(SeqRecvsPath( + PortId::default(), + ChannelId::default() + ))), + ); + + let path = "nextSequenceAck/ports/defaultPort/channels/channel-0"; + let components: Vec<&str> = path.split('/').collect(); + + assert_eq!( + parse_seqs(&components), + Some(Path::SeqAcks(SeqAcksPath( + PortId::default(), + ChannelId::default() + ))), + ); + } + + #[test] + fn sequence_send_path_parses() { + let path = "nextSequenceSend/ports/defaultPort/channels/channel-0"; + let path = Path::from_str(path); + + assert!(path.is_ok()); + assert_eq!( + path.unwrap(), + Path::SeqSends(SeqSendsPath(PortId::default(), ChannelId::default())), + ); + } + + #[test] + fn sequence_recv_path_parses() { + let path = "nextSequenceRecv/ports/defaultPort/channels/channel-0"; + let path = Path::from_str(path); + + assert!(path.is_ok()); + assert_eq!( + path.unwrap(), + Path::SeqRecvs(SeqRecvsPath(PortId::default(), ChannelId::default())), + ); + } + + #[test] + fn sequence_ack_path_parses() { + let path = "nextSequenceAck/ports/defaultPort/channels/channel-0"; + let path = Path::from_str(path); + + assert!(path.is_ok()); + assert_eq!( + path.unwrap(), + Path::SeqAcks(SeqAcksPath(PortId::default(), ChannelId::default())), + ); + } + + #[test] + fn test_parse_commitments_fn() { + let path = "commitments/ports/defaultPort/channels/channel-0/sequences/0"; + let components: Vec<&str> = path.split('/').collect(); + + assert_eq!( + parse_commitments(&components), + Some(Path::Commitments(CommitmentsPath { + port_id: PortId::default(), + channel_id: ChannelId::default(), + sequence: Sequence::default(), + })), + ); + } + + #[test] + fn commitments_path_parses() { + let path = "commitments/ports/defaultPort/channels/channel-0/sequences/0"; + let path = Path::from_str(path); + + assert!(path.is_ok()); + assert_eq!( + path.unwrap(), + Path::Commitments(CommitmentsPath { + port_id: PortId::default(), + channel_id: ChannelId::default(), + sequence: Sequence::default(), + }), + ); + } + + #[test] + fn test_parse_acks_fn() { + let path = "acks/ports/defaultPort/channels/channel-0/sequences/0"; + let components: Vec<&str> = path.split('/').collect(); + + assert_eq!( + parse_acks(&components), + Some(Path::Acks(AcksPath { + port_id: PortId::default(), + channel_id: ChannelId::default(), + sequence: Sequence::default(), + })), + ); + } + + #[test] + fn acks_path_parses() { + let path = "acks/ports/defaultPort/channels/channel-0/sequences/0"; + let path = Path::from_str(path); + + assert!(path.is_ok()); + assert_eq!( + path.unwrap(), + Path::Acks(AcksPath { + port_id: PortId::default(), + channel_id: ChannelId::default(), + sequence: Sequence::default(), + }), + ); + } + + #[test] + fn test_parse_receipts_fn() { + let path = "receipts/ports/defaultPort/channels/channel-0/sequences/0"; + let components: Vec<&str> = path.split('/').collect(); + + assert_eq!( + parse_receipts(&components), + Some(Path::Receipts(ReceiptsPath { + port_id: PortId::default(), + channel_id: ChannelId::default(), + sequence: Sequence::default(), + })), + ); + } + + #[test] + fn receipts_path_parses() { + let path = "receipts/ports/defaultPort/channels/channel-0/sequences/0"; + let path = Path::from_str(path); + + assert!(path.is_ok()); + assert_eq!( + path.unwrap(), + Path::Receipts(ReceiptsPath { + port_id: PortId::default(), + channel_id: ChannelId::default(), + sequence: Sequence::default(), + }), + ); + } + + #[test] + fn test_parse_upgrades_fn() { + let path = "upgradedIBCState/0/upgradedClient"; + let components: Vec<&str> = path.split('/').collect(); + + assert_eq!( + parse_upgrades(&components), + Some(Path::Upgrade(ClientUpgradePath::UpgradedClientState(0))), + ); + + let path = "upgradedIBCState/0/upgradedConsState"; + let components: Vec<&str> = path.split('/').collect(); + + assert_eq!( + parse_upgrades(&components), + Some(Path::Upgrade( + ClientUpgradePath::UpgradedClientConsensusState(0) + )), + ) + } + + #[test] + fn upgrade_client_state_path_parses() { + let path = "upgradedIBCState/0/upgradedClient"; + let path = Path::from_str(path); + + assert!(path.is_ok()); + assert_eq!( + path.unwrap(), + Path::Upgrade(ClientUpgradePath::UpgradedClientState(0)), + ); + } + + #[test] + fn upgrade_client_consensus_state_path_parses() { + let path = "upgradedIBCState/0/upgradedConsState"; + let path = Path::from_str(path); + + assert!(path.is_ok()); + assert_eq!( + path.unwrap(), + Path::Upgrade(ClientUpgradePath::UpgradedClientConsensusState(0)), + ); + } +} diff --git a/modules/src/ics24_host/validate.rs b/modules/src/core/ics24_host/validate.rs similarity index 93% rename from modules/src/ics24_host/validate.rs rename to modules/src/core/ics24_host/validate.rs index 0e61957a8..5a19a1370 100644 --- a/modules/src/ics24_host/validate.rs +++ b/modules/src/core/ics24_host/validate.rs @@ -61,10 +61,10 @@ pub fn validate_connection_identifier(id: &str) -> Result<(), Error> { /// Default validator function for Port identifiers. /// -/// A valid Identifier must be between 2-64 characters and only contain lowercase +/// A valid Identifier must be between 2-128 characters and only contain lowercase /// alphabetic characters, pub fn validate_port_identifier(id: &str) -> Result<(), Error> { - validate_identifier(id, 2, 64) + validate_identifier(id, 2, 128) } /// Default validator function for Channel identifiers. @@ -77,11 +77,11 @@ pub fn validate_channel_identifier(id: &str) -> Result<(), Error> { #[cfg(test)] mod tests { - use crate::ics24_host::validate::{ + use crate::core::ics24_host::validate::{ validate_channel_identifier, validate_client_identifier, validate_connection_identifier, validate_identifier, validate_port_identifier, }; - use test_env_log::test; + use test_log::test; #[test] fn parse_invalid_port_id_min() { @@ -92,9 +92,9 @@ mod tests { #[test] fn parse_invalid_port_id_max() { - // invalid max port id (test string length is 65 chars) + // invalid max port id (test string length is 130 chars) let id = validate_port_identifier( - "9anxkcme6je544d5lnj46zqiiiygfqzf8w4bjecbnyj4lj6s7zlpst67yln64tixp", + "9anxkcme6je544d5lnj46zqiiiygfqzf8w4bjecbnyj4lj6s7zlpst67yln64tixp9anxkcme6je544d5lnj46zqiiiygfqzf8w4bjecbnyj4lj6s7zlpst67yln64tixp", ); assert!(id.is_err()) } diff --git a/modules/src/ics26_routing/context.rs b/modules/src/core/ics26_routing/context.rs similarity index 56% rename from modules/src/ics26_routing/context.rs rename to modules/src/core/ics26_routing/context.rs index e94b11085..e01133c39 100644 --- a/modules/src/ics26_routing/context.rs +++ b/modules/src/core/ics26_routing/context.rs @@ -1,8 +1,8 @@ -use crate::application::ics20_fungible_token_transfer::context::Ics20Context; -use crate::ics02_client::context::{ClientKeeper, ClientReader}; -use crate::ics03_connection::context::{ConnectionKeeper, ConnectionReader}; -use crate::ics04_channel::context::{ChannelKeeper, ChannelReader}; -use crate::ics05_port::context::PortReader; +use crate::applications::ics20_fungible_token_transfer::context::Ics20Context; +use crate::core::ics02_client::context::{ClientKeeper, ClientReader}; +use crate::core::ics03_connection::context::{ConnectionKeeper, ConnectionReader}; +use crate::core::ics04_channel::context::{ChannelKeeper, ChannelReader}; +use crate::core::ics05_port::context::PortReader; /// This trait captures all the functional dependencies (i.e., context) which the ICS26 module /// requires to be able to dispatch and process IBC messages. In other words, this is the @@ -16,6 +16,5 @@ pub trait Ics26Context: + ChannelReader + PortReader + Ics20Context - + Clone { } diff --git a/modules/src/ics26_routing/error.rs b/modules/src/core/ics26_routing/error.rs similarity index 85% rename from modules/src/ics26_routing/error.rs rename to modules/src/core/ics26_routing/error.rs index 8413a62b9..2c4af31ae 100644 --- a/modules/src/ics26_routing/error.rs +++ b/modules/src/core/ics26_routing/error.rs @@ -1,10 +1,10 @@ use crate::prelude::*; use flex_error::{define_error, TraceError}; -use crate::application::ics20_fungible_token_transfer; -use crate::ics02_client; -use crate::ics03_connection; -use crate::ics04_channel; +use crate::applications::ics20_fungible_token_transfer; +use crate::core::ics02_client; +use crate::core::ics03_connection; +use crate::core::ics04_channel; define_error! { #[derive(Debug, PartialEq, Eq)] diff --git a/modules/src/ics26_routing/handler.rs b/modules/src/core/ics26_routing/handler.rs similarity index 88% rename from modules/src/ics26_routing/handler.rs rename to modules/src/core/ics26_routing/handler.rs index 1990f55e0..7c1395828 100644 --- a/modules/src/ics26_routing/handler.rs +++ b/modules/src/core/ics26_routing/handler.rs @@ -1,22 +1,15 @@ -use crate::ics04_channel::handler::recv_packet::RecvPacketResult; -use crate::ics04_channel::msgs::acknowledgement::MsgAcknowledgement; -use crate::ics04_channel::msgs::recv_packet::MsgRecvPacket; -use crate::ics04_channel::msgs::PacketMsg; -use crate::ics04_channel::packet::PacketResult; use crate::prelude::*; -use core::convert::TryInto; + use prost_types::Any; -use crate::application::ics20_fungible_token_transfer::relay_application_logic::send_transfer::send_transfer as ics20_msg_dispatcher; -use crate::ics02_client::handler::dispatch as ics2_msg_dispatcher; -use crate::ics03_connection::handler::dispatch as ics3_msg_dispatcher; -use crate::ics04_channel::handler::channel_dispatch as ics4_msg_dispatcher; -use crate::ics04_channel::handler::packet_dispatch as ics04_packet_msg_dispatcher; -pub use crate::ics04_channel::handler::write_acknowledgement; -use crate::ics04_channel::packet::Packet; -use crate::ics26_routing::context::Ics26Context; -use crate::ics26_routing::error::Error; -use crate::ics26_routing::msgs::Ics26Envelope::{ +use crate::applications::ics20_fungible_token_transfer::relay_application_logic::send_transfer::send_transfer as ics20_msg_dispatcher; +use crate::core::ics02_client::handler::dispatch as ics2_msg_dispatcher; +use crate::core::ics03_connection::handler::dispatch as ics3_msg_dispatcher; +use crate::core::ics04_channel::handler::channel_dispatch as ics4_msg_dispatcher; +use crate::core::ics04_channel::handler::packet_dispatch as ics04_packet_msg_dispatcher; +use crate::core::ics26_routing::context::Ics26Context; +use crate::core::ics26_routing::error::Error; +use crate::core::ics26_routing::msgs::Ics26Envelope::{ self, Ics20Msg, Ics2Msg, Ics3Msg, Ics4ChannelMsg, Ics4PacketMsg, }; use crate::{events::IbcEvent, handler::HandlerOutput}; @@ -28,9 +21,6 @@ pub fn deliver(ctx: &mut Ctx, messages: Vec) -> Result, where Ctx: Ics26Context, { - // Create a clone, which will store each intermediary stage of applying txs. - let mut ctx_interim = ctx.clone(); - // A buffer for all the events, to be used as return value. let mut res: Vec = Vec::new(); @@ -39,13 +29,12 @@ where let envelope = decode(any_msg)?; // Process the envelope, and accumulate any events that were generated. - let mut output = dispatch(&mut ctx_interim, envelope)?; + let mut output = dispatch(ctx, envelope)?; + // TODO: output.log and output.result are discarded res.append(&mut output.events); } - // No error has surfaced, so we now apply the changes permanently to the original context. - *ctx = ctx_interim; Ok(res) } @@ -135,28 +124,28 @@ where #[cfg(test)] mod tests { use crate::prelude::*; - use core::convert::TryFrom; - use test_env_log::test; + use test_log::test; + + use crate::core::ics02_client::client_consensus::AnyConsensusState; + use crate::core::ics02_client::client_state::AnyClientState; use crate::events::IbcEvent; - use crate::ics02_client::client_consensus::AnyConsensusState; - use crate::ics02_client::client_state::AnyClientState; use crate::{ - application::ics20_fungible_token_transfer::msgs::transfer::test_util::get_dummy_msg_transfer, - ics23_commitment::commitment::test_util::get_dummy_merkle_proof, + applications::ics20_fungible_token_transfer::msgs::transfer::test_util::get_dummy_msg_transfer, + core::ics23_commitment::commitment::test_util::get_dummy_merkle_proof, }; - use crate::ics02_client::msgs::{ + use crate::core::ics02_client::msgs::{ create_client::MsgCreateAnyClient, update_client::MsgUpdateAnyClient, upgrade_client::MsgUpgradeAnyClient, ClientMsg, }; - use crate::ics03_connection::msgs::{ + use crate::core::ics03_connection::msgs::{ conn_open_ack::{test_util::get_dummy_raw_msg_conn_open_ack, MsgConnectionOpenAck}, conn_open_init::{test_util::get_dummy_raw_msg_conn_open_init, MsgConnectionOpenInit}, conn_open_try::{test_util::get_dummy_raw_msg_conn_open_try, MsgConnectionOpenTry}, ConnectionMsg, }; - use crate::ics04_channel::msgs::{ + use crate::core::ics04_channel::msgs::{ chan_close_confirm::{ test_util::get_dummy_raw_msg_chan_close_confirm, MsgChannelCloseConfirm, }, @@ -169,13 +158,14 @@ mod tests { ChannelMsg, PacketMsg, }; - use crate::ics24_host::identifier::ConnectionId; - use crate::ics26_routing::handler::dispatch; - use crate::ics26_routing::msgs::Ics26Envelope; + use crate::core::ics24_host::identifier::ConnectionId; + use crate::core::ics26_routing::handler::dispatch; + use crate::core::ics26_routing::msgs::Ics26Envelope; use crate::mock::client_state::{MockClientState, MockConsensusState}; use crate::mock::context::MockContext; use crate::mock::header::MockHeader; use crate::test_utils::get_dummy_account_id; + use crate::timestamp::Timestamp; use crate::Height; #[test] @@ -206,7 +196,7 @@ mod tests { let mut ctx = MockContext::default(); let create_client_msg = MsgCreateAnyClient::new( - AnyClientState::from(MockClientState(MockHeader::new(start_client_height))), + AnyClientState::from(MockClientState::new(MockHeader::new(start_client_height))), AnyConsensusState::Mock(MockConsensusState::new(MockHeader::new( start_client_height, ))), @@ -262,7 +252,6 @@ mod tests { .unwrap(); let msg_transfer = get_dummy_msg_transfer(35); - let msg_transfer_two = get_dummy_msg_transfer(36); let mut msg_to_on_close = @@ -286,7 +275,7 @@ mod tests { res ); - ctx.add_port(msg_chan_init.port_id().clone()); + ctx.add_port(msg_chan_init.port_id.clone()); // Figure out the ID of the client that was just created. let mut events = res.unwrap().events; @@ -306,7 +295,9 @@ mod tests { name: "Client update successful".to_string(), msg: Ics26Envelope::Ics2Msg(ClientMsg::UpdateClient(MsgUpdateAnyClient { client_id: client_id.clone(), - header: MockHeader::new(update_client_height).into(), + header: MockHeader::new(update_client_height) + .with_timestamp(Timestamp::now()) + .into(), signer: default_signer.clone(), })), want_pass: true, @@ -381,10 +372,12 @@ mod tests { // The client update is required in this test, because the proof associated with // msg_recv_packet has the same height as the packet TO height (see get_dummy_raw_msg_recv_packet) Test { - name: "Client update successful".to_string(), + name: "Client update successful #2".to_string(), msg: Ics26Envelope::Ics2Msg(ClientMsg::UpdateClient(MsgUpdateAnyClient { client_id: client_id.clone(), - header: MockHeader::new(update_client_height_after_send).into(), + header: MockHeader::new(update_client_height_after_send) + .with_timestamp(Timestamp::now()) + .into(), signer: default_signer.clone(), })), want_pass: true, @@ -438,7 +431,9 @@ mod tests { name: "Client upgrade successful".to_string(), msg: Ics26Envelope::Ics2Msg(ClientMsg::UpgradeClient(MsgUpgradeAnyClient::new( client_id.clone(), - AnyClientState::Mock(MockClientState(MockHeader::new(upgrade_client_height))), + AnyClientState::Mock(MockClientState::new(MockHeader::new( + upgrade_client_height, + ))), AnyConsensusState::Mock(MockConsensusState::new(MockHeader::new( upgrade_client_height, ))), @@ -452,7 +447,7 @@ mod tests { name: "Client upgrade un-successful".to_string(), msg: Ics26Envelope::Ics2Msg(ClientMsg::UpgradeClient(MsgUpgradeAnyClient::new( client_id, - AnyClientState::Mock(MockClientState(MockHeader::new( + AnyClientState::Mock(MockClientState::new(MockHeader::new( upgrade_client_height_second, ))), AnyConsensusState::Mock(MockConsensusState::new(MockHeader::new( diff --git a/modules/src/core/ics26_routing/mod.rs b/modules/src/core/ics26_routing/mod.rs new file mode 100644 index 000000000..79e5a5ff2 --- /dev/null +++ b/modules/src/core/ics26_routing/mod.rs @@ -0,0 +1,7 @@ +//! ICS 26: Routing module keeps a lookup table of modules for looking +//! the appropriate module to relay to when a packet is received. + +pub mod context; +pub mod error; +pub mod handler; +pub mod msgs; diff --git a/modules/src/ics26_routing/msgs.rs b/modules/src/core/ics26_routing/msgs.rs similarity index 95% rename from modules/src/ics26_routing/msgs.rs rename to modules/src/core/ics26_routing/msgs.rs index ad49e989b..37b512c71 100644 --- a/modules/src/ics26_routing/msgs.rs +++ b/modules/src/core/ics26_routing/msgs.rs @@ -1,19 +1,18 @@ use crate::prelude::*; -use core::convert::TryFrom; + use prost_types::Any; -use crate::application::ics20_fungible_token_transfer::msgs::{transfer, transfer::MsgTransfer}; -use crate::ics02_client::msgs::{ - create_client, misbehavior, update_client, upgrade_client, ClientMsg, -}; -use crate::ics03_connection::msgs::{ + +use crate::applications::ics20_fungible_token_transfer::msgs::{transfer, transfer::MsgTransfer}; +use crate::core::ics02_client::msgs::{create_client, update_client, upgrade_client, misbehavior, ClientMsg}; +use crate::core::ics03_connection::msgs::{ conn_open_ack, conn_open_confirm, conn_open_init, conn_open_try, ConnectionMsg, }; -use crate::ics04_channel::msgs::{ +use crate::core::ics04_channel::msgs::{ acknowledgement, chan_close_confirm, chan_close_init, chan_open_ack, chan_open_confirm, chan_open_init, chan_open_try, recv_packet, timeout, timeout_on_close, ChannelMsg, PacketMsg, }; -use crate::ics26_routing::error::Error; +use crate::core::ics26_routing::error::Error; use tendermint_proto::Protobuf; /// Enumeration of all messages that the local ICS26 module is capable of routing. diff --git a/modules/src/core/mod.rs b/modules/src/core/mod.rs new file mode 100644 index 000000000..ef9cc9468 --- /dev/null +++ b/modules/src/core/mod.rs @@ -0,0 +1,10 @@ +//! The designs and logic pertaining to the transport, authentication, and +//! ordering layers of the IBC protocol. + +pub mod ics02_client; +pub mod ics03_connection; +pub mod ics04_channel; +pub mod ics05_port; +pub mod ics23_commitment; +pub mod ics24_host; +pub mod ics26_routing; diff --git a/modules/src/events.rs b/modules/src/events.rs index 3ca4581e2..442be3e60 100644 --- a/modules/src/events.rs +++ b/modules/src/events.rs @@ -1,19 +1,24 @@ use crate::prelude::*; +use alloc::collections::btree_map::BTreeMap as HashMap; +use core::convert::{TryFrom, TryInto}; use core::fmt; -use flex_error::{define_error, DisplayOnly}; +use core::str::FromStr; +use flex_error::{define_error, TraceError}; use prost::alloc::fmt::Formatter; use serde_derive::{Deserialize, Serialize}; +use tendermint::abci::Event as AbciEvent; -use crate::ics02_client::error as client_error; -use crate::ics02_client::events as ClientEvents; -use crate::ics02_client::events::NewBlock; -use crate::ics02_client::height::HeightError; -use crate::ics03_connection::events as ConnectionEvents; -use crate::ics03_connection::events::Attributes as ConnectionAttributes; -use crate::ics04_channel::error as channel_error; -use crate::ics04_channel::events as ChannelEvents; -use crate::ics04_channel::events::Attributes as ChannelAttributes; -use crate::ics24_host::error::ValidationError; +use crate::core::ics02_client::error as client_error; +use crate::core::ics02_client::events as ClientEvents; +use crate::core::ics02_client::events::NewBlock; +use crate::core::ics02_client::height::HeightError; +use crate::core::ics03_connection::events as ConnectionEvents; +use crate::core::ics03_connection::events::Attributes as ConnectionAttributes; +use crate::core::ics04_channel::error as channel_error; +use crate::core::ics04_channel::events as ChannelEvents; +use crate::core::ics04_channel::events::Attributes as ChannelAttributes; +use crate::core::ics04_channel::packet::Packet; +use crate::core::ics24_host::error::ValidationError; use crate::timestamp::ParseTimestampError; use crate::Height; @@ -44,47 +49,164 @@ define_error! { | e | { format_args!("missing event key {}", e.key) }, Decode - [ DisplayOnly ] + [ TraceError ] | _ | { "error decoding protobuf" }, SubtleEncoding - [ DisplayOnly ] + [ TraceError ] | _ | { "error decoding hex" }, MissingActionString - | _ | { "Missing action string" }, + | _ | { "missing action string" }, IncorrectEventType { event: String } - | e | { - format_args!("Incorrect Event Type {}", - e.event) - }, + | e | { format_args!("incorrect event type: {}", e.event) }, } } +/// Events whose data is not included in the app state and must be extracted using tendermint RPCs +/// (i.e. /tx_search or /block_search) +#[derive(Debug, Clone, Deserialize, Serialize)] +pub enum WithBlockDataType { + CreateClient, + UpdateClient, + SendPacket, + WriteAck, +} + +impl WithBlockDataType { + pub fn as_str(&self) -> &'static str { + match *self { + WithBlockDataType::CreateClient => "create_client", + WithBlockDataType::UpdateClient => "update_client", + WithBlockDataType::SendPacket => "send_packet", + WithBlockDataType::WriteAck => "write_acknowledgement", + } + } +} + +const NEW_BLOCK_EVENT: &str = "new_block"; +const EMPTY_EVENT: &str = "empty"; +const CHAIN_ERROR_EVENT: &str = "chain_error"; +/// Client event types +const CREATE_CLIENT_EVENT: &str = "create_client"; +const UPDATE_CLIENT_EVENT: &str = "update_client"; +const CLIENT_MISBEHAVIOUR_EVENT: &str = "client_misbehaviour"; +const UPGRADE_CLIENT_EVENT: &str = "upgrade_client"; +/// Connection event types +const CONNECTION_INIT_EVENT: &str = "connection_open_init"; +const CONNECTION_TRY_EVENT: &str = "connection_open_try"; +const CONNECTION_ACK_EVENT: &str = "connection_open_ack"; +const CONNECTION_CONFIRM_EVENT: &str = "connection_open_confirm"; +/// Channel event types +const CHANNEL_OPEN_INIT_EVENT: &str = "channel_open_init"; +const CHANNEL_OPEN_TRY_EVENT: &str = "channel_open_try"; +const CHANNEL_OPEN_ACK_EVENT: &str = "channel_open_ack"; +const CHANNEL_OPEN_CONFIRM_EVENT: &str = "channel_open_confirm"; +const CHANNEL_CLOSE_INIT_EVENT: &str = "channel_close_init"; +const CHANNEL_CLOSE_CONFIRM_EVENT: &str = "channel_close_confirm"; +/// Packet event types +const SEND_PACKET_EVENT: &str = "send_packet"; +const RECEIVE_PACKET_EVENT: &str = "receive_packet"; +const WRITE_ACK_EVENT: &str = "write_acknowledgement"; +const ACK_PACKET_EVENT: &str = "acknowledge_packet"; +const TIMEOUT_EVENT: &str = "timeout_packet"; +const TIMEOUT_ON_CLOSE_EVENT: &str = "timeout_packet_on_close"; + /// Events types #[derive(Debug, Clone, Deserialize, Serialize)] pub enum IbcEventType { + NewBlock, CreateClient, UpdateClient, + UpgradeClient, + ClientMisbehaviour, + OpenInitConnection, + OpenTryConnection, + OpenAckConnection, + OpenConfirmConnection, + OpenInitChannel, + OpenTryChannel, + OpenAckChannel, + OpenConfirmChannel, + CloseInitChannel, + CloseConfirmChannel, SendPacket, + ReceivePacket, WriteAck, + AckPacket, + Timeout, + TimeoutOnClose, + Empty, + ChainError, } impl IbcEventType { pub fn as_str(&self) -> &'static str { match *self { - IbcEventType::CreateClient => "create_client", - IbcEventType::UpdateClient => "update_client", - IbcEventType::SendPacket => "send_packet", - IbcEventType::WriteAck => "write_acknowledgement", + IbcEventType::NewBlock => NEW_BLOCK_EVENT, + IbcEventType::CreateClient => CREATE_CLIENT_EVENT, + IbcEventType::UpdateClient => UPDATE_CLIENT_EVENT, + IbcEventType::UpgradeClient => UPGRADE_CLIENT_EVENT, + IbcEventType::ClientMisbehaviour => CLIENT_MISBEHAVIOUR_EVENT, + IbcEventType::OpenInitConnection => CONNECTION_INIT_EVENT, + IbcEventType::OpenTryConnection => CONNECTION_TRY_EVENT, + IbcEventType::OpenAckConnection => CONNECTION_ACK_EVENT, + IbcEventType::OpenConfirmConnection => CONNECTION_CONFIRM_EVENT, + IbcEventType::OpenInitChannel => CHANNEL_OPEN_INIT_EVENT, + IbcEventType::OpenTryChannel => CHANNEL_OPEN_TRY_EVENT, + IbcEventType::OpenAckChannel => CHANNEL_OPEN_ACK_EVENT, + IbcEventType::OpenConfirmChannel => CHANNEL_OPEN_CONFIRM_EVENT, + IbcEventType::CloseInitChannel => CHANNEL_CLOSE_INIT_EVENT, + IbcEventType::CloseConfirmChannel => CHANNEL_CLOSE_CONFIRM_EVENT, + IbcEventType::SendPacket => SEND_PACKET_EVENT, + IbcEventType::ReceivePacket => RECEIVE_PACKET_EVENT, + IbcEventType::WriteAck => WRITE_ACK_EVENT, + IbcEventType::AckPacket => ACK_PACKET_EVENT, + IbcEventType::Timeout => TIMEOUT_EVENT, + IbcEventType::TimeoutOnClose => TIMEOUT_ON_CLOSE_EVENT, + IbcEventType::Empty => EMPTY_EVENT, + IbcEventType::ChainError => CHAIN_ERROR_EVENT, + } + } +} + +impl FromStr for IbcEventType { + type Err = Error; + + fn from_str(s: &str) -> Result { + match s { + NEW_BLOCK_EVENT => Ok(IbcEventType::NewBlock), + CREATE_CLIENT_EVENT => Ok(IbcEventType::CreateClient), + UPDATE_CLIENT_EVENT => Ok(IbcEventType::UpdateClient), + UPGRADE_CLIENT_EVENT => Ok(IbcEventType::UpgradeClient), + CLIENT_MISBEHAVIOUR_EVENT => Ok(IbcEventType::ClientMisbehaviour), + CONNECTION_INIT_EVENT => Ok(IbcEventType::OpenInitConnection), + CONNECTION_TRY_EVENT => Ok(IbcEventType::OpenTryConnection), + CONNECTION_ACK_EVENT => Ok(IbcEventType::OpenAckConnection), + CONNECTION_CONFIRM_EVENT => Ok(IbcEventType::OpenConfirmConnection), + CHANNEL_OPEN_INIT_EVENT => Ok(IbcEventType::OpenInitChannel), + CHANNEL_OPEN_TRY_EVENT => Ok(IbcEventType::OpenTryChannel), + CHANNEL_OPEN_ACK_EVENT => Ok(IbcEventType::OpenAckChannel), + CHANNEL_OPEN_CONFIRM_EVENT => Ok(IbcEventType::OpenConfirmChannel), + CHANNEL_CLOSE_INIT_EVENT => Ok(IbcEventType::CloseInitChannel), + CHANNEL_CLOSE_CONFIRM_EVENT => Ok(IbcEventType::CloseConfirmChannel), + SEND_PACKET_EVENT => Ok(IbcEventType::SendPacket), + RECEIVE_PACKET_EVENT => Ok(IbcEventType::ReceivePacket), + WRITE_ACK_EVENT => Ok(IbcEventType::WriteAck), + ACK_PACKET_EVENT => Ok(IbcEventType::AckPacket), + TIMEOUT_EVENT => Ok(IbcEventType::Timeout), + TIMEOUT_ON_CLOSE_EVENT => Ok(IbcEventType::TimeoutOnClose), + EMPTY_EVENT => Ok(IbcEventType::Empty), + CHAIN_ERROR_EVENT => Ok(IbcEventType::ChainError), + _ => Err(Error::incorrect_event_type(s.to_string())), } } } /// Events created by the IBC component of a chain, destined for a relayer. -#[derive(Debug, Clone, Deserialize, Serialize)] +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] pub enum IbcEvent { NewBlock(NewBlock), @@ -116,6 +238,12 @@ pub enum IbcEvent { ChainError(String), // Special event, signifying an error on CheckTx or DeliverTx } +impl Default for IbcEvent { + fn default() -> Self { + Self::Empty("".to_string()) + } +} + /// For use in debug messages pub struct PrettyEvents<'a>(pub &'a [IbcEvent]); impl<'a> fmt::Display for PrettyEvents<'a> { @@ -163,6 +291,34 @@ impl fmt::Display for IbcEvent { } } +impl TryFrom for AbciEvent { + type Error = Error; + + fn try_from(event: IbcEvent) -> Result { + Ok(match event { + IbcEvent::CreateClient(event) => event.into(), + IbcEvent::UpdateClient(event) => event.into(), + IbcEvent::UpgradeClient(event) => event.into(), + IbcEvent::ClientMisbehaviour(event) => event.into(), + IbcEvent::OpenInitConnection(event) => event.into(), + IbcEvent::OpenTryConnection(event) => event.into(), + IbcEvent::OpenAckConnection(event) => event.into(), + IbcEvent::OpenConfirmConnection(event) => event.into(), + IbcEvent::OpenInitChannel(event) => event.into(), + IbcEvent::OpenTryChannel(event) => event.into(), + IbcEvent::OpenAckChannel(event) => event.into(), + IbcEvent::OpenConfirmChannel(event) => event.into(), + IbcEvent::CloseInitChannel(event) => event.into(), + IbcEvent::CloseConfirmChannel(event) => event.into(), + IbcEvent::SendPacket(event) => event.try_into().map_err(Error::channel)?, + IbcEvent::WriteAcknowledgement(event) => event.try_into().map_err(Error::channel)?, + IbcEvent::AcknowledgePacket(event) => event.try_into().map_err(Error::channel)?, + IbcEvent::TimeoutPacket(event) => event.try_into().map_err(Error::channel)?, + _ => return Err(Error::incorrect_event_type(event.to_string())), + }) + } +} + // This is tendermint specific pub fn from_tx_response_event(height: Height, event: &tendermint::abci::Event) -> Option { // Return the first hit we find @@ -239,6 +395,34 @@ impl IbcEvent { } } + pub fn event_type(&self) -> IbcEventType { + match self { + IbcEvent::NewBlock(_) => IbcEventType::NewBlock, + IbcEvent::CreateClient(_) => IbcEventType::CreateClient, + IbcEvent::UpdateClient(_) => IbcEventType::UpdateClient, + IbcEvent::ClientMisbehaviour(_) => IbcEventType::ClientMisbehaviour, + IbcEvent::UpgradeClient(_) => IbcEventType::UpgradeClient, + IbcEvent::OpenInitConnection(_) => IbcEventType::OpenInitConnection, + IbcEvent::OpenTryConnection(_) => IbcEventType::OpenTryConnection, + IbcEvent::OpenAckConnection(_) => IbcEventType::OpenAckConnection, + IbcEvent::OpenConfirmConnection(_) => IbcEventType::OpenConfirmConnection, + IbcEvent::OpenInitChannel(_) => IbcEventType::OpenInitChannel, + IbcEvent::OpenTryChannel(_) => IbcEventType::OpenTryChannel, + IbcEvent::OpenAckChannel(_) => IbcEventType::OpenAckChannel, + IbcEvent::OpenConfirmChannel(_) => IbcEventType::OpenConfirmChannel, + IbcEvent::CloseInitChannel(_) => IbcEventType::CloseInitChannel, + IbcEvent::CloseConfirmChannel(_) => IbcEventType::CloseConfirmChannel, + IbcEvent::SendPacket(_) => IbcEventType::SendPacket, + IbcEvent::ReceivePacket(_) => IbcEventType::ReceivePacket, + IbcEvent::WriteAcknowledgement(_) => IbcEventType::WriteAck, + IbcEvent::AcknowledgePacket(_) => IbcEventType::AckPacket, + IbcEvent::TimeoutPacket(_) => IbcEventType::Timeout, + IbcEvent::TimeoutOnClosePacket(_) => IbcEventType::TimeoutOnClose, + IbcEvent::Empty(_) => IbcEventType::Empty, + IbcEvent::ChainError(_) => IbcEventType::ChainError, + } + } + pub fn channel_attributes(&self) -> Option<&ChannelAttributes> { match self { IbcEvent::OpenInitChannel(ev) => Some(ev.attributes()), @@ -248,6 +432,7 @@ impl IbcEvent { _ => None, } } + pub fn connection_attributes(&self) -> Option<&ConnectionAttributes> { match self { IbcEvent::OpenInitConnection(ev) => Some(ev.attributes()), @@ -257,4 +442,74 @@ impl IbcEvent { _ => None, } } + + pub fn packet(&self) -> Option<&Packet> { + match self { + IbcEvent::SendPacket(ev) => Some(&ev.packet), + IbcEvent::ReceivePacket(ev) => Some(&ev.packet), + IbcEvent::WriteAcknowledgement(ev) => Some(&ev.packet), + IbcEvent::AcknowledgePacket(ev) => Some(&ev.packet), + IbcEvent::TimeoutPacket(ev) => Some(&ev.packet), + IbcEvent::TimeoutOnClosePacket(ev) => Some(&ev.packet), + _ => None, + } + } + + pub fn ack(&self) -> Option<&[u8]> { + match self { + IbcEvent::WriteAcknowledgement(ev) => Some(&ev.ack), + _ => None, + } + } +} + +#[derive(Debug, Clone, Serialize)] +pub struct RawObject<'a> { + pub height: Height, + pub action: String, + pub idx: usize, + pub events: &'a HashMap>, +} + +impl<'a> RawObject<'a> { + pub fn new( + height: Height, + action: String, + idx: usize, + events: &'a HashMap>, + ) -> RawObject<'a> { + RawObject { + height, + action, + idx, + events, + } + } +} + +pub fn extract_events( + events: &HashMap>, + action_string: &str, +) -> Result<(), Error> { + if let Some(message_action) = events.get("message.action") { + if message_action.contains(&action_string.to_owned()) { + return Ok(()); + } + return Err(Error::missing_action_string()); + } + Err(Error::incorrect_event_type(action_string.to_string())) +} + +pub fn extract_attribute(object: &RawObject<'_>, key: &str) -> Result { + let value = object + .events + .get(key) + .ok_or_else(|| Error::missing_key(key.to_string()))?[object.idx] + .clone(); + + Ok(value) +} + +pub fn maybe_extract_attribute(object: &RawObject<'_>, key: &str) -> Option { + object.events.get(key).map(|tags| tags[object.idx].clone()) } diff --git a/modules/src/ics02_client/context.rs b/modules/src/ics02_client/context.rs deleted file mode 100644 index a64c3a60c..000000000 --- a/modules/src/ics02_client/context.rs +++ /dev/null @@ -1,101 +0,0 @@ -//! ICS2 (client) context. The two traits `ClientReader` and `ClientKeeper` define the interface -//! that any host chain must implement to be able to process any `ClientMsg`. See -//! "ADR 003: IBC protocol implementation" for more details. - -use crate::ics02_client::client_consensus::AnyConsensusState; -use crate::ics02_client::client_state::AnyClientState; -use crate::ics02_client::client_type::ClientType; -use crate::ics02_client::error::Error; -use crate::ics02_client::handler::ClientResult::{self, Create, Misbehaviour, Update, Upgrade}; -use crate::ics24_host::identifier::ClientId; -use crate::Height; - -/// Defines the read-only part of ICS2 (client functions) context. -pub trait ClientReader { - fn client_type(&self, client_id: &ClientId) -> Result; - fn client_state(&self, client_id: &ClientId) -> Result; - fn consensus_state( - &self, - client_id: &ClientId, - height: Height, - ) -> Result; - - /// Returns a natural number, counting how many clients have been created thus far. - /// The value of this counter should increase only via method `ClientKeeper::increase_client_counter`. - fn client_counter(&self) -> Result; -} - -/// Defines the write-only part of ICS2 (client functions) context. -pub trait ClientKeeper { - fn store_client_result(&mut self, handler_res: ClientResult) -> Result<(), Error> { - match handler_res { - Create(res) => { - let client_id = res.client_id.clone(); - - self.store_client_type(client_id.clone(), res.client_type)?; - self.store_client_state(client_id.clone(), res.client_state.clone())?; - self.store_consensus_state( - client_id, - res.client_state.latest_height(), - res.consensus_state, - )?; - self.increase_client_counter(); - Ok(()) - } - Update(res) => { - self.store_client_state(res.client_id.clone(), res.client_state.clone())?; - self.store_consensus_state( - res.client_id.clone(), - res.client_state.latest_height(), - res.consensus_state, - )?; - Ok(()) - } - Upgrade(res) => { - self.store_client_state(res.client_id.clone(), res.client_state.clone())?; - self.store_consensus_state( - res.client_id.clone(), - res.client_state.latest_height(), - res.consensus_state, - )?; - Ok(()) - } - Misbehaviour(res) => { - self.store_client_state(res.client_id.clone(), res.client_state.clone())?; - self.store_consensus_state( - res.client_id.clone(), - res.client_state.latest_height(), - res.consensus_state, - )?; - Ok(()) - } - } - } - - /// Called upon successful client creation - fn store_client_type( - &mut self, - client_id: ClientId, - client_type: ClientType, - ) -> Result<(), Error>; - - /// Called upon successful client creation and update - fn store_client_state( - &mut self, - client_id: ClientId, - client_state: AnyClientState, - ) -> Result<(), Error>; - - /// Called upon successful client creation and update - fn store_consensus_state( - &mut self, - client_id: ClientId, - height: Height, - consensus_state: AnyConsensusState, - ) -> Result<(), Error>; - - /// Called upon client creation. - /// Increases the counter which keeps track of how many clients have been created. - /// Should never fail. - fn increase_client_counter(&mut self); -} diff --git a/modules/src/ics02_client/events.rs b/modules/src/ics02_client/events.rs deleted file mode 100644 index c8bb720fb..000000000 --- a/modules/src/ics02_client/events.rs +++ /dev/null @@ -1,272 +0,0 @@ -//! Types for the IBC events emitted from Tendermint Websocket by the client module. -use serde_derive::{Deserialize, Serialize}; -use subtle_encoding::hex; -use tendermint_proto::Protobuf; - -use crate::events::IbcEvent; -use crate::ics02_client::client_type::ClientType; -use crate::ics02_client::header::AnyHeader; -use crate::ics02_client::height::Height; -use crate::ics24_host::identifier::ClientId; - -/// The content of the `type` field for the event that a chain produces upon executing the create client transaction. -const CREATE_EVENT_TYPE: &str = "create_client"; -const UPDATE_EVENT_TYPE: &str = "update_client"; -const MISBEHAVIOUR_EVENT_TYPE: &str = "client_misbehaviour"; -const UPGRADE_EVENT_TYPE: &str = "upgrade_client"; - -/// The content of the `key` field for the attribute containing the client identifier. -const CLIENT_ID_ATTRIBUTE_KEY: &str = "client_id"; - -/// The content of the `key` field for the attribute containing the client type. -const CLIENT_TYPE_ATTRIBUTE_KEY: &str = "client_type"; - -/// The content of the `key` field for the attribute containing the height. -const CONSENSUS_HEIGHT_ATTRIBUTE_KEY: &str = "consensus_height"; - -/// The content of the `key` field for the header in update client event. -const HEADER: &str = "header"; - -pub fn try_from_tx(event: &tendermint::abci::Event) -> Option { - match event.type_str.as_ref() { - CREATE_EVENT_TYPE => Some(IbcEvent::CreateClient(CreateClient( - extract_attributes_from_tx(event), - ))), - UPDATE_EVENT_TYPE => Some(IbcEvent::UpdateClient(UpdateClient { - common: extract_attributes_from_tx(event), - header: extract_header_from_tx(event), - })), - MISBEHAVIOUR_EVENT_TYPE => Some(IbcEvent::ClientMisbehaviour(ClientMisbehaviour( - extract_attributes_from_tx(event), - ))), - UPGRADE_EVENT_TYPE => Some(IbcEvent::UpgradeClient(UpgradeClient( - extract_attributes_from_tx(event), - ))), - _ => None, - } -} - -fn extract_attributes_from_tx(event: &tendermint::abci::Event) -> Attributes { - let mut attr = Attributes::default(); - - for tag in &event.attributes { - let key = tag.key.as_ref(); - let value = tag.value.as_ref(); - match key { - CLIENT_ID_ATTRIBUTE_KEY => attr.client_id = value.parse().unwrap(), - CLIENT_TYPE_ATTRIBUTE_KEY => attr.client_type = value.parse().unwrap(), - CONSENSUS_HEIGHT_ATTRIBUTE_KEY => attr.consensus_height = value.parse().unwrap(), - // TODO: `Attributes` has 4 fields and we're only parsing 3 - _ => {} - } - } - - attr -} - -pub fn extract_header_from_tx(event: &tendermint::abci::Event) -> Option { - for tag in &event.attributes { - let key = tag.key.as_ref(); - let value = tag.value.as_ref(); - if let HEADER = key { - let header_bytes = hex::decode(value).unwrap(); - let result = match Protobuf::decode(header_bytes.as_ref()) { - Ok(header) => Some(header), - Err(e) => { - tracing::error!("error {} while decoding {:?}", e, header_bytes); - None - } - }; - return result; - } - } - None -} - -/// NewBlock event signals the committing & execution of a new block. -// TODO - find a better place for NewBlock -#[derive(Debug, Deserialize, Serialize, Clone, Copy)] -pub struct NewBlock { - pub height: Height, -} - -impl NewBlock { - pub fn new(h: Height) -> NewBlock { - NewBlock { height: h } - } - pub fn set_height(&mut self, height: Height) { - self.height = height; - } - pub fn height(&self) -> Height { - self.height - } -} - -impl From for IbcEvent { - fn from(v: NewBlock) -> Self { - IbcEvent::NewBlock(v) - } -} - -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Attributes { - pub height: Height, - pub client_id: ClientId, - pub client_type: ClientType, - pub consensus_height: Height, -} - -impl Default for Attributes { - fn default() -> Self { - Attributes { - height: Default::default(), - client_id: Default::default(), - client_type: ClientType::Tendermint, - consensus_height: Height::default(), - } - } -} - -impl core::fmt::Display for Attributes { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - write!( - f, - "h: {}, cs_h: {}({})", - self.height, self.client_id, self.consensus_height - ) - } -} - -/// CreateClient event signals the creation of a new on-chain client (IBC client). -#[derive(Debug, Deserialize, Serialize, Clone)] -pub struct CreateClient(pub Attributes); - -impl CreateClient { - pub fn new(attributes: Attributes) -> Self { - Self(attributes) - } - pub fn client_id(&self) -> &ClientId { - &self.0.client_id - } - pub fn height(&self) -> Height { - self.0.height - } - pub fn set_height(&mut self, height: Height) { - self.0.height = height; - } -} - -impl From for CreateClient { - fn from(attrs: Attributes) -> Self { - CreateClient(attrs) - } -} - -impl From for IbcEvent { - fn from(v: CreateClient) -> Self { - IbcEvent::CreateClient(v) - } -} - -impl core::fmt::Display for CreateClient { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - write!(f, "{}", self.0) - } -} - -/// UpdateClient event signals a recent update of an on-chain client (IBC Client). -#[derive(Debug, Deserialize, Serialize, Clone)] -pub struct UpdateClient { - pub common: Attributes, - pub header: Option, -} - -impl UpdateClient { - pub fn client_id(&self) -> &ClientId { - &self.common.client_id - } - pub fn client_type(&self) -> ClientType { - self.common.client_type - } - - pub fn height(&self) -> Height { - self.common.height - } - - pub fn set_height(&mut self, height: Height) { - self.common.height = height; - } - - pub fn consensus_height(&self) -> Height { - self.common.consensus_height - } -} - -impl From for UpdateClient { - fn from(attrs: Attributes) -> Self { - UpdateClient { - common: attrs, - header: None, - } - } -} - -impl From for IbcEvent { - fn from(v: UpdateClient) -> Self { - IbcEvent::UpdateClient(v) - } -} - -impl core::fmt::Display for UpdateClient { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - write!(f, "{}", self.common) - } -} - -/// ClientMisbehaviour event signals the update of an on-chain client (IBC Client) with evidence of -/// misbehaviour. -#[derive(Debug, Deserialize, Serialize, Clone)] -pub struct ClientMisbehaviour(pub Attributes); - -impl From for ClientMisbehaviour { - fn from(val: Attributes) -> Self { - Self(val) - } -} - -impl ClientMisbehaviour { - pub fn client_id(&self) -> &ClientId { - &self.0.client_id - } - pub fn height(&self) -> Height { - self.0.height - } - pub fn set_height(&mut self, height: Height) { - self.0.height = height; - } -} - -impl From for IbcEvent { - fn from(v: ClientMisbehaviour) -> Self { - IbcEvent::ClientMisbehaviour(v) - } -} - -/// Signals a recent upgrade of an on-chain client (IBC Client). -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)] -pub struct UpgradeClient(pub Attributes); - -impl UpgradeClient { - pub fn set_height(&mut self, height: Height) { - self.0.height = height; - } - pub fn client_id(&self) -> &ClientId { - &self.0.client_id - } -} - -impl From for UpgradeClient { - fn from(attrs: Attributes) -> Self { - UpgradeClient(attrs) - } -} diff --git a/modules/src/ics02_client/handler/update_client.rs b/modules/src/ics02_client/handler/update_client.rs deleted file mode 100644 index 5f4972729..000000000 --- a/modules/src/ics02_client/handler/update_client.rs +++ /dev/null @@ -1,230 +0,0 @@ -//! Protocol logic specific to processing ICS2 messages of type `MsgUpdateAnyClient`. - -use crate::events::IbcEvent; -use crate::handler::{HandlerOutput, HandlerResult}; -use crate::ics02_client::client_consensus::AnyConsensusState; -use crate::ics02_client::client_def::{AnyClient, ClientDef}; -use crate::ics02_client::client_state::AnyClientState; -use crate::ics02_client::context::ClientReader; -use crate::ics02_client::error::Error; -use crate::ics02_client::events::Attributes; -use crate::ics02_client::handler::ClientResult; -use crate::ics02_client::header::Header; -use crate::ics02_client::msgs::update_client::MsgUpdateAnyClient; -use crate::ics24_host::identifier::ClientId; -use crate::prelude::*; - -/// The result following the successful processing of a `MsgUpdateAnyClient` message. Preferably -/// this data type should be used with a qualified name `update_client::Result` to avoid ambiguity. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct Result { - pub client_id: ClientId, - pub client_state: AnyClientState, - pub consensus_state: AnyConsensusState, -} - -pub fn process( - ctx: &dyn ClientReader, - msg: MsgUpdateAnyClient, -) -> HandlerResult { - let mut output = HandlerOutput::builder(); - - let MsgUpdateAnyClient { - client_id, - header, - signer: _, - } = msg; - - tracing::info!("in ics02_client: [update_client] >> Header: {:?}", header); - - // Read client type from the host chain store. The client should already exist. - let client_type = ctx.client_type(&client_id)?; - - let client_def = AnyClient::from_client_type(client_type); - - // Read client state from the host chain store. - let client_state = ctx.client_state(&client_id)?; - - let latest_height = client_state.latest_height(); - let consensus_state = ctx.consensus_state(&client_id, latest_height)?; - tracing::info!( - "in ics02_client: [update_client] >> client_state = {:?}", - client_state - ); - tracing::info!( - "in ics02_client: [update_client] >> consensus_state = {:?}", - consensus_state - ); - - // Use client_state to validate the new header against the latest consensus_state. - // This function will return the new client_state (its latest_height changed) and a - // consensus_state obtained from header. These will be later persisted by the keeper. - let (new_client_state, new_consensus_state) = client_def - .check_header_and_update_state(client_state, header.clone()) - .map_err(|e| Error::header_verification_failure(e.to_string()))?; - - tracing::info!( - "in ics02_client: [update_client] >> new_client_state = {:?}, new_consensus_state = {:?}", - new_client_state, - new_consensus_state - ); - - let result = ClientResult::Update(Result { - client_id: client_id.clone(), - client_state: new_client_state, - consensus_state: new_consensus_state, - }); - tracing::info!("in ics02_client: [update_client] >> result : {:?}", result); - - // TODO have ibc-rs informal have some different - let event_attributes = Attributes { - height: header.clone().height(), - client_id, - client_type: header.client_type().clone(), - consensus_height: header.clone().height(), - ..Default::default() - }; - output.emit(IbcEvent::UpdateClient(event_attributes.into())); - - Ok(output.with_result(result)) -} - -#[cfg(test)] -mod tests { - use core::str::FromStr; - use test_env_log::test; - - use crate::events::IbcEvent; - use crate::handler::HandlerOutput; - use crate::ics02_client::client_state::AnyClientState; - use crate::ics02_client::error::{Error, ErrorDetail}; - use crate::ics02_client::handler::dispatch; - use crate::ics02_client::handler::ClientResult::Update; - use crate::ics02_client::header::Header; - use crate::ics02_client::msgs::update_client::MsgUpdateAnyClient; - use crate::ics02_client::msgs::ClientMsg; - use crate::ics24_host::identifier::ClientId; - use crate::mock::client_state::MockClientState; - use crate::mock::context::MockContext; - use crate::mock::header::MockHeader; - use crate::prelude::*; - use crate::test_utils::get_dummy_account_id; - use crate::Height; - - #[test] - fn test_update_client_ok() { - let client_id = ClientId::default(); - let signer = get_dummy_account_id(); - - let ctx = MockContext::default().with_client(&client_id, Height::new(0, 42)); - let msg = MsgUpdateAnyClient { - client_id: client_id.clone(), - header: MockHeader::new(Height::new(0, 46)).into(), - signer, - }; - - let output = dispatch(&ctx, ClientMsg::UpdateClient(msg.clone())); - - match output { - Ok(HandlerOutput { - result, - mut events, - log, - }) => { - assert_eq!(events.len(), 1); - let event = events.pop().unwrap(); - assert!( - matches!(event, IbcEvent::UpdateClient(e) if e.client_id() == &msg.client_id) - ); - assert!(log.is_empty()); - // Check the result - match result { - Update(upd_res) => { - assert_eq!(upd_res.client_id, client_id); - assert_eq!( - upd_res.client_state, - AnyClientState::Mock(MockClientState(MockHeader::new( - msg.header.height() - ))) - ) - } - _ => panic!("update handler result has incorrect type"), - } - } - Err(err) => { - panic!("unexpected error: {}", err); - } - } - } - - #[test] - fn test_update_nonexisting_client() { - let client_id = ClientId::from_str("mockclient1").unwrap(); - let signer = get_dummy_account_id(); - - let ctx = MockContext::default().with_client(&client_id, Height::new(0, 42)); - - let msg = MsgUpdateAnyClient { - client_id: ClientId::from_str("nonexistingclient").unwrap(), - header: MockHeader::new(Height::new(0, 46)).into(), - signer, - }; - - let output = dispatch(&ctx, ClientMsg::UpdateClient(msg.clone())); - - match output { - Err(Error(ErrorDetail::ClientNotFound(e), _)) => { - assert_eq!(e.client_id, msg.client_id); - } - _ => { - panic!("expected ClientNotFound error, instead got {:?}", output) - } - } - } - - #[test] - fn test_update_client_ok_multiple() { - let client_ids = vec![ - ClientId::from_str("mockclient1").unwrap(), - ClientId::from_str("mockclient2").unwrap(), - ClientId::from_str("mockclient3").unwrap(), - ]; - let signer = get_dummy_account_id(); - let initial_height = Height::new(0, 45); - let update_height = Height::new(0, 49); - - let mut ctx = MockContext::default(); - - for cid in &client_ids { - ctx = ctx.with_client(cid, initial_height); - } - - for cid in &client_ids { - let msg = MsgUpdateAnyClient { - client_id: cid.clone(), - header: MockHeader::new(update_height).into(), - signer: signer.clone(), - }; - - let output = dispatch(&ctx, ClientMsg::UpdateClient(msg.clone())); - - match output { - Ok(HandlerOutput { - result: _, - mut events, - log, - }) => { - assert_eq!(events.len(), 1); - let event = events.pop().unwrap(); - assert!( - matches!(event, IbcEvent::UpdateClient(e) if e.client_id() == &msg.client_id) - ); - assert!(log.is_empty()); - } - Err(err) => { - panic!("unexpected error: {}", err); - } - } - } - } -} diff --git a/modules/src/ics03_connection/events.rs b/modules/src/ics03_connection/events.rs deleted file mode 100644 index f57278278..000000000 --- a/modules/src/ics03_connection/events.rs +++ /dev/null @@ -1,201 +0,0 @@ -//! Types for the IBC events emitted from Tendermint Websocket by the connection module. - -use serde_derive::{Deserialize, Serialize}; - -use crate::events::IbcEvent; -use crate::ics02_client::height::Height; -use crate::ics24_host::identifier::{ClientId, ConnectionId}; - -/// The content of the `type` field for the event that a chain produces upon executing a connection handshake transaction. -const INIT_EVENT_TYPE: &str = "connection_open_init"; -const TRY_EVENT_TYPE: &str = "connection_open_try"; -const ACK_EVENT_TYPE: &str = "connection_open_ack"; -const CONFIRM_EVENT_TYPE: &str = "connection_open_confirm"; - -/// The content of the `key` field for the attribute containing the connection identifier. -const CONN_ID_ATTRIBUTE_KEY: &str = "connection_id"; -const CLIENT_ID_ATTRIBUTE_KEY: &str = "client_id"; -const COUNTERPARTY_CONN_ID_ATTRIBUTE_KEY: &str = "counterparty_connection_id"; -const COUNTERPARTY_CLIENT_ID_ATTRIBUTE_KEY: &str = "counterparty_client_id"; - -pub fn try_from_tx(event: &tendermint::abci::Event) -> Option { - match event.type_str.as_ref() { - INIT_EVENT_TYPE => Some(IbcEvent::OpenInitConnection(OpenInit::from( - extract_attributes_from_tx(event), - ))), - TRY_EVENT_TYPE => Some(IbcEvent::OpenTryConnection(OpenTry::from( - extract_attributes_from_tx(event), - ))), - ACK_EVENT_TYPE => Some(IbcEvent::OpenAckConnection(OpenAck::from( - extract_attributes_from_tx(event), - ))), - CONFIRM_EVENT_TYPE => Some(IbcEvent::OpenConfirmConnection(OpenConfirm::from( - extract_attributes_from_tx(event), - ))), - _ => None, - } -} - -fn extract_attributes_from_tx(event: &tendermint::abci::Event) -> Attributes { - let mut attr = Attributes::default(); - - for tag in &event.attributes { - let key = tag.key.as_ref(); - let value = tag.value.as_ref(); - match key { - CONN_ID_ATTRIBUTE_KEY => attr.connection_id = value.parse().ok(), - CLIENT_ID_ATTRIBUTE_KEY => attr.client_id = value.parse().unwrap(), - COUNTERPARTY_CONN_ID_ATTRIBUTE_KEY => { - attr.counterparty_connection_id = value.parse().ok() - } - COUNTERPARTY_CLIENT_ID_ATTRIBUTE_KEY => { - attr.counterparty_client_id = value.parse().unwrap() - } - // TODO: `Attributes` has 5 fields and we're only parsing 4 - _ => {} - } - } - - attr -} - -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Attributes { - pub height: Height, - pub connection_id: Option, - pub client_id: ClientId, - pub counterparty_connection_id: Option, - pub counterparty_client_id: ClientId, -} - -impl Default for Attributes { - fn default() -> Self { - Attributes { - height: Default::default(), - connection_id: Default::default(), - client_id: Default::default(), - counterparty_connection_id: Default::default(), - counterparty_client_id: Default::default(), - } - } -} - -#[derive(Debug, Deserialize, Serialize, Clone)] -pub struct OpenInit(pub Attributes); - -impl OpenInit { - pub fn attributes(&self) -> &Attributes { - &self.0 - } - pub fn connection_id(&self) -> &Option { - &self.0.connection_id - } - pub fn height(&self) -> Height { - self.0.height - } - pub fn set_height(&mut self, height: Height) { - self.0.height = height; - } -} - -impl From for OpenInit { - fn from(attrs: Attributes) -> Self { - OpenInit(attrs) - } -} - -impl From for IbcEvent { - fn from(v: OpenInit) -> Self { - IbcEvent::OpenInitConnection(v) - } -} - -#[derive(Debug, Deserialize, Serialize, Clone)] -pub struct OpenTry(pub Attributes); - -impl OpenTry { - pub fn attributes(&self) -> &Attributes { - &self.0 - } - pub fn connection_id(&self) -> &Option { - &self.0.connection_id - } - pub fn height(&self) -> Height { - self.0.height - } - pub fn set_height(&mut self, height: Height) { - self.0.height = height; - } -} - -impl From for OpenTry { - fn from(attrs: Attributes) -> Self { - OpenTry(attrs) - } -} - -impl From for IbcEvent { - fn from(v: OpenTry) -> Self { - IbcEvent::OpenTryConnection(v) - } -} - -#[derive(Debug, Deserialize, Serialize, Clone)] -pub struct OpenAck(pub Attributes); - -impl OpenAck { - pub fn attributes(&self) -> &Attributes { - &self.0 - } - pub fn connection_id(&self) -> &Option { - &self.0.connection_id - } - pub fn height(&self) -> Height { - self.0.height - } - pub fn set_height(&mut self, height: Height) { - self.0.height = height; - } -} - -impl From for OpenAck { - fn from(attrs: Attributes) -> Self { - OpenAck(attrs) - } -} - -impl From for IbcEvent { - fn from(v: OpenAck) -> Self { - IbcEvent::OpenAckConnection(v) - } -} - -#[derive(Debug, Deserialize, Serialize, Clone)] -pub struct OpenConfirm(pub Attributes); - -impl OpenConfirm { - pub fn attributes(&self) -> &Attributes { - &self.0 - } - pub fn connection_id(&self) -> &Option { - &self.0.connection_id - } - pub fn height(&self) -> Height { - self.0.height - } - pub fn set_height(&mut self, height: Height) { - self.0.height = height; - } -} - -impl From for OpenConfirm { - fn from(attrs: Attributes) -> Self { - OpenConfirm(attrs) - } -} - -impl From for IbcEvent { - fn from(v: OpenConfirm) -> Self { - IbcEvent::OpenConfirmConnection(v) - } -} diff --git a/modules/src/ics04_channel/events.rs b/modules/src/ics04_channel/events.rs deleted file mode 100644 index 42b22c8d4..000000000 --- a/modules/src/ics04_channel/events.rs +++ /dev/null @@ -1,638 +0,0 @@ -//! Types for the IBC events emitted from Tendermint Websocket by the channels module. -use crate::events::IbcEvent; -use crate::ics02_client::height::Height; -use crate::ics04_channel::packet::Packet; -use crate::ics24_host::identifier::{ChannelId, ConnectionId, PortId}; -use crate::prelude::*; - -use serde_derive::{Deserialize, Serialize}; - -/// Channel event types -const OPEN_INIT_EVENT_TYPE: &str = "channel_open_init"; -const OPEN_TRY_EVENT_TYPE: &str = "channel_open_try"; -const OPEN_ACK_EVENT_TYPE: &str = "channel_open_ack"; -const OPEN_CONFIRM_EVENT_TYPE: &str = "channel_open_confirm"; -const CLOSE_INIT_EVENT_TYPE: &str = "channel_close_init"; -const CLOSE_CONFIRM_EVENT_TYPE: &str = "channel_close_confirm"; - -/// Channel event attribute keys -const CONNECTION_ID_ATTRIBUTE_KEY: &str = "connection_id"; -const CHANNEL_ID_ATTRIBUTE_KEY: &str = "channel_id"; -const PORT_ID_ATTRIBUTE_KEY: &str = "port_id"; -const COUNTERPARTY_CHANNEL_ID_ATTRIBUTE_KEY: &str = "counterparty_channel_id"; -const COUNTERPARTY_PORT_ID_ATTRIBUTE_KEY: &str = "counterparty_port_id"; - -/// Packet event types -const SEND_PACKET: &str = "send_packet"; -const WRITE_ACK: &str = "write_acknowledgement"; -const ACK_PACKET: &str = "acknowledge_packet"; -const TIMEOUT: &str = "timeout_packet"; - -/// Packet event attribute keys -const PKT_SEQ_ATTRIBUTE_KEY: &str = "packet_sequence"; -const PKT_DATA_ATTRIBUTE_KEY: &str = "packet_data"; -const PKT_SRC_PORT_ATTRIBUTE_KEY: &str = "packet_src_port"; -const PKT_SRC_CHANNEL_ATTRIBUTE_KEY: &str = "packet_src_channel"; -const PKT_DST_PORT_ATTRIBUTE_KEY: &str = "packet_dst_port"; -const PKT_DST_CHANNEL_ATTRIBUTE_KEY: &str = "packet_dst_channel"; -const PKT_TIMEOUT_HEIGHT_ATTRIBUTE_KEY: &str = "packet_timeout_height"; -const PKT_TIMEOUT_TIMESTAMP_ATTRIBUTE_KEY: &str = "packet_timeout_timestamp"; - -const PKT_ACK_ATTRIBUTE_KEY: &str = "packet_ack"; - -pub fn try_from_tx(event: &tendermint::abci::Event) -> Option { - match event.type_str.as_str() { - OPEN_INIT_EVENT_TYPE => Some(IbcEvent::OpenInitChannel(OpenInit::from( - extract_attributes_from_tx(event), - ))), - OPEN_TRY_EVENT_TYPE => Some(IbcEvent::OpenTryChannel(OpenTry::from( - extract_attributes_from_tx(event), - ))), - OPEN_ACK_EVENT_TYPE => Some(IbcEvent::OpenAckChannel(OpenAck::from( - extract_attributes_from_tx(event), - ))), - OPEN_CONFIRM_EVENT_TYPE => Some(IbcEvent::OpenConfirmChannel(OpenConfirm::from( - extract_attributes_from_tx(event), - ))), - CLOSE_INIT_EVENT_TYPE => Some(IbcEvent::CloseInitChannel(CloseInit::from( - extract_attributes_from_tx(event), - ))), - CLOSE_CONFIRM_EVENT_TYPE => Some(IbcEvent::CloseConfirmChannel(CloseConfirm::from( - extract_attributes_from_tx(event), - ))), - SEND_PACKET => { - let (packet, write_ack) = extract_packet_and_write_ack_from_tx(event); - // This event should not have a write ack. - assert_eq!(write_ack.len(), 0); - Some(IbcEvent::SendPacket(SendPacket { - height: Default::default(), - packet, - })) - } - WRITE_ACK => { - let (packet, write_ack) = extract_packet_and_write_ack_from_tx(event); - Some(IbcEvent::WriteAcknowledgement(WriteAcknowledgement { - height: Default::default(), - packet, - ack: write_ack, - })) - } - ACK_PACKET => { - let (packet, write_ack) = extract_packet_and_write_ack_from_tx(event); - // This event should not have a write ack. - assert_eq!(write_ack.len(), 0); - Some(IbcEvent::AcknowledgePacket(AcknowledgePacket { - height: Default::default(), - packet, - })) - } - TIMEOUT => { - let (packet, write_ack) = extract_packet_and_write_ack_from_tx(event); - // This event should not have a write ack. - assert_eq!(write_ack.len(), 0); - Some(IbcEvent::TimeoutPacket(TimeoutPacket { - height: Default::default(), - packet, - })) - } - _ => None, - } -} - -fn extract_attributes_from_tx(event: &tendermint::abci::Event) -> Attributes { - let mut attr = Attributes::default(); - - for tag in &event.attributes { - let key = tag.key.as_ref(); - let value = tag.value.as_ref(); - match key { - PORT_ID_ATTRIBUTE_KEY => attr.port_id = value.parse().unwrap(), - CHANNEL_ID_ATTRIBUTE_KEY => attr.channel_id = value.parse().ok(), - CONNECTION_ID_ATTRIBUTE_KEY => attr.connection_id = value.parse().unwrap(), - COUNTERPARTY_PORT_ID_ATTRIBUTE_KEY => { - attr.counterparty_port_id = value.parse().unwrap() - } - COUNTERPARTY_CHANNEL_ID_ATTRIBUTE_KEY => { - attr.counterparty_channel_id = value.parse().ok() - } - _ => {} - } - } - - attr -} - -fn extract_packet_and_write_ack_from_tx(event: &tendermint::abci::Event) -> (Packet, Vec) { - let mut packet = Packet::default(); - let mut write_ack: Vec = Vec::new(); - for tag in &event.attributes { - let key = tag.key.as_ref(); - let value = tag.value.as_ref(); - match key { - PKT_SRC_PORT_ATTRIBUTE_KEY => packet.source_port = value.parse().unwrap(), - PKT_SRC_CHANNEL_ATTRIBUTE_KEY => packet.source_channel = value.parse().unwrap(), - PKT_DST_PORT_ATTRIBUTE_KEY => packet.destination_port = value.parse().unwrap(), - PKT_DST_CHANNEL_ATTRIBUTE_KEY => packet.destination_channel = value.parse().unwrap(), - PKT_SEQ_ATTRIBUTE_KEY => packet.sequence = value.parse::().unwrap().into(), - PKT_TIMEOUT_HEIGHT_ATTRIBUTE_KEY => packet.timeout_height = value.parse().unwrap(), - PKT_TIMEOUT_TIMESTAMP_ATTRIBUTE_KEY => { - packet.timeout_timestamp = value.parse().unwrap() - } - PKT_DATA_ATTRIBUTE_KEY => packet.data = Vec::from(value.as_bytes()), - PKT_ACK_ATTRIBUTE_KEY => write_ack = Vec::from(value.as_bytes()), - _ => {} - }; - } - - (packet, write_ack) -} - -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Attributes { - pub height: Height, - pub port_id: PortId, - pub channel_id: Option, - pub connection_id: ConnectionId, - pub counterparty_port_id: PortId, - pub counterparty_channel_id: Option, -} - -impl Attributes { - pub fn port_id(&self) -> &PortId { - &self.port_id - } - pub fn channel_id(&self) -> Option<&ChannelId> { - self.channel_id.as_ref() - } -} - -impl Default for Attributes { - fn default() -> Self { - Attributes { - height: Default::default(), - port_id: Default::default(), - channel_id: Default::default(), - connection_id: Default::default(), - counterparty_port_id: Default::default(), - counterparty_channel_id: Default::default(), - } - } -} - -#[derive(Debug, Deserialize, Serialize, Clone)] -pub struct OpenInit(pub Attributes); - -impl OpenInit { - pub fn attributes(&self) -> &Attributes { - &self.0 - } - pub fn channel_id(&self) -> Option<&ChannelId> { - self.0.channel_id.as_ref() - } - pub fn port_id(&self) -> &PortId { - &self.0.port_id - } - pub fn height(&self) -> Height { - self.0.height - } - pub fn set_height(&mut self, height: Height) { - self.0.height = height; - } -} - -impl From for OpenInit { - fn from(attrs: Attributes) -> Self { - OpenInit(attrs) - } -} - -impl From for IbcEvent { - fn from(v: OpenInit) -> Self { - IbcEvent::OpenInitChannel(v) - } -} - -#[derive(Debug, Deserialize, Serialize, Clone)] -pub struct OpenTry(pub Attributes); - -impl OpenTry { - pub fn attributes(&self) -> &Attributes { - &self.0 - } - pub fn channel_id(&self) -> Option<&ChannelId> { - self.0.channel_id.as_ref() - } - pub fn port_id(&self) -> &PortId { - &self.0.port_id - } - pub fn height(&self) -> Height { - self.0.height - } - pub fn set_height(&mut self, height: Height) { - self.0.height = height; - } -} - -impl From for OpenTry { - fn from(attrs: Attributes) -> Self { - OpenTry(attrs) - } -} - -impl From for IbcEvent { - fn from(v: OpenTry) -> Self { - IbcEvent::OpenTryChannel(v) - } -} - -#[derive(Debug, Deserialize, Serialize, Clone)] -pub struct OpenAck(pub Attributes); - -impl OpenAck { - pub fn attributes(&self) -> &Attributes { - &self.0 - } - pub fn channel_id(&self) -> Option<&ChannelId> { - self.0.channel_id.as_ref() - } - pub fn port_id(&self) -> &PortId { - &self.0.port_id - } - pub fn height(&self) -> Height { - self.0.height - } - pub fn set_height(&mut self, height: Height) { - self.0.height = height; - } - - pub fn counterparty_channel_id(&self) -> Option<&ChannelId> { - self.0.counterparty_channel_id.as_ref() - } -} - -impl From for OpenAck { - fn from(attrs: Attributes) -> Self { - OpenAck(attrs) - } -} - -impl From for IbcEvent { - fn from(v: OpenAck) -> Self { - IbcEvent::OpenAckChannel(v) - } -} - -#[derive(Debug, Deserialize, Serialize, Clone)] -pub struct OpenConfirm(pub Attributes); - -impl OpenConfirm { - pub fn attributes(&self) -> &Attributes { - &self.0 - } - pub fn channel_id(&self) -> Option<&ChannelId> { - self.0.channel_id.as_ref() - } - pub fn port_id(&self) -> &PortId { - &self.0.port_id - } - pub fn height(&self) -> Height { - self.0.height - } - pub fn set_height(&mut self, height: Height) { - self.0.height = height; - } -} - -impl From for OpenConfirm { - fn from(attrs: Attributes) -> Self { - OpenConfirm(attrs) - } -} - -impl From for IbcEvent { - fn from(v: OpenConfirm) -> Self { - IbcEvent::OpenConfirmChannel(v) - } -} - -#[derive(Debug, Deserialize, Serialize, Clone)] -pub struct CloseInit(pub Attributes); - -impl CloseInit { - pub fn port_id(&self) -> &PortId { - &self.0.port_id - } - - pub fn channel_id(&self) -> &ChannelId { - // FIXME(romac): Rework encoding of IbcEvents which use `Attributes` - self.0 - .channel_id - .as_ref() - .expect("CloseInit should always have a channel_id") - } - - pub fn counterparty_port_id(&self) -> &PortId { - &self.0.counterparty_port_id - } - - pub fn counterparty_channel_id(&self) -> Option<&ChannelId> { - self.0.counterparty_channel_id.as_ref() - } - - pub fn height(&self) -> Height { - self.0.height - } - - pub fn set_height(&mut self, height: Height) { - self.0.height = height; - } -} - -impl From for CloseInit { - fn from(attrs: Attributes) -> Self { - CloseInit(attrs) - } -} - -impl From for IbcEvent { - fn from(v: CloseInit) -> Self { - IbcEvent::CloseInitChannel(v) - } -} - -impl core::fmt::Display for CloseInit { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - write!( - f, - "{} {} {:?}", - self.height(), - CLOSE_INIT_EVENT_TYPE, - self.0 - ) - } -} - -#[derive(Debug, Deserialize, Serialize, Clone)] -pub struct CloseConfirm(pub Attributes); - -impl CloseConfirm { - pub fn channel_id(&self) -> Option<&ChannelId> { - self.0.channel_id.as_ref() - } - pub fn height(&self) -> Height { - self.0.height - } - pub fn set_height(&mut self, height: Height) { - self.0.height = height; - } -} - -impl From for CloseConfirm { - fn from(attrs: Attributes) -> Self { - CloseConfirm(attrs) - } -} - -impl From for IbcEvent { - fn from(v: CloseConfirm) -> Self { - IbcEvent::CloseConfirmChannel(v) - } -} - -#[derive(Debug, Deserialize, Serialize, Clone)] -pub struct SendPacket { - pub height: Height, - pub packet: Packet, -} - -impl SendPacket { - pub fn height(&self) -> Height { - self.height - } - pub fn set_height(&mut self, height: Height) { - self.height = height; - } - pub fn src_port_id(&self) -> &PortId { - &self.packet.source_port - } - pub fn src_channel_id(&self) -> &ChannelId { - &self.packet.source_channel - } - pub fn dst_port_id(&self) -> &PortId { - &self.packet.destination_port - } - pub fn dst_channel_id(&self) -> &ChannelId { - &self.packet.destination_channel - } -} - -impl From for IbcEvent { - fn from(v: SendPacket) -> Self { - IbcEvent::SendPacket(v) - } -} - -impl core::fmt::Display for SendPacket { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - write!(f, "SendPacket - h:{}, {}", self.height, self.packet) - } -} - -#[derive(Debug, Deserialize, Serialize, Clone)] -pub struct ReceivePacket { - pub height: Height, - pub packet: Packet, -} - -impl ReceivePacket { - pub fn height(&self) -> Height { - self.height - } - pub fn set_height(&mut self, height: Height) { - self.height = height; - } - pub fn src_port_id(&self) -> &PortId { - &self.packet.source_port - } - pub fn src_channel_id(&self) -> &ChannelId { - &self.packet.source_channel - } - pub fn dst_port_id(&self) -> &PortId { - &self.packet.destination_port - } - pub fn dst_channel_id(&self) -> &ChannelId { - &self.packet.destination_channel - } -} - -impl From for IbcEvent { - fn from(v: ReceivePacket) -> Self { - IbcEvent::ReceivePacket(v) - } -} - -impl core::fmt::Display for ReceivePacket { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - write!(f, "ReceivePacket - h:{}, {}", self.height, self.packet) - } -} - -#[derive(Debug, Deserialize, Serialize, Clone)] -pub struct WriteAcknowledgement { - pub height: Height, - pub packet: Packet, - #[serde(serialize_with = "crate::serializers::ser_hex_upper")] - pub ack: Vec, -} - -impl WriteAcknowledgement { - pub fn height(&self) -> Height { - self.height - } - pub fn set_height(&mut self, height: Height) { - self.height = height; - } - pub fn src_port_id(&self) -> &PortId { - &self.packet.source_port - } - pub fn src_channel_id(&self) -> &ChannelId { - &self.packet.source_channel - } - pub fn dst_port_id(&self) -> &PortId { - &self.packet.destination_port - } - pub fn dst_channel_id(&self) -> &ChannelId { - &self.packet.destination_channel - } -} - -impl From for IbcEvent { - fn from(v: WriteAcknowledgement) -> Self { - IbcEvent::WriteAcknowledgement(v) - } -} - -impl core::fmt::Display for WriteAcknowledgement { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - write!( - f, - "WriteAcknowledgement - h:{}, {}", - self.height, self.packet - ) - } -} - -#[derive(Debug, Deserialize, Serialize, Clone)] -pub struct AcknowledgePacket { - pub height: Height, - pub packet: Packet, -} - -impl AcknowledgePacket { - pub fn height(&self) -> Height { - self.height - } - pub fn set_height(&mut self, height: Height) { - self.height = height; - } - pub fn src_port_id(&self) -> &PortId { - &self.packet.source_port - } - pub fn src_channel_id(&self) -> &ChannelId { - &self.packet.source_channel - } -} - -impl From for IbcEvent { - fn from(v: AcknowledgePacket) -> Self { - IbcEvent::AcknowledgePacket(v) - } -} - -impl core::fmt::Display for AcknowledgePacket { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - write!(f, "h:{}, {}", self.height, self.packet) - } -} - -#[derive(Debug, Deserialize, Serialize, Clone)] -pub struct TimeoutPacket { - pub height: Height, - pub packet: Packet, -} - -impl TimeoutPacket { - pub fn height(&self) -> Height { - self.height - } - pub fn set_height(&mut self, height: Height) { - self.height = height; - } - pub fn src_port_id(&self) -> &PortId { - &self.packet.source_port - } - pub fn src_channel_id(&self) -> &ChannelId { - &self.packet.source_channel - } - pub fn dst_port_id(&self) -> &PortId { - &self.packet.destination_port - } - pub fn dst_channel_id(&self) -> &ChannelId { - &self.packet.destination_channel - } -} - -impl From for IbcEvent { - fn from(v: TimeoutPacket) -> Self { - IbcEvent::TimeoutPacket(v) - } -} - -impl core::fmt::Display for TimeoutPacket { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - write!(f, "TimeoutPacket - h:{}, {}", self.height, self.packet) - } -} - -#[derive(Debug, Deserialize, Serialize, Clone)] -pub struct TimeoutOnClosePacket { - pub height: Height, - pub packet: Packet, -} - -impl TimeoutOnClosePacket { - pub fn height(&self) -> Height { - self.height - } - pub fn set_height(&mut self, height: Height) { - self.height = height; - } - pub fn src_port_id(&self) -> &PortId { - &self.packet.source_port - } - pub fn src_channel_id(&self) -> &ChannelId { - &self.packet.source_channel - } - pub fn dst_port_id(&self) -> &PortId { - &self.packet.destination_port - } - pub fn dst_channel_id(&self) -> &ChannelId { - &self.packet.destination_channel - } -} - -impl From for IbcEvent { - fn from(v: TimeoutOnClosePacket) -> Self { - IbcEvent::TimeoutOnClosePacket(v) - } -} - -impl core::fmt::Display for TimeoutOnClosePacket { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - write!( - f, - "TimeoutOnClosePacket - h:{}, {}", - self.height, self.packet - ) - } -} diff --git a/modules/src/ics04_channel/mod.rs b/modules/src/ics04_channel/mod.rs deleted file mode 100644 index 1baad1e34..000000000 --- a/modules/src/ics04_channel/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -//! ICS 04: IBC Channel implementation - -pub mod channel; -pub mod context; -pub mod error; -pub mod events; - -pub mod handler; -pub mod msgs; -pub mod packet; -pub mod version; diff --git a/modules/src/ics04_channel/version.rs b/modules/src/ics04_channel/version.rs deleted file mode 100644 index dbd098106..000000000 --- a/modules/src/ics04_channel/version.rs +++ /dev/null @@ -1,118 +0,0 @@ -use crate::prelude::*; -use core::convert::TryFrom; -use core::str::FromStr; -use ibc_proto::ibc::core::connection::v1::Version as RawVersion; -use tendermint_proto::Protobuf; - -use crate::ics04_channel::error::Error; - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct Version { - /// unique version identifier - identifier: String, - /// list of features compatible with the specified identifier - features: Vec, -} - -impl Protobuf for Version {} - -impl TryFrom for Version { - type Error = Error; - fn try_from(value: RawVersion) -> Result { - Ok(Version { - identifier: value.identifier, - features: value.features, - }) - } -} - -impl From for RawVersion { - fn from(value: Version) -> Self { - Self { - identifier: value.identifier, - features: value.features, - } - } -} - -impl Default for Version { - fn default() -> Self { - Version { - identifier: "1".to_string(), - features: vec!["TOKEN_TRANSFER".to_string()], - } - } -} - -impl FromStr for Version { - type Err = Error; - - fn from_str(s: &str) -> Result { - Version::decode(s.as_bytes()).map_err(Error::invalid_version) - } -} - -impl core::fmt::Display for Version { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - write!( - f, - "{}", - String::from_utf8(Version::encode_vec(self).unwrap()).unwrap() - ) - } -} - -pub fn default_version_string() -> String { - Version::default().to_string() -} - -pub fn get_compatible_versions() -> Vec { - vec![default_version_string()] -} - -pub fn pick_version( - supported_versions: Vec, - counterparty_versions: Vec, -) -> Result { - let mut intersection: Vec = Vec::new(); - for s in supported_versions.iter() { - let supported_version = Version::decode(s.as_bytes()).map_err(Error::invalid_version)?; - for c in counterparty_versions.iter() { - let counterparty_version = Version::from_str(c.as_str())?; - if supported_version.identifier != counterparty_version.identifier { - continue; - } - // TODO - perform feature intersection and error if empty - intersection.append(&mut vec![supported_version.clone()]); - } - } - intersection.sort_by(|a, b| a.identifier.cmp(&b.identifier)); - if intersection.is_empty() { - return Err(Error::no_common_version()); - } - Ok(intersection[0].to_string()) -} - -pub fn validate_versions(versions: Vec) -> Result, Error> { - if versions.is_empty() { - return Err(Error::empty_version()); - } - for version_str in versions.iter() { - validate_version(version_str.clone())?; - } - Ok(versions) -} - -pub fn validate_version(raw_version: String) -> Result { - let version = Version::from_str(raw_version.as_ref())?; - - if version.identifier.trim().is_empty() { - return Err(Error::empty_version()); - } - for feature in version.features { - if feature.trim().is_empty() { - return Err(Error::empty_version()); - } - } - Ok(raw_version) -} diff --git a/modules/src/ics05_port/capabilities.rs b/modules/src/ics05_port/capabilities.rs deleted file mode 100644 index 01083092f..000000000 --- a/modules/src/ics05_port/capabilities.rs +++ /dev/null @@ -1,28 +0,0 @@ -//! Capabilities: this is a placeholder. - -#[derive(Clone, Debug, PartialEq)] -pub struct Capability { - index: u64, -} - -impl Capability { - pub fn new() -> Capability { - Self { index: 0x0 } - } - - pub fn index(&self) -> u64 { - self.index - } -} - -impl Default for Capability { - fn default() -> Self { - Self::new() - } -} - -impl From for Capability { - fn from(index: u64) -> Self { - Self { index } - } -} diff --git a/modules/src/ics05_port/context.rs b/modules/src/ics05_port/context.rs deleted file mode 100644 index ad2c9a426..000000000 --- a/modules/src/ics05_port/context.rs +++ /dev/null @@ -1,11 +0,0 @@ -use crate::ics05_port::capabilities::Capability; -use crate::ics05_port::error::Error; -use crate::ics24_host::identifier::PortId; - -// A context supplying all the necessary read-only dependencies for processing any information regarding a port. -pub trait PortReader { - fn lookup_module_by_port(&self, port_id: &PortId) -> Result; - fn authenticate(&self, key: &Capability, port_id: &PortId) -> bool; -} - -// Result//return Ok(Capability::new()); diff --git a/modules/src/ics05_port/error.rs b/modules/src/ics05_port/error.rs deleted file mode 100644 index ce923ea0e..000000000 --- a/modules/src/ics05_port/error.rs +++ /dev/null @@ -1,14 +0,0 @@ -use crate::ics24_host::identifier::PortId; -use flex_error::define_error; - -define_error! { - #[derive(Debug, PartialEq)] - Error { - UnknownPort - { port_id: PortId } - | e | { format_args!("Port {0} is unknown", e.port_id) }, - - ImplementationSpecific - | _ | { "implementation specific error" }, - } -} diff --git a/modules/src/ics05_port/mod.rs b/modules/src/ics05_port/mod.rs deleted file mode 100644 index 7f6f91fb0..000000000 --- a/modules/src/ics05_port/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod capabilities; -pub mod context; -pub mod error; diff --git a/modules/src/ics07_tendermint/client_def.rs b/modules/src/ics07_tendermint/client_def.rs deleted file mode 100644 index ed4d1269f..000000000 --- a/modules/src/ics07_tendermint/client_def.rs +++ /dev/null @@ -1,158 +0,0 @@ -use ibc_proto::ibc::core::commitment::v1::MerkleProof; - -use crate::ics02_client::client_consensus::AnyConsensusState; -use crate::ics02_client::client_def::ClientDef; -use crate::ics02_client::client_state::AnyClientState; -use crate::ics02_client::error::Error; -use crate::ics03_connection::connection::ConnectionEnd; -use crate::ics04_channel::channel::ChannelEnd; -use crate::ics04_channel::packet::Sequence; -use crate::ics07_tendermint::client_state::ClientState; -use crate::ics07_tendermint::consensus_state::ConsensusState; -use crate::ics07_tendermint::header::Header; -use crate::ics23_commitment::commitment::{CommitmentPrefix, CommitmentProofBytes, CommitmentRoot}; -use crate::ics24_host::identifier::ConnectionId; -use crate::ics24_host::identifier::{ChannelId, ClientId, PortId}; -use crate::prelude::*; -use crate::Height; - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct TendermintClient; - -impl ClientDef for TendermintClient { - type Header = Header; - type ClientState = ClientState; - type ConsensusState = ConsensusState; - - fn check_header_and_update_state( - &self, - client_state: Self::ClientState, - header: Self::Header, - ) -> Result<(Self::ClientState, Self::ConsensusState), Error> { - if client_state.latest_height() >= header.height() { - return Err(Error::low_header_height( - header.height(), - client_state.latest_height(), - )); - } - - // TODO: Additional verifications should be implemented here. - - Ok(( - client_state.with_header(header.clone()), - ConsensusState::from(header), - )) - } - - fn verify_client_consensus_state( - &self, - _client_state: &Self::ClientState, - _height: Height, - _prefix: &CommitmentPrefix, - _proof: &CommitmentProofBytes, - _client_id: &ClientId, - _consensus_height: Height, - _expected_consensus_state: &AnyConsensusState, - ) -> Result<(), Error> { - Ok(()) - } - - fn verify_connection_state( - &self, - _client_state: &Self::ClientState, - _height: Height, - _prefix: &CommitmentPrefix, - _proof: &CommitmentProofBytes, - _connection_id: Option<&ConnectionId>, - _expected_connection_end: &ConnectionEnd, - ) -> Result<(), Error> { - Ok(()) - } - - fn verify_channel_state( - &self, - _client_state: &Self::ClientState, - _height: Height, - _prefix: &CommitmentPrefix, - _proof: &CommitmentProofBytes, - _port_id: &PortId, - _channel_id: &ChannelId, - _expected_channel_end: &ChannelEnd, - ) -> Result<(), Error> { - Ok(()) - } - - fn verify_client_full_state( - &self, - _client_state: &Self::ClientState, - _height: Height, - _root: &CommitmentRoot, - _prefix: &CommitmentPrefix, - _client_id: &ClientId, - _proof: &CommitmentProofBytes, - _expected_client_state: &AnyClientState, - ) -> Result<(), Error> { - Ok(()) - } - - fn verify_packet_data( - &self, - _client_state: &Self::ClientState, - _height: Height, - _proof: &CommitmentProofBytes, - _port_id: &PortId, - _channel_id: &ChannelId, - _seq: &Sequence, - _data: String, - ) -> Result<(), Error> { - Ok(()) // Todo: - } - - fn verify_packet_acknowledgement( - &self, - _client_state: &Self::ClientState, - _height: Height, - _proof: &CommitmentProofBytes, - _port_id: &PortId, - _channel_id: &ChannelId, - _seq: &Sequence, - _data: Vec, - ) -> Result<(), Error> { - Ok(()) // Todo: - } - - fn verify_next_sequence_recv( - &self, - _client_state: &Self::ClientState, - _height: Height, - _proof: &CommitmentProofBytes, - _port_id: &PortId, - _channel_id: &ChannelId, - _seq: &Sequence, - ) -> Result<(), Error> { - Ok(()) // Todo: - } - - fn verify_packet_receipt_absence( - &self, - _client_state: &Self::ClientState, - _height: Height, - _proof: &CommitmentProofBytes, - _port_id: &PortId, - _channel_id: &ChannelId, - _seq: &Sequence, - ) -> Result<(), Error> { - Ok(()) // Todo: - } - - fn verify_upgrade_and_update_state( - &self, - client_state: &Self::ClientState, - consensus_state: &Self::ConsensusState, - _proof_upgrade_client: MerkleProof, - _proof_upgrade_consensus_state: MerkleProof, - ) -> Result<(Self::ClientState, Self::ConsensusState), Error> { - // TODO - Ok((client_state.clone(), consensus_state.clone())) - } -} diff --git a/modules/src/ics07_tendermint/error.rs b/modules/src/ics07_tendermint/error.rs deleted file mode 100644 index e0561d112..000000000 --- a/modules/src/ics07_tendermint/error.rs +++ /dev/null @@ -1,115 +0,0 @@ -use crate::prelude::*; - -use core::num::TryFromIntError; -use flex_error::{define_error, TraceError}; -use tendermint::Error as TendermintError; - -use crate::ics24_host::error::ValidationError; - -define_error! { - #[derive(Debug, PartialEq, Eq)] - Error { - Tendermint - [ TendermintError ] - | _ | { "tendermint error" }, - - InvalidTrustingPeriod - { reason: String } - | _ | { "invalid trusting period" }, - - InvalidUnboundingPeriod - { reason: String } - | _ | { "invalid unbonding period" }, - - InvalidAddress - | _ | { "invalid address" }, - - InvalidHeader - { reason: String } - [ tendermint::Error ] - | _ | { "invalid header, failed basic validation" }, - - InvalidTrustThreshold - { reason: String } - | e | { - format_args!("invalid client state trust threshold: {}", - e.reason) - }, - - MissingSignedHeader - | _ | { "missing signed header" }, - - Validation - { reason: String } - | _ | { "invalid header, failed basic validation" }, - - InvalidRawClientState - { reason: String } - | _ | { "invalid raw client state" }, - - MissingValidatorSet - | _ | { "missing validator set" }, - - MissingTrustedValidatorSet - | _ | { "missing trusted validator set" }, - - MissingTrustedHeight - | _ | { "missing trusted height" }, - - MissingTrustingPeriod - | _ | { "missing trusting period" }, - - MissingUnbondingPeriod - | _ | { "missing unbonding period" }, - - InvalidChainIdentifier - [ ValidationError ] - | _ | { "Invalid chain identifier" }, - - NegativeTrustingPeriod - | _ | { "negative trusting period" }, - - NegativeUnbondingPeriod - | _ | { "negative unbonding period" }, - - MissingMaxClockDrift - | _ | { "missing max clock drift" }, - - NegativeMaxClockDrift - | _ | { "negative max clock drift" }, - - MissingLatestHeight - | _ | { "missing latest height" }, - - MissingFrozenHeight - | _ | { "missing frozen height" }, - - InvalidChainId - { raw_value: String } - [ ValidationError ] - | e | { format_args!("invalid chain identifier: raw value {0}", e.raw_value) }, - - InvalidRawHeight - | _ | { "invalid raw height" }, - - InvalidRawConsensusState - { reason: String } - | _ | { "invalid raw client consensus state" }, - - InvalidRawHeader - [ tendermint::Error ] - | _ | { "invalid raw header" }, - - InvalidRawMisbehaviour - { reason: String } - | _ | { "invalid raw misbehaviour" }, - - Decode - [ TraceError ] - | _ | { "decode error" }, - - TimestampOverflow - [ TraceError ] - | _ | { "timestamp overflow" }, - } -} diff --git a/modules/src/ics07_tendermint/mod.rs b/modules/src/ics07_tendermint/mod.rs deleted file mode 100644 index 0c4263997..000000000 --- a/modules/src/ics07_tendermint/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -//! ICS 07: Tendermint Client - -pub mod client_def; -pub mod client_state; -pub mod consensus_state; -pub mod error; -pub mod header; -pub mod misbehaviour; diff --git a/modules/src/ics18_relayer/mod.rs b/modules/src/ics18_relayer/mod.rs deleted file mode 100644 index 380a73836..000000000 --- a/modules/src/ics18_relayer/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -//! ICS 18: Implementation of basic relayer functions. - -pub mod context; -pub mod error; -pub mod utils; diff --git a/modules/src/ics23_commitment/error.rs b/modules/src/ics23_commitment/error.rs deleted file mode 100644 index 43d8032f8..000000000 --- a/modules/src/ics23_commitment/error.rs +++ /dev/null @@ -1,15 +0,0 @@ -use flex_error::{define_error, TraceError}; -use prost::DecodeError; - -define_error! { - #[derive(Debug, PartialEq, Eq)] - Error { - InvalidRawMerkleProof - [ TraceError ] - |_| { "invalid raw merkle proof" }, - - CommitmentProofDecodingFailed - [ TraceError ] - |_| { "failed to decode commitment proof" }, - } -} diff --git a/modules/src/ics23_commitment/merkle.rs b/modules/src/ics23_commitment/merkle.rs deleted file mode 100644 index 6cb390fc4..000000000 --- a/modules/src/ics23_commitment/merkle.rs +++ /dev/null @@ -1,96 +0,0 @@ -use crate::prelude::*; -use tendermint::merkle::proof::Proof; - -use ibc_proto::ibc::core::commitment::v1::MerklePath; -use ibc_proto::ibc::core::commitment::v1::MerkleProof as RawMerkleProof; - -use crate::ics23_commitment::commitment::{CommitmentPrefix, CommitmentProofBytes}; -use crate::ics23_commitment::error::Error; - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct EmptyPrefixError; - -pub fn apply_prefix( - prefix: &CommitmentPrefix, - mut path: Vec, -) -> Result { - if prefix.is_empty() { - return Err(EmptyPrefixError); - } - - let mut result: Vec = vec![format!("{:?}", prefix)]; - result.append(&mut path); - - Ok(MerklePath { key_path: result }) -} - -#[derive(Clone, Debug, PartialEq)] -pub struct MerkleProof { - pub proof: Vec, -} - -// Merkle Proof serialization notes: -// "Proof" id currently defined in a number of forms and included in a number of places -// - TmProof: in tendermint-rs/src/merkle/proof.rs:Proof -// - RawProofOps: in tendermint-proto/tendermint.cyrpto.rs:ProofOps -// - RawMerkleProof: in ibc-proto/ibc.core.commitment.v1.rs:MerkleProof -// - structure that includes a RawProofOps in its only `proof` field. -// #[derive(Clone, PartialEq, ::prost::Message)] -// pub struct MerkleProof { -// #[prost(message, optional, tag="1")] -// pub proof: ::core::option::Option<::tendermint_proto::crypto::ProofOps>, -// } -// - Vec: RawMerkleProof is not explicitly used but, serialized as Vec, it is -// included in all handshake messages that require proofs (i.e. all except the two `OpenInit`), -// and also in all queries that require proofs -// - MerkleProof: Domain type for RawMerkleProof, currently not used and identical to RawMerkleProof. -// This will change with verification implementation. -// - CommitmentProof: Defined in ibc-rs as Vec and currently used in all its messages -// -// Here are a couple of flows that illustrate the different conversions: -// IBC Messages and Handlers: sink happens in the handle verification -// Vec -> CommitmentProof -> RawMerkleProof -> MerkleProof -// -// Relayer: from the proof in the query response to the proof being included in a message -// TmProof -> RawProofOps => RawMerkleProof -> MerkleProof -> verify() -// -> MerkleProof -> RawMerkleProof -> CommitmentProof -> Vec -// Note: current implementation for ^ is simplified since verification is not yet implemented: -// TmProof -> RawProofOps => RawMerkleProof -> CommitmentProof -> Vec -// -// Implementations of (de)serializers and conversions: -// - commitment.rs: -// Vec <-> CommitmentProof -// CommitmentProof <-> RawMerkleProof -// - merkle.rs: -// RawMerkleProof <-> MerkleProof -// - tendermint-rs/src/merkle/proof.rs: -// TmProof <-> RawProofOps -// - cosmos.rs:abci_query() converts from query proof to Merkle proof: -// RawProofOps => RawMerkleProof -// -// impl TryFrom for MerkleProof { -// type Error = Error; -// fn try_from(value: RawMerkleProof) -> Result { -// Ok(MerkleProof { proof: value.proofs.into_iter().map(|v| v.into()).collect() }) -// } -// } -// -// impl From for RawMerkleProof { -// fn from(value: MerkleProof) -> Self { -// RawMerkleProof { proof: value.proof } -// } -// } - -pub fn convert_tm_to_ics_merkle_proof(tm_proof: &Proof) -> Result { - let mut proofs = Vec::new(); - - for op in &tm_proof.ops { - let mut parsed = ibc_proto::ics23::CommitmentProof { proof: None }; - prost::Message::merge(&mut parsed, op.data.as_slice()) - .map_err(Error::commitment_proof_decoding_failed)?; - - proofs.push(parsed); - } - - Ok(RawMerkleProof { proofs }) -} diff --git a/modules/src/ics23_commitment/mod.rs b/modules/src/ics23_commitment/mod.rs deleted file mode 100644 index 885c5dbd1..000000000 --- a/modules/src/ics23_commitment/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod commitment; -pub mod error; -pub mod merkle; -pub mod mock; -pub mod specs; diff --git a/modules/src/ics23_commitment/specs.rs b/modules/src/ics23_commitment/specs.rs deleted file mode 100644 index 728ea63b6..000000000 --- a/modules/src/ics23_commitment/specs.rs +++ /dev/null @@ -1,46 +0,0 @@ -use crate::prelude::*; -use ibc_proto::ics23::ProofSpec as ProtoProofSpec; -use ics23::ProofSpec; - -/// An array of proof specifications. -/// -/// This type encapsulates different types of proof specifications, mostly predefined, e.g., for -/// Cosmos-SDK. -/// Additionally, this type also aids in the conversion from `ProofSpec` types from crate `ics23` -/// into proof specifications as represented in the `ibc_proto` type; see the -/// `From` trait(s) below. -pub struct ProofSpecs { - specs: Vec, -} - -impl ProofSpecs { - /// Returns the specification for Cosmos-SDK proofs - pub fn cosmos() -> Self { - Self { - specs: vec![ - ics23::iavl_spec(), // Format of proofs-iavl (iavl merkle proofs) - ics23::tendermint_spec(), // Format of proofs-tendermint (crypto/ merkle SimpleProof) - ], - } - } -} - -/// Converts from the domain type (which is represented as a vector of `ics23::ProofSpec` -/// to the corresponding proto type (vector of `ibc_proto::ProofSpec`). -/// TODO: fix with -impl From for Vec { - fn from(domain_specs: ProofSpecs) -> Self { - let mut raw_specs = Vec::new(); - for ds in domain_specs.specs.iter() { - // Both `ProofSpec` types implement trait `prost::Message`. Convert by encoding, then - // decoding into the destination type. - // Safety note: the source and target data structures are identical, hence the - // encode/decode conversion here should be infallible. - let mut encoded = Vec::new(); - prost::Message::encode(ds, &mut encoded).unwrap(); - let decoded: ProtoProofSpec = prost::Message::decode(&*encoded).unwrap(); - raw_specs.push(decoded); - } - raw_specs - } -} diff --git a/modules/src/ics24_host/mod.rs b/modules/src/ics24_host/mod.rs deleted file mode 100644 index 3f3fea529..000000000 --- a/modules/src/ics24_host/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -//! ICS 24: Host Requirements - -pub use path::{ClientUpgradePath, Path, IBC_QUERY_PATH, SDK_UPGRADE_QUERY_PATH}; - -pub mod error; -pub mod identifier; -mod path; -pub mod validate; diff --git a/modules/src/ics24_host/path.rs b/modules/src/ics24_host/path.rs deleted file mode 100644 index 92c8d89fb..000000000 --- a/modules/src/ics24_host/path.rs +++ /dev/null @@ -1,157 +0,0 @@ -use crate::prelude::*; - -/// Path-space as listed in ICS-024 -/// https://github.com/cosmos/ibc/tree/master/spec/ics-024-host-requirements#path-space -/// Some of these are implemented in other ICSs, but ICS-024 has a nice summary table. -/// -use core::fmt::{Display, Formatter, Result}; - -use crate::ics04_channel::packet::Sequence; -use crate::ics24_host::identifier::{ChannelId, ClientId, ConnectionId, PortId}; - -/// ABCI Query path for the IBC sub-store -pub const IBC_QUERY_PATH: &str = "store/ibc/key"; - -/// ABCI Query path for the upgrade sub-store -/// ## Note: This is SDK/Tendermint specific! -pub const SDK_UPGRADE_QUERY_PATH: &str = "store/upgrade/key"; - -/// ABCI client upgrade keys -/// - The key identifying the upgraded IBC state within the upgrade sub-store -const UPGRADED_IBC_STATE: &str = "upgradedIBCState"; -///- The key identifying the upgraded client state -const UPGRADED_CLIENT_STATE: &str = "upgradedClient"; -/// - The key identifying the upgraded consensus state -const UPGRADED_CLIENT_CONSENSUS_STATE: &str = "upgradedConsState"; - -/// The Path enum abstracts out the different sub-paths -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum Path { - ClientType(ClientId), - ClientState(ClientId), - ClientConsensusState { - client_id: ClientId, - epoch: u64, - height: u64, - }, - ClientConnections(ClientId), - Connections(ConnectionId), - Ports(PortId), - ChannelEnds(PortId, ChannelId), - SeqSends(PortId, ChannelId), - SeqRecvs(PortId, ChannelId), - SeqAcks(PortId, ChannelId), - Commitments { - port_id: PortId, - channel_id: ChannelId, - sequence: Sequence, - }, - Acks { - port_id: PortId, - channel_id: ChannelId, - sequence: Sequence, - }, - Receipts { - port_id: PortId, - channel_id: ChannelId, - sequence: Sequence, - }, - Upgrade(ClientUpgradePath), -} - -/// Paths that are specific for client upgrades. -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum ClientUpgradePath { - UpgradedClientState(u64), - UpgradedClientConsensusState(u64), -} - -impl Path { - /// Indication if the path is provable. - pub fn is_provable(&self) -> bool { - !matches!(&self, Path::ClientConnections(_) | Path::Ports(_)) - } - - /// into_bytes implementation - pub fn into_bytes(self) -> Vec { - self.to_string().into_bytes() - } -} - -/// The Display trait adds the `.to_string()` method to the Path struct -/// This is where the different path strings are constructed -impl Display for Path { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - match &self { - Path::ClientType(client_id) => write!(f, "clients/{}/clientType", client_id), - Path::ClientState(client_id) => write!(f, "clients/{}/clientState", client_id), - Path::ClientConsensusState { - client_id, - epoch, - height, - } => write!( - f, - "clients/{}/consensusStates/{}-{}", - client_id, epoch, height - ), - Path::ClientConnections(client_id) => write!(f, "clients/{}/connections", client_id), - Path::Connections(connection_id) => write!(f, "connections/{}", connection_id), - Path::Ports(port_id) => write!(f, "ports/{}", port_id), - Path::ChannelEnds(port_id, channel_id) => { - write!(f, "channelEnds/ports/{}/channels/{}", port_id, channel_id) - } - Path::SeqSends(port_id, channel_id) => write!( - f, - "nextSequenceSend/ports/{}/channels/{}", - port_id, channel_id - ), - Path::SeqRecvs(port_id, channel_id) => write!( - f, - "nextSequenceRecv/ports/{}/channels/{}", - port_id, channel_id - ), - Path::SeqAcks(port_id, channel_id) => write!( - f, - "nextSequenceAck/ports/{}/channels/{}", - port_id, channel_id - ), - Path::Commitments { - port_id, - channel_id, - sequence, - } => write!( - f, - "commitments/ports/{}/channels/{}/sequences/{}", - port_id, channel_id, sequence - ), - Path::Acks { - port_id, - channel_id, - sequence, - } => write!( - f, - "acks/ports/{}/channels/{}/sequences/{}", - port_id, channel_id, sequence - ), - Path::Receipts { - port_id, - channel_id, - sequence, - } => write!( - f, - "receipts/ports/{}/channels/{}/sequences/{}", - port_id, channel_id, sequence - ), - Path::Upgrade(ClientUpgradePath::UpgradedClientState(height)) => write!( - f, - "{}/{}/{}", - UPGRADED_IBC_STATE, height, UPGRADED_CLIENT_STATE - ), - Path::Upgrade(ClientUpgradePath::UpgradedClientConsensusState(height)) => write!( - f, - "{}/{}/{}", - UPGRADED_IBC_STATE, height, UPGRADED_CLIENT_CONSENSUS_STATE - ), - } - } -} diff --git a/modules/src/ics26_routing/mod.rs b/modules/src/ics26_routing/mod.rs deleted file mode 100644 index 40cf9bee7..000000000 --- a/modules/src/ics26_routing/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -//! ICS 26: Routing module implementation - -pub mod context; -pub mod error; -pub mod handler; -pub mod msgs; diff --git a/modules/src/lib.rs b/modules/src/lib.rs index 2119c9e31..b75e4bf67 100644 --- a/modules/src/lib.rs +++ b/modules/src/lib.rs @@ -5,8 +5,7 @@ #![no_std] #![allow(clippy::large_enum_variant)] #![deny( - // warnings, - // missing_docs, + warnings, trivial_casts, trivial_numeric_casts, unused_import_braces, @@ -20,55 +19,62 @@ // #![cfg_attr(not(test), deny(clippy::unwrap_used))] #![forbid(unsafe_code)] -//! Implementation of the following ICS modules: +//! This library implements the InterBlockchain Communication (IBC) protocol in Rust. IBC is +//! a distributed protocol that enables communication between distinct sovereign blockchains. +//! Loose analogies may be drawn between the IBC protocol and the TCP/UDP protocols that enable +//! communication over the internet via packet streaming. Indeed, IBC also encodes the notion of +//! ordered and unordered packet streams. //! -//! - ICS 02: Client -//! - ICS 03: Connection -//! - ICS 04: Channel -//! - ICS 05: Port -//! - ICS 07: Tendermint Client -//! - ICS 18: Basic relayer functions -//! - ICS 23: Vector Commitment Scheme -//! - ICS 24: Host Requirements -//! - ICS 26: Routing -//! - Applications: -//! - ICS 20: Fungible Token Transfer +//! The layout of this crate mirrors the classification of the [Interchain +//! Standards][ics-standards]. The classification consists of [Core][core], [Clients][clients], +//! [Applications][applications], and [Relayer][relayer]. +//! +//! `Core` consists of the designs and logic pertaining to the transport, authentication, and +//! ordering layers of the IBC protocol, the fundamental pieces. +//! +//! `Clients` consists of implementations of client verification algorithms (following the base +//! client interface that is defined in `Core`) for specific types of chains. A chain uses these +//! verification algorithms to verify the state of remote chains. +//! +//! `Applications` consists of various packet encoding and processing semantics which underpin the +//! various types of transactions that users can perform on any IBC-compliant chain. +//! +//! `Relayer` contains utilities for testing the `ibc` crate against the [Hermes IBC relayer][relayer-repo]. It acts +//! as scaffolding for gluing the `ibc` crate with Hermes for testing purposes. +//! +//! [core]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/core +//! [clients]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/clients +//! [applications]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/applications +//! [ics-standards]: https://github.com/cosmos/ibc#interchain-standards +//! [relayer]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/relayer +//! [relayer-repo]: https://github.com/informalsystems/ibc-rs/tree/master/relayer extern crate alloc; -// Only allow the use of std in tests. Otherwise the main -// ibc crate works with no_std. -#[cfg(test)] + +#[cfg(feature = "std")] extern crate std; mod prelude; -pub mod application; +pub mod applications; +pub mod clients; +pub mod core; pub mod events; pub mod handler; pub mod keys; pub mod macros; pub mod proofs; pub mod query; +pub mod relayer; pub mod signer; pub mod timestamp; pub mod tx_msg; -pub mod ics02_client; -pub mod ics03_connection; -pub mod ics04_channel; -pub mod ics05_port; -pub mod ics07_tendermint; -pub mod ics10_grandpa; -pub mod ics18_relayer; -pub mod ics23_commitment; -pub mod ics24_host; -pub mod ics26_routing; - mod serializers; /// Re-export of ICS 002 Height domain type -pub type Height = crate::ics02_client::height::Height; +pub type Height = crate::core::ics02_client::height::Height; #[cfg(test)] mod test; diff --git a/modules/src/mock/client_def.rs b/modules/src/mock/client_def.rs index 4b520f1da..2691a559b 100644 --- a/modules/src/mock/client_def.rs +++ b/modules/src/mock/client_def.rs @@ -1,16 +1,21 @@ use ibc_proto::ibc::core::commitment::v1::MerkleProof; -use crate::ics02_client::client_consensus::AnyConsensusState; -use crate::ics02_client::client_def::ClientDef; -use crate::ics02_client::client_state::AnyClientState; -use crate::ics02_client::error::Error; -use crate::ics03_connection::connection::ConnectionEnd; -use crate::ics04_channel::channel::ChannelEnd; -use crate::ics04_channel::packet::Sequence; -use crate::ics23_commitment::commitment::{CommitmentPrefix, CommitmentProofBytes, CommitmentRoot}; -use crate::ics23_commitment::merkle::apply_prefix; -use crate::ics24_host::identifier::{ChannelId, ClientId, ConnectionId, PortId}; -use crate::ics24_host::Path; +use crate::core::ics02_client::client_consensus::AnyConsensusState; +use crate::core::ics02_client::client_def::ClientDef; +use crate::core::ics02_client::client_state::AnyClientState; +use crate::core::ics02_client::context::ClientReader; +use crate::core::ics02_client::error::Error; +use crate::core::ics03_connection::connection::ConnectionEnd; +use crate::core::ics04_channel::channel::ChannelEnd; +use crate::core::ics04_channel::context::ChannelReader; +use crate::core::ics04_channel::packet::Sequence; +use crate::core::ics23_commitment::commitment::{ + CommitmentPrefix, CommitmentProofBytes, CommitmentRoot, +}; +use crate::core::ics23_commitment::merkle::apply_prefix; +use crate::core::ics24_host::identifier::{ChannelId, ClientId, ConnectionId, PortId}; +use crate::core::ics24_host::path::ClientConsensusStatePath; +use crate::core::ics24_host::Path; use crate::mock::client_state::{MockClientState, MockConsensusState}; use crate::mock::header::MockHeader; use crate::prelude::*; @@ -26,6 +31,8 @@ impl ClientDef for MockClient { fn check_header_and_update_state( &self, + _ctx: &dyn ClientReader, + _client_id: ClientId, client_state: Self::ClientState, header: Self::Header, ) -> Result<(Self::ClientState, Self::ConsensusState), Error> { @@ -35,33 +42,31 @@ impl ClientDef for MockClient { client_state.latest_height(), )); } - Ok((MockClientState(header), MockConsensusState::new(header))) + Ok(( + MockClientState::new(header), + MockConsensusState::new(header), + )) } fn verify_client_consensus_state( &self, _client_state: &Self::ClientState, - height: Height, + _height: Height, prefix: &CommitmentPrefix, _proof: &CommitmentProofBytes, + _root: &CommitmentRoot, client_id: &ClientId, - _consensus_height: Height, + consensus_height: Height, _expected_consensus_state: &AnyConsensusState, ) -> Result<(), Error> { - let client_prefixed_path = Path::ClientConsensusState { + let client_prefixed_path = Path::ClientConsensusState(ClientConsensusStatePath { client_id: client_id.clone(), - epoch: height.revision_number, - height: height.revision_height, - } + epoch: consensus_height.revision_number, + height: consensus_height.revision_height, + }) .to_string(); - let _path = - apply_prefix(prefix, vec![client_prefixed_path]).map_err(Error::empty_prefix)?; - - // TODO - add ctx to all client verification functions - // let cs = ctx.fetch_self_consensus_state(height); - // TODO - implement this - // proof.verify_membership(cs.root(), path, expected_consensus_state) + let _path = apply_prefix(prefix, vec![client_prefixed_path]); Ok(()) } @@ -72,7 +77,8 @@ impl ClientDef for MockClient { _height: Height, _prefix: &CommitmentPrefix, _proof: &CommitmentProofBytes, - _connection_id: Option<&ConnectionId>, + _root: &CommitmentRoot, + _connection_id: &ConnectionId, _expected_connection_end: &ConnectionEnd, ) -> Result<(), Error> { Ok(()) @@ -84,6 +90,7 @@ impl ClientDef for MockClient { _height: Height, _prefix: &CommitmentPrefix, _proof: &CommitmentProofBytes, + _root: &CommitmentRoot, _port_id: &PortId, _channel_id: &ChannelId, _expected_channel_end: &ChannelEnd, @@ -95,10 +102,10 @@ impl ClientDef for MockClient { &self, _client_state: &Self::ClientState, _height: Height, - _root: &CommitmentRoot, _prefix: &CommitmentPrefix, - _client_id: &ClientId, _proof: &CommitmentProofBytes, + _root: &CommitmentRoot, + _client_id: &ClientId, _expected_client_state: &AnyClientState, ) -> Result<(), Error> { Ok(()) @@ -106,53 +113,66 @@ impl ClientDef for MockClient { fn verify_packet_data( &self, + _ctx: &dyn ChannelReader, _client_state: &Self::ClientState, _height: Height, + _connection_end: &ConnectionEnd, _proof: &CommitmentProofBytes, + _root: &CommitmentRoot, _port_id: &PortId, _channel_id: &ChannelId, - _seq: &Sequence, - _data: String, + _sequence: Sequence, + _commitment: String, ) -> Result<(), Error> { Ok(()) } fn verify_packet_acknowledgement( &self, + _ctx: &dyn ChannelReader, _client_state: &Self::ClientState, _height: Height, + _connection_end: &ConnectionEnd, _proof: &CommitmentProofBytes, + _root: &CommitmentRoot, _port_id: &PortId, _channel_id: &ChannelId, - _seq: &Sequence, - _data: Vec, + _sequence: Sequence, + _ack: Vec, ) -> Result<(), Error> { Ok(()) } fn verify_next_sequence_recv( &self, + _ctx: &dyn ChannelReader, _client_state: &Self::ClientState, _height: Height, + _connection_end: &ConnectionEnd, _proof: &CommitmentProofBytes, + _root: &CommitmentRoot, _port_id: &PortId, _channel_id: &ChannelId, - _seq: &Sequence, + _sequence: Sequence, ) -> Result<(), Error> { Ok(()) } fn verify_packet_receipt_absence( &self, + _ctx: &dyn ChannelReader, _client_state: &Self::ClientState, _height: Height, + _connection_end: &ConnectionEnd, _proof: &CommitmentProofBytes, + _root: &CommitmentRoot, _port_id: &PortId, _channel_id: &ChannelId, - _seq: &Sequence, + _sequence: Sequence, ) -> Result<(), Error> { Ok(()) } + fn verify_upgrade_and_update_state( &self, client_state: &Self::ClientState, diff --git a/modules/src/mock/client_state.rs b/modules/src/mock/client_state.rs index 75903927c..aa4d7863c 100644 --- a/modules/src/mock/client_state.rs +++ b/modules/src/mock/client_state.rs @@ -1,7 +1,8 @@ use crate::prelude::*; + use alloc::collections::btree_map::BTreeMap as HashMap; + use core::convert::Infallible; -use core::convert::{TryFrom, TryInto}; use core::time::Duration; use serde::{Deserialize, Serialize}; @@ -10,12 +11,12 @@ use tendermint_proto::Protobuf; use ibc_proto::ibc::mock::ClientState as RawMockClientState; use ibc_proto::ibc::mock::ConsensusState as RawMockConsensusState; -use crate::ics02_client::client_consensus::{AnyConsensusState, ConsensusState}; -use crate::ics02_client::client_state::{AnyClientState, ClientState}; -use crate::ics02_client::client_type::ClientType; -use crate::ics02_client::error::Error; -use crate::ics23_commitment::commitment::CommitmentRoot; -use crate::ics24_host::identifier::ChainId; +use crate::core::ics02_client::client_consensus::{AnyConsensusState, ConsensusState}; +use crate::core::ics02_client::client_state::{AnyClientState, ClientState}; +use crate::core::ics02_client::client_type::ClientType; +use crate::core::ics02_client::error::Error; +use crate::core::ics23_commitment::commitment::CommitmentRoot; +use crate::core::ics24_host::identifier::ChainId; use crate::mock::header::MockHeader; use crate::timestamp::Timestamp; use crate::Height; @@ -36,20 +37,30 @@ pub struct MockClientRecord { /// A mock of a client state. For an example of a real structure that this mocks, you can see /// `ClientState` of ics07_tendermint/client_state.rs. -// TODO: `MockClientState` should evolve, at the very least needs a `is_frozen` boolean field. #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct MockClientState(pub MockHeader); +pub struct MockClientState { + pub header: MockHeader, + pub frozen_height: Option, +} impl Protobuf for MockClientState {} impl MockClientState { + pub fn new(header: MockHeader) -> Self { + Self { + header, + frozen_height: None, + } + } + pub fn latest_height(&self) -> Height { - (self.0).height + self.header.height() } pub fn refresh_time(&self) -> Option { None } + pub fn expired(&self, _elapsed: Duration) -> bool { false } @@ -65,7 +76,7 @@ impl TryFrom for MockClientState { type Error = Error; fn try_from(raw: RawMockClientState) -> Result { - Ok(MockClientState(raw.header.unwrap().try_into()?)) + Ok(Self::new(raw.header.unwrap().try_into()?)) } } @@ -73,14 +84,16 @@ impl From for RawMockClientState { fn from(value: MockClientState) -> Self { RawMockClientState { header: Some(ibc_proto::ibc::mock::Header { - height: Some(value.0.height().into()), - timestamp: (value.0).timestamp.as_nanoseconds(), + height: Some(value.header.height().into()), + timestamp: value.header.timestamp.nanoseconds(), }), } } } impl ClientState for MockClientState { + type UpgradeOptions = (); + fn chain_id(&self) -> ChainId { todo!() } @@ -90,12 +103,15 @@ impl ClientState for MockClientState { } fn latest_height(&self) -> Height { - self.0.height() + self.header.height() } - fn is_frozen(&self) -> bool { - // TODO - false + fn frozen_height(&self) -> Option { + self.frozen_height + } + + fn upgrade(self, _upgrade_height: Height, _upgrade_options: (), _chain_id: ChainId) -> Self { + todo!() } fn wrap_any(self) -> AnyClientState { @@ -105,7 +121,7 @@ impl ClientState for MockClientState { impl From for MockClientState { fn from(cs: MockConsensusState) -> Self { - Self(cs.header) + Self::new(cs.header) } } @@ -148,7 +164,7 @@ impl From for RawMockConsensusState { RawMockConsensusState { header: Some(ibc_proto::ibc::mock::Header { height: Some(value.header.height().into()), - timestamp: value.header.timestamp.as_nanoseconds(), + timestamp: value.header.timestamp.nanoseconds(), }), } } @@ -171,10 +187,6 @@ impl ConsensusState for MockConsensusState { &self.root } - fn validate_basic(&self) -> Result<(), Infallible> { - Ok(()) - } - fn wrap_any(self) -> AnyConsensusState { AnyConsensusState::Mock(self) } diff --git a/modules/src/mock/context.rs b/modules/src/mock/context.rs index 63920fedc..badc1c93c 100644 --- a/modules/src/mock/context.rs +++ b/modules/src/mock/context.rs @@ -1,45 +1,52 @@ //! Implementation of a global context mock. Used in testing handlers of all IBC modules. use crate::prelude::*; -use alloc::collections::btree_map::BTreeMap as HashMap; + +use alloc::collections::btree_map::BTreeMap; use core::cmp::min; +use core::ops::{Add, Sub}; +use core::time::Duration; use prost_types::Any; use sha2::Digest; - -use crate::application::ics20_fungible_token_transfer::context::Ics20Context; +use tracing::debug; + +use crate::applications::ics20_fungible_token_transfer::context::Ics20Context; +use crate::clients::ics07_tendermint::client_state::test_util::get_dummy_tendermint_client_state; +use crate::core::ics02_client::client_consensus::{AnyConsensusState, AnyConsensusStateWithHeight}; +use crate::core::ics02_client::client_state::AnyClientState; +use crate::core::ics02_client::client_type::ClientType; +use crate::core::ics02_client::context::{ClientKeeper, ClientReader}; +use crate::core::ics02_client::error::Error as Ics02Error; +use crate::core::ics02_client::header::AnyHeader; +use crate::core::ics03_connection::connection::ConnectionEnd; +use crate::core::ics03_connection::context::{ConnectionKeeper, ConnectionReader}; +use crate::core::ics03_connection::error::Error as Ics03Error; +use crate::core::ics04_channel::channel::ChannelEnd; +use crate::core::ics04_channel::context::{ChannelKeeper, ChannelReader}; +use crate::core::ics04_channel::error::Error as Ics04Error; +use crate::core::ics04_channel::packet::{Receipt, Sequence}; +use crate::core::ics05_port::capabilities::{Capability, CapabilityName}; +use crate::core::ics05_port::context::{CapabilityReader, PortReader}; +use crate::core::ics05_port::error::Error as Ics05Error; +use crate::core::ics05_port::error::Error; +use crate::core::ics23_commitment::commitment::CommitmentPrefix; +use crate::core::ics24_host::identifier::{ChainId, ChannelId, ClientId, ConnectionId, PortId}; +use crate::core::ics26_routing::context::Ics26Context; +use crate::core::ics26_routing::handler::{deliver, dispatch}; +use crate::core::ics26_routing::msgs::Ics26Envelope; use crate::events::IbcEvent; -use crate::ics02_client::client_consensus::{AnyConsensusState, AnyConsensusStateWithHeight}; -use crate::ics02_client::client_state::AnyClientState; -use crate::ics02_client::client_type::ClientType; -use crate::ics02_client::context::{ClientKeeper, ClientReader}; -use crate::ics02_client::error::Error as Ics02Error; -use crate::ics02_client::header::AnyHeader; -use crate::ics03_connection::connection::ConnectionEnd; -use crate::ics03_connection::context::{ConnectionKeeper, ConnectionReader}; -use crate::ics03_connection::error::Error as Ics03Error; -use crate::ics04_channel::channel::ChannelEnd; -use crate::ics04_channel::context::{ChannelKeeper, ChannelReader}; -use crate::ics04_channel::error::Error as Ics04Error; -use crate::ics04_channel::packet::{Receipt, Sequence}; -use crate::ics05_port::capabilities::Capability; -use crate::ics05_port::context::PortReader; -use crate::ics05_port::error::Error as Ics05Error; -use crate::ics07_tendermint::client_state::test_util::get_dummy_tendermint_client_state; -use crate::ics18_relayer::context::Ics18Context; -use crate::ics18_relayer::error::Error as Ics18Error; -use crate::ics23_commitment::commitment::CommitmentPrefix; -use crate::ics24_host::identifier::{ChainId, ChannelId, ClientId, ConnectionId, PortId}; -use crate::ics26_routing::context::Ics26Context; -use crate::ics26_routing::handler::{deliver, dispatch}; -use crate::ics26_routing::msgs::Ics26Envelope; use crate::mock::client_state::{MockClientRecord, MockClientState, MockConsensusState}; use crate::mock::header::MockHeader; use crate::mock::host::{HostBlock, HostType}; +use crate::relayer::ics18_relayer::context::Ics18Context; +use crate::relayer::ics18_relayer::error::Error as Ics18Error; use crate::signer::Signer; use crate::timestamp::Timestamp; use crate::Height; +pub const DEFAULT_BLOCK_TIME_SECS: u64 = 3; + /// A context implementing the dependencies necessary for testing any IBC module. #[derive(Clone, Debug)] pub struct MockContext { @@ -52,60 +59,63 @@ pub struct MockContext { /// Maximum size for the history of the host chain. Any block older than this is pruned. max_history_size: usize, - /// Highest height (i.e., most recent) of the blocks in the history. - latest_height: Height, - - /// Highest timestamp, i.e., of the most recent block in the history. - timestamp: Timestamp, - /// The chain of blocks underlying this context. A vector of size up to `max_history_size` /// blocks, ascending order by their height (latest block is on the last position). history: Vec, /// The set of all clients, indexed by their id. - clients: HashMap, + clients: BTreeMap, + + /// Tracks the processed time for clients header updates + client_processed_times: BTreeMap<(ClientId, Height), Timestamp>, + + /// Tracks the processed height for the clients + client_processed_heights: BTreeMap<(ClientId, Height), Height>, /// Counter for the client identifiers, necessary for `increase_client_counter` and the /// `client_counter` methods. client_ids_counter: u64, /// Association between client ids and connection ids. - client_connections: HashMap, + client_connections: BTreeMap, /// All the connections in the store. - connections: HashMap, + connections: BTreeMap, /// Counter for connection identifiers (see `increase_connection_counter`). connection_ids_counter: u64, /// Association between connection ids and channel ids. - connection_channels: HashMap>, + connection_channels: BTreeMap>, /// Counter for channel identifiers (see `increase_channel_counter`). channel_ids_counter: u64, /// All the channels in the store. TODO Make new key PortId X ChanneId - channels: HashMap<(PortId, ChannelId), ChannelEnd>, + channels: BTreeMap<(PortId, ChannelId), ChannelEnd>, /// Tracks the sequence number for the next packet to be sent. - next_sequence_send: HashMap<(PortId, ChannelId), Sequence>, + next_sequence_send: BTreeMap<(PortId, ChannelId), Sequence>, /// Tracks the sequence number for the next packet to be received. - next_sequence_recv: HashMap<(PortId, ChannelId), Sequence>, + next_sequence_recv: BTreeMap<(PortId, ChannelId), Sequence>, /// Tracks the sequence number for the next packet to be acknowledged. - next_sequence_ack: HashMap<(PortId, ChannelId), Sequence>, + next_sequence_ack: BTreeMap<(PortId, ChannelId), Sequence>, - packet_acknowledgement: HashMap<(PortId, ChannelId, Sequence), String>, + packet_acknowledgement: BTreeMap<(PortId, ChannelId, Sequence), String>, /// Maps ports to their capabilities - port_capabilities: HashMap, + port_capabilities: BTreeMap, /// Constant-size commitments to packets data fields - packet_commitment: HashMap<(PortId, ChannelId, Sequence), String>, + packet_commitment: BTreeMap<(PortId, ChannelId, Sequence), String>, // Used by unordered channel - packet_receipt: HashMap<(PortId, ChannelId, Sequence), Receipt>, + packet_receipt: BTreeMap<(PortId, ChannelId, Sequence), Receipt>, + + /// Average time duration between blocks + block_time: Duration, } /// Returns a MockContext with bare minimum initialization: no clients, no connections and no channels are @@ -140,7 +150,12 @@ impl MockContext { "The chain must have a non-zero max_history_size" ); - // Compute the number of blocks to store. If latest_height is 0, nothing is stored. + assert_ne!( + latest_height.revision_height, 0, + "The chain must have a non-zero max_history_size" + ); + + // Compute the number of blocks to store. let n = min(max_history_size as u64, latest_height.revision_height); assert_eq!( @@ -149,25 +164,32 @@ impl MockContext { "The version in the chain identifier must match the version in the latest height" ); + let block_time = Duration::from_secs(DEFAULT_BLOCK_TIME_SECS); + let next_block_timestamp = Timestamp::now().add(block_time).unwrap(); MockContext { host_chain_type: host_type, host_chain_id: host_id.clone(), max_history_size, - latest_height, - timestamp: Default::default(), history: (0..n) .rev() .map(|i| { + // generate blocks with timestamps -> N, N - BT, N - 2BT, ... + // where N = now(), BT = block_time HostBlock::generate_block( host_id.clone(), host_type, latest_height.sub(i).unwrap().revision_height, + next_block_timestamp + .sub(Duration::from_secs(DEFAULT_BLOCK_TIME_SECS * (i + 1))) + .unwrap(), ) }) .collect(), connections: Default::default(), client_ids_counter: 0, clients: Default::default(), + client_processed_times: Default::default(), + client_processed_heights: Default::default(), client_connections: Default::default(), channels: Default::default(), connection_channels: Default::default(), @@ -180,6 +202,7 @@ impl MockContext { packet_acknowledgement: Default::default(), connection_ids_counter: 0, channel_ids_counter: 0, + block_time, } } @@ -209,7 +232,7 @@ impl MockContext { let (client_state, consensus_state) = match client_type { // If it's a mock client, create the corresponding mock states. ClientType::Mock => ( - Some(MockClientState(MockHeader::new(client_state_height)).into()), + Some(MockClientState::new(MockHeader::new(client_state_height)).into()), MockConsensusState::new(MockHeader::new(cs_height)).into(), ), // If it's a Tendermint client, we need TM states. @@ -217,7 +240,9 @@ impl MockContext { let light_block = HostBlock::generate_tm_block( self.host_chain_id.clone(), cs_height.revision_height, + Timestamp::now(), ); + let consensus_state = AnyConsensusState::from(light_block.clone()); let client_state = get_dummy_tendermint_client_state(light_block.signed_header.header); @@ -229,6 +254,8 @@ impl MockContext { }; let consensus_states = vec![(cs_height, consensus_state)].into_iter().collect(); + debug!("consensus states: {:?}", consensus_states); + let client_record = MockClientRecord { client_type, client_state, @@ -238,6 +265,75 @@ impl MockContext { self } + pub fn with_client_parametrized_history( + mut self, + client_id: &ClientId, + client_state_height: Height, + client_type: Option, + consensus_state_height: Option, + ) -> Self { + let cs_height = consensus_state_height.unwrap_or(client_state_height); + let prev_cs_height = cs_height.clone().sub(1).unwrap_or(client_state_height); + + let client_type = client_type.unwrap_or(ClientType::Mock); + let now = Timestamp::now(); + + let (client_state, consensus_state) = match client_type { + // If it's a mock client, create the corresponding mock states. + ClientType::Mock => ( + Some(MockClientState::new(MockHeader::new(client_state_height)).into()), + MockConsensusState::new(MockHeader::new(cs_height)).into(), + ), + // If it's a Tendermint client, we need TM states. + ClientType::Tendermint => { + let light_block = HostBlock::generate_tm_block( + self.host_chain_id.clone(), + cs_height.revision_height, + now, + ); + + let consensus_state = AnyConsensusState::from(light_block.clone()); + let client_state = + get_dummy_tendermint_client_state(light_block.signed_header.header); + + // Return the tuple. + (Some(client_state), consensus_state) + } + }; + + let prev_consensus_state = match client_type { + // If it's a mock client, create the corresponding mock states. + ClientType::Mock => MockConsensusState::new(MockHeader::new(prev_cs_height)).into(), + // If it's a Tendermint client, we need TM states. + ClientType::Tendermint => { + let light_block = HostBlock::generate_tm_block( + self.host_chain_id.clone(), + prev_cs_height.revision_height, + now.sub(self.block_time).unwrap(), + ); + AnyConsensusState::from(light_block) + } + }; + + let consensus_states = vec![ + (prev_cs_height, prev_consensus_state), + (cs_height, consensus_state), + ] + .into_iter() + .collect(); + + debug!("consensus states: {:?}", consensus_states); + + let client_record = MockClientRecord { + client_type, + client_state, + consensus_states, + }; + + self.clients.insert(client_id.clone(), client_record); + self + } + /// Associates a connection to this context. pub fn with_connection( mut self, @@ -307,21 +403,18 @@ impl MockContext { } } - pub fn with_timestamp(self, timestamp: Timestamp) -> Self { - Self { timestamp, ..self } - } - pub fn with_height(self, target_height: Height) -> Self { - if target_height.revision_number > self.latest_height.revision_number { + let latest_height = self.latest_height(); + if target_height.revision_number > latest_height.revision_number { unimplemented!() - } else if target_height.revision_number < self.latest_height.revision_number { + } else if target_height.revision_number < latest_height.revision_number { panic!("Cannot rewind history of the chain to a smaller revision number!") - } else if target_height.revision_height < self.latest_height.revision_height { + } else if target_height.revision_height < latest_height.revision_height { panic!("Cannot rewind history of the chain to a smaller revision height!") - } else if target_height.revision_height > self.latest_height.revision_height { + } else if target_height.revision_height > latest_height.revision_height { // Repeatedly advance the host chain height till we hit the desired height let mut ctx = MockContext { ..self }; - while ctx.latest_height.revision_height < target_height.revision_height { + while ctx.latest_height().revision_height < target_height.revision_height { ctx.advance_host_chain_height() } ctx @@ -348,9 +441,9 @@ impl MockContext { /// Accessor for a block of the local (host) chain from this context. /// Returns `None` if the block at the requested height does not exist. - fn host_block(&self, target_height: Height) -> Option<&HostBlock> { + pub fn host_block(&self, target_height: Height) -> Option<&HostBlock> { let target = target_height.revision_height as usize; - let latest = self.latest_height.revision_height as usize; + let latest = self.latest_height().revision_height as usize; // Check that the block is not too advanced, nor has it been pruned. if (target > latest) || (target <= latest - self.history.len()) { @@ -362,10 +455,12 @@ impl MockContext { /// Triggers the advancing of the host chain, by extending the history of blocks (or headers). pub fn advance_host_chain_height(&mut self) { + let latest_block = self.history.last().expect("history cannot be empty"); let new_block = HostBlock::generate_block( self.host_chain_id.clone(), self.host_chain_type, - self.latest_height.increment().revision_height, + latest_block.height().increment().revision_height, + latest_block.timestamp().add(self.block_time).unwrap(), ); // Append the new header at the tip of the history. @@ -377,7 +472,6 @@ impl MockContext { // History is not full yet. self.history.push(new_block); } - self.latest_height = self.latest_height.increment(); } /// A datagram passes from the relayer to the IBC module (on host chain). @@ -402,7 +496,7 @@ impl MockContext { // Get the highest block. let lh = &self.history[self.history.len() - 1]; // Check latest is properly updated with highest header height. - if lh.height() != self.latest_height { + if lh.height() != self.latest_height() { return Err("latest height is not updated".to_string()); } } @@ -432,23 +526,61 @@ impl MockContext { }) .collect() } + + pub fn latest_client_states(&self, client_id: &ClientId) -> &AnyClientState { + self.clients[client_id].client_state.as_ref().unwrap() + } + + pub fn latest_consensus_states( + &self, + client_id: &ClientId, + height: &Height, + ) -> &AnyConsensusState { + self.clients[client_id] + .consensus_states + .get(height) + .unwrap() + } + + #[inline] + fn latest_height(&self) -> Height { + self.history + .last() + .expect("history cannot be empty") + .height() + } } impl Ics26Context for MockContext {} impl Ics20Context for MockContext {} +impl CapabilityReader for MockContext { + fn get_capability(&self, _name: &CapabilityName) -> Result { + todo!() + } + + fn authenticate_capability( + &self, + _name: &CapabilityName, + _capability: &Capability, + ) -> Result<(), Ics05Error> { + Ok(()) + } +} + impl PortReader for MockContext { - fn lookup_module_by_port(&self, port_id: &PortId) -> Result { + type ModuleId = (); + + fn lookup_module_by_port( + &self, + port_id: &PortId, + ) -> Result<(Self::ModuleId, Capability), Error> { match self.port_capabilities.get(port_id) { - Some(cap) => Ok(cap.clone()), + Some(mod_cap) => Ok(((), mod_cap.clone())), None => Err(Ics05Error::unknown_port(port_id.clone())), } } - - fn authenticate(&self, _cap: &Capability, _port_id: &PortId) -> bool { - true - } } impl ChannelReader for MockContext { @@ -492,8 +624,8 @@ impl ChannelReader for MockContext { fn authenticated_capability(&self, port_id: &PortId) -> Result { match PortReader::lookup_module_by_port(self, port_id) { - Ok(key) => { - if !PortReader::authenticate(self, &key, port_id) { + Ok((_, key)) => { + if !PortReader::authenticate(self, port_id.clone(), &key) { Err(Ics04Error::invalid_port_capability()) } else { Ok(key) @@ -572,16 +704,63 @@ impl ChannelReader for MockContext { } fn host_height(&self) -> Height { - self.latest_height + self.latest_height() } fn host_timestamp(&self) -> Timestamp { - self.timestamp + ClientReader::host_timestamp(self) + } + + fn host_consensus_state(&self, height: Height) -> Result { + ConnectionReader::host_consensus_state(self, height).map_err(Ics04Error::ics03_connection) + } + + fn pending_host_consensus_state(&self) -> Result { + ClientReader::pending_host_consensus_state(self) + .map_err(|e| Ics04Error::ics03_connection(Ics03Error::ics02_client(e))) + } + + fn client_update_time( + &self, + client_id: &ClientId, + height: Height, + ) -> Result { + match self + .client_processed_times + .get(&(client_id.clone(), height)) + { + Some(time) => Ok(*time), + None => Err(Ics04Error::processed_time_not_found( + client_id.clone(), + height, + )), + } + } + + fn client_update_height( + &self, + client_id: &ClientId, + height: Height, + ) -> Result { + match self + .client_processed_heights + .get(&(client_id.clone(), height)) + { + Some(height) => Ok(*height), + None => Err(Ics04Error::processed_height_not_found( + client_id.clone(), + height, + )), + } } fn channel_counter(&self) -> Result { Ok(self.channel_ids_counter) } + + fn max_expected_time_per_block(&self) -> Duration { + self.block_time + } } impl ChannelKeeper for MockContext { @@ -701,7 +880,7 @@ impl ConnectionReader for MockContext { } fn host_current_height(&self) -> Height { - self.latest_height + self.latest_height() } fn host_oldest_height(&self) -> Height { @@ -710,7 +889,7 @@ impl ConnectionReader for MockContext { } fn commitment_prefix(&self) -> CommitmentPrefix { - CommitmentPrefix::from(Vec::new()) + CommitmentPrefix::try_from(b"mock".to_vec()).unwrap() } fn client_consensus_state( @@ -724,10 +903,7 @@ impl ConnectionReader for MockContext { } fn host_consensus_state(&self, height: Height) -> Result { - match self.host_block(height) { - Some(block_ref) => Ok(block_ref.clone().into()), - None => Err(Ics03Error::missing_local_consensus_state(height)), - } + ClientReader::host_consensus_state(self, height).map_err(Ics03Error::ics02_client) } fn connection_counter(&self) -> Result { @@ -799,6 +975,84 @@ impl ClientReader for MockContext { } } + /// Search for the lowest consensus state higher than `height`. + fn next_consensus_state( + &self, + client_id: &ClientId, + height: Height, + ) -> Result, Ics02Error> { + let client_record = self + .clients + .get(client_id) + .ok_or_else(|| Ics02Error::client_not_found(client_id.clone()))?; + + // Get the consensus state heights and sort them in ascending order. + let mut heights: Vec = client_record.consensus_states.keys().cloned().collect(); + heights.sort(); + + // Search for next state. + for h in heights { + if h > height { + // unwrap should never happen, as the consensus state for h must exist + return Ok(Some( + client_record.consensus_states.get(&h).unwrap().clone(), + )); + } + } + Ok(None) + } + + /// Search for the highest consensus state lower than `height`. + fn prev_consensus_state( + &self, + client_id: &ClientId, + height: Height, + ) -> Result, Ics02Error> { + let client_record = self + .clients + .get(client_id) + .ok_or_else(|| Ics02Error::client_not_found(client_id.clone()))?; + + // Get the consensus state heights and sort them in descending order. + let mut heights: Vec = client_record.consensus_states.keys().cloned().collect(); + heights.sort_by(|a, b| b.cmp(a)); + + // Search for previous state. + for h in heights { + if h < height { + // unwrap should never happen, as the consensus state for h must exist + return Ok(Some( + client_record.consensus_states.get(&h).unwrap().clone(), + )); + } + } + Ok(None) + } + + fn host_height(&self) -> Height { + self.latest_height() + } + + fn host_timestamp(&self) -> Timestamp { + self.history + .last() + .expect("history cannot be empty") + .timestamp() + .add(self.block_time) + .unwrap() + } + + fn host_consensus_state(&self, height: Height) -> Result { + match self.host_block(height) { + Some(block_ref) => Ok(block_ref.clone().into()), + None => Err(Ics02Error::missing_local_consensus_state(height)), + } + } + + fn pending_host_consensus_state(&self) -> Result { + Err(Ics02Error::missing_local_consensus_state(Height::zero())) + } + fn client_counter(&self) -> Result { Ok(self.client_ids_counter) } @@ -856,6 +1110,30 @@ impl ClientKeeper for MockContext { fn increase_client_counter(&mut self) { self.client_ids_counter += 1 } + + fn store_update_time( + &mut self, + client_id: ClientId, + height: Height, + timestamp: Timestamp, + ) -> Result<(), Ics02Error> { + let _ = self + .client_processed_times + .insert((client_id, height), timestamp); + Ok(()) + } + + fn store_update_height( + &mut self, + client_id: ClientId, + height: Height, + host_height: Height, + ) -> Result<(), Ics02Error> { + let _ = self + .client_processed_heights + .insert((client_id, height), host_height); + Ok(()) + } } impl Ics18Context for MockContext { @@ -888,12 +1166,12 @@ impl Ics18Context for MockContext { #[cfg(test)] mod tests { - use crate::ics24_host::identifier::ChainId; + use crate::core::ics24_host::identifier::ChainId; use crate::mock::context::MockContext; use crate::mock::host::HostType; use crate::prelude::*; use crate::Height; - use test_env_log::test; + use test_log::test; #[test] fn test_history_manipulation() { @@ -909,8 +1187,8 @@ mod tests { ctx: MockContext::new( ChainId::new("mockgaia".to_string(), cv), HostType::Mock, - 1, - Height::new(cv, 0), + 2, + Height::new(cv, 1), ), }, Test { @@ -918,8 +1196,8 @@ mod tests { ctx: MockContext::new( ChainId::new("mocksgaia".to_string(), cv), HostType::SyntheticTendermint, - 1, - Height::new(cv, 0), + 2, + Height::new(cv, 1), ), }, Test { @@ -1005,7 +1283,7 @@ mod tests { test.ctx ); - let current_height = test.ctx.latest_height; + let current_height = test.ctx.latest_height(); // After advancing the chain's height, the context should still be valid. test.ctx.advance_host_chain_height(); @@ -1018,7 +1296,8 @@ mod tests { let next_height = current_height.increment(); assert_eq!( - test.ctx.latest_height, next_height, + test.ctx.latest_height(), + next_height, "Failed while increasing height for context {:?}", test.ctx ); diff --git a/modules/src/mock/header.rs b/modules/src/mock/header.rs index 13af52f11..381975ae4 100644 --- a/modules/src/mock/header.rs +++ b/modules/src/mock/header.rs @@ -1,15 +1,13 @@ -use core::convert::TryFrom; - use serde_derive::{Deserialize, Serialize}; use tendermint_proto::Protobuf; use ibc_proto::ibc::mock::Header as RawMockHeader; -use crate::ics02_client::client_consensus::AnyConsensusState; -use crate::ics02_client::client_type::ClientType; -use crate::ics02_client::error::Error; -use crate::ics02_client::header::AnyHeader; -use crate::ics02_client::header::Header; +use crate::core::ics02_client::client_consensus::AnyConsensusState; +use crate::core::ics02_client::client_type::ClientType; +use crate::core::ics02_client::error::Error; +use crate::core::ics02_client::header::AnyHeader; +use crate::core::ics02_client::header::Header; use crate::mock::client_state::MockConsensusState; use crate::timestamp::Timestamp; use crate::Height; @@ -39,7 +37,7 @@ impl From for RawMockHeader { fn from(value: MockHeader) -> Self { RawMockHeader { height: Some(value.height.into()), - timestamp: value.timestamp.as_nanoseconds(), + timestamp: value.timestamp.nanoseconds(), } } } @@ -52,9 +50,13 @@ impl MockHeader { pub fn new(height: Height) -> Self { Self { height, - timestamp: Default::default(), + timestamp: Timestamp::now(), } } + + pub fn with_timestamp(self, timestamp: Timestamp) -> Self { + Self { timestamp, ..self } + } } impl From for AnyHeader { @@ -72,6 +74,10 @@ impl Header for MockHeader { self.height } + fn timestamp(&self) -> Timestamp { + self.timestamp + } + fn wrap_any(self) -> AnyHeader { AnyHeader::Mock(self) } @@ -89,14 +95,14 @@ mod tests { #[test] fn encode_any() { - let header = MockHeader::new(Height::new(1, 10)); + let header = MockHeader::new(Height::new(1, 10)).with_timestamp(Timestamp::none()); let bytes = header.wrap_any().encode_vec().unwrap(); assert_eq!( &bytes, &[ 10, 16, 47, 105, 98, 99, 46, 109, 111, 99, 107, 46, 72, 101, 97, 100, 101, 114, 18, - 6, 10, 4, 8, 1, 16, 10, + 6, 10, 4, 8, 1, 16, 10 ] ); } diff --git a/modules/src/mock/host.rs b/modules/src/mock/host.rs index 5409c1c56..d94b90f89 100644 --- a/modules/src/mock/host.rs +++ b/modules/src/mock/host.rs @@ -1,18 +1,15 @@ //! Host chain types and methods, used by context mock. -use crate::prelude::*; -use core::convert::TryFrom; - -use tendermint::chain::Id as TMChainId; use tendermint_testgen::light_block::TmLightBlock; use tendermint_testgen::{Generator, LightBlock as TestgenLightBlock}; -use crate::ics02_client::client_consensus::AnyConsensusState; -use crate::ics02_client::header::AnyHeader; -use crate::ics07_tendermint::consensus_state::ConsensusState as TMConsensusState; -use crate::ics07_tendermint::header::Header as TMHeader; -use crate::ics24_host::identifier::ChainId; +use crate::clients::ics07_tendermint::consensus_state::ConsensusState as TMConsensusState; +use crate::clients::ics07_tendermint::header::Header as TMHeader; +use crate::core::ics02_client::client_consensus::AnyConsensusState; +use crate::core::ics02_client::header::AnyHeader; +use crate::core::ics24_host::identifier::ChainId; use crate::mock::header::MockHeader; +use crate::prelude::*; use crate::timestamp::Timestamp; use crate::Height; @@ -47,24 +44,42 @@ impl HostBlock { } } + /// Returns the timestamp of a block. + pub fn timestamp(&self) -> Timestamp { + match self { + HostBlock::Mock(header) => header.timestamp, + HostBlock::SyntheticTendermint(light_block) => { + light_block.signed_header.header.time.into() + } + } + } + /// Generates a new block at `height` for the given chain identifier and chain type. - pub fn generate_block(chain_id: ChainId, chain_type: HostType, height: u64) -> HostBlock { + pub fn generate_block( + chain_id: ChainId, + chain_type: HostType, + height: u64, + timestamp: Timestamp, + ) -> HostBlock { match chain_type { HostType::Mock => HostBlock::Mock(MockHeader { height: Height::new(chain_id.version(), height), - timestamp: Timestamp::from_nanoseconds(1).unwrap(), + timestamp, }), - HostType::SyntheticTendermint => { - HostBlock::SyntheticTendermint(Box::new(Self::generate_tm_block(chain_id, height))) - } + HostType::SyntheticTendermint => HostBlock::SyntheticTendermint(Box::new( + Self::generate_tm_block(chain_id, height, timestamp), + )), } } - pub fn generate_tm_block(chain_id: ChainId, height: u64) -> TmLightBlock { - let mut block = TestgenLightBlock::new_default(height).generate().unwrap(); - block.signed_header.header.chain_id = TMChainId::try_from(chain_id.to_string()).unwrap(); - - block + pub fn generate_tm_block(chain_id: ChainId, height: u64, timestamp: Timestamp) -> TmLightBlock { + TestgenLightBlock::new_default_with_time_and_chain_id( + chain_id.to_string(), + timestamp.into_tm_time().unwrap(), + height, + ) + .generate() + .unwrap() } } diff --git a/modules/src/mock/misbehaviour.rs b/modules/src/mock/misbehaviour.rs index 8a3a8b7ba..1b4d01517 100644 --- a/modules/src/mock/misbehaviour.rs +++ b/modules/src/mock/misbehaviour.rs @@ -1,13 +1,12 @@ use crate::prelude::*; -use core::convert::{TryFrom, TryInto}; use tendermint_proto::Protobuf; use ibc_proto::ibc::mock::Misbehaviour as RawMisbehaviour; -use crate::ics02_client::error::Error; -use crate::ics02_client::misbehaviour::AnyMisbehaviour; -use crate::ics24_host::identifier::ClientId; +use crate::core::ics02_client::error::Error; +use crate::core::ics02_client::misbehaviour::AnyMisbehaviour; +use crate::core::ics24_host::identifier::ClientId; use crate::mock::header::MockHeader; use crate::Height; @@ -18,7 +17,7 @@ pub struct Misbehaviour { pub header2: MockHeader, } -impl crate::ics02_client::misbehaviour::Misbehaviour for Misbehaviour { +impl crate::core::ics02_client::misbehaviour::Misbehaviour for Misbehaviour { fn client_id(&self) -> &ClientId { &self.client_id } diff --git a/modules/src/prelude.rs b/modules/src/prelude.rs index 9ff42a989..bdce26208 100644 --- a/modules/src/prelude.rs +++ b/modules/src/prelude.rs @@ -9,3 +9,7 @@ pub use alloc::vec::Vec; pub use alloc::format; pub use alloc::vec; + +// Those are exported by default in the std prelude in Rust 2021 +pub use core::convert::{TryFrom, TryInto}; +pub use core::iter::FromIterator; diff --git a/modules/src/proofs.rs b/modules/src/proofs.rs index 91ec56969..30e84aa72 100644 --- a/modules/src/proofs.rs +++ b/modules/src/proofs.rs @@ -1,6 +1,6 @@ use serde::Serialize; -use crate::ics23_commitment::commitment::CommitmentProofBytes; +use crate::core::ics23_commitment::commitment::CommitmentProofBytes; use crate::Height; use flex_error::define_error; @@ -41,10 +41,6 @@ impl Proofs { return Err(ProofError::zero_height()); } - if object_proof.is_empty() { - return Err(ProofError::empty_proof()); - } - Ok(Self { object_proof, client_proof, @@ -96,9 +92,6 @@ impl ConsensusProof { if consensus_height.is_zero() { return Err(ProofError::zero_height()); } - if consensus_proof.is_empty() { - return Err(ProofError::empty_proof()); - } Ok(Self { proof: consensus_proof, diff --git a/modules/src/query.rs b/modules/src/query.rs index 68393ea38..9b7f035c8 100644 --- a/modules/src/query.rs +++ b/modules/src/query.rs @@ -1,7 +1,7 @@ use tendermint::abci::transaction::Hash; -use crate::ics02_client::client_consensus::QueryClientEventRequest; -use crate::ics04_channel::channel::QueryPacketEventDataRequest; +use crate::core::ics02_client::client_consensus::QueryClientEventRequest; +use crate::core::ics04_channel::channel::QueryPacketEventDataRequest; /// Used for queries and not yet standardized in channel's query.proto #[derive(Clone, Debug)] @@ -11,5 +11,10 @@ pub enum QueryTxRequest { Transaction(QueryTxHash), } +#[derive(Clone, Debug)] +pub enum QueryBlockRequest { + Packet(QueryPacketEventDataRequest), +} + #[derive(Clone, Debug)] pub struct QueryTxHash(pub Hash); diff --git a/modules/src/ics18_relayer/context.rs b/modules/src/relayer/ics18_relayer/context.rs similarity index 86% rename from modules/src/ics18_relayer/context.rs rename to modules/src/relayer/ics18_relayer/context.rs index 144392465..b6d10b514 100644 --- a/modules/src/ics18_relayer/context.rs +++ b/modules/src/relayer/ics18_relayer/context.rs @@ -1,12 +1,12 @@ use crate::prelude::*; use prost_types::Any; +use crate::core::ics02_client::client_state::AnyClientState; +use crate::core::ics02_client::header::AnyHeader; use crate::events::IbcEvent; -use crate::ics02_client::client_state::AnyClientState; -use crate::ics02_client::header::AnyHeader; -use crate::ics18_relayer::error::Error; -use crate::ics24_host::identifier::ClientId; +use crate::core::ics24_host::identifier::ClientId; +use crate::relayer::ics18_relayer::error::Error; use crate::signer::Signer; use crate::Height; /// Trait capturing all dependencies (i.e., the context) which algorithms in ICS18 require to diff --git a/modules/src/ics18_relayer/error.rs b/modules/src/relayer/ics18_relayer/error.rs similarity index 91% rename from modules/src/ics18_relayer/error.rs rename to modules/src/relayer/ics18_relayer/error.rs index eb75c7aa2..e975de5a3 100644 --- a/modules/src/ics18_relayer/error.rs +++ b/modules/src/relayer/ics18_relayer/error.rs @@ -1,5 +1,5 @@ -use crate::ics24_host::identifier::ClientId; -use crate::ics26_routing::error::Error as RoutingError; +use crate::core::ics24_host::identifier::ClientId; +use crate::core::ics26_routing::error::Error as RoutingError; use crate::Height; use flex_error::define_error; diff --git a/modules/src/relayer/ics18_relayer/mod.rs b/modules/src/relayer/ics18_relayer/mod.rs new file mode 100644 index 000000000..254c69aa4 --- /dev/null +++ b/modules/src/relayer/ics18_relayer/mod.rs @@ -0,0 +1,5 @@ +//! ICS 18: Relayer contains utilities for testing `ibc` against the Hermes relayer. + +pub mod context; +pub mod error; +pub mod utils; diff --git a/modules/src/ics18_relayer/utils.rs b/modules/src/relayer/ics18_relayer/utils.rs similarity index 83% rename from modules/src/ics18_relayer/utils.rs rename to modules/src/relayer/ics18_relayer/utils.rs index 4bf7671ed..34cd79cd7 100644 --- a/modules/src/ics18_relayer/utils.rs +++ b/modules/src/relayer/ics18_relayer/utils.rs @@ -1,9 +1,9 @@ -use crate::ics02_client::header::{AnyHeader, Header}; -use crate::ics02_client::msgs::update_client::MsgUpdateAnyClient; -use crate::ics02_client::msgs::ClientMsg; -use crate::ics18_relayer::context::Ics18Context; -use crate::ics18_relayer::error::Error; -use crate::ics24_host::identifier::ClientId; +use crate::core::ics02_client::header::{AnyHeader, Header}; +use crate::core::ics02_client::msgs::update_client::MsgUpdateAnyClient; +use crate::core::ics02_client::msgs::ClientMsg; +use crate::core::ics24_host::identifier::ClientId; +use crate::relayer::ics18_relayer::context::Ics18Context; +use crate::relayer::ics18_relayer::error::Error; /// Builds a `ClientMsg::UpdateClient` for a client with id `client_id` running on the `dest` /// context, assuming that the latest header on the source context is `src_header`. @@ -49,17 +49,18 @@ where #[cfg(test)] mod tests { - use crate::ics02_client::client_type::ClientType; - use crate::ics02_client::header::Header; - use crate::ics18_relayer::context::Ics18Context; - use crate::ics18_relayer::utils::build_client_update_datagram; - use crate::ics24_host::identifier::{ChainId, ClientId}; - use crate::ics26_routing::msgs::Ics26Envelope; + use crate::core::ics02_client::client_type::ClientType; + use crate::core::ics02_client::header::{AnyHeader, Header}; + use crate::core::ics24_host::identifier::{ChainId, ClientId}; + use crate::core::ics26_routing::msgs::Ics26Envelope; use crate::mock::context::MockContext; use crate::mock::host::HostType; use crate::prelude::*; + use crate::relayer::ics18_relayer::context::Ics18Context; + use crate::relayer::ics18_relayer::utils::build_client_update_datagram; use crate::Height; - use test_env_log::test; + use test_log::test; + use tracing::debug; #[test] /// Serves to test both ICS 26 `dispatch` & `build_client_update_datagram` functions. @@ -150,7 +151,17 @@ mod tests { // Update client on chain B to latest height of B. // - create the client update message with the latest header from B - let b_latest_header = ctx_b.query_latest_header().unwrap(); + // The test uses LightClientBlock that does not store the trusted height + let b_latest_header = match ctx_b.query_latest_header().unwrap() { + AnyHeader::Tendermint(header) => { + let th = header.height(); + let mut hheader = header.clone(); + hheader.trusted_height = th.decrement().unwrap(); + hheader.wrap_any() + } + AnyHeader::Mock(header) => header.wrap_any(), + }; + assert_eq!( b_latest_header.client_type(), ClientType::Tendermint, @@ -171,6 +182,8 @@ mod tests { let client_msg_a = client_msg_a_res.unwrap(); + debug!("client_msg_a = {:?}", client_msg_a); + // - send the message to A let dispatch_res_a = ctx_a.deliver(Ics26Envelope::Ics2Msg(client_msg_a)); let validation_res = ctx_a.validate(); diff --git a/modules/src/relayer/mod.rs b/modules/src/relayer/mod.rs new file mode 100644 index 000000000..e88996bcd --- /dev/null +++ b/modules/src/relayer/mod.rs @@ -0,0 +1,5 @@ +//! Utilities for testing the `ibc` crate against the [Hermes IBC relayer][relayer-repo]. +//! +//! [relayer-repo]: https://github.com/informalsystems/ibc-rs/tree/master/relayer + +pub mod ics18_relayer; diff --git a/modules/src/test.rs b/modules/src/test.rs index 45ba0d0aa..b6a9cb1f3 100644 --- a/modules/src/test.rs +++ b/modules/src/test.rs @@ -1,6 +1,5 @@ use core::fmt::Debug; use serde::{de::DeserializeOwned, Serialize}; -use std::println; /// Test that a struct `T` can be: /// @@ -22,9 +21,6 @@ where let parsed1 = serde_json::from_str::(&serialized); assert!(parsed1.is_ok()); - let parsed1 = parsed1.unwrap(); - println!("json_data0: {:?}", parsed0); - println!("json_data1: {:?}", parsed1); // TODO - fix PartialEq bound issue in AbciQuery //assert_eq!(parsed0, parsed1); diff --git a/modules/src/timestamp.rs b/modules/src/timestamp.rs index 9252880c9..7b14afae9 100644 --- a/modules/src/timestamp.rs +++ b/modules/src/timestamp.rs @@ -1,27 +1,39 @@ use crate::prelude::*; -use core::convert::TryInto; + use core::fmt::Display; -use core::num::{ParseIntError, TryFromIntError}; +use core::hash::{Hash, Hasher}; +use core::num::ParseIntError; use core::ops::{Add, Sub}; use core::str::FromStr; use core::time::Duration; -use chrono::{offset::Utc, DateTime, TimeZone}; use flex_error::{define_error, TraceError}; use serde_derive::{Deserialize, Serialize}; +use tendermint::Time; +use time::OffsetDateTime; pub const ZERO_DURATION: Duration = Duration::from_secs(0); -/// A newtype wrapper over `Option>` to keep track of +/// A newtype wrapper over `Option