diff --git a/.changelog/epilogue.md b/.changelog/epilogue.md index c10d8dd22f..ac2d169412 100644 --- a/.changelog/epilogue.md +++ b/.changelog/epilogue.md @@ -504,7 +504,7 @@ This release also finalizes the initial implementation of all the ICS 004 handle - Fix for chains that don't have `cosmos` account prefix ([#416]) - Fix for building the `trusted_validator_set` for the header used in client updates ([#770]) - Don't send `MsgAcknowledgment` if channel is closed ([#675]) - - Fix a bug where the keys addresses had their account prefix overriden by the prefix in the configuration ([#751]) + - Fix a bug where the keys addresses had their account prefix overridden by the prefix in the configuration ([#751]) - [ibc-relayer-cli] - Hermes guide: improved installation guideline ([#672]) @@ -642,7 +642,7 @@ Noteworthy changes in this release include: ### FEATURES -- Continous Integration (CI) end-to-end (e2e) testing with gaia v4 ([#32], [#582], [#602]) +- Continuous Integration (CI) end-to-end (e2e) testing with gaia v4 ([#32], [#582], [#602]) - Add support for streamlining releases ([#507]) - [ibc-relayer-cli] @@ -799,7 +799,7 @@ Special thanks to external contributors for this release: @CharlyCst ([#347], [# - CLI for client update message ([#277]) - Implement the relayer CLI for connection handshake messages ([#358], [#359], [#360]) - Implement the relayer CLI for channel handshake messages ([#371], [#372], [#373], [#374]) - - Added basic client, connection, and channel lifecyle in relayer v0 ([#376], [#377], [#378]) + - Added basic client, connection, and channel lifecycle in relayer v0 ([#376], [#377], [#378]) - Implement commands to add and list keys for a chain ([#363]) - Allow overriding of peer_id, height and hash in light add command ([#428]) - [proto-compiler] 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 index 94e4e72be4..9f337b3a5a 100644 --- 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 @@ -1,2 +1,2 @@ -- Improved documention w.r.t. keys for Ethermint-based chains +- Improved documentation 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.7.0/summary.md b/.changelog/v0.7.0/summary.md index e098cdbc39..33611b8472 100644 --- a/.changelog/v0.7.0/summary.md +++ b/.changelog/v0.7.0/summary.md @@ -1,3 +1,3 @@ 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. -Additionnally, Hermes now includes a REST server which exposes the relayer's internal state over HTTP. +Additionally, Hermes now includes a REST server which exposes the relayer's internal state over HTTP. diff --git a/.changelog/v1.10.0/bug-fixes/4034-ensure-no-dropped-events.md b/.changelog/v1.10.0/bug-fixes/4034-ensure-no-dropped-events.md new file mode 100644 index 0000000000..d0943e5245 --- /dev/null +++ b/.changelog/v1.10.0/bug-fixes/4034-ensure-no-dropped-events.md @@ -0,0 +1,3 @@ +- Fix a bug where in some cases, Hermes would drop all events in a + batch that came after an event rejected by the filtering policy + ([\#4034](https://github.com/informalsystems/hermes/issues/4034)) \ No newline at end of file diff --git a/.changelog/v1.10.0/bug-fixes/ibc-relayer/4021-chain-level-ccq-filter.md b/.changelog/v1.10.0/bug-fixes/ibc-relayer/4021-chain-level-ccq-filter.md new file mode 100644 index 0000000000..d3b2c7f51f --- /dev/null +++ b/.changelog/v1.10.0/bug-fixes/ibc-relayer/4021-chain-level-ccq-filter.md @@ -0,0 +1,2 @@ +- Discard CrossChain queries intended for unconfigured chains. + ([\#4021](https://github.com/informalsystems/hermes/issues/4021)) \ No newline at end of file diff --git a/.changelog/v1.10.0/features/ibc-integration-test/4046-test-authz.md b/.changelog/v1.10.0/features/ibc-integration-test/4046-test-authz.md new file mode 100644 index 0000000000..3082b737f2 --- /dev/null +++ b/.changelog/v1.10.0/features/ibc-integration-test/4046-test-authz.md @@ -0,0 +1,3 @@ +- Add tests to ensure that Hermes correctly relays transfer messages + from a grantee address with granted authorisation using `authz` module. + ([\#4046](https://github.com/informalsystems/hermes/issues/4046)) \ No newline at end of file diff --git a/.changelog/v1.10.0/features/ibc-relayer/4040-disable-ics31-icqs.md b/.changelog/v1.10.0/features/ibc-relayer/4040-disable-ics31-icqs.md new file mode 100644 index 0000000000..98ea3ddc6d --- /dev/null +++ b/.changelog/v1.10.0/features/ibc-relayer/4040-disable-ics31-icqs.md @@ -0,0 +1,3 @@ +- Add a new per-chain configuration `allow_ccq` to enable or disable + relaying of ICS31 Cross Chain Query packets. + ([\#4040](https://github.com/informalsystems/hermes/issues/4040)) \ No newline at end of file diff --git a/.changelog/v1.10.0/improvements/ibc-integration-test/4023-update-gaia-to-v17.md b/.changelog/v1.10.0/improvements/ibc-integration-test/4023-update-gaia-to-v17.md new file mode 100644 index 0000000000..4d833215f5 --- /dev/null +++ b/.changelog/v1.10.0/improvements/ibc-integration-test/4023-update-gaia-to-v17.md @@ -0,0 +1,2 @@ +- Update the version of Gaia running the integration tests in the CI from `v15.2.0` + to `v17.2.0` ([\#4023](https://github.com/informalsystems/hermes/issues/4023)) \ No newline at end of file diff --git a/.changelog/v1.10.0/improvements/ibc-integration-test/4024-update-osmosis-to-v25.md b/.changelog/v1.10.0/improvements/ibc-integration-test/4024-update-osmosis-to-v25.md new file mode 100644 index 0000000000..f1cbc137bc --- /dev/null +++ b/.changelog/v1.10.0/improvements/ibc-integration-test/4024-update-osmosis-to-v25.md @@ -0,0 +1,2 @@ +- Update the version of Osmosis running the integration tests in the CI from `v24.0.1` + to `v25.0.0` ([\#4024](https://github.com/informalsystems/hermes/issues/4024)) \ No newline at end of file diff --git a/.changelog/v1.10.0/improvements/ibc-integration-test/4025-update-juno-to-v22.md b/.changelog/v1.10.0/improvements/ibc-integration-test/4025-update-juno-to-v22.md new file mode 100644 index 0000000000..4744857094 --- /dev/null +++ b/.changelog/v1.10.0/improvements/ibc-integration-test/4025-update-juno-to-v22.md @@ -0,0 +1,2 @@ +- Update the version of Juno running the integration tests in the CI from `v21.0.0` + to `v22.0.0` ([\#4025](https://github.com/informalsystems/hermes/issues/4025)) \ No newline at end of file diff --git a/.changelog/v1.10.0/improvements/ibc-integration-test/4026-update-neutron-to-v305.md b/.changelog/v1.10.0/improvements/ibc-integration-test/4026-update-neutron-to-v305.md new file mode 100644 index 0000000000..360d0985eb --- /dev/null +++ b/.changelog/v1.10.0/improvements/ibc-integration-test/4026-update-neutron-to-v305.md @@ -0,0 +1,2 @@ +- Update the version of Neutron running the integration tests in the CI from `v3.0.2` + to `v3.0.5` ([\#4026](https://github.com/informalsystems/hermes/issues/4026)) \ No newline at end of file diff --git a/.changelog/v1.10.0/improvements/ibc-integration-test/4027-update-celestia-to-v1-11.md b/.changelog/v1.10.0/improvements/ibc-integration-test/4027-update-celestia-to-v1-11.md new file mode 100644 index 0000000000..0cd4d5746b --- /dev/null +++ b/.changelog/v1.10.0/improvements/ibc-integration-test/4027-update-celestia-to-v1-11.md @@ -0,0 +1,2 @@ +- Update the version of Celestia app running the integration tests in the CI from `v1.4.0` + to `v1.11.0` ([\#4027](https://github.com/informalsystems/hermes/issues/4027)) \ No newline at end of file diff --git a/.changelog/v1.10.0/improvements/ibc-integration-test/4029-update-wasmd-to-v051.md b/.changelog/v1.10.0/improvements/ibc-integration-test/4029-update-wasmd-to-v051.md new file mode 100644 index 0000000000..d9e00a1898 --- /dev/null +++ b/.changelog/v1.10.0/improvements/ibc-integration-test/4029-update-wasmd-to-v051.md @@ -0,0 +1,2 @@ +- Update the version of `wasmd` running the integration tests in the CI from `v0.50.0` + to `v0.51.0` ([\#4029](https://github.com/informalsystems/hermes/issues/4029)) \ No newline at end of file diff --git a/.changelog/v1.10.0/improvements/ibc-integration-test/4053-reduce-ics29-tests-run-time.md b/.changelog/v1.10.0/improvements/ibc-integration-test/4053-reduce-ics29-tests-run-time.md new file mode 100644 index 0000000000..88e727e88d --- /dev/null +++ b/.changelog/v1.10.0/improvements/ibc-integration-test/4053-reduce-ics29-tests-run-time.md @@ -0,0 +1,4 @@ +- Reduce run time for ICS29 tests by immediately verifying if either + the legacy fees, `recv_fee + ack_fee + timeout_fee` or current + fees, `max(recv_fee + ack_fee, timeout_fee)` have been escrowed. + ([\#4053](https://github.com/informalsystems/hermes/issues/4053)) \ No newline at end of file diff --git a/.changelog/v1.10.0/improvements/ibc-integration-test/4099-specify-topology-for-nary-tests.md b/.changelog/v1.10.0/improvements/ibc-integration-test/4099-specify-topology-for-nary-tests.md new file mode 100644 index 0000000000..b920789213 --- /dev/null +++ b/.changelog/v1.10.0/improvements/ibc-integration-test/4099-specify-topology-for-nary-tests.md @@ -0,0 +1,4 @@ +- Refactored the test-framework bootstrapping for n-ary chain tests + to utilize the specified topology. + * Currently, only linear, cyclic and fully connected topologies are supported. + ([\#4038](https://github.com/informalsystems/hermes/issues/4038)) \ No newline at end of file diff --git a/.changelog/v1.10.0/improvements/ibc-relayer/3979-add-custom-user-agent.md b/.changelog/v1.10.0/improvements/ibc-relayer/3979-add-custom-user-agent.md new file mode 100644 index 0000000000..4854632ae5 --- /dev/null +++ b/.changelog/v1.10.0/improvements/ibc-relayer/3979-add-custom-user-agent.md @@ -0,0 +1,2 @@ +- Use custom User-Agent for Hermes queries + ([\#3979](https://github.com/informalsystems/hermes/issues/3979)) diff --git a/.changelog/v1.10.0/improvements/ibc-relayer/4045-trim-whitespaces-channel-port-filter.md b/.changelog/v1.10.0/improvements/ibc-relayer/4045-trim-whitespaces-channel-port-filter.md new file mode 100644 index 0000000000..8cfcd2c1bc --- /dev/null +++ b/.changelog/v1.10.0/improvements/ibc-relayer/4045-trim-whitespaces-channel-port-filter.md @@ -0,0 +1,5 @@ +- Updated the channel and port filter parsing to ignore whitespaces. + This will prevent unintended channel scanning due to accidental + whitespaces when exact matches are specified in the `packet_filter` + configuration. + ([\#4045](https://github.com/informalsystems/hermes/issues/4045)) \ No newline at end of file diff --git a/.changelog/v1.10.0/improvements/ibc-relayer/4047-improve-excluded-sequences-config.md b/.changelog/v1.10.0/improvements/ibc-relayer/4047-improve-excluded-sequences-config.md new file mode 100644 index 0000000000..19de3111df --- /dev/null +++ b/.changelog/v1.10.0/improvements/ibc-relayer/4047-improve-excluded-sequences-config.md @@ -0,0 +1,11 @@ +- Improve the `excluded_sequences` configuration so that it now accepts + ranges of sequence values in addition to exact values. + Accepted format: + * Exact sequence, e.g. [1, 2, 3] + * "-" separator, e.g. ["1-3"] + + These can be combined making the following configurations equivalent: + * `excluded_sequences = { 'channel-0' = [1, "3-5", 7, "9-12"] }` + * `excluded_sequences = { 'channel-0' = [1, 3, 4, 5, 7, 9, 10, 11, 12] }` + + ([\#4047](https://github.com/informalsystems/hermes/issues/4047)) \ No newline at end of file diff --git a/.changelog/v1.10.0/summary.md b/.changelog/v1.10.0/summary.md new file mode 100644 index 0000000000..8da54c60a8 --- /dev/null +++ b/.changelog/v1.10.0/summary.md @@ -0,0 +1,11 @@ +*June 24th, 2024* + +This release enhances filter configurations and includes the following updates: + +1. `excluded_sequences` supports sequence ranges in addition to exact values, + e.g. `[1, 2, "5-10", 13]` is now valid. +2. `packet_filter` now ignores unintended whitespace. +3. A new `allow_ccq` per-chain configuration has been added to skip the relaying of + ICS31 Cross Chain Queries. + +Additionally, various improvements to testing and bug fixes have been implemented. diff --git a/.changelog/v1.10.1/breaking-changes/4093-update-ibc-proto-and-tendermint-rs.md b/.changelog/v1.10.1/breaking-changes/4093-update-ibc-proto-and-tendermint-rs.md new file mode 100644 index 0000000000..f87427d3a2 --- /dev/null +++ b/.changelog/v1.10.1/breaking-changes/4093-update-ibc-proto-and-tendermint-rs.md @@ -0,0 +1,3 @@ +- Bump version of `ibc-proto` from `v0.46.0` to `v0.47.0` and + version of `tendermint-rs` from `v0.37.0` to `v0.38.1`. + ([\#4093](https://github.com/informalsystems/hermes/issues/4093)) \ No newline at end of file diff --git a/.changelog/v1.10.1/improvements/ibc-integration-test/3195-add-pfm-ica-features-to-osmosis.md b/.changelog/v1.10.1/improvements/ibc-integration-test/3195-add-pfm-ica-features-to-osmosis.md new file mode 100644 index 0000000000..073bd29431 --- /dev/null +++ b/.changelog/v1.10.1/improvements/ibc-integration-test/3195-add-pfm-ica-features-to-osmosis.md @@ -0,0 +1,3 @@ +- Add the features `packet-forward` and `ica` to enable + Packet Forward Middleware and ICA when running tests with Osmosis + ([\#3195](https://github.com/informalsystems/hermes/issues/3195)) \ No newline at end of file diff --git a/.changelog/v1.10.1/improvements/ibc-relayer/4072-packet-clear-logs.md b/.changelog/v1.10.1/improvements/ibc-relayer/4072-packet-clear-logs.md new file mode 100644 index 0000000000..3ed50bd279 --- /dev/null +++ b/.changelog/v1.10.1/improvements/ibc-relayer/4072-packet-clear-logs.md @@ -0,0 +1,6 @@ +- Improve logs when clearing packet. + * When Hermes doesn't pull packet data it will now warn the user + instead of logging `pulled packet data for 0 events out of X` + * When ICS20 packets are filtered due to having a receiver or memo + field too big, the log will be at `warn` level instead of `debug`. + ([\#4072](https://github.com/informalsystems/hermes/issues/4072)) \ No newline at end of file diff --git a/.changelog/v1.10.1/summary.md b/.changelog/v1.10.1/summary.md new file mode 100644 index 0000000000..1d39539dad --- /dev/null +++ b/.changelog/v1.10.1/summary.md @@ -0,0 +1,5 @@ +*July 23th, 2024* + +In this release `tendermint-rs` has been updated to the latest version, addressing issues with the `/block_results` response. This ensures compatibility with CometBFT v0.38.10. + +And enhancements have been made to the logs regarding packet clearing, providing better insights and warnings for users. diff --git a/.changelog/v1.10.2/bug-fixes/ibc-relayer/4104-memo-overwrite-bug.md b/.changelog/v1.10.2/bug-fixes/ibc-relayer/4104-memo-overwrite-bug.md new file mode 100644 index 0000000000..785c896cc6 --- /dev/null +++ b/.changelog/v1.10.2/bug-fixes/ibc-relayer/4104-memo-overwrite-bug.md @@ -0,0 +1,3 @@ +- Fix the `memo_overwrite` configuration to correctly apply the + overwrite if it is configured. + ([\#4104](https://github.com/informalsystems/hermes/issues/4104)) \ No newline at end of file diff --git a/.changelog/v1.10.2/bug-fixes/ibc-telemetry/4145-fix-dynamic-gas-price-metric-name.md b/.changelog/v1.10.2/bug-fixes/ibc-telemetry/4145-fix-dynamic-gas-price-metric-name.md new file mode 100644 index 0000000000..fc0b9f836c --- /dev/null +++ b/.changelog/v1.10.2/bug-fixes/ibc-telemetry/4145-fix-dynamic-gas-price-metric-name.md @@ -0,0 +1,3 @@ +- Fix the `dynamic_gas_queried_success_fees` Prometheus metric name. + ([\#4104](https://github.com/informalsystems/hermes/issues/4104)) + \ No newline at end of file diff --git a/.changelog/v1.10.2/improvements/ibc-integration-test/4114-update-gaia-to-v18.md b/.changelog/v1.10.2/improvements/ibc-integration-test/4114-update-gaia-to-v18.md new file mode 100644 index 0000000000..eeb9978ca4 --- /dev/null +++ b/.changelog/v1.10.2/improvements/ibc-integration-test/4114-update-gaia-to-v18.md @@ -0,0 +1,2 @@ +- Update the version of Gaia running the integration tests in the CI from `v17.2.1` + to `v18.1.0` ([\#4114](https://github.com/informalsystems/hermes/issues/4114)) \ No newline at end of file diff --git a/.changelog/v1.10.2/improvements/ibc-integration-test/4115-update-provenance-to-v1-19-1.md b/.changelog/v1.10.2/improvements/ibc-integration-test/4115-update-provenance-to-v1-19-1.md new file mode 100644 index 0000000000..f09668d2fc --- /dev/null +++ b/.changelog/v1.10.2/improvements/ibc-integration-test/4115-update-provenance-to-v1-19-1.md @@ -0,0 +1,2 @@ +- Update the version of Provenance running the integration tests in the CI from `v1.17.0` + to `v1.19.1` ([\#4115](https://github.com/informalsystems/hermes/issues/4115)) \ No newline at end of file diff --git a/.changelog/v1.10.2/improvements/ibc-integration-test/4116-update-osmosis-to-v25-2-0.md b/.changelog/v1.10.2/improvements/ibc-integration-test/4116-update-osmosis-to-v25-2-0.md new file mode 100644 index 0000000000..c97282cd12 --- /dev/null +++ b/.changelog/v1.10.2/improvements/ibc-integration-test/4116-update-osmosis-to-v25-2-0.md @@ -0,0 +1,2 @@ +- Update the version of Osmosis running the integration tests in the CI from `v25.0.0` + to `v25.2.0` ([\#4116](https://github.com/informalsystems/hermes/issues/4116)) \ No newline at end of file diff --git a/.changelog/v1.10.2/improvements/ibc-integration-test/4117-update-juno-to-v23.md b/.changelog/v1.10.2/improvements/ibc-integration-test/4117-update-juno-to-v23.md new file mode 100644 index 0000000000..c2f08e7bec --- /dev/null +++ b/.changelog/v1.10.2/improvements/ibc-integration-test/4117-update-juno-to-v23.md @@ -0,0 +1,2 @@ +- Update the version of Juno running the integration tests in the CI from `v22.0.0` + to `v23.0.0` ([\#4117](https://github.com/informalsystems/hermes/issues/4117)) \ No newline at end of file diff --git a/.changelog/v1.10.2/improvements/ibc-integration-test/4118-update-migaloo-to-v4-2-0.md b/.changelog/v1.10.2/improvements/ibc-integration-test/4118-update-migaloo-to-v4-2-0.md new file mode 100644 index 0000000000..772a0edc72 --- /dev/null +++ b/.changelog/v1.10.2/improvements/ibc-integration-test/4118-update-migaloo-to-v4-2-0.md @@ -0,0 +1,2 @@ +- Update the version of Migaloo Chain running the integration tests in the CI from `v4.1.3` + to `v4.2.0` ([\#4118](https://github.com/informalsystems/hermes/issues/4118)) \ No newline at end of file diff --git a/.changelog/v1.10.2/improvements/ibc-integration-test/4120-update-wasmd-to-v0-52.md b/.changelog/v1.10.2/improvements/ibc-integration-test/4120-update-wasmd-to-v0-52.md new file mode 100644 index 0000000000..d281b1a3ee --- /dev/null +++ b/.changelog/v1.10.2/improvements/ibc-integration-test/4120-update-wasmd-to-v0-52.md @@ -0,0 +1,2 @@ +- Update the version of `wasmd` running the integration tests in the CI from `v0.51.0` + to `v0.52.0` ([\#4120](https://github.com/informalsystems/hermes/issues/4120)) \ No newline at end of file diff --git a/.changelog/v1.10.2/improvements/ibc-integration-test/4121-update-stride-to-v23.md b/.changelog/v1.10.2/improvements/ibc-integration-test/4121-update-stride-to-v23.md new file mode 100644 index 0000000000..d867eefd47 --- /dev/null +++ b/.changelog/v1.10.2/improvements/ibc-integration-test/4121-update-stride-to-v23.md @@ -0,0 +1,2 @@ +- Update the version of Stride running the integration tests in the CI from `v21.0.0` + to `v23.0.1` ([\#4121](https://github.com/informalsystems/hermes/issues/4121)) \ No newline at end of file diff --git a/.changelog/v1.10.2/improvements/ibc-integration-test/4122-update-neutron-to-v4.md b/.changelog/v1.10.2/improvements/ibc-integration-test/4122-update-neutron-to-v4.md new file mode 100644 index 0000000000..009d9cc047 --- /dev/null +++ b/.changelog/v1.10.2/improvements/ibc-integration-test/4122-update-neutron-to-v4.md @@ -0,0 +1,2 @@ +- Update the version of Neutron running the integration tests in the CI from `v3.0.5` + to `v4.1.0` ([\#4122](https://github.com/informalsystems/hermes/issues/4122)) \ No newline at end of file diff --git a/.changelog/v1.10.2/improvements/ibc-relayer/4071-split-packet-clear-scheduling.md b/.changelog/v1.10.2/improvements/ibc-relayer/4071-split-packet-clear-scheduling.md new file mode 100644 index 0000000000..8aeec76505 --- /dev/null +++ b/.changelog/v1.10.2/improvements/ibc-relayer/4071-split-packet-clear-scheduling.md @@ -0,0 +1,4 @@ +- Add a new configuration `clear_limit` to specify the maximum number + of packets cleared every time packet clearing is triggered. + Defaults to 50. + ([\#4071](https://github.com/informalsystems/hermes/issues/4071)) \ No newline at end of file diff --git a/.changelog/v1.10.2/improvements/ibc-relayer/4101-add-pagination.md b/.changelog/v1.10.2/improvements/ibc-relayer/4101-add-pagination.md new file mode 100644 index 0000000000..912fdd9733 --- /dev/null +++ b/.changelog/v1.10.2/improvements/ibc-relayer/4101-add-pagination.md @@ -0,0 +1,3 @@ +- Paginate results of `query_packet_commitments` and `query_packet_acknowledgements` + queries to speed up the scanning phase. + ([\#4101](https://github.com/informalsystems/hermes/issues/4101)) \ No newline at end of file diff --git a/.changelog/v1.10.2/improvements/ibc-relayer/4143-use-connection-params-in-validate-params.md b/.changelog/v1.10.2/improvements/ibc-relayer/4143-use-connection-params-in-validate-params.md new file mode 100644 index 0000000000..81073cdfb7 --- /dev/null +++ b/.changelog/v1.10.2/improvements/ibc-relayer/4143-use-connection-params-in-validate-params.md @@ -0,0 +1,4 @@ +- Use the `ibc.core.connection.v1.ConnectionParams` gRPC query to retrieve `maxExpectedTimePerBlock` + and check it against the configured `max_block_time` instead of using the `/genesis` endpoint. + This improves both startup times and reliability for most chains. + ([\#4143](https://github.com/informalsystems/hermes/issues/4143)) \ No newline at end of file diff --git a/.changelog/v1.10.2/summary.md b/.changelog/v1.10.2/summary.md new file mode 100644 index 0000000000..220dccc7e8 --- /dev/null +++ b/.changelog/v1.10.2/summary.md @@ -0,0 +1 @@ +This release brings significant performance improvements and introduces a new configuration options for better control over packet clearing. Enhancements include faster startup times through optimized queries and the introduction of a `clear_limit` setting for packet clearing. Additionally, bug fixes and updates to the integration test framework ensure greater stability and compatibility across various environments. \ No newline at end of file diff --git a/.changelog/v1.10.3/bug-fixes/ibc-chain-registry/4160-explicit-rootls-config.md b/.changelog/v1.10.3/bug-fixes/ibc-chain-registry/4160-explicit-rootls-config.md new file mode 100644 index 0000000000..8bccf778ae --- /dev/null +++ b/.changelog/v1.10.3/bug-fixes/ibc-chain-registry/4160-explicit-rootls-config.md @@ -0,0 +1,2 @@ +- Add explicit root TLS configuration to gRPC clients + ([\#4160](https://github.com/informalsystems/hermes/issues/4160)) \ No newline at end of file diff --git a/.changelog/v1.10.3/bug-fixes/ibc-relayer-cli/3951-exclude-sequences-with-clear-cli.md b/.changelog/v1.10.3/bug-fixes/ibc-relayer-cli/3951-exclude-sequences-with-clear-cli.md new file mode 100644 index 0000000000..aca6d720ec --- /dev/null +++ b/.changelog/v1.10.3/bug-fixes/ibc-relayer-cli/3951-exclude-sequences-with-clear-cli.md @@ -0,0 +1,3 @@ +- Correctly filter out sequences from the `excluded_sequences` configuration + when clearing packets with the `clear packet` CLI. + ([\#4158](https://github.com/informalsystems/hermes/issues/4158)) \ No newline at end of file diff --git a/.changelog/v1.10.3/bug-fixes/ibc-relayer/4160-explicit-rootls-config.md b/.changelog/v1.10.3/bug-fixes/ibc-relayer/4160-explicit-rootls-config.md new file mode 100644 index 0000000000..8bccf778ae --- /dev/null +++ b/.changelog/v1.10.3/bug-fixes/ibc-relayer/4160-explicit-rootls-config.md @@ -0,0 +1,2 @@ +- Add explicit root TLS configuration to gRPC clients + ([\#4160](https://github.com/informalsystems/hermes/issues/4160)) \ No newline at end of file diff --git a/.changelog/v1.10.3/features/ibc-integration-test/4151-add-ibc-go-v9.md b/.changelog/v1.10.3/features/ibc-integration-test/4151-add-ibc-go-v9.md new file mode 100644 index 0000000000..806a0e0372 --- /dev/null +++ b/.changelog/v1.10.3/features/ibc-integration-test/4151-add-ibc-go-v9.md @@ -0,0 +1,2 @@ +- Add ibc-go `v9` to the chains running the integration tests in the CI. + ([\#4151](https://github.com/informalsystems/hermes/issues/4151)) \ No newline at end of file diff --git a/.changelog/v1.10.3/improvements/ibc-integration-test/4123-update-celestia-to-v1-14-0.md b/.changelog/v1.10.3/improvements/ibc-integration-test/4123-update-celestia-to-v1-14-0.md new file mode 100644 index 0000000000..6de196f323 --- /dev/null +++ b/.changelog/v1.10.3/improvements/ibc-integration-test/4123-update-celestia-to-v1-14-0.md @@ -0,0 +1,2 @@ +- Update the version of Celestia running the integration tests in the CI from `v1.11.0` + to `v1.14.0` ([\#4123](https://github.com/informalsystems/hermes/issues/4123)) \ No newline at end of file diff --git a/.changelog/v1.10.3/improvements/ibc-integration-test/4168-update-neutron-v4-2-2.md b/.changelog/v1.10.3/improvements/ibc-integration-test/4168-update-neutron-v4-2-2.md new file mode 100644 index 0000000000..1ca212bf53 --- /dev/null +++ b/.changelog/v1.10.3/improvements/ibc-integration-test/4168-update-neutron-v4-2-2.md @@ -0,0 +1,2 @@ +- Update the version of Neutron running the integration tests in the CI from `v4.1.0` + to `v4.2.2` ([\#4168](https://github.com/informalsystems/hermes/issues/4168)) \ No newline at end of file diff --git a/.changelog/v1.10.3/improvements/ibc-integration-test/4169-update-wasmd-to-v0-53-0.md b/.changelog/v1.10.3/improvements/ibc-integration-test/4169-update-wasmd-to-v0-53-0.md new file mode 100644 index 0000000000..3caa36c8e6 --- /dev/null +++ b/.changelog/v1.10.3/improvements/ibc-integration-test/4169-update-wasmd-to-v0-53-0.md @@ -0,0 +1,2 @@ +- Update the version of `wasmd` running the integration tests in the CI from `v0.52.0` + to `v0.53.0` ([\#4169](https://github.com/informalsystems/hermes/issues/4169)) \ No newline at end of file diff --git a/.changelog/v1.10.3/improvements/ibc-integration-test/4171-update-juno-v24.md b/.changelog/v1.10.3/improvements/ibc-integration-test/4171-update-juno-v24.md new file mode 100644 index 0000000000..e5d46c87f5 --- /dev/null +++ b/.changelog/v1.10.3/improvements/ibc-integration-test/4171-update-juno-v24.md @@ -0,0 +1,2 @@ +- Update the version of Juno running the integration tests in the CI from `v23.0.0` + to `v24.0.0` ([\#4171](https://github.com/informalsystems/hermes/issues/4171)) \ No newline at end of file diff --git a/.changelog/v1.10.3/improvements/ibc-relayer/4102-abci-query-during-health-check.md b/.changelog/v1.10.3/improvements/ibc-relayer/4102-abci-query-during-health-check.md new file mode 100644 index 0000000000..6f2613b12d --- /dev/null +++ b/.changelog/v1.10.3/improvements/ibc-relayer/4102-abci-query-during-health-check.md @@ -0,0 +1,3 @@ +- Use `abci_query` instead of gRPC queries when retrieving staking params + and service config during health-check, and when retrieving version information. + ([\#4102](https://github.com/informalsystems/hermes/issues/4102)) \ No newline at end of file diff --git a/.changelog/v1.10.3/summary.md b/.changelog/v1.10.3/summary.md new file mode 100644 index 0000000000..c7343de8ea --- /dev/null +++ b/.changelog/v1.10.3/summary.md @@ -0,0 +1,5 @@ +*September 2nd, 2024* + +This release fixes an issue where Hermes could not connect to gRPC servers over TLS. Additionally, this release also fixes a bug in the `clear packet` CLI where the `excluded_sequences` configuration option was not always taken into account. + +Furthermore, Hermes now uses `abci_query` instead of gRPC for some queries, for instance for querying staking parameters and service configuration during health checks, and when retrieving version information. diff --git a/.changelog/v1.10.4/bug-fixes/ibc-relayer/4204-fix-errors-logs.md b/.changelog/v1.10.4/bug-fixes/ibc-relayer/4204-fix-errors-logs.md new file mode 100644 index 0000000000..539ae153ef --- /dev/null +++ b/.changelog/v1.10.4/bug-fixes/ibc-relayer/4204-fix-errors-logs.md @@ -0,0 +1,3 @@ +- Fix error messages in logs to accurately display the RPC endpoint + that failed. + ([\#4250](https://github.com/informalsystems/hermes/issues/4250)) \ No newline at end of file diff --git a/.changelog/v1.10.4/bug-fixes/ibc-relayer/4237-improve-tls-configuration.md b/.changelog/v1.10.4/bug-fixes/ibc-relayer/4237-improve-tls-configuration.md new file mode 100644 index 0000000000..1c246d6aef --- /dev/null +++ b/.changelog/v1.10.4/bug-fixes/ibc-relayer/4237-improve-tls-configuration.md @@ -0,0 +1,3 @@ +- Fix an issue where Hermes would fail to connect to gRPC servers + with an IPv6 address. + ([\#4237](https://github.com/informalsystems/hermes/issues/4237)) \ No newline at end of file diff --git a/.changelog/v1.10.4/bug-fixes/ibc-relayer/4247-fix-chain-name-extraction.md b/.changelog/v1.10.4/bug-fixes/ibc-relayer/4247-fix-chain-name-extraction.md new file mode 100644 index 0000000000..6f538ac1d9 --- /dev/null +++ b/.changelog/v1.10.4/bug-fixes/ibc-relayer/4247-fix-chain-name-extraction.md @@ -0,0 +1,3 @@ +- Fix the extraction of the chain name from the chain ID to ensure + accurate identification. + ([\#4247](https://github.com/informalsystems/hermes/issues/4247)) \ No newline at end of file diff --git a/.changelog/v1.10.4/features/ibc-integration-test/4153-add-ipv6-test.md b/.changelog/v1.10.4/features/ibc-integration-test/4153-add-ipv6-test.md new file mode 100644 index 0000000000..8c7c3b98a7 --- /dev/null +++ b/.changelog/v1.10.4/features/ibc-integration-test/4153-add-ipv6-test.md @@ -0,0 +1,2 @@ +- Disable TLS configuration when using IPv6 for the gRPC endpoint. + ([\#4224](https://github.com/informalsystems/hermes/issues/4224)) \ No newline at end of file diff --git a/.changelog/v1.10.4/improvements/4178-compat-mode-infer.md b/.changelog/v1.10.4/improvements/4178-compat-mode-infer.md new file mode 100644 index 0000000000..b4a8a05d78 --- /dev/null +++ b/.changelog/v1.10.4/improvements/4178-compat-mode-infer.md @@ -0,0 +1,3 @@ +- Improve detection of Tendermint/CometBFT compatibility + mode when a chain runs a non-standard version + ([\#4178](https://github.com/informalsystems/hermes/issues/4178)) \ No newline at end of file diff --git a/.changelog/v1.10.4/improvements/ibc-integration-test/4202-update-simd-versions.md b/.changelog/v1.10.4/improvements/ibc-integration-test/4202-update-simd-versions.md new file mode 100644 index 0000000000..c35847633e --- /dev/null +++ b/.changelog/v1.10.4/improvements/ibc-integration-test/4202-update-simd-versions.md @@ -0,0 +1,7 @@ +- Update the versions of the following `simd` running the integration tests in the CI: + * From `v6.3.0` to `v6.3.1` + * From `v7.4.0` to `v7.8.0` + * From `v8.3.1` to `v8.5.1` + * From `v9.0.0-beta.1` to `v9.0.0-rc.0` + + ([\#4202](https://github.com/informalsystems/hermes/issues/4202)) \ No newline at end of file diff --git a/.changelog/v1.10.4/improvements/ibc-integration-test/4204-update-gaia-to-v20.md b/.changelog/v1.10.4/improvements/ibc-integration-test/4204-update-gaia-to-v20.md new file mode 100644 index 0000000000..2fcbe90beb --- /dev/null +++ b/.changelog/v1.10.4/improvements/ibc-integration-test/4204-update-gaia-to-v20.md @@ -0,0 +1,2 @@ +- Update the version of Gaia running the integration tests in the CI from `v18.1.0` + to `v20.0.0` ([\#4204](https://github.com/informalsystems/hermes/issues/4204)) \ No newline at end of file diff --git a/.changelog/v1.10.4/improvements/ibc-relayer/4153-update-misbehaviour-to-permissionless.md b/.changelog/v1.10.4/improvements/ibc-relayer/4153-update-misbehaviour-to-permissionless.md new file mode 100644 index 0000000000..65bbfe1c77 --- /dev/null +++ b/.changelog/v1.10.4/improvements/ibc-relayer/4153-update-misbehaviour-to-permissionless.md @@ -0,0 +1,2 @@ +- Use CCV consumer ID to submit misbehaviour messages + ([\#4153](https://github.com/informalsystems/hermes/issues/4153)) \ No newline at end of file diff --git a/.changelog/v1.10.4/improvements/ibc-relayer/4252-improve-redundant-packet-log.md b/.changelog/v1.10.4/improvements/ibc-relayer/4252-improve-redundant-packet-log.md new file mode 100644 index 0000000000..8bf8a29a8d --- /dev/null +++ b/.changelog/v1.10.4/improvements/ibc-relayer/4252-improve-redundant-packet-log.md @@ -0,0 +1,3 @@ +- Improve log message when broadcasting redundant packet and set it + to `INFO` instead of `ERROR`. + ([\#4252](https://github.com/informalsystems/hermes/issues/4252)) \ No newline at end of file diff --git a/.changelog/v1.10.4/summary.md b/.changelog/v1.10.4/summary.md new file mode 100644 index 0000000000..52fb5319d0 --- /dev/null +++ b/.changelog/v1.10.4/summary.md @@ -0,0 +1,3 @@ +*November 19th, 2024* + +This release introduces compatibility with the new Consumer ID for Permissionless ICS, improves detection of Tendermint/CometBFT versions for non-standard chains, and enhances IPv6 support for gRPC connections. Log messages have been refined for better clarity, including adjusting redundant packet broadcasts to INFO. diff --git a/.changelog/v1.10.5/improvements/ibc-integration-test/4203-update-juno-to-v25.md b/.changelog/v1.10.5/improvements/ibc-integration-test/4203-update-juno-to-v25.md new file mode 100644 index 0000000000..6d4407a557 --- /dev/null +++ b/.changelog/v1.10.5/improvements/ibc-integration-test/4203-update-juno-to-v25.md @@ -0,0 +1,2 @@ +- Update the version of Juno running the integration tests in the CI from `v24.0.0` + to `v25.0.0` ([\#4203](https://github.com/informalsystems/hermes/issues/4203)) \ No newline at end of file diff --git a/.changelog/v1.10.5/improvements/ibc-relayer/4263-collect-events-finalize-block.md b/.changelog/v1.10.5/improvements/ibc-relayer/4263-collect-events-finalize-block.md new file mode 100644 index 0000000000..e7e78897cf --- /dev/null +++ b/.changelog/v1.10.5/improvements/ibc-relayer/4263-collect-events-finalize-block.md @@ -0,0 +1,2 @@ +- Collect events from `finalized_block_events` when using `pull` mode + ([\#4263](https://github.com/informalsystems/hermes/issues/4263)) \ No newline at end of file diff --git a/.changelog/v1.10.5/summary.md b/.changelog/v1.10.5/summary.md new file mode 100644 index 0000000000..a959df702f --- /dev/null +++ b/.changelog/v1.10.5/summary.md @@ -0,0 +1,3 @@ +*December 13rd, 2024* + +This release addresses an issue with pull-mode event collection. The functionality has been enhanced to accurately retrieve events from `finalized_block_events`, ensuring more reliable event processing. \ No newline at end of file diff --git a/.changelog/v1.4.0/summary.md b/.changelog/v1.4.0/summary.md index ab025f4608..e4d1406036 100644 --- a/.changelog/v1.4.0/summary.md +++ b/.changelog/v1.4.0/summary.md @@ -1,16 +1,16 @@ *March 27th, 2023* Hermes v1.4.0 brings compatibility with chains based on Tendermint/CometBFT 0.37, -while retaining compatiblity with Tendermint/CometBFT 0.34. This is transparent +while retaining compatibility with Tendermint/CometBFT 0.34. This is transparent and does not require any additional configuration. The relayer now supports ICS consumer chains, which only requires operators to specify the `unbonding_period` parameter in the chain settings. This is only -a temporary requirement, in the future Hermes will seamlessy support consumer +a temporary requirement, in the future Hermes will seamlessly support consumer chains with minimal changes to the configuration. This release also deprecates support for chains based on Cosmos SDK 0.43.x and lower, -and bumps the compatiblity to Cosmos SDK 0.47.x. +and bumps the compatibility to Cosmos SDK 0.47.x. The relayer now also allows operators to filter out packets to relay based on whether or not they contain a fee, and the minimal amount of such fee. diff --git a/.changelog/v1.7.1/summary.md b/.changelog/v1.7.1/summary.md index 28905e6542..aedd51533f 100644 --- a/.changelog/v1.7.1/summary.md +++ b/.changelog/v1.7.1/summary.md @@ -3,7 +3,7 @@ at a different value for each chain, using the new per-chain `clear_interval` se The global `clear_interval` setting is used as a default value if the per-chain setting is not defined. -Additionnaly, operators can now override the CometBFT compatibility mode to be used +Additionally, operators can now override the CometBFT compatibility mode to be used for a chain by using the new `compat_mode` per-chain setting. The main use case for this is to override the automatically detected compatibility mode in case Hermes gets it wrong or encounters a non-standard version number and falls back on the wrong CometBFT version. diff --git a/.changelog/v1.8.1/bug-fixes/ibc-relayer/3770-non-utf8-packet-data.md b/.changelog/v1.8.1/bug-fixes/ibc-relayer/3770-non-utf8-packet-data.md new file mode 100644 index 0000000000..eae49f1583 --- /dev/null +++ b/.changelog/v1.8.1/bug-fixes/ibc-relayer/3770-non-utf8-packet-data.md @@ -0,0 +1,6 @@ +- Allow relaying ICS-04 packets with non-UTF-8 payloads ([\#3770](https://github.com/informalsystems/hermes/issues/3770)) + Hermes does not assume anymore that an ICS-04 packet data is valid UTF-8, + by using the `packet_data_hex` attribute when assembling a packet from events, instead of the deprecated `packet_data` attribute. + Relying on the `packet_data` attribute enforces a UTF-8 encoded payload (eg. JSON), disallowing eg. Protobuf-encoded payloads. + The `packet_data` attribute [has been deprecated][0] in favor of `packet_data_hex` since IBC-Go v1.0.0. + [0]: https://github.com/cosmos/ibc-go/blob/fadf8f2b0ab184798d021d220d877e00c7634e26/CHANGELOG.md?plain=1#L1417 diff --git a/.changelog/v1.8.1/bug-fixes/ibc-relayer/3831-better-compat-check.md b/.changelog/v1.8.1/bug-fixes/ibc-relayer/3831-better-compat-check.md new file mode 100644 index 0000000000..b533e98fe6 --- /dev/null +++ b/.changelog/v1.8.1/bug-fixes/ibc-relayer/3831-better-compat-check.md @@ -0,0 +1,2 @@ +- Improve reliability of compatibility check and fix parsing of expected modules + versions ([\#3831](https://github.com/informalsystems/hermes/issues/3831)) \ No newline at end of file diff --git a/.changelog/v1.8.1/features/ibc-relayer/3754-filter-packet-clearing.md b/.changelog/v1.8.1/features/ibc-relayer/3754-filter-packet-clearing.md new file mode 100644 index 0000000000..bdf29e069e --- /dev/null +++ b/.changelog/v1.8.1/features/ibc-relayer/3754-filter-packet-clearing.md @@ -0,0 +1,5 @@ +- Add a per-chain configuration `excluded_sequences` allowing + users to specify a list of packet sequences which will not be + cleared. + This configuration has no impact on standard packet relaying. + ([\#3754](https://github.com/informalsystems/hermes/issues/3754)) \ No newline at end of file diff --git a/.changelog/v1.8.1/features/ibc-relayer/3811-relayer-memo-overwrite.md b/.changelog/v1.8.1/features/ibc-relayer/3811-relayer-memo-overwrite.md new file mode 100644 index 0000000000..6a3a649a9e --- /dev/null +++ b/.changelog/v1.8.1/features/ibc-relayer/3811-relayer-memo-overwrite.md @@ -0,0 +1,3 @@ +- Add a per-chain configuration `memo_overwrite` allowing users + to overwrite the relayer memo used for each transaction + ([\#3811](https://github.com/informalsystems/hermes/issues/3811)) \ No newline at end of file diff --git a/.changelog/v1.8.1/features/ibc-telemetry/3845-add-simulate-errors-metric.md b/.changelog/v1.8.1/features/ibc-telemetry/3845-add-simulate-errors-metric.md new file mode 100644 index 0000000000..7e83a36b32 --- /dev/null +++ b/.changelog/v1.8.1/features/ibc-telemetry/3845-add-simulate-errors-metric.md @@ -0,0 +1,11 @@ +- Added a new Prometheus metric `simulate_errors` for tracking when a transaction simulation fails, with the following labels: + * `recoverable` (can the execution continue if this happened?) + * `account` (account from which the tx was sent) + * `error_description` (description of the error) + ([\#3845](https://github.com/informalsystems/hermes/issues/3845)) + + ``` + # HELP simulate_errors_total Number of errors observed by Hermes when simulating a Tx + # TYPE simulate_errors_total counter + simulate_errors_total{account="osmo17ndx5qfku28ymxgmq6zq4a6d02dvpfjjul0hyh",error_description="Unknown error",recoverable="false",service_name="unknown_service",otel_scope_name="hermes",otel_scope_version=""} 4 + ``` diff --git a/.changelog/v1.8.1/improvements/3814-grpc-syncing.md b/.changelog/v1.8.1/improvements/3814-grpc-syncing.md new file mode 100644 index 0000000000..877555aa43 --- /dev/null +++ b/.changelog/v1.8.1/improvements/3814-grpc-syncing.md @@ -0,0 +1,3 @@ +- Add syncing check for gRPC node ([#3814]) + +[#3814]: https://github.com/informalsystems/ibc-rs/issues/3814 diff --git a/.changelog/v1.8.1/improvements/3814-status-use-client-latest-height.md b/.changelog/v1.8.1/improvements/3814-status-use-client-latest-height.md new file mode 100644 index 0000000000..bf06bc6f8d --- /dev/null +++ b/.changelog/v1.8.1/improvements/3814-status-use-client-latest-height.md @@ -0,0 +1,3 @@ +- Use the consensus state at client latest height in status CLI ([#3814]) + +[#3814]: https://github.com/informalsystems/ibc-rs/issues/3814 diff --git a/.changelog/v1.8.1/improvements/ibc-relayer/3530-out-of-gas-error-log.md b/.changelog/v1.8.1/improvements/ibc-relayer/3530-out-of-gas-error-log.md new file mode 100644 index 0000000000..f1742da3ed --- /dev/null +++ b/.changelog/v1.8.1/improvements/ibc-relayer/3530-out-of-gas-error-log.md @@ -0,0 +1,4 @@ +- Improve the log diagnostic when an out of gas error is thrown. + And a new entry related to gas error has been added to the Hermes + guide. + ([\#3530](https://github.com/informalsystems/hermes/issues/3530)) \ No newline at end of file diff --git a/.changelog/v1.8.1/improvements/ibc-relayer/3540-ordered-channels-resilience.md b/.changelog/v1.8.1/improvements/ibc-relayer/3540-ordered-channels-resilience.md new file mode 100644 index 0000000000..88899c96f5 --- /dev/null +++ b/.changelog/v1.8.1/improvements/ibc-relayer/3540-ordered-channels-resilience.md @@ -0,0 +1,6 @@ +- Improve resilience when relaying on ordered channels. + When relaying packets on an ordered channel, Hermes will now attempt + to detect whether the next message to send has the sequence number + expected on that channel. If there is a mismatch, then Hermes will trigger a packet + clear on the channel to unblock it before resuming operations on that channel. + ([\#3540](https://github.com/informalsystems/hermes/issues/3540)) diff --git a/.changelog/v1.8.1/improvements/ibc-relayer/3792-legacy-simulation.md b/.changelog/v1.8.1/improvements/ibc-relayer/3792-legacy-simulation.md new file mode 100644 index 0000000000..f09d5088c1 --- /dev/null +++ b/.changelog/v1.8.1/improvements/ibc-relayer/3792-legacy-simulation.md @@ -0,0 +1,2 @@ +- Recover from gas simulation failures on legacy chains. + ([\#3792](https://github.com/informalsystems/hermes/issues/3792)) diff --git a/.changelog/v1.8.1/summary.md b/.changelog/v1.8.1/summary.md new file mode 100644 index 0000000000..40908d602b --- /dev/null +++ b/.changelog/v1.8.1/summary.md @@ -0,0 +1,19 @@ +*March 6th, 2024* + +This release improves reliability when relaying, more enhanced configuration and improved monitoring. + +Reliability has been improved: +* It is now possible to relay ICS-04 packets with non-UTF-8 payloads +* Packet sequences are now verified for ordered channels before trying to relay + +Additional per-chain configurations have been added: +* `excluded_sequences` used to skip problematic packets when clearing +* `memo_overwrite` allowing users to overwrite the relayer memo when chains have a +strict limit for the size of the memo + +Monitoring issues improvements: +* A new metric `simulate_errors` which counts the number of failed simulated transactions +* Out of gas error diagnostic gives more information and a dedicated entry to the guide has been added +* Failed gas simulation will not be considered as unrecoverable for legacy chains +* The compatibility check during the health-check has been improved will assess more correctly the versions + for Ibc-Go and Cosmos SDK diff --git a/.changelog/v1.8.2/bug-fixes/ibc-relayer-cli/3889-clear-packet-cli-fix.md b/.changelog/v1.8.2/bug-fixes/ibc-relayer-cli/3889-clear-packet-cli-fix.md new file mode 100644 index 0000000000..6470abd610 --- /dev/null +++ b/.changelog/v1.8.2/bug-fixes/ibc-relayer-cli/3889-clear-packet-cli-fix.md @@ -0,0 +1,3 @@ +- Correctly use the counterparty channel and port IDs when clearing the packets + from the destination chain to the source chain in the `packet clear` command + ([\#3889](https://github.com/informalsystems/hermes/issues/3889)) \ No newline at end of file diff --git a/.changelog/v1.8.2/bug-fixes/ibc-relayer/3880-health-check-fix.md b/.changelog/v1.8.2/bug-fixes/ibc-relayer/3880-health-check-fix.md new file mode 100644 index 0000000000..e6106fa10a --- /dev/null +++ b/.changelog/v1.8.2/bug-fixes/ibc-relayer/3880-health-check-fix.md @@ -0,0 +1,2 @@ +- Fix parsing of IBC-Go version in health check and improve health check + reporting ([\#3880](https://github.com/informalsystems/hermes/issues/3880)) \ No newline at end of file diff --git a/.changelog/v1.8.2/features/ibc-integration-test/3887-test-with-injective.md b/.changelog/v1.8.2/features/ibc-integration-test/3887-test-with-injective.md new file mode 100644 index 0000000000..5a9981b4e5 --- /dev/null +++ b/.changelog/v1.8.2/features/ibc-integration-test/3887-test-with-injective.md @@ -0,0 +1,2 @@ +- Add Injective chain to the chains running the integration tests in the CI. + ([\#3887](https://github.com/informalsystems/hermes/issues/3887)) \ No newline at end of file diff --git a/.changelog/v1.8.2/improvements/ibc-relayer/3864-handshake-retry.md b/.changelog/v1.8.2/improvements/ibc-relayer/3864-handshake-retry.md new file mode 100644 index 0000000000..45f5e18c86 --- /dev/null +++ b/.changelog/v1.8.2/improvements/ibc-relayer/3864-handshake-retry.md @@ -0,0 +1,3 @@ +- Change connection and channel handshake retry strategy + to retry at most 10 times (5 times per block max) + ([\#3864](https://github.com/informalsystems/hermes/issues/3864)) \ No newline at end of file diff --git a/.changelog/v1.8.2/summary.md b/.changelog/v1.8.2/summary.md new file mode 100644 index 0000000000..fba1f2ac82 --- /dev/null +++ b/.changelog/v1.8.2/summary.md @@ -0,0 +1,6 @@ +*March 12th, 2024* + +This release fixes the two following bugs and improves the connection and channel handshake retry mechanism: + +* Fix erroneous warnings for incompatible version of IBC-Go during health checks, ensuring accurate compatibility reporting +* Fix a bug in the `clear packets` command which caused packet clearing to fail with an "counterparty channel not found" error diff --git a/.changelog/v1.8.3/bug-fixes/ibc-relayer-cli/3999-duplicate-vote-fix-query.md b/.changelog/v1.8.3/bug-fixes/ibc-relayer-cli/3999-duplicate-vote-fix-query.md new file mode 100644 index 0000000000..a248e67ca2 --- /dev/null +++ b/.changelog/v1.8.3/bug-fixes/ibc-relayer-cli/3999-duplicate-vote-fix-query.md @@ -0,0 +1,2 @@ +- Fix the trusted height consensus state query when submitting the double vote evidence + ([\#3999](https://github.com/informalsystems/hermes/issues/3999)) diff --git a/.changelog/v1.8.3/summary.md b/.changelog/v1.8.3/summary.md new file mode 100644 index 0000000000..0495f558c3 --- /dev/null +++ b/.changelog/v1.8.3/summary.md @@ -0,0 +1 @@ +This patch release fixes a bug that may happen prevent the relayer from submitting the evidence for a duplicate vote in some cases. diff --git a/.changelog/v1.9.0/breaking-changes/ibc-telemetry/3878-remove-telemetry-flag.md b/.changelog/v1.9.0/breaking-changes/ibc-telemetry/3878-remove-telemetry-flag.md new file mode 100644 index 0000000000..aac1189638 --- /dev/null +++ b/.changelog/v1.9.0/breaking-changes/ibc-telemetry/3878-remove-telemetry-flag.md @@ -0,0 +1,3 @@ +- Remove the `telemetry` and `rest-server` feature flags, ensuring Hermes is always built with telemetry and REST support. + Both servers can still be disabled in the configuration file, by setting `telemetry.enabled = false` and `rest.enabled = false`, respectively. + ([\#3878](https://github.com/informalsystems/hermes/pull/3878)) diff --git a/.changelog/v1.9.0/bug-fixes/ibc-relayer-cli/3893-fix-min-gas-price-healthcheck.md b/.changelog/v1.9.0/bug-fixes/ibc-relayer-cli/3893-fix-min-gas-price-healthcheck.md new file mode 100644 index 0000000000..abe83a3a1a --- /dev/null +++ b/.changelog/v1.9.0/bug-fixes/ibc-relayer-cli/3893-fix-min-gas-price-healthcheck.md @@ -0,0 +1,2 @@ +- Fixed `minimum-gas-prices` health-check messages and make it more verbose and legible + ([\#3893](https://github.com/informalsystems/hermes/issues/3893)) diff --git a/.changelog/v1.9.0/bug-fixes/ibc-relayer-cli/3910-fix-subscribe-bug.md b/.changelog/v1.9.0/bug-fixes/ibc-relayer-cli/3910-fix-subscribe-bug.md new file mode 100644 index 0000000000..065ca533fe --- /dev/null +++ b/.changelog/v1.9.0/bug-fixes/ibc-relayer-cli/3910-fix-subscribe-bug.md @@ -0,0 +1,2 @@ +- Set `compat_mode` for pull mode in `hermes listen` command + ([\#3910](https://github.com/informalsystems/hermes/issues/3910)) \ No newline at end of file diff --git a/.changelog/v1.9.0/bug-fixes/ibc-relayer-cli/3999-duplicate-vote-fix-query.md b/.changelog/v1.9.0/bug-fixes/ibc-relayer-cli/3999-duplicate-vote-fix-query.md new file mode 100644 index 0000000000..8ba593c9a6 --- /dev/null +++ b/.changelog/v1.9.0/bug-fixes/ibc-relayer-cli/3999-duplicate-vote-fix-query.md @@ -0,0 +1,2 @@ +- Fixed the trusted height consensus state query when submitting the double vote evidence + ([\#3999](https://github.com/informalsystems/hermes/issues/3999)) diff --git a/.changelog/v1.9.0/bug-fixes/ibc-relayer/3817-deserialize-block-results.md b/.changelog/v1.9.0/bug-fixes/ibc-relayer/3817-deserialize-block-results.md new file mode 100644 index 0000000000..611643818d --- /dev/null +++ b/.changelog/v1.9.0/bug-fixes/ibc-relayer/3817-deserialize-block-results.md @@ -0,0 +1,3 @@ +- Fix creation of channels and connection on chains + using an unsupported version of ibc-go, eg. Sei + ([\#3817](https://github.com/informalsystems/hermes/issues/3817)) \ No newline at end of file diff --git a/.changelog/v1.9.0/bug-fixes/ibc-relayer/3954-interchainquery-missed-events.md b/.changelog/v1.9.0/bug-fixes/ibc-relayer/3954-interchainquery-missed-events.md new file mode 100644 index 0000000000..9ac2212acb --- /dev/null +++ b/.changelog/v1.9.0/bug-fixes/ibc-relayer/3954-interchainquery-missed-events.md @@ -0,0 +1,2 @@ +- Fix a bug where Hermes would only ever extract the first emitted ICS 031 CrossChain Query event, which would cause it to miss the other CCQ events. + ([\#3954](https://github.com/informalsystems/hermes/issues/3954)) \ No newline at end of file diff --git a/.changelog/v1.9.0/features/ibc-relayer/2547-channel-upgrades.md b/.changelog/v1.9.0/features/ibc-relayer/2547-channel-upgrades.md new file mode 100644 index 0000000000..869b7096d4 --- /dev/null +++ b/.changelog/v1.9.0/features/ibc-relayer/2547-channel-upgrades.md @@ -0,0 +1,2 @@ + - Add support for upgrading channels, as per the [ICS 004 specification](https://github.com/cosmos/ibc/blob/main/spec/core/ics-004-channel-and-packet-semantics/UPGRADES.md) ([#3228](https://github.com/informalsystems/hermes/issues/2547)) + This feature allows chains to upgrade an existing channel to take advantage of new features without having to create a new channel, thus preserving all existing packet state processed on the channel. For example, a channel could now be upgraded to enable the [ICS 029 fee middleware](https://ibc.cosmos.network/main/middleware/ics29-fee/overview), allowing relayer operators on that channel to receive fees each time they relay an incentivized packet. diff --git a/.changelog/v1.9.0/features/ibc-relayer/3894-continue-event-sourcing.md b/.changelog/v1.9.0/features/ibc-relayer/3894-continue-event-sourcing.md new file mode 100644 index 0000000000..f71ef4007e --- /dev/null +++ b/.changelog/v1.9.0/features/ibc-relayer/3894-continue-event-sourcing.md @@ -0,0 +1,6 @@ +- Improve reliability of event source in `pull` mode by proceeding to next block even if Hermes cannot parse the current block. + Add new configuration option to `event_source` setting: `max_retries` defines how many times Hermes should attempt to pull a block over RPC. + ```toml + event_source = { mode = 'pull', interval = '1s', max_retries = 4 } + ``` + ([\#3894](https://github.com/informalsystems/hermes/issues/3894)) diff --git a/.changelog/v1.9.0/improvements/ibc-integration-test/3959-update-juno-to-v21.md b/.changelog/v1.9.0/improvements/ibc-integration-test/3959-update-juno-to-v21.md new file mode 100644 index 0000000000..17a9b17a68 --- /dev/null +++ b/.changelog/v1.9.0/improvements/ibc-integration-test/3959-update-juno-to-v21.md @@ -0,0 +1,2 @@ +- Update the version of Juno running the integration tests in the CI from `v17.1.1` + to `v21.0.0` ([\#3959](https://github.com/informalsystems/hermes/issues/3959)) \ No newline at end of file diff --git a/.changelog/v1.9.0/improvements/ibc-integration-test/3960-update-migaloo-to-v4.md b/.changelog/v1.9.0/improvements/ibc-integration-test/3960-update-migaloo-to-v4.md new file mode 100644 index 0000000000..447e299663 --- /dev/null +++ b/.changelog/v1.9.0/improvements/ibc-integration-test/3960-update-migaloo-to-v4.md @@ -0,0 +1,3 @@ +- Update the version of Migaloo Chain running the + integration tests in the CI from `v3.0.2` to `v4.1.3` + ([\#3960](https://github.com/informalsystems/hermes/issues/3960)) \ No newline at end of file diff --git a/.changelog/v1.9.0/improvements/ibc-integration-test/3961-update-wasmd-to-v0-50.md b/.changelog/v1.9.0/improvements/ibc-integration-test/3961-update-wasmd-to-v0-50.md new file mode 100644 index 0000000000..b1847636bd --- /dev/null +++ b/.changelog/v1.9.0/improvements/ibc-integration-test/3961-update-wasmd-to-v0-50.md @@ -0,0 +1,3 @@ +- Update the version of `wasmd` running the + integration tests in the CI from `v0.30.0` to `v0.50.0` + ([\#3961](https://github.com/informalsystems/hermes/issues/3961)) \ No newline at end of file diff --git a/.changelog/v1.9.0/improvements/ibc-integration-test/4009-update-ibc-go-v8-ci.md b/.changelog/v1.9.0/improvements/ibc-integration-test/4009-update-ibc-go-v8-ci.md new file mode 100644 index 0000000000..ce8c7ee27e --- /dev/null +++ b/.changelog/v1.9.0/improvements/ibc-integration-test/4009-update-ibc-go-v8-ci.md @@ -0,0 +1,3 @@ +- Update the version of ibc-go simapp running the + integration tests in the CI from `v8.2.0` to `v8.3.1` + ([\#4009](https://github.com/informalsystems/hermes/issues/4009)) \ No newline at end of file diff --git a/.changelog/v1.9.0/improvements/ibc-relayer-cli/3913-config-auto-pull.md b/.changelog/v1.9.0/improvements/ibc-relayer-cli/3913-config-auto-pull.md new file mode 100644 index 0000000000..c19c7f34d6 --- /dev/null +++ b/.changelog/v1.9.0/improvements/ibc-relayer-cli/3913-config-auto-pull.md @@ -0,0 +1,2 @@ +- Use RPC (pull) event source instead of WebSocket (push) when generating configuration with `hermes config auto` + ([\#3913](https://github.com/informalsystems/hermes/issues/3913)) diff --git a/.changelog/v1.9.0/improvements/ibc-relayer/3895-tendermint-rs-0.35.md b/.changelog/v1.9.0/improvements/ibc-relayer/3895-tendermint-rs-0.35.md new file mode 100644 index 0000000000..fd27d9961e --- /dev/null +++ b/.changelog/v1.9.0/improvements/ibc-relayer/3895-tendermint-rs-0.35.md @@ -0,0 +1,2 @@ +- Update to tendermint-rs v0.35.0 + ([\#3895](https://github.com/informalsystems/hermes/issues/3895)) \ No newline at end of file diff --git a/.changelog/v1.9.0/improvements/ibc-relayer/3921-packet-ack-hex.md b/.changelog/v1.9.0/improvements/ibc-relayer/3921-packet-ack-hex.md new file mode 100644 index 0000000000..cd0f2c0aed --- /dev/null +++ b/.changelog/v1.9.0/improvements/ibc-relayer/3921-packet-ack-hex.md @@ -0,0 +1,2 @@ +- Use `packet_ack_hex` event attribute instead of deprecated `packet_ack` attribute to decode `WriteAck` event + ([\#3921](https://github.com/informalsystems/hermes/issues/3921)) diff --git a/.changelog/v1.9.0/improvements/ibc-relayer/3966-tendermint-rs-0.36.md b/.changelog/v1.9.0/improvements/ibc-relayer/3966-tendermint-rs-0.36.md new file mode 100644 index 0000000000..9d2d3f865e --- /dev/null +++ b/.changelog/v1.9.0/improvements/ibc-relayer/3966-tendermint-rs-0.36.md @@ -0,0 +1,2 @@ +- Update to tendermint-rs v0.36.0 + ([\#3966](https://github.com/informalsystems/hermes/issues/3966)) \ No newline at end of file diff --git a/.changelog/v1.9.0/improvements/ibc-relayer/4000-update-dynamic-gas-fee.md b/.changelog/v1.9.0/improvements/ibc-relayer/4000-update-dynamic-gas-fee.md new file mode 100644 index 0000000000..4c7123523a --- /dev/null +++ b/.changelog/v1.9.0/improvements/ibc-relayer/4000-update-dynamic-gas-fee.md @@ -0,0 +1,2 @@ +- Add support for dynamic gas fee for chains using Skip's [`x/feemarket`](https://github.com/skip-mev/feemarket) module, while keeping compatibility with Osmosis' bespoke implementation + ([\#4000](https://github.com/informalsystems/hermes/issues/4000)) \ No newline at end of file diff --git a/.changelog/v1.9.0/summary.md b/.changelog/v1.9.0/summary.md new file mode 100644 index 0000000000..8da025760a --- /dev/null +++ b/.changelog/v1.9.0/summary.md @@ -0,0 +1,11 @@ +*May 30th, 2024* + +This v1.9.0 release introduces new features and improvements to Hermes. + +**Major Features**: + +1. Channel Upgrade Compatibility: Hermes now supports channel upgrade events introduced in ibc-go v8, ensuring smoother transitions and enhanced functionality. + +3. Dynamic Gas Fees Compatibility: Hermes is now compatible with Skip's feemarket for dynamic gas fees, in addition to Osmosis' implementation, providing more flexibility in gas fee management. + +Additionally, this release includes various bug fixes enhancing the stability and performance of Hermes. These fixes address issues with channel and connection creation on unsupported ibc-go versions, event extraction, health-check messages, and more. diff --git a/.github/ISSUE_TEMPLATE/release-template.md b/.github/ISSUE_TEMPLATE/release-template.md index 1a80ba309f..960b3364ab 100644 --- a/.github/ISSUE_TEMPLATE/release-template.md +++ b/.github/ISSUE_TEMPLATE/release-template.md @@ -20,3 +20,4 @@ v without deliberation - [ ] Create a new release in the changelog, using [`unclog`](https://github.com/informalsystems/unclog) - If doing a release candidate (`rc`) version, then skip the `unclog release` step - [ ] Reassign unfinished issues of previous milestone to the next milestone +- [ ] Notify the comms team about the pending new release by tagging [@isa-belch](https://github.com/isa-belch) as a reviewer here diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index dc9bf1d7b8..90985e2118 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -25,6 +25,7 @@ ______ - [ ] Added tests: integration (for Hermes) or unit/mock tests (for modules). - [ ] Linked to GitHub issue. - [ ] Updated code comments and documentation (e.g., `docs/`). + - [ ] If guide has been updated, tag GitHub user `mircea-c` - [ ] Tagged *one* reviewer who will be the one responsible for shepherding this PR. ### Reviewer checklist: diff --git a/.github/codespell/codespell.ini b/.github/codespell/codespell.ini index 681ebbd0f1..2e8efedbbd 100644 --- a/.github/codespell/codespell.ini +++ b/.github/codespell/codespell.ini @@ -1,3 +1,3 @@ [codespell] -skip = *.js,*.ts,*.css,*.svg,*.html,*.json,./target,./tools/integration-test/data,./tools/check-guide/target,./ci/misbehaviour/data +skip = *.js,*.ts,*.css,*.svg,*.html,*.json,./target,./tools/integration-test/data,./tools/check-guide/target,./ci/misbehaviour/data,./.git ignore-words = .github/codespell/words.txt diff --git a/.github/workflows/cargo-doc.yaml b/.github/workflows/cargo-doc.yaml index ebc03618b6..9682a8456f 100644 --- a/.github/workflows/cargo-doc.yaml +++ b/.github/workflows/cargo-doc.yaml @@ -26,11 +26,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions-rs/toolchain@v1 + - uses: actions-rust-lang/setup-rust-toolchain@v1 with: - toolchain: nightly-2023-07-13 - override: true - + toolchain: nightly-2024-04-21 - name: Build API documentation uses: actions-rs/cargo@v1 env: @@ -41,7 +39,7 @@ jobs: - name: Push API documentation to GitHub Pages if: github.ref == 'refs/heads/master' - uses: peaceiris/actions-gh-pages@v3 + uses: peaceiris/actions-gh-pages@v4 with: deploy_key: ${{ secrets.IBC_RS_DOC_PRIVATE_KEY }} external_repository: informalsystems/hermes-api-doc diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index 6ad483e50d..7b82ed249f 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -17,6 +17,7 @@ jobs: - uses: actions/checkout@v4 - uses: codespell-project/actions-codespell@v2 with: - skip: '*.js,*.ts,*.css,*.svg,*.html,*.json,./target,./tools/integration-test/data,./tools/check-guide/target,./ci/misbehaviour/data' + skip: '*.js,*.ts,*.css,*.svg,*.html,*.json,./target,./tools/integration-test/data,./tools/check-guide/target,./ci/misbehaviour/data,./.git' ignore_words_file: .github/codespell/words.txt + check_hidden: true diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 5b3ac9891e..859dfa424c 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -31,6 +31,10 @@ jobs: uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY_IMAGE }} + tags: | + type=ref,event=tag + type=ref,event=branch + type=semver,pattern={{version}} - name: Set up QEMU uses: docker/setup-qemu-action@v3 @@ -47,7 +51,7 @@ jobs: - name: Build and push by digest id: build - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: . file: ./ci/release/hermes.Dockerfile @@ -91,6 +95,10 @@ jobs: uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY_IMAGE }} + tags: | + type=ref,event=tag + type=ref,event=branch + type=semver,pattern={{version}} - name: Login to Docker Hub uses: docker/login-action@v3 diff --git a/.github/workflows/guide-templates.yaml b/.github/workflows/guide-templates.yaml index 1d558a86cc..9eefc0d3fc 100644 --- a/.github/workflows/guide-templates.yaml +++ b/.github/workflows/guide-templates.yaml @@ -28,10 +28,9 @@ jobs: timeout-minutes: 60 steps: - uses: actions/checkout@v4 - - uses: actions-rs/toolchain@v1 + - uses: actions-rust-lang/setup-rust-toolchain@v1 with: toolchain: stable - override: true - name: Check templates run: bash scripts/auto_gen_templates.sh --mode "check" - uses: actions-rs/cargo@v1 diff --git a/.github/workflows/guide.yml b/.github/workflows/guide.yml index 5f37b5665e..869c5a4f6f 100644 --- a/.github/workflows/guide.yml +++ b/.github/workflows/guide.yml @@ -33,7 +33,7 @@ jobs: # Only deploy guide when releasing a new version of Hermes - name: Deploy to GitHub Pages - uses: peaceiris/actions-gh-pages@v3 + uses: peaceiris/actions-gh-pages@v4 if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') with: github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml index bc9f4a5427..fb98841907 100644 --- a/.github/workflows/integration.yaml +++ b/.github/workflows/integration.yaml @@ -45,31 +45,31 @@ jobs: fail-fast: false matrix: chain: - - package: gaia13 + - package: gaia20 command: gaiad account_prefix: cosmos native_token: stake - features: forward-packet,clean-workers - - package: gaia14 - command: gaiad - account_prefix: cosmos - native_token: stake - features: forward-packet,clean-workers + features: forward-packet,clean-workers,ica,ics29-fee - package: ibc-go-v6-simapp command: simd account_prefix: cosmos native_token: stake - features: ica,ics29-fee + features: ica,ics29-fee,authz - package: ibc-go-v7-simapp command: simd account_prefix: cosmos native_token: stake - features: ica,ics29-fee + features: ica,ics29-fee,authz - package: ibc-go-v8-simapp command: simd account_prefix: cosmos native_token: stake - features: ica,ics29-fee + features: ica,ics29-fee,new-register-interchain-account,channel-upgrade,authz + - package: ibc-go-v9-simapp + command: simd + account_prefix: cosmos + native_token: stake + features: ica,ics29-fee,new-register-interchain-account,channel-upgrade,authz,no-denom-trace - package: wasmd command: wasmd account_prefix: wasm @@ -79,39 +79,45 @@ jobs: command: osmosisd account_prefix: osmo native_token: stake - features: dynamic-gas-fee + features: dynamic-gas-fee,forward-packet,ica - package: juno command: junod account_prefix: juno native_token: stake - features: juno,forward-packet + features: juno,forward-packet,ica,ics29-fee - package: provenance command: provenanced account_prefix: pb native_token: nhash - features: fee-grant,async-icq + features: fee-grant,authz,async-icq - package: migaloo command: migalood account_prefix: migaloo native_token: stake - features: '' + features: ics29-fee,ica,forward-packet + # Disable Injective because wasmvm hasn't been correctly + # wired for Injective in Cosmos Nix + #- package: injective + # command: injectived + # account_prefix: inj + # native_token: stake + # features: forward-packet,fee-grant steps: - uses: actions/checkout@v4 - - uses: cachix/install-nix-action@v25 - 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@v14 - with: - name: cosmos - - uses: actions-rs/toolchain@v1 + - name: Install Nix + uses: DeterminateSystems/nix-installer-action@main + with: + extra-conf: | + substituters = https://cache.nixos.org + trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= + - name: Install Cachix + uses: cachix/cachix-action@v15 + with: + name: cosmos-nix + - uses: actions-rust-lang/setup-rust-toolchain@v1 with: toolchain: stable - override: true - - uses: Swatinem/rust-cache@v2 - uses: actions-rs/cargo@v1 with: command: test @@ -137,20 +143,19 @@ jobs: timeout-minutes: 60 steps: - uses: actions/checkout@v4 - - uses: cachix/install-nix-action@v25 - 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@v14 - with: - name: cosmos - - uses: actions-rs/toolchain@v1 + - name: Install Nix + uses: DeterminateSystems/nix-installer-action@main + with: + extra-conf: | + substituters = https://cache.nixos.org + trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= + - name: Install Cachix + uses: cachix/cachix-action@v15 + with: + name: cosmos-nix + - uses: actions-rust-lang/setup-rust-toolchain@v1 with: toolchain: stable - override: true - - uses: Swatinem/rust-cache@v2 - uses: actions-rs/cargo@v1 with: command: test @@ -167,84 +172,37 @@ jobs: cargo nextest run -p ibc-integration-test --no-fail-fast --failure-output final --test-threads=2 \ --features ordered test_ordered_channel - interchain-security-no-ica: - runs-on: ubuntu-20.04 - strategy: - fail-fast: false - matrix: - chain: - - package: .#gaia13 .#neutron - command: gaiad,neutrond - account_prefix: cosmos,neutron - - package: .#gaia14 .#neutron - command: gaiad,neutrond - account_prefix: cosmos,neutron - steps: - - uses: actions/checkout@v4 - - uses: cachix/install-nix-action@v25 - 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@v14 - with: - name: cosmos - - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - override: true - - uses: Swatinem/rust-cache@v2 - - uses: actions-rs/cargo@v1 - with: - command: test - args: -p ibc-integration-test --features interchain-security --no-fail-fast --no-run - - name: Install cargo-nextest - run: curl -LsSf https://get.nexte.st/latest/linux | tar zxf - -C ${CARGO_HOME:-~/.cargo}/bin - - env: - RUST_LOG: trace - RUST_BACKTRACE: 1 - NO_COLOR_LOG: 1 - NEXTEST_RETRIES: 2 - CHAIN_COMMAND_PATHS: ${{ matrix.chain.command }} - ACCOUNT_PREFIXES: ${{ matrix.chain.account_prefix }} - run: | - nix shell ${{ matrix.chain.package }} -c \ - cargo nextest run -p ibc-integration-test --no-fail-fast --failure-output final --test-threads=2 \ - --features interchain-security interchain_security:: - interchain-security-ica: runs-on: ubuntu-20.04 strategy: fail-fast: false matrix: chain: - - package: .#gaia13 .#stride-consumer - command: gaiad,strided - account_prefix: cosmos,stride - - package: .#gaia14 .#stride-consumer + - package: .#gaia20 .#stride command: gaiad,strided account_prefix: cosmos,stride + - package: .#gaia20 .#neutron + command: gaiad,neutrond + account_prefix: cosmos,neutron steps: - uses: actions/checkout@v4 - - uses: cachix/install-nix-action@v25 - 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@v14 - with: - name: cosmos - - uses: actions-rs/toolchain@v1 + - name: Install Nix + uses: DeterminateSystems/nix-installer-action@main + with: + extra-conf: | + substituters = https://cache.nixos.org + trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= + - name: Install Cachix + uses: cachix/cachix-action@v15 + with: + name: cosmos-nix + - uses: actions-rust-lang/setup-rust-toolchain@v1 with: toolchain: stable - override: true - - uses: Swatinem/rust-cache@v2 - uses: actions-rs/cargo@v1 with: command: test - args: -p ibc-integration-test --features interchain-security --no-fail-fast --no-run + args: -p ibc-integration-test --features interchain-security,ica --no-fail-fast --no-run - name: Install cargo-nextest run: curl -LsSf https://get.nexte.st/latest/linux | tar zxf - -C ${CARGO_HOME:-~/.cargo}/bin - env: @@ -260,33 +218,30 @@ jobs: --features interchain-security,ica interchain_security:: interchain-security-icq: + if: false # Disable CCQ test runs-on: ubuntu-20.04 strategy: fail-fast: false matrix: chain: - - package: .#gaia13 .#stride-consumer-no-admin - command: gaiad,strided - account_prefix: cosmos,stride - - package: .#gaia14 .#stride-consumer-no-admin + - package: .#gaia20 .#stride-no-admin command: gaiad,strided account_prefix: cosmos,stride steps: - uses: actions/checkout@v4 - - uses: cachix/install-nix-action@v25 - 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@v14 - with: - name: cosmos - - uses: actions-rs/toolchain@v1 + - name: Install Nix + uses: DeterminateSystems/nix-installer-action@main + with: + extra-conf: | + substituters = https://cache.nixos.org + trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= + - name: Install Cachix + uses: cachix/cachix-action@v15 + with: + name: cosmos-nix + - uses: actions-rust-lang/setup-rust-toolchain@v1 with: toolchain: stable - override: true - - uses: Swatinem/rust-cache@v2 - uses: actions-rs/cargo@v1 with: command: test @@ -310,30 +265,25 @@ jobs: fail-fast: false matrix: chain: - - package: .#celestia .#gaia13 - command: celestia-appd,gaiad - account_prefix: celestia,cosmos - native_token: utia,stake - - package: .#celestia .#gaia14 + - package: .#celestia .#gaia20 command: celestia-appd,gaiad account_prefix: celestia,cosmos native_token: utia,stake steps: - uses: actions/checkout@v4 - - uses: cachix/install-nix-action@v25 - 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@v14 - with: - name: cosmos - - uses: actions-rs/toolchain@v1 + - name: Install Nix + uses: DeterminateSystems/nix-installer-action@main + with: + extra-conf: | + substituters = https://cache.nixos.org + trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= + - name: Install Cachix + uses: cachix/cachix-action@v15 + with: + name: cosmos-nix + - uses: actions-rust-lang/setup-rust-toolchain@v1 with: toolchain: stable - override: true - - uses: Swatinem/rust-cache@v2 - uses: actions-rs/cargo@v1 with: command: test @@ -344,7 +294,7 @@ jobs: RUST_LOG: info RUST_BACKTRACE: 1 NO_COLOR_LOG: 1 - COMPAT_MODES: 0.34 + COMPAT_MODES: 0.34,0.37 CHAIN_COMMAND_PATHS: ${{ matrix.chain.command }} ACCOUNT_PREFIXES: ${{ matrix.chain.account_prefix }} NATIVE_TOKENS: ${{ matrix.chain.native_token }} @@ -353,42 +303,45 @@ jobs: cargo nextest run -p ibc-integration-test --no-fail-fast --failure-output final --test-threads=2 \ --features celestia - model-based-test: + # Run the transfer test using IPv6 for gRPC endpoint + ipv6-grpc-endpoint: runs-on: ubuntu-20.04 - timeout-minutes: 60 strategy: + fail-fast: false matrix: - gaiad: - - gaia6 + chain: + - package: .#gaia20 + command: gaiad + account_prefix: cosmos steps: - uses: actions/checkout@v4 - - uses: cachix/install-nix-action@v25 + - name: Install Nix + uses: DeterminateSystems/nix-installer-action@main 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@v14 + extra-conf: | + substituters = https://cache.nixos.org + trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= + - name: Install Cachix + uses: cachix/cachix-action@v15 with: - name: cosmos - - uses: actions-rs/toolchain@v1 + name: cosmos-nix + - uses: actions-rust-lang/setup-rust-toolchain@v1 with: toolchain: stable - override: true - - uses: Swatinem/rust-cache@v2 - uses: actions-rs/cargo@v1 with: command: test - args: -p ibc-integration-test --features mbt --no-fail-fast --no-run - # Disable running MBT tests until flakiness is addressed - # - env: - # RUST_LOG: debug - # RUST_BACKTRACE: 1 - # NO_COLOR_LOG: 1 - # run: | - # nix shell \ - # .#${{ matrix.gaiad }} \ - # .#apalache \ - # -c cargo \ - # test -p ibc-integration-test --features mbt --no-fail-fast -- \ - # --failure-output final --test-threads=2 --test-threads=1 mbt + args: -p ibc-integration-test --no-fail-fast --no-run + - name: Install cargo-nextest + run: curl -LsSf https://get.nexte.st/latest/linux | tar zxf - -C ${CARGO_HOME:-~/.cargo}/bin + - env: + RUST_LOG: info + RUST_BACKTRACE: 1 + NO_COLOR_LOG: 1 + CHAIN_COMMAND_PATHS: ${{ matrix.chain.command }} + ACCOUNT_PREFIXES: ${{ matrix.chain.account_prefix }} + IPV6_GRPC: true + run: | + nix shell ${{ matrix.chain.package }} -c \ + cargo nextest run -p ibc-integration-test --no-fail-fast --failure-output final --test-threads=2 \ + tests::transfer::test_ibc_transfer diff --git a/.github/workflows/markdown-link-check.yml b/.github/workflows/markdown-link-check.yml index f5da1e2a04..01c16456da 100644 --- a/.github/workflows/markdown-link-check.yml +++ b/.github/workflows/markdown-link-check.yml @@ -13,7 +13,7 @@ jobs: - uses: actions/checkout@v4 - name: Link Checker id: lychee - uses: lycheeverse/lychee-action@v1.9.3 + uses: lycheeverse/lychee-action@v1.10.0 with: args: --verbose --no-progress --max-concurrency 16 './**/*.md' token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/misbehaviour.yml b/.github/workflows/misbehaviour.yml index 629ce08faf..135ef7c9a1 100644 --- a/.github/workflows/misbehaviour.yml +++ b/.github/workflows/misbehaviour.yml @@ -43,22 +43,23 @@ jobs: fail-fast: false matrix: chain: - - package: gaia14 + - package: gaia20 command: gaiad account_prefix: cosmos steps: - uses: actions/checkout@v4 - name: Install Nix - uses: cachix/install-nix-action@v25 + uses: DeterminateSystems/nix-installer-action@main with: - extra_nix_config: | - experimental-features = nix-command flakes - - name: Use cachix cache - uses: cachix/cachix-action@v14 + extra-conf: | + substituters = https://cache.nixos.org + trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= + - name: Install Cachix + uses: cachix/cachix-action@v15 with: - name: cosmos + name: cosmos-nix - name: Install sconfig - uses: jaxxstorm/action-install-gh-release@v1.10.0 + uses: jaxxstorm/action-install-gh-release@v1.12.0 with: repo: freshautomations/sconfig platform: linux @@ -67,7 +68,7 @@ jobs: rename-to: sconfig chmod: 0755 - name: Install stoml - uses: jaxxstorm/action-install-gh-release@v1.10.0 + uses: jaxxstorm/action-install-gh-release@v1.12.0 with: repo: freshautomations/stoml platform: linux @@ -76,12 +77,9 @@ jobs: rename-to: stoml chmod: 0755 - name: Install Rust - uses: actions-rs/toolchain@v1 + uses: actions-rust-lang/setup-rust-toolchain@v1 with: toolchain: stable - override: true - - name: Use Rust cache - uses: Swatinem/rust-cache@v2 - name: Build Hermes uses: actions-rs/cargo@v1 with: @@ -103,16 +101,17 @@ jobs: steps: - uses: actions/checkout@v4 - name: Install Nix - uses: cachix/install-nix-action@v25 + uses: DeterminateSystems/nix-installer-action@main with: - extra_nix_config: | - experimental-features = nix-command flakes - - name: Use cachix cache - uses: cachix/cachix-action@v14 + extra-conf: | + substituters = https://cache.nixos.org + trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= + - name: Install Cachix + uses: cachix/cachix-action@v15 with: - name: cosmos + name: cosmos-nix - name: Install sconfig - uses: jaxxstorm/action-install-gh-release@v1.10.0 + uses: jaxxstorm/action-install-gh-release@v1.12.0 with: repo: freshautomations/sconfig platform: linux @@ -121,7 +120,7 @@ jobs: rename-to: sconfig chmod: 0755 - name: Install stoml - uses: jaxxstorm/action-install-gh-release@v1.10.0 + uses: jaxxstorm/action-install-gh-release@v1.12.0 with: repo: freshautomations/stoml platform: linux @@ -130,12 +129,9 @@ jobs: rename-to: stoml chmod: 0755 - name: Install Rust - uses: actions-rs/toolchain@v1 + uses: actions-rust-lang/setup-rust-toolchain@v1 with: toolchain: stable - override: true - - name: Use Rust cache - uses: Swatinem/rust-cache@v2 - name: Build Hermes uses: actions-rs/cargo@v1 with: @@ -157,16 +153,17 @@ jobs: steps: - uses: actions/checkout@v4 - name: Install Nix - uses: cachix/install-nix-action@v25 + uses: DeterminateSystems/nix-installer-action@main with: - extra_nix_config: | - experimental-features = nix-command flakes - - name: Use cachix cache - uses: cachix/cachix-action@v14 + extra-conf: | + substituters = https://cache.nixos.org + trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= + - name: Install Cachix + uses: cachix/cachix-action@v15 with: - name: cosmos + name: cosmos-nix - name: Install sconfig - uses: jaxxstorm/action-install-gh-release@v1.10.0 + uses: jaxxstorm/action-install-gh-release@v1.12.0 with: repo: freshautomations/sconfig platform: linux @@ -175,7 +172,7 @@ jobs: rename-to: sconfig chmod: 0755 - name: Install stoml - uses: jaxxstorm/action-install-gh-release@v1.10.0 + uses: jaxxstorm/action-install-gh-release@v1.12.0 with: repo: freshautomations/stoml platform: linux @@ -184,12 +181,9 @@ jobs: rename-to: stoml chmod: 0755 - name: Install Rust - uses: actions-rs/toolchain@v1 + uses: actions-rust-lang/setup-rust-toolchain@v1 with: toolchain: stable - override: true - - name: Use Rust cache - uses: Swatinem/rust-cache@v2 - name: Build Hermes uses: actions-rs/cargo@v1 with: @@ -199,7 +193,6 @@ jobs: run: | nix shell .#${{ matrix.chain.package }} -c bash light_client_attack_freeze_test.sh - ics-double-sign: runs-on: ubuntu-20.04 timeout-minutes: 20 @@ -212,16 +205,17 @@ jobs: steps: - uses: actions/checkout@v4 - name: Install Nix - uses: cachix/install-nix-action@v25 + uses: DeterminateSystems/nix-installer-action@main with: - extra_nix_config: | - experimental-features = nix-command flakes - - name: Use cachix cache - uses: cachix/cachix-action@v14 + extra-conf: | + substituters = https://cache.nixos.org + trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= + - name: Install Cachix + uses: cachix/cachix-action@v15 with: - name: cosmos + name: cosmos-nix - name: Install sconfig - uses: jaxxstorm/action-install-gh-release@v1.10.0 + uses: jaxxstorm/action-install-gh-release@v1.12.0 with: repo: freshautomations/sconfig platform: linux @@ -230,7 +224,7 @@ jobs: rename-to: sconfig chmod: 0755 - name: Install stoml - uses: jaxxstorm/action-install-gh-release@v1.10.0 + uses: jaxxstorm/action-install-gh-release@v1.12.0 with: repo: freshautomations/stoml platform: linux @@ -239,12 +233,9 @@ jobs: rename-to: stoml chmod: 0755 - name: Install Rust - uses: actions-rs/toolchain@v1 + uses: actions-rust-lang/setup-rust-toolchain@v1 with: toolchain: stable - override: true - - name: Use Rust cache - uses: Swatinem/rust-cache@v2 - name: Build Hermes uses: actions-rs/cargo@v1 with: @@ -253,4 +244,3 @@ jobs: working-directory: ci/misbehaviour-ics run: | nix shell .#${{ matrix.chain.package }} -c bash double_sign_test.sh - diff --git a/.github/workflows/multi-chains.yaml b/.github/workflows/multi-chains.yaml index 63edbede02..9aeb907848 100644 --- a/.github/workflows/multi-chains.yaml +++ b/.github/workflows/multi-chains.yaml @@ -58,10 +58,7 @@ jobs: fail-fast: false matrix: first-package: - - package: gaia13 - command: gaiad - account_prefix: cosmos - - package: gaia14 + - package: gaia20 command: gaiad account_prefix: cosmos - package: ibc-go-v7-simapp @@ -70,6 +67,9 @@ jobs: - package: ibc-go-v8-simapp command: simd account_prefix: cosmos + - package: ibc-go-v9-simapp + command: simd + account_prefix: cosmos second-package: - package: osmosis command: osmosisd @@ -80,23 +80,25 @@ jobs: - package: wasmd command: wasmd account_prefix: wasm + - package: injective + command: injectived + account_prefix: inj steps: - uses: actions/checkout@v4 - - uses: cachix/install-nix-action@v25 - 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@v14 - with: - name: cosmos - - uses: actions-rs/toolchain@v1 + - name: Install Nix + uses: DeterminateSystems/nix-installer-action@main + with: + extra-conf: | + substituters = https://cache.nixos.org + trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= + - name: Install Cachix + uses: cachix/cachix-action@v15 + with: + name: cosmos-nix + - uses: actions-rust-lang/setup-rust-toolchain@v1 with: toolchain: stable - override: true - - uses: Swatinem/rust-cache@v2 - uses: actions-rs/cargo@v1 with: command: test diff --git a/.github/workflows/publish-dry-run.yml b/.github/workflows/publish-dry-run.yml index 9689c0d1f0..2f22b4d851 100644 --- a/.github/workflows/publish-dry-run.yml +++ b/.github/workflows/publish-dry-run.yml @@ -11,10 +11,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions-rs/toolchain@v1 + - uses: actions-rust-lang/setup-rust-toolchain@v1 with: toolchain: stable - override: true - uses: katyo/publish-crates@v2 with: dry-run: true diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 29b0e03d40..42106466c5 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -11,10 +11,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions-rs/toolchain@v1 + - uses: actions-rust-lang/setup-rust-toolchain@v1 with: toolchain: stable - override: true - uses: katyo/publish-crates@v2 with: registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }} diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 49acf5017c..bc19b03142 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -38,10 +38,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions-rs/toolchain@v1 + - uses: actions-rust-lang/setup-rust-toolchain@v1 with: toolchain: stable - override: true - uses: actions-rs/cargo@v1 with: command: fmt @@ -51,12 +50,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions-rs/toolchain@v1 + - uses: actions-rust-lang/setup-rust-toolchain@v1 with: toolchain: stable components: clippy - override: true - - uses: Swatinem/rust-cache@v2 - uses: actions-rs/clippy-check@v1 with: name: clippy-all-features @@ -67,12 +64,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions-rs/toolchain@v1 + - uses: actions-rust-lang/setup-rust-toolchain@v1 with: toolchain: stable components: clippy - override: true - - uses: Swatinem/rust-cache@v2 - uses: actions-rs/clippy-check@v1 with: name: clippy-no-default-features @@ -84,11 +79,9 @@ jobs: timeout-minutes: 30 steps: - uses: actions/checkout@v4 - - uses: actions-rs/toolchain@v1 + - uses: actions-rust-lang/setup-rust-toolchain@v1 with: toolchain: stable - override: true - - uses: Swatinem/rust-cache@v2 - name: Install cargo-nextest run: curl -LsSf https://get.nexte.st/latest/linux | tar zxf - -C ${CARGO_HOME:-~/.cargo}/bin - uses: actions-rs/cargo@v1 @@ -100,13 +93,27 @@ jobs: command: nextest args: run --all-features --no-fail-fast --workspace --exclude ibc-integration-test --no-capture + msrv: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + toolchain: stable + - name: Install cargo-binstall + uses: taiki-e/install-action@cargo-binstall + - name: Install cargo-msrv + run: cargo binstall --no-confirm --force cargo-msrv@0.16.0-beta.20 + - name: Check MSRV + run: cargo msrv verify --output-format minimal --manifest-path crates/relayer-cli/Cargo.toml -- 'cargo check --all-features' + # test-coverage: # runs-on: ubuntu-latest # steps: # - uses: actions/checkout@v4 # with: # fetch-depth: 0 - # - uses: actions-rs/toolchain@v1 + # - uses: actions-rust-lang/setup-rust-toolchain@v1 # with: # toolchain: stable # override: true diff --git a/.gitignore b/.gitignore index edd589a061..f46e505cd9 100644 --- a/.gitignore +++ b/.gitignore @@ -21,7 +21,7 @@ data .mypy_cache/ __pycache__/ -# Ignore modelator aritfacts +# Ignore modelator artifacts .modelator mc.log @@ -30,3 +30,6 @@ mc.log # Ignore tooling Cargo.lock tools/check-guide/Cargo.lock + +# Ignore data generated from wasm contract +ibc_08-wasm_client_data \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index e9328dfc7d..620a2d05a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,456 @@ # CHANGELOG +## v1.10.5 + +*December 13rd, 2024* + +This release addresses an issue with pull-mode event collection. The functionality has been enhanced to accurately retrieve events from `finalized_block_events`, ensuring more reliable event processing. + +### IMPROVEMENTS + +- [Relayer Library](relayer) + - Collect events from `finalized_block_events` when using `pull` mode + ([\#4263](https://github.com/informalsystems/hermes/issues/4263)) +- [Integration Test Framework](tools/test-framework) + - Update the version of Juno running the integration tests in the CI from `v24.0.0` + to `v25.0.0` ([\#4203](https://github.com/informalsystems/hermes/issues/4203)) + +## v1.10.4 + +*November 19th, 2024* + +This release introduces compatibility with the new Consumer ID for Permissionless ICS, improves detection of Tendermint/CometBFT versions for non-standard chains, and enhances IPv6 support for gRPC connections. Log messages have been refined for better clarity, including adjusting redundant packet broadcasts to INFO. + +### BUG FIXES + +- [Relayer Library](relayer) + - Fix error messages in logs to accurately display the RPC endpoint + that failed. + ([\#4250](https://github.com/informalsystems/hermes/issues/4250)) + - Fix an issue where Hermes would fail to connect to gRPC servers + with an IPv6 address. + ([\#4237](https://github.com/informalsystems/hermes/issues/4237)) + - Fix the extraction of the chain name from the chain ID to ensure + accurate identification. + ([\#4247](https://github.com/informalsystems/hermes/issues/4247)) + +### FEATURES + +- [Integration Test Framework](tools/test-framework) + - Disable TLS configuration when using IPv6 for the gRPC endpoint. + ([\#4224](https://github.com/informalsystems/hermes/issues/4224)) + +### IMPROVEMENTS + +- General + - Improve detection of Tendermint/CometBFT compatibility + mode when a chain runs a non-standard version + ([\#4178](https://github.com/informalsystems/hermes/issues/4178)) +- [Relayer Library](relayer) + - Use CCV consumer ID to submit misbehaviour messages + ([\#4153](https://github.com/informalsystems/hermes/issues/4153)) + - Improve log message when broadcasting redundant packet and set it + to `INFO` instead of `ERROR`. + ([\#4252](https://github.com/informalsystems/hermes/issues/4252)) +- [Integration Test Framework](tools/test-framework) + - Update the versions of the following `simd` running the integration tests in the CI: + * From `v6.3.0` to `v6.3.1` + * From `v7.4.0` to `v7.8.0` + * From `v8.3.1` to `v8.5.1` + * From `v9.0.0-beta.1` to `v9.0.0-rc.0` + + ([\#4202](https://github.com/informalsystems/hermes/issues/4202)) + - Update the version of Gaia running the integration tests in the CI from `v18.1.0` + to `v20.0.0` ([\#4204](https://github.com/informalsystems/hermes/issues/4204)) + +## v1.10.3 + +*September 2nd, 2024* + +This release fixes an issue where Hermes could not connect to gRPC servers over TLS. Additionally, this release also fixes a bug in the `clear packet` CLI where the `excluded_sequences` configuration option was not always taken into account. + +Furthermore, Hermes now uses `abci_query` instead of gRPC for some queries, for instance for querying staking parameters and service configuration during health checks, and when retrieving version information. + +### BUG FIXES + +- [Chain Registry](chain-registry) + - Add explicit root TLS configuration to gRPC clients + ([\#4160](https://github.com/informalsystems/hermes/issues/4160)) +- [Relayer Library](relayer) + - Add explicit root TLS configuration to gRPC clients + ([\#4160](https://github.com/informalsystems/hermes/issues/4160)) +- [Relayer CLI](relayer-cli) + - Correctly filter out sequences from the `excluded_sequences` configuration + when clearing packets with the `clear packet` CLI. + ([\#4158](https://github.com/informalsystems/hermes/issues/4158)) + +### IMPROVEMENTS + +- [Relayer Library](relayer) + - Use `abci_query` instead of gRPC queries when retrieving staking params + and service config during health-check, and when retrieving version information. + ([\#4102](https://github.com/informalsystems/hermes/issues/4102)) +- [Integration Test Framework](tools/test-framework) + - Update the version of Celestia running the integration tests in the CI from `v1.11.0` + to `v1.14.0` ([\#4123](https://github.com/informalsystems/hermes/issues/4123)) + - Update the version of Neutron running the integration tests in the CI from `v4.1.0` + to `v4.2.2` ([\#4168](https://github.com/informalsystems/hermes/issues/4168)) + - Update the version of `wasmd` running the integration tests in the CI from `v0.52.0` + to `v0.53.0` ([\#4169](https://github.com/informalsystems/hermes/issues/4169)) + - Update the version of Juno running the integration tests in the CI from `v23.0.0` + to `v24.0.0` ([\#4171](https://github.com/informalsystems/hermes/issues/4171)) + +### FEATURES + +- [Integration Test Framework](tools/test-framework) + - Add ibc-go `v9` to the chains running the integration tests in the CI. + ([\#4151](https://github.com/informalsystems/hermes/issues/4151)) + +## v1.10.2 + +*August 14th, 2024* + +This release brings significant performance improvements and introduces a new configuration options for better control over packet clearing. Enhancements include faster startup times through optimized queries and the introduction of a `clear_limit` setting for packet clearing. Additionally, bug fixes and updates to the integration test framework ensure greater stability and compatibility across various environments. + +### BUG FIXES + +- [Relayer Library](relayer) + - Fix the `memo_overwrite` configuration to correctly apply the + overwrite if it is configured. + ([\#4104](https://github.com/informalsystems/hermes/issues/4104)) +- [Telemetry & Metrics](telemetry) + - Fix the `dynamic_gas_queried_success_fees` Prometheus metric name. + ([\#4104](https://github.com/informalsystems/hermes/issues/4104)) + + +### IMPROVEMENTS +- [Relayer Library](relayer) + - Add a new configuration `clear_limit` to specify the maximum number + of packets cleared every time packet clearing is triggered. + Defaults to 50. + ([\#4071](https://github.com/informalsystems/hermes/issues/4071)) + - Paginate results of `query_packet_commitments` and `query_packet_acknowledgements` + queries to speed up the scanning phase. + ([\#4101](https://github.com/informalsystems/hermes/issues/4101)) + - Use the `ibc.core.connection.v1.ConnectionParams` gRPC query to retrieve `maxExpectedTimePerBlock` + and check it against the configured `max_block_time` instead of using the `/genesis` endpoint. + This improves both startup times and reliability for most chains. + ([\#4143](https://github.com/informalsystems/hermes/issues/4143)) +- [Integration Test Framework](tools/test-framework) + - Update the version of Gaia running the integration tests in the CI from `v17.2.1` + to `v18.1.0` ([\#4114](https://github.com/informalsystems/hermes/issues/4114)) + - Update the version of Provenance running the integration tests in the CI from `v1.17.0` + to `v1.19.1` ([\#4115](https://github.com/informalsystems/hermes/issues/4115)) + - Update the version of Osmosis running the integration tests in the CI from `v25.0.0` + to `v25.2.0` ([\#4116](https://github.com/informalsystems/hermes/issues/4116)) + - Update the version of Juno running the integration tests in the CI from `v22.0.0` + to `v23.0.0` ([\#4117](https://github.com/informalsystems/hermes/issues/4117)) + - Update the version of Migaloo Chain running the integration tests in the CI from `v4.1.3` + to `v4.2.0` ([\#4118](https://github.com/informalsystems/hermes/issues/4118)) + - Update the version of `wasmd` running the integration tests in the CI from `v0.51.0` + to `v0.52.0` ([\#4120](https://github.com/informalsystems/hermes/issues/4120)) + - Update the version of Stride running the integration tests in the CI from `v21.0.0` + to `v23.0.1` ([\#4121](https://github.com/informalsystems/hermes/issues/4121)) + - Update the version of Neutron running the integration tests in the CI from `v3.0.5` + to `v4.1.0` ([\#4122](https://github.com/informalsystems/hermes/issues/4122)) + +## v1.10.1 + +*July 23th, 2024* + +In this release `tendermint-rs` has been updated to the latest version, addressing issues with the `/block_results` response. This ensures compatibility with CometBFT v0.38.10. + +And enhancements have been made to the logs regarding packet clearing, providing better insights and warnings for users. + + +### BREAKING CHANGES + +- Bump version of `ibc-proto` from `v0.46.0` to `v0.47.0` and + version of `tendermint-rs` from `v0.37.0` to `v0.38.1`. + ([\#4093](https://github.com/informalsystems/hermes/issues/4093)) + +### IMPROVEMENTS + +- [Integration Test Framework](tools/test-framework) + - Add the features `packet-forward` and `ica` to enable + Packet Forward Middleware and ICA when running tests with Osmosis + ([\#3195](https://github.com/informalsystems/hermes/issues/3195)) +- [Relayer Library](relayer) + - Improve logs when clearing packet. + * When Hermes doesn't pull packet data it will now warn the user + instead of logging `pulled packet data for 0 events out of X` + * When ICS20 packets are filtered due to having a receiver or memo + field too big, the log will be at `warn` level instead of `debug`. + ([\#4072](https://github.com/informalsystems/hermes/issues/4072)) + +## v1.10.0 + +*June 24th, 2024* + +This release enhances filter configurations and includes the following updates: + +1. `excluded_sequences` supports sequence ranges in addition to exact values, + e.g. `[1, 2, "5-10", 13]` is now valid. +2. `packet_filter` now ignores unintended whitespace. +3. A new `allow_ccq` per-chain configuration has been added to skip the relaying of + ICS31 Cross Chain Queries. + +Additionally, various improvements to testing and bug fixes have been implemented. + +### BUG FIXES + +- General + - Fix a bug where in some cases, Hermes would drop all events in a + batch that came after an event rejected by the filtering policy + ([\#4034](https://github.com/informalsystems/hermes/issues/4034)) +- [Relayer Library](relayer) + - Discard CrossChain queries intended for unconfigured chains. + ([\#4021](https://github.com/informalsystems/hermes/issues/4021)) + +### FEATURES + +- [Integration Test Framework](tools/test-framework) + - Add tests to ensure that Hermes correctly relays transfer messages + from a grantee address with granted authorisation using `authz` module. + ([\#4046](https://github.com/informalsystems/hermes/issues/4046)) +- [Relayer Library](relayer) + - Add a new per-chain configuration `allow_ccq` to enable or disable + relaying of ICS31 Cross Chain Query packets. + ([\#4040](https://github.com/informalsystems/hermes/issues/4040)) + +### IMPROVEMENTS + +- [Integration Test Framework](tools/test-framework) + - Update the version of Gaia running the integration tests in the CI from `v15.2.0` + to `v17.2.0` ([\#4023](https://github.com/informalsystems/hermes/issues/4023)) + - Update the version of Osmosis running the integration tests in the CI from `v24.0.1` + to `v25.0.0` ([\#4024](https://github.com/informalsystems/hermes/issues/4024)) + - Update the version of Juno running the integration tests in the CI from `v21.0.0` + to `v22.0.0` ([\#4025](https://github.com/informalsystems/hermes/issues/4025)) + - Update the version of Neutron running the integration tests in the CI from `v3.0.2` + to `v3.0.5` ([\#4026](https://github.com/informalsystems/hermes/issues/4026)) + - Update the version of Celestia app running the integration tests in the CI from `v1.4.0` + to `v1.11.0` ([\#4027](https://github.com/informalsystems/hermes/issues/4027)) + - Update the version of `wasmd` running the integration tests in the CI from `v0.50.0` + to `v0.51.0` ([\#4029](https://github.com/informalsystems/hermes/issues/4029)) + - Reduce run time for ICS29 tests by immediately verifying if either + the legacy fees, `recv_fee + ack_fee + timeout_fee` or current + fees, `max(recv_fee + ack_fee, timeout_fee)` have been escrowed. + ([\#4053](https://github.com/informalsystems/hermes/issues/4053)) + - Refactored the test-framework bootstrapping for n-ary chain tests + to utilize the specified topology. + * Currently, only linear, cyclic and fully connected topologies are supported. + ([\#4038](https://github.com/informalsystems/hermes/issues/4038)) +- [Relayer Library](relayer) + - Use custom User-Agent for Hermes queries + ([\#3979](https://github.com/informalsystems/hermes/issues/3979)) + - Updated the channel and port filter parsing to ignore whitespaces. + This will prevent unintended channel scanning due to accidental + whitespaces when exact matches are specified in the `packet_filter` + configuration. + ([\#4045](https://github.com/informalsystems/hermes/issues/4045)) + - Improve the `excluded_sequences` configuration so that it now accepts + ranges of sequence values in addition to exact values. + Accepted format: + * Exact sequence, e.g. [1, 2, 3] + * "-" separator, e.g. ["1-3"] + + These can be combined making the following configurations equivalent: + * `excluded_sequences = { 'channel-0' = [1, "3-5", 7, "9-12"] }` + * `excluded_sequences = { 'channel-0' = [1, 3, 4, 5, 7, 9, 10, 11, 12] }` + + ([\#4047](https://github.com/informalsystems/hermes/issues/4047)) + +## v1.9.0 + +*May 30th, 2024* + +This v1.9.0 release introduces new features and improvements to Hermes. + +**Major Features**: + +1. **Channel Upgrades:** Hermes now handles [channel upgrade](https://www.ibcprotocol.dev/blog/introducing-ibc-channel-upgradability) events introduced in ibc-go v8, helping chains opting-in to new functionality on existing channels. +2. **Dynamic Gas Fees Compatibility:** Hermes is now compatible with Skip's `x/feemarket` module for dynamic gas fees, in addition to Osmosis' implementation, providing more flexibility in gas fee management. + +Additionally, this release includes various bug fixes enhancing the stability and performance of Hermes. These fixes address issues with channel and connection creation on older ibc-go versions, event extraction, health-check messages, and more. + +### BREAKING CHANGES + +- [Telemetry & Metrics](telemetry) + - Remove the `telemetry` and `rest-server` feature flags, ensuring Hermes is always built with telemetry and REST support. + Both servers can still be disabled in the configuration file, by setting `telemetry.enabled = false` and `rest.enabled = false`, respectively. + ([\#3878](https://github.com/informalsystems/hermes/pull/3878)) + +### FEATURES + +- [Relayer Library](relayer) + - Add support for upgrading channels, as per the [ICS 004 specification](https://github.com/cosmos/ibc/blob/main/spec/core/ics-004-channel-and-packet-semantics/UPGRADES.md) ([#3228](https://github.com/informalsystems/hermes/issues/2547)) + This feature allows chains to upgrade an existing channel to take advantage of new features without having to create a new channel, thus preserving all existing packet state processed on the channel. For example, a channel could now be upgraded to enable the [ICS 029 fee middleware](https://ibc.cosmos.network/main/middleware/ics29-fee/overview), allowing relayer operators on that channel to receive fees each time they relay an incentivized packet. + - Improve reliability of event source in `pull` mode by proceeding to next block even if Hermes cannot parse the current block. + Add new configuration option to `event_source` setting: `max_retries` defines how many times Hermes should attempt to pull a block over RPC. + ```toml + event_source = { mode = 'pull', interval = '1s', max_retries = 4 } + ``` + ([\#3894](https://github.com/informalsystems/hermes/issues/3894)) + +### IMPROVEMENTS + +- [Integration Test Framework](tools/test-framework) + - Update the version of Juno running the integration tests in the CI from `v17.1.1` + to `v21.0.0` ([\#3959](https://github.com/informalsystems/hermes/issues/3959)) + - Update the version of Migaloo Chain running the + integration tests in the CI from `v3.0.2` to `v4.1.3` + ([\#3960](https://github.com/informalsystems/hermes/issues/3960)) + - Update the version of `wasmd` running the + integration tests in the CI from `v0.30.0` to `v0.50.0` + ([\#3961](https://github.com/informalsystems/hermes/issues/3961)) + - Update the version of ibc-go simapp running the + integration tests in the CI from `v8.2.0` to `v8.3.1` + ([\#4009](https://github.com/informalsystems/hermes/issues/4009)) +- [Relayer Library](relayer) + - Update to tendermint-rs v0.35.0 + ([\#3895](https://github.com/informalsystems/hermes/issues/3895)) + - Use `packet_ack_hex` event attribute instead of deprecated `packet_ack` attribute to decode `WriteAck` event + ([\#3921](https://github.com/informalsystems/hermes/issues/3921)) + - Update to tendermint-rs v0.36.0 + ([\#3966](https://github.com/informalsystems/hermes/issues/3966)) + - Add support for dynamic gas fee for chains using Skip's [`x/feemarket`](https://github.com/skip-mev/feemarket) module, while keeping compatibility with Osmosis' bespoke implementation + ([\#4000](https://github.com/informalsystems/hermes/issues/4000)) +- [Relayer CLI](relayer-cli) + - Use RPC (pull) event source instead of WebSocket (push) when generating configuration with `hermes config auto` + ([\#3913](https://github.com/informalsystems/hermes/issues/3913)) + +### BUG FIXES + +- [Relayer Library](relayer) + - Fix creation of channels and connection on chains + using an unsupported version of ibc-go, eg. Sei + ([\#3817](https://github.com/informalsystems/hermes/issues/3817)) + - Fix a bug where Hermes would only ever extract the first emitted ICS 031 CrossChain Query event, which would cause it to miss the other CCQ events. + ([\#3954](https://github.com/informalsystems/hermes/issues/3954)) +- [Relayer CLI](relayer-cli) + - Fixed `minimum-gas-prices` health-check messages and make it more verbose and legible + ([\#3893](https://github.com/informalsystems/hermes/issues/3893)) + - Set `compat_mode` for pull mode in `hermes listen` command + ([\#3910](https://github.com/informalsystems/hermes/issues/3910)) + - Fixed the trusted height consensus state query when submitting the double vote evidence + ([\#3999](https://github.com/informalsystems/hermes/issues/3999)) + +## v1.8.3 + +*May 28th, 2024* + +This patch release fixes a bug that may happen prevent the relayer from submitting the evidence for a duplicate vote in some cases. + +### BUG FIXES + +- [Relayer CLI](relayer-cli) + - Fix the trusted height consensus state query when submitting the double vote evidence + ([\#3999](https://github.com/informalsystems/hermes/issues/3999)) + +## v1.8.2 + +*March 12th, 2024* + +This release fixes the two following bugs and improves the connection and channel handshake retry mechanism: + +* Fix erroneous warnings for incompatible version of IBC-Go during health checks, ensuring accurate compatibility reporting +* Fix a bug in the `clear packets` command which caused packet clearing to fail with an "counterparty channel not found" error + +### BUG FIXES + +- [Relayer CLI](relayer-cli) + - Correctly use the counterparty channel and port IDs when clearing the packets + from the destination chain to the source chain in the `packet clear` command + ([\#3889](https://github.com/informalsystems/hermes/issues/3889)) +- [Relayer](relayer) + - Fix parsing of IBC-Go version in health check and improve health check + reporting ([\#3880](https://github.com/informalsystems/hermes/issues/3880)) + +### FEATURES + +- [Integration Test Framework](tools/test-framework) + - Add Injective chain to the chains running the integration tests in the CI. + ([\#3887](https://github.com/informalsystems/hermes/issues/3887)) + +### IMPROVEMENTS + +- [Relayer](relayer) + - Change connection and channel handshake retry strategy + to retry at most 10 times (5 times per block max) + ([\#3864](https://github.com/informalsystems/hermes/issues/3864)) + +## v1.8.1 + +*March 7th, 2024* + +This v1.8.1 release brings better reliability when relaying, more enhanced configuration and improved monitoring. + +Reliability has been improved: +* It is now possible to relay ICS-04 packets with non-UTF-8 payloads +* Packet sequences are now verified for ordered channels before trying to relay + +Additional per-chain configurations have been added: +* `excluded_sequences` used to skip problematic packets when clearing +* `memo_overwrite` allowing users to overwrite the relayer memo when chains have a strict limit for the size of the memo. + +Monitoring issues improvements: +* A new metric `simulate_errors` which counts the number of failed simulated transactions +* Out of gas error diagnostic gives more information and a dedicated entry to the guide has been added +* Failed gas simulation will not be considered as unrecoverable for legacy chains. +* The compatibility check during the health-check has been improved will assess more correctly the versions for Ibc-Go and Cosmos SDK + +Special thanks to our contributors for their valuable additions to this release: + +* Sergey (@freak12techno) for adding the `simulate_errors` metric ([#3845]) +* Martin Dyring-Andersen (@mdyring) for adding recovery from failed gas simulation for legacy chains ([#3792]) + +### BUG FIXES + +- Allow relaying ICS-04 packets with non-UTF-8 payloads ([\#3770](https://github.com/informalsystems/hermes/issues/3770)) + Hermes does not assume anymore that an ICS-04 packet data is valid UTF-8, + by using the `packet_data_hex` attribute when assembling a packet from events, instead of the deprecated `packet_data` attribute. + Relying on the `packet_data` attribute enforces a UTF-8 encoded payload (eg. JSON), disallowing eg. Protobuf-encoded payloads. + The `packet_data` attribute [has been deprecated][0] in favor of `packet_data_hex` since IBC-Go v1.0.0. +- Improve reliability of compatibility check and fix parsing of expected modules versions ([\#3831](https://github.com/informalsystems/hermes/issues/3831)) + +[0]: https://github.com/cosmos/ibc-go/blob/fadf8f2b0ab184798d021d220d877e00c7634e26/CHANGELOG.md?plain=1#L1417 + +### FEATURES + +- Add a per-chain configuration `excluded_sequences` allowing users to specify a list of packet sequences which will not be cleared. + This configuration has no impact on standard packet relaying. + ([\#3754](https://github.com/informalsystems/hermes/issues/3754)) +- Add a per-chain configuration `memo_overwrite` allowing users to overwrite the relayer memo used for each transaction + ([\#3811](https://github.com/informalsystems/hermes/issues/3811)) +- Added a new Prometheus metric `simulate_errors` for tracking when a transaction simulation fails, with the following labels: + ([\#3845](https://github.com/informalsystems/hermes/issues/3845)) + * `recoverable` (can the execution continue if this happened?) + * `account` (account from which the tx was sent) + * `error_description` (description of the error) + + ``` + # HELP simulate_errors_total Number of errors observed by Hermes when simulating a Tx + # TYPE simulate_errors_total counter + simulate_errors_total{account="osmo17ndx5qfku28ymxgmq6zq4a6d02dvpfjjul0hyh",error_description="Unknown error",recoverable="false",service_name="unknown_service",otel_scope_name="hermes",otel_scope_version=""} 4 + ``` + +### IMPROVEMENTS + +- Use the consensus state at client latest height in status CLI ([#3814](https://github.com/informalsystems/ibc-rs/issues/3814)) +- Add syncing check for gRPC node ([#3814](https://github.com/informalsystems/ibc-rs/issues/3814)) +- Improve the log diagnostic when an out of gas error is thrown. + And a new entry related to gas error has been added to the Hermes guide. + ([\#3530](https://github.com/informalsystems/hermes/issues/3530)) +- Improve resilience when relaying on ordered channels. + When relaying packets on an ordered channel, Hermes will now attempt + to detect whether the next message to send has the sequence number + expected on that channel. If there is a mismatch, then Hermes will trigger a packet + clear on the channel to unblock it before resuming operations on that channel. + ([\#3540](https://github.com/informalsystems/hermes/issues/3540)) +- Recover from gas simulation failures on legacy chains. + ([\#3792](https://github.com/informalsystems/hermes/issues/3792)) + ## v1.8.0 *January 23rd, 2024* diff --git a/Cargo.lock b/Cargo.lock index 6d40be1bc6..c3dd849ea3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -38,7 +38,7 @@ dependencies = [ "proc-macro2", "quote", "syn 1.0.109", - "synstructure", + "synstructure 0.12.6", ] [[package]] @@ -58,78 +58,106 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anstream" -version = "0.6.11" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.4" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.3" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.2" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.2" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.79" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" [[package]] name = "arc-swap" -version = "1.6.0" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + +[[package]] +name = "arrayref" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "async-stream" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" dependencies = [ "async-stream-impl", "futures-core", @@ -138,58 +166,65 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.90", ] [[package]] name = "async-trait" -version = "0.1.77" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.90", ] [[package]] name = "async-tungstenite" -version = "0.23.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1e9efbe14612da0a19fb983059a0b621e9cf6225d7018ecab4f9988215540dc" +checksum = "3609af4bbf701ddaf1f6bb4e6257dff4ff8932327d0e685d3f653724c258b1ac" dependencies = [ "futures-io", "futures-util", "log", "pin-project-lite", - "rustls-native-certs", + "rustls-native-certs 0.7.3", + "rustls-pki-types", "tokio", - "tokio-rustls", + "tokio-rustls 0.25.0", "tungstenite", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi 0.1.19", + "hermit-abi", "libc", "winapi", ] [[package]] name = "autocfg" -version = "1.1.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "axum" @@ -198,13 +233,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" dependencies = [ "async-trait", - "axum-core", + "axum-core 0.3.4", "bitflags 1.3.2", "bytes", "futures-util", - "http", - "http-body", - "hyper", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.31", "itoa", "matchit", "memchr", @@ -216,9 +251,36 @@ dependencies = [ "serde_json", "serde_path_to_error", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 0.1.2", "tokio", - "tower", + "tower 0.4.13", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" +dependencies = [ + "async-trait", + "axum-core 0.4.5", + "bytes", + "futures-util", + "http 1.2.0", + "http-body 1.0.1", + "http-body-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper 1.0.2", + "tower 0.5.2", "tower-layer", "tower-service", ] @@ -232,23 +294,43 @@ dependencies = [ "async-trait", "bytes", "futures-util", - "http", - "http-body", + "http 0.2.12", + "http-body 0.4.6", + "mime", + "rustversion", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 1.2.0", + "http-body 1.0.1", + "http-body-util", "mime", + "pin-project-lite", "rustversion", + "sync_wrapper 1.0.2", "tower-layer", "tower-service", ] [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ "addr2line", "cc", - "cfg-if 1.0.0", + "cfg-if", "libc", "miniz_oxide", "object", @@ -263,15 +345,15 @@ checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] name = "base64" -version = "0.13.1" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "base64" -version = "0.21.7" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" @@ -293,9 +375,9 @@ checksum = "98f7eed2b2781a6f0b5c903471d48e15f56fb4e1165df8a9a2337fd1a59d45ea" [[package]] name = "bitcoin" -version = "0.31.1" +version = "0.31.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd00f3c09b5f21fb357abe32d29946eb8bb7a0862bae62c0b5e4a692acbbe73c" +checksum = "6c85783c2fe40083ea54a33aa2f0ba58831d90fcd190f5bdc47e74e84d2a96ae" dependencies = [ "bech32 0.10.0-beta", "bitcoin-internals", @@ -334,9 +416,31 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.2" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "blake3" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "b8ee0c1824c4dea5b5f81736aff91bae041d2c07ee1192bec91054e10e3e601e" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", +] [[package]] name = "block-buffer" @@ -358,18 +462,18 @@ dependencies = [ [[package]] name = "bs58" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" dependencies = [ "tinyvec", ] [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byte-unit" @@ -381,12 +485,6 @@ dependencies = [ "utf8-width", ] -[[package]] -name = "bytecount" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e5f035d16fc623ae5f74981db80a439803888314e3a555fd6f04acd51a3205" - [[package]] name = "byteorder" version = "1.5.0" @@ -395,18 +493,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" -dependencies = [ - "serde", -] - -[[package]] -name = "camino" -version = "1.1.6" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" dependencies = [ "serde", ] @@ -417,48 +506,34 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e9e01327e6c86e92ec72b1c798d4a94810f147209bbe3ffab6a86954937a6f" -[[package]] -name = "cargo-platform" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceed8ef69d8518a5dda55c07425450b58a4e1946f4951eab6d7191ee86c2443d" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", -] - [[package]] name = "cc" -version = "1.0.83" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf" dependencies = [ - "libc", + "shlex", ] [[package]] name = "cfg-if" -version = "0.1.10" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "cfg-if" -version = "1.0.0" +name = "chrono" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-targets 0.52.6", +] [[package]] name = "clap" @@ -510,9 +585,9 @@ dependencies = [ [[package]] name = "color-eyre" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a667583cca8c4f8436db8de46ea8233c42a7d9ae424a82d338f2e4675229204" +checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5" dependencies = [ "backtrace", "color-spantrace", @@ -537,9 +612,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "console" @@ -560,6 +635,12 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + [[package]] name = "contracts" version = "0.6.3" @@ -581,38 +662,51 @@ dependencies = [ "libc", ] +[[package]] +name = "core-foundation" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] -name = "cpufeatures" -version = "0.2.12" +name = "cosmos-sdk-proto" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "462e1f6a8e005acc8835d32d60cbd7973ed65ea2a8d8473830e675f050956427" dependencies = [ - "libc", + "informalsystems-pbjson", + "prost", + "serde", + "tendermint-proto", + "tonic", ] [[package]] -name = "crossbeam-channel" -version = "0.4.4" +name = "cpufeatures" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ - "crossbeam-utils 0.7.2", - "maybe-uninit", + "libc", ] [[package]] name = "crossbeam-channel" -version = "0.5.11" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" dependencies = [ - "crossbeam-utils 0.8.19", + "crossbeam-utils", ] [[package]] @@ -621,25 +715,14 @@ version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "crossbeam-utils 0.8.19", -] - -[[package]] -name = "crossbeam-utils" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" -dependencies = [ - "autocfg", - "cfg-if 0.1.10", - "lazy_static", + "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" @@ -671,16 +754,15 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.1.1" +version = "4.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89b8c6a2e4b1f45971ad09761aafb85514a84744b67a95e32c3cc1352d1f65c" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "curve25519-dalek-derive", "digest 0.10.7", "fiat-crypto", - "platforms", "rustc_version", "subtle", "zeroize", @@ -694,7 +776,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.90", ] [[package]] @@ -716,8 +798,8 @@ version = "5.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ - "cfg-if 1.0.0", - "hashbrown 0.14.3", + "cfg-if", + "hashbrown 0.14.5", "lock_api", "once_cell", "parking_lot_core", @@ -725,15 +807,15 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] name = "der" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", "zeroize", @@ -756,13 +838,13 @@ checksum = "6e5c37193a1db1d8ed868c03ec7b152175f26160a5b740e5e484143877e0adf0" [[package]] name = "derive_more" -version = "0.99.17" +version = "0.99.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.90", ] [[package]] @@ -805,7 +887,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "dirs-sys-next", ] @@ -820,6 +902,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "ecdsa" version = "0.16.9" @@ -860,9 +953,9 @@ dependencies = [ [[package]] name = "ed25519-dalek" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f628eaec48bfd21b865dc2950cfa014450c01d2fa2b69a86c2fd5844ec523c0" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" dependencies = [ "curve25519-dalek", "ed25519", @@ -887,9 +980,9 @@ dependencies = [ [[package]] name = "either" -version = "1.9.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "elliptic-curve" @@ -918,18 +1011,18 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "encoding_rs" -version = "0.8.33" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] name = "env_filter" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" dependencies = [ "log", "regex", @@ -937,18 +1030,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" -dependencies = [ - "log", -] - -[[package]] -name = "env_logger" -version = "0.11.1" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05e7cf40684ae96ade6232ed84582f40ce0a66efcd43a5117aef610534f8e0b8" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" dependencies = [ "anstream", "anstyle", @@ -965,28 +1049,19 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "error-chain" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" -dependencies = [ - "version_check", + "windows-sys 0.59.0", ] [[package]] name = "eyre" -version = "0.6.11" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6267a1fa6f59179ea4afc8e50fd8612a3cc60bc858f786ff877a4a8cb042799" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" dependencies = [ "indenter", "once_cell", @@ -994,9 +1069,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "ff" @@ -1010,9 +1085,9 @@ dependencies = [ [[package]] name = "fiat-crypto" -version = "0.2.5" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "fixed-hash" @@ -1029,7 +1104,6 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c606d892c9de11507fa0dcffc116434f94e105d0bbdc4e405b61519464c49d7b" dependencies = [ - "anyhow", "eyre", "paste", ] @@ -1060,9 +1134,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -1075,9 +1149,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -1085,15 +1159,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -1102,38 +1176,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.90", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -1160,11 +1234,11 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "libc", "wasi", @@ -1177,12 +1251,6 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - [[package]] name = "group" version = "0.13.0" @@ -1216,17 +1284,36 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.24" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" dependencies = [ "bytes", "fnv", "futures-core", "futures-sink", "futures-util", - "http", - "indexmap 2.2.1", + "http 0.2.12", + "indexmap 2.7.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "h2" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.2.0", + "indexmap 2.7.0", "slab", "tokio", "tokio-util", @@ -1235,9 +1322,9 @@ dependencies = [ [[package]] name = "half" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" +checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" [[package]] name = "hashbrown" @@ -1247,9 +1334,15 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "hdpath" @@ -1275,12 +1368,6 @@ dependencies = [ "libc", ] -[[package]] -name = "hermit-abi" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" - [[package]] name = "hex" version = "0.4.3" @@ -1289,9 +1376,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hex-conservative" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2" +checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20" [[package]] name = "hex_lit" @@ -1310,9 +1397,20 @@ dependencies = [ [[package]] name = "http" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" dependencies = [ "bytes", "fnv", @@ -1326,17 +1424,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http", + "http 0.2.12", "pin-project-lite", ] [[package]] -name = "httparse" -version = "1.8.0" +name = "http-body" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.2.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http 1.2.0", + "http-body 1.0.1", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" + +[[package]] name = "httpdate" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1360,17 +1481,17 @@ dependencies = [ [[package]] name = "hyper" -version = "0.14.28" +version = "0.14.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" dependencies = [ "bytes", "futures-channel", "futures-core", "futures-util", - "h2", - "http", - "http-body", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", "httparse", "httpdate", "itoa", @@ -1382,6 +1503,27 @@ dependencies = [ "want", ] +[[package]] +name = "hyper" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2 0.4.7", + "http 1.2.0", + "http-body 1.0.1", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + [[package]] name = "hyper-rustls" version = "0.24.2" @@ -1389,36 +1531,80 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", - "http", - "hyper", - "rustls", + "http 0.2.12", + "hyper 0.14.31", + "rustls 0.21.12", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", ] [[package]] name = "hyper-timeout" -version = "0.4.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" +checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" dependencies = [ - "hyper", + "hyper 1.5.1", + "hyper-util", "pin-project-lite", "tokio", - "tokio-io-timeout", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.2.0", + "http-body 1.0.1", + "hyper 1.5.1", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", ] [[package]] name = "ibc-chain-registry" -version = "0.27.0" +version = "0.29.5" dependencies = [ "async-trait", "flex-error", "futures", - "http", + "http 1.2.0", "ibc-proto", + "ibc-relayer", "ibc-relayer-types", - "itertools 0.10.5", + "itertools", "reqwest", "serde", "serde_json", @@ -1429,35 +1615,35 @@ dependencies = [ [[package]] name = "ibc-integration-test" -version = "0.27.0" +version = "0.29.5" dependencies = [ "byte-unit", - "http", + "http 1.2.0", "ibc-relayer", "ibc-relayer-types", "ibc-test-framework", "prost", "serde", "serde_json", - "tempfile", "tendermint", "tendermint-rpc", "time", - "toml 0.8.8", + "toml 0.8.19", "tonic", ] [[package]] name = "ibc-proto" -version = "0.41.0" +version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd4ee32b22d3b06f31529b956f4928e5c9a068d71e46cf6abfa19c31ca550553" +checksum = "9b70f517162e74e2d35875b8b94bf4d1e45f2c69ef3de452dc855944455d33ca" dependencies = [ - "base64 0.21.7", + "base64 0.22.1", "bytes", + "cosmos-sdk-proto", "flex-error", "ics23", - "informalsystems-pbjson 0.7.0", + "informalsystems-pbjson", "prost", "serde", "subtle-encoding", @@ -1467,7 +1653,7 @@ dependencies = [ [[package]] name = "ibc-relayer" -version = "0.27.0" +version = "0.29.5" dependencies = [ "anyhow", "async-stream", @@ -1476,25 +1662,25 @@ dependencies = [ "bs58", "byte-unit", "bytes", - "crossbeam-channel 0.5.11", + "crossbeam-channel", "digest 0.10.7", "dirs-next", "ed25519", "ed25519-dalek", "ed25519-dalek-bip32", - "env_logger 0.11.1", + "env_logger", "flex-error", "futures", "generic-array", "hdpath", "hex", - "http", + "http 1.2.0", "humantime", "humantime-serde", "ibc-proto", "ibc-relayer-types", "ibc-telemetry", - "itertools 0.10.5", + "itertools", "moka", "num-bigint", "num-rational", @@ -1527,37 +1713,37 @@ dependencies = [ "tiny-keccak", "tokio", "tokio-stream", - "toml 0.8.8", + "toml 0.8.19", "tonic", "tracing", "tracing-subscriber", - "uuid 1.7.0", + "uuid", ] [[package]] name = "ibc-relayer-cli" -version = "1.8.0" +version = "1.10.5" dependencies = [ "abscissa_core", "clap", "clap_complete", "color-eyre", "console", - "crossbeam-channel 0.5.11", + "crossbeam-channel", "dialoguer", "dirs-next", "eyre", "flex-error", "futures", "hdpath", - "http", + "http 1.2.0", "humantime", "ibc-chain-registry", "ibc-relayer", "ibc-relayer-rest", "ibc-relayer-types", "ibc-telemetry", - "itertools 0.10.5", + "itertools", "once_cell", "oneline-eyre", "regex", @@ -1577,30 +1763,30 @@ dependencies = [ [[package]] name = "ibc-relayer-rest" -version = "0.27.0" +version = "0.29.5" dependencies = [ - "axum", - "crossbeam-channel 0.5.11", + "axum 0.6.20", + "crossbeam-channel", "ibc-relayer", "ibc-relayer-types", "reqwest", "serde", "tokio", - "toml 0.8.8", + "toml 0.8.19", "tracing", ] [[package]] name = "ibc-relayer-types" -version = "0.27.0" +version = "0.29.5" dependencies = [ "bytes", "derive_more", - "env_logger 0.11.1", + "env_logger", "flex-error", "ibc-proto", "ics23", - "itertools 0.10.5", + "itertools", "num-rational", "primitive-types", "prost", @@ -1623,9 +1809,9 @@ dependencies = [ [[package]] name = "ibc-telemetry" -version = "0.27.0" +version = "0.29.5" dependencies = [ - "axum", + "axum 0.6.20", "dashmap", "ibc-relayer-types", "moka", @@ -1642,20 +1828,21 @@ dependencies = [ [[package]] name = "ibc-test-framework" -version = "0.27.0" +version = "0.29.5" dependencies = [ + "chrono", "color-eyre", - "crossbeam-channel 0.5.11", + "crossbeam-channel", "eyre", "flex-error", "hdpath", "hex", - "http", + "http 1.2.0", "ibc-proto", "ibc-relayer", "ibc-relayer-cli", "ibc-relayer-types", - "itertools 0.10.5", + "itertools", "once_cell", "prost", "rand", @@ -1667,7 +1854,7 @@ dependencies = [ "subtle-encoding", "tendermint-rpc", "tokio", - "toml 0.8.8", + "toml 0.8.19", "tonic", "tracing", "tracing-subscriber", @@ -1675,14 +1862,16 @@ dependencies = [ [[package]] name = "ics23" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "661e2d6f79952a65bc92b1c81f639ebd37228dae6ff412a5aba7d474bdc4b957" +checksum = "73b17f1a5bd7d12ad30a21445cfa5f52fd7651cb3243ba866f9916b1ec112f12" dependencies = [ "anyhow", + "blake2", + "blake3", "bytes", "hex", - "informalsystems-pbjson 0.6.0", + "informalsystems-pbjson", "prost", "ripemd", "serde", @@ -1690,6 +1879,124 @@ dependencies = [ "sha3", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -1698,12 +2005,23 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", ] [[package]] @@ -1733,22 +2051,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.1" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433de089bd45971eecf4668ee0ee8f4cec17db4f8bd8f7bc3197a6ce37aa7d9b" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown 0.14.3", -] - -[[package]] -name = "informalsystems-pbjson" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4eecd90f87bea412eac91c6ef94f6b1e390128290898cbe14f2b926787ae1fb" -dependencies = [ - "base64 0.13.1", - "serde", + "hashbrown 0.15.2", ] [[package]] @@ -1763,50 +2071,48 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.9.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" [[package]] -name = "itertools" -version = "0.10.5" +name = "is_terminal_polyfill" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" -version = "0.11.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "js-sys" -version = "0.3.67" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" dependencies = [ + "once_cell", "wasm-bindgen", ] [[package]] name = "k256" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "ecdsa", "elliptic-curve", "sha2 0.10.8", @@ -1823,38 +2129,43 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.152" +version = "0.2.168" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" +checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" [[package]] name = "libredox" -version = "0.0.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.6.0", "libc", - "redox_syscall", ] [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "litemap" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -1862,9 +2173,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "matchers" @@ -1881,17 +2192,11 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" -[[package]] -name = "maybe-uninit" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" - [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "mime" @@ -1901,43 +2206,42 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.8.10" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "moka" -version = "0.12.4" +version = "0.12.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad9dc9808102655926a6086abd0b9965ebefd4a39ef0d184f074c34ba5049ec6" +checksum = "32cf62eb4dd975d2dde76432fb1075c49e3ee2331cf36f1f8fd4b66550d32b6f" dependencies = [ - "crossbeam-channel 0.5.11", + "crossbeam-channel", "crossbeam-epoch", - "crossbeam-utils 0.8.19", + "crossbeam-utils", "once_cell", "parking_lot", "quanta", "rustc_version", - "skeptic", "smallvec", "tagptr", "thiserror", "triomphe", - "uuid 1.7.0", + "uuid", ] [[package]] @@ -1952,44 +2256,36 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ - "autocfg", "num-integer", "num-traits", "serde", ] [[package]] -name = "num-derive" -version = "0.3.3" +name = "num-conv" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] [[package]] name = "num-rational" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ - "autocfg", "num-bigint", "num-integer", "num-traits", @@ -1998,23 +2294,13 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi 0.3.4", - "libc", -] - [[package]] name = "object" version = "0.32.2" @@ -2026,9 +2312,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "oneline-eyre" @@ -2041,9 +2327,9 @@ dependencies = [ [[package]] name = "opaque-debug" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl-probe" @@ -2095,7 +2381,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b3a2a91fdbfdd4d212c0dcc2ab540de2c2bcbbd90be17de7a7daf8822d010c1" dependencies = [ "async-trait", - "crossbeam-channel 0.5.11", + "crossbeam-channel", "dashmap", "fnv", "futures-channel", @@ -2128,9 +2414,9 @@ checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -2138,22 +2424,22 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pbkdf2" @@ -2166,9 +2452,9 @@ dependencies = [ [[package]] name = "peg" -version = "0.7.0" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07c0b841ea54f523f7aa556956fbd293bcbe06f2e67d2eb732b7278aaf1d166a" +checksum = "295283b02df346d1ef66052a757869b2876ac29a6bb0ac3f5f7cd44aebe40e8f" dependencies = [ "peg-macros", "peg-runtime", @@ -2176,9 +2462,9 @@ dependencies = [ [[package]] name = "peg-macros" -version = "0.7.0" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aa52829b8decbef693af90202711348ab001456803ba2a98eb4ec8fb70844c" +checksum = "bdad6a1d9cf116a059582ce415d5f5566aabcd4008646779dab7fdc2a9a9d426" dependencies = [ "peg-runtime", "proc-macro2", @@ -2187,9 +2473,9 @@ dependencies = [ [[package]] name = "peg-runtime" -version = "0.7.0" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c719dcf55f09a3a7e764c6649ab594c18a177e3599c467983cdf644bfc0a4088" +checksum = "e3aeb8f54c078314c2065ee649a7241f46b9d8e418e1a9581ba0546657d7aa3a" [[package]] name = "percent-encoding" @@ -2199,29 +2485,29 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project" -version = "1.1.3" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.3" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.90", ] [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -2239,12 +2525,6 @@ dependencies = [ "spki", ] -[[package]] -name = "platforms" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "626dec3cac7cc0e1577a2ec3fc496277ec2baa084bebad95bb6fdbfae235f84c" - [[package]] name = "powerfmt" version = "0.2.0" @@ -2253,9 +2533,12 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "primitive-types" @@ -2294,20 +2577,20 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] [[package]] name = "prometheus" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "449811d15fbdf5ceb5c1144416066429cf82316e2ec8ce0c1f6f8a02e7bbcf8c" +checksum = "3d33c28a30771f7f96db69893f78b857f7450d7e0237e9c8fc6427a81bae7ed1" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "fnv", "lazy_static", "memchr", @@ -2318,9 +2601,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.12.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" +checksum = "2c0fef6c4230e4ccf618a35c59d7ede15dea37de8427500f50aff708806e42ec" dependencies = [ "bytes", "prost-derive", @@ -2328,24 +2611,15 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.12.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" +checksum = "157c5a9d7ea5c2ed2d9fb8f495b64759f7816c7eaea54ba3978f0d63000162e3" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools", "proc-macro2", "quote", - "syn 2.0.48", -] - -[[package]] -name = "prost-types" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "193898f59edcf43c26227dcd4c8427f00d99d61e95dcde58dabd49fa291d470e" -dependencies = [ - "prost", + "syn 2.0.90", ] [[package]] @@ -2354,24 +2628,13 @@ version = "2.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" -[[package]] -name = "pulldown-cmark" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998" -dependencies = [ - "bitflags 1.3.2", - "memchr", - "unicase", -] - [[package]] name = "quanta" -version = "0.12.2" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca0b7bac0b97248c40bb77288fc52029cf1459c0461ea1b05ee32ccf011de2c" +checksum = "773ce68d0bb9bc7ef20be3536ffe94e223e1f365bd374108b2659fac0c65cfe6" dependencies = [ - "crossbeam-utils 0.8.19", + "crossbeam-utils", "libc", "once_cell", "raw-cpuid", @@ -2382,9 +2645,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.35" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -2421,27 +2684,27 @@ dependencies = [ [[package]] name = "raw-cpuid" -version = "11.0.1" +version = "11.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d86a7c4638d42c44551f4791a20e687dbb4c3de1f33c43dd71e355cd429def1" +checksum = "1ab240315c661615f2ee9f0f2cd32d5a7343a84d5ebcccb99d46e6637565e7b0" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.6.0", ] [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", ] [[package]] name = "redox_users" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom", "libredox", @@ -2450,14 +2713,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.3" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.4", - "regex-syntax 0.8.2", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", ] [[package]] @@ -2471,13 +2734,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.4" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b7fa1134405e2ec9353fd416b17f8dacd46c473d7d3fd1cf202706a14eb792a" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.2", + "regex-syntax 0.8.5", ] [[package]] @@ -2488,25 +2751,25 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.11.23" +version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ "base64 0.21.7", "bytes", "encoding_rs", "futures-core", "futures-util", - "h2", - "http", - "http-body", - "hyper", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.31", "hyper-rustls", "ipnet", "js-sys", @@ -2515,15 +2778,16 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls", - "rustls-native-certs", - "rustls-pemfile", + "rustls 0.21.12", + "rustls-native-certs 0.6.3", + "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", + "sync_wrapper 0.1.2", "system-configuration", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", "tower-service", "url", "wasm-bindgen", @@ -2550,16 +2814,17 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.7" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", + "cfg-if", "getrandom", "libc", "spin", "untrusted", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -2573,9 +2838,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" @@ -2585,38 +2850,67 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] [[package]] name = "rustix" -version = "0.38.30" +version = "0.38.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" +checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "rustls" -version = "0.21.10" +version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", "ring", - "rustls-webpki", + "rustls-webpki 0.101.7", "sct", ] +[[package]] +name = "rustls" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" +dependencies = [ + "log", + "ring", + "rustls-pki-types", + "rustls-webpki 0.102.8", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls" +version = "0.23.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" +dependencies = [ + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki 0.102.8", + "subtle", + "zeroize", +] + [[package]] name = "rustls-native-certs" version = "0.6.3" @@ -2624,9 +2918,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" dependencies = [ "openssl-probe", - "rustls-pemfile", + "rustls-pemfile 1.0.4", + "schannel", + "security-framework 2.11.1", +] + +[[package]] +name = "rustls-native-certs" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" +dependencies = [ + "openssl-probe", + "rustls-pemfile 2.2.0", + "rustls-pki-types", + "schannel", + "security-framework 2.11.1", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +dependencies = [ + "openssl-probe", + "rustls-pki-types", "schannel", - "security-framework", + "security-framework 3.0.1", ] [[package]] @@ -2638,6 +2957,21 @@ dependencies = [ "base64 0.21.7", ] +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" + [[package]] name = "rustls-webpki" version = "0.101.7" @@ -2648,17 +2982,28 @@ dependencies = [ "untrusted", ] +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "rustversion" -version = "1.0.14" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "ryu" -version = "1.0.16" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" @@ -2669,13 +3014,22 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "scc" +version = "2.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66b202022bb57c049555430e11fc22fea12909276a80a4c3d368da36ac1d88ed" +dependencies = [ + "sdd", +] + [[package]] name = "schannel" -version = "0.1.23" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2694,6 +3048,12 @@ dependencies = [ "untrusted", ] +[[package]] +name = "sdd" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49c1eeaf4b6a87c7479688c6d52b9f1153cedd3c489300564f932b065c6eab95" + [[package]] name = "sec1" version = "0.7.3" @@ -2710,9 +3070,9 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.28.1" +version = "0.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f622567e3b4b38154fb8190bcf6b160d7a4301d70595a49195b48c116007a27" +checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10" dependencies = [ "bitcoin_hashes", "rand", @@ -2741,12 +3101,25 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.9.2" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 1.3.2", - "core-foundation", + "bitflags 2.6.0", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1415a607e92bec364ea2cf9264646dcce0f91e6d65281bd6f2819cca3bf39c8" +dependencies = [ + "bitflags 2.6.0", + "core-foundation 0.10.0", "core-foundation-sys", "libc", "security-framework-sys", @@ -2754,9 +3127,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.9.1" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" dependencies = [ "core-foundation-sys", "libc", @@ -2764,27 +3137,27 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.21" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" +checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.195" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.14" +version = "0.11.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" +checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" dependencies = [ "serde", ] @@ -2801,31 +3174,32 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.195" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.90", ] [[package]] name = "serde_json" -version = "1.0.111" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] [[package]] name = "serde_path_to_error" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd154a240de39fdebcf5775d2675c204d7c13cf39a4c697be6493c8e734337c" +checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" dependencies = [ "itoa", "serde", @@ -2833,20 +3207,20 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" +checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.90", ] [[package]] name = "serde_spanned" -version = "0.6.5" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] @@ -2865,11 +3239,11 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.9.31" +version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adf8a49373e98a4c5f0ceb5d05aa7c648d75f63774981ed95b7c7443bbd50c6e" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.2.1", + "indexmap 2.7.0", "itoa", "ryu", "serde", @@ -2878,27 +3252,27 @@ dependencies = [ [[package]] name = "serial_test" -version = "3.0.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ad9342b3aaca7cb43c45c097dd008d4907070394bd0751a0aa8817e5a018d" +checksum = "1b258109f244e1d6891bf1053a55d63a5cd4f8f4c30cf9a1280989f80e7a1fa9" dependencies = [ - "dashmap", "futures", - "lazy_static", "log", + "once_cell", "parking_lot", + "scc", "serial_test_derive", ] [[package]] name = "serial_test_derive" -version = "3.0.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b93fb4adc70021ac1b47f7d45e8cc4169baaa7ea58483bc5b721d19a26202212" +checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.90", ] [[package]] @@ -2907,7 +3281,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest 0.10.7", ] @@ -2919,7 +3293,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer 0.9.0", - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest 0.9.0", "opaque-debug", @@ -2931,7 +3305,7 @@ version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest 0.10.7", ] @@ -2961,6 +3335,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook" version = "0.3.17" @@ -2973,9 +3353,9 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ "libc", ] @@ -2992,24 +3372,9 @@ dependencies = [ [[package]] name = "simple-error" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc47a29ce97772ca5c927f75bac34866b16d64e07f330c3248e2d7226623901b" - -[[package]] -name = "skeptic" -version = "0.13.7" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8" -dependencies = [ - "bytecount", - "cargo_metadata", - "error-chain", - "glob", - "pulldown-cmark", - "tempfile", - "walkdir", -] +checksum = "7e2accd2c41a0e920d2abd91b2badcfa1da784662f54fbc47e0e3a51f1e2e1cf" [[package]] name = "slab" @@ -3022,18 +3387,18 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" -version = "0.5.5" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -3052,6 +3417,12 @@ dependencies = [ "der", ] +[[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" @@ -3083,14 +3454,14 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.48", + "syn 2.0.90", ] [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "subtle-encoding" @@ -3120,9 +3491,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.48" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -3135,6 +3506,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" + [[package]] name = "synstructure" version = "0.12.6" @@ -3147,6 +3524,17 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "system-configuration" version = "0.5.1" @@ -3154,7 +3542,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ "bitflags 1.3.2", - "core-foundation", + "core-foundation 0.9.4", "system-configuration-sys", ] @@ -3176,22 +3564,22 @@ checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" [[package]] name = "tempfile" -version = "3.9.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "fastrand", - "redox_syscall", + "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "tendermint" -version = "0.34.0" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc2294fa667c8b548ee27a9ba59115472d0a09c2ba255771092a7f1dcf03a789" +checksum = "37d513ce7f9e41c67ab2dd3d554ef65f36fbcc61745af1e1f93eafdeefa1ce37" dependencies = [ "bytes", "digest 0.10.7", @@ -3203,7 +3591,6 @@ dependencies = [ "num-traits", "once_cell", "prost", - "prost-types", "ripemd", "serde", "serde_bytes", @@ -3220,26 +3607,26 @@ dependencies = [ [[package]] name = "tendermint-config" -version = "0.34.0" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a25dbe8b953e80f3d61789fbdb83bf9ad6c0ef16df5ca6546f49912542cc137" +checksum = "4de4e66e78c6bfb768993e69c4fc5333dbc863f6d54ebd7a5d08d91556768087" dependencies = [ "flex-error", "serde", "serde_json", "tendermint", - "toml 0.5.11", + "toml 0.8.19", "url", ] [[package]] name = "tendermint-light-client" -version = "0.34.0" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94aecbdccbc4b557649b2d1b1a4bfc27ec85205e00fb8020fce044245a4c9e3f" +checksum = "3e88c08a112db05101396a79f71c017d7dbf548dc21614f82251f17ecbe5d5e8" dependencies = [ "contracts", - "crossbeam-channel 0.4.4", + "crossbeam-channel", "derive_more", "flex-error", "futures", @@ -3259,12 +3646,11 @@ dependencies = [ [[package]] name = "tendermint-light-client-detector" -version = "0.34.0" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea83654b03e3ddc6782c9704a3fefd4d0671bd6c5e3f09d29e31fcb45e75636c" +checksum = "d48a431ea923182c37ca9f3cc8333490ac6746a64520d1c4a3dd18c08b0806ac" dependencies = [ - "contracts", - "crossbeam-channel 0.4.4", + "crossbeam-channel", "derive_more", "flex-error", "futures", @@ -3283,9 +3669,9 @@ dependencies = [ [[package]] name = "tendermint-light-client-verifier" -version = "0.34.0" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74994da9de4b1144837a367ca2c60c650f5526a7c1a54760a3020959b522e474" +checksum = "7affc5fffe9df158185e15bce3e47fc3a0c901e6708f3b7d33f0867d7aef8ce1" dependencies = [ "derive_more", "flex-error", @@ -3296,16 +3682,13 @@ dependencies = [ [[package]] name = "tendermint-proto" -version = "0.34.0" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc728a4f9e891d71adf66af6ecaece146f9c7a11312288a3107b3e1d6979aaf" +checksum = "c81ba1b023ec00763c3bc4f4376c67c0047f185cccf95c416c7a2f16272c4cbb" dependencies = [ "bytes", "flex-error", - "num-derive", - "num-traits", "prost", - "prost-types", "serde", "serde_bytes", "subtle-encoding", @@ -3314,9 +3697,9 @@ dependencies = [ [[package]] name = "tendermint-rpc" -version = "0.34.0" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbf0a4753b46a190f367337e0163d0b552a2674a6bac54e74f9f2cdcde2969b" +checksum = "4d3ec9d6a266cb079a44272189b5a033227d058ab28659722557c1f7fed6b83c" dependencies = [ "async-trait", "async-tungstenite", @@ -3326,6 +3709,7 @@ dependencies = [ "getrandom", "peg", "pin-project", + "rand", "reqwest", "semver", "serde", @@ -3341,15 +3725,15 @@ dependencies = [ "tokio", "tracing", "url", - "uuid 0.8.2", + "uuid", "walkdir", ] [[package]] name = "tendermint-testgen" -version = "0.34.0" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19d4f02b7e38ce790da973fdc9edc71a0e35340ac57737bf278c8379037c1f5" +checksum = "7d97c36f54bf8754292166604e0c1a16cdbac3c7a2b59cb866f068b25fb0c811" dependencies = [ "ed25519-consensus", "gumdrop", @@ -3372,69 +3756,70 @@ dependencies = [ [[package]] name = "test-log" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6159ab4116165c99fc88cce31f99fa2c9dbe08d3691cb38da02fc3b45f357d2b" +checksum = "3dffced63c2b5c7be278154d76b479f9f9920ed34e7574201407f0b14e2bbb93" dependencies = [ - "env_logger 0.10.2", + "env_logger", "test-log-macros", "tracing-subscriber", ] [[package]] name = "test-log-macros" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ba277e77219e9eea169e8508942db1bf5d8a41ff2db9b20aab5a5aadc9fa25d" +checksum = "5999e24eaa32083191ba4e425deb75cdf25efefabe5aaccb7446dd0d4122a3f5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.90", ] [[package]] name = "textwrap" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" [[package]] name = "thiserror" -version = "1.0.56" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.56" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.90", ] [[package]] name = "thread_local" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "once_cell", ] [[package]] name = "time" -version = "0.3.31" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", + "num-conv", "powerfmt", "serde", "time-core", @@ -3449,10 +3834,11 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.16" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" dependencies = [ + "num-conv", "time-core", ] @@ -3484,11 +3870,21 @@ dependencies = [ "crunchy", ] +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -3501,59 +3897,69 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.35.1" +version = "1.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" +checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] -name = "tokio-io-timeout" -version = "1.2.0" +name = "tokio-macros" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ - "pin-project-lite", + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.12", "tokio", ] [[package]] -name = "tokio-macros" -version = "2.2.0" +name = "tokio-rustls" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", + "rustls 0.22.4", + "rustls-pki-types", + "tokio", ] [[package]] name = "tokio-rustls" -version = "0.24.1" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" dependencies = [ - "rustls", + "rustls 0.23.20", "tokio", ] [[package]] name = "tokio-stream" -version = "0.1.14" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" dependencies = [ "futures-core", "pin-project-lite", @@ -3562,16 +3968,15 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.10" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" dependencies = [ "bytes", "futures-core", "futures-sink", "pin-project-lite", "tokio", - "tracing", ] [[package]] @@ -3585,9 +3990,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.8" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", "serde_spanned", @@ -3597,20 +4002,20 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.21.0" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.2.1", + "indexmap 2.7.0", "serde", "serde_spanned", "toml_datetime", @@ -3619,30 +4024,32 @@ dependencies = [ [[package]] name = "tonic" -version = "0.10.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d560933a0de61cf715926b9cac824d4c883c2c43142f787595e48280c40a1d0e" +checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" dependencies = [ "async-stream", "async-trait", - "axum", - "base64 0.21.7", + "axum 0.7.9", + "base64 0.22.1", "bytes", - "h2", - "http", - "http-body", - "hyper", + "h2 0.4.7", + "http 1.2.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.5.1", "hyper-timeout", + "hyper-util", "percent-encoding", "pin-project", "prost", - "rustls", - "rustls-native-certs", - "rustls-pemfile", + "rustls-native-certs 0.8.1", + "rustls-pemfile 2.2.0", + "socket2", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.1", "tokio-stream", - "tower", + "tower 0.4.13", "tower-layer", "tower-service", "tracing", @@ -3668,23 +4075,37 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 1.0.2", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-layer" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "log", "pin-project-lite", @@ -3694,20 +4115,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.90", ] [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", "valuable", @@ -3715,9 +4136,9 @@ dependencies = [ [[package]] name = "tracing-error" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" +checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" dependencies = [ "tracing", "tracing-subscriber", @@ -3747,9 +4168,9 @@ dependencies = [ [[package]] name = "tracing-serde" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" dependencies = [ "serde", "tracing-core", @@ -3757,9 +4178,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ "matchers", "nu-ansi-term", @@ -3790,18 +4211,19 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tungstenite" -version = "0.20.1" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" dependencies = [ "byteorder", "bytes", "data-encoding", - "http", + "http 1.2.0", "httparse", "log", "rand", - "rustls", + "rustls 0.22.4", + "rustls-pki-types", "sha1", "thiserror", "url", @@ -3826,53 +4248,38 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "unicase" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] [[package]] name = "unicode-width" -version = "0.1.11" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "unsafe-libyaml" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" [[package]] name = "untrusted" @@ -3882,9 +4289,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.0" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", @@ -3903,6 +4310,12 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + [[package]] name = "utf8-width" version = "0.1.7" @@ -3910,22 +4323,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" [[package]] -name = "utf8parse" -version = "0.2.1" +name = "utf8_iter" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] -name = "uuid" -version = "0.8.2" +name = "utf8parse" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.7.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" dependencies = [ "getrandom", ] @@ -3938,9 +4351,9 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wait-timeout" @@ -3953,9 +4366,9 @@ dependencies = [ [[package]] name = "walkdir" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", @@ -3978,46 +4391,47 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.90" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.90" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.90", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.40" +version = "0.4.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bde2032aeb86bdfaecc8b261eef3cba735cc426c1f3a3416d1e0791be95fc461" +checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.90" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4025,28 +4439,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.90" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.90", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.90" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" [[package]] name = "web-sys" -version = "0.3.67" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed" +checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" dependencies = [ "js-sys", "wasm-bindgen", @@ -4070,11 +4484,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "winapi", + "windows-sys 0.59.0", ] [[package]] @@ -4083,6 +4497,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -4098,7 +4521,16 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -4118,17 +4550,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -4139,9 +4572,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -4151,9 +4584,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -4163,9 +4596,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -4175,9 +4614,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -4187,9 +4626,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -4199,9 +4638,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -4211,15 +4650,15 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.5.34" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7cf47b659b318dccbd69cc4797a39ae128f533dce7902a1096044d1967b9c16" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] @@ -4230,15 +4669,93 @@ version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "windows-sys 0.48.0", ] +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", + "synstructure 0.13.1", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", + "synstructure 0.13.1", +] + [[package]] name = "zeroize" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" dependencies = [ "zeroize_derive", ] @@ -4251,5 +4768,27 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.90", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", ] diff --git a/Cargo.toml b/Cargo.toml index c651008bfc..c634628408 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,107 @@ exclude = [ "tools/query-events", ] +[workspace.dependencies] +# Hermes dependencies +ibc-relayer-cli = { version = "1.10.5", path = "crates/relayer-cli" } +ibc-relayer = { version = "0.29.5", path = "crates/relayer" } +ibc-relayer-rest = { version = "0.29.5", path = "crates/relayer-rest" } +ibc-relayer-types = { version = "0.29.5", path = "crates/relayer-types" } +ibc-chain-registry = { version = "0.29.5", path = "crates/chain-registry" } +ibc-telemetry = { version = "0.29.5", path = "crates/telemetry" } +ibc-test-framework = { version = "0.29.5", path = "tools/test-framework" } +ibc-integration-test = { version = "0.29.5", path = "tools/integration-test" } + +# IBC dependencies +ibc-proto = "0.51.0" +ics23 = "0.12.0" + +# Tendermint dependencies +tendermint = { version = "0.40.0", default-features = false } +tendermint-light-client = { version = "0.40.0", default-features = false } +tendermint-light-client-detector = { version = "0.40.0", default-features = false } +tendermint-light-client-verifier = { version = "0.40.0", default-features = false } +tendermint-proto = { version = "0.40.0" } +tendermint-rpc = { version = "0.40.0" } +tendermint-testgen = { version = "0.40.0" } + + +# Other dependencies +abscissa_core = "=0.6.0" +anyhow = "1.0" +async-stream = "0.3.6" +async-trait = "0.1.83" +axum = "0.6.18" +bech32 = "0.9.1" +bitcoin = "0.31.2" +bs58 = "0.5.1" +byte-unit = { version = "4.0.19", default-features = false } +bytes = "1.8.0" +clap = "3.2" +clap_complete = "3.2" +color-eyre = "0.6" +console = "0.15.5" +crossbeam-channel = "0.5.12" +dashmap = "5.4.0" +derive_more = { version = "0.99.18", default-features = false } +dialoguer = "0.11.0" +digest = "0.10.6" +dirs-next = "2.0.0" +ed25519 = "2.2.2" +ed25519-dalek = "2.0.0" +ed25519-dalek-bip32 = "0.3.0" +env_logger = "0.11.5" +eyre = "0.6.12" +flex-error = { version = "0.4.4", default-features = false } +futures = "0.3.27" +generic-array = "0.14.7" +hdpath = "0.6.3" +hex = "0.4.3" +http = "1.0.0" +humantime = "2.1.0" +humantime-serde = "1.1.1" +itertools = "0.13.0" +moka = "0.12.8" +num-bigint = "0.4" +num-rational = "0.4.1" +once_cell = "1.20.2" +oneline-eyre = "0.1" +opentelemetry = "0.19.0" +opentelemetry-prometheus = "0.12.0" +primitive-types = { version = "0.12.1", default-features = false } +prometheus = "0.13.4" +prost = "0.13" +rand = "0.8.5" +regex = "1.11.1" +reqwest = { version = "0.11.27", default-features = false } +retry = { version = "2.0.0", default-features = false } +ripemd = "0.1.3" +secp256k1 = "0.28.2" +semver = "1.0.21" +serde = "1.0.214" +serde_derive = "1.0.104" +serde_json = "1.0.132" +serde_yaml = "0.9.34" +serial_test = "3.2.0" +sha2 = "0.10.6" +signal-hook = "0.3.17" +signature = "2.1.0" +strum = "0.25" +subtle-encoding = "0.5.1" +test-log = "0.2.14" +thiserror = "1.0.69" +time = "0.3" +tiny-bip39 = "1.0.0" +tiny-keccak = { version = "2.0.2", default-features = false } +tokio = "1.39.2" +tokio-stream = "0.1.16" +toml = "0.8.19" +tonic = "0.12" +tracing = { version = "0.1.36", default-features = false } +tracing-subscriber = "0.3.14" +uint = "0.9" +uuid = "1.11.0" + [profile.release] overflow-checks = true diff --git a/README.md b/README.md index b816b659e0..7dccced969 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,14 @@ # Hermes IBC relayer +![hermes-banner](https://github.com/informalsystems/hermes/assets/1757002/0878ab2a-1c6f-4137-a089-66352f948407) + [![Cosmos ecosystem][cosmos-shield]][cosmos-link] [![Build Status][build-image]][build-link] [![Integration tests][test-image]][test-link] [![Apache 2.0 Licensed][license-image]][license-link] ![Rust Stable][rustc-image] -![Rust 1.71+][rustc-version] +![Rust 1.76+][rustc-version] Rust implementation of an Inter-Blockchain Communication (IBC) relayer. @@ -46,7 +48,7 @@ The repository also includes [TLA+ specifications](docs/spec). ## Requirements -The crates in this project require Rust `1.71.0`. +The crates in this project require Rust `1.76.0`. ## Hermes Guide @@ -116,12 +118,12 @@ Unless required by applicable law or agreed to in writing, software distributed [build-image]: https://github.com/informalsystems/hermes/workflows/Rust/badge.svg [build-link]: https://github.com/informalsystems/hermes/actions?query=workflow%3ARust -[test-image]: https://github.com/informalsystems/hermes/workflows/Integration/badge.svg +[test-image]: https://github.com/informalsystems/hermes/actions/workflows/integration.yaml/badge.svg?branch=master [test-link]: https://github.com/informalsystems/hermes/actions?query=workflow%3A%22Integration%22 [license-image]: https://img.shields.io/badge/license-Apache_2.0-blue.svg [license-link]: https://github.com/informalsystems/hermes/blob/master/LICENSE [rustc-image]: https://img.shields.io/badge/rustc-stable-blue.svg -[rustc-version]: https://img.shields.io/badge/rustc-1.71+-blue.svg +[rustc-version]: https://img.shields.io/badge/rustc-1.76+-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/misbehaviour-ics/double_sign_test.sh b/ci/misbehaviour-ics/double_sign_test.sh index 3685868433..4829f59c0f 100644 --- a/ci/misbehaviour-ics/double_sign_test.sh +++ b/ci/misbehaviour-ics/double_sign_test.sh @@ -1,6 +1,10 @@ #!/bin/bash # shellcheck disable=2086,2004 +## Prerequisites: +# * ICS v6.x +# * Hermes v1.10.3+45a29cc00 + set -eu DEBUG=${DEBUG:-false} @@ -9,13 +13,6 @@ if [ "$DEBUG" = true ]; then set -x fi -# User balance of stake tokens -USER_COINS="100000000000stake" -# Amount of stake tokens staked -STAKE="100000000stake" -# Node IP address -NODE_IP="127.0.0.1" - # Home directory HOME_DIR="/tmp/hermes-ics-double-sign" @@ -25,11 +22,19 @@ if [ "$DEBUG" = true ]; then else HERMES_DEBUG="" fi + # Hermes config HERMES_CONFIG="$HOME_DIR/hermes.toml" # Hermes binary HERMES_BIN="cargo run -q --bin hermes -- $HERMES_DEBUG --config $HERMES_CONFIG" +# User balance of stake tokens +USER_COINS="100000000000stake" +# Amount of stake tokens staked +STAKE="100000000stake" +# Node IP address +NODE_IP="127.0.0.1" + # Validator moniker MONIKERS=("coordinator" "alice" "bob") LEAD_VALIDATOR_MONIKER="coordinator" @@ -51,13 +56,8 @@ CLIENT_BASEPORT=29220 # Clean start pkill -f interchain-security-pd &> /dev/null || true -pkill -f interchain-security-cd &> /dev/null || true -pkill -f hermes &> /dev/null || true sleep 1 - -mkdir -p "${HOME_DIR}" -rm -rf "${PROV_NODES_ROOT_DIR}" -rm -rf "${CONS_NODES_ROOT_DIR}" +rm -rf ${PROV_NODES_ROOT_DIR} # Let lead validator create genesis file LEAD_VALIDATOR_PROV_DIR=${PROV_NODES_ROOT_DIR}/provider-${LEAD_VALIDATOR_MONIKER} @@ -70,7 +70,6 @@ do MONIKER=${MONIKERS[$index]} # validator key PROV_KEY=${MONIKER}-key - PROV_KEY2=${MONIKER}-key2 # home directory of this validator on provider PROV_NODE_DIR=${PROV_NODES_ROOT_DIR}/provider-${MONIKER} @@ -80,16 +79,17 @@ do # Build genesis file and node directory structure interchain-security-pd init $MONIKER --chain-id provider --home ${PROV_NODE_DIR} - jq ".app_state.gov.params.voting_period = \"5s\" | .app_state.staking.params.unbonding_time = \"86400s\"" \ + jq ".app_state.gov.params.voting_period = \"10s\" \ + | .app_state.gov.params.expedited_voting_period = \"9s\" \ + | .app_state.staking.params.unbonding_time = \"86400s\" \ + | .app_state.provider.params.blocks_per_epoch = \"5\"" \ ${PROV_NODE_DIR}/config/genesis.json > \ ${PROV_NODE_DIR}/edited_genesis.json && mv ${PROV_NODE_DIR}/edited_genesis.json ${PROV_NODE_DIR}/config/genesis.json - sleep 1 # Create account keypair - interchain-security-pd keys add $PROV_KEY --home ${PROV_NODE_DIR} --keyring-backend test --output json > ${PROV_NODE_DIR}/${PROV_KEY}.json 2>&1 - interchain-security-pd keys add $PROV_KEY2 --home ${PROV_NODE_DIR} --keyring-backend test --output json > ${PROV_NODE_DIR}/${PROV_KEY2}.json 2>&1 + interchain-security-pd keys add $PROV_KEY --home ${PROV_NODE_DIR} --keyring-backend test --output json > ${PROV_NODE_DIR}/${PROV_KEY}.json 2>&1 sleep 1 # copy genesis in, unless this validator is the lead validator @@ -100,9 +100,6 @@ do # Add stake to user PROV_ACCOUNT_ADDR=$(jq -r '.address' ${PROV_NODE_DIR}/${PROV_KEY}.json) interchain-security-pd genesis add-genesis-account $PROV_ACCOUNT_ADDR $USER_COINS --home ${PROV_NODE_DIR} --keyring-backend test - - PROV_ACCOUNT_ADDR2=$(jq -r '.address' ${PROV_NODE_DIR}/${PROV_KEY2}.json) - interchain-security-pd genesis add-genesis-account $PROV_ACCOUNT_ADDR2 $USER_COINS --home ${PROV_NODE_DIR} --keyring-backend test sleep 1 # copy genesis out, unless this validator is the lead validator @@ -141,10 +138,10 @@ do fi # Stake 1/1000 user's coins - interchain-security-pd genesis gentx $PROV_KEY $STAKE --chain-id provider --home ${PROV_NODE_DIR} --keyring-backend test --moniker $MONIKER + interchain-security-pd genesis gentx $PROV_KEY $STAKE --chain-id provider --home ${PROV_NODE_DIR} --keyring-backend test --moniker $MONIKER sleep 1 - # Copy gentxs to the lead validator for possible future collection. + # Copy gentxs to the lead validator for possible future collection. # Obviously we don't need to copy the first validator's gentx to itself if [ $MONIKER != $LEAD_VALIDATOR_MONIKER ]; then cp ${PROV_NODE_DIR}/config/gentx/* ${LEAD_VALIDATOR_PROV_DIR}/config/gentx/ @@ -183,7 +180,6 @@ do # validator key PROV_KEY=${MONIKER}-key - PROV_KEY2=${MONIKER}-key2 # home directory of this validator on provider PROV_NODE_DIR=${PROV_NODES_ROOT_DIR}/provider-${MONIKER} @@ -219,89 +215,217 @@ do done # Build consumer chain proposal file -tee ${LEAD_VALIDATOR_PROV_DIR}/consumer-proposal.json< /dev/null || true +sleep 1 +rm -rf ${CONS_NODES_ROOT_DIR} + for index in "${!MONIKERS[@]}" do MONIKER=${MONIKERS[$index]} # validator key PROV_KEY=${MONIKER}-key - PROV_KEY2=${MONIKER}-key2 PROV_NODE_DIR=${PROV_NODES_ROOT_DIR}/provider-${MONIKER} @@ -314,8 +438,7 @@ do sleep 1 # Create account keypair - interchain-security-cd keys add $PROV_KEY --home ${CONS_NODE_DIR} --keyring-backend test --output json > ${CONS_NODE_DIR}/${PROV_KEY}.json 2>&1 - interchain-security-cd keys add $PROV_KEY2 --home ${CONS_NODE_DIR} --keyring-backend test --output json > ${CONS_NODE_DIR}/${PROV_KEY2}.json 2>&1 + interchain-security-cd keys add $PROV_KEY --home ${CONS_NODE_DIR} --keyring-backend test --output json > ${CONS_NODE_DIR}/${PROV_KEY}.json 2>&1 sleep 1 # copy genesis in, unless this validator is the lead validator @@ -326,15 +449,15 @@ do # Add stake to user CONS_ACCOUNT_ADDR=$(jq -r '.address' ${CONS_NODE_DIR}/${PROV_KEY}.json) interchain-security-cd genesis add-genesis-account $CONS_ACCOUNT_ADDR $USER_COINS --home ${CONS_NODE_DIR} - CONS_ACCOUNT_ADDR2=$(jq -r '.address' ${CONS_NODE_DIR}/${PROV_KEY2}.json) - interchain-security-cd genesis add-genesis-account $CONS_ACCOUNT_ADDR2 $USER_COINS --home ${CONS_NODE_DIR} - sleep 10 ### this probably does not have to be done for each node # Add consumer genesis states to genesis file RPC_LADDR_PORT=$(($RPC_LADDR_BASEPORT + $index)) RPC_LADDR=tcp://${NODE_IP}:${RPC_LADDR_PORT} - interchain-security-pd query provider consumer-genesis consumer --home ${PROV_NODE_DIR} --node ${RPC_LADDR} -o json > consumer_gen.json + interchain-security-pd query provider consumer-genesis $CONSUMER_ID \ + --home ${PROV_NODE_DIR} \ + --node ${RPC_LADDR} -o json > consumer_gen.json + jq -s '.[0].app_state.ccvconsumer = .[1] | .[0]' ${CONS_NODE_DIR}/config/genesis.json consumer_gen.json > ${CONS_NODE_DIR}/edited_genesis.json \ && mv ${CONS_NODE_DIR}/edited_genesis.json ${CONS_NODE_DIR}/config/genesis.json rm consumer_gen.json @@ -376,7 +499,6 @@ done sleep 1 - for index in "${!MONIKERS[@]}" do MONIKER=${MONIKERS[$index]} @@ -437,42 +559,13 @@ do sleep 6 done -## Cause double signing - -# create directory for double signing node -mkdir $CONS_NODES_ROOT_DIR/consumer-bob-sybil/ -cp -r $CONS_NODES_ROOT_DIR/consumer-bob/* $CONS_NODES_ROOT_DIR/consumer-bob-sybil - -# clear state in consumer-bob-sybil -echo '{"height": "0","round": 0,"step": 0,"signature":"","signbytes":""}' > $CONS_NODES_ROOT_DIR/consumer-bob-sybil/data/priv_validator_state.json - -# add new node key to sybil -# key was generated using gaiad init -# if the node key is not unique, double signing cannot be achieved -# and errors such as this can be seen in the terminal -# 5:54PM ERR found conflicting vote from ourselves; did you unsafe_reset a validator? height=1961 module=consensus round=0 type=2 -# 5:54PM ERR failed to process message err="conflicting votes from validator C888306A908A217B9A943D1DAD8790044D0947A4" -echo '{"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"tj55by/yYwruSz4NxsOG9y9k2WrPvKLXKQdz/9jL9Uptmi647OYpcisjwf92TyA+wCUYVDOgW7D53Q+638l9/w=="}}' > $CONS_NODES_ROOT_DIR/consumer-bob-sybil/config/node_key.json - -# does not use persistent peers; will do a lookup in genesis.json to find peers -#ARGS="--address tcp://$CHAIN_PREFIX.252:26655 --rpc.laddr tcp://$CHAIN_PREFIX.252:26658 --grpc.address $CHAIN_PREFIX.252:9091 --log_level trace --p2p.laddr tcp://$CHAIN_PREFIX.252:26656 --grpc-web.enable=false" - -# start double signing node - it should not talk to the node with the same key -#ip netns exec $HOME/nodes/consumer/consumer-bob-sybil $BIN $ARGS --home $HOME/nodes/consumer/consumer-bob-sybil start &> $HOME/nodes/consumer/consumer-bob-sybil/logs & - -# Start gaia -interchain-security-cd start \ - --home $CONS_NODES_ROOT_DIR/consumer-bob-sybil \ - --p2p.persistent_peers ${PERSISTENT_PEERS} \ - --rpc.laddr tcp://${NODE_IP}:29179 \ - --grpc.address ${NODE_IP}:29199 \ - --address tcp://${NODE_IP}:29209 \ - --p2p.laddr tcp://${NODE_IP}:29189 \ - --grpc-web.enable=false &> $CONS_NODES_ROOT_DIR/consumer-bob-sybil/logs & +## Setup Hermes -# Setup Hermes config file +HERMES_PROV_NODE_DIR=${PROV_NODES_ROOT_DIR}/provider-${HERMES_VALIDATOR_MONIKER} +HERMES_KEY=${HERMES_VALIDATOR_MONIKER}-key +HERMES_CONS_NODE_DIR=${CONS_NODES_ROOT_DIR}/consumer-${HERMES_VALIDATOR_MONIKER} -tee $HERMES_CONFIG< $HOME_DIR/hermes-start-logs.txt & +sleep 5 + +## Cause double signing + +CONS_NODE_SYBIL_DIR=${CONS_NODES_ROOT_DIR}/consumer-${MONIKER}-sybil + +# create directory for double signing node +mkdir $CONS_NODE_SYBIL_DIR +cp -r $CONS_NODE_DIR/* $CONS_NODE_SYBIL_DIR + +# clear state in sybil node directory +echo '{"height": "0","round": 0,"step": 0,"signature":"","signbytes":""}' \ + > $CONS_NODE_SYBIL_DIR/data/priv_validator_state.json + +# add new node key to sybil +# key was generated using gaiad init +# if the node key is not unique, double signing cannot be achieved +# and errors such as this can be seen in the terminal +# 5:54PM ERR found conflicting vote from ourselves; did you unsafe_reset a validator? height=1961 module=consensus round=0 type=2 +# 5:54PM ERR failed to process message err="conflicting votes from validator C888306A908A217B9A943D1DAD8790044D0947A4" +echo '{"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"tj55by/yYwruSz4NxsOG9y9k2WrPvKLXKQdz/9jL9Uptmi647OYpcisjwf92TyA+wCUYVDOgW7D53Q+638l9/w=="}}' \ + > $CONS_NODE_SYBIL_DIR/config/node_key.json + +# does not use persistent peers; will do a lookup in genesis.json to find peers +# start double signing node - it should not talk to the node with the same key + +# Start gaia +interchain-security-cd start \ + --home ${CONS_NODE_SYBIL_DIR} \ + --rpc.laddr tcp://${NODE_IP}:$((RPC_LADDR_PORT+1)) \ + --grpc.address ${NODE_IP}:$((GRPC_LADDR_PORT+1)) \ + --address tcp://${NODE_IP}:$((NODE_ADDRESS_PORT+1)) \ + --p2p.laddr tcp://${NODE_IP}:$((P2P_LADDR_PORT+1)) \ + --grpc-web.enable=false &> ${CONS_NODE_SYBIL_DIR}/logs & + +sleep 5 + +## start Hermes in evidence mode +$HERMES_BIN evidence --chain consumer --check-past-blocks 0 &> $HOME_DIR/hermes-evidence-logs.txt & -$HERMES_BIN evidence --chain consumer --key-name evidence &> $HOME_DIR/hermes-evidence-logs.txt & +sleep 1 + +# Wait for Hermes to submit double signing evidence +$HERMES_BIN update client --host-chain consumer --client 07-tendermint-0 for _ in $(seq 1 10) do sleep 5 MSG="successfully submitted double voting evidence to chain" - + if grep -c "$MSG" $HOME_DIR/hermes-evidence-logs.txt; then echo "[SUCCESS] Successfully submitted double voting evidence to provider chain" exit 0 @@ -600,9 +717,6 @@ done echo "[ERROR] Failed to submit double voting evidence to provider chain" echo "" echo "---------------------------------------------------------------" -echo "Hermes start logs:" -cat $HOME_DIR/hermes-start-logs.txt -echo "---------------------------------------------------------------" echo "Hermes evidence logs:" cat $HOME_DIR/hermes-evidence-logs.txt echo "---------------------------------------------------------------" diff --git a/ci/misbehaviour-ics/light_client_attack_freeze_test.sh b/ci/misbehaviour-ics/light_client_attack_freeze_test.sh index 24661ace22..2cd1b50f58 100644 --- a/ci/misbehaviour-ics/light_client_attack_freeze_test.sh +++ b/ci/misbehaviour-ics/light_client_attack_freeze_test.sh @@ -85,7 +85,10 @@ rm -rf "${CONS_FORK_NODE_DIR}" # Build genesis file and node directory structure interchain-security-pd init $MONIKER --chain-id provider --home ${PROV_NODE_DIR} -jq ".app_state.gov.params.voting_period = \"5s\" | .app_state.staking.params.unbonding_time = \"86400s\"" \ +jq ".app_state.gov.params.voting_period = \"5s\" \ +| .app_state.gov.params.expedited_voting_period = \"4s\" \ +| .app_state.staking.params.unbonding_time = \"86400s\" \ +| .app_state.provider.params.blocks_per_epoch = \"5\"" \ ${PROV_NODE_DIR}/config/genesis.json > \ ${PROV_NODE_DIR}/edited_genesis.json && mv ${PROV_NODE_DIR}/edited_genesis.json ${PROV_NODE_DIR}/config/genesis.json @@ -160,31 +163,171 @@ interchain-security-pd start \ waiting 10 "for provider sub-node to start" # Build consumer chain proposal file -tee ${PROV_NODE_DIR}/consumer-proposal.json< consumer_gen.json +interchain-security-pd query provider consumer-genesis $CONSUMER_ID --home ${PROV_NODE_DIR} -o json > consumer_gen.json jq -s '.[0].app_state.ccvconsumer = .[1] | .[0]' ${CONS_NODE_DIR}/config/genesis.json consumer_gen.json > ${CONS_NODE_DIR}/edited_genesis.json \ && mv ${CONS_NODE_DIR}/edited_genesis.json ${CONS_NODE_DIR}/config/genesis.json rm consumer_gen.json @@ -296,7 +439,7 @@ rpc_addr = "http://${NODE_IP}:26648" rpc_timeout = "10s" store_prefix = "ibc" trusting_period = "2days" -event_source = { mode = 'push', url = 'ws://${NODE_IP}:26648/websocket' , batch_delay = '50ms' } +event_source = { mode = 'pull', interval = '500ms', max_retries = 4 } [chains.gas_price] denom = "stake" @@ -319,7 +462,7 @@ rpc_addr = "http://${NODE_IP}:26658" rpc_timeout = "10s" store_prefix = "ibc" trusting_period = "2days" -event_source = { mode = 'push', url = 'ws://${NODE_IP}:26658/websocket' , batch_delay = '50ms' } +event_source = { mode = 'pull', interval = '500ms', max_retries = 4 } [chains.gas_price] denom = "stake" @@ -419,7 +562,7 @@ rpc_addr = "http://${NODE_IP}:26638" rpc_timeout = "10s" store_prefix = "ibc" trusting_period = "2days" -event_source = { mode = 'push', url = 'ws://${NODE_IP}:26638/websocket' , batch_delay = '50ms' } +event_source = { mode = 'pull', interval = '500ms', max_retries = 4 } [chains.gas_price] denom = "stake" @@ -442,7 +585,7 @@ rpc_addr = "http://${NODE_IP}:26658" rpc_timeout = "10s" store_prefix = "ibc" trusting_period = "2days" -event_source = { mode = 'push', url = 'ws://${NODE_IP}:26658/websocket' , batch_delay = '50ms' } +event_source = { mode = 'pull', interval = '500ms', max_retries = 4 } [chains.gas_price] denom = "stake" @@ -506,6 +649,7 @@ if [ "$FROZEN_HEIGHT" != "null" ]; then diag "Client is frozen, as expected." else diag "Client is not frozen, aborting." + ${HOME_DIR}/hermes-evidence-logs.txt exit 1 fi @@ -513,6 +657,7 @@ if grep -q "found light client attack evidence" ${HOME_DIR}/hermes-evidence-logs diag "Evidence found, proceeding." else diag "Evidence not found, aborting." + cat ${HOME_DIR}/hermes-evidence-logs.txt exit 1 fi diff --git a/ci/misbehaviour-ics/light_client_attack_test.sh b/ci/misbehaviour-ics/light_client_attack_test.sh index f42982c353..9d5d93c472 100644 --- a/ci/misbehaviour-ics/light_client_attack_test.sh +++ b/ci/misbehaviour-ics/light_client_attack_test.sh @@ -85,7 +85,10 @@ rm -rf "${CONS_FORK_NODE_DIR}" # Build genesis file and node directory structure interchain-security-pd init $MONIKER --chain-id provider --home ${PROV_NODE_DIR} -jq ".app_state.gov.params.voting_period = \"5s\" | .app_state.staking.params.unbonding_time = \"86400s\"" \ +jq ".app_state.gov.params.voting_period = \"5s\" \ +| .app_state.gov.params.expedited_voting_period = \"4s\" \ +| .app_state.staking.params.unbonding_time = \"86400s\" \ +| .app_state.provider.params.blocks_per_epoch = \"5\"" \ ${PROV_NODE_DIR}/config/genesis.json > \ ${PROV_NODE_DIR}/edited_genesis.json && mv ${PROV_NODE_DIR}/edited_genesis.json ${PROV_NODE_DIR}/config/genesis.json @@ -169,33 +172,173 @@ interchain-security-pd start \ waiting 5 "for provider sub-node to start" # Build consumer chain proposal file -tee ${PROV_NODE_DIR}/consumer-proposal.json< consumer_gen.json +interchain-security-pd query provider consumer-genesis $CONSUMER_ID --home ${PROV_NODE_DIR} -o json > consumer_gen.json jq -s '.[0].app_state.ccvconsumer = .[1] | .[0]' ${CONS_NODE_DIR}/config/genesis.json consumer_gen.json > ${CONS_NODE_DIR}/edited_genesis.json \ && mv ${CONS_NODE_DIR}/edited_genesis.json ${CONS_NODE_DIR}/config/genesis.json rm consumer_gen.json @@ -305,7 +448,7 @@ rpc_addr = "http://${NODE_IP}:26648" rpc_timeout = "10s" store_prefix = "ibc" trusting_period = "2days" -event_source = { mode = 'push', url = 'ws://${NODE_IP}:26648/websocket' , batch_delay = '50ms' } +event_source = { mode = 'pull', interval = '500ms', max_retries = 4 } [chains.gas_price] denom = "stake" @@ -328,7 +471,7 @@ rpc_addr = "http://${NODE_IP}:26658" rpc_timeout = "10s" store_prefix = "ibc" trusting_period = "2days" -event_source = { mode = 'push', url = 'ws://${NODE_IP}:26658/websocket' , batch_delay = '50ms' } +event_source = { mode = 'pull', interval = '500ms', max_retries = 4 } [chains.gas_price] denom = "stake" @@ -445,7 +588,7 @@ rpc_addr = "http://${NODE_IP}:26638" rpc_timeout = "10s" store_prefix = "ibc" trusting_period = "2days" -event_source = { mode = 'push', url = 'ws://${NODE_IP}:26638/websocket' , batch_delay = '50ms' } +event_source = { mode = 'pull', interval = '500ms', max_retries = 4 } [chains.gas_price] denom = "stake" @@ -467,7 +610,7 @@ rpc_addr = "http://${NODE_IP}:26658" rpc_timeout = "10s" store_prefix = "ibc" trusting_period = "2days" -event_source = { mode = 'push', url = 'ws://${NODE_IP}:26658/websocket' , batch_delay = '50ms' } +event_source = { mode = 'pull', interval = '500ms', max_retries = 4 } [chains.gas_price] denom = "stake" @@ -479,6 +622,7 @@ event_source = { mode = 'push', url = 'ws://${NODE_IP}:26658/websocket' , batch_ EOF waiting 10 "for a couple blocks" +sleep 5 read -r height hash < <( curl -s "localhost:26648"/commit \ @@ -512,7 +656,7 @@ waiting 10 "for Hermes relayer to start" diag "Running Hermes relayer evidence command" # Run hermes in evidence mode -$HERMES_BIN evidence --chain consumer &> ${HOME_DIR}/hermes-evidence-logs.txt & +$HERMES_BIN --debug=rpc evidence --chain consumer &> ${HOME_DIR}/hermes-evidence-logs.txt & # If we sleep 5 here and above, we end up on the forked block later waiting 10 "for Hermes evidence monitor to start" @@ -555,6 +699,7 @@ if grep -q "found light client attack evidence" ${HOME_DIR}/hermes-evidence-logs diag "Evidence found, proceeding!" else diag "Evidence not found, aborting." + cat ${HOME_DIR}/hermes-evidence-logs.txt exit 1 fi diff --git a/ci/misbehaviour/config.toml b/ci/misbehaviour/config.toml index 92845f89ed..41b18706fd 100644 --- a/ci/misbehaviour/config.toml +++ b/ci/misbehaviour/config.toml @@ -211,6 +211,19 @@ gas_price = { price = 0.001, denom = 'stake' } # Minimum value: 1.0 gas_multiplier = 1.3 +# Query the current gas price from the chain instead of using the static `gas_price` from the config. +# Useful for chains which have [EIP-1559][eip]-like dynamic gas price. +# +# At the moment, only chains which support the `osmosis.txfees.v1beta1.Query/GetEipBaseFee` +# query or have enabled Skip's `x/feemarket` module https://github.com/skip-mev/feemarket +# can be used with dynamic gas price enabled. +# +# See this page in the Hermes guide for more information: +# https://hermes.informal.systems/documentation/configuration/dynamic-gas-fees.html +# +# Default: { enabled = false, multiplier = 1.1, max = 0.6 } +dynamic_gas_price = { enabled = true, multiplier = 1.3, max = 5.0 } + # Specify how many IBC messages at most to include in a single transaction. # Default: 30 max_msg_num = 30 @@ -314,6 +327,7 @@ default_gas = 100000 max_gas = 400000 gas_price = { price = 0.001, denom = 'stake' } gas_multiplier = 1.3 +dynamic_gas_price = { enabled = true, multiplier = 1.3, max = 5.0 } max_msg_num = 30 max_tx_size = 2097152 clock_drift = '5s' diff --git a/ci/misbehaviour/config_fork.toml b/ci/misbehaviour/config_fork.toml index 060dda1566..d637f8db48 100644 --- a/ci/misbehaviour/config_fork.toml +++ b/ci/misbehaviour/config_fork.toml @@ -208,7 +208,20 @@ gas_price = { price = 0.001, denom = 'stake' } # # Default: 1.1, ie. the gas is increased by 10% # Minimum value: 1.0 -gas_multiplier = 1.1 +gas_multiplier = 1.3 + +# Query the current gas price from the chain instead of using the static `gas_price` from the config. +# Useful for chains which have [EIP-1559][eip]-like dynamic gas price. +# +# At the moment, only chains which support the `osmosis.txfees.v1beta1.Query/GetEipBaseFee` +# query or have enabled Skip's `x/feemarket` module https://github.com/skip-mev/feemarket +# can be used with dynamic gas price enabled. +# +# See this page in the Hermes guide for more information: +# https://hermes.informal.systems/documentation/configuration/dynamic-gas-fees.html +# +# Default: { enabled = false, multiplier = 1.1, max = 0.6 } +dynamic_gas_price = { enabled = true, multiplier = 1.3, max = 5.0 } # Specify how many IBC messages at most to include in a single transaction. # Default: 30 @@ -312,7 +325,8 @@ store_prefix = 'ibc' default_gas = 100000 max_gas = 400000 gas_price = { price = 0.001, denom = 'stake' } -gas_multiplier = 1.1 +gas_multiplier = 1.3 +dynamic_gas_price = { enabled = true, multiplier = 1.3, max = 5.0 } max_msg_num = 30 max_tx_size = 2097152 clock_drift = '5s' diff --git a/ci/misbehaviour/create_fork.sh b/ci/misbehaviour/create_fork.sh index 66092298d0..c21eefa7f0 100755 --- a/ci/misbehaviour/create_fork.sh +++ b/ci/misbehaviour/create_fork.sh @@ -50,7 +50,7 @@ sconfig data/ibc-1-f/config/config.toml "rpc.laddr=tcp://0.0.0.0:26457" sconfig data/ibc-1-f/config/config.toml "p2p.laddr=tcp://0.0.0.0:26456" info "Starting ibc-1..." -gaiad --home ./data/ibc-1 start --pruning=nothing --grpc.address=0.0.0.0:9091 --log_level error > data/ibc-1.log 2>&1 & +gaiad --home ./data/ibc-1 start --pruning=nothing --rpc.laddr="tcp://0.0.0.0:26557" --grpc.address=0.0.0.0:9091 --log_level error > data/ibc-1.log 2>&1 & info "Starting ibc-1 fork..." -gaiad --home ./data/ibc-1-f start --pruning=nothing --grpc.address=0.0.0.0:9092 --log_level error > data/ibc-1-f.log 2>&1 & +gaiad --home ./data/ibc-1-f start --pruning=nothing --rpc.laddr="tcp://0.0.0.0:26457" --grpc.address=0.0.0.0:9092 --log_level error > data/ibc-1-f.log 2>&1 & diff --git a/ci/release/hermes.Dockerfile b/ci/release/hermes.Dockerfile index 5da3f2c6e1..8540b2446b 100644 --- a/ci/release/hermes.Dockerfile +++ b/ci/release/hermes.Dockerfile @@ -14,8 +14,8 @@ RUN cargo build --release FROM ubuntu:latest LABEL maintainer="hello@informal.systems" -ARG UID=1000 -ARG GID=1000 +ARG UID=2000 +ARG GID=2000 RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates RUN update-ca-certificates diff --git a/clippy.toml b/clippy.toml index 8f7dac5dc3..7372c60ff2 100644 --- a/clippy.toml +++ b/clippy.toml @@ -1 +1 @@ -msrv = "1.71.0" +msrv = "1.76.0" diff --git a/config.toml b/config.toml index f45e2289cf..aeb2eff924 100644 --- a/config.toml +++ b/config.toml @@ -59,6 +59,10 @@ clear_interval = 100 # Whether or not to clear packets on start. [Default: true] clear_on_start = true +# Set the maximum number of packets to clear each time packet clearing is triggered. +# [Default: 50] +#clear_limit = 50 + # Toggle the transaction confirmation mechanism. # The tx confirmation mechanism periodically queries the `/tx_search` RPC # endpoint to check that previously-submitted transactions @@ -189,11 +193,12 @@ grpc_addr = 'http://127.0.0.1:9090' # b) Pull: for polling for IBC events via the `/block_results` RPC endpoint. # -# `{ mode = 'pull', interval = '1s' }` +# `{ mode = 'pull', interval = '1s', max_retries = 4 }` # # where # # - `interval` is the interval at which to poll for blocks. Default: 1s +# - `max_retries` is the maximum number of retries to collect events for each block. Default: 4 # # This mode should only be used in situations where Hermes misses events that it should be # receiving, such as when relaying for CosmWasm-enabled chains which emit IBC events without @@ -307,7 +312,8 @@ gas_multiplier = 1.1 # Useful for chains which have [EIP-1559][eip]-like dynamic gas price. # # At the moment, only chains which support the `osmosis.txfees.v1beta1.Query/GetEipBaseFee` -# query can be used with dynamic gas price enabled. +# query or have enabled Skip's `x/feemarket` module https://github.com/skip-mev/feemarket +# can be used with dynamic gas price enabled. # # See this page in the Hermes guide for more information: # https://hermes.informal.systems/documentation/configuration/dynamic-gas-fees.html @@ -369,6 +375,13 @@ trust_threshold = '2/3' # operational debugging information, e.g., relayer build version. memo_prefix = '' +# If this is set to a string, it will overwrite the memo used by Hermes for each transaction +# it submits to this chain. +# Default: not set. +# This is used for chains which have a very small character limit for the memo, +# and the additional information appended by Hermes would overflow that limit. +# memo_overwrite = '' + # This section specifies the filters for policy based relaying. # # Default: no policy / filters, allow all packets on all channels. @@ -433,6 +446,25 @@ memo_prefix = '' # This will override the global clear interval for this chain only, allowing different intervals for each chain. # clear_interval = 50 +# Specify packet sequences which should not be cleared, per channel. +# +# For each channel, specify a list of sequences which should not be cleared. Acceptable value +# include range of sequences with separator "-", eg. +# +# [chains.excluded_sequences] +# channel-0 = [1, 2, "3-7", 9, 11], +# channel-1 = [4, 5, 6], +# +# Default: No filter +# excluded_sequences = {} + +# Enable or disable relaying of ICS31 Cross Chain Query packets. +# If this configuration is set to false, Hermes will skip ICS31 +# Cross Chain Query packets. +# +# Default: true +# allow_ccq = true + [[chains]] id = 'ibc-1' rpc_addr = 'http://127.0.0.1:26557' diff --git a/crates/chain-registry/Cargo.toml b/crates/chain-registry/Cargo.toml index d64dcf5f9e..5d01bb6940 100644 --- a/crates/chain-registry/Cargo.toml +++ b/crates/chain-registry/Cargo.toml @@ -1,28 +1,29 @@ [package] name = "ibc-chain-registry" -version = "0.27.0" +version = "0.29.5" edition = "2021" license = "Apache-2.0" keywords = ["cosmos", "ibc", "relayer", "chain", "registry"] repository = "https://github.com/informalsystems/hermes" authors = ["Informal Systems "] -rust-version = "1.71" +rust-version = "1.76.0" description = """ Service to fetch data from the chain-registry """ [dependencies] -ibc-relayer-types = { version = "0.27.0", path = "../relayer-types" } -ibc-proto = { version = "0.41.0", features = ["serde"] } -tendermint-rpc = { version = "0.34.0", features = ["http-client", "websocket-client"] } +ibc-relayer = { workspace = true } +ibc-relayer-types = { workspace = true } +ibc-proto = { workspace = true, features = ["serde"] } +tendermint-rpc = { workspace = true, features = ["http-client", "websocket-client"] } -async-trait = "0.1.72" -flex-error = { version = "0.4.4", default-features = false } -futures = { version = "0.3.27", features = ["executor"] } -http = "0.2" -itertools = "0.10.5" -reqwest = { version = "0.11.13", features = ["rustls-tls-native-roots", "json"], default-features = false } -serde = "1.0.195" -serde_json = "1" -tokio = "1.17.0" -tracing = "0.1.36" +async-trait = { workspace = true } +flex-error = { workspace = true } +futures = { workspace = true, features = ["executor"] } +http = { workspace = true } +itertools = { workspace = true } +reqwest = { workspace = true, features = ["rustls-tls-native-roots", "json"] } +serde = { workspace = true } +serde_json = { workspace = true } +tokio = { workspace = true } +tracing = { workspace = true } diff --git a/crates/chain-registry/src/asset_list.rs b/crates/chain-registry/src/asset_list.rs index a4edc40a8c..af0f513f03 100644 --- a/crates/chain-registry/src/asset_list.rs +++ b/crates/chain-registry/src/asset_list.rs @@ -45,6 +45,8 @@ pub struct LogoURIs { } impl Fetchable for AssetList { + const DESC: &'static str = "asset list"; + fn path(resource: &str) -> PathBuf { [resource, "assetlist.json"].iter().collect() } diff --git a/crates/chain-registry/src/chain.rs b/crates/chain-registry/src/chain.rs index 48434c404d..72c654160e 100644 --- a/crates/chain-registry/src/chain.rs +++ b/crates/chain-registry/src/chain.rs @@ -152,6 +152,8 @@ pub struct Grpc { } impl Fetchable for ChainData { + const DESC: &'static str = "chain data"; + fn path(resource: &str) -> PathBuf { [resource, "chain.json"].iter().collect() } diff --git a/crates/chain-registry/src/error.rs b/crates/chain-registry/src/error.rs index 662ce5cbab..01ccf6af39 100644 --- a/crates/chain-registry/src/error.rs +++ b/crates/chain-registry/src/error.rs @@ -1,10 +1,7 @@ +use std::path::PathBuf; + use flex_error::{define_error, TraceError}; -use http; use itertools::Itertools; -use reqwest; -use serde_json; -use std::path::PathBuf; -use tendermint_rpc; use tokio::task::JoinError; use tokio::time::error::Elapsed; @@ -77,7 +74,7 @@ define_error! { .iter() .join(", "); - format!("Error finding a healthy endpoint after {} retries. Endpoints: {endpoints}", e.retries) + format!("Did not find a healthy endpoint after {} retries. Endpoints: {endpoints}", e.retries) }, UriParseError diff --git a/crates/chain-registry/src/fetchable.rs b/crates/chain-registry/src/fetchable.rs index 4085849a36..bf66dedb6f 100644 --- a/crates/chain-registry/src/fetchable.rs +++ b/crates/chain-registry/src/fetchable.rs @@ -15,6 +15,8 @@ pub trait Fetchable where Self: DeserializeOwned, { + const DESC: &'static str; + /// The path of the fetchable resource. fn path(resource: &str) -> PathBuf; diff --git a/crates/chain-registry/src/formatter.rs b/crates/chain-registry/src/formatter.rs index 88b4227f7a..5d97832703 100644 --- a/crates/chain-registry/src/formatter.rs +++ b/crates/chain-registry/src/formatter.rs @@ -2,13 +2,16 @@ //! Contains struct to build a `tendermint_rpc::Url` representing a //! WebSocket URL from a RPC URL and to parse or build a valid `http::Uri` //! from an (in)complete GRPC URL. -use crate::error::RegistryError; + +use std::str::FromStr; + use http::uri::Scheme; use http::Uri; -use std::str::FromStr; use tendermint_rpc::Url; +use crate::error::RegistryError; + /// `UriFormatter` contains the basic expectations to parse a valid URL from a `&str`. pub trait UriFormatter { /// Expected output format of the formatter. @@ -98,7 +101,6 @@ impl UriFormatter for SimpleGrpcFormatter { mod tests { use super::*; - use std::cmp::PartialEq; use std::fmt::Debug; struct FormatterTest { diff --git a/crates/chain-registry/src/paths.rs b/crates/chain-registry/src/paths.rs index 83f15e387e..e7cf1bc918 100644 --- a/crates/chain-registry/src/paths.rs +++ b/crates/chain-registry/src/paths.rs @@ -58,6 +58,8 @@ pub enum Tag { } impl Fetchable for IBCPath { + const DESC: &'static str = "IBC path"; + fn path(resource: &str) -> PathBuf { ["_IBC", resource].iter().collect() } diff --git a/crates/chain-registry/src/querier.rs b/crates/chain-registry/src/querier.rs index ac5a2c385c..146f9226fa 100644 --- a/crates/chain-registry/src/querier.rs +++ b/crates/chain-registry/src/querier.rs @@ -8,15 +8,16 @@ use std::str::FromStr; use async_trait::async_trait; use futures::{stream::FuturesUnordered, StreamExt}; use http::Uri; -use tokio::time::timeout; -use tokio::time::Duration; +use tendermint_rpc::HttpClient; +use tendermint_rpc::HttpClientUrl; use tracing::{debug, info}; use ibc_proto::cosmos::bank::v1beta1::query_client::QueryClient; -use tendermint_rpc::{Client, SubscriptionClient, Url, WebSocketClient}; +use ibc_relayer::util::create_grpc_client; +use ibc_relayer::HERMES_VERSION; +use tendermint_rpc::{Client, Url}; use crate::error::RegistryError; -use crate::formatter::{SimpleWebSocketFormatter, UriFormatter}; /// `QueryTypes` represents the basic types required to query a node pub trait QueryTypes { @@ -73,8 +74,8 @@ pub trait QueryContext: QueryTypes { // ----------------- RPC ------------------ -/// `SimpleHermesRpcQuerier` retrieves `HermesConfigData` by querying a list of RPC endpoints through their WebSocket API -/// and returns the result of the first endpoint to answer. +/// `SimpleHermesRpcQuerier` retrieves `HermesConfigData` by querying a list of RPC endpoints +/// through their RPC API and returns the result of the first endpoint to answer. pub struct SimpleHermesRpcQuerier; /// Data which must be retrieved from RPC endpoints for Hermes @@ -82,7 +83,6 @@ pub struct SimpleHermesRpcQuerier; pub struct HermesConfigData { pub rpc_address: Url, pub max_block_size: u64, - pub websocket: Url, // max_block_time should also be retrieved from the RPC // however it looks like it is not in the genesis file anymore } @@ -101,46 +101,32 @@ impl QueryContext for SimpleHermesRpcQuerier { RegistryError::no_healthy_rpc(chain_name) } - /// Convert the RPC url to a WebSocket url, query the endpoint, return the data from the RPC. - async fn query(rpc: Self::QueryInput) -> Result { - let websocket_addr = SimpleWebSocketFormatter::parse_or_build_address(rpc.as_str())?; + /// Query the endpoint, return the data from the RPC. + async fn query(rpc_url: Self::QueryInput) -> Result { + info!("Querying RPC server at {rpc_url}"); - info!("Querying WebSocket server at {websocket_addr}"); + let url = HttpClientUrl::from_str(&rpc_url) + .map_err(|e| RegistryError::tendermint_url_parse_error(rpc_url.clone(), e))?; - let (client, driver) = timeout( - Duration::from_secs(5), - WebSocketClient::new(websocket_addr.clone()), - ) - .await - .map_err(|e| RegistryError::websocket_time_out_error(websocket_addr.to_string(), e))? - .map_err(|e| RegistryError::websocket_connect_error(websocket_addr.to_string(), e))?; - - let driver_handle = tokio::spawn(driver.run()); + let client = HttpClient::builder(url) + .user_agent(format!("hermes/{}", HERMES_VERSION)) + .build() + .map_err(|e| RegistryError::rpc_connect_error(rpc_url.clone(), e))?; let latest_consensus_params = match client.latest_consensus_params().await { Ok(response) => response.consensus_params.block.max_bytes, Err(e) => { return Err(RegistryError::rpc_consensus_params_error( - websocket_addr.to_string(), + rpc_url.to_string(), e, )) } }; - client.close().map_err(|e| { - RegistryError::websocket_conn_close_error(websocket_addr.to_string(), e) - })?; - - driver_handle - .await - .map_err(|e| RegistryError::join_error("chain_data_join".to_string(), e))? - .map_err(|e| RegistryError::websocket_driver_error(websocket_addr.to_string(), e))?; - Ok(HermesConfigData { - rpc_address: Url::from_str(&rpc) - .map_err(|e| RegistryError::tendermint_url_parse_error(rpc, e))?, + rpc_address: Url::from_str(&rpc_url) + .map_err(|e| RegistryError::tendermint_url_parse_error(rpc_url, e))?, max_block_size: latest_consensus_params, - websocket: websocket_addr, }) } } @@ -174,7 +160,7 @@ impl QueryContext for GrpcHealthCheckQuerier { info!("Querying gRPC server at {tendermint_url}"); - QueryClient::connect(uri) + create_grpc_client(&uri, QueryClient::new) .await .map_err(|_| RegistryError::unable_to_connect_with_grpc())?; diff --git a/crates/relayer-cli/Cargo.toml b/crates/relayer-cli/Cargo.toml index 8087507ffb..47676af45e 100644 --- a/crates/relayer-cli/Cargo.toml +++ b/crates/relayer-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ibc-relayer-cli" -version = "1.8.0" +version = "1.10.5" edition = "2021" license = "Apache-2.0" readme = "README.md" @@ -8,7 +8,7 @@ keywords = ["blockchain", "consensus", "cosmos", "ibc", "tendermint"] homepage = "https://hermes.informal.systems/" repository = "https://github.com/informalsystems/hermes" authors = ["Informal Systems "] -rust-version = "1.71" +rust-version = "1.76.0" description = """ Hermes is an IBC Relayer written in Rust """ @@ -17,61 +17,44 @@ default-run = "hermes" [[bin]] name = "hermes" -[features] -default = ["telemetry", "rest-server", "std", "eyre_tracer"] -std = ["flex-error/std"] -eyre_tracer = ["flex-error/eyre_tracer"] -telemetry = ["ibc-relayer/telemetry", "ibc-telemetry"] -rest-server = ["ibc-relayer-rest"] - [dependencies] -ibc-relayer-types = { version = "0.27.0", path = "../relayer-types" } -ibc-relayer = { version = "0.27.0", path = "../relayer" } -ibc-telemetry = { version = "0.27.0", path = "../telemetry", optional = true } -ibc-relayer-rest = { version = "0.27.0", path = "../relayer-rest", optional = true } -ibc-chain-registry = { version = "0.27.0" , path = "../chain-registry" } - -clap = { version = "3.2", features = ["cargo"] } -clap_complete = "3.2" -color-eyre = "0.6" -console = "0.15.5" -crossbeam-channel = "0.5.11" -dialoguer = "0.11.0" -dirs-next = "2.0.0" -eyre = "0.6.8" -flex-error = { version = "0.4.4", default-features = false, features = ["std", "eyre_tracer"] } -futures = "0.3.27" -hdpath = "0.6.3" -http = "0.2" -humantime = "2.1" -itertools = "0.10.5" -oneline-eyre = "0.1" -regex = "1.9.5" -serde = { version = "1.0", features = ["serde_derive"] } -serde_json = "1" -signal-hook = "0.3.17" -subtle-encoding = "0.5" -tokio = { version = "1.0", features = ["full"] } -tracing = "0.1.36" -tracing-subscriber = { version = "0.3.14", features = ["fmt", "env-filter", "json"]} -time = "0.3" -[dependencies.tendermint] -version = "0.34.0" -features = ["secp256k1"] - -[dependencies.tendermint-rpc] -version = "0.34.0" -features = ["http-client", "websocket-client"] - -[dependencies.tendermint-light-client-verifier] -version = "0.34.0" - -[dependencies.abscissa_core] -version = "=0.6.0" -features = ["options"] +ibc-relayer-types = { workspace = true } +ibc-relayer = { workspace = true } +ibc-telemetry = { workspace = true } +ibc-relayer-rest = { workspace = true } +ibc-chain-registry = { workspace = true } + +abscissa_core = { workspace = true, features = ["options"] } +clap = { workspace = true, features = ["cargo"] } +clap_complete = { workspace = true } +color-eyre = { workspace = true } +console = { workspace = true } +crossbeam-channel = { workspace = true } +dialoguer = { workspace = true } +dirs-next = { workspace = true } +eyre = { workspace = true } +flex-error = { workspace = true, features = ["std", "eyre_tracer"] } +futures = { workspace = true } +hdpath = { workspace = true } +http = { workspace = true } +humantime = { workspace = true } +itertools = { workspace = true } +oneline-eyre = { workspace = true } +regex = { workspace = true } +serde = { workspace = true, features = ["serde_derive"] } +serde_json = { workspace = true } +signal-hook = { workspace = true } +subtle-encoding = { workspace = true } +tendermint-light-client-verifier = { workspace = true } +tendermint-rpc = { workspace = true, features = ["http-client", "websocket-client"] } +tendermint = { workspace = true, features = ["secp256k1"] } +time = { workspace = true } +tokio = { workspace = true, features = ["full"] } +tracing = { workspace = true } +tracing-subscriber = { workspace = true, features = ["fmt", "env-filter", "json"] } [dev-dependencies] -abscissa_core = { version = "=0.6.0", features = ["testing"] } -once_cell = "1.19" -regex = "1.9" -serial_test = "3.0.0" +abscissa_core = { workspace = true, features = ["testing"] } +once_cell = { workspace = true } +regex = { workspace = true } +serial_test = { workspace = true } diff --git a/crates/relayer-cli/src/application.rs b/crates/relayer-cli/src/application.rs index e7d524bf96..a6b9c656e0 100644 --- a/crates/relayer-cli/src/application.rs +++ b/crates/relayer-cli/src/application.rs @@ -166,7 +166,7 @@ impl Application for CliApp { let terminal = Terminal::new(self.term_colors(command)); let config_path = command.config_path(); - self.config_path = config_path.clone(); + self.config_path.clone_from(&config_path); let config = config_path .map(|path| self.load_config(&path)) diff --git a/crates/relayer-cli/src/bin/hermes/main.rs b/crates/relayer-cli/src/bin/hermes/main.rs index 4cdb1744fc..214fbb6ab5 100644 --- a/crates/relayer-cli/src/bin/hermes/main.rs +++ b/crates/relayer-cli/src/bin/hermes/main.rs @@ -1,6 +1,6 @@ //! Main entry point for Cli -#![deny(warnings, missing_docs, trivial_casts, unused_qualifications)] +#![deny(warnings, missing_docs, trivial_casts)] #![forbid(unsafe_code)] use ibc_relayer_cli::application::APPLICATION; diff --git a/crates/relayer-cli/src/chain_registry.rs b/crates/relayer-cli/src/chain_registry.rs index cbaae53590..f9fdb22d1d 100644 --- a/crates/relayer-cli/src/chain_registry.rs +++ b/crates/relayer-cli/src/chain_registry.rs @@ -1,14 +1,14 @@ //! Contains functions to generate a relayer config for a given chain +use std::collections::BTreeMap; use std::collections::HashMap; use std::fmt::Display; -use std::marker::Send; use futures::future::join_all; use http::Uri; -use ibc_relayer::config::dynamic_gas::DynamicGasPrice; +use tendermint_rpc::Url; use tokio::task::{JoinError, JoinHandle}; -use tracing::trace; +use tracing::{error, trace}; use ibc_chain_registry::asset_list::AssetList; use ibc_chain_registry::chain::ChainData; @@ -18,13 +18,13 @@ use ibc_chain_registry::formatter::{SimpleGrpcFormatter, UriFormatter}; use ibc_chain_registry::paths::IBCPath; use ibc_chain_registry::querier::*; use ibc_relayer::chain::cosmos::config::CosmosSdkConfig; +use ibc_relayer::config::dynamic_gas::DynamicGasPrice; use ibc_relayer::config::filter::{FilterPattern, PacketFilter}; use ibc_relayer::config::gas_multiplier::GasMultiplier; use ibc_relayer::config::types::{MaxMsgNum, MaxTxSize, Memo, TrustThreshold}; use ibc_relayer::config::{default, AddressType, ChainConfig, EventSourceMode, GasPrice}; use ibc_relayer::keyring::Store; - -use tendermint_rpc::Url; +use ibc_relayer::util::excluded_sequences::ExcludedSequences; const MAX_HEALTHY_QUERY_RETRIES: u8 = 5; @@ -110,11 +110,6 @@ where ) .await?; - let websocket_address = - rpc_data.websocket.clone().try_into().map_err(|e| { - RegistryError::websocket_url_parse_error(rpc_data.websocket.to_string(), e) - })?; - let avg_gas_price = if let Some(fee_token) = chain_data.fees.fee_tokens.first() { fee_token.average_gas_price } else { @@ -132,9 +127,9 @@ where id: chain_data.chain_id, rpc_addr: rpc_data.rpc_address, grpc_addr: grpc_address, - event_source: EventSourceMode::Push { - url: websocket_address, - batch_delay: default::batch_delay(), + event_source: EventSourceMode::Pull { + interval: default::poll_interval(), + max_retries: default::max_retries(), }, rpc_timeout: default::rpc_timeout(), trusted_node: default::trusted_node(), @@ -160,6 +155,7 @@ where client_refresh_rate: default::client_refresh_rate(), ccv_consumer_chain: false, memo_prefix: Memo::default(), + memo_overwrite: None, proof_specs: Default::default(), trust_threshold: TrustThreshold::default(), gas_price: GasPrice { @@ -172,6 +168,8 @@ where extension_options: Vec::new(), compat_mode: None, clear_interval: None, + excluded_sequences: ExcludedSequences::new(BTreeMap::new()), + allow_ccq: true, })) } @@ -190,6 +188,7 @@ where for i in 0..retries { let query_response = QuerierType::query_healthy(chain_name.to_string(), endpoints.clone()).await; + match query_response { Ok(r) => { return Ok(r); @@ -199,13 +198,13 @@ where } } } - Err(RegistryError::unhealthy_endpoints( - endpoints - .iter() - .map(|endpoint| endpoint.to_string()) - .collect(), - retries, - )) + + let endpoints = endpoints + .iter() + .map(|endpoint| endpoint.to_string()) + .collect(); + + Err(RegistryError::unhealthy_endpoints(endpoints, retries)) } /// Fetches the specified resources from the Cosmos chain registry, using the specified commit hash @@ -213,15 +212,21 @@ where /// Returns a vector of handles that need to be awaited in order to access the fetched data, or the /// error that occurred while fetching. async fn get_handles( - resources: &[String], + chain_ids: &[String], commit: &Option, -) -> Vec>> { - let handles = resources +) -> Vec<(String, JoinHandle>)> { + let handles = chain_ids .iter() - .map(|resource| { - let resource = resource.to_string(); + .map(|chain_id| { let commit = commit.clone(); - tokio::spawn(async move { T::fetch(resource, commit).await }) + let handle = { + let chain_id = chain_id.to_string(); + tokio::spawn(async move { + tracing::info!("{chain_id}: Fetching {}...", T::DESC); + T::fetch(chain_id, commit).await + }) + }; + (chain_id.to_string(), handle) }) .collect(); handles @@ -230,14 +235,18 @@ async fn get_handles( /// Given a vector of handles, awaits them and returns a vector of results. Any errors /// that occurred are mapped to a `RegistryError`. async fn get_data_from_handles( - handles: Vec>>, + handles: Vec<(String, JoinHandle>)>, error_task: &str, -) -> Result>, RegistryError> { - join_all(handles) +) -> Result)>, RegistryError> { + let (names, tasks): (Vec<_>, Vec<_>) = handles.into_iter().unzip(); + + let results = join_all(tasks) .await .into_iter() .collect::, JoinError>>() - .map_err(|e| RegistryError::join_error(error_task.to_string(), e)) + .map_err(|e| RegistryError::join_error(error_task.to_string(), e))?; + + Ok(names.into_iter().zip(results).collect()) } /// Fetches a list of ChainConfigs specified by the given slice of chain names. These @@ -260,17 +269,17 @@ async fn get_data_from_handles( pub async fn get_configs( chains: &[String], commit: Option, -) -> Result>, RegistryError> { - let n = chains.len(); - - if n == 0 { - return Ok(Vec::new()); +) -> Result>, RegistryError> { + if chains.is_empty() { + return Ok(HashMap::new()); } // Spawn tasks to fetch data from the chain-registry let chain_data_handle = get_handles::(chains, &commit).await; let asset_lists_handle = get_handles::(chains, &commit).await; + let n = chains.len(); + let mut path_handles = Vec::with_capacity(n * (n - 1) / 2); for i in 0..n { @@ -290,43 +299,65 @@ pub async fn get_configs( let asset_list_results = get_data_from_handles::(asset_lists_handle, "asset_handle_join").await?; - let chain_data_array: Vec = chain_data_results + let chain_data_array: Vec<(String, ChainData)> = chain_data_results .into_iter() - .filter_map(|chain_data| chain_data.ok()) + .filter_map(|(name, data)| match data { + Ok(data) => Some((name, data)), + Err(e) => { + error!("Error while fetching chain data for chain {name}: {e}"); + None + } + }) .collect(); - let asset_lists: Vec = asset_list_results + + let asset_lists: Vec<(String, AssetList)> = asset_list_results .into_iter() - .filter_map(|asset_list| asset_list.ok()) + .filter_map(|(name, assets)| match assets { + Ok(assets) => Some((name, assets)), + Err(e) => { + error!("Error while fetching asset list for chain {name}: {e}"); + None + } + }) .collect(); let path_data: Result, JoinError> = join_all(path_handles).await.into_iter().collect(); - let path_data: Vec = path_data + let path_data: Vec<_> = path_data .map_err(|e| RegistryError::join_error("path_handle_join".to_string(), e))? .into_iter() - .filter_map(|path| path.ok()) + .filter_map(|path| match path { + Ok(path) => Some(path), + Err(e) => { + error!("Error while fetching path data: {e}"); + None + } + }) .collect(); let mut packet_filters = construct_packet_filters(path_data); // Construct ChainConfig - let config_handles: Vec>> = chain_data_array + let config_handles: Vec<_> = chain_data_array .into_iter() .zip(asset_lists.into_iter()) - .zip(chains.iter()) - .map(|((chain_data, assets), chain_name)| { - let packet_filter = packet_filters.remove(chain_name); - tokio::spawn(async move { - hermes_config::< - GrpcHealthCheckQuerier, - SimpleHermesRpcQuerier, - SimpleGrpcFormatter, - >(chain_data, assets, packet_filter) - .await - }) + .map(|((chain_name, chain_data), (_, assets))| { + let packet_filter = packet_filters.remove(&chain_name); + let handle = tokio::spawn(hermes_config::< + GrpcHealthCheckQuerier, + SimpleHermesRpcQuerier, + SimpleGrpcFormatter, + >(chain_data, assets, packet_filter)); + + (chain_name, handle) }) .collect(); - get_data_from_handles::(config_handles, "config_handle_join").await + let result = get_data_from_handles::(config_handles, "config_handle_join") + .await? + .into_iter() + .collect(); + + Ok(result) } /// Concurrent RPC and GRPC queries are likely to fail. @@ -350,7 +381,7 @@ mod tests { async fn should_have_no_filter(test_chains: &[String]) -> Result<(), RegistryError> { let configs = get_configs(test_chains, Some(TEST_COMMIT.to_owned())).await?; - for config in configs { + for (_name, config) in configs { match config { Ok(config) => { assert_eq!( @@ -358,10 +389,7 @@ mod tests { ChannelPolicy::AllowAll ); } - Err(e) => panic!( - "Encountered an unexpected error in chain registry test: {}", - e - ), + Err(e) => panic!("Encountered an unexpected error in chain registry test: {e}"), } } @@ -380,7 +408,7 @@ mod tests { let configs = get_configs(test_chains, Some(TEST_COMMIT.to_owned())).await?; - for config in configs { + for (_name, config) in configs { match config { Ok(config) => match &config.packet_filter().channel_policy { ChannelPolicy::Allow(channel_filter) => { diff --git a/crates/relayer-cli/src/commands.rs b/crates/relayer-cli/src/commands.rs index 60879018f5..fbd50510dd 100644 --- a/crates/relayer-cli/src/commands.rs +++ b/crates/relayer-cli/src/commands.rs @@ -100,7 +100,7 @@ pub enum CliCmd { /// The `version` subcommand, retained for backward compatibility. Version(VersionCmd), - /// Performs a health check of all chains in the the config + /// Performs a health check of all chains in the config HealthCheck(HealthCheckCmd), /// Generate auto-complete scripts for different shells. @@ -151,7 +151,11 @@ impl Configurable for CliCmd { for ccfg in config.chains.iter_mut() { #[allow(irrefutable_let_patterns)] if let ChainConfig::CosmosSdk(ref mut cosmos_ccfg) = ccfg { - cosmos_ccfg.memo_prefix.apply_suffix(&suffix); + if let Some(memo) = &cosmos_ccfg.memo_overwrite { + cosmos_ccfg.memo_prefix = memo.clone(); + } else { + cosmos_ccfg.memo_prefix.apply_suffix(&suffix); + } } } diff --git a/crates/relayer-cli/src/commands/clear.rs b/crates/relayer-cli/src/commands/clear.rs index 7535614312..14868011a2 100644 --- a/crates/relayer-cli/src/commands/clear.rs +++ b/crates/relayer-cli/src/commands/clear.rs @@ -1,3 +1,4 @@ +use eyre::eyre; use std::ops::RangeInclusive; use abscissa_core::clap::Parser; @@ -5,6 +6,7 @@ use abscissa_core::config::Override; use abscissa_core::{Command, FrameworkErrorKind, Runnable}; use ibc_relayer::chain::handle::{BaseChainHandle, ChainHandle}; +use ibc_relayer::chain::requests::{IncludeProof, QueryChannelRequest, QueryHeight}; use ibc_relayer::config::Config; use ibc_relayer::link::error::LinkError; use ibc_relayer::link::{Link, LinkParameters}; @@ -146,27 +148,84 @@ impl Runnable for ClearPacketsCmd { } } - let mut ev_list = vec![]; + let (channel, _) = match chains.src.query_channel( + QueryChannelRequest { + port_id: self.port_id.clone(), + channel_id: self.channel_id.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) { + Ok(channel) => channel, + Err(e) => Output::error(e).exit(), + }; + + let exclude_src_sequences = config + .find_chain(&chains.src.id()) + .map(|chain_config| chain_config.excluded_sequences(&self.channel_id).to_vec()) + .unwrap_or_default(); + + let exclude_dst_sequences = + if let Some(counterparty_channel_id) = channel.counterparty().channel_id() { + config + .find_chain(&chains.dst.id()) + .map(|chain_config| { + chain_config + .excluded_sequences(counterparty_channel_id) + .to_vec() + }) + .unwrap_or_default() + } else { + Vec::new() + }; // Construct links in both directions. - let opts = LinkParameters { + let fwd_opts = LinkParameters { src_port_id: self.port_id.clone(), src_channel_id: self.channel_id.clone(), max_memo_size: config.mode.packets.ics20_max_memo_size, max_receiver_size: config.mode.packets.ics20_max_receiver_size, + exclude_src_sequences, }; - let fwd_link = match Link::new_from_opts(chains.src.clone(), chains.dst, opts, false, false) - { + let counterparty_channel_id = match channel.counterparty().channel_id() { + Some(channel_id) => channel_id.clone(), + None => Output::error(eyre!( + "Channel `{}` and port `{}` does not have a counterparty channel id", + self.channel_id, + self.port_id + )) + .exit(), + }; + + // Construct links in both directions. + let reverse_opts = LinkParameters { + src_port_id: channel.counterparty().port_id().clone(), + src_channel_id: counterparty_channel_id, + max_memo_size: config.mode.packets.ics20_max_memo_size, + max_receiver_size: config.mode.packets.ics20_max_receiver_size, + exclude_src_sequences: exclude_dst_sequences, + }; + + let fwd_link = match Link::new_from_opts( + chains.src.clone(), + chains.dst.clone(), + fwd_opts, + false, + false, + ) { Ok(link) => link, Err(e) => Output::error(e).exit(), }; - let rev_link = match fwd_link.reverse(false, false) { + let rev_link = match Link::new_from_opts(chains.dst, chains.src, reverse_opts, false, false) + { Ok(link) => link, Err(e) => Output::error(e).exit(), }; + let mut ev_list = vec![]; + // Schedule RecvPacket messages for pending packets in both directions or, // if packet sequences are provided, only on the specified chain. // This may produce pending acks which will be processed in the next phase. diff --git a/crates/relayer-cli/src/commands/config/auto.rs b/crates/relayer-cli/src/commands/config/auto.rs index 64241d030d..dde3742428 100644 --- a/crates/relayer-cli/src/commands/config/auto.rs +++ b/crates/relayer-cli/src/commands/config/auto.rs @@ -9,7 +9,7 @@ use ibc_relayer::config::{store, ChainConfig, Config}; use std::collections::HashSet; use std::path::PathBuf; -use tracing::{info, warn}; +use tracing::{error, info, warn}; fn find_key(chain_config: &ChainConfig) -> Option { let keys = chain_config.list_keys().ok()?; @@ -81,18 +81,17 @@ impl Runnable for AutoCmd { // Extract keys and sort chains by name let names_and_keys = extract_chains_and_keys(&self.chain_names); - let sorted_names = names_and_keys + + let chain_names = names_and_keys .iter() - .map(|n| &n.0) + .map(|(n, _)| n) .cloned() .collect::>(); - let sorted_names_set: HashSet = HashSet::from_iter(sorted_names.iter().cloned()); - let commit = self.commit.clone(); // Fetch chain configs from the chain registry - let config_results = runtime.block_on(get_configs(&sorted_names, commit)); + let config_results = runtime.block_on(get_configs(&chain_names, commit)); if let Err(e) = config_results { let config = Config::default(); @@ -113,22 +112,32 @@ impl Runnable for AutoCmd { } }; - let mut chain_configs: Vec = config_results + let mut chain_configs: Vec<(String, ChainConfig)> = config_results .unwrap() .into_iter() - .filter_map(|r| r.ok()) + .filter_map(|(name, config)| match config { + Ok(config) => Some((name, config)), + Err(e) => { + error!("Failed to generate chain config for chain '{name}': {e}"); + None + } + }) .collect(); // Determine which chains were not fetched - let fetched_chains_set = HashSet::from_iter(chain_configs.iter().map(|c| c.id().name())); - let missing_chains_set: HashSet<_> = - sorted_names_set.difference(&fetched_chains_set).collect(); + let fetched_chains_set: HashSet<_> = + HashSet::from_iter(chain_configs.iter().map(|(name, _)| name).cloned()); + let expected_chains_set: HashSet<_> = HashSet::from_iter(chain_names.iter().cloned()); + + let missing_chains_set: HashSet<_> = expected_chains_set + .difference(&fetched_chains_set) + .collect(); let configs_and_keys = chain_configs .iter_mut() - .zip(names_and_keys.iter().map(|n| &n.1).cloned()); + .zip(names_and_keys.iter().map(|(_, keys)| keys).cloned()); - for (chain_config, key_option) in configs_and_keys { + for ((_name, chain_config), key_option) in configs_and_keys { // If a key is provided, use it if let Some(key_name) = key_option { info!("{}: uses key \"{}\"", &chain_config.id(), &key_name); @@ -148,7 +157,7 @@ impl Runnable for AutoCmd { } let config = Config { - chains: chain_configs, + chains: chain_configs.into_iter().map(|(_, c)| c).collect(), ..Config::default() }; diff --git a/crates/relayer-cli/src/commands/config/validate.rs b/crates/relayer-cli/src/commands/config/validate.rs index 03efaf018c..1be5e3f78c 100644 --- a/crates/relayer-cli/src/commands/config/validate.rs +++ b/crates/relayer-cli/src/commands/config/validate.rs @@ -1,7 +1,6 @@ use std::fs; use abscissa_core::clap::Parser; -use abscissa_core::{Command, Runnable}; use crate::conclude::Output; use crate::config; diff --git a/crates/relayer-cli/src/commands/create/channel.rs b/crates/relayer-cli/src/commands/create/channel.rs index 98b8464ff3..2295d09e6c 100644 --- a/crates/relayer-cli/src/commands/create/channel.rs +++ b/crates/relayer-cli/src/commands/create/channel.rs @@ -1,5 +1,4 @@ use abscissa_core::clap::Parser; -use abscissa_core::{Command, Runnable}; use console::style; use dialoguer::Confirm; @@ -9,6 +8,7 @@ use ibc_relayer::chain::requests::{ IncludeProof, QueryClientStateRequest, QueryConnectionRequest, QueryHeight, }; use ibc_relayer::channel::Channel; +use ibc_relayer::config::default::connection_delay; use ibc_relayer::connection::Connection; use ibc_relayer::foreign_client::ForeignClient; use ibc_relayer_types::core::ics03_connection::connection::IdentifiedConnectionEnd; @@ -19,7 +19,6 @@ use ibc_relayer_types::core::ics24_host::identifier::{ChainId, ConnectionId, Por use crate::cli_utils::{spawn_chain_runtime, ChainHandlePair}; use crate::conclude::{exit_with_unrecoverable_error, Output}; use crate::prelude::*; -use ibc_relayer::config::default::connection_delay; static PROMPT: &str = "Are you sure you want a new connection & clients to be created? Hermes will use default security parameters."; static HINT: &str = "Consider using the default invocation\n\nhermes create channel --a-port --b-port --a-chain --a-connection \n\nto reuse a pre-existing connection."; diff --git a/crates/relayer-cli/src/commands/create/connection.rs b/crates/relayer-cli/src/commands/create/connection.rs index 052411d069..e6d5982c25 100644 --- a/crates/relayer-cli/src/commands/create/connection.rs +++ b/crates/relayer-cli/src/commands/create/connection.rs @@ -1,7 +1,6 @@ use core::time::Duration; use abscissa_core::clap::Parser; -use abscissa_core::{Command, Runnable}; use ibc_relayer::chain::handle::ChainHandle; use ibc_relayer::chain::requests::{IncludeProof, QueryClientStateRequest, QueryHeight}; diff --git a/crates/relayer-cli/src/commands/evidence.rs b/crates/relayer-cli/src/commands/evidence.rs index eb3bc9afe8..c74c1286e3 100644 --- a/crates/relayer-cli/src/commands/evidence.rs +++ b/crates/relayer-cli/src/commands/evidence.rs @@ -5,7 +5,6 @@ use std::thread::sleep; use std::time::Duration; use abscissa_core::clap::Parser; -use abscissa_core::{Command, Runnable}; use ibc_relayer::config::{ChainConfig, Config}; use tokio::runtime::Runtime as TokioRuntime; @@ -19,7 +18,7 @@ use ibc_relayer::chain::endpoint::ChainEndpoint; use ibc_relayer::chain::handle::{BaseChainHandle, ChainHandle}; use ibc_relayer::chain::requests::{IncludeProof, PageRequest, QueryHeight}; use ibc_relayer::chain::tracking::TrackedMsgs; -use ibc_relayer::foreign_client::ForeignClient; +use ibc_relayer::foreign_client::{fetch_ccv_consumer_id, ForeignClient}; use ibc_relayer::spawn::spawn_chain_runtime_with_modified_config; use ibc_relayer_types::applications::ics28_ccv::msgs::ccv_double_voting::MsgSubmitIcsConsumerDoubleVoting; use ibc_relayer_types::applications::ics28_ccv::msgs::ccv_misbehaviour::MsgSubmitIcsConsumerMisbehaviour; @@ -319,10 +318,15 @@ fn submit_duplicate_vote_evidence( let signer = counterparty_chain_handle.get_signer()?; - if !is_counterparty_provider(chain, counterparty_chain_handle, counterparty_client_id) { - debug!("counterparty client `{counterparty_client_id}` on chain `{counterparty_chain_id}` is not a CCV client, skipping..."); - return Ok(ControlFlow::Continue(())); - } + let consumer_id = match fetch_ccv_consumer_id(counterparty_chain_handle, counterparty_client_id) + { + Ok(consumer_id) => consumer_id, + Err(e) => { + info!("Failed to query Consumer ID: {e}. \ + Counterparty client `{counterparty_client_id}` on chain `{counterparty_chain_id}` might not be a CCV client, skipping..."); + return Ok(ControlFlow::Continue(())); + } + }; let infraction_height = evidence.vote_a.height; @@ -330,11 +334,12 @@ fn submit_duplicate_vote_evidence( // ie. retrieve the consensus state at the highest height smaller than the infraction height. // // Note: The consensus state heights are sorted in increasing order. - let consensus_state_heights = - chain.query_consensus_state_heights(QueryConsensusStateHeightsRequest { + let consensus_state_heights = counterparty_chain_handle.query_consensus_state_heights( + QueryConsensusStateHeightsRequest { client_id: counterparty_client_id.clone(), pagination: Some(PageRequest::all()), - })?; + }, + )?; // Retrieve the consensus state at the highest height smaller than the infraction height. let consensus_state_height_before_infraction_height = consensus_state_heights @@ -359,6 +364,7 @@ fn submit_duplicate_vote_evidence( submitter: signer.clone(), duplicate_vote_evidence: evidence.clone(), infraction_block_header, + consumer_id, } .to_any(); @@ -507,42 +513,14 @@ fn submit_light_client_attack_evidence( counterparty.id(), ); - let counterparty_is_provider = - is_counterparty_provider(chain, counterparty, &counterparty_client_id); - let counterparty_client_is_frozen = counterparty_client.is_frozen(); - if !counterparty_is_provider && counterparty_client_is_frozen { - warn!( - "cannot submit light client attack evidence to client `{}` on counterparty chain `{}`", - counterparty_client_id, - counterparty.id() - ); - warn!("reason: client is frozen and chain is not a CCV provider chain"); - - return Ok(()); - } - let signer = counterparty.get_signer()?; let common_height = Height::from_tm(evidence.common_height, chain.id()); let counterparty_has_common_consensus_state = has_consensus_state(counterparty, &counterparty_client_id, common_height); - if counterparty_is_provider - && counterparty_client_is_frozen - && !counterparty_has_common_consensus_state - { - warn!( - "cannot submit light client attack evidence to client `{}` on provider chain `{}`", - counterparty_client_id, - counterparty.id() - ); - warn!("reason: client is frozen and does not have a consensus state at height {common_height}"); - - return Ok(()); - } - let mut msgs = if counterparty_has_common_consensus_state { info!( "skip building update client message for client `{}` on counterparty chain `{}`", @@ -550,8 +528,8 @@ fn submit_light_client_attack_evidence( counterparty.id() ); info!( - "reason: counterparty chain already has consensus state at common height {common_height}" - ); + "reason: counterparty chain already has consensus state at common height {common_height}" + ); Vec::new() } else { @@ -571,21 +549,31 @@ fn submit_light_client_attack_evidence( } }; - if counterparty_is_provider { + if let Ok(consumer_id) = fetch_ccv_consumer_id(counterparty, &counterparty_client_id) { + if counterparty_client_is_frozen && !counterparty_has_common_consensus_state { + warn!( + "cannot submit light client attack evidence to client `{}` on provider chain `{}`", + counterparty_client_id, + counterparty.id() + ); + warn!("reason: client is frozen and does not have a consensus state at height {common_height}"); + + return Ok(()); + } info!( "will submit consumer light client attack evidence to client `{}` on provider chain `{}`", counterparty_client_id, counterparty.id(), ); - - let msg = MsgSubmitIcsConsumerMisbehaviour { - submitter: signer.clone(), - misbehaviour: misbehaviour.clone(), - } - .to_any(); - - msgs.push(msg); - }; + msgs.push( + MsgSubmitIcsConsumerMisbehaviour { + submitter: signer.clone(), + misbehaviour: misbehaviour.clone(), + consumer_id, + } + .to_any(), + ); + } // We do not need to submit the misbehaviour if the client is already frozen. if !counterparty_client_is_frozen { @@ -662,29 +650,6 @@ fn has_consensus_state( res.is_ok() } -/// If the misbehaving chain is a CCV consumer chain, -/// then try fetch the consumer chains of the counterparty chains. -/// If that fails, then the counterparty chain is not a provider chain. -/// Otherwise, check if the misbehaving chain is a consumer of the counterparty chain, -/// which is then definitely a provider. -fn is_counterparty_provider( - chain: &CosmosSdkChain, - counterparty_chain_handle: &BaseChainHandle, - counterparty_client_id: &ClientId, -) -> bool { - if chain.config().ccv_consumer_chain { - let consumer_chains = counterparty_chain_handle - .query_consumer_chains() - .unwrap_or_default(); // If the query fails, use an empty list of consumers - - consumer_chains.iter().any(|(chain_id, client_id)| { - chain_id == chain.id() && client_id == counterparty_client_id - }) - } else { - false - } -} - /// Fetch all the counterparty clients of the given chain. /// A counterparty client is a client that has a connection with that chain. /// @@ -716,6 +681,11 @@ fn fetch_all_counterparty_clients( connection.connection_id ); + if client_id.as_str() == "09-localhost" { + debug!("skipping localhost client `{client_id}`..."); + continue; + } + debug!( "fetching client state for client `{client_id}` on connection `{}`", connection.connection_id diff --git a/crates/relayer-cli/src/commands/fee/transfer.rs b/crates/relayer-cli/src/commands/fee/transfer.rs index 3893a2d232..2ea80d63b3 100644 --- a/crates/relayer-cli/src/commands/fee/transfer.rs +++ b/crates/relayer-cli/src/commands/fee/transfer.rs @@ -1,8 +1,6 @@ use core::time::Duration; -use abscissa_core::{ - clap::Parser, config::Override, Command, FrameworkError, FrameworkErrorKind, Runnable, -}; +use abscissa_core::{clap::Parser, config::Override, FrameworkError, FrameworkErrorKind}; use eyre::eyre; use ibc_relayer::{ diff --git a/crates/relayer-cli/src/commands/health.rs b/crates/relayer-cli/src/commands/health.rs index 8514bb087f..6ecdd588dd 100644 --- a/crates/relayer-cli/src/commands/health.rs +++ b/crates/relayer-cli/src/commands/health.rs @@ -1,5 +1,4 @@ use abscissa_core::clap::Parser; -use abscissa_core::{Command, Runnable}; use ibc_relayer::chain::endpoint::HealthCheck::*; use ibc_relayer::chain::handle::ChainHandle; diff --git a/crates/relayer-cli/src/commands/listen.rs b/crates/relayer-cli/src/commands/listen.rs index 68bd5c22ad..ea8bd979cb 100644 --- a/crates/relayer-cli/src/commands/listen.rs +++ b/crates/relayer-cli/src/commands/listen.rs @@ -1,25 +1,24 @@ use alloc::sync::Arc; -use core::{ - fmt::{Display, Error as FmtError, Formatter}, - str::FromStr, -}; +use core::fmt::{Display, Error as FmtError, Formatter}; +use core::str::FromStr; use std::thread; +use abscissa_core::application::fatal_error; use abscissa_core::clap::Parser; -use abscissa_core::{application::fatal_error, Runnable}; use eyre::eyre; use itertools::Itertools; -use tendermint_rpc::{client::CompatMode, Client, HttpClient}; +use tendermint_rpc::{client::CompatMode, HttpClient}; use tokio::runtime::Runtime as TokioRuntime; use tracing::{error, info, instrument}; -use ibc_relayer::{ - chain::handle::Subscription, - config::{ChainConfig, EventSourceMode}, - event::source::EventSource, - util::compat_mode::compat_mode_from_version, -}; -use ibc_relayer_types::{core::ics24_host::identifier::ChainId, events::IbcEvent}; +use ibc_relayer::chain::cosmos::fetch_compat_mode; +use ibc_relayer::chain::handle::Subscription; +use ibc_relayer::config::{ChainConfig, EventSourceMode}; +use ibc_relayer::error::Error; +use ibc_relayer::event::source::EventSource; +use ibc_relayer::HERMES_VERSION; +use ibc_relayer_types::core::ics24_host::identifier::ChainId; +use ibc_relayer_types::events::IbcEvent; use crate::prelude::*; @@ -156,12 +155,24 @@ fn subscribe( *batch_delay, rt, ), - EventSourceMode::Pull { interval } => EventSource::rpc( - chain_config.id().clone(), - HttpClient::new(config.rpc_addr.clone())?, - *interval, - rt, - ), + EventSourceMode::Pull { + interval, + max_retries, + } => { + let mut rpc_client = HttpClient::builder(config.rpc_addr.clone().try_into()?) + .user_agent(format!("hermes/{}", HERMES_VERSION)) + .build() + .map_err(|e| Error::rpc(config.rpc_addr.clone(), e))?; + rpc_client.set_compat_mode(compat_mode); + + EventSource::rpc( + chain_config.id().clone(), + rpc_client, + *interval, + *max_retries, + rt, + ) + } }?; thread::spawn(move || event_source.run()); @@ -180,13 +191,15 @@ fn detect_compatibility_mode( let rpc_addr = match config { ChainConfig::CosmosSdk(config) => config.rpc_addr.clone(), }; - let client = HttpClient::new(rpc_addr)?; - let status = rt.block_on(client.status())?; + + let client = HttpClient::builder(rpc_addr.try_into()?) + .user_agent(format!("hermes/{}", HERMES_VERSION)) + .build()?; + let compat_mode = match config { - ChainConfig::CosmosSdk(config) => { - compat_mode_from_version(&config.compat_mode, status.node_info.version)?.into() - } + ChainConfig::CosmosSdk(config) => rt.block_on(fetch_compat_mode(&client, config))?, }; + Ok(compat_mode) } diff --git a/crates/relayer-cli/src/commands/logs/reset.rs b/crates/relayer-cli/src/commands/logs/reset.rs index e216af3c32..f9165b9da1 100644 --- a/crates/relayer-cli/src/commands/logs/reset.rs +++ b/crates/relayer-cli/src/commands/logs/reset.rs @@ -1,6 +1,5 @@ use abscissa_core::clap::Parser; use abscissa_core::Command; -use abscissa_core::Runnable; use crate::components::default_directive; use crate::prelude::*; diff --git a/crates/relayer-cli/src/commands/misbehaviour.rs b/crates/relayer-cli/src/commands/misbehaviour.rs index 8400d11ad9..a231c7c1bc 100644 --- a/crates/relayer-cli/src/commands/misbehaviour.rs +++ b/crates/relayer-cli/src/commands/misbehaviour.rs @@ -1,5 +1,5 @@ use abscissa_core::clap::Parser; -use abscissa_core::{Command, Runnable}; +use abscissa_core::Command; use ibc_relayer::chain::handle::ChainHandle; use ibc_relayer::chain::requests::{IncludeProof, QueryClientStateRequest, QueryHeight}; use ibc_relayer::config::Config; diff --git a/crates/relayer-cli/src/commands/query/channel.rs b/crates/relayer-cli/src/commands/query/channel.rs index f350ea8dd6..14b402d3dc 100644 --- a/crates/relayer-cli/src/commands/query/channel.rs +++ b/crates/relayer-cli/src/commands/query/channel.rs @@ -1,5 +1,4 @@ use abscissa_core::clap::Parser; -use abscissa_core::{Command, Runnable}; use ibc_relayer::chain::handle::ChainHandle; use ibc_relayer::chain::requests::{IncludeProof, QueryChannelRequest, QueryHeight}; diff --git a/crates/relayer-cli/src/commands/query/channel_ends.rs b/crates/relayer-cli/src/commands/query/channel_ends.rs index aaa668beb1..bc316865ab 100644 --- a/crates/relayer-cli/src/commands/query/channel_ends.rs +++ b/crates/relayer-cli/src/commands/query/channel_ends.rs @@ -1,5 +1,4 @@ use abscissa_core::clap::Parser; -use abscissa_core::{Command, Runnable}; use serde::{Deserialize, Serialize}; use eyre::eyre; diff --git a/crates/relayer-cli/src/commands/query/channels.rs b/crates/relayer-cli/src/commands/query/channels.rs index a516854416..88d85fe103 100644 --- a/crates/relayer-cli/src/commands/query/channels.rs +++ b/crates/relayer-cli/src/commands/query/channels.rs @@ -1,7 +1,6 @@ use core::fmt::{Debug, Error, Formatter}; use abscissa_core::clap::Parser; -use abscissa_core::Runnable; use serde::Serialize; use eyre::eyre; diff --git a/crates/relayer-cli/src/commands/query/client.rs b/crates/relayer-cli/src/commands/query/client.rs index cd613df4df..30c0ba0cfc 100644 --- a/crates/relayer-cli/src/commands/query/client.rs +++ b/crates/relayer-cli/src/commands/query/client.rs @@ -1,6 +1,5 @@ use abscissa_core::clap::Parser; use abscissa_core::{Command, Runnable}; -use color_eyre::eyre::eyre; use ibc_relayer::chain::handle::ChainHandle; use ibc_relayer::chain::requests::{ @@ -318,24 +317,10 @@ fn client_status( return Ok(Status::Frozen); } - let consensus_state_heights = - chain.query_consensus_state_heights(QueryConsensusStateHeightsRequest { - client_id: client_id.clone(), - pagination: Some(PageRequest::all()), - })?; - - let latest_consensus_height = consensus_state_heights.last().copied().ok_or_else(|| { - eyre!( - "no consensus state found for client '{}' on chain '{}'", - client_id, - chain.id() - ) - })?; - let (latest_consensus_state, _) = chain.query_consensus_state( QueryConsensusStateRequest { client_id: client_id.clone(), - consensus_height: latest_consensus_height, + consensus_height: client_state.latest_height(), query_height: QueryHeight::Latest, }, IncludeProof::No, diff --git a/crates/relayer-cli/src/commands/query/clients.rs b/crates/relayer-cli/src/commands/query/clients.rs index 0ced719b2b..e852636801 100644 --- a/crates/relayer-cli/src/commands/query/clients.rs +++ b/crates/relayer-cli/src/commands/query/clients.rs @@ -1,5 +1,4 @@ use abscissa_core::clap::Parser; -use abscissa_core::{Command, Runnable}; use ibc_relayer::chain::handle::ChainHandle; use serde::Serialize; diff --git a/crates/relayer-cli/src/commands/query/connection.rs b/crates/relayer-cli/src/commands/query/connection.rs index 28b044985d..0dbf675bb7 100644 --- a/crates/relayer-cli/src/commands/query/connection.rs +++ b/crates/relayer-cli/src/commands/query/connection.rs @@ -1,5 +1,4 @@ use abscissa_core::clap::Parser; -use abscissa_core::{Command, Runnable}; use ibc_relayer::chain::handle::ChainHandle; use ibc_relayer::chain::requests::{ IncludeProof, PageRequest, QueryConnectionChannelsRequest, QueryConnectionRequest, QueryHeight, diff --git a/crates/relayer-cli/src/commands/query/connections.rs b/crates/relayer-cli/src/commands/query/connections.rs index dadef9d6a2..69aa86526a 100644 --- a/crates/relayer-cli/src/commands/query/connections.rs +++ b/crates/relayer-cli/src/commands/query/connections.rs @@ -1,5 +1,4 @@ use abscissa_core::clap::Parser; -use abscissa_core::Runnable; use ibc_relayer::chain::handle::ChainHandle; use ibc_relayer::chain::requests::{ diff --git a/crates/relayer-cli/src/commands/query/packet/ack.rs b/crates/relayer-cli/src/commands/query/packet/ack.rs index 93c59d1efc..86fbb65361 100644 --- a/crates/relayer-cli/src/commands/query/packet/ack.rs +++ b/crates/relayer-cli/src/commands/query/packet/ack.rs @@ -1,5 +1,4 @@ use abscissa_core::clap::Parser; -use abscissa_core::{Command, Runnable}; use ibc_relayer::chain::requests::{IncludeProof, QueryHeight, QueryPacketAcknowledgementRequest}; use subtle_encoding::{Encoding, Hex}; diff --git a/crates/relayer-cli/src/commands/query/packet/acks.rs b/crates/relayer-cli/src/commands/query/packet/acks.rs index f7e85156dc..9d7a0c4f2e 100644 --- a/crates/relayer-cli/src/commands/query/packet/acks.rs +++ b/crates/relayer-cli/src/commands/query/packet/acks.rs @@ -1,5 +1,4 @@ use abscissa_core::clap::Parser; -use abscissa_core::{Command, Runnable}; use ibc_relayer::chain::counterparty::acknowledgements_on_chain; use ibc_relayer::chain::handle::BaseChainHandle; diff --git a/crates/relayer-cli/src/commands/query/packet/commitment.rs b/crates/relayer-cli/src/commands/query/packet/commitment.rs index 74779dd5a1..4c4edd911b 100644 --- a/crates/relayer-cli/src/commands/query/packet/commitment.rs +++ b/crates/relayer-cli/src/commands/query/packet/commitment.rs @@ -1,10 +1,8 @@ use abscissa_core::clap::Parser; -use abscissa_core::{Command, Runnable}; -use ibc_relayer::chain::requests::{IncludeProof, QueryHeight, QueryPacketCommitmentRequest}; -use serde::Serialize; use subtle_encoding::{Encoding, Hex}; use ibc_relayer::chain::handle::ChainHandle; +use ibc_relayer::chain::requests::{IncludeProof, QueryHeight, QueryPacketCommitmentRequest}; use ibc_relayer_types::core::ics04_channel::packet::Sequence; use ibc_relayer_types::core::ics24_host::identifier::{ChainId, ChannelId, PortId}; use ibc_relayer_types::Height; @@ -14,12 +12,6 @@ use crate::conclude::{exit_with_unrecoverable_error, Output}; use crate::error::Error; use crate::prelude::*; -#[derive(Serialize, Debug)] -struct PacketSeqs { - height: Height, - seqs: Vec, -} - #[derive(Clone, Command, Debug, Parser, PartialEq, Eq)] pub struct QueryPacketCommitmentCmd { #[clap( diff --git a/crates/relayer-cli/src/commands/query/packet/commitments.rs b/crates/relayer-cli/src/commands/query/packet/commitments.rs index a308e5b83d..836df55b27 100644 --- a/crates/relayer-cli/src/commands/query/packet/commitments.rs +++ b/crates/relayer-cli/src/commands/query/packet/commitments.rs @@ -1,11 +1,13 @@ use abscissa_core::clap::Parser; -use abscissa_core::{Command, Runnable}; use ibc_relayer::chain::counterparty::commitments_on_chain; +use ibc_relayer::chain::handle::ChainHandle; +use ibc_relayer::chain::requests::{Paginate, QueryHeight}; +use ibc_relayer_types::core::ics02_client::height::Height; use ibc_relayer_types::core::ics24_host::identifier::{ChainId, ChannelId, PortId}; use crate::cli_utils::spawn_chain_runtime; -use crate::conclude::Output; +use crate::conclude::{exit_with_unrecoverable_error, Output}; use crate::error::Error; use crate::prelude::*; @@ -40,6 +42,13 @@ pub struct QueryPacketCommitmentsCmd { help = "Identifier of the channel to query" )] channel_id: ChannelId, + + #[clap( + long = "height", + value_name = "HEIGHT", + help = "Height of the state to query. Leave unspecified for latest height." + )] + height: Option, } impl QueryPacketCommitmentsCmd { @@ -48,12 +57,25 @@ impl QueryPacketCommitmentsCmd { let chain = spawn_chain_runtime(&config, &self.chain_id)?; - commitments_on_chain(&chain, &self.port_id, &self.channel_id) - .map_err(Error::supervisor) - .map(|(seqs_vec, height)| PacketSeqs { - height, - seqs: seqs_vec, - }) + let query_height = self.height.map_or(QueryHeight::Latest, |revision_height| { + QueryHeight::Specific( + Height::new(chain.id().version(), revision_height) + .unwrap_or_else(exit_with_unrecoverable_error), + ) + }); + + commitments_on_chain( + &chain, + &query_height, + &self.port_id, + &self.channel_id, + Paginate::All, + ) + .map_err(Error::supervisor) + .map(|(seqs_vec, height)| PacketSeqs { + height, + seqs: seqs_vec, + }) } } @@ -85,7 +107,8 @@ mod tests { QueryPacketCommitmentsCmd { chain_id: ChainId::from_string("chain_id"), port_id: PortId::from_str("port_id").unwrap(), - channel_id: ChannelId::from_str("channel-07").unwrap() + channel_id: ChannelId::from_str("channel-07").unwrap(), + height: None, }, QueryPacketCommitmentsCmd::parse_from([ "test", @@ -105,7 +128,8 @@ mod tests { QueryPacketCommitmentsCmd { chain_id: ChainId::from_string("chain_id"), port_id: PortId::from_str("port_id").unwrap(), - channel_id: ChannelId::from_str("channel-07").unwrap() + channel_id: ChannelId::from_str("channel-07").unwrap(), + height: None, }, QueryPacketCommitmentsCmd::parse_from([ "test", diff --git a/crates/relayer-cli/src/commands/query/packet/pending.rs b/crates/relayer-cli/src/commands/query/packet/pending.rs index 73a1781b5c..94434adc69 100644 --- a/crates/relayer-cli/src/commands/query/packet/pending.rs +++ b/crates/relayer-cli/src/commands/query/packet/pending.rs @@ -1,13 +1,13 @@ use core::fmt; use abscissa_core::clap::Parser; -use abscissa_core::{Command, Runnable}; use serde::Serialize; use ibc_relayer::chain::counterparty::{ channel_on_destination, pending_packet_summary, PendingPackets, }; use ibc_relayer::chain::handle::{BaseChainHandle, ChainHandle}; +use ibc_relayer::chain::requests::Paginate; use ibc_relayer_types::core::ics24_host::identifier::{ChainId, ChannelId, PortId}; use crate::cli_utils::spawn_chain_counterparty; @@ -131,8 +131,13 @@ impl QueryPendingPacketsCmd { self.chain_id, chan_conn_cli.channel ); - let src_summary = pending_packet_summary(&chains.src, &chains.dst, &chan_conn_cli.channel) - .map_err(Error::supervisor)?; + let src_summary = pending_packet_summary( + &chains.src, + &chains.dst, + &chan_conn_cli.channel, + Paginate::All, + ) + .map_err(Error::supervisor)?; let counterparty_channel = channel_on_destination( &chan_conn_cli.channel, @@ -142,8 +147,13 @@ impl QueryPendingPacketsCmd { .map_err(Error::supervisor)? .ok_or_else(|| Error::missing_counterparty_channel_id(chan_conn_cli.channel))?; - let dst_summary = pending_packet_summary(&chains.dst, &chains.src, &counterparty_channel) - .map_err(Error::supervisor)?; + let dst_summary = pending_packet_summary( + &chains.dst, + &chains.src, + &counterparty_channel, + Paginate::All, + ) + .map_err(Error::supervisor)?; Ok(Summary { src_chain: chains.src.id(), diff --git a/crates/relayer-cli/src/commands/query/packet/pending_acks.rs b/crates/relayer-cli/src/commands/query/packet/pending_acks.rs index ea5288dbbc..2f332b7416 100644 --- a/crates/relayer-cli/src/commands/query/packet/pending_acks.rs +++ b/crates/relayer-cli/src/commands/query/packet/pending_acks.rs @@ -1,8 +1,8 @@ use abscissa_core::clap::Parser; -use abscissa_core::{Command, Runnable}; use ibc_relayer::chain::counterparty::unreceived_acknowledgements; use ibc_relayer::chain::handle::BaseChainHandle; +use ibc_relayer::chain::requests::Paginate; use ibc_relayer::path::PathIdentifiers; use ibc_relayer::util::collate::CollatedIterExt; use ibc_relayer_types::core::ics04_channel::packet::Sequence; @@ -69,8 +69,9 @@ impl QueryPendingAcksCmd { let path_identifiers = PathIdentifiers::from_channel_end(channel.clone()) .ok_or_else(|| Error::missing_counterparty_channel_id(channel))?; - let acks = unreceived_acknowledgements(&chains.src, &chains.dst, &path_identifiers) - .map_err(Error::supervisor)?; + let acks = + unreceived_acknowledgements(&chains.src, &chains.dst, &path_identifiers, Paginate::All) + .map_err(Error::supervisor)?; Ok(acks.map_or(vec![], |(sns, _)| sns)) } diff --git a/crates/relayer-cli/src/commands/query/packet/pending_sends.rs b/crates/relayer-cli/src/commands/query/packet/pending_sends.rs index 8d305e496e..8df9fbdd23 100644 --- a/crates/relayer-cli/src/commands/query/packet/pending_sends.rs +++ b/crates/relayer-cli/src/commands/query/packet/pending_sends.rs @@ -1,8 +1,8 @@ use abscissa_core::clap::Parser; -use abscissa_core::{Command, Runnable}; use ibc_relayer::chain::counterparty::unreceived_packets; use ibc_relayer::chain::handle::BaseChainHandle; +use ibc_relayer::chain::requests::Paginate; use ibc_relayer::path::PathIdentifiers; use ibc_relayer::util::collate::CollatedIterExt; use ibc_relayer_types::core::ics04_channel::packet::Sequence; @@ -69,7 +69,7 @@ impl QueryPendingSendsCmd { let path_identifiers = PathIdentifiers::from_channel_end(channel.clone()) .ok_or_else(|| Error::missing_counterparty_channel_id(channel))?; - unreceived_packets(&chains.src, &chains.dst, &path_identifiers) + unreceived_packets(&chains.src, &chains.dst, &path_identifiers, Paginate::All) .map_err(Error::supervisor) .map(|(seq, _)| seq) } diff --git a/crates/relayer-cli/src/commands/query/transfer/denom_trace.rs b/crates/relayer-cli/src/commands/query/transfer/denom_trace.rs index 3ce25c0658..a678b93ff6 100644 --- a/crates/relayer-cli/src/commands/query/transfer/denom_trace.rs +++ b/crates/relayer-cli/src/commands/query/transfer/denom_trace.rs @@ -14,7 +14,7 @@ use crate::conclude::{exit_with_unrecoverable_error, json, Output}; /// /// `query transfer denom-trace --chain --hash ` /// -/// If successful the the base denomination and the path will be displayed. +/// If successful the base denomination and the path will be displayed. #[derive(Clone, Command, Debug, Parser, PartialEq, Eq)] pub struct DenomTraceCmd { #[clap( diff --git a/crates/relayer-cli/src/commands/start.rs b/crates/relayer-cli/src/commands/start.rs index 5f0346d211..cc9c9193f7 100644 --- a/crates/relayer-cli/src/commands/start.rs +++ b/crates/relayer-cli/src/commands/start.rs @@ -4,7 +4,6 @@ use std::error::Error; use std::io; use abscissa_core::clap::Parser; -use abscissa_core::{Command, Runnable}; use crossbeam_channel::Sender; use ibc_relayer::chain::handle::{CachingChainHandle, ChainHandle}; @@ -132,7 +131,6 @@ fn register_signals(tx_cmd: Sender) -> Result<(), io::Error> { Ok(()) } -#[cfg(feature = "rest-server")] fn spawn_rest_server(config: &Config) -> Option { use ibc_relayer::util::spawn_blocking; @@ -170,23 +168,6 @@ fn spawn_rest_server(config: &Config) -> Option { Some(rx) } -#[cfg(not(feature = "rest-server"))] -fn spawn_rest_server(config: &Config) -> Option { - let rest = config.rest.clone(); - - if rest.enabled { - warn!( - "REST server enabled in the config but Hermes was built without REST support, \ - build Hermes with --features=rest-server to enable REST support." - ); - - None - } else { - None - } -} - -#[cfg(feature = "telemetry")] fn spawn_telemetry_server(config: &Config) { use ibc_relayer::util::spawn_blocking; @@ -221,16 +202,6 @@ fn spawn_telemetry_server(config: &Config) { }); } -#[cfg(not(feature = "telemetry"))] -fn spawn_telemetry_server(config: &Config) { - if config.telemetry.enabled { - warn!( - "telemetry enabled in the config but Hermes was built without telemetry support, \ - build Hermes with --features=telemetry to enable telemetry support." - ); - } -} - fn make_supervisor( config: Config, options: SupervisorOptions, diff --git a/crates/relayer-cli/src/commands/tx.rs b/crates/relayer-cli/src/commands/tx.rs index f8cadf766b..dc5099250c 100644 --- a/crates/relayer-cli/src/commands/tx.rs +++ b/crates/relayer-cli/src/commands/tx.rs @@ -44,6 +44,24 @@ pub enum TxCmd { /// Confirm the closing of a channel (ChannelCloseConfirm) ChanCloseConfirm(channel::TxChanCloseConfirmCmd), + /// Relay the channel upgrade attempt (ChannelUpgradeTry) + ChanUpgradeTry(channel::TxChanUpgradeTryCmd), + + /// Relay the channel upgrade attempt (ChannelUpgradeAck) + ChanUpgradeAck(channel::TxChanUpgradeAckCmd), + + /// Relay the channel upgrade attempt (ChannelUpgradeConfirm) + ChanUpgradeConfirm(channel::TxChanUpgradeConfirmCmd), + + /// Relay the channel upgrade attempt (ChannelUpgradeOpen) + ChanUpgradeOpen(channel::TxChanUpgradeOpenCmd), + + /// Relay the channel upgrade cancellation (ChannelUpgradeCancel) + ChanUpgradeCancel(channel::TxChanUpgradeCancelCmd), + + /// Relay the channel upgrade timeout (ChannelUpgradeTimeout) + ChanUpgradeTimeout(channel::TxChanUpgradeTimeoutCmd), + /// Send a fungible token transfer test transaction (ICS20 MsgTransfer) FtTransfer(transfer::TxIcs20MsgTransferCmd), diff --git a/crates/relayer-cli/src/commands/tx/channel.rs b/crates/relayer-cli/src/commands/tx/channel.rs index 0531c85dfe..7db47011e7 100644 --- a/crates/relayer-cli/src/commands/tx/channel.rs +++ b/crates/relayer-cli/src/commands/tx/channel.rs @@ -1,7 +1,7 @@ #![allow(clippy::redundant_closure_call)] use abscissa_core::clap::Parser; -use abscissa_core::{Command, Runnable}; +use abscissa_core::Command; use ibc_relayer::chain::handle::ChainHandle; use ibc_relayer::chain::requests::{IncludeProof, QueryConnectionRequest, QueryHeight}; @@ -18,6 +18,19 @@ use crate::conclude::Output; use crate::error::Error; use crate::prelude::*; +/// Macro that generates the `Runnable::run` implementation for a +/// `tx channel` subcommand. +/// +/// The macro takes the following arguments: +/// - `$dbg_string`: a string literal that will be used to identify the subcommand +/// in debug logs +/// - `$func`: the method that will be called to build and send the `Channel` message +/// - `$self`: the type that `Runnable` is being implemented for +/// - `$chan`: a closure that specifies how to build the `Channel` object +/// +/// The macro spawns a `ChainHandlePair`, fetches the destination connection, +/// creates a `Channel` object via the closure, and then calls the `$func` method +/// with the `Channel` object. macro_rules! tx_chan_cmd { ($dbg_string:literal, $func:ident, $self:expr, $chan:expr) => { let config = app_config(); @@ -113,56 +126,33 @@ pub struct TxChanOpenInitCmd { impl Runnable for TxChanOpenInitCmd { fn run(&self) { - let config = app_config(); - - let chains = match ChainHandlePair::spawn(&config, &self.src_chain_id, &self.dst_chain_id) { - Ok(chains) => chains, - Err(e) => Output::error(e).exit(), - }; - - // Retrieve the connection - let dst_connection = match chains.dst.query_connection( - QueryConnectionRequest { - connection_id: self.dst_conn_id.clone(), - height: QueryHeight::Latest, - }, - IncludeProof::No, - ) { - Ok((connection, _)) => connection, - Err(e) => Output::error(e).exit(), - }; - - let channel = Channel { - connection_delay: Default::default(), - ordering: self.order, - a_side: ChannelSide::new( - chains.src, - ClientId::default(), - ConnectionId::default(), - self.src_port_id.clone(), - None, - None, - ), - b_side: ChannelSide::new( - chains.dst, - dst_connection.client_id().clone(), - self.dst_conn_id.clone(), - self.dst_port_id.clone(), - None, - None, - ), - }; - - info!("message ChanOpenInit: {}", channel); - - let res: Result = channel - .build_chan_open_init_and_send() - .map_err(Error::channel); - - match res { - Ok(receipt) => Output::success(receipt).exit(), - Err(e) => Output::error(e).exit(), - } + tx_chan_cmd!( + "ChanOpenInit", + build_chan_open_init_and_send, + self, + |chains: ChainHandlePair, dst_connection: ConnectionEnd| { + Channel { + connection_delay: Default::default(), + ordering: self.order, + a_side: ChannelSide::new( + chains.src, + ClientId::default(), + ConnectionId::default(), + self.src_port_id.clone(), + None, + None, + ), + b_side: ChannelSide::new( + chains.dst, + dst_connection.client_id().clone(), + self.dst_conn_id.clone(), + self.dst_port_id.clone(), + None, + None, + ), + } + } + ); } } @@ -669,19 +659,803 @@ impl Runnable for TxChanCloseConfirmCmd { } } -#[cfg(test)] -mod tests { - use super::{ - TxChanCloseConfirmCmd, TxChanCloseInitCmd, TxChanOpenAckCmd, TxChanOpenConfirmCmd, - TxChanOpenInitCmd, TxChanOpenTryCmd, - }; +/// Relay the channel upgrade attempt (ChannelUpgradeTry) +/// +/// Build and send a `ChannelUpgradeTry` message in response to +/// a `ChannelUpgradeInit` message, signaling the chain's intent to +/// cooperate with the source chain on upgrading the specified channel +/// and initiating the upgrade handshake. +#[derive(Clone, Command, Debug, Parser, PartialEq, Eq)] +pub struct TxChanUpgradeTryCmd { + #[clap( + long = "dst-chain", + required = true, + value_name = "DST_CHAIN_ID", + help_heading = "REQUIRED", + help = "Identifier of the destination chain" + )] + dst_chain_id: ChainId, - use std::str::FromStr; + #[clap( + long = "src-chain", + required = true, + value_name = "SRC_CHAIN_ID", + help_heading = "REQUIRED", + help = "Identifier of the source chain" + )] + src_chain_id: ChainId, - use abscissa_core::clap::Parser; - use ibc_relayer_types::core::{ - ics04_channel::channel::Ordering, - ics24_host::identifier::{ChainId, ChannelId, ConnectionId, PortId}, + #[clap( + long = "dst-connection", + visible_alias = "dst-conn", + required = true, + value_name = "DST_CONNECTION_ID", + help_heading = "REQUIRED", + help = "Identifier of the destination connection" + )] + dst_conn_id: ConnectionId, + + #[clap( + long = "dst-port", + required = true, + value_name = "DST_PORT_ID", + help_heading = "REQUIRED", + help = "Identifier of the destination port" + )] + dst_port_id: PortId, + + #[clap( + long = "src-port", + required = true, + value_name = "SRC_PORT_ID", + help_heading = "REQUIRED", + help = "Identifier of the source port" + )] + src_port_id: PortId, + + #[clap( + long = "src-channel", + visible_alias = "src-chan", + required = true, + value_name = "SRC_CHANNEL_ID", + help_heading = "REQUIRED", + help = "Identifier of the source channel (required)" + )] + src_chan_id: ChannelId, + + #[clap( + long = "dst-channel", + visible_alias = "dst-chan", + required = true, + help_heading = "REQUIRED", + value_name = "DST_CHANNEL_ID", + help = "Identifier of the destination channel (optional)" + )] + dst_chan_id: Option, +} + +impl Runnable for TxChanUpgradeTryCmd { + fn run(&self) { + let config = app_config(); + + let chains = match ChainHandlePair::spawn(&config, &self.src_chain_id, &self.dst_chain_id) { + Ok(chains) => chains, + Err(e) => Output::error(format!("{}", e)).exit(), + }; + + // Retrieve the connection + let dst_connection = match chains.dst.query_connection( + QueryConnectionRequest { + connection_id: self.dst_conn_id.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) { + Ok((connection, _)) => connection, + Err(e) => Output::error(format!("{}", e)).exit(), + }; + + // Fetch the Channel that will facilitate the communication between the channel ends + // being upgraded. This channel is assumed to already exist on the destination chain. + let channel = Channel { + connection_delay: Default::default(), + ordering: Ordering::default(), + a_side: ChannelSide::new( + chains.src, + ClientId::default(), + ConnectionId::default(), + self.src_port_id.clone(), + Some(self.src_chan_id.clone()), + None, + ), + b_side: ChannelSide::new( + chains.dst, + dst_connection.client_id().clone(), + self.dst_conn_id.clone(), + self.dst_port_id.clone(), + self.dst_chan_id.clone(), + None, + ), + }; + + info!("message ChanUpgradeTry: {}", channel); + + let res: Result = channel + .build_chan_upgrade_try_and_send() + .map_err(Error::channel); + + match res { + Ok(receipt) => Output::success(receipt).exit(), + Err(e) => Output::error(e).exit(), + } + } +} + +/// Relay the channel upgrade attempt (ChannelUpgradeAck) +/// +/// Build and send a `ChannelUpgradeAck` message in response to +/// a `ChannelUpgradeTry` message in order to continue the channel +/// upgrade handshake. +#[derive(Clone, Command, Debug, Parser, PartialEq, Eq)] +pub struct TxChanUpgradeAckCmd { + #[clap( + long = "dst-chain", + required = true, + value_name = "DST_CHAIN_ID", + help_heading = "REQUIRED", + help = "Identifier of the destination chain" + )] + dst_chain_id: ChainId, + + #[clap( + long = "src-chain", + required = true, + value_name = "SRC_CHAIN_ID", + help_heading = "REQUIRED", + help = "Identifier of the source chain" + )] + src_chain_id: ChainId, + + #[clap( + long = "dst-connection", + visible_alias = "dst-conn", + required = true, + value_name = "DST_CONNECTION_ID", + help_heading = "REQUIRED", + help = "Identifier of the destination connection" + )] + dst_conn_id: ConnectionId, + + #[clap( + long = "dst-port", + required = true, + value_name = "DST_PORT_ID", + help_heading = "REQUIRED", + help = "Identifier of the destination port" + )] + dst_port_id: PortId, + + #[clap( + long = "src-port", + required = true, + value_name = "SRC_PORT_ID", + help_heading = "REQUIRED", + help = "Identifier of the source port" + )] + src_port_id: PortId, + + #[clap( + long = "src-channel", + visible_alias = "src-chan", + required = true, + value_name = "SRC_CHANNEL_ID", + help_heading = "REQUIRED", + help = "Identifier of the source channel (required)" + )] + src_chan_id: ChannelId, + + #[clap( + long = "dst-channel", + visible_alias = "dst-chan", + required = true, + help_heading = "REQUIRED", + value_name = "DST_CHANNEL_ID", + help = "Identifier of the destination channel (optional)" + )] + dst_chan_id: Option, +} + +impl Runnable for TxChanUpgradeAckCmd { + fn run(&self) { + let config = app_config(); + + let chains = match ChainHandlePair::spawn(&config, &self.src_chain_id, &self.dst_chain_id) { + Ok(chains) => chains, + Err(e) => Output::error(format!("{}", e)).exit(), + }; + + // Retrieve the connection + let dst_connection = match chains.dst.query_connection( + QueryConnectionRequest { + connection_id: self.dst_conn_id.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) { + Ok((connection, _)) => connection, + Err(e) => Output::error(format!("{}", e)).exit(), + }; + + // Fetch the Channel that will facilitate the communication between the channel ends + // being upgraded. This channel is assumed to already exist on the destination chain. + let channel = Channel { + connection_delay: Default::default(), + ordering: Ordering::default(), + a_side: ChannelSide::new( + chains.src, + ClientId::default(), + ConnectionId::default(), + self.src_port_id.clone(), + Some(self.src_chan_id.clone()), + None, + ), + b_side: ChannelSide::new( + chains.dst, + dst_connection.client_id().clone(), + self.dst_conn_id.clone(), + self.dst_port_id.clone(), + self.dst_chan_id.clone(), + None, + ), + }; + + info!("message ChanUpgradeAck: {}", channel); + + let res: Result = channel + .build_chan_upgrade_ack_and_send() + .map_err(Error::channel); + + match res { + Ok(receipt) => Output::success(receipt).exit(), + Err(e) => Output::error(e).exit(), + } + } +} + +/// Relay the channel upgrade attempt (ChannelUpgradeConfirm) +/// +/// Build and send a `ChannelUpgradeConfirm` message in response to +/// a `ChannelUpgradeAck` message in order to continue the channel +/// upgrade handshake. +#[derive(Clone, Command, Debug, Parser, PartialEq, Eq)] +pub struct TxChanUpgradeConfirmCmd { + #[clap( + long = "dst-chain", + required = true, + value_name = "DST_CHAIN_ID", + help_heading = "REQUIRED", + help = "Identifier of the destination chain" + )] + dst_chain_id: ChainId, + + #[clap( + long = "src-chain", + required = true, + value_name = "SRC_CHAIN_ID", + help_heading = "REQUIRED", + help = "Identifier of the source chain" + )] + src_chain_id: ChainId, + + #[clap( + long = "dst-connection", + visible_alias = "dst-conn", + required = true, + value_name = "DST_CONNECTION_ID", + help_heading = "REQUIRED", + help = "Identifier of the destination connection" + )] + dst_conn_id: ConnectionId, + + #[clap( + long = "dst-port", + required = true, + value_name = "DST_PORT_ID", + help_heading = "REQUIRED", + help = "Identifier of the destination port" + )] + dst_port_id: PortId, + + #[clap( + long = "src-port", + required = true, + value_name = "SRC_PORT_ID", + help_heading = "REQUIRED", + help = "Identifier of the source port" + )] + src_port_id: PortId, + + #[clap( + long = "src-channel", + visible_alias = "src-chan", + required = true, + value_name = "SRC_CHANNEL_ID", + help_heading = "REQUIRED", + help = "Identifier of the source channel (required)" + )] + src_chan_id: ChannelId, + + #[clap( + long = "dst-channel", + visible_alias = "dst-chan", + required = true, + help_heading = "REQUIRED", + value_name = "DST_CHANNEL_ID", + help = "Identifier of the destination channel (optional)" + )] + dst_chan_id: Option, +} + +impl Runnable for TxChanUpgradeConfirmCmd { + fn run(&self) { + let config = app_config(); + + let chains = match ChainHandlePair::spawn(&config, &self.src_chain_id, &self.dst_chain_id) { + Ok(chains) => chains, + Err(e) => Output::error(format!("{}", e)).exit(), + }; + + // Retrieve the connection + let dst_connection = match chains.dst.query_connection( + QueryConnectionRequest { + connection_id: self.dst_conn_id.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) { + Ok((connection, _)) => connection, + Err(e) => Output::error(format!("{}", e)).exit(), + }; + + // Fetch the Channel that will facilitate the communication between the channel ends + // being upgraded. This channel is assumed to already exist on the destination chain. + let channel = Channel { + connection_delay: Default::default(), + ordering: Ordering::default(), + a_side: ChannelSide::new( + chains.src, + ClientId::default(), + ConnectionId::default(), + self.src_port_id.clone(), + Some(self.src_chan_id.clone()), + None, + ), + b_side: ChannelSide::new( + chains.dst, + dst_connection.client_id().clone(), + self.dst_conn_id.clone(), + self.dst_port_id.clone(), + self.dst_chan_id.clone(), + None, + ), + }; + + info!("message ChanUpgradeConfirm: {}", channel); + + let res: Result = channel + .build_chan_upgrade_confirm_and_send() + .map_err(Error::channel); + + match res { + Ok(receipt) => Output::success(receipt).exit(), + Err(e) => Output::error(e).exit(), + } + } +} + +/// Relay the channel upgrade attempt (ChannelUpgradeOpen) +/// +/// Build and send a `ChannelUpgradeOpen` message to finalize +/// the channel upgrade handshake. +#[derive(Clone, Command, Debug, Parser, PartialEq, Eq)] +pub struct TxChanUpgradeOpenCmd { + #[clap( + long = "dst-chain", + required = true, + value_name = "DST_CHAIN_ID", + help_heading = "REQUIRED", + help = "Identifier of the destination chain" + )] + dst_chain_id: ChainId, + + #[clap( + long = "src-chain", + required = true, + value_name = "SRC_CHAIN_ID", + help_heading = "REQUIRED", + help = "Identifier of the source chain" + )] + src_chain_id: ChainId, + + #[clap( + long = "dst-connection", + visible_alias = "dst-conn", + required = true, + value_name = "DST_CONNECTION_ID", + help_heading = "REQUIRED", + help = "Identifier of the destination connection" + )] + dst_conn_id: ConnectionId, + + #[clap( + long = "dst-port", + required = true, + value_name = "DST_PORT_ID", + help_heading = "REQUIRED", + help = "Identifier of the destination port" + )] + dst_port_id: PortId, + + #[clap( + long = "src-port", + required = true, + value_name = "SRC_PORT_ID", + help_heading = "REQUIRED", + help = "Identifier of the source port" + )] + src_port_id: PortId, + + #[clap( + long = "src-channel", + visible_alias = "src-chan", + required = true, + value_name = "SRC_CHANNEL_ID", + help_heading = "REQUIRED", + help = "Identifier of the source channel (required)" + )] + src_chan_id: ChannelId, + + #[clap( + long = "dst-channel", + visible_alias = "dst-chan", + required = true, + help_heading = "REQUIRED", + value_name = "DST_CHANNEL_ID", + help = "Identifier of the destination channel (optional)" + )] + dst_chan_id: Option, +} + +impl Runnable for TxChanUpgradeOpenCmd { + fn run(&self) { + let config = app_config(); + + let chains = match ChainHandlePair::spawn(&config, &self.src_chain_id, &self.dst_chain_id) { + Ok(chains) => chains, + Err(e) => Output::error(format!("{}", e)).exit(), + }; + + // Retrieve the connection + let dst_connection = match chains.dst.query_connection( + QueryConnectionRequest { + connection_id: self.dst_conn_id.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) { + Ok((connection, _)) => connection, + Err(e) => Output::error(format!("{}", e)).exit(), + }; + + // Fetch the Channel that will facilitate the communication between the channel ends + // being upgraded. This channel is assumed to already exist on the destination chain. + let channel = Channel { + connection_delay: Default::default(), + ordering: Ordering::default(), + a_side: ChannelSide::new( + chains.src, + ClientId::default(), + ConnectionId::default(), + self.src_port_id.clone(), + Some(self.src_chan_id.clone()), + None, + ), + b_side: ChannelSide::new( + chains.dst, + dst_connection.client_id().clone(), + self.dst_conn_id.clone(), + self.dst_port_id.clone(), + self.dst_chan_id.clone(), + None, + ), + }; + + info!("message ChanUpgradeOpen: {}", channel); + + let res: Result = channel + .build_chan_upgrade_open_and_send() + .map_err(Error::channel); + + match res { + Ok(receipt) => Output::success(receipt).exit(), + Err(e) => Output::error(e).exit(), + } + } +} + +/// Relay channel upgrade cancel when counterparty has aborted the upgrade (ChannelUpgradeCancel) +/// +/// Build and send a `ChannelUpgradeCancel` message to cancel +/// the channel upgrade handshake given that the counterparty has aborted. +#[derive(Clone, Command, Debug, Parser, PartialEq, Eq)] +pub struct TxChanUpgradeCancelCmd { + #[clap( + long = "dst-chain", + required = true, + value_name = "DST_CHAIN_ID", + help_heading = "REQUIRED", + help = "Identifier of the destination chain" + )] + dst_chain_id: ChainId, + + #[clap( + long = "src-chain", + required = true, + value_name = "SRC_CHAIN_ID", + help_heading = "REQUIRED", + help = "Identifier of the source chain" + )] + src_chain_id: ChainId, + + #[clap( + long = "dst-connection", + visible_alias = "dst-conn", + required = true, + value_name = "DST_CONNECTION_ID", + help_heading = "REQUIRED", + help = "Identifier of the destination connection" + )] + dst_conn_id: ConnectionId, + + #[clap( + long = "dst-port", + required = true, + value_name = "DST_PORT_ID", + help_heading = "REQUIRED", + help = "Identifier of the destination port" + )] + dst_port_id: PortId, + + #[clap( + long = "src-port", + required = true, + value_name = "SRC_PORT_ID", + help_heading = "REQUIRED", + help = "Identifier of the source port" + )] + src_port_id: PortId, + + #[clap( + long = "src-channel", + visible_alias = "src-chan", + required = true, + value_name = "SRC_CHANNEL_ID", + help_heading = "REQUIRED", + help = "Identifier of the source channel (required)" + )] + src_chan_id: ChannelId, + + #[clap( + long = "dst-channel", + visible_alias = "dst-chan", + required = true, + help_heading = "REQUIRED", + value_name = "DST_CHANNEL_ID", + help = "Identifier of the destination channel (optional)" + )] + dst_chan_id: Option, +} + +impl Runnable for TxChanUpgradeCancelCmd { + fn run(&self) { + let config = app_config(); + + let chains = match ChainHandlePair::spawn(&config, &self.src_chain_id, &self.dst_chain_id) { + Ok(chains) => chains, + Err(e) => Output::error(format!("{}", e)).exit(), + }; + + // Retrieve the connection + let dst_connection = match chains.dst.query_connection( + QueryConnectionRequest { + connection_id: self.dst_conn_id.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) { + Ok((connection, _)) => connection, + Err(e) => Output::error(format!("{}", e)).exit(), + }; + + // Fetch the Channel that will facilitate the communication between the channel ends + // being upgraded. This channel is assumed to already exist on the destination chain. + let channel = Channel { + connection_delay: Default::default(), + ordering: Ordering::default(), + a_side: ChannelSide::new( + chains.src, + ClientId::default(), + ConnectionId::default(), + self.src_port_id.clone(), + Some(self.src_chan_id.clone()), + None, + ), + b_side: ChannelSide::new( + chains.dst, + dst_connection.client_id().clone(), + self.dst_conn_id.clone(), + self.dst_port_id.clone(), + self.dst_chan_id.clone(), + None, + ), + }; + + info!("message ChanUpgradeCancel: {}", channel); + + let res: Result = channel + .build_chan_upgrade_cancel_and_send() + .map_err(Error::channel); + + match res { + Ok(receipt) => Output::success(receipt).exit(), + Err(e) => Output::error(e).exit(), + } + } +} + +/// Relay channel upgrade timeout when counterparty has not flushed packets before upgrade timeout (ChannelUpgradeTimeout) +/// +/// Build and send a `ChannelUpgradeTimeout` message to timeout +/// the channel upgrade handshake given that the counterparty has not flushed packets before upgrade timeout. +#[derive(Clone, Command, Debug, Parser, PartialEq, Eq)] +pub struct TxChanUpgradeTimeoutCmd { + #[clap( + long = "dst-chain", + required = true, + value_name = "DST_CHAIN_ID", + help_heading = "REQUIRED", + help = "Identifier of the destination chain" + )] + dst_chain_id: ChainId, + + #[clap( + long = "src-chain", + required = true, + value_name = "SRC_CHAIN_ID", + help_heading = "REQUIRED", + help = "Identifier of the source chain" + )] + src_chain_id: ChainId, + + #[clap( + long = "dst-connection", + visible_alias = "dst-conn", + required = true, + value_name = "DST_CONNECTION_ID", + help_heading = "REQUIRED", + help = "Identifier of the destination connection" + )] + dst_conn_id: ConnectionId, + + #[clap( + long = "dst-port", + required = true, + value_name = "DST_PORT_ID", + help_heading = "REQUIRED", + help = "Identifier of the destination port" + )] + dst_port_id: PortId, + + #[clap( + long = "src-port", + required = true, + value_name = "SRC_PORT_ID", + help_heading = "REQUIRED", + help = "Identifier of the source port" + )] + src_port_id: PortId, + + #[clap( + long = "src-channel", + visible_alias = "src-chan", + required = true, + value_name = "SRC_CHANNEL_ID", + help_heading = "REQUIRED", + help = "Identifier of the source channel (required)" + )] + src_chan_id: ChannelId, + + #[clap( + long = "dst-channel", + visible_alias = "dst-chan", + required = true, + help_heading = "REQUIRED", + value_name = "DST_CHANNEL_ID", + help = "Identifier of the destination channel (optional)" + )] + dst_chan_id: Option, +} + +impl Runnable for TxChanUpgradeTimeoutCmd { + fn run(&self) { + let config = app_config(); + + let chains = match ChainHandlePair::spawn(&config, &self.src_chain_id, &self.dst_chain_id) { + Ok(chains) => chains, + Err(e) => Output::error(format!("{}", e)).exit(), + }; + + // Retrieve the connection + let dst_connection = match chains.dst.query_connection( + QueryConnectionRequest { + connection_id: self.dst_conn_id.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) { + Ok((connection, _)) => connection, + Err(e) => Output::error(format!("{}", e)).exit(), + }; + + // Fetch the Channel that will facilitate the communication between the channel ends + // being upgraded. This channel is assumed to already exist on the destination chain. + let channel = Channel { + connection_delay: Default::default(), + ordering: Ordering::default(), + a_side: ChannelSide::new( + chains.src, + ClientId::default(), + ConnectionId::default(), + self.src_port_id.clone(), + Some(self.src_chan_id.clone()), + None, + ), + b_side: ChannelSide::new( + chains.dst, + dst_connection.client_id().clone(), + self.dst_conn_id.clone(), + self.dst_port_id.clone(), + self.dst_chan_id.clone(), + None, + ), + }; + + info!("message ChanUpgradeTimeout: {}", channel); + + let res: Result = channel + .build_chan_upgrade_timeout_and_send() + .map_err(Error::channel); + + match res { + Ok(receipt) => Output::success(receipt).exit(), + Err(e) => Output::error(e).exit(), + } + } +} + +#[cfg(test)] +mod tests { + use abscissa_core::clap::Parser; + use std::str::FromStr; + + use ibc_relayer_types::core::{ + ics04_channel::channel::Ordering, + ics24_host::identifier::{ChainId, ChannelId, ConnectionId, PortId}, + }; + + use crate::commands::tx::channel::{ + TxChanCloseConfirmCmd, TxChanCloseInitCmd, TxChanOpenAckCmd, TxChanOpenConfirmCmd, + TxChanOpenInitCmd, TxChanOpenTryCmd, }; #[test] diff --git a/crates/relayer-cli/src/commands/tx/connection.rs b/crates/relayer-cli/src/commands/tx/connection.rs index fb88a61d2e..20f602e5f7 100644 --- a/crates/relayer-cli/src/commands/tx/connection.rs +++ b/crates/relayer-cli/src/commands/tx/connection.rs @@ -1,7 +1,6 @@ #![allow(clippy::redundant_closure_call)] use abscissa_core::clap::Parser; -use abscissa_core::{Command, Runnable}; use ibc_relayer::connection::{Connection, ConnectionSide}; use ibc_relayer_types::core::ics24_host::identifier::{ChainId, ClientId, ConnectionId}; diff --git a/crates/relayer-cli/src/commands/tx/packet.rs b/crates/relayer-cli/src/commands/tx/packet.rs index 9a81666b37..89fc8d6aa7 100644 --- a/crates/relayer-cli/src/commands/tx/packet.rs +++ b/crates/relayer-cli/src/commands/tx/packet.rs @@ -1,5 +1,4 @@ use abscissa_core::clap::Parser; -use abscissa_core::{Command, Runnable}; use ibc_relayer_types::core::ics02_client::height::Height; use std::ops::RangeInclusive; @@ -88,7 +87,11 @@ impl Runnable for TxPacketRecvCmd { src_channel_id: self.src_channel_id.clone(), max_memo_size: config.mode.packets.ics20_max_memo_size, max_receiver_size: config.mode.packets.ics20_max_receiver_size, + + // Packets are only excluded when clearing + exclude_src_sequences: vec![], }; + let link = match Link::new_from_opts(chains.src, chains.dst, opts, false, false) { Ok(link) => link, Err(e) => Output::error(e).exit(), @@ -185,7 +188,11 @@ impl Runnable for TxPacketAckCmd { src_channel_id: self.src_channel_id.clone(), max_memo_size: config.mode.packets.ics20_max_memo_size, max_receiver_size: config.mode.packets.ics20_max_receiver_size, + + // Packets are only excluded when clearing + exclude_src_sequences: vec![], }; + let link = match Link::new_from_opts(chains.src, chains.dst, opts, false, false) { Ok(link) => link, Err(e) => Output::error(e).exit(), diff --git a/crates/relayer-cli/src/commands/tx/transfer.rs b/crates/relayer-cli/src/commands/tx/transfer.rs index 66b14026ae..62c3d96625 100644 --- a/crates/relayer-cli/src/commands/tx/transfer.rs +++ b/crates/relayer-cli/src/commands/tx/transfer.rs @@ -1,7 +1,7 @@ use core::time::Duration; use abscissa_core::clap::Parser; -use abscissa_core::{config::Override, Command, FrameworkErrorKind, Runnable}; +use abscissa_core::{config::Override, FrameworkErrorKind}; use eyre::eyre; use ibc_relayer::{ diff --git a/crates/relayer-cli/src/commands/tx/upgrade.rs b/crates/relayer-cli/src/commands/tx/upgrade.rs index c56a60832c..d41bf6ce1e 100644 --- a/crates/relayer-cli/src/commands/tx/upgrade.rs +++ b/crates/relayer-cli/src/commands/tx/upgrade.rs @@ -1,7 +1,6 @@ use core::time::Duration; use abscissa_core::clap::Parser; -use abscissa_core::{Command, Runnable}; use ibc_relayer::upgrade_chain::requires_legacy_upgrade_proposal; use ibc_relayer::upgrade_chain::{build_and_send_ibc_upgrade_proposal, UpgradePlanOptions}; diff --git a/crates/relayer-cli/src/conclude.rs b/crates/relayer-cli/src/conclude.rs index 41b45d8cbb..7ee650583c 100644 --- a/crates/relayer-cli/src/conclude.rs +++ b/crates/relayer-cli/src/conclude.rs @@ -17,9 +17,9 @@ //! ``` //! //! - Exit from a query/tx with an error of type `anomaly`: -//! In the case where the error is a complex type such as anomaly (including backtraces), it is -//! better to simplify the output and only write out the chain of error sources, which we can -//! achieve with `format!("{}", e)`. The complete solution is as follows: +//! In the case where the error is a complex type such as anomaly (including backtraces), it is +//! better to simplify the output and only write out the chain of error sources, which we can +//! achieve with `format!("{}", e)`. The complete solution is as follows: //! //! ```ignore //! let e: Error = Kind::Query.into(); @@ -171,7 +171,7 @@ impl Output { /// Builder-style method for attaching a result to an output object. pub fn with_result(mut self, result: R) -> Self where - R: Serialize + core::fmt::Debug + 'static, + R: Serialize + fmt::Debug + 'static, { if json() { self.result = Result::Json(serialize_result(result)); @@ -192,7 +192,7 @@ impl Output { /// input `result`. pub fn success(result: R) -> Self where - R: Serialize + core::fmt::Debug + 'static, + R: Serialize + fmt::Debug + 'static, { Output::with_success().with_result(result) } @@ -236,7 +236,7 @@ impl Output { } /// Helper to serialize a result into a `serde_json::Value`. -fn serialize_result(res: impl Serialize + core::fmt::Debug) -> serde_json::Value { +fn serialize_result(res: impl Serialize + fmt::Debug) -> serde_json::Value { let last_resort = format!("{res:#?}"); match serde_json::to_value(res) { diff --git a/crates/relayer-cli/src/entry.rs b/crates/relayer-cli/src/entry.rs index 1ffa17bc3e..29fa21c0da 100644 --- a/crates/relayer-cli/src/entry.rs +++ b/crates/relayer-cli/src/entry.rs @@ -1,5 +1,3 @@ -#![allow(unused_qualifications)] // Fix for warning in `ValueEnum` generated code - //! Definition of the entrypoint for the Hermes CLI. use std::path::PathBuf; diff --git a/crates/relayer-cli/src/lib.rs b/crates/relayer-cli/src/lib.rs index ff28651be7..0b817798ff 100644 --- a/crates/relayer-cli/src/lib.rs +++ b/crates/relayer-cli/src/lib.rs @@ -13,13 +13,8 @@ // Tip: Deny warnings with `RUSTFLAGS="-D warnings"` environment variable in CI #![forbid(unsafe_code)] -#![deny( - rust_2018_idioms, - trivial_casts, - unused_lifetimes, - unused_qualifications -)] -#![allow(deprecated)] +#![deny(rust_2018_idioms, trivial_casts, unused_lifetimes)] +#![allow(deprecated, unknown_lints, non_local_definitions)] extern crate alloc; diff --git a/crates/relayer-cli/src/prelude.rs b/crates/relayer-cli/src/prelude.rs index fac61533bc..8108fee094 100644 --- a/crates/relayer-cli/src/prelude.rs +++ b/crates/relayer-cli/src/prelude.rs @@ -6,6 +6,7 @@ /// Abscissa core prelude pub use abscissa_core::prelude::*; +pub use abscissa_core::Command; /// Application state accessors pub use crate::application::{app_config, app_reader}; diff --git a/crates/relayer-cli/tests/acceptance.rs b/crates/relayer-cli/tests/acceptance.rs index c50c4b0866..6b568ee1ef 100644 --- a/crates/relayer-cli/tests/acceptance.rs +++ b/crates/relayer-cli/tests/acceptance.rs @@ -10,13 +10,7 @@ // Tip: Deny warnings with `RUSTFLAGS="-D warnings"` environment variable in CI #![forbid(unsafe_code)] -#![warn( - missing_docs, - rust_2018_idioms, - trivial_casts, - unused_lifetimes, - unused_qualifications -)] +#![warn(missing_docs, rust_2018_idioms, trivial_casts, unused_lifetimes)] use abscissa_core::testing::prelude::*; use once_cell::sync::Lazy; @@ -30,7 +24,6 @@ use once_cell::sync::Lazy; pub static RUNNER: Lazy = Lazy::new(CmdRunner::default); /// Use `Config::default()` value if no config or args -#[cfg(not(tarpaulin))] #[test] fn start_no_args() { let mut runner = RUNNER.clone(); @@ -46,7 +39,6 @@ fn start_no_args() { cmd.wait().unwrap().expect_success(); } -#[cfg(not(tarpaulin))] #[test] fn example_configuration_is_valid() { let mut runner = RUNNER.clone(); diff --git a/crates/relayer-rest/Cargo.toml b/crates/relayer-rest/Cargo.toml index 1f891a77ef..134fb6c3e5 100644 --- a/crates/relayer-rest/Cargo.toml +++ b/crates/relayer-rest/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ibc-relayer-rest" -version = "0.27.0" +version = "0.29.5" authors = ["Informal Systems "] edition = "2021" license = "Apache-2.0" @@ -8,21 +8,21 @@ readme = "README.md" keywords = ["ibc", "rest", "api", "cosmos", "tendermint"] homepage = "https://hermes.informal.systems/" repository = "https://github.com/informalsystems/hermes" -rust-version = "1.71" +rust-version = "1.76.0" description = """ Rust implementation of a RESTful API server for Hermes """ [dependencies] -ibc-relayer-types = { version = "0.27.0", path = "../relayer-types" } -ibc-relayer = { version = "0.27.0", path = "../relayer" } +ibc-relayer-types = { workspace = true } +ibc-relayer = { workspace = true } -crossbeam-channel = "0.5" -serde = "1.0" -tracing = "0.1" -axum = "0.6" -tokio = "1.26" +axum = { workspace = true } +crossbeam-channel = { workspace = true } +serde = { workspace = true } +tokio = { workspace = true } +tracing = { workspace = true } [dev-dependencies] -reqwest = { version = "0.11.16", features = ["json"], default-features = false } -toml = "0.8.8" +reqwest = { workspace = true, features = ["json"] } +toml = { workspace = true } diff --git a/crates/relayer-rest/README.md b/crates/relayer-rest/README.md index ee66cb6870..db2dd9ca9f 100644 --- a/crates/relayer-rest/README.md +++ b/crates/relayer-rest/README.md @@ -6,7 +6,7 @@ [![End to End testing][e2e-image]][e2e-link] [![Apache 2.0 Licensed][license-image]][license-link] ![Rust Stable][rustc-image] -![Rust 1.71+][rustc-version] +![Rust 1.76.0+][rustc-version] This is the repository for the IBC REST server for use in the Hermes IBC relayer. @@ -39,4 +39,4 @@ Unless required by applicable law or agreed to in writing, software distributed [license-image]: https://img.shields.io/badge/license-Apache2.0-blue.svg [license-link]: https://github.com/informalsystems/hermes/blob/master/LICENSE [rustc-image]: https://img.shields.io/badge/rustc-stable-blue.svg -[rustc-version]: https://img.shields.io/badge/rustc-1.71+-blue.svg +[rustc-version]: https://img.shields.io/badge/rustc-1.76.0+-blue.svg diff --git a/crates/relayer-rest/tests/mock.rs b/crates/relayer-rest/tests/mock.rs index 9b1b1e530a..1e78a77d7b 100644 --- a/crates/relayer-rest/tests/mock.rs +++ b/crates/relayer-rest/tests/mock.rs @@ -64,7 +64,7 @@ async fn version() { let rest_api_version = VersionInfo { name: "ibc-relayer-rest".to_string(), - version: "0.27.0".to_string(), + version: "0.29.5".to_string(), }; let result: JsonResult<_, ()> = JsonResult::Success(vec![version.clone(), rest_api_version]); diff --git a/crates/relayer-types/Cargo.toml b/crates/relayer-types/Cargo.toml index 38cb6d710e..9184537bc2 100644 --- a/crates/relayer-types/Cargo.toml +++ b/crates/relayer-types/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "ibc-relayer-types" -version = "0.27.0" +version = "0.29.5" edition = "2021" license = "Apache-2.0" readme = "README.md" keywords = ["blockchain", "consensus", "cosmos", "ibc", "tendermint"] repository = "https://github.com/informalsystems/hermes" authors = ["Informal Systems "] -rust-version = "1.71" +rust-version = "1.76.0" description = """ Implementation of the Inter-Blockchain Communication Protocol (IBC). This crate comprises the main data structures and on-chain logic. @@ -18,48 +18,34 @@ all-features = true [features] clock = [] -# 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", "clock"] [dependencies] -# Proto definitions for all IBC-related interfaces, e.g., connections or channels. -ibc-proto = { version = "0.41.0", features = ["serde"] } -ics23 = { version = "0.11.0", features = ["std", "host-functions"] } -time = { version = "0.3" } -serde_derive = { version = "1.0.104" } -serde = { version = "1.0" } -serde_json = { version = "1" } -prost = { version = "0.12" } -bytes = { version = "1.4.0" } -subtle-encoding = { version = "0.5" } -flex-error = { version = "0.4.4" } -derive_more = { version = "0.99.17", default-features = false, features = ["from", "into", "display"] } -uint = { version = "0.9" } -itertools = { version = "0.10.3" } -primitive-types = { version = "0.12.1", default-features = false, features = ["serde_no_std"] } -num-rational = "0.4.1" -regex = "1" - -[dependencies.tendermint] -version = "0.34.0" -features = ["clock"] - -[dependencies.tendermint-proto] -version = "0.34.0" - -[dependencies.tendermint-light-client-verifier] -version = "0.34.0" -features = ["rust-crypto"] - -[dependencies.tendermint-testgen] -version = "0.34.0" -optional = true +bytes = { workspace = true } +derive_more = { workspace = true, features = ["from", "into", "display"] } +flex-error = { workspace = true } +ibc-proto = { workspace = true, features = ["serde"] } +ics23 = { workspace = true, features = ["std", "host-functions"] } +itertools = { workspace = true } +num-rational = { workspace = true } +primitive-types = { workspace = true, features = ["serde_no_std"] } +prost = { workspace = true } +regex = { workspace = true } +serde = { workspace = true } +serde_derive = { workspace = true } +serde_json = { workspace = true } +subtle-encoding = { workspace = true } +tendermint-light-client-verifier = { workspace = true, features = ["rust-crypto"] } +tendermint-proto = { workspace = true } +tendermint-testgen = { workspace = true, optional = true } +tendermint = { workspace = true, features = ["clock"] } +time = { workspace = true } +uint = { workspace = true } +tracing = { workspace = true } [dev-dependencies] -env_logger = "0.11.1" -tracing = { version = "0.1.36", default-features = false } -tracing-subscriber = { version = "0.3.14", features = ["fmt", "env-filter", "json"] } -test-log = { version = "0.2.14", features = ["trace"] } -tendermint-rpc = { version = "0.34.0", features = ["http-client", "websocket-client"] } -tendermint-testgen = { version = "0.34.0" } # Needed for generating (synthetic) light blocks. +env_logger = { workspace = true } +tendermint-rpc = { workspace = true, features = ["http-client", "websocket-client"] } +tendermint-testgen = { workspace = true } # Needed for generating (synthetic) light blocks. +test-log = { workspace = true, features = ["trace"] } +tracing = { workspace = true } +tracing-subscriber = { workspace = true, features = ["fmt", "env-filter", "json"] } diff --git a/crates/relayer-types/src/applications/ics27_ica/error.rs b/crates/relayer-types/src/applications/ics27_ica/error.rs index 52f2027496..263f090fe1 100644 --- a/crates/relayer-types/src/applications/ics27_ica/error.rs +++ b/crates/relayer-types/src/applications/ics27_ica/error.rs @@ -1,3 +1,4 @@ +use crate::core::ics04_channel::error as channel_error; use crate::core::ics24_host::error::ValidationError; use crate::signer::SignerError; @@ -6,13 +7,21 @@ use flex_error::define_error; define_error! { #[derive(Debug, PartialEq, Eq)] Error { + Ics04Channel + [ channel_error::Error ] + | _ | { "ICS 04 channel error" }, + Owner [ SignerError ] - | _ | { "failed to parse owner" }, + | _ | { "failed to parse owner" }, InvalidConnectionIdentifier [ ValidationError ] - | _ | { "connection identifier error" }, + | _ | { "connection identifier error" }, + + InvalidOrdering + { ordering: i32 } + | e | { format_args!("invalid ordering: {}", e.ordering) }, InvalidPacketData | _ | { "packet data is None" }, diff --git a/crates/relayer-types/src/applications/ics27_ica/mod.rs b/crates/relayer-types/src/applications/ics27_ica/mod.rs index c42612c711..74c81280b4 100644 --- a/crates/relayer-types/src/applications/ics27_ica/mod.rs +++ b/crates/relayer-types/src/applications/ics27_ica/mod.rs @@ -2,3 +2,6 @@ pub mod cosmos_tx; pub mod error; pub mod msgs; pub mod packet_data; + +/// ICS27 application current version. +pub const VERSION: &str = "ics27-1"; diff --git a/crates/relayer-types/src/applications/ics27_ica/msgs/register.rs b/crates/relayer-types/src/applications/ics27_ica/msgs/register.rs index 9c73c9de93..9258c4c07f 100644 --- a/crates/relayer-types/src/applications/ics27_ica/msgs/register.rs +++ b/crates/relayer-types/src/applications/ics27_ica/msgs/register.rs @@ -4,6 +4,7 @@ use ibc_proto::ibc::applications::interchain_accounts::controller::v1::MsgRegist use ibc_proto::Protobuf; use crate::applications::ics27_ica::error::Error; +use crate::core::ics04_channel::channel::Ordering; use crate::core::ics04_channel::version::Version; use crate::core::ics24_host::error::ValidationError; use crate::core::ics24_host::identifier::ConnectionId; @@ -18,6 +19,7 @@ pub struct MsgRegisterInterchainAccount { pub owner: Signer, pub connection_id: ConnectionId, pub version: Version, + pub ordering: Ordering, } impl Msg for MsgRegisterInterchainAccount { @@ -46,6 +48,8 @@ impl TryFrom for MsgRegisterInterchainAccount { .parse() .map_err(Error::invalid_connection_identifier)?, version: value.version.into(), + ordering: Ordering::from_i32(value.ordering) + .map_err(|_| Error::invalid_ordering(value.ordering))?, }) } } @@ -56,6 +60,65 @@ impl From for RawMsgRegisterInterchainAccount { owner: value.owner.to_string(), connection_id: value.connection_id.to_string(), version: value.version.to_string(), + ordering: value.ordering as i32, + } + } +} + +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, prost::Message)] +pub struct LegacyRawMsgRegisterInterchainAccount { + #[prost(string, tag = "1")] + pub owner: String, + #[prost(string, tag = "2")] + pub connection_id: String, + #[prost(string, tag = "3")] + pub version: String, +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct LegacyMsgRegisterInterchainAccount { + pub owner: Signer, + pub connection_id: ConnectionId, + pub version: Version, +} + +impl Msg for LegacyMsgRegisterInterchainAccount { + type ValidationError = ValidationError; + type Raw = LegacyRawMsgRegisterInterchainAccount; + + fn route(&self) -> String { + crate::keys::ROUTER_KEY.to_string() + } + + fn type_url(&self) -> String { + TYPE_URL.to_string() + } +} + +impl Protobuf for LegacyMsgRegisterInterchainAccount {} + +impl TryFrom for LegacyMsgRegisterInterchainAccount { + type Error = Error; + + fn try_from(value: LegacyRawMsgRegisterInterchainAccount) -> Result { + Ok(LegacyMsgRegisterInterchainAccount { + owner: value.owner.parse().map_err(Error::owner)?, + connection_id: value + .connection_id + .parse() + .map_err(Error::invalid_connection_identifier)?, + version: value.version.into(), + }) + } +} + +impl From for LegacyRawMsgRegisterInterchainAccount { + fn from(value: LegacyMsgRegisterInterchainAccount) -> Self { + LegacyRawMsgRegisterInterchainAccount { + owner: value.owner.to_string(), + connection_id: value.connection_id.to_string(), + version: value.version.to_string(), } } } diff --git a/crates/relayer-types/src/applications/ics28_ccv/msgs/ccv_double_voting.rs b/crates/relayer-types/src/applications/ics28_ccv/msgs/ccv_double_voting.rs index a1ce4291d9..9f07f31539 100644 --- a/crates/relayer-types/src/applications/ics28_ccv/msgs/ccv_double_voting.rs +++ b/crates/relayer-types/src/applications/ics28_ccv/msgs/ccv_double_voting.rs @@ -9,6 +9,7 @@ use crate::signer::Signer; use crate::tx_msg::Msg; use super::error::Error; +use super::ConsumerId; pub const ICS_DOUBLE_VOTING_TYPE_URL: &str = "/interchain_security.ccv.provider.v1.MsgSubmitConsumerDoubleVoting"; @@ -18,6 +19,7 @@ pub struct MsgSubmitIcsConsumerDoubleVoting { pub submitter: Signer, pub duplicate_vote_evidence: DuplicateVoteEvidence, pub infraction_block_header: Header, + pub consumer_id: ConsumerId, } impl Msg for MsgSubmitIcsConsumerDoubleVoting { @@ -57,6 +59,7 @@ impl TryFrom for MsgSubmitIcsConsumerDoubleVoting { .map_err(|e| { Error::invalid_raw_double_voting(format!("cannot convert header: {e}")) })?, + consumer_id: ConsumerId::new(raw.consumer_id), }) } } @@ -67,6 +70,7 @@ impl From for RawIcsDoubleVoting { submitter: value.submitter.to_string(), duplicate_vote_evidence: Some(value.duplicate_vote_evidence.into()), infraction_block_header: Some(value.infraction_block_header.into()), + consumer_id: value.consumer_id.to_string(), } } } diff --git a/crates/relayer-types/src/applications/ics28_ccv/msgs/ccv_misbehaviour.rs b/crates/relayer-types/src/applications/ics28_ccv/msgs/ccv_misbehaviour.rs index 8b5c6c2750..67a7d20102 100644 --- a/crates/relayer-types/src/applications/ics28_ccv/msgs/ccv_misbehaviour.rs +++ b/crates/relayer-types/src/applications/ics28_ccv/msgs/ccv_misbehaviour.rs @@ -10,6 +10,7 @@ use crate::signer::Signer; use crate::tx_msg::Msg; use super::error::Error; +use super::ConsumerId; pub const ICS_MISBEHAVIOR_TYPE_URL: &str = "/interchain_security.ccv.provider.v1.MsgSubmitConsumerMisbehaviour"; @@ -18,6 +19,7 @@ pub const ICS_MISBEHAVIOR_TYPE_URL: &str = pub struct MsgSubmitIcsConsumerMisbehaviour { pub submitter: Signer, pub misbehaviour: Misbehaviour, + pub consumer_id: ConsumerId, } impl Msg for MsgSubmitIcsConsumerMisbehaviour { @@ -48,6 +50,7 @@ impl TryFrom for MsgSubmitIcsConsumerMisbehaviour { .map_err(|_e| { Error::invalid_raw_misbehaviour("cannot convert misbehaviour".into()) })?, + consumer_id: ConsumerId::new(raw.consumer_id), }) } } @@ -57,6 +60,7 @@ impl From for RawIcsMisbehaviour { RawIcsMisbehaviour { submitter: value.submitter.to_string(), misbehaviour: Some(value.misbehaviour.into()), + consumer_id: value.consumer_id.to_string(), } } } diff --git a/crates/relayer-types/src/applications/ics28_ccv/msgs/mod.rs b/crates/relayer-types/src/applications/ics28_ccv/msgs/mod.rs index df28e4a73a..6f992ae0f7 100644 --- a/crates/relayer-types/src/applications/ics28_ccv/msgs/mod.rs +++ b/crates/relayer-types/src/applications/ics28_ccv/msgs/mod.rs @@ -1,3 +1,52 @@ pub mod ccv_double_voting; pub mod ccv_misbehaviour; pub mod error; + +use std::convert::Infallible; + +use derive_more::Display; +use ibc_proto::interchain_security::ccv::provider::v1::Chain; +use serde::{Deserialize, Serialize}; + +use crate::core::ics24_host; +use crate::core::ics24_host::identifier::{ChainId, ClientId}; + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display, Serialize, Deserialize)] +pub struct ConsumerId(String); + +impl ConsumerId { + pub const fn new(id: String) -> Self { + Self(id) + } + + pub fn as_str(&self) -> &str { + &self.0 + } +} + +impl std::str::FromStr for ConsumerId { + type Err = Infallible; + + fn from_str(s: &str) -> Result { + Ok(Self(s.to_string())) + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct ConsumerChain { + pub chain_id: ChainId, + pub consumer_id: ConsumerId, + pub client_id: ClientId, +} + +impl TryFrom for ConsumerChain { + type Error = ics24_host::error::ValidationError; + + fn try_from(value: Chain) -> Result { + Ok(Self { + chain_id: ChainId::from_string(&value.chain_id), + consumer_id: ConsumerId::new(value.consumer_id), + client_id: value.client_id.parse()?, + }) + } +} diff --git a/crates/relayer-types/src/applications/ics29_fee/error.rs b/crates/relayer-types/src/applications/ics29_fee/error.rs index 79ba5e1bc2..f8cc66ae65 100644 --- a/crates/relayer-types/src/applications/ics29_fee/error.rs +++ b/crates/relayer-types/src/applications/ics29_fee/error.rs @@ -37,6 +37,10 @@ define_error! { EventAttributeNotFound { key: String } - | e | { format_args!("IBC event attribute not found for key: {}", e.key) }, + | e | { format_args!("IBC event attribute not found for key `{}`", e.key) }, + + EventAttributeInvalidUtf8 + { key: String } + | e | { format_args!("IBC event attribute value for key `{}` is not a valid UTF-8 string", e.key) }, } } diff --git a/crates/relayer-types/src/applications/ics29_fee/events.rs b/crates/relayer-types/src/applications/ics29_fee/events.rs index 34ea98c8c0..1db6ed9deb 100644 --- a/crates/relayer-types/src/applications/ics29_fee/events.rs +++ b/crates/relayer-types/src/applications/ics29_fee/events.rs @@ -26,12 +26,17 @@ fn find_value<'a>(key: &str, entries: &'a [abci::EventAttribute]) -> Result<&'a entries .iter() .find_map(|entry| { - if entry.key == key { - Some(entry.value.as_str()) + if entry.key_bytes() == key.as_bytes() { + Some( + entry + .value_str() + .map_err(|_| Error::event_attribute_invalid_utf8(key.to_owned())), + ) } else { None } }) + .transpose()? .ok_or_else(|| Error::event_attribute_not_found(key.to_owned())) } diff --git a/crates/relayer-types/src/applications/ics31_icq/events.rs b/crates/relayer-types/src/applications/ics31_icq/events.rs index 739fecedba..eea8511d15 100644 --- a/crates/relayer-types/src/applications/ics31_icq/events.rs +++ b/crates/relayer-types/src/applications/ics31_icq/events.rs @@ -1,4 +1,3 @@ -use std::collections::BTreeMap; use std::str::FromStr; use serde::{Deserialize, Serialize}; @@ -9,7 +8,7 @@ use crate::events::IbcEvent; use super::error::Error; -const EVENT_TYPE_PREFIX: &str = "query_request"; +pub const EVENT_TYPE_PREFIX: &str = "query_request"; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] pub struct CrossChainQueryPacket { @@ -23,25 +22,32 @@ pub struct CrossChainQueryPacket { pub request: String, } +impl From for IbcEvent { + fn from(packet: CrossChainQueryPacket) -> Self { + IbcEvent::CrossChainQueryPacket(packet) + } +} + fn find_value<'a>(key: &str, entries: &'a [abci::EventAttribute]) -> Result<&'a str, Error> { entries .iter() .find_map(|entry| { - if entry.key == key { - Some(entry.value.as_str()) + if entry.key_bytes() == key.as_bytes() { + Some(entry.value_str().map_err(|_| { + Error::event(format!( + "attribute value for key {key} is not a valid UTF-8 string" + )) + })) } else { None } }) + .transpose()? .ok_or_else(|| Error::event(format!("attribute not found for key: {key}"))) } fn new_attr(key: &str, value: &str) -> abci::EventAttribute { - abci::EventAttribute { - key: String::from(key), - value: String::from(value), - index: true, - } + abci::EventAttribute::from((key, value, true)) } impl From for abci::Event { @@ -93,66 +99,3 @@ impl<'a> TryFrom<&'a [abci::EventAttribute]> for CrossChainQueryPacket { }) } } - -fn fetch_first_element_from_events( - block_events: &BTreeMap>, - key: &str, -) -> Result { - let res = block_events - .get(key) - .ok_or_else(|| Error::event(format!("attribute not found for key: {key}")))? - .first() - .ok_or_else(|| { - Error::event(format!( - "element at position 0, of attribute with key `{key}`, not found" - )) - })?; - - Ok(res.clone()) -} - -impl CrossChainQueryPacket { - pub fn extract_query_event( - block_events: &BTreeMap>, - ) -> Result { - let chain_id_str = fetch_first_element_from_events( - block_events, - &format!("{}.{}", EVENT_TYPE_PREFIX, "chain_id"), - )?; - let connection_id_str = fetch_first_element_from_events( - block_events, - &format!("{}.{}", EVENT_TYPE_PREFIX, "connection_id"), - )?; - let query_type = fetch_first_element_from_events( - block_events, - &format!("{}.{}", EVENT_TYPE_PREFIX, "type"), - )?; - let height_str = fetch_first_element_from_events( - block_events, - &format!("{}.{}", EVENT_TYPE_PREFIX, "height"), - )?; - - Ok(IbcEvent::CrossChainQueryPacket(CrossChainQueryPacket { - module: fetch_first_element_from_events( - block_events, - &format!("{}.{}", EVENT_TYPE_PREFIX, "module"), - )?, - action: fetch_first_element_from_events( - block_events, - &format!("{}.{}", EVENT_TYPE_PREFIX, "action"), - )?, - query_id: fetch_first_element_from_events( - block_events, - &format!("{}.{}", EVENT_TYPE_PREFIX, "query_id"), - )?, - chain_id: ChainId::from_string(&chain_id_str), - connection_id: ConnectionId::from_str(&connection_id_str)?, - query_type, - height: Height::from_str(&height_str)?, - request: fetch_first_element_from_events( - block_events, - &format!("{}.{}", EVENT_TYPE_PREFIX, "request"), - )?, - })) - } -} diff --git a/crates/relayer-types/src/applications/ics31_icq/response.rs b/crates/relayer-types/src/applications/ics31_icq/response.rs index 98b45acf06..7a5c9bb638 100644 --- a/crates/relayer-types/src/applications/ics31_icq/response.rs +++ b/crates/relayer-types/src/applications/ics31_icq/response.rs @@ -52,11 +52,13 @@ impl CrossChainQueryResponse { pub fn try_to_any(&self, signer: Signer) -> Result { let mut encoded = vec![]; + let proof_ops = into_proof_ops(self.proof.clone()); + let msg_submit_cross_chain_query_result = MsgSubmitQueryResponse { chain_id: self.chain_id.to_string(), query_id: self.query_id.to_string(), result: self.result.clone(), - proof_ops: Some(into_proof_ops(self.proof.clone())), + proof_ops: Some(proof_ops), height: self.height, from_address: signer.as_ref().to_string(), }; diff --git a/crates/relayer-types/src/applications/transfer/error.rs b/crates/relayer-types/src/applications/transfer/error.rs index f0e52d946d..71c8d04b0f 100644 --- a/crates/relayer-types/src/applications/transfer/error.rs +++ b/crates/relayer-types/src/applications/transfer/error.rs @@ -4,7 +4,6 @@ use std::string::FromUtf8Error; use flex_error::{define_error, DisplayOnly, TraceError}; use subtle_encoding::Error as EncodingError; -use tendermint_proto::Error as TendermintProtoError; use uint::FromDecStrErr; use crate::core::ics04_channel::channel::Ordering; @@ -127,7 +126,7 @@ define_error! { | _ | { "no trace associated with specified hash" }, DecodeRawMsg - [ TraceError ] + [ TraceError ] | _ | { "error decoding raw msg" }, UnknownMsgType diff --git a/crates/relayer-types/src/applications/transfer/msgs/send.rs b/crates/relayer-types/src/applications/transfer/msgs/send.rs index 36e71dc66b..fcbb34a6bb 100644 --- a/crates/relayer-types/src/applications/transfer/msgs/send.rs +++ b/crates/relayer-types/src/applications/transfer/msgs/send.rs @@ -43,11 +43,11 @@ where type Error = Error; fn try_from(value: RawMsgSend) -> Result { - let amount: Vec> = value + let amount = value .amount .into_iter() - .map(Coin::try_from) - .collect::>, _>>()?; + .map(Coin::::try_from) + .collect::, _>>()?; Ok(MsgSend { from_address: value.from_address, to_address: value.to_address, diff --git a/crates/relayer-types/src/applications/transfer/packet.rs b/crates/relayer-types/src/applications/transfer/packet.rs index c467542fe4..7b13d49b1e 100644 --- a/crates/relayer-types/src/applications/transfer/packet.rs +++ b/crates/relayer-types/src/applications/transfer/packet.rs @@ -1,6 +1,4 @@ -use std::convert::TryFrom; use std::str::FromStr; -use std::string::{String, ToString}; use ibc_proto::ibc::applications::transfer::v2::FungibleTokenPacketData as RawPacketData; use serde::{Deserialize, Serialize}; diff --git a/crates/relayer-types/src/clients/ics07_tendermint/client_state.rs b/crates/relayer-types/src/clients/ics07_tendermint/client_state.rs index 9ca7c7e233..44888d8afa 100644 --- a/crates/relayer-types/src/clients/ics07_tendermint/client_state.rs +++ b/crates/relayer-types/src/clients/ics07_tendermint/client_state.rs @@ -1,4 +1,3 @@ -use std::convert::{TryFrom, TryInto}; use std::time::Duration; use prost::Message; @@ -13,7 +12,9 @@ use tendermint_light_client_verifier::options::Options; use crate::clients::ics07_tendermint::error::Error; use crate::clients::ics07_tendermint::header::Header as TmHeader; -use crate::core::ics02_client::client_state::ClientState as Ics2ClientState; +use crate::core::ics02_client::client_state::{ + ClientState as Ics2ClientState, UpgradableClientState, +}; 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; @@ -193,8 +194,6 @@ pub struct UpgradeOptions { } impl Ics2ClientState for ClientState { - type UpgradeOptions = UpgradeOptions; - fn chain_id(&self) -> ChainId { self.chain_id.clone() } @@ -211,6 +210,14 @@ impl Ics2ClientState for ClientState { self.frozen_height } + fn expired(&self, elapsed: Duration) -> bool { + elapsed > self.trusting_period + } +} + +impl UpgradableClientState for ClientState { + type UpgradeOptions = UpgradeOptions; + fn upgrade( &mut self, upgrade_height: Height, @@ -230,10 +237,6 @@ impl Ics2ClientState for ClientState { self.unbonding_period = upgrade_options.unbonding_period; self.chain_id = chain_id; } - - fn expired(&self, elapsed: Duration) -> bool { - elapsed > self.trusting_period - } } impl Protobuf for ClientState {} @@ -302,9 +305,9 @@ impl From for RawTmClientState { Self { chain_id: value.chain_id.to_string(), trust_level: Some(value.trust_threshold.into()), - trusting_period: Some(value.trusting_period.into()), - unbonding_period: Some(value.unbonding_period.into()), - max_clock_drift: Some(value.max_clock_drift.into()), + trusting_period: Some(value.trusting_period.try_into().unwrap()), + unbonding_period: Some(value.unbonding_period.try_into().unwrap()), + max_clock_drift: Some(value.max_clock_drift.try_into().unwrap()), frozen_height: Some(value.frozen_height.map(|height| height.into()).unwrap_or( RawHeight { revision_number: 0, @@ -660,36 +663,3 @@ mod tests { } } } - -#[cfg(any(test, feature = "mocks"))] -pub mod test_util { - use core::time::Duration; - - use tendermint::block::Header; - - use crate::clients::ics07_tendermint::client_state::{AllowUpdate, ClientState}; - use crate::core::ics02_client::height::Height; - use crate::core::ics24_host::identifier::ChainId; - - pub fn get_dummy_tendermint_client_state(tm_header: Header) -> ClientState { - ClientState::new( - ChainId::from(tm_header.chain_id.clone()), - Default::default(), - Duration::from_secs(64000), - Duration::from_secs(128000), - Duration::from_millis(3000), - Height::new( - ChainId::chain_version(tm_header.chain_id.as_str()), - u64::from(tm_header.height), - ) - .unwrap(), - Default::default(), - vec!["".to_string()], - AllowUpdate { - after_expiry: false, - after_misbehaviour: false, - }, - ) - .unwrap() - } -} diff --git a/crates/relayer-types/src/clients/ics07_tendermint/header.rs b/crates/relayer-types/src/clients/ics07_tendermint/header.rs index 57b99db1e9..412aa11630 100644 --- a/crates/relayer-types/src/clients/ics07_tendermint/header.rs +++ b/crates/relayer-types/src/clients/ics07_tendermint/header.rs @@ -146,68 +146,3 @@ impl From
for RawHeader { } } } - -#[cfg(any(test, feature = "mocks"))] -pub mod test_util { - - use subtle_encoding::hex; - use tendermint::block::signed_header::SignedHeader; - use tendermint::validator::Info as ValidatorInfo; - use tendermint::validator::Set as ValidatorSet; - use tendermint::PublicKey; - - 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 - } - - // TODO: This should be replaced with a ::default() or ::produce(). - // The implementation of this function comprises duplicate code (code borrowed from - // `tendermint-rs` for assembling a Header). - // See https://github.com/informalsystems/tendermint-rs/issues/381. - // - // The normal flow is: - // - get the (trusted) signed header and the `trusted_validator_set` at a `trusted_height` - // - get the `signed_header` and the `validator_set` at latest height - // - build the ics07 Header - // For testing purposes this function does: - // - get the `signed_header` from a .json file - // - create the `validator_set` with a single validator that is also the proposer - // - assume a `trusted_height` of 1 and no change in the validator set since height 1, - // i.e. `trusted_validator_set` = `validator_set` - 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" - )) - .unwrap(); - - // Build a set of validators. - // Below are test values inspired form `test_validator_set()` in tendermint-rs. - let v1: ValidatorInfo = ValidatorInfo::new( - PublicKey::from_raw_ed25519( - &hex::decode_upper( - "F349539C7E5EF7C49549B09C4BFC2335318AB0FE51FBFAA2433B4F13E816F4A7", - ) - .unwrap(), - ) - .unwrap(), - 281_815_u64.try_into().unwrap(), - ); - - let vs = ValidatorSet::new(vec![v1.clone()], Some(v1)); - - Header { - signed_header: shdr, - validator_set: vs.clone(), - trusted_height: Height::new(0, 1).unwrap(), - trusted_validator_set: vs, - } - } -} diff --git a/crates/relayer-types/src/core/ics02_client/client_state.rs b/crates/relayer-types/src/core/ics02_client/client_state.rs index 007bc19e17..b91baf62a1 100644 --- a/crates/relayer-types/src/core/ics02_client/client_state.rs +++ b/crates/relayer-types/src/core/ics02_client/client_state.rs @@ -1,5 +1,4 @@ use core::fmt::Debug; -use std::marker::{Send, Sync}; use std::time::Duration; use crate::core::ics02_client::client_type::ClientType; @@ -7,10 +6,7 @@ use crate::core::ics24_host::identifier::ChainId; use crate::Height; -pub trait ClientState: Clone + Debug + Send + Sync // Any: From, -{ - type UpgradeOptions; - +pub trait ClientState: Clone + Debug + Send + Sync { /// 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; @@ -32,6 +28,10 @@ pub trait ClientState: Clone + Debug + Send + Sync // Any: From, /// Check if the state is expired when `elapsed` time has passed since the latest consensus /// state timestamp fn expired(&self, elapsed: Duration) -> bool; +} + +pub trait UpgradableClientState: ClientState { + type UpgradeOptions; /// Helper function to verify the upgrade client procedure. /// Resets all fields except the blockchain-specific ones, diff --git a/crates/relayer-types/src/core/ics02_client/client_type.rs b/crates/relayer-types/src/core/ics02_client/client_type.rs index a35e44604d..0966d500b5 100644 --- a/crates/relayer-types/src/core/ics02_client/client_type.rs +++ b/crates/relayer-types/src/core/ics02_client/client_type.rs @@ -7,24 +7,15 @@ use super::error::Error; #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] pub enum ClientType { Tendermint = 1, - - #[cfg(any(test, feature = "mocks"))] - Mock = 9999, } impl ClientType { const TENDERMINT_STR: &'static str = "07-tendermint"; - #[cfg_attr(not(test), allow(dead_code))] - const MOCK_STR: &'static str = "9999-mock"; - /// Yields the identifier of this client type as a string pub fn as_str(&self) -> &'static str { match self { Self::Tendermint => Self::TENDERMINT_STR, - - #[cfg(any(test, feature = "mocks"))] - Self::Mock => Self::MOCK_STR, } } } @@ -42,9 +33,6 @@ impl core::str::FromStr for ClientType { match s { Self::TENDERMINT_STR => Ok(Self::Tendermint), - #[cfg(any(test, feature = "mocks"))] - Self::MOCK_STR => Ok(Self::Mock), - _ => Err(Error::unknown_client_type(s.to_string())), } } @@ -68,16 +56,6 @@ mod tests { } } - #[test] - fn parse_mock_client_type() { - let client_type = ClientType::from_str("9999-mock"); - - match client_type { - Ok(ClientType::Mock) => (), - _ => panic!("parse failed"), - } - } - #[test] fn parse_unknown_client_type() { let client_type_str = "some-random-client-type"; @@ -93,14 +71,6 @@ mod tests { } } - #[test] - fn parse_mock_as_string_result() { - let client_type = ClientType::Mock; - let type_string = client_type.as_str(); - let client_type_from_str = ClientType::from_str(type_string).unwrap(); - assert_eq!(client_type_from_str, client_type); - } - #[test] fn parse_tendermint_as_string_result() { let client_type = ClientType::Tendermint; diff --git a/crates/relayer-types/src/core/ics02_client/consensus_state.rs b/crates/relayer-types/src/core/ics02_client/consensus_state.rs index fc544f800d..196f486d7e 100644 --- a/crates/relayer-types/src/core/ics02_client/consensus_state.rs +++ b/crates/relayer-types/src/core/ics02_client/consensus_state.rs @@ -1,5 +1,4 @@ use core::fmt::Debug; -use core::marker::{Send, Sync}; use crate::core::ics02_client::client_type::ClientType; use crate::core::ics23_commitment::commitment::CommitmentRoot; diff --git a/crates/relayer-types/src/core/ics02_client/error.rs b/crates/relayer-types/src/core/ics02_client/error.rs index 094a883aa6..27316e2747 100644 --- a/crates/relayer-types/src/core/ics02_client/error.rs +++ b/crates/relayer-types/src/core/ics02_client/error.rs @@ -1,5 +1,4 @@ use flex_error::{define_error, TraceError}; -use tendermint_proto::Error as TendermintProtoError; use crate::core::ics02_client::client_type::ClientType; use crate::core::ics02_client::height::HeightError; @@ -109,14 +108,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 @@ -138,7 +137,7 @@ define_error! { | _ | { "invalid client identifier" }, InvalidRawHeader - [ TraceError ] + [ TraceError ] | _ | { "invalid raw header" }, MalformedHeader @@ -148,7 +147,7 @@ define_error! { | _ | { "missing raw header" }, DecodeRawMisbehaviour - [ TraceError ] + [ TraceError ] | _ | { "invalid raw misbehaviour" }, InvalidRawMisbehaviour @@ -254,19 +253,19 @@ define_error! { | e | { format_args!("the local consensus state could not be retrieved for height {}", e.height) }, InvalidConnectionEnd - [ TraceError] + [ TraceError] | _ | { "invalid connection end" }, InvalidChannelEnd - [ TraceError] + [ TraceError] | _ | { "invalid channel end" }, InvalidAnyClientState - [ TraceError] + [ TraceError] | _ | { "invalid any client state" }, InvalidAnyConsensusState - [ TraceError ] + [ TraceError ] | _ | { "invalid any client consensus state" }, Signer @@ -280,5 +279,12 @@ define_error! { ClientSpecific { description: String } | e | { format_args!("client specific error: {0}", e.description) }, + + MalformedEventAttributeKey + | _ | { format_args!("event attribute key is not valid UTF-8") }, + + MalformedEventAttributeValue + { key: String } + | e | { format_args!("event attribute value for key {} is not valid UTF-8", e.key) }, } } diff --git a/crates/relayer-types/src/core/ics02_client/events.rs b/crates/relayer-types/src/core/ics02_client/events.rs index 3abe9b7b8d..da295833ef 100644 --- a/crates/relayer-types/src/core/ics02_client/events.rs +++ b/crates/relayer-types/src/core/ics02_client/events.rs @@ -1,9 +1,10 @@ //! Types for the IBC events emitted from Tendermint Websocket by the client module. -use serde_derive::{Deserialize, Serialize}; use std::fmt::{Display, Error as FmtError, Formatter}; + +use ibc_proto::Protobuf; +use serde_derive::{Deserialize, Serialize}; use tendermint::abci; -use tendermint_proto::Protobuf; use super::header::AnyHeader; use crate::core::ics02_client::client_type::ClientType; diff --git a/crates/relayer-types/src/core/ics02_client/msgs/create_client.rs b/crates/relayer-types/src/core/ics02_client/msgs/create_client.rs index 078bce2d31..1c760f644f 100644 --- a/crates/relayer-types/src/core/ics02_client/msgs/create_client.rs +++ b/crates/relayer-types/src/core/ics02_client/msgs/create_client.rs @@ -72,38 +72,3 @@ impl From for RawMsgCreateClient { } } } - -#[cfg(test)] -mod tests { - - use test_log::test; - - use ibc_proto::ibc::core::client::v1::MsgCreateClient as RawMsgCreateClient; - - use crate::clients::ics07_tendermint::client_state::test_util::get_dummy_tendermint_client_state; - use crate::clients::ics07_tendermint::consensus_state::ConsensusState as TmConsensusState; - use crate::clients::ics07_tendermint::header::test_util::get_dummy_tendermint_header; - use crate::core::ics02_client::msgs::create_client::MsgCreateClient; - use crate::test_utils::get_dummy_account_id; - - #[test] - fn msg_create_client_serialization() { - let signer = get_dummy_account_id(); - - let tm_header = get_dummy_tendermint_header(); - let tm_client_state = get_dummy_tendermint_client_state(tm_header.clone()).into(); - - let msg = MsgCreateClient::new( - tm_client_state, - TmConsensusState::from(tm_header).into(), - signer, - ) - .unwrap(); - - let raw = RawMsgCreateClient::from(msg.clone()); - let msg_back = MsgCreateClient::try_from(raw.clone()).unwrap(); - let raw_back = RawMsgCreateClient::from(msg_back.clone()); - assert_eq!(msg, msg_back); - assert_eq!(raw, raw_back); - } -} diff --git a/crates/relayer-types/src/core/ics02_client/msgs/update_client.rs b/crates/relayer-types/src/core/ics02_client/msgs/update_client.rs index e5966b7b7c..a0de417d6a 100644 --- a/crates/relayer-types/src/core/ics02_client/msgs/update_client.rs +++ b/crates/relayer-types/src/core/ics02_client/msgs/update_client.rs @@ -69,31 +69,3 @@ impl From for RawMsgUpdateClient { } } } - -#[cfg(test)] -mod tests { - - use test_log::test; - - use ibc_proto::ibc::core::client::v1::MsgUpdateClient as RawMsgUpdateClient; - - use crate::clients::ics07_tendermint::header::test_util::get_dummy_ics07_header; - use crate::core::ics02_client::msgs::MsgUpdateClient; - use crate::core::ics24_host::identifier::ClientId; - use crate::test_utils::get_dummy_account_id; - - #[test] - fn msg_update_client_serialization() { - let client_id: ClientId = "tendermint".parse().unwrap(); - let signer = get_dummy_account_id(); - - let header = get_dummy_ics07_header(); - - let msg = MsgUpdateClient::new(client_id, header.into(), signer); - let raw = RawMsgUpdateClient::from(msg.clone()); - let msg_back = MsgUpdateClient::try_from(raw.clone()).unwrap(); - let raw_back = RawMsgUpdateClient::from(msg_back.clone()); - assert_eq!(msg, msg_back); - assert_eq!(raw, raw_back); - } -} diff --git a/crates/relayer-types/src/core/ics02_client/msgs/upgrade_client.rs b/crates/relayer-types/src/core/ics02_client/msgs/upgrade_client.rs index 20fcf6ccc3..5338eda56b 100644 --- a/crates/relayer-types/src/core/ics02_client/msgs/upgrade_client.rs +++ b/crates/relayer-types/src/core/ics02_client/msgs/upgrade_client.rs @@ -112,83 +112,3 @@ impl TryFrom for MsgUpgradeClient { }) } } - -#[cfg(test)] -pub mod test_util { - use ibc_proto::ibc::core::client::v1::MsgUpgradeClient as RawMsgUpgradeClient; - - use crate::{ - core::{ics02_client::height::Height, ics24_host::identifier::ClientId}, - mock::{ - client_state::MockClientState, consensus_state::MockConsensusState, header::MockHeader, - }, - test_utils::{get_dummy_bech32_account, get_dummy_proof}, - }; - - use super::MsgUpgradeClient; - - /// Extends the implementation with additional helper methods. - impl MsgUpgradeClient { - /// Setter for `client_id`. Amenable to chaining, since it consumes the input message. - pub fn with_client_id(self, client_id: ClientId) -> Self { - MsgUpgradeClient { client_id, ..self } - } - } - - /// Returns a dummy `RawMsgUpgradeClient`, for testing only! - pub fn get_dummy_raw_msg_upgrade_client(height: Height) -> RawMsgUpgradeClient { - RawMsgUpgradeClient { - client_id: "tendermint".parse().unwrap(), - client_state: Some(MockClientState::new(MockHeader::new(height)).into()), - consensus_state: Some(MockConsensusState::new(MockHeader::new(height)).into()), - proof_upgrade_client: get_dummy_proof(), - proof_upgrade_consensus_state: get_dummy_proof(), - signer: get_dummy_bech32_account(), - } - } -} - -#[cfg(test)] -mod tests { - - use ibc_proto::ibc::core::client::v1::MsgUpgradeClient as RawMsgUpgradeClient; - - use crate::{ - core::{ - ics02_client::{height::Height, msgs::upgrade_client::MsgUpgradeClient}, - ics23_commitment::commitment::test_util::get_dummy_merkle_proof, - ics24_host::identifier::ClientId, - }, - mock::{ - client_state::MockClientState, consensus_state::MockConsensusState, header::MockHeader, - }, - test_utils::get_dummy_account_id, - }; - - #[test] - fn msg_upgrade_client_serialization() { - let client_id: ClientId = "tendermint".parse().unwrap(); - let signer = get_dummy_account_id(); - - let height = Height::new(1, 1).unwrap(); - - let client_state = MockClientState::new(MockHeader::new(height)); - let consensus_state = MockConsensusState::new(MockHeader::new(height)); - - let proof = get_dummy_merkle_proof(); - - let msg = MsgUpgradeClient::new( - client_id, - client_state.into(), - consensus_state.into(), - proof.clone(), - proof, - signer, - ); - let raw: RawMsgUpgradeClient = RawMsgUpgradeClient::from(msg.clone()); - let msg_back = MsgUpgradeClient::try_from(raw.clone()).unwrap(); - let raw_back: RawMsgUpgradeClient = RawMsgUpgradeClient::from(msg_back.clone()); - assert_eq!(msg, msg_back); - assert_eq!(raw, raw_back); - } -} diff --git a/crates/relayer-types/src/core/ics02_client/trust_threshold.rs b/crates/relayer-types/src/core/ics02_client/trust_threshold.rs index 8f249b820f..96795cea2d 100644 --- a/crates/relayer-types/src/core/ics02_client/trust_threshold.rs +++ b/crates/relayer-types/src/core/ics02_client/trust_threshold.rs @@ -2,7 +2,6 @@ //! represented as a fraction with valid values in the //! range `[0, 1)`. -use std::convert::TryFrom; use std::fmt::{Display, Error as FmtError, Formatter}; use std::str::FromStr; @@ -218,7 +217,7 @@ where struct StringOrInt; - impl<'de> Visitor<'de> for StringOrInt { + impl Visitor<'_> for StringOrInt { type Value = u64; fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { diff --git a/crates/relayer-types/src/core/ics03_connection/connection.rs b/crates/relayer-types/src/core/ics03_connection/connection.rs index d240eaf905..d9c3ce9c60 100644 --- a/crates/relayer-types/src/core/ics03_connection/connection.rs +++ b/crates/relayer-types/src/core/ics03_connection/connection.rs @@ -1,9 +1,6 @@ +use std::fmt::{Display, Error as FmtError, Formatter}; use std::str::FromStr; use std::time::Duration; -use std::{ - fmt::{Display, Error as FmtError, Formatter}, - u64, -}; use ibc_proto::Protobuf; use serde::{Deserialize, Serialize}; @@ -388,6 +385,6 @@ impl TryFrom for State { impl From for i32 { fn from(value: State) -> Self { - value.into() + value as i32 } } diff --git a/crates/relayer-types/src/core/ics03_connection/error.rs b/crates/relayer-types/src/core/ics03_connection/error.rs index 068b3ee30a..00b4529f8b 100644 --- a/crates/relayer-types/src/core/ics03_connection/error.rs +++ b/crates/relayer-types/src/core/ics03_connection/error.rs @@ -157,5 +157,12 @@ define_error! { ImplementationSpecific | _ | { "implementation specific error" }, + + MalformedEventAttributeKey + | _ | { format_args!("event attribute key is not valid UTF-8") }, + + MalformedEventAttributeValue + { key: String } + | e | { format_args!("event attribute value for key {} is not valid UTF-8", e.key) }, } } diff --git a/crates/relayer-types/src/core/ics03_connection/msgs/conn_open_try.rs b/crates/relayer-types/src/core/ics03_connection/msgs/conn_open_try.rs index 8cebee431b..bd7ce58751 100644 --- a/crates/relayer-types/src/core/ics03_connection/msgs/conn_open_try.rs +++ b/crates/relayer-types/src/core/ics03_connection/msgs/conn_open_try.rs @@ -1,8 +1,4 @@ -use std::{ - convert::{TryFrom, TryInto}, - str::FromStr, - time::Duration, -}; +use std::{str::FromStr, time::Duration}; use ibc_proto::google::protobuf::Any; use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenTry as RawMsgConnectionOpenTry; diff --git a/crates/relayer-types/src/core/ics04_channel/channel.rs b/crates/relayer-types/src/core/ics04_channel/channel.rs index 0205e2998a..722ed1f8cd 100644 --- a/crates/relayer-types/src/core/ics04_channel/channel.rs +++ b/crates/relayer-types/src/core/ics04_channel/channel.rs @@ -11,6 +11,7 @@ use ibc_proto::ibc::core::channel::v1::{ IdentifiedChannel as RawIdentifiedChannel, }; +use crate::core::ics04_channel::packet::Sequence; use crate::core::ics04_channel::{error::Error, version::Version}; use crate::core::ics24_host::identifier::{ChannelId, ConnectionId, PortId}; @@ -43,6 +44,7 @@ impl TryFrom for IdentifiedChannelEnd { counterparty: value.counterparty, connection_hops: value.connection_hops, version: value.version, + upgrade_sequence: value.upgrade_sequence, }; Ok(IdentifiedChannelEnd { @@ -56,7 +58,7 @@ impl TryFrom for IdentifiedChannelEnd { impl From for RawIdentifiedChannel { fn from(value: IdentifiedChannelEnd) -> Self { RawIdentifiedChannel { - state: value.channel_end.state as i32, + state: value.channel_end.state.as_i32(), ordering: value.channel_end.ordering as i32, counterparty: Some(value.channel_end.counterparty().clone().into()), connection_hops: value @@ -68,6 +70,7 @@ impl From for RawIdentifiedChannel { version: value.channel_end.version.to_string(), port_id: value.port_id.to_string(), channel_id: value.channel_id.to_string(), + upgrade_sequence: value.channel_end.upgrade_sequence.into(), } } } @@ -79,14 +82,15 @@ pub struct ChannelEnd { pub remote: Counterparty, pub connection_hops: Vec, pub version: Version, + pub upgrade_sequence: Sequence, } impl Display for ChannelEnd { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { write!( f, - "ChannelEnd {{ state: {}, ordering: {}, remote: {}, connection_hops: {}, version: {} }}", - self.state, self.ordering, self.remote, PrettySlice(&self.connection_hops), self.version + "ChannelEnd {{ state: {}, ordering: {}, remote: {}, connection_hops: {}, version: {}, upgrade_sequence: {} }}", + self.state, self.ordering, self.remote, PrettySlice(&self.connection_hops), self.version, self.upgrade_sequence ) } } @@ -99,6 +103,7 @@ impl Default for ChannelEnd { remote: Counterparty::default(), connection_hops: Vec::new(), version: Version::default(), + upgrade_sequence: Sequence::from(0), // The value of 0 indicates the channel has never been upgraded } } } @@ -139,6 +144,7 @@ impl TryFrom for ChannelEnd { remote, connection_hops, version, + value.upgrade_sequence.into(), )) } } @@ -146,7 +152,7 @@ impl TryFrom for ChannelEnd { impl From for RawChannel { fn from(value: ChannelEnd) -> Self { RawChannel { - state: value.state as i32, + state: value.state.as_i32(), ordering: value.ordering as i32, counterparty: Some(value.counterparty().clone().into()), connection_hops: value @@ -155,6 +161,7 @@ impl From for RawChannel { .map(|v| v.as_str().to_string()) .collect(), version: value.version.to_string(), + upgrade_sequence: value.upgrade_sequence.into(), } } } @@ -167,6 +174,7 @@ impl ChannelEnd { remote: Counterparty, connection_hops: Vec, version: Version, + upgrade_sequence: Sequence, ) -> Self { Self { state, @@ -174,6 +182,7 @@ impl ChannelEnd { remote, connection_hops, version, + upgrade_sequence, } } @@ -190,9 +199,11 @@ impl ChannelEnd { self.remote.channel_id = Some(c); } - /// Returns `true` if this `ChannelEnd` is in state [`State::Open`]. + /// Returns `true` if this `ChannelEnd` is in state [`State::Open`] + /// [`State::Open(UpgradeState::Upgrading)`] is only used in the channel upgrade + /// handshake so this method matches with [`State::Open(UpgradeState::NotUpgrading)`]. pub fn is_open(&self) -> bool { - self.state_matches(&State::Open) + self.state_matches(&State::Open(UpgradeState::NotUpgrading)) } pub fn state(&self) -> &State { @@ -227,25 +238,35 @@ impl ChannelEnd { /// Helper function to compare the state of this end with another state. pub fn state_matches(&self, other: &State) -> bool { - self.state.eq(other) + self.state() == other } /// Helper function to compare the order of this end with another order. pub fn order_matches(&self, other: &Ordering) -> bool { - self.ordering.eq(other) + self.ordering() == other } - #[allow(clippy::ptr_arg)] pub fn connection_hops_matches(&self, other: &Vec) -> bool { - self.connection_hops.eq(other) + self.connection_hops() == other } pub fn counterparty_matches(&self, other: &Counterparty) -> bool { - self.counterparty().eq(other) + self.counterparty() == other } pub fn version_matches(&self, other: &Version) -> bool { - self.version().eq(other) + self.version() == other + } + + /// Returns whether or not the channel with this state is + /// being upgraded. + pub fn is_upgrading(&self) -> bool { + use State::*; + + matches!( + self.state, + Open(UpgradeState::Upgrading) | Flushing | FlushComplete + ) } } @@ -371,13 +392,61 @@ impl FromStr for Ordering { } } +/// This enum is used to differentiate if a channel is being upgraded when +/// a `UpgradeInitChannel` or a `UpgradeOpenChannel` is received. +/// See `handshake_step` method in `crates/relayer/src/channel.rs`. #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub enum UpgradeState { + Upgrading, + NotUpgrading, +} + +/// The possible state variants that a channel can exhibit. +/// +/// These are encoded with integer discriminants so that there is +/// an easy way to compare channel states against one another. More +/// explicitly, this is an attempt to capture the lifecycle of a +/// channel, beginning from the `Uninitialized` state, through the +/// `Open` state, before finally being `Closed`. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize)] pub enum State { - Uninitialized = 0, - Init = 1, - TryOpen = 2, - Open = 3, - Closed = 4, + /// Default state + Uninitialized, + /// A channel has just started the opening handshake. + Init, + /// A channel has acknowledged the handshake step on the counterparty chain. + TryOpen, + /// A channel has completed the handshake step. Open channels are ready to + /// send and receive packets. + /// During some steps of channel upgrades, the state is still in Open. The + /// `UpgradeState` is used to differentiate these states during the upgrade + /// handshake. + /// + Open(UpgradeState), + /// A channel has been closed and can no longer be used to send or receive + /// packets. + Closed, + /// A channel has just accepted the upgrade handshake attempt and is flushing in-flight packets. + Flushing, + /// A channel has just completed flushing any in-flight packets. + FlushComplete, +} + +impl Serialize for State { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match self { + Self::Uninitialized => serializer.serialize_str("Uninitialized"), + Self::Init => serializer.serialize_str("Init"), + Self::TryOpen => serializer.serialize_str("TryOpen"), + Self::Open(_) => serializer.serialize_str("Open"), + Self::Closed => serializer.serialize_str("Closed"), + Self::Flushing => serializer.serialize_str("Flushing"), + Self::FlushComplete => serializer.serialize_str("FlushComplete"), + } + } } impl State { @@ -387,8 +456,10 @@ impl State { Self::Uninitialized => "UNINITIALIZED", Self::Init => "INIT", Self::TryOpen => "TRYOPEN", - Self::Open => "OPEN", + Self::Open(_) => "OPEN", Self::Closed => "CLOSED", + Self::Flushing => "FLUSHING", + Self::FlushComplete => "FLUSHCOMPLETE", } } @@ -398,15 +469,30 @@ impl State { 0 => Ok(Self::Uninitialized), 1 => Ok(Self::Init), 2 => Ok(Self::TryOpen), - 3 => Ok(Self::Open), + 3 => Ok(Self::Open(UpgradeState::NotUpgrading)), 4 => Ok(Self::Closed), + 5 => Ok(Self::Flushing), + 6 => Ok(Self::FlushComplete), _ => Err(Error::unknown_state(s)), } } + // Parses the State out from a i32. + pub fn as_i32(&self) -> i32 { + match self { + State::Uninitialized => 0, + State::Init => 1, + State::TryOpen => 2, + State::Open(_) => 3, + State::Closed => 4, + State::Flushing => 5, + State::FlushComplete => 6, + } + } + /// Returns whether or not this channel state is `Open`. pub fn is_open(self) -> bool { - self == State::Open + self == State::Open(UpgradeState::NotUpgrading) } /// Returns whether or not this channel state is `Closed`. @@ -416,6 +502,7 @@ impl State { /// Returns whether or not the channel with this state /// has progressed less or the same than the argument. + /// This only takes into account the open channel handshake. /// /// # Example /// ```rust,ignore @@ -424,7 +511,16 @@ impl State { /// assert!(!State::Closed.less_or_equal_progress(State::Open)); /// ``` pub fn less_or_equal_progress(self, other: Self) -> bool { - self as u32 <= other as u32 + use State::*; + + match self { + Uninitialized => true, + + Init => !matches!(other, Uninitialized), + TryOpen => !matches!(other, Uninitialized | Init), + Open(UpgradeState::NotUpgrading) => !matches!(other, Uninitialized | Init | TryOpen), + _ => false, + } } } @@ -459,6 +555,7 @@ pub mod test_util { counterparty: Some(get_dummy_raw_counterparty()), connection_hops: vec![ConnectionId::default().to_string()], version: "ics20".to_string(), // The version is not validated. + upgrade_sequence: 0, // The value of 0 indicates the channel has never been upgraded } } } @@ -599,4 +696,119 @@ mod tests { } } } + + #[test] + fn less_or_equal_progress_uninitialized() { + use crate::core::ics04_channel::channel::State; + use crate::core::ics04_channel::channel::UpgradeState; + + let higher_or_equal_states = vec![ + State::Uninitialized, + State::Init, + State::TryOpen, + State::Open(UpgradeState::NotUpgrading), + State::Open(UpgradeState::Upgrading), + State::Closed, + State::Flushing, + State::FlushComplete, + ]; + for state in higher_or_equal_states { + assert!(State::Uninitialized.less_or_equal_progress(state)) + } + } + + #[test] + fn less_or_equal_progress_init() { + use crate::core::ics04_channel::channel::State; + use crate::core::ics04_channel::channel::UpgradeState; + + let lower_states = vec![State::Uninitialized]; + let higher_or_equal_states = vec![ + State::Init, + State::TryOpen, + State::Open(UpgradeState::NotUpgrading), + State::Open(UpgradeState::Upgrading), + State::Closed, + State::Flushing, + State::FlushComplete, + ]; + for state in lower_states { + assert!(!State::Init.less_or_equal_progress(state)); + } + for state in higher_or_equal_states { + assert!(State::Init.less_or_equal_progress(state)) + } + } + + #[test] + fn less_or_equal_progress_tryopen() { + use crate::core::ics04_channel::channel::State; + use crate::core::ics04_channel::channel::UpgradeState; + + let lower_states = vec![State::Uninitialized, State::Init]; + let higher_or_equal_states = vec![ + State::TryOpen, + State::Open(UpgradeState::NotUpgrading), + State::Open(UpgradeState::Upgrading), + State::Closed, + State::Flushing, + State::FlushComplete, + ]; + for state in lower_states { + assert!(!State::TryOpen.less_or_equal_progress(state)); + } + for state in higher_or_equal_states { + assert!(State::TryOpen.less_or_equal_progress(state)) + } + } + + #[test] + fn less_or_equal_progress_open_not_upgrading() { + use crate::core::ics04_channel::channel::State; + use crate::core::ics04_channel::channel::UpgradeState; + + let lower_states = vec![State::Uninitialized, State::Init, State::TryOpen]; + let higher_or_equal_states = vec![ + State::Open(UpgradeState::NotUpgrading), + State::Open(UpgradeState::Upgrading), + State::Closed, + State::Flushing, + State::FlushComplete, + ]; + for state in lower_states { + assert!(!State::Open(UpgradeState::NotUpgrading).less_or_equal_progress(state)); + } + for state in higher_or_equal_states { + assert!(State::Open(UpgradeState::NotUpgrading).less_or_equal_progress(state)) + } + } + + #[test] + fn less_or_equal_progress_upgrading_states() { + use crate::core::ics04_channel::channel::State; + use crate::core::ics04_channel::channel::UpgradeState; + + let states = [ + State::Uninitialized, + State::Init, + State::TryOpen, + State::Open(UpgradeState::NotUpgrading), + State::Open(UpgradeState::Upgrading), + State::Closed, + State::Flushing, + State::FlushComplete, + ]; + + let upgrading_states = vec![ + State::Open(UpgradeState::Upgrading), + State::Closed, + State::Flushing, + State::FlushComplete, + ]; + for upgrade_state in upgrading_states { + for state in states.iter() { + assert!(!upgrade_state.less_or_equal_progress(*state)); + } + } + } } diff --git a/crates/relayer-types/src/core/ics04_channel/error.rs b/crates/relayer-types/src/core/ics04_channel/error.rs index 817f0337f8..3dd6126749 100644 --- a/crates/relayer-types/src/core/ics04_channel/error.rs +++ b/crates/relayer-types/src/core/ics04_channel/error.rs @@ -12,6 +12,7 @@ use crate::timestamp::Timestamp; use crate::Height; use flex_error::{define_error, TraceError}; +use itertools::Itertools; use tendermint_proto::Error as TendermintError; define_error! { @@ -25,6 +26,14 @@ define_error! { { state: i32 } | e | { format_args!("channel state unknown: {}", e.state) }, + UnknownFlushStatus + { state: i32 } + | e | { format_args!("flush status unknown: {}", e.state) }, + + UnknownFlushStatusType + { type_id: String } + | e | { format_args!("flush status unknown: {}", e.type_id) }, + Identifier [ ValidationError ] | _ | { "identifier error" }, @@ -53,6 +62,11 @@ define_error! { [ TraceError ] | _ | { "invalid version" }, + InvalidFlushStatus + { flush_status: i32 } + | e | { format_args!("invalid flush_status value: {}", e.flush_status) }, + + Signer [ SignerError ] | _ | { "invalid signer address" }, @@ -81,6 +95,10 @@ define_error! { InvalidTimeoutHeight | _ | { "invalid timeout height for the packet" }, + InvalidTimeoutTimestamp + [ crate::timestamp::ParseTimestampError ] + | _ | { "invalid timeout timestamp" }, + InvalidPacket | _ | { "invalid packet" }, @@ -94,11 +112,32 @@ define_error! { | _ | { "missing counterparty" }, NoCommonVersion - | _ | { "no commong version" }, + | _ | { "no common version" }, MissingChannel | _ | { "missing channel end" }, + MissingUpgradeTimeout + | _ | { "missing upgrade timeout, either a height or a timestamp must be set" }, + + MissingUpgrade + | _ | { "missing upgrade" }, + + MissingUpgradeFields + | _ | { "missing upgrade fields" }, + + MissingUpgradeErrorReceipt + | _ | { "missing upgrade error receipt" }, + + MissingProposedUpgradeChannel + | _ | { "missing proposed upgrade channel" }, + + MissingProofHeight + | _ | { "missing proof height" }, + + InvalidProofHeight + | _ | { "invalid proof height" }, + InvalidVersionLengthConnection | _ | { "single version must be negotiated on connection before opening channel" }, @@ -191,6 +230,22 @@ define_error! { e.given_sequence, e.next_sequence) }, + InvalidPacketData + { + data: String, + } + | e | { + format_args!("Invalid packet data, not a valid hex-encoded string: {}", e.data) + }, + + InvalidPacketAck + { + ack: String, + } + | e | { + format_args!("Invalid packet ack, not a valid hex-encoded string: {}", e.ack) + }, + LowPacketHeight { chain_height: Height, @@ -343,7 +398,25 @@ define_error! { AbciConversionFailed { abci_event: String } - | e | { format_args!("Failed to convert abci event to IbcEvent: {}", e.abci_event)} + | e | { format_args!("Failed to convert abci event to IbcEvent: {}", e.abci_event)}, + + ParseConnectionHopsVector + { failures: Vec<(String, ValidationError)> } + | e | { + let failures = e.failures + .iter() + .map(|(s, e)| format!("\"{}\": {}", s, e)) + .join(", "); + + format!("error parsing a vector of ConnectionId: {}", failures) + }, + + MalformedEventAttributeKey + | _ | { format_args!("event attribute key is not valid UTF-8") }, + + MalformedEventAttributeValue + { key: String } + | e | { format_args!("event attribute value for key {} is not valid UTF-8", e.key) }, } } diff --git a/crates/relayer-types/src/core/ics04_channel/events.rs b/crates/relayer-types/src/core/ics04_channel/events.rs index 3f6d7c4382..85e2493fe5 100644 --- a/crates/relayer-types/src/core/ics04_channel/events.rs +++ b/crates/relayer-types/src/core/ics04_channel/events.rs @@ -1,15 +1,18 @@ //! Types for the IBC events emitted from Tendermint Websocket by the channels module. -use serde_derive::{Deserialize, Serialize}; use std::fmt::{Display, Error as FmtError, Formatter}; use std::str; + +use serde_derive::{Deserialize, Serialize}; use tendermint::abci; +use crate::core::ics02_client::height::Height; use crate::core::ics04_channel::error::Error; use crate::core::ics04_channel::packet::Packet; +use crate::core::ics04_channel::packet::Sequence; use crate::core::ics24_host::identifier::{ChannelId, ConnectionId, PortId}; use crate::events::{Error as EventError, IbcEvent, IbcEventType}; - +use crate::timestamp::Timestamp; use crate::utils::pretty::PrettySlice; /// Channel event attribute keys @@ -21,14 +24,20 @@ pub const COUNTERPARTY_PORT_ID_ATTRIBUTE_KEY: &str = "counterparty_port_id"; /// Packet event attribute keys pub const PKT_SEQ_ATTRIBUTE_KEY: &str = "packet_sequence"; -pub const PKT_DATA_ATTRIBUTE_KEY: &str = "packet_data"; +pub const PKT_DATA_ATTRIBUTE_KEY: &str = "packet_data_hex"; pub const PKT_SRC_PORT_ATTRIBUTE_KEY: &str = "packet_src_port"; pub const PKT_SRC_CHANNEL_ATTRIBUTE_KEY: &str = "packet_src_channel"; pub const PKT_DST_PORT_ATTRIBUTE_KEY: &str = "packet_dst_port"; pub const PKT_DST_CHANNEL_ATTRIBUTE_KEY: &str = "packet_dst_channel"; pub const PKT_TIMEOUT_HEIGHT_ATTRIBUTE_KEY: &str = "packet_timeout_height"; pub const PKT_TIMEOUT_TIMESTAMP_ATTRIBUTE_KEY: &str = "packet_timeout_timestamp"; -pub const PKT_ACK_ATTRIBUTE_KEY: &str = "packet_ack"; +pub const PKT_ACK_ATTRIBUTE_KEY: &str = "packet_ack_hex"; + +/// Channel upgrade attribute keys +pub const UPGRADE_SEQUENCE: &str = "upgrade_sequence"; +pub const UPGRADE_TIMEOUT_HEIGHT: &str = "timeout_height"; +pub const UPGRADE_TIMEOUT_TIMESTAMP: &str = "timeout_timestamp"; +pub const UPGRADE_ERROR_RECEIPT: &str = "error_receipt"; #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)] pub struct Attributes { @@ -85,10 +94,71 @@ impl From for Vec { } } +/// The attributes emitted by upon receiving a channel upgrade init message. +#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)] +pub struct UpgradeAttributes { + pub port_id: PortId, + pub channel_id: ChannelId, + pub counterparty_port_id: PortId, + pub counterparty_channel_id: Option, + pub upgrade_sequence: Sequence, + pub upgrade_timeout_height: Option, + pub upgrade_timeout_timestamp: Option, + pub error_receipt: Option, +} + +impl UpgradeAttributes { + pub fn port_id(&self) -> &PortId { + &self.port_id + } + pub fn channel_id(&self) -> &ChannelId { + &self.channel_id + } +} + +impl Display for UpgradeAttributes { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { + if let Some(counterparty_channel_id) = &self.counterparty_channel_id { + write!(f, "UpgradeAttributes {{ port_id: {}, channel_id: {}, counterparty_port_id: {}, counterparty_channel_id: {counterparty_channel_id}, upgrade_connection_hops: [", self.port_id, self.channel_id, self.counterparty_port_id)?; + } else { + write!(f, "UpgradeAttributes {{ port_id: {}, channel_id: {}, counterparty_port_id: {}, counterparty_channel_id: None, upgrade_connection_hops: [", self.port_id, self.channel_id, self.counterparty_port_id)?; + } + write!(f, "], upgrade_sequence: {} }}", self.upgrade_sequence) + } +} pub trait EventType { fn event_type() -> IbcEventType; } +/// Convert channel upgrade attributes to Tendermint ABCI tags +impl From for Vec { + fn from(a: UpgradeAttributes) -> Self { + let mut attributes: Vec = vec![]; + + let port_id: abci::EventAttribute = (PORT_ID_ATTRIBUTE_KEY, a.port_id.as_str()).into(); + attributes.push(port_id); + + let channel_id: abci::EventAttribute = + (CHANNEL_ID_ATTRIBUTE_KEY, a.channel_id.as_str()).into(); + attributes.push(channel_id); + + let counterparty_port_id = ( + COUNTERPARTY_PORT_ID_ATTRIBUTE_KEY, + a.counterparty_port_id.as_str(), + ) + .into(); + + attributes.push(counterparty_port_id); + let channel_id = (COUNTERPARTY_CHANNEL_ID_ATTRIBUTE_KEY, a.channel_id.as_str()).into(); + attributes.push(channel_id); + + let upgrade_sequence = (UPGRADE_SEQUENCE, a.upgrade_sequence.to_string().as_str()).into(); + attributes.push(upgrade_sequence); + + attributes + } +} + #[derive(Clone, Debug, PartialEq, Eq, Serialize)] pub struct OpenInit { pub port_id: PortId, @@ -431,6 +501,663 @@ impl EventType for CloseConfirm { } } +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] +pub struct UpgradeInit { + pub port_id: PortId, + pub channel_id: ChannelId, + pub counterparty_port_id: PortId, + pub counterparty_channel_id: Option, + pub upgrade_sequence: Sequence, +} + +impl Display for UpgradeInit { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { + if let Some(counterparty_channel_id) = &self.counterparty_channel_id { + write!(f, "UpgradeAttributes {{ port_id: {}, channel_id: {}, counterparty_port_id: {}, counterparty_channel_id: {counterparty_channel_id}, upgrade_connection_hops: [", self.port_id, self.channel_id, self.counterparty_port_id)?; + } else { + write!(f, "UpgradeAttributes {{ port_id: {}, channel_id: {}, counterparty_port_id: {}, counterparty_channel_id: None, upgrade_connection_hops: [", self.port_id, self.channel_id, self.counterparty_port_id)?; + } + write!(f, "], upgrade_sequence: {} }}", self.upgrade_sequence) + } +} + +impl From for UpgradeAttributes { + fn from(ev: UpgradeInit) -> Self { + Self { + port_id: ev.port_id, + channel_id: ev.channel_id, + counterparty_port_id: ev.counterparty_port_id, + counterparty_channel_id: ev.counterparty_channel_id, + upgrade_sequence: ev.upgrade_sequence, + upgrade_timeout_height: None, + upgrade_timeout_timestamp: None, + error_receipt: None, + } + } +} + +impl UpgradeInit { + pub fn channel_id(&self) -> &ChannelId { + &self.channel_id + } + + pub fn port_id(&self) -> &PortId { + &self.port_id + } + + pub fn counterparty_port_id(&self) -> &PortId { + &self.counterparty_port_id + } + + pub fn counterparty_channel_id(&self) -> Option<&ChannelId> { + self.counterparty_channel_id.as_ref() + } +} + +impl TryFrom for UpgradeInit { + type Error = EventError; + + fn try_from(attrs: UpgradeAttributes) -> Result { + Ok(Self { + port_id: attrs.port_id, + channel_id: attrs.channel_id, + counterparty_port_id: attrs.counterparty_port_id, + counterparty_channel_id: attrs.counterparty_channel_id, + upgrade_sequence: attrs.upgrade_sequence, + }) + } +} + +impl From for IbcEvent { + fn from(v: UpgradeInit) -> Self { + IbcEvent::UpgradeInitChannel(v) + } +} + +impl EventType for UpgradeInit { + fn event_type() -> IbcEventType { + IbcEventType::UpgradeInitChannel + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] +pub struct UpgradeTry { + pub port_id: PortId, + pub channel_id: ChannelId, + pub counterparty_port_id: PortId, + pub counterparty_channel_id: Option, + pub upgrade_sequence: Sequence, +} + +impl Display for UpgradeTry { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { + if let Some(counterparty_channel_id) = &self.counterparty_channel_id { + write!(f, "UpgradeAttributes {{ port_id: {}, channel_id: {}, counterparty_port_id: {}, counterparty_channel_id: {counterparty_channel_id}, upgrade_connection_hops: [", self.port_id, self.channel_id, self.counterparty_port_id)?; + } else { + write!(f, "UpgradeAttributes {{ port_id: {}, channel_id: {}, counterparty_port_id: {}, counterparty_channel_id: None, upgrade_connection_hops: [", self.port_id, self.channel_id, self.counterparty_port_id)?; + } + write!(f, "], upgrade_sequence: {} }}", self.upgrade_sequence) + } +} + +impl From for UpgradeAttributes { + fn from(ev: UpgradeTry) -> Self { + Self { + port_id: ev.port_id, + channel_id: ev.channel_id, + counterparty_port_id: ev.counterparty_port_id, + counterparty_channel_id: ev.counterparty_channel_id, + upgrade_sequence: ev.upgrade_sequence, + upgrade_timeout_height: None, + upgrade_timeout_timestamp: None, + error_receipt: None, + } + } +} + +impl UpgradeTry { + pub fn channel_id(&self) -> &ChannelId { + &self.channel_id + } + + pub fn port_id(&self) -> &PortId { + &self.port_id + } + + pub fn counterparty_port_id(&self) -> &PortId { + &self.counterparty_port_id + } + + pub fn counterparty_channel_id(&self) -> Option<&ChannelId> { + self.counterparty_channel_id.as_ref() + } +} + +impl TryFrom for UpgradeTry { + type Error = EventError; + + fn try_from(attrs: UpgradeAttributes) -> Result { + Ok(Self { + port_id: attrs.port_id, + channel_id: attrs.channel_id, + counterparty_port_id: attrs.counterparty_port_id, + counterparty_channel_id: attrs.counterparty_channel_id, + upgrade_sequence: attrs.upgrade_sequence, + }) + } +} + +impl From for IbcEvent { + fn from(v: UpgradeTry) -> Self { + IbcEvent::UpgradeTryChannel(v) + } +} + +impl EventType for UpgradeTry { + fn event_type() -> IbcEventType { + IbcEventType::UpgradeTryChannel + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] +pub struct UpgradeAck { + pub port_id: PortId, + pub channel_id: ChannelId, + pub counterparty_port_id: PortId, + pub counterparty_channel_id: Option, + pub upgrade_sequence: Sequence, +} + +impl Display for UpgradeAck { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { + if let Some(counterparty_channel_id) = &self.counterparty_channel_id { + write!(f, "UpgradeAttributes {{ port_id: {}, channel_id: {}, counterparty_port_id: {}, counterparty_channel_id: {counterparty_channel_id}, upgrade_connection_hops: [", self.port_id, self.channel_id, self.counterparty_port_id)?; + } else { + write!(f, "UpgradeAttributes {{ port_id: {}, channel_id: {}, counterparty_port_id: {}, counterparty_channel_id: None, upgrade_connection_hops: [", self.port_id, self.channel_id, self.counterparty_port_id)?; + } + write!(f, "], upgrade_sequence: {} }}", self.upgrade_sequence) + } +} + +impl From for UpgradeAttributes { + fn from(ev: UpgradeAck) -> Self { + Self { + port_id: ev.port_id, + channel_id: ev.channel_id, + counterparty_port_id: ev.counterparty_port_id, + counterparty_channel_id: ev.counterparty_channel_id, + upgrade_sequence: ev.upgrade_sequence, + upgrade_timeout_height: None, + upgrade_timeout_timestamp: None, + error_receipt: None, + } + } +} + +impl UpgradeAck { + pub fn channel_id(&self) -> &ChannelId { + &self.channel_id + } + + pub fn port_id(&self) -> &PortId { + &self.port_id + } + + pub fn counterparty_port_id(&self) -> &PortId { + &self.counterparty_port_id + } + + pub fn counterparty_channel_id(&self) -> Option<&ChannelId> { + self.counterparty_channel_id.as_ref() + } +} + +impl TryFrom for UpgradeAck { + type Error = EventError; + + fn try_from(attrs: UpgradeAttributes) -> Result { + Ok(Self { + port_id: attrs.port_id, + channel_id: attrs.channel_id, + counterparty_port_id: attrs.counterparty_port_id, + counterparty_channel_id: attrs.counterparty_channel_id, + upgrade_sequence: attrs.upgrade_sequence, + }) + } +} + +impl From for IbcEvent { + fn from(v: UpgradeAck) -> Self { + IbcEvent::UpgradeAckChannel(v) + } +} + +impl EventType for UpgradeAck { + fn event_type() -> IbcEventType { + IbcEventType::UpgradeAckChannel + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] +pub struct UpgradeConfirm { + pub port_id: PortId, + pub channel_id: ChannelId, + pub counterparty_port_id: PortId, + pub counterparty_channel_id: Option, + pub upgrade_sequence: Sequence, +} + +impl Display for UpgradeConfirm { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { + if let Some(counterparty_channel_id) = &self.counterparty_channel_id { + write!(f, "UpgradeAttributes {{ port_id: {}, channel_id: {}, counterparty_port_id: {}, counterparty_channel_id: {counterparty_channel_id}, upgrade_connection_hops: [", self.port_id, self.channel_id, self.counterparty_port_id)?; + } else { + write!(f, "UpgradeAttributes {{ port_id: {}, channel_id: {}, counterparty_port_id: {}, counterparty_channel_id: None, upgrade_connection_hops: [", self.port_id, self.channel_id, self.counterparty_port_id)?; + } + write!(f, "], upgrade_sequence: {} }}", self.upgrade_sequence) + } +} + +impl From for UpgradeAttributes { + fn from(ev: UpgradeConfirm) -> Self { + Self { + port_id: ev.port_id, + channel_id: ev.channel_id, + counterparty_port_id: ev.counterparty_port_id, + counterparty_channel_id: ev.counterparty_channel_id, + upgrade_sequence: ev.upgrade_sequence, + upgrade_timeout_height: None, + upgrade_timeout_timestamp: None, + error_receipt: None, + } + } +} + +impl UpgradeConfirm { + pub fn channel_id(&self) -> &ChannelId { + &self.channel_id + } + + pub fn port_id(&self) -> &PortId { + &self.port_id + } + + pub fn counterparty_port_id(&self) -> &PortId { + &self.counterparty_port_id + } + + pub fn counterparty_channel_id(&self) -> Option<&ChannelId> { + self.counterparty_channel_id.as_ref() + } +} + +impl TryFrom for UpgradeConfirm { + type Error = EventError; + + fn try_from(attrs: UpgradeAttributes) -> Result { + Ok(Self { + port_id: attrs.port_id, + channel_id: attrs.channel_id, + counterparty_port_id: attrs.counterparty_port_id, + counterparty_channel_id: attrs.counterparty_channel_id, + upgrade_sequence: attrs.upgrade_sequence, + }) + } +} + +impl From for IbcEvent { + fn from(v: UpgradeConfirm) -> Self { + IbcEvent::UpgradeConfirmChannel(v) + } +} + +impl EventType for UpgradeConfirm { + fn event_type() -> IbcEventType { + IbcEventType::UpgradeConfirmChannel + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] +pub struct UpgradeOpen { + pub port_id: PortId, + pub channel_id: ChannelId, + pub counterparty_port_id: PortId, + pub counterparty_channel_id: Option, + pub upgrade_sequence: Sequence, +} + +impl Display for UpgradeOpen { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { + if let Some(counterparty_channel_id) = &self.counterparty_channel_id { + write!(f, "UpgradeAttributes {{ port_id: {}, channel_id: {}, counterparty_port_id: {}, counterparty_channel_id: {counterparty_channel_id}, upgrade_connection_hops: [", self.port_id, self.channel_id, self.counterparty_port_id)?; + } else { + write!(f, "UpgradeAttributes {{ port_id: {}, channel_id: {}, counterparty_port_id: {}, counterparty_channel_id: None, upgrade_connection_hops: [", self.port_id, self.channel_id, self.counterparty_port_id)?; + } + write!(f, "], upgrade_sequence: {} }}", self.upgrade_sequence) + } +} + +impl From for UpgradeAttributes { + fn from(ev: UpgradeOpen) -> Self { + Self { + port_id: ev.port_id, + channel_id: ev.channel_id, + counterparty_port_id: ev.counterparty_port_id, + counterparty_channel_id: ev.counterparty_channel_id, + upgrade_sequence: ev.upgrade_sequence, + upgrade_timeout_height: None, + upgrade_timeout_timestamp: None, + error_receipt: None, + } + } +} + +impl UpgradeOpen { + pub fn channel_id(&self) -> &ChannelId { + &self.channel_id + } + + pub fn port_id(&self) -> &PortId { + &self.port_id + } + + pub fn counterparty_port_id(&self) -> &PortId { + &self.counterparty_port_id + } + + pub fn counterparty_channel_id(&self) -> Option<&ChannelId> { + self.counterparty_channel_id.as_ref() + } +} + +impl TryFrom for UpgradeOpen { + type Error = EventError; + + fn try_from(attrs: UpgradeAttributes) -> Result { + Ok(Self { + port_id: attrs.port_id, + channel_id: attrs.channel_id, + counterparty_port_id: attrs.counterparty_port_id, + counterparty_channel_id: attrs.counterparty_channel_id, + upgrade_sequence: attrs.upgrade_sequence, + }) + } +} + +impl From for IbcEvent { + fn from(v: UpgradeOpen) -> Self { + IbcEvent::UpgradeOpenChannel(v) + } +} + +impl EventType for UpgradeOpen { + fn event_type() -> IbcEventType { + IbcEventType::UpgradeOpenChannel + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] +pub struct UpgradeCancel { + pub port_id: PortId, + pub channel_id: ChannelId, + pub counterparty_port_id: PortId, + pub counterparty_channel_id: Option, + pub upgrade_sequence: Sequence, +} + +impl Display for UpgradeCancel { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { + if let Some(counterparty_channel_id) = &self.counterparty_channel_id { + write!(f, "UpgradeAttributes {{ port_id: {}, channel_id: {}, counterparty_port_id: {}, counterparty_channel_id: {counterparty_channel_id}, upgrade_connection_hops: [", self.port_id, self.channel_id, self.counterparty_port_id)?; + } else { + write!(f, "UpgradeAttributes {{ port_id: {}, channel_id: {}, counterparty_port_id: {}, counterparty_channel_id: None, upgrade_connection_hops: [", self.port_id, self.channel_id, self.counterparty_port_id)?; + } + write!(f, "], upgrade_sequence: {} }}", self.upgrade_sequence) + } +} + +impl From for UpgradeAttributes { + fn from(ev: UpgradeCancel) -> Self { + Self { + port_id: ev.port_id, + channel_id: ev.channel_id, + counterparty_port_id: ev.counterparty_port_id, + counterparty_channel_id: ev.counterparty_channel_id, + upgrade_sequence: ev.upgrade_sequence, + upgrade_timeout_height: None, + upgrade_timeout_timestamp: None, + error_receipt: None, + } + } +} + +impl UpgradeCancel { + pub fn channel_id(&self) -> &ChannelId { + &self.channel_id + } + + pub fn port_id(&self) -> &PortId { + &self.port_id + } + + pub fn counterparty_port_id(&self) -> &PortId { + &self.counterparty_port_id + } + + pub fn counterparty_channel_id(&self) -> Option<&ChannelId> { + self.counterparty_channel_id.as_ref() + } +} + +impl TryFrom for UpgradeCancel { + type Error = EventError; + + fn try_from(attrs: UpgradeAttributes) -> Result { + Ok(Self { + port_id: attrs.port_id, + channel_id: attrs.channel_id, + counterparty_port_id: attrs.counterparty_port_id, + counterparty_channel_id: attrs.counterparty_channel_id, + upgrade_sequence: attrs.upgrade_sequence, + }) + } +} + +impl From for IbcEvent { + fn from(v: UpgradeCancel) -> Self { + IbcEvent::UpgradeCancelChannel(v) + } +} + +impl EventType for UpgradeCancel { + fn event_type() -> IbcEventType { + IbcEventType::UpgradeCancelChannel + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] +pub struct UpgradeTimeout { + pub port_id: PortId, + pub channel_id: ChannelId, + pub counterparty_port_id: PortId, + pub counterparty_channel_id: Option, + pub upgrade_sequence: Sequence, + pub upgrade_timeout_height: Option, + pub upgrade_timeout_timestamp: Option, +} + +impl Display for UpgradeTimeout { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { + if let Some(counterparty_channel_id) = &self.counterparty_channel_id { + write!(f, "UpgradeAttributes {{ port_id: {}, channel_id: {}, counterparty_port_id: {}, counterparty_channel_id: {counterparty_channel_id}, upgrade_connection_hops: [", self.port_id, self.channel_id, self.counterparty_port_id)?; + } else { + write!(f, "UpgradeAttributes {{ port_id: {}, channel_id: {}, counterparty_port_id: {}, counterparty_channel_id: None, upgrade_connection_hops: [", self.port_id, self.channel_id, self.counterparty_port_id)?; + } + + write!(f, "], upgrade_sequence: {}", self.upgrade_sequence)?; + + match (self.upgrade_timeout_height, self.upgrade_timeout_timestamp) { + (Some(height), Some(timestamp)) => write!( + f, + " timeout_height: {}, timeout_timestamp: {} }}", + height, timestamp + ), + (Some(height), None) => write!(f, " timeout_height: {} }}", height), + (None, Some(timestamp)) => write!(f, " timeout_timestamp: {} }}", timestamp), + (None, None) => write!(f, " }}"), + } + } +} + +impl From for UpgradeAttributes { + fn from(ev: UpgradeTimeout) -> Self { + Self { + port_id: ev.port_id, + channel_id: ev.channel_id, + counterparty_port_id: ev.counterparty_port_id, + counterparty_channel_id: ev.counterparty_channel_id, + upgrade_sequence: ev.upgrade_sequence, + upgrade_timeout_height: ev.upgrade_timeout_height, + upgrade_timeout_timestamp: ev.upgrade_timeout_timestamp, + error_receipt: None, + } + } +} + +impl UpgradeTimeout { + pub fn channel_id(&self) -> &ChannelId { + &self.channel_id + } + + pub fn port_id(&self) -> &PortId { + &self.port_id + } + + pub fn counterparty_port_id(&self) -> &PortId { + &self.counterparty_port_id + } + + pub fn counterparty_channel_id(&self) -> Option<&ChannelId> { + self.counterparty_channel_id.as_ref() + } +} + +impl TryFrom for UpgradeTimeout { + type Error = EventError; + + fn try_from(attrs: UpgradeAttributes) -> Result { + Ok(Self { + port_id: attrs.port_id, + channel_id: attrs.channel_id, + counterparty_port_id: attrs.counterparty_port_id, + counterparty_channel_id: attrs.counterparty_channel_id, + upgrade_sequence: attrs.upgrade_sequence, + upgrade_timeout_height: attrs.upgrade_timeout_height, + upgrade_timeout_timestamp: attrs.upgrade_timeout_timestamp, + }) + } +} + +impl From for IbcEvent { + fn from(v: UpgradeTimeout) -> Self { + IbcEvent::UpgradeTimeoutChannel(v) + } +} + +impl EventType for UpgradeTimeout { + fn event_type() -> IbcEventType { + IbcEventType::UpgradeTimeoutChannel + } +} +// + +#[derive(Clone, Debug, PartialEq, Eq, Serialize)] +pub struct UpgradeError { + pub port_id: PortId, + pub channel_id: ChannelId, + pub counterparty_port_id: PortId, + pub counterparty_channel_id: Option, + pub upgrade_sequence: Sequence, + pub error_receipt: String, +} + +impl Display for UpgradeError { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { + if let Some(counterparty_channel_id) = &self.counterparty_channel_id { + write!(f, "UpgradeAttributes {{ port_id: {}, channel_id: {}, counterparty_port_id: {}, counterparty_channel_id: {counterparty_channel_id}, upgrade_connection_hops: [", self.port_id, self.channel_id, self.counterparty_port_id)?; + } else { + write!(f, "UpgradeAttributes {{ port_id: {}, channel_id: {}, counterparty_port_id: {}, counterparty_channel_id: None, upgrade_connection_hops: [", self.port_id, self.channel_id, self.counterparty_port_id)?; + } + + write!( + f, + "], upgrade_sequence: {}, error_receipt: {} }}", + self.upgrade_sequence, self.error_receipt + ) + } +} + +impl From for UpgradeAttributes { + fn from(ev: UpgradeError) -> Self { + Self { + port_id: ev.port_id, + channel_id: ev.channel_id, + counterparty_port_id: ev.counterparty_port_id, + counterparty_channel_id: ev.counterparty_channel_id, + upgrade_sequence: ev.upgrade_sequence, + upgrade_timeout_height: None, + upgrade_timeout_timestamp: None, + error_receipt: Some(ev.error_receipt), + } + } +} + +impl UpgradeError { + pub fn channel_id(&self) -> &ChannelId { + &self.channel_id + } + + pub fn port_id(&self) -> &PortId { + &self.port_id + } + + pub fn counterparty_port_id(&self) -> &PortId { + &self.counterparty_port_id + } + + pub fn counterparty_channel_id(&self) -> Option<&ChannelId> { + self.counterparty_channel_id.as_ref() + } +} + +impl TryFrom for UpgradeError { + type Error = EventError; + + fn try_from(attrs: UpgradeAttributes) -> Result { + let error_receipt = attrs.error_receipt.unwrap_or_default(); + Ok(Self { + port_id: attrs.port_id, + channel_id: attrs.channel_id, + counterparty_port_id: attrs.counterparty_port_id, + counterparty_channel_id: attrs.counterparty_channel_id, + upgrade_sequence: attrs.upgrade_sequence, + error_receipt, + }) + } +} + +impl From for IbcEvent { + fn from(v: UpgradeError) -> Self { + IbcEvent::UpgradeErrorChannel(v) + } +} + +impl EventType for UpgradeError { + fn event_type() -> IbcEventType { + IbcEventType::UpgradeErrorChannel + } +} + macro_rules! impl_try_from_attribute_for_event { ($($event:ty),+) => { $(impl TryFrom for $event { diff --git a/crates/relayer-types/src/core/ics04_channel/mod.rs b/crates/relayer-types/src/core/ics04_channel/mod.rs index 21d1378da6..018a0608de 100644 --- a/crates/relayer-types/src/core/ics04_channel/mod.rs +++ b/crates/relayer-types/src/core/ics04_channel/mod.rs @@ -9,4 +9,6 @@ pub mod msgs; pub mod packet; pub mod packet_id; pub mod timeout; +pub mod upgrade; +pub mod upgrade_fields; pub mod version; diff --git a/crates/relayer-types/src/core/ics04_channel/msgs.rs b/crates/relayer-types/src/core/ics04_channel/msgs.rs index c69f2e267f..c856d76866 100644 --- a/crates/relayer-types/src/core/ics04_channel/msgs.rs +++ b/crates/relayer-types/src/core/ics04_channel/msgs.rs @@ -22,6 +22,15 @@ pub mod chan_open_try; pub mod chan_close_confirm; pub mod chan_close_init; +// Upgrade handshake messages. +pub mod chan_upgrade_ack; +pub mod chan_upgrade_cancel; +pub mod chan_upgrade_confirm; +pub mod chan_upgrade_init; +pub mod chan_upgrade_open; +pub mod chan_upgrade_timeout; +pub mod chan_upgrade_try; + // Packet specific messages. pub mod acknowledgement; pub mod recv_packet; diff --git a/crates/relayer-types/src/core/ics04_channel/msgs/chan_close_confirm.rs b/crates/relayer-types/src/core/ics04_channel/msgs/chan_close_confirm.rs index e29872320d..50736ece9e 100644 --- a/crates/relayer-types/src/core/ics04_channel/msgs/chan_close_confirm.rs +++ b/crates/relayer-types/src/core/ics04_channel/msgs/chan_close_confirm.rs @@ -3,6 +3,7 @@ use ibc_proto::Protobuf; use ibc_proto::ibc::core::channel::v1::MsgChannelCloseConfirm as RawMsgChannelCloseConfirm; use crate::core::ics04_channel::error::Error; +use crate::core::ics04_channel::packet::Sequence; use crate::core::ics24_host::identifier::{ChannelId, PortId}; use crate::proofs::Proofs; use crate::signer::Signer; @@ -20,6 +21,7 @@ pub struct MsgChannelCloseConfirm { pub channel_id: ChannelId, pub proofs: Proofs, pub signer: Signer, + pub counterparty_upgrade_sequence: Sequence, } impl MsgChannelCloseConfirm { @@ -29,6 +31,7 @@ impl MsgChannelCloseConfirm { channel_id, proofs, signer, + counterparty_upgrade_sequence: Sequence::from(0), } } } @@ -73,6 +76,7 @@ impl TryFrom for MsgChannelCloseConfirm { channel_id: raw_msg.channel_id.parse().map_err(Error::identifier)?, proofs, signer: raw_msg.signer.parse().map_err(Error::signer)?, + counterparty_upgrade_sequence: raw_msg.counterparty_upgrade_sequence.into(), }) } } @@ -85,6 +89,7 @@ impl From for RawMsgChannelCloseConfirm { proof_init: domain_msg.proofs.object_proof().clone().into(), proof_height: Some(domain_msg.proofs.height().into()), signer: domain_msg.signer.to_string(), + counterparty_upgrade_sequence: domain_msg.counterparty_upgrade_sequence.into(), } } } @@ -109,6 +114,7 @@ pub mod test_util { revision_height: proof_height, }), signer: get_dummy_bech32_account(), + counterparty_upgrade_sequence: 0, } } } diff --git a/crates/relayer-types/src/core/ics04_channel/msgs/chan_close_init.rs b/crates/relayer-types/src/core/ics04_channel/msgs/chan_close_init.rs index 9e249d6137..d2036eccad 100644 --- a/crates/relayer-types/src/core/ics04_channel/msgs/chan_close_init.rs +++ b/crates/relayer-types/src/core/ics04_channel/msgs/chan_close_init.rs @@ -9,9 +9,7 @@ use crate::tx_msg::Msg; pub const TYPE_URL: &str = "/ibc.core.channel.v1.MsgChannelCloseInit"; -/// /// Message definition for the first step in the channel close handshake (`ChanCloseInit` datagram). -/// #[derive(Clone, Debug, PartialEq, Eq)] pub struct MsgChannelCloseInit { pub port_id: PortId, diff --git a/crates/relayer-types/src/core/ics04_channel/msgs/chan_open_init.rs b/crates/relayer-types/src/core/ics04_channel/msgs/chan_open_init.rs index 8128674f24..528b5cb9ab 100644 --- a/crates/relayer-types/src/core/ics04_channel/msgs/chan_open_init.rs +++ b/crates/relayer-types/src/core/ics04_channel/msgs/chan_open_init.rs @@ -10,9 +10,7 @@ use ibc_proto::Protobuf; pub const TYPE_URL: &str = "/ibc.core.channel.v1.MsgChannelOpenInit"; -/// /// Message definition for the first step in the channel open handshake (`ChanOpenInit` datagram). -/// #[derive(Clone, Debug, PartialEq, Eq)] pub struct MsgChannelOpenInit { pub port_id: PortId, diff --git a/crates/relayer-types/src/core/ics04_channel/msgs/chan_open_try.rs b/crates/relayer-types/src/core/ics04_channel/msgs/chan_open_try.rs index 597204e5ec..e802433cc4 100644 --- a/crates/relayer-types/src/core/ics04_channel/msgs/chan_open_try.rs +++ b/crates/relayer-types/src/core/ics04_channel/msgs/chan_open_try.rs @@ -1,7 +1,6 @@ use crate::core::ics04_channel::channel::ChannelEnd; use crate::core::ics04_channel::error::Error as ChannelError; use crate::core::ics04_channel::version::Version; -use crate::core::ics24_host::error::ValidationError; use crate::core::ics24_host::identifier::{ChannelId, PortId}; use crate::proofs::Proofs; @@ -15,9 +14,7 @@ use core::str::FromStr; pub const TYPE_URL: &str = "/ibc.core.channel.v1.MsgChannelOpenTry"; -/// /// Message definition for the second step in the channel open handshake (`ChanOpenTry` datagram). -/// #[derive(Clone, Debug, PartialEq, Eq)] pub struct MsgChannelOpenTry { pub port_id: PortId, @@ -59,13 +56,6 @@ impl Msg for MsgChannelOpenTry { fn type_url(&self) -> String { TYPE_URL.to_string() } - - fn validate_basic(&self) -> Result<(), ValidationError> { - match self.channel.counterparty().channel_id() { - None => Err(ValidationError::invalid_counterparty_channel_id()), - Some(_c) => Ok(()), - } - } } impl Protobuf for MsgChannelOpenTry {} @@ -97,21 +87,25 @@ impl TryFrom for MsgChannelOpenTry { .transpose() .map_err(ChannelError::identifier)?; + let channel: ChannelEnd = raw_msg + .channel + .ok_or_else(ChannelError::missing_channel)? + .try_into()?; + + assert!( + channel.counterparty().channel_id().is_some(), + "Expected counterparty channel to have a channel ID" + ); + let msg = MsgChannelOpenTry { port_id: raw_msg.port_id.parse().map_err(ChannelError::identifier)?, previous_channel_id, - channel: raw_msg - .channel - .ok_or_else(ChannelError::missing_channel)? - .try_into()?, + channel, counterparty_version: raw_msg.counterparty_version.into(), proofs, signer: raw_msg.signer.parse().map_err(ChannelError::signer)?, }; - msg.validate_basic() - .map_err(ChannelError::invalid_counterparty_channel_id)?; - Ok(msg) } } diff --git a/crates/relayer-types/src/core/ics04_channel/msgs/chan_upgrade_ack.rs b/crates/relayer-types/src/core/ics04_channel/msgs/chan_upgrade_ack.rs new file mode 100644 index 0000000000..3b92cb7db0 --- /dev/null +++ b/crates/relayer-types/src/core/ics04_channel/msgs/chan_upgrade_ack.rs @@ -0,0 +1,249 @@ +use ibc_proto::ibc::core::channel::v1::MsgChannelUpgradeAck as RawMsgChannelUpgradeAck; +use ibc_proto::Protobuf; + +use crate::core::ics04_channel::error::Error; +use crate::core::ics04_channel::upgrade::Upgrade; +use crate::core::ics23_commitment::commitment::CommitmentProofBytes; +use crate::core::ics24_host::identifier::{ChannelId, PortId}; +use crate::signer::Signer; +use crate::tx_msg::Msg; +use crate::Height; + +pub const TYPE_URL: &str = "/ibc.core.channel.v1.MsgChannelUpgradeAck"; + +/// Message definition for the third step of the channel upgrade +/// handshake (the `ChanUpgradeAck` datagram). +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct MsgChannelUpgradeAck { + pub port_id: PortId, + pub channel_id: ChannelId, + pub counterparty_upgrade: Upgrade, + /// The proof of the counterparty channel + pub proof_channel: CommitmentProofBytes, + /// The proof of the counterparty upgrade + pub proof_upgrade: CommitmentProofBytes, + /// The height at which the proofs were queried. + pub proof_height: Height, + pub signer: Signer, +} + +impl MsgChannelUpgradeAck { + #[allow(clippy::too_many_arguments)] + pub fn new( + port_id: PortId, + channel_id: ChannelId, + counterparty_upgrade: Upgrade, + proof_channel: CommitmentProofBytes, + proof_upgrade: CommitmentProofBytes, + proof_height: Height, + signer: Signer, + ) -> Self { + Self { + port_id, + channel_id, + counterparty_upgrade, + proof_channel, + proof_upgrade, + proof_height, + signer, + } + } +} + +impl Msg for MsgChannelUpgradeAck { + type ValidationError = Error; + type Raw = RawMsgChannelUpgradeAck; + + fn route(&self) -> String { + crate::keys::ROUTER_KEY.to_string() + } + + fn type_url(&self) -> String { + TYPE_URL.to_string() + } +} + +impl Protobuf for MsgChannelUpgradeAck {} + +impl TryFrom for MsgChannelUpgradeAck { + type Error = Error; + + fn try_from(raw_msg: RawMsgChannelUpgradeAck) -> Result { + let counterparty_upgrade = raw_msg + .counterparty_upgrade + .ok_or(Error::missing_upgrade())? + .try_into()?; + + let proof_height = raw_msg + .proof_height + .ok_or_else(Error::missing_proof_height)? + .try_into() + .map_err(|_| Error::invalid_proof_height())?; + + Ok(MsgChannelUpgradeAck { + port_id: raw_msg.port_id.parse().map_err(Error::identifier)?, + channel_id: raw_msg.channel_id.parse().map_err(Error::identifier)?, + counterparty_upgrade, + proof_channel: raw_msg + .proof_channel + .try_into() + .map_err(Error::invalid_proof)?, + proof_upgrade: raw_msg + .proof_upgrade + .try_into() + .map_err(Error::invalid_proof)?, + proof_height, + signer: raw_msg.signer.parse().map_err(Error::signer)?, + }) + } +} + +impl From for RawMsgChannelUpgradeAck { + fn from(domain_msg: MsgChannelUpgradeAck) -> Self { + RawMsgChannelUpgradeAck { + port_id: domain_msg.port_id.to_string(), + channel_id: domain_msg.channel_id.to_string(), + counterparty_upgrade: Some(domain_msg.counterparty_upgrade.into()), + proof_upgrade: domain_msg.proof_upgrade.into(), + proof_channel: domain_msg.proof_channel.into(), + proof_height: Some(domain_msg.proof_height.into()), + signer: domain_msg.signer.to_string(), + } + } +} + +#[cfg(test)] +pub mod test_util { + use ibc_proto::ibc::core::channel::v1::MsgChannelUpgradeAck as RawMsgChannelUpgradeAck; + use ibc_proto::ibc::core::client::v1::Height as RawHeight; + + use crate::core::ics04_channel::upgrade::test_util::get_dummy_upgrade; + use crate::core::ics24_host::identifier::{ChannelId, PortId}; + use crate::test_utils::{get_dummy_bech32_account, get_dummy_proof}; + + /// Returns a dummy `RawMsgChannelUpgradeAck`, for testing only! + pub fn get_dummy_raw_msg_chan_upgrade_ack() -> RawMsgChannelUpgradeAck { + RawMsgChannelUpgradeAck { + port_id: PortId::default().to_string(), + channel_id: ChannelId::default().to_string(), + counterparty_upgrade: Some(get_dummy_upgrade()), + proof_upgrade: get_dummy_proof(), + proof_channel: get_dummy_proof(), + proof_height: Some(RawHeight { + revision_number: 1, + revision_height: 1, + }), + signer: get_dummy_bech32_account(), + } + } +} + +#[cfg(test)] +mod tests { + use test_log::test; + + use ibc_proto::ibc::core::channel::v1::MsgChannelUpgradeAck as RawMsgChannelUpgradeAck; + + use crate::core::ics04_channel::msgs::chan_upgrade_ack::test_util::get_dummy_raw_msg_chan_upgrade_ack; + use crate::core::ics04_channel::msgs::chan_upgrade_ack::MsgChannelUpgradeAck; + + #[test] + fn parse_channel_upgrade_try_msg() { + struct Test { + name: String, + raw: RawMsgChannelUpgradeAck, + want_pass: bool, + } + + let default_raw_msg = get_dummy_raw_msg_chan_upgrade_ack(); + + let tests: Vec = vec![ + Test { + name: "Good parameters".to_string(), + raw: default_raw_msg.clone(), + want_pass: true, + }, + Test { + name: "Correct port ID".to_string(), + raw: RawMsgChannelUpgradeAck { + port_id: "p36".to_string(), + ..default_raw_msg.clone() + }, + want_pass: true, + }, + Test { + name: "Port too short".to_string(), + raw: RawMsgChannelUpgradeAck { + port_id: "p".to_string(), + ..default_raw_msg.clone() + }, + want_pass: false, + }, + Test { + name: "Port too long".to_string(), + raw: RawMsgChannelUpgradeAck { + port_id: "abcdefsdfasdfasdfasdfasdfasdfadsfasdgafsgadfasdfasdfasdfsdfasdfaghijklmnopqrstuabcdefsdfasdfasdfasdfasdfasdfadsfasdgafsgadfasdfasdfasdfsdfasdfaghijklmnopqrstu".to_string(), + ..default_raw_msg.clone() + }, + want_pass: false, + }, + Test { + name: "Correct channel ID".to_string(), + raw: RawMsgChannelUpgradeAck { + channel_id: "channel-2".to_string(), + ..default_raw_msg.clone() + }, + want_pass: true, + }, + Test { + name: "Channel name too short".to_string(), + raw: RawMsgChannelUpgradeAck { + channel_id: "c".to_string(), + ..default_raw_msg.clone() + }, + want_pass: false, + }, + Test { + name: "Channel name too long".to_string(), + raw: RawMsgChannelUpgradeAck { + channel_id: "channel-128391283791827398127398791283912837918273981273987912839".to_string(), + ..default_raw_msg.clone() + }, + want_pass: false, + }, + Test { + name: "Empty proof channel".to_string(), + raw: RawMsgChannelUpgradeAck { + proof_channel: vec![], + ..default_raw_msg + }, + want_pass: false, + }, + ] + .into_iter() + .collect(); + + for test in tests { + let res = MsgChannelUpgradeAck::try_from(test.raw.clone()); + + assert_eq!( + test.want_pass, + res.is_ok(), + "MsgChannelUpgradeAck::try_from failed for test {}, \nraw msg {:?} with err {:?}", + test.name, + test.raw, + res.err() + ); + } + } + + #[test] + fn to_and_from() { + let raw = get_dummy_raw_msg_chan_upgrade_ack(); + let msg = MsgChannelUpgradeAck::try_from(raw.clone()).unwrap(); + let raw_back = RawMsgChannelUpgradeAck::from(msg.clone()); + let msg_back = MsgChannelUpgradeAck::try_from(raw_back.clone()).unwrap(); + assert_eq!(raw, raw_back); + assert_eq!(msg, msg_back); + } +} diff --git a/crates/relayer-types/src/core/ics04_channel/msgs/chan_upgrade_cancel.rs b/crates/relayer-types/src/core/ics04_channel/msgs/chan_upgrade_cancel.rs new file mode 100644 index 0000000000..f2e33039b1 --- /dev/null +++ b/crates/relayer-types/src/core/ics04_channel/msgs/chan_upgrade_cancel.rs @@ -0,0 +1,241 @@ +use ibc_proto::ibc::core::channel::v1::MsgChannelUpgradeCancel as RawMsgChannelUpgradeCancel; +use ibc_proto::Protobuf; + +use crate::core::ics04_channel::error::Error; +use crate::core::ics04_channel::upgrade::ErrorReceipt; +use crate::core::ics23_commitment::commitment::CommitmentProofBytes; +use crate::core::ics24_host::identifier::{ChannelId, PortId}; +use crate::signer::Signer; +use crate::tx_msg::Msg; +use crate::Height; + +pub const TYPE_URL: &str = "/ibc.core.channel.v1.MsgChannelUpgradeCancel"; + +/// Message definition the `ChanUpgradeCancel` datagram. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct MsgChannelUpgradeCancel { + pub port_id: PortId, + pub channel_id: ChannelId, + pub error_receipt: ErrorReceipt, + /// The proof of the counterparty error receipt + pub proof_error_receipt: CommitmentProofBytes, + /// The height at which the proofs were queried. + pub proof_height: Height, + pub signer: Signer, +} + +impl MsgChannelUpgradeCancel { + #[allow(clippy::too_many_arguments)] + pub fn new( + port_id: PortId, + channel_id: ChannelId, + error_receipt: ErrorReceipt, + proof_error_receipt: CommitmentProofBytes, + proof_height: Height, + signer: Signer, + ) -> Self { + Self { + port_id, + channel_id, + error_receipt, + proof_error_receipt, + proof_height, + signer, + } + } +} + +impl Msg for MsgChannelUpgradeCancel { + type ValidationError = Error; + type Raw = RawMsgChannelUpgradeCancel; + + fn route(&self) -> String { + crate::keys::ROUTER_KEY.to_string() + } + + fn type_url(&self) -> String { + TYPE_URL.to_string() + } +} + +impl Protobuf for MsgChannelUpgradeCancel {} + +impl TryFrom for MsgChannelUpgradeCancel { + type Error = Error; + + fn try_from(raw_msg: RawMsgChannelUpgradeCancel) -> Result { + let raw_error_receipt = raw_msg + .error_receipt + .ok_or(Error::missing_upgrade_error_receipt())?; + let error_receipt = ErrorReceipt::try_from(raw_error_receipt)?; + + let proof_height = raw_msg + .proof_height + .ok_or_else(Error::missing_proof_height)? + .try_into() + .map_err(|_| Error::invalid_proof_height())?; + + Ok(MsgChannelUpgradeCancel { + port_id: raw_msg.port_id.parse().map_err(Error::identifier)?, + channel_id: raw_msg.channel_id.parse().map_err(Error::identifier)?, + error_receipt, + proof_error_receipt: raw_msg + .proof_error_receipt + .try_into() + .map_err(Error::invalid_proof)?, + proof_height, + signer: raw_msg.signer.parse().map_err(Error::signer)?, + }) + } +} + +impl From for RawMsgChannelUpgradeCancel { + fn from(domain_msg: MsgChannelUpgradeCancel) -> Self { + RawMsgChannelUpgradeCancel { + port_id: domain_msg.port_id.to_string(), + channel_id: domain_msg.channel_id.to_string(), + error_receipt: Some(domain_msg.error_receipt.into()), + proof_error_receipt: domain_msg.proof_error_receipt.into(), + proof_height: Some(domain_msg.proof_height.into()), + signer: domain_msg.signer.to_string(), + } + } +} + +#[cfg(test)] +pub mod test_util { + use ibc_proto::ibc::core::channel::v1::ErrorReceipt as RawErrorReceipt; + use ibc_proto::ibc::core::channel::v1::MsgChannelUpgradeCancel as RawMsgChannelUpgradeCancel; + use ibc_proto::ibc::core::client::v1::Height as RawHeight; + + use crate::core::ics24_host::identifier::{ChannelId, PortId}; + use crate::test_utils::{get_dummy_bech32_account, get_dummy_proof}; + + /// Returns a dummy `RawMsgChannelUpgradeCnacel`, for testing only! + pub fn get_dummy_raw_msg_chan_upgrade_cancel() -> RawMsgChannelUpgradeCancel { + RawMsgChannelUpgradeCancel { + port_id: PortId::default().to_string(), + channel_id: ChannelId::default().to_string(), + error_receipt: Some(RawErrorReceipt { + sequence: 1, + message: "error message".to_string(), + }), + proof_error_receipt: get_dummy_proof(), + proof_height: Some(RawHeight { + revision_number: 1, + revision_height: 1, + }), + signer: get_dummy_bech32_account(), + } + } +} + +#[cfg(test)] +mod tests { + use test_log::test; + + use ibc_proto::ibc::core::channel::v1::MsgChannelUpgradeCancel as RawMsgChannelUpgradeCancel; + + use crate::core::ics04_channel::msgs::chan_upgrade_cancel::test_util::get_dummy_raw_msg_chan_upgrade_cancel; + use crate::core::ics04_channel::msgs::chan_upgrade_cancel::MsgChannelUpgradeCancel; + + #[test] + fn parse_channel_upgrade_try_msg() { + struct Test { + name: String, + raw: RawMsgChannelUpgradeCancel, + want_pass: bool, + } + + let default_raw_msg = get_dummy_raw_msg_chan_upgrade_cancel(); + + let tests: Vec = vec![ + Test { + name: "Good parameters".to_string(), + raw: default_raw_msg.clone(), + want_pass: true, + }, + Test { + name: "Correct port ID".to_string(), + raw: RawMsgChannelUpgradeCancel { + port_id: "p36".to_string(), + ..default_raw_msg.clone() + }, + want_pass: true, + }, + Test { + name: "Port too short".to_string(), + raw: RawMsgChannelUpgradeCancel { + port_id: "p".to_string(), + ..default_raw_msg.clone() + }, + want_pass: false, + }, + Test { + name: "Port too long".to_string(), + raw: RawMsgChannelUpgradeCancel { + port_id: "abcdefsdfasdfasdfasdfasdfasdfadsfasdgafsgadfasdfasdfasdfsdfasdfaghijklmnopqrstuabcdefsdfasdfasdfasdfasdfasdfadsfasdgafsgadfasdfasdfasdfsdfasdfaghijklmnopqrstu".to_string(), + ..default_raw_msg.clone() + }, + want_pass: false, + }, + Test { + name: "Correct channel ID".to_string(), + raw: RawMsgChannelUpgradeCancel { + channel_id: "channel-2".to_string(), + ..default_raw_msg.clone() + }, + want_pass: true, + }, + Test { + name: "Channel name too short".to_string(), + raw: RawMsgChannelUpgradeCancel { + channel_id: "c".to_string(), + ..default_raw_msg.clone() + }, + want_pass: false, + }, + Test { + name: "Channel name too long".to_string(), + raw: RawMsgChannelUpgradeCancel { + channel_id: "channel-128391283791827398127398791283912837918273981273987912839".to_string(), + ..default_raw_msg.clone() + }, + want_pass: false, + }, + Test { + name: "Empty proof channel".to_string(), + raw: RawMsgChannelUpgradeCancel { + proof_error_receipt: vec![], + ..default_raw_msg + }, + want_pass: false, + }, + ] + .into_iter() + .collect(); + + for test in tests { + let res = MsgChannelUpgradeCancel::try_from(test.raw.clone()); + + assert_eq!( + test.want_pass, + res.is_ok(), + "RawMsgChannelUpgradeCancel::try_from failed for test {}, \nraw msg {:?} with err {:?}", + test.name, + test.raw, + res.err() + ); + } + } + + #[test] + fn to_and_from() { + let raw = get_dummy_raw_msg_chan_upgrade_cancel(); + let msg = MsgChannelUpgradeCancel::try_from(raw.clone()).unwrap(); + let raw_back = RawMsgChannelUpgradeCancel::from(msg.clone()); + let msg_back = MsgChannelUpgradeCancel::try_from(raw_back.clone()).unwrap(); + assert_eq!(raw, raw_back); + assert_eq!(msg, msg_back); + } +} diff --git a/crates/relayer-types/src/core/ics04_channel/msgs/chan_upgrade_confirm.rs b/crates/relayer-types/src/core/ics04_channel/msgs/chan_upgrade_confirm.rs new file mode 100644 index 0000000000..d2a2c96b22 --- /dev/null +++ b/crates/relayer-types/src/core/ics04_channel/msgs/chan_upgrade_confirm.rs @@ -0,0 +1,256 @@ +use ibc_proto::ibc::core::channel::v1::MsgChannelUpgradeConfirm as RawMsgChannelUpgradeConfirm; +use ibc_proto::Protobuf; + +use crate::core::ics04_channel::channel::State; +use crate::core::ics04_channel::error::Error; +use crate::core::ics04_channel::upgrade::Upgrade; +use crate::core::ics23_commitment::commitment::CommitmentProofBytes; +use crate::core::ics24_host::identifier::{ChannelId, PortId}; +use crate::signer::Signer; +use crate::tx_msg::Msg; +use crate::Height; + +pub const TYPE_URL: &str = "/ibc.core.channel.v1.MsgChannelUpgradeConfirm"; + +/// Message definition for the third step of the channel upgrade +/// handshake (the `ChanUpgradeConfirm` datagram). +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct MsgChannelUpgradeConfirm { + pub port_id: PortId, + pub channel_id: ChannelId, + pub counterparty_channel_state: State, + pub counterparty_upgrade: Upgrade, + /// The proof of the counterparty channel + pub proof_channel: CommitmentProofBytes, + /// The proof of the counterparty upgrade + pub proof_upgrade: CommitmentProofBytes, + /// The height at which the proofs were queried. + pub proof_height: Height, + pub signer: Signer, +} + +impl MsgChannelUpgradeConfirm { + #[allow(clippy::too_many_arguments)] + pub fn new( + port_id: PortId, + channel_id: ChannelId, + counterparty_channel_state: State, + counterparty_upgrade: Upgrade, + proof_channel: CommitmentProofBytes, + proof_upgrade: CommitmentProofBytes, + proof_height: Height, + signer: Signer, + ) -> Self { + Self { + port_id, + channel_id, + counterparty_channel_state, + counterparty_upgrade, + proof_channel, + proof_upgrade, + proof_height, + signer, + } + } +} + +impl Msg for MsgChannelUpgradeConfirm { + type ValidationError = Error; + type Raw = RawMsgChannelUpgradeConfirm; + + fn route(&self) -> String { + crate::keys::ROUTER_KEY.to_string() + } + + fn type_url(&self) -> String { + TYPE_URL.to_string() + } +} + +impl Protobuf for MsgChannelUpgradeConfirm {} + +impl TryFrom for MsgChannelUpgradeConfirm { + type Error = Error; + + fn try_from(raw_msg: RawMsgChannelUpgradeConfirm) -> Result { + let counterparty_upgrade = raw_msg + .counterparty_upgrade + .ok_or(Error::missing_upgrade())? + .try_into()?; + + let proof_height = raw_msg + .proof_height + .ok_or_else(Error::missing_proof_height)? + .try_into() + .map_err(|_| Error::invalid_proof_height())?; + + Ok(MsgChannelUpgradeConfirm { + port_id: raw_msg.port_id.parse().map_err(Error::identifier)?, + channel_id: raw_msg.channel_id.parse().map_err(Error::identifier)?, + counterparty_channel_state: State::from_i32(raw_msg.counterparty_channel_state)?, + counterparty_upgrade, + proof_channel: raw_msg + .proof_channel + .try_into() + .map_err(Error::invalid_proof)?, + proof_upgrade: raw_msg + .proof_upgrade + .try_into() + .map_err(Error::invalid_proof)?, + proof_height, + signer: raw_msg.signer.parse().map_err(Error::signer)?, + }) + } +} + +impl From for RawMsgChannelUpgradeConfirm { + fn from(domain_msg: MsgChannelUpgradeConfirm) -> Self { + RawMsgChannelUpgradeConfirm { + port_id: domain_msg.port_id.to_string(), + channel_id: domain_msg.channel_id.to_string(), + counterparty_channel_state: domain_msg.counterparty_channel_state.as_i32(), + counterparty_upgrade: Some(domain_msg.counterparty_upgrade.into()), + proof_upgrade: domain_msg.proof_upgrade.into(), + proof_channel: domain_msg.proof_channel.into(), + proof_height: Some(domain_msg.proof_height.into()), + signer: domain_msg.signer.to_string(), + } + } +} + +#[cfg(test)] +pub mod test_util { + use ibc_proto::ibc::core::channel::v1::MsgChannelUpgradeConfirm as RawMsgChannelUpgradeConfirm; + use ibc_proto::ibc::core::client::v1::Height as RawHeight; + + use crate::core::ics04_channel::upgrade::test_util::get_dummy_upgrade; + use crate::core::ics24_host::identifier::{ChannelId, PortId}; + use crate::test_utils::{get_dummy_bech32_account, get_dummy_proof}; + + /// Returns a dummy `RawMsgChannelUpgradeConfirm`, for testing only! + pub fn get_dummy_raw_msg_chan_upgrade_confirm() -> RawMsgChannelUpgradeConfirm { + RawMsgChannelUpgradeConfirm { + port_id: PortId::default().to_string(), + channel_id: ChannelId::default().to_string(), + counterparty_channel_state: 6, // FlushComplete + counterparty_upgrade: Some(get_dummy_upgrade()), + proof_upgrade: get_dummy_proof(), + proof_channel: get_dummy_proof(), + proof_height: Some(RawHeight { + revision_number: 1, + revision_height: 1, + }), + signer: get_dummy_bech32_account(), + } + } +} + +#[cfg(test)] +mod tests { + use test_log::test; + + use ibc_proto::ibc::core::channel::v1::MsgChannelUpgradeConfirm as RawMsgChannelUpgradeConfirm; + + use crate::core::ics04_channel::msgs::chan_upgrade_confirm::test_util::get_dummy_raw_msg_chan_upgrade_confirm; + use crate::core::ics04_channel::msgs::chan_upgrade_confirm::MsgChannelUpgradeConfirm; + + #[test] + fn parse_channel_upgrade_try_msg() { + struct Test { + name: String, + raw: RawMsgChannelUpgradeConfirm, + want_pass: bool, + } + + let default_raw_msg = get_dummy_raw_msg_chan_upgrade_confirm(); + + let tests: Vec = vec![ + Test { + name: "Good parameters".to_string(), + raw: default_raw_msg.clone(), + want_pass: true, + }, + Test { + name: "Correct port ID".to_string(), + raw: RawMsgChannelUpgradeConfirm { + port_id: "p36".to_string(), + ..default_raw_msg.clone() + }, + want_pass: true, + }, + Test { + name: "Port too short".to_string(), + raw: RawMsgChannelUpgradeConfirm { + port_id: "p".to_string(), + ..default_raw_msg.clone() + }, + want_pass: false, + }, + Test { + name: "Port too long".to_string(), + raw: RawMsgChannelUpgradeConfirm { + port_id: "abcdefsdfasdfasdfasdfasdfasdfadsfasdgafsgadfasdfasdfasdfsdfasdfaghijklmnopqrstuabcdefsdfasdfasdfasdfasdfasdfadsfasdgafsgadfasdfasdfasdfsdfasdfaghijklmnopqrstu".to_string(), + ..default_raw_msg.clone() + }, + want_pass: false, + }, + Test { + name: "Correct channel ID".to_string(), + raw: RawMsgChannelUpgradeConfirm { + channel_id: "channel-2".to_string(), + ..default_raw_msg.clone() + }, + want_pass: true, + }, + Test { + name: "Channel name too short".to_string(), + raw: RawMsgChannelUpgradeConfirm { + channel_id: "c".to_string(), + ..default_raw_msg.clone() + }, + want_pass: false, + }, + Test { + name: "Channel name too long".to_string(), + raw: RawMsgChannelUpgradeConfirm { + channel_id: "channel-128391283791827398127398791283912837918273981273987912839".to_string(), + ..default_raw_msg.clone() + }, + want_pass: false, + }, + Test { + name: "Empty proof channel".to_string(), + raw: RawMsgChannelUpgradeConfirm { + proof_channel: vec![], + ..default_raw_msg + }, + want_pass: false, + }, + ] + .into_iter() + .collect(); + + for test in tests { + let res = MsgChannelUpgradeConfirm::try_from(test.raw.clone()); + + assert_eq!( + test.want_pass, + res.is_ok(), + "MsgChannelUpgradeConfirm::try_from failed for test {}, \nraw msg {:?} with err {:?}", + test.name, + test.raw, + res.err() + ); + } + } + + #[test] + fn to_and_from() { + let raw = get_dummy_raw_msg_chan_upgrade_confirm(); + let msg = MsgChannelUpgradeConfirm::try_from(raw.clone()).unwrap(); + let raw_back = RawMsgChannelUpgradeConfirm::from(msg.clone()); + let msg_back = MsgChannelUpgradeConfirm::try_from(raw_back.clone()).unwrap(); + assert_eq!(raw, raw_back); + assert_eq!(msg, msg_back); + } +} diff --git a/crates/relayer-types/src/core/ics04_channel/msgs/chan_upgrade_init.rs b/crates/relayer-types/src/core/ics04_channel/msgs/chan_upgrade_init.rs new file mode 100644 index 0000000000..df696905d5 --- /dev/null +++ b/crates/relayer-types/src/core/ics04_channel/msgs/chan_upgrade_init.rs @@ -0,0 +1,200 @@ +use crate::core::ics04_channel::upgrade_fields::UpgradeFields; + +use ibc_proto::ibc::core::channel::v1::MsgChannelUpgradeInit as RawMsgChannelUpgradeInit; +use ibc_proto::Protobuf; + +use crate::core::ics04_channel::error::Error; +use crate::core::ics24_host::identifier::{ChannelId, PortId}; +use crate::signer::Signer; +use crate::tx_msg::Msg; + +pub const TYPE_URL: &str = "/ibc.core.channel.v1.MsgChannelUpgradeInit"; + +/// Message definition for the first step in the channel +/// upgrade handshake (`ChanUpgradeInit` datagram). +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct MsgChannelUpgradeInit { + pub port_id: PortId, + pub channel_id: ChannelId, + pub fields: UpgradeFields, + pub signer: Signer, +} + +impl MsgChannelUpgradeInit { + pub fn new( + port_id: PortId, + channel_id: ChannelId, + fields: UpgradeFields, + signer: Signer, + ) -> Self { + Self { + port_id, + channel_id, + fields, + signer, + } + } +} + +impl Msg for MsgChannelUpgradeInit { + type ValidationError = Error; + type Raw = RawMsgChannelUpgradeInit; + + fn route(&self) -> String { + crate::keys::ROUTER_KEY.to_string() + } + + fn type_url(&self) -> String { + TYPE_URL.to_string() + } +} + +impl Protobuf for MsgChannelUpgradeInit {} + +impl TryFrom for MsgChannelUpgradeInit { + type Error = Error; + + fn try_from(raw_msg: RawMsgChannelUpgradeInit) -> Result { + let raw_fields = raw_msg.fields.ok_or(Error::missing_upgrade_fields())?; + let fields = UpgradeFields::try_from(raw_fields)?; + + Ok(MsgChannelUpgradeInit { + port_id: raw_msg.port_id.parse().map_err(Error::identifier)?, + channel_id: raw_msg.channel_id.parse().map_err(Error::identifier)?, + signer: raw_msg.signer.parse().map_err(Error::signer)?, + fields, + }) + } +} + +impl From for RawMsgChannelUpgradeInit { + fn from(domain_msg: MsgChannelUpgradeInit) -> Self { + Self { + port_id: domain_msg.port_id.to_string(), + channel_id: domain_msg.channel_id.to_string(), + signer: domain_msg.signer.to_string(), + fields: Some(domain_msg.fields.into()), + } + } +} + +#[cfg(test)] +pub mod test_util { + use ibc_proto::ibc::core::channel::v1::MsgChannelUpgradeInit as RawMsgChannelUpgradeInit; + + use crate::core::ics04_channel::upgrade_fields::test_util::get_dummy_upgrade_fields; + use crate::core::ics24_host::identifier::{ChannelId, PortId}; + use crate::test_utils::get_dummy_bech32_account; + + /// Returns a dummy `RawMsgChannelUpgadeInit`, for testing only! + pub fn get_dummy_raw_msg_chan_upgrade_init() -> RawMsgChannelUpgradeInit { + RawMsgChannelUpgradeInit { + port_id: PortId::default().to_string(), + channel_id: ChannelId::default().to_string(), + signer: get_dummy_bech32_account(), + fields: Some(get_dummy_upgrade_fields()), + } + } +} + +#[cfg(test)] +mod tests { + use test_log::test; + + use ibc_proto::ibc::core::channel::v1::MsgChannelUpgradeInit as RawMsgChannelUpgradeInit; + + use crate::core::ics04_channel::msgs::chan_upgrade_init::test_util::get_dummy_raw_msg_chan_upgrade_init; + use crate::core::ics04_channel::msgs::chan_upgrade_init::MsgChannelUpgradeInit; + + #[test] + fn parse_channel_upgrade_init_msg() { + struct Test { + name: String, + raw: RawMsgChannelUpgradeInit, + want_pass: bool, + } + + let default_raw_msg = get_dummy_raw_msg_chan_upgrade_init(); + + let tests: Vec = vec![ + Test { + name: "Good parameters".to_string(), + raw: default_raw_msg.clone(), + want_pass: true, + }, + Test { + name: "Correct port ID".to_string(), + raw: RawMsgChannelUpgradeInit { + port_id: "p36".to_string(), + ..default_raw_msg.clone() + }, + want_pass: true, + }, + Test { + name: "Port too short".to_string(), + raw: RawMsgChannelUpgradeInit { + port_id: "p".to_string(), + ..default_raw_msg.clone() + }, + want_pass: false, + }, + Test { + name: "Port too long".to_string(), + raw: RawMsgChannelUpgradeInit { + port_id: "abcdefsdfasdfasdfasdfasdfasdfadsfasdgafsgadfasdfasdfasdfsdfasdfaghijklmnopqrstuabcdefsdfasdfasdfasdfasdfasdfadsfasdgafsgadfasdfasdfasdfsdfasdfaghijklmnopqrstu".to_string(), + ..default_raw_msg.clone() + }, + want_pass: false, + }, + Test { + name: "Correct channel ID".to_string(), + raw: RawMsgChannelUpgradeInit { + channel_id: "channel-2".to_string(), + ..default_raw_msg.clone() + }, + want_pass: true, + }, + Test { + name: "Channel name too short".to_string(), + raw: RawMsgChannelUpgradeInit { + channel_id: "c".to_string(), + ..default_raw_msg.clone() + }, + want_pass: false, + }, + Test { + name: "Channel name too long".to_string(), + raw: RawMsgChannelUpgradeInit { + channel_id: "channel-128391283791827398127398791283912837918273981273987912839".to_string(), + ..default_raw_msg.clone() + }, + want_pass: false, + }, + ] + .into_iter() + .collect(); + + for test in tests { + let res = MsgChannelUpgradeInit::try_from(test.raw.clone()); + + assert_eq!( + test.want_pass, + res.is_ok(), + "MsgChannelUpgradeInit::try_from failed for test {}, \nraw msg {:?} with err {:?}", + test.name, + test.raw, + res.err() + ); + } + } + + #[test] + fn to_and_from() { + let raw = get_dummy_raw_msg_chan_upgrade_init(); + let msg = MsgChannelUpgradeInit::try_from(raw.clone()).unwrap(); + let raw_back = RawMsgChannelUpgradeInit::from(msg.clone()); + let msg_back = MsgChannelUpgradeInit::try_from(raw_back.clone()).unwrap(); + assert_eq!(raw, raw_back); + assert_eq!(msg, msg_back); + } +} diff --git a/crates/relayer-types/src/core/ics04_channel/msgs/chan_upgrade_open.rs b/crates/relayer-types/src/core/ics04_channel/msgs/chan_upgrade_open.rs new file mode 100644 index 0000000000..36bac21367 --- /dev/null +++ b/crates/relayer-types/src/core/ics04_channel/msgs/chan_upgrade_open.rs @@ -0,0 +1,240 @@ +use ibc_proto::ibc::core::channel::v1::MsgChannelUpgradeOpen as RawMsgChannelUpgradeOpen; +use ibc_proto::Protobuf; + +use crate::core::ics04_channel::channel::State; +use crate::core::ics04_channel::error::Error; +use crate::core::ics04_channel::packet::Sequence; +use crate::core::ics23_commitment::commitment::CommitmentProofBytes; +use crate::core::ics24_host::identifier::{ChannelId, PortId}; +use crate::signer::Signer; +use crate::tx_msg::Msg; +use crate::Height; + +pub const TYPE_URL: &str = "/ibc.core.channel.v1.MsgChannelUpgradeOpen"; + +/// Message definition for the last step of the channel upgrade +/// handshake (the `ChanUpgradeOpen` datagram). +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct MsgChannelUpgradeOpen { + pub port_id: PortId, + pub channel_id: ChannelId, + pub counterparty_channel_state: State, + pub counterparty_upgrade_sequence: Sequence, + /// The proof of the counterparty channel + pub proof_channel: CommitmentProofBytes, + /// The height at which the proofs were queried. + pub proof_height: Height, + pub signer: Signer, +} + +impl MsgChannelUpgradeOpen { + #[allow(clippy::too_many_arguments)] + pub fn new( + port_id: PortId, + channel_id: ChannelId, + counterparty_channel_state: State, + counterparty_upgrade_sequence: Sequence, + proof_channel: CommitmentProofBytes, + proof_height: Height, + signer: Signer, + ) -> Self { + Self { + port_id, + channel_id, + counterparty_channel_state, + counterparty_upgrade_sequence, + proof_channel, + proof_height, + signer, + } + } +} + +impl Msg for MsgChannelUpgradeOpen { + type ValidationError = Error; + type Raw = RawMsgChannelUpgradeOpen; + + fn route(&self) -> String { + crate::keys::ROUTER_KEY.to_string() + } + + fn type_url(&self) -> String { + TYPE_URL.to_string() + } +} + +impl Protobuf for MsgChannelUpgradeOpen {} + +impl TryFrom for MsgChannelUpgradeOpen { + type Error = Error; + + fn try_from(raw_msg: RawMsgChannelUpgradeOpen) -> Result { + let proof_height = raw_msg + .proof_height + .ok_or_else(Error::missing_proof_height)? + .try_into() + .map_err(|_| Error::invalid_proof_height())?; + + Ok(MsgChannelUpgradeOpen { + port_id: raw_msg.port_id.parse().map_err(Error::identifier)?, + channel_id: raw_msg.channel_id.parse().map_err(Error::identifier)?, + counterparty_channel_state: State::from_i32(raw_msg.counterparty_channel_state)?, + counterparty_upgrade_sequence: raw_msg.counterparty_upgrade_sequence.into(), + proof_channel: raw_msg + .proof_channel + .try_into() + .map_err(Error::invalid_proof)?, + proof_height, + signer: raw_msg.signer.parse().map_err(Error::signer)?, + }) + } +} + +impl From for RawMsgChannelUpgradeOpen { + fn from(domain_msg: MsgChannelUpgradeOpen) -> Self { + RawMsgChannelUpgradeOpen { + port_id: domain_msg.port_id.to_string(), + channel_id: domain_msg.channel_id.to_string(), + counterparty_channel_state: domain_msg.counterparty_channel_state.as_i32(), + counterparty_upgrade_sequence: domain_msg.counterparty_upgrade_sequence.into(), + proof_channel: domain_msg.proof_channel.into(), + proof_height: Some(domain_msg.proof_height.into()), + signer: domain_msg.signer.to_string(), + } + } +} + +#[cfg(test)] +pub mod test_util { + use ibc_proto::ibc::core::channel::v1::MsgChannelUpgradeOpen as RawMsgChannelUpgradeOpen; + use ibc_proto::ibc::core::client::v1::Height as RawHeight; + + use crate::core::ics24_host::identifier::{ChannelId, PortId}; + use crate::test_utils::{get_dummy_bech32_account, get_dummy_proof}; + + /// Returns a dummy `RawMsgChannelUpgradeOpen`, for testing only! + pub fn get_dummy_raw_msg_chan_upgrade_open() -> RawMsgChannelUpgradeOpen { + RawMsgChannelUpgradeOpen { + port_id: PortId::default().to_string(), + channel_id: ChannelId::default().to_string(), + counterparty_channel_state: 6, // FlushComplete + counterparty_upgrade_sequence: 1, + proof_channel: get_dummy_proof(), + proof_height: Some(RawHeight { + revision_number: 1, + revision_height: 1, + }), + signer: get_dummy_bech32_account(), + } + } +} + +#[cfg(test)] +mod tests { + use test_log::test; + + use ibc_proto::ibc::core::channel::v1::MsgChannelUpgradeOpen as RawMsgChannelUpgradeOpen; + + use crate::core::ics04_channel::msgs::chan_upgrade_open::test_util::get_dummy_raw_msg_chan_upgrade_open; + use crate::core::ics04_channel::msgs::chan_upgrade_open::MsgChannelUpgradeOpen; + + #[test] + fn parse_channel_upgrade_try_msg() { + struct Test { + name: String, + raw: RawMsgChannelUpgradeOpen, + want_pass: bool, + } + + let default_raw_msg = get_dummy_raw_msg_chan_upgrade_open(); + + let tests: Vec = vec![ + Test { + name: "Good parameters".to_string(), + raw: default_raw_msg.clone(), + want_pass: true, + }, + Test { + name: "Correct port ID".to_string(), + raw: RawMsgChannelUpgradeOpen { + port_id: "p36".to_string(), + ..default_raw_msg.clone() + }, + want_pass: true, + }, + Test { + name: "Port too short".to_string(), + raw: RawMsgChannelUpgradeOpen { + port_id: "p".to_string(), + ..default_raw_msg.clone() + }, + want_pass: false, + }, + Test { + name: "Port too long".to_string(), + raw: RawMsgChannelUpgradeOpen { + port_id: "abcdefsdfasdfasdfasdfasdfasdfadsfasdgafsgadfasdfasdfasdfsdfasdfaghijklmnopqrstuabcdefsdfasdfasdfasdfasdfasdfadsfasdgafsgadfasdfasdfasdfsdfasdfaghijklmnopqrstu".to_string(), + ..default_raw_msg.clone() + }, + want_pass: false, + }, + Test { + name: "Correct channel ID".to_string(), + raw: RawMsgChannelUpgradeOpen { + channel_id: "channel-2".to_string(), + ..default_raw_msg.clone() + }, + want_pass: true, + }, + Test { + name: "Channel name too short".to_string(), + raw: RawMsgChannelUpgradeOpen { + channel_id: "c".to_string(), + ..default_raw_msg.clone() + }, + want_pass: false, + }, + Test { + name: "Channel name too long".to_string(), + raw: RawMsgChannelUpgradeOpen { + channel_id: "channel-128391283791827398127398791283912837918273981273987912839".to_string(), + ..default_raw_msg.clone() + }, + want_pass: false, + }, + Test { + name: "Empty proof channel".to_string(), + raw: RawMsgChannelUpgradeOpen { + proof_channel: vec![], + ..default_raw_msg + }, + want_pass: false, + }, + ] + .into_iter() + .collect(); + + for test in tests { + let res = MsgChannelUpgradeOpen::try_from(test.raw.clone()); + + assert_eq!( + test.want_pass, + res.is_ok(), + "MsgChannelUpgradeOpen::try_from failed for test {}, \nraw msg {:?} with err {:?}", + test.name, + test.raw, + res.err() + ); + } + } + + #[test] + fn to_and_from() { + let raw = get_dummy_raw_msg_chan_upgrade_open(); + let msg = MsgChannelUpgradeOpen::try_from(raw.clone()).unwrap(); + let raw_back = RawMsgChannelUpgradeOpen::from(msg.clone()); + let msg_back = MsgChannelUpgradeOpen::try_from(raw_back.clone()).unwrap(); + assert_eq!(raw, raw_back); + assert_eq!(msg, msg_back); + } +} diff --git a/crates/relayer-types/src/core/ics04_channel/msgs/chan_upgrade_timeout.rs b/crates/relayer-types/src/core/ics04_channel/msgs/chan_upgrade_timeout.rs new file mode 100644 index 0000000000..e6bbe74fd9 --- /dev/null +++ b/crates/relayer-types/src/core/ics04_channel/msgs/chan_upgrade_timeout.rs @@ -0,0 +1,258 @@ +use ibc_proto::ibc::core::channel::v1::MsgChannelUpgradeTimeout as RawMsgChannelUpgradeTimeout; +use ibc_proto::Protobuf; + +use crate::core::ics04_channel::channel::ChannelEnd; +use crate::core::ics04_channel::error::Error; +use crate::core::ics23_commitment::commitment::CommitmentProofBytes; +use crate::core::ics24_host::identifier::{ChannelId, PortId}; +use crate::signer::Signer; +use crate::tx_msg::Msg; +use crate::Height; + +pub const TYPE_URL: &str = "/ibc.core.channel.v1.MsgChannelUpgradeTimeout"; + +/// Message definition the `ChanUpgradeTimeout` datagram. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct MsgChannelUpgradeTimeout { + pub port_id: PortId, + pub channel_id: ChannelId, + pub counterparty_channel: ChannelEnd, + /// The proof of the counterparty channel + pub proof_channel: CommitmentProofBytes, + /// The height at which the proofs were queried. + pub proof_height: Height, + pub signer: Signer, +} + +impl MsgChannelUpgradeTimeout { + #[allow(clippy::too_many_arguments)] + pub fn new( + port_id: PortId, + channel_id: ChannelId, + counterparty_channel: ChannelEnd, + proof_channel: CommitmentProofBytes, + proof_height: Height, + signer: Signer, + ) -> Self { + Self { + port_id, + channel_id, + counterparty_channel, + proof_channel, + proof_height, + signer, + } + } +} + +impl Msg for MsgChannelUpgradeTimeout { + type ValidationError = Error; + type Raw = RawMsgChannelUpgradeTimeout; + + fn route(&self) -> String { + crate::keys::ROUTER_KEY.to_string() + } + + fn type_url(&self) -> String { + TYPE_URL.to_string() + } +} + +impl Protobuf for MsgChannelUpgradeTimeout {} + +impl TryFrom for MsgChannelUpgradeTimeout { + type Error = Error; + + fn try_from(raw_msg: RawMsgChannelUpgradeTimeout) -> Result { + let raw_counterparty_channel = raw_msg + .counterparty_channel + .ok_or(Error::missing_channel())?; + let counterparty_channel = ChannelEnd::try_from(raw_counterparty_channel)?; + + let proof_height = raw_msg + .proof_height + .ok_or_else(Error::missing_proof_height)? + .try_into() + .map_err(|_| Error::invalid_proof_height())?; + + Ok(MsgChannelUpgradeTimeout { + port_id: raw_msg.port_id.parse().map_err(Error::identifier)?, + channel_id: raw_msg.channel_id.parse().map_err(Error::identifier)?, + counterparty_channel, + proof_channel: raw_msg + .proof_channel + .try_into() + .map_err(Error::invalid_proof)?, + proof_height, + signer: raw_msg.signer.parse().map_err(Error::signer)?, + }) + } +} + +impl From for RawMsgChannelUpgradeTimeout { + fn from(domain_msg: MsgChannelUpgradeTimeout) -> Self { + RawMsgChannelUpgradeTimeout { + port_id: domain_msg.port_id.to_string(), + channel_id: domain_msg.channel_id.to_string(), + counterparty_channel: Some(domain_msg.counterparty_channel.into()), + proof_channel: domain_msg.proof_channel.into(), + proof_height: Some(domain_msg.proof_height.into()), + signer: domain_msg.signer.to_string(), + } + } +} + +#[cfg(test)] +pub mod test_util { + use crate::core::ics04_channel::channel::test_util::get_dummy_raw_channel_end; + use ibc_proto::ibc::core::channel::v1::MsgChannelUpgradeTimeout as RawMsgChannelUpgradeTimeout; + use ibc_proto::ibc::core::client::v1::Height as RawHeight; + + use crate::core::ics24_host::identifier::{ChannelId, PortId}; + use crate::test_utils::{get_dummy_bech32_account, get_dummy_proof}; + + /// Returns a dummy `RawMsgChannelUpgradeCnacel`, for testing only! + pub fn get_dummy_raw_msg_chan_upgrade_timeout() -> RawMsgChannelUpgradeTimeout { + RawMsgChannelUpgradeTimeout { + port_id: PortId::default().to_string(), + channel_id: ChannelId::default().to_string(), + counterparty_channel: Some(get_dummy_raw_channel_end()), + proof_channel: get_dummy_proof(), + proof_height: Some(RawHeight { + revision_number: 1, + revision_height: 1, + }), + signer: get_dummy_bech32_account(), + } + } +} + +#[cfg(test)] +mod tests { + use test_log::test; + + use ibc_proto::ibc::core::channel::v1::MsgChannelUpgradeTimeout as RawMsgChannelUpgradeTimeout; + use ibc_proto::ibc::core::client::v1::Height; + + use crate::core::ics04_channel::msgs::chan_upgrade_timeout::test_util::get_dummy_raw_msg_chan_upgrade_timeout; + use crate::core::ics04_channel::msgs::chan_upgrade_timeout::MsgChannelUpgradeTimeout; + + #[test] + fn parse_channel_upgrade_try_msg() { + struct Test { + name: String, + raw: RawMsgChannelUpgradeTimeout, + want_pass: bool, + } + + let default_raw_msg = get_dummy_raw_msg_chan_upgrade_timeout(); + + let tests: Vec = vec![ + Test { + name: "Good parameters".to_string(), + raw: default_raw_msg.clone(), + want_pass: true, + }, + Test { + name: "Correct port ID".to_string(), + raw: RawMsgChannelUpgradeTimeout { + port_id: "p36".to_string(), + ..default_raw_msg.clone() + }, + want_pass: true, + }, + Test { + name: "Port too short".to_string(), + raw: RawMsgChannelUpgradeTimeout { + port_id: "p".to_string(), + ..default_raw_msg.clone() + }, + want_pass: false, + }, + Test { + name: "Port too long".to_string(), + raw: RawMsgChannelUpgradeTimeout { + port_id: "abcdefsdfasdfasdfasdfasdfasdfadsfasdgafsgadfasdfasdfasdfsdfasdfaghijklmnopqrstuabcdefsdfasdfasdfasdfasdfasdfadsfasdgafsgadfasdfasdfasdfsdfasdfaghijklmnopqrstu".to_string(), + ..default_raw_msg.clone() + }, + want_pass: false, + }, + Test { + name: "Correct channel ID".to_string(), + raw: RawMsgChannelUpgradeTimeout { + channel_id: "channel-2".to_string(), + ..default_raw_msg.clone() + }, + want_pass: true, + }, + Test { + name: "Channel name too short".to_string(), + raw: RawMsgChannelUpgradeTimeout { + channel_id: "c".to_string(), + ..default_raw_msg.clone() + }, + want_pass: false, + }, + Test { + name: "Channel name too long".to_string(), + raw: RawMsgChannelUpgradeTimeout { + channel_id: "channel-128391283791827398127398791283912837918273981273987912839".to_string(), + ..default_raw_msg.clone() + }, + want_pass: false, + }, + Test { + name: "Empty proof channel".to_string(), + raw: RawMsgChannelUpgradeTimeout { + proof_channel: vec![], + ..default_raw_msg.clone() + }, + want_pass: false, + }, + Test { + name: "Bad proof height, height = 0".to_string(), + raw: RawMsgChannelUpgradeTimeout { + proof_height: Some(Height { + revision_number: 0, + revision_height: 0, + }), + ..default_raw_msg.clone() + }, + want_pass: false, + }, + Test { + name: "Missing proof height".to_string(), + raw: RawMsgChannelUpgradeTimeout { + proof_height: None, + ..default_raw_msg.clone() + }, + want_pass: false, + }, + ] + .into_iter() + .collect(); + + for test in tests { + let res = MsgChannelUpgradeTimeout::try_from(test.raw.clone()); + + assert_eq!( + test.want_pass, + res.is_ok(), + "RawMsgChannelUpgradeTimeout::try_from failed for test {}, \nraw msg {:?} with err {:?}", + test.name, + test.raw, + res.err() + ); + } + } + + #[test] + fn to_and_from() { + let raw = get_dummy_raw_msg_chan_upgrade_timeout(); + let msg = MsgChannelUpgradeTimeout::try_from(raw.clone()).unwrap(); + let raw_back = RawMsgChannelUpgradeTimeout::from(msg.clone()); + let msg_back = MsgChannelUpgradeTimeout::try_from(raw_back.clone()).unwrap(); + assert_eq!(raw, raw_back); + assert_eq!(msg, msg_back); + } +} diff --git a/crates/relayer-types/src/core/ics04_channel/msgs/chan_upgrade_try.rs b/crates/relayer-types/src/core/ics04_channel/msgs/chan_upgrade_try.rs new file mode 100644 index 0000000000..fa4c2333f9 --- /dev/null +++ b/crates/relayer-types/src/core/ics04_channel/msgs/chan_upgrade_try.rs @@ -0,0 +1,276 @@ +use crate::core::ics04_channel::packet::Sequence; +use crate::core::ics04_channel::upgrade_fields::UpgradeFields; +use crate::Height; + +use ibc_proto::Protobuf; + +use ibc_proto::ibc::core::channel::v1::MsgChannelUpgradeTry as RawMsgChannelUpgradeTry; + +use crate::core::ics04_channel::error::Error; +use crate::core::ics23_commitment::commitment::CommitmentProofBytes; +use crate::core::ics24_host::identifier::{ChannelId, ConnectionId, PortId}; +use crate::signer::Signer; +use crate::tx_msg::Msg; + +pub const TYPE_URL: &str = "/ibc.core.channel.v1.MsgChannelUpgradeTry"; + +/// Message definition for the second step of the channel upgrade +/// handshake (the `ChanUpgradeTry` datagram). +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct MsgChannelUpgradeTry { + pub port_id: PortId, + pub channel_id: ChannelId, + pub proposed_upgrade_connection_hops: Vec, + pub counterparty_upgrade_fields: UpgradeFields, + pub counterparty_upgrade_sequence: Sequence, + /// The proof of the counterparty channel + pub proof_channel: CommitmentProofBytes, + /// The proof of the counterparty upgrade + pub proof_upgrade: CommitmentProofBytes, + /// The height at which the proofs were queried. + pub proof_height: Height, + pub signer: Signer, +} + +impl MsgChannelUpgradeTry { + #[allow(clippy::too_many_arguments)] + pub fn new( + port_id: PortId, + channel_id: ChannelId, + proposed_upgrade_connection_hops: Vec, + counterparty_upgrade_fields: UpgradeFields, + counterparty_upgrade_sequence: Sequence, + proof_channel: CommitmentProofBytes, + proof_upgrade: CommitmentProofBytes, + proof_height: Height, + signer: Signer, + ) -> Self { + Self { + port_id, + channel_id, + proposed_upgrade_connection_hops, + counterparty_upgrade_fields, + counterparty_upgrade_sequence, + proof_channel, + proof_upgrade, + proof_height, + signer, + } + } +} + +impl Msg for MsgChannelUpgradeTry { + type ValidationError = Error; + type Raw = RawMsgChannelUpgradeTry; + + fn route(&self) -> String { + crate::keys::ROUTER_KEY.to_string() + } + + fn type_url(&self) -> String { + TYPE_URL.to_string() + } +} + +impl Protobuf for MsgChannelUpgradeTry {} + +impl TryFrom for MsgChannelUpgradeTry { + type Error = Error; + + fn try_from(raw_msg: RawMsgChannelUpgradeTry) -> Result { + let proposed_upgrade_connection_hops: Result, Error> = raw_msg + .proposed_upgrade_connection_hops + .iter() + .map(|hop| hop.parse().map_err(Error::identifier)) + .collect(); + let counterparty_upgrade_fields = raw_msg + .counterparty_upgrade_fields + .ok_or(Error::missing_upgrade_fields())? + .try_into()?; + let counterparty_upgrade_sequence = raw_msg.counterparty_upgrade_sequence.into(); + + let proof_height = raw_msg + .proof_height + .ok_or_else(Error::missing_proof_height)? + .try_into() + .map_err(|_| Error::invalid_proof_height())?; + + Ok(MsgChannelUpgradeTry { + port_id: raw_msg.port_id.parse().map_err(Error::identifier)?, + channel_id: raw_msg.channel_id.parse().map_err(Error::identifier)?, + proposed_upgrade_connection_hops: proposed_upgrade_connection_hops?, + counterparty_upgrade_fields, + counterparty_upgrade_sequence, + proof_channel: raw_msg + .proof_channel + .try_into() + .map_err(Error::invalid_proof)?, + proof_upgrade: raw_msg + .proof_upgrade + .try_into() + .map_err(Error::invalid_proof)?, + proof_height, + signer: raw_msg.signer.parse().map_err(Error::signer)?, + }) + } +} + +impl From for RawMsgChannelUpgradeTry { + fn from(domain_msg: MsgChannelUpgradeTry) -> Self { + let proposed_upgrade_connection_hops = domain_msg + .proposed_upgrade_connection_hops + .into_iter() + .map(|hop| hop.to_string()) + .collect(); + + RawMsgChannelUpgradeTry { + port_id: domain_msg.port_id.to_string(), + channel_id: domain_msg.channel_id.to_string(), + proposed_upgrade_connection_hops, + counterparty_upgrade_fields: Some(domain_msg.counterparty_upgrade_fields.into()), + counterparty_upgrade_sequence: domain_msg.counterparty_upgrade_sequence.into(), + proof_upgrade: domain_msg.proof_upgrade.into(), + proof_channel: domain_msg.proof_channel.into(), + proof_height: Some(domain_msg.proof_height.into()), + signer: domain_msg.signer.to_string(), + } + } +} + +#[cfg(test)] +pub mod test_util { + use ibc_proto::ibc::core::channel::v1::MsgChannelUpgradeTry as RawMsgChannelUpgradeTry; + use ibc_proto::ibc::core::client::v1::Height as RawHeight; + + use crate::core::ics04_channel::upgrade_fields::test_util::get_dummy_upgrade_fields; + use crate::core::ics24_host::identifier::{ChannelId, PortId}; + use crate::test_utils::{get_dummy_bech32_account, get_dummy_proof}; + + /// Returns a dummy `RawMsgChannelUpgradeTry`, for testing only! + pub fn get_dummy_raw_msg_chan_upgrade_try() -> RawMsgChannelUpgradeTry { + RawMsgChannelUpgradeTry { + port_id: PortId::default().to_string(), + channel_id: ChannelId::default().to_string(), + proposed_upgrade_connection_hops: vec![], + counterparty_upgrade_fields: Some(get_dummy_upgrade_fields()), + counterparty_upgrade_sequence: 1, + proof_upgrade: get_dummy_proof(), + proof_channel: get_dummy_proof(), + proof_height: Some(RawHeight { + revision_number: 1, + revision_height: 1, + }), + signer: get_dummy_bech32_account(), + } + } +} + +#[cfg(test)] +mod tests { + use test_log::test; + + use ibc_proto::ibc::core::channel::v1::MsgChannelUpgradeTry as RawMsgChannelUpgradeTry; + + use crate::core::ics04_channel::msgs::chan_upgrade_try::test_util::get_dummy_raw_msg_chan_upgrade_try; + use crate::core::ics04_channel::msgs::chan_upgrade_try::MsgChannelUpgradeTry; + + #[test] + fn parse_channel_upgrade_try_msg() { + struct Test { + name: String, + raw: RawMsgChannelUpgradeTry, + want_pass: bool, + } + + let default_raw_msg = get_dummy_raw_msg_chan_upgrade_try(); + + let tests: Vec = vec![ + Test { + name: "Good parameters".to_string(), + raw: default_raw_msg.clone(), + want_pass: true, + }, + Test { + name: "Correct port ID".to_string(), + raw: RawMsgChannelUpgradeTry { + port_id: "p36".to_string(), + ..default_raw_msg.clone() + }, + want_pass: true, + }, + Test { + name: "Port too short".to_string(), + raw: RawMsgChannelUpgradeTry { + port_id: "p".to_string(), + ..default_raw_msg.clone() + }, + want_pass: false, + }, + Test { + name: "Port too long".to_string(), + raw: RawMsgChannelUpgradeTry { + port_id: "abcdefsdfasdfasdfasdfasdfasdfadsfasdgafsgadfasdfasdfasdfsdfasdfaghijklmnopqrstuabcdefsdfasdfasdfasdfasdfasdfadsfasdgafsgadfasdfasdfasdfsdfasdfaghijklmnopqrstu".to_string(), + ..default_raw_msg.clone() + }, + want_pass: false, + }, + Test { + name: "Correct channel ID".to_string(), + raw: RawMsgChannelUpgradeTry { + channel_id: "channel-2".to_string(), + ..default_raw_msg.clone() + }, + want_pass: true, + }, + Test { + name: "Channel name too short".to_string(), + raw: RawMsgChannelUpgradeTry { + channel_id: "c".to_string(), + ..default_raw_msg.clone() + }, + want_pass: false, + }, + Test { + name: "Channel name too long".to_string(), + raw: RawMsgChannelUpgradeTry { + channel_id: "channel-128391283791827398127398791283912837918273981273987912839".to_string(), + ..default_raw_msg.clone() + }, + want_pass: false, + }, + Test { + name: "Empty proof channel".to_string(), + raw: RawMsgChannelUpgradeTry { + proof_channel: vec![], + ..default_raw_msg + }, + want_pass: false, + }, + ] + .into_iter() + .collect(); + + for test in tests { + let res = MsgChannelUpgradeTry::try_from(test.raw.clone()); + + assert_eq!( + test.want_pass, + res.is_ok(), + "MsgChannelUpgradeTry::try_from failed for test {}, \nraw msg {:?} with err {:?}", + test.name, + test.raw, + res.err() + ); + } + } + + #[test] + fn to_and_from() { + let raw = get_dummy_raw_msg_chan_upgrade_try(); + let msg = MsgChannelUpgradeTry::try_from(raw.clone()).unwrap(); + let raw_back = RawMsgChannelUpgradeTry::from(msg.clone()); + let msg_back = MsgChannelUpgradeTry::try_from(raw_back.clone()).unwrap(); + assert_eq!(raw, raw_back); + assert_eq!(msg, msg_back); + } +} diff --git a/crates/relayer-types/src/core/ics04_channel/msgs/timeout_on_close.rs b/crates/relayer-types/src/core/ics04_channel/msgs/timeout_on_close.rs index 8d6fc5e970..17a47fe2a0 100644 --- a/crates/relayer-types/src/core/ics04_channel/msgs/timeout_on_close.rs +++ b/crates/relayer-types/src/core/ics04_channel/msgs/timeout_on_close.rs @@ -18,6 +18,7 @@ pub struct MsgTimeoutOnClose { pub next_sequence_recv: Sequence, pub proofs: Proofs, pub signer: Signer, + pub counterparty_upgrade_sequence: Sequence, } impl MsgTimeoutOnClose { @@ -26,12 +27,14 @@ impl MsgTimeoutOnClose { next_sequence_recv: Sequence, proofs: Proofs, signer: Signer, + counterparty_upgrade_sequence: Sequence, ) -> MsgTimeoutOnClose { Self { packet, next_sequence_recv, proofs, signer, + counterparty_upgrade_sequence, } } } @@ -86,6 +89,7 @@ impl TryFrom for MsgTimeoutOnClose { next_sequence_recv: Sequence::from(raw_msg.next_sequence_recv), signer: raw_msg.signer.parse().map_err(Error::signer)?, proofs, + counterparty_upgrade_sequence: raw_msg.counterparty_upgrade_sequence.into(), }) } } @@ -102,6 +106,7 @@ impl From for RawMsgTimeoutOnClose { proof_height: Some(domain_msg.proofs.height().into()), next_sequence_recv: domain_msg.next_sequence_recv.into(), signer: domain_msg.signer.to_string(), + counterparty_upgrade_sequence: domain_msg.counterparty_upgrade_sequence.into(), } } } @@ -217,6 +222,7 @@ pub mod test_util { }), next_sequence_recv: 1, signer: get_dummy_bech32_account(), + counterparty_upgrade_sequence: 0, } } } diff --git a/crates/relayer-types/src/core/ics04_channel/packet.rs b/crates/relayer-types/src/core/ics04_channel/packet.rs index 316227c08f..28babd7d43 100644 --- a/crates/relayer-types/src/core/ics04_channel/packet.rs +++ b/crates/relayer-types/src/core/ics04_channel/packet.rs @@ -129,7 +129,7 @@ pub struct Packet { struct PacketData<'a>(&'a [u8]); -impl<'a> core::fmt::Debug for PacketData<'a> { +impl core::fmt::Debug for PacketData<'_> { fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { write!(formatter, "{:?}", self.0) } diff --git a/crates/relayer-types/src/core/ics04_channel/packet_id.rs b/crates/relayer-types/src/core/ics04_channel/packet_id.rs index d492d0a80a..f55d2aa2cc 100644 --- a/crates/relayer-types/src/core/ics04_channel/packet_id.rs +++ b/crates/relayer-types/src/core/ics04_channel/packet_id.rs @@ -1,5 +1,4 @@ use ibc_proto::ibc::core::channel::v1::PacketId as ProtoPacketId; -use std::convert::TryFrom; use std::str::FromStr; use crate::core::ics04_channel::error::Error; diff --git a/crates/relayer-types/src/core/ics04_channel/timeout.rs b/crates/relayer-types/src/core/ics04_channel/timeout.rs index aa33ec23b1..cee5f40601 100644 --- a/crates/relayer-types/src/core/ics04_channel/timeout.rs +++ b/crates/relayer-types/src/core/ics04_channel/timeout.rs @@ -1,10 +1,16 @@ -use std::fmt::{Display, Error as FmtError, Formatter}; +use core::fmt::{Display, Error as FmtError, Formatter}; +use std::str::FromStr; +use flex_error::{define_error, TraceError}; use serde::{Deserialize, Serialize}; +use ibc_proto::ibc::core::channel::v1::Timeout as RawTimeout; use ibc_proto::ibc::core::client::v1::Height as RawHeight; +use ibc_proto::Protobuf; use crate::core::ics02_client::{error::Error as ICS2Error, height::Height}; +use crate::core::ics04_channel::error::Error as ChannelError; +use crate::timestamp::{ParseTimestampError, Timestamp}; /// Indicates a consensus height on the destination chain after which the packet /// will no longer be processed, and will instead count as having timed-out. @@ -180,3 +186,146 @@ impl<'de> Deserialize<'de> for TimeoutHeight { }) } } + +/// A composite of timeout height and timeout timestamp types, useful for when +/// performing a channel upgrade handshake, as there are cases when only timeout +/// height is set, only timeout timestamp is set, or both are set. +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub enum Timeout { + /// Timeout height indicates the height at which the counterparty + /// must no longer proceed with the upgrade handshake. + /// The chains will then preserve their original channel and the upgrade handshake is aborted + Height(Height), + + /// Timeout timestamp indicates the time on the counterparty at which + /// the counterparty must no longer proceed with the upgrade handshake. + /// The chains will then preserve their original channel and the upgrade handshake is aborted. + Timestamp(Timestamp), + + /// Both timeouts are set. + Both(Height, Timestamp), +} + +impl Display for Timeout { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { + match self { + Self::Height(height) => write!(f, "{height}"), + Self::Timestamp(timestamp) => write!(f, "{timestamp}"), + Self::Both(height, timestamp) => write!(f, "{height}, {timestamp}"), + } + } +} + +impl Timeout { + pub fn new(height: Option, timestamp: Option) -> Result { + match (height, timestamp) { + (Some(height), None) => Ok(Timeout::Height(height)), + (None, Some(timestamp)) => Ok(Timeout::Timestamp(timestamp)), + (Some(height), Some(timestamp)) => Ok(Timeout::Both(height, timestamp)), + (None, None) => Err(ChannelError::missing_upgrade_timeout()), + } + } + + pub fn into_tuple(self) -> (Option, Option) { + match self { + Timeout::Height(height) => (Some(height), None), + Timeout::Timestamp(timestamp) => (None, Some(timestamp)), + Timeout::Both(height, timestamp) => (Some(height), Some(timestamp)), + } + } +} + +define_error! { + #[derive(Debug, PartialEq, Eq)] + TimeoutError { + InvalidTimestamp + { timestamp: String } + [ TraceError ] + |e| { format_args!("cannot convert into a `Timestamp` type from string {0}", e.timestamp) }, + + InvalidTimeout + { timeout: String } + |e| { format_args!("invalid timeout {0}", e.timeout) }, + } +} + +impl FromStr for Timeout { + type Err = TimeoutError; + + fn from_str(value: &str) -> Result { + let split: Vec<&str> = value.split(' ').collect(); + + if split.len() != 2 { + return Err(TimeoutError::invalid_timeout(value.to_owned())); + } + + // only timeout timestamp are supported at the moment + split[1] + .parse::() + .map(Timeout::Timestamp) + .map_err(|e| TimeoutError::invalid_timestamp(value.to_owned(), e)) + } +} + +impl Protobuf for Timeout {} + +impl TryFrom for Timeout { + type Error = ChannelError; + + fn try_from(value: RawTimeout) -> Result { + let raw_timeout_height = value.height.map(Height::try_from).transpose(); + + let raw_timeout_timestamp = Timestamp::from_nanoseconds(value.timestamp) + .map_err(|_| Self::Error::invalid_timeout_timestamp) + .ok() + .filter(|ts| ts.nanoseconds() > 0); + + let (timeout_height, timeout_timestamp) = match (raw_timeout_height, raw_timeout_timestamp) + { + (Ok(timeout_height), Some(timeout_timestamp)) => { + (timeout_height, Some(timeout_timestamp)) + } + (Ok(timeout_height), None) => (timeout_height, None), + (Err(_), Some(timeout_timestamp)) => (None, Some(timeout_timestamp)), + (Err(e), None) => { + return Err(e).map_err(|_| Self::Error::invalid_timeout_height()); + } + }; + + Self::new(timeout_height, timeout_timestamp) + } +} + +impl From for RawTimeout { + fn from(value: Timeout) -> Self { + match value { + Timeout::Height(height) => Self { + height: Some(RawHeight::from(height)), + timestamp: 0, + }, + Timeout::Timestamp(timestamp) => Self { + height: None, + timestamp: timestamp.nanoseconds(), + }, + Timeout::Both(height, timestamp) => Self { + height: Some(RawHeight::from(height)), + timestamp: timestamp.nanoseconds(), + }, + } + } +} + +#[cfg(test)] +pub mod test_util { + use ibc_proto::ibc::core::channel::v1::Timeout as RawTimeout; + use ibc_proto::ibc::core::client::v1::Height as RawHeight; + + use crate::core::ics02_client::height::Height; + + pub fn get_dummy_upgrade_timeout() -> RawTimeout { + RawTimeout { + height: Some(RawHeight::from(Height::new(1, 50).unwrap())), + timestamp: 0, + } + } +} diff --git a/crates/relayer-types/src/core/ics04_channel/upgrade.rs b/crates/relayer-types/src/core/ics04_channel/upgrade.rs new file mode 100644 index 0000000000..6eb5b9bea2 --- /dev/null +++ b/crates/relayer-types/src/core/ics04_channel/upgrade.rs @@ -0,0 +1,96 @@ +use ibc_proto::ibc::core::channel::v1::ErrorReceipt as RawErrorReceipt; +use ibc_proto::ibc::core::channel::v1::Upgrade as RawUpgrade; +use ibc_proto::Protobuf; + +use crate::core::ics04_channel::error::Error as ChannelError; +use crate::core::ics04_channel::packet::Sequence; +use crate::core::ics04_channel::timeout::Timeout; +use crate::core::ics04_channel::upgrade_fields::UpgradeFields; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Upgrade { + pub fields: UpgradeFields, + // timeout can be zero, see `TryFrom` implementation + pub timeout: Option, + pub next_sequence_send: Sequence, +} + +impl Protobuf for Upgrade {} + +impl TryFrom for Upgrade { + type Error = ChannelError; + + fn try_from(value: RawUpgrade) -> Result { + let fields = value + .fields + .ok_or(ChannelError::missing_upgrade_fields())? + .try_into()?; + let timeout = value + .timeout + .filter(|tm| Timeout::try_from(*tm).is_ok()) + .map(|tm| Timeout::try_from(tm).unwrap()); + let next_sequence_send = value.next_sequence_send.into(); + + Ok(Self { + fields, + timeout, + next_sequence_send, + }) + } +} + +impl From for RawUpgrade { + fn from(value: Upgrade) -> Self { + let timeout = value.timeout.map(|tm| tm.into()); + Self { + fields: Some(value.fields.into()), + timeout, + next_sequence_send: value.next_sequence_send.into(), + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct ErrorReceipt { + pub sequence: Sequence, + pub message: String, +} + +impl Protobuf for ErrorReceipt {} + +impl TryFrom for ErrorReceipt { + type Error = ChannelError; + + fn try_from(value: RawErrorReceipt) -> Result { + Ok(Self { + sequence: value.sequence.into(), + message: value.message, + }) + } +} + +impl From for RawErrorReceipt { + fn from(value: ErrorReceipt) -> Self { + Self { + sequence: value.sequence.into(), + message: value.message, + } + } +} + +#[cfg(test)] +pub mod test_util { + use crate::core::ics04_channel::{ + timeout::test_util::get_dummy_upgrade_timeout, + upgrade_fields::test_util::get_dummy_upgrade_fields, + }; + use ibc_proto::ibc::core::channel::v1::Upgrade as RawUpgrade; + + pub fn get_dummy_upgrade() -> RawUpgrade { + RawUpgrade { + fields: Some(get_dummy_upgrade_fields()), + timeout: Some(get_dummy_upgrade_timeout()), + next_sequence_send: 1, + } + } +} diff --git a/crates/relayer-types/src/core/ics04_channel/upgrade_fields.rs b/crates/relayer-types/src/core/ics04_channel/upgrade_fields.rs new file mode 100644 index 0000000000..9d90ed41c1 --- /dev/null +++ b/crates/relayer-types/src/core/ics04_channel/upgrade_fields.rs @@ -0,0 +1,88 @@ +use core::str::FromStr; + +use ibc_proto::ibc::core::channel::v1::UpgradeFields as RawUpgradeFields; +use ibc_proto::Protobuf; +use itertools::Itertools; + +use crate::core::ics04_channel::channel::Ordering; +use crate::core::ics04_channel::error::Error as ChannelError; +use crate::core::ics04_channel::version::Version; +use crate::core::ics24_host::identifier::ConnectionId; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct UpgradeFields { + ordering: Ordering, + connection_hops: Vec, + version: Version, +} + +impl UpgradeFields { + pub fn new(ordering: Ordering, connection_hops: Vec, version: Version) -> Self { + Self { + ordering, + connection_hops, + version, + } + } +} + +impl Protobuf for UpgradeFields {} + +impl TryFrom for UpgradeFields { + type Error = ChannelError; + + fn try_from(value: RawUpgradeFields) -> Result { + use itertools::Either; + + let ordering = Ordering::from_i32(value.ordering)?; + + let (connection_hops, failures): (Vec<_>, Vec<_>) = value + .connection_hops + .iter() + .partition_map(|id| match ConnectionId::from_str(id) { + Ok(connection_id) => Either::Left(connection_id), + Err(e) => Either::Right((id.clone(), e)), + }); + + if !failures.is_empty() { + return Err(Self::Error::parse_connection_hops_vector(failures)); + } + + let version = Version::from(value.version); + + Ok(Self::new(ordering, connection_hops, version)) + } +} + +impl From for RawUpgradeFields { + fn from(value: UpgradeFields) -> Self { + let raw_connection_hops = value + .connection_hops + .iter() + .map(|id| id.to_string()) + .collect(); + Self { + ordering: value.ordering as i32, + connection_hops: raw_connection_hops, + version: value.version.to_string(), + } + } +} + +#[cfg(test)] +pub mod test_util { + use std::string::ToString; + use std::vec; + + use ibc_proto::ibc::core::channel::v1::UpgradeFields as RawUpgradeFields; + + use crate::core::ics04_channel::version::Version; + + pub fn get_dummy_upgrade_fields() -> RawUpgradeFields { + RawUpgradeFields { + ordering: 1, + connection_hops: vec![], + version: Version::ics20_with_fee().to_string(), + } + } +} diff --git a/crates/relayer-types/src/core/ics04_channel/version.rs b/crates/relayer-types/src/core/ics04_channel/version.rs index 4d15ae3d4b..151b97f746 100644 --- a/crates/relayer-types/src/core/ics04_channel/version.rs +++ b/crates/relayer-types/src/core/ics04_channel/version.rs @@ -15,7 +15,7 @@ use crate::applications::transfer; /// 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)] +#[derive(Clone, Debug, Eq, Deserialize, Serialize)] pub struct Version(pub String); impl Version { @@ -36,6 +36,15 @@ impl Version { Self::new(val.to_string()) } + pub fn app_version_with_fee(app_version: &str) -> Self { + let val = json::json!({ + "fee_version": "ics29-1", + "app_version": app_version, + }); + + Self::new(val.to_string()) + } + pub fn empty() -> Self { Self::new("".to_string()) } @@ -54,6 +63,28 @@ impl Version { } } +impl PartialEq for Version { + fn eq(&self, other: &Self) -> bool { + if self.0 != other.0 { + // If the Version strings don't match, check that this isn't due to the json + // fields being in a different order + let parsed_version = match serde_json::from_str::(&self.0) { + Ok(value) => value, + Err(_) => return false, + }; + let parsed_other = match serde_json::from_str::(&other.to_string()) { + Ok(value) => value, + Err(_) => return false, + }; + + if parsed_version != parsed_other { + return false; + } + } + true + } +} + impl From for Version { fn from(s: String) -> Self { Self::new(s) diff --git a/crates/relayer-types/src/core/ics23_commitment/commitment.rs b/crates/relayer-types/src/core/ics23_commitment/commitment.rs index 978f126df0..7a6cee11e9 100644 --- a/crates/relayer-types/src/core/ics23_commitment/commitment.rs +++ b/crates/relayer-types/src/core/ics23_commitment/commitment.rs @@ -1,5 +1,5 @@ use serde::{Deserialize, Serialize}; -use std::{convert::TryFrom, fmt}; +use std::fmt; use subtle_encoding::{Encoding, Hex}; use ibc_proto::ibc::core::commitment::v1::MerkleProof as RawMerkleProof; diff --git a/crates/relayer-types/src/core/ics23_commitment/merkle.rs b/crates/relayer-types/src/core/ics23_commitment/merkle.rs index 64704c8bb2..229c8c0c7b 100644 --- a/crates/relayer-types/src/core/ics23_commitment/merkle.rs +++ b/crates/relayer-types/src/core/ics23_commitment/merkle.rs @@ -102,7 +102,7 @@ impl MerkleProof { ) { return Err(Error::verification_failure()); } - value = subroot.clone(); + value.clone_from(&subroot); } _ => return Err(Error::invalid_merkle_proof()), } diff --git a/crates/relayer-types/src/core/ics23_commitment/mock.rs b/crates/relayer-types/src/core/ics23_commitment/mock.rs deleted file mode 100644 index 8b13789179..0000000000 --- a/crates/relayer-types/src/core/ics23_commitment/mock.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/crates/relayer-types/src/core/ics23_commitment/mod.rs b/crates/relayer-types/src/core/ics23_commitment/mod.rs index e3806ad771..ecffa81d63 100644 --- a/crates/relayer-types/src/core/ics23_commitment/mod.rs +++ b/crates/relayer-types/src/core/ics23_commitment/mod.rs @@ -4,5 +4,4 @@ pub mod commitment; pub mod error; pub mod merkle; -pub mod mock; pub mod specs; diff --git a/crates/relayer-types/src/core/ics24_host/error.rs b/crates/relayer-types/src/core/ics24_host/error.rs index 11e6983fe6..331d578a69 100644 --- a/crates/relayer-types/src/core/ics24_host/error.rs +++ b/crates/relayer-types/src/core/ics24_host/error.rs @@ -15,11 +15,20 @@ define_error! { min: usize, max: usize, } - | e | { format_args!("identifier {0} has invalid length {1} must be between {2}-{3} characters", e.id, e.length, e.min, e.max) }, + | e | { + format_args!( + "identifier {0} has invalid length {1} must be between {2}-{3} characters", + e.id, e.length, e.min, e.max + ) + }, InvalidCharacter { id: String } - | e | { format_args!("identifier {0} must only contain alphanumeric characters or `.`, `_`, `+`, `-`, `#`, - `[`, `]`, `<`, `>`", e.id) }, + | e | { + format_args!( + "identifier {0} must only contain alphanumeric characters or `.`, `_`, `+`, `-`, `#`, - `[`, `]`, `<`, `>`", e.id + ) + }, Empty | _ | { "identifier cannot be empty" }, @@ -29,6 +38,14 @@ define_error! { | e | { format_args!("chain identifiers are expected to be in epoch format {0}", e.id) }, InvalidCounterpartyChannelId - |_| { "Invalid channel id in counterparty" } + |_| { "invalid channel id in counterparty" } } } + +impl PartialEq for ValidationError { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} + +impl Eq for ValidationError {} diff --git a/crates/relayer-types/src/core/ics24_host/identifier.rs b/crates/relayer-types/src/core/ics24_host/identifier.rs index e96bebfb01..dbe60ea337 100644 --- a/crates/relayer-types/src/core/ics24_host/identifier.rs +++ b/crates/relayer-types/src/core/ics24_host/identifier.rs @@ -1,4 +1,4 @@ -use std::convert::{From, Infallible}; +use std::convert::Infallible; use std::fmt::{Debug, Display, Error as FmtError, Formatter}; use std::str::FromStr; @@ -68,8 +68,20 @@ impl ChainId { /// Extract the chain name from this chain identifier. The chain name /// consists of the first part of the identifier, before the dash. - pub fn name(&self) -> String { - self.id.split('-').take(1).collect::>().join("") + /// If the value following the dash is not an integer, or if there are no + /// dashes, the entire chain ID will be returned. + pub fn name(&self) -> &str { + self.id + .rsplit_once('-') + .and_then(|(chain_name, rev_number_str)| { + // Parses the revision number string into a `u64` and checks its validity. + if rev_number_str.parse::().is_ok() { + Some(chain_name) + } else { + None + } + }) + .unwrap_or_else(|| &self.id) } /// Extract the version from the given chain identifier. @@ -178,9 +190,6 @@ impl ClientId { pub fn prefix(client_type: ClientType) -> &'static str { match client_type { ClientType::Tendermint => ClientType::Tendermint.as_str(), - - #[cfg(any(test, feature = "mocks"))] - ClientType::Mock => ClientType::Mock.as_str(), } } @@ -445,3 +454,82 @@ impl Display for PortChannelId { write!(f, "{}/{}", self.port_id, self.channel_id) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_chain_id_name() { + let chain_id = ChainId::from_str("ibc-5").unwrap(); + assert_eq!(chain_id.name(), "ibc".to_owned()); + } + + #[test] + fn test_chain_id_name_with_test() { + let chain_id = ChainId::from_str("ibc-test-5").unwrap(); + assert_eq!(chain_id.name(), "ibc-test".to_owned()); + } + + #[test] + fn test_chain_id_name_no_dash() { + let chain_id = ChainId::from_str("ibc5").unwrap(); + assert_eq!(chain_id.name(), "ibc5".to_owned()); + } + + #[test] + fn standard_chain_names() { + let test_cases = [ + ("ibc-0", "ibc"), + ("osmosis-1", "osmosis"), + ("cosmoshub-4", "cosmoshub"), + ("juno-mainnet-1", "juno-mainnet"), + ("akash-testnet-2", "akash-testnet"), + ("stargaze-123", "stargaze"), + ("crypto-org-chain-0", "crypto-org-chain"), + ("mars-hub-1", "mars-hub"), + ("evmos-9000-1", "evmos-9000"), + ]; + + for (input, expected) in test_cases { + let chain_id = ChainId::from_str(input).unwrap(); + assert_eq!(chain_id.name(), expected); + } + } + + #[test] + fn missing_or_invalid_revision_numbers() { + let test_cases = [ + ("osmosis", "osmosis"), + ("ibc-test", "ibc-test"), + ("cosmos-hub", "cosmos-hub"), + ("juno-", "juno-"), + ("akash-testnet-x", "akash-testnet-x"), + ("stargaze-abc", "stargaze-abc"), + ("chain-123-xyz", "chain-123-xyz"), + ]; + + for (input, expected) in test_cases { + let chain_id = ChainId::from_str(input).unwrap(); + assert_eq!(chain_id.name(), expected); + } + } + + #[test] + fn edge_cases() { + let test_cases = [ + ("", ""), + ("-", "-"), + ("chain-", "chain-"), + ( + "chain-9999999999999999999999", + "chain-9999999999999999999999", + ), // number too large for u64 + ]; + + for (input, expected) in test_cases { + let chain_id = ChainId::from_str(input).unwrap(); + assert_eq!(chain_id.name(), expected); + } + } +} diff --git a/crates/relayer-types/src/core/ics24_host/path.rs b/crates/relayer-types/src/core/ics24_host/path.rs index 300982d929..6642cbeebb 100644 --- a/crates/relayer-types/src/core/ics24_host/path.rs +++ b/crates/relayer-types/src/core/ics24_host/path.rs @@ -42,6 +42,22 @@ pub enum Path { Acks(AcksPath), Receipts(ReceiptsPath), Upgrade(ClientUpgradePath), + ChannelUpgrade(ChannelUpgradePath), + ChannelUpgradeError(ChannelUpgradeErrorPath), +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] +#[display(fmt = "channelUpgrades/upgradeError/ports/{port_id}/channels/{channel_id}")] +pub struct ChannelUpgradeErrorPath { + pub port_id: PortId, + pub channel_id: ChannelId, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] +#[display(fmt = "channelUpgrades/upgrades/ports/{port_id}/channels/{channel_id}")] +pub struct ChannelUpgradePath { + pub port_id: PortId, + pub channel_id: ChannelId, } #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] @@ -579,7 +595,6 @@ fn parse_upgrades(components: &[&str]) -> Option { #[cfg(test)] mod tests { use super::*; - use core::str::FromStr; #[test] fn invalid_path_doesnt_parse() { diff --git a/crates/relayer-types/src/core/ics26_routing/error.rs b/crates/relayer-types/src/core/ics26_routing/error.rs index f51581b6e0..5a4773e5af 100644 --- a/crates/relayer-types/src/core/ics26_routing/error.rs +++ b/crates/relayer-types/src/core/ics26_routing/error.rs @@ -29,7 +29,7 @@ define_error! { | e | { format_args!("unknown type URL {0}", e.url) }, MalformedMessageBytes - [ TraceError ] + [ TraceError ] | _ | { "the message is malformed and cannot be decoded" }, } } diff --git a/crates/relayer-types/src/events.rs b/crates/relayer-types/src/events.rs index d1f85ea7fb..7ceb45d5c2 100644 --- a/crates/relayer-types/src/events.rs +++ b/crates/relayer-types/src/events.rs @@ -1,5 +1,4 @@ use std::borrow::Cow; -use std::convert::TryFrom; use std::fmt::{Display, Error as FmtError, Formatter}; use std::str::FromStr; @@ -18,8 +17,8 @@ use crate::core::ics03_connection::error as connection_error; 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::events::{self as ChannelEvents, UpgradeAttributes}; use crate::core::ics04_channel::packet::Packet; use crate::core::ics24_host::error::ValidationError; use crate::timestamp::ParseTimestampError; @@ -66,9 +65,13 @@ define_error! { [ TraceError ] | _ | { "error decoding protobuf" }, - SubtleEncoding - [ TraceError ] - | _ | { "error decoding hex" }, + InvalidPacketData + { data: String } + | e | { format_args!("error decoding hex-encoded packet data: {}", e.data) }, + + InvalidPacketAck + { ack: String } + | e | { format_args!("error decoding hex-encoded packet ack: {}", e.ack) }, MissingActionString | _ | { "missing action string" }, @@ -129,6 +132,15 @@ 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"; +/// Channel upgrade event types +const CHANNEL_UPGRADE_INIT_EVENT: &str = "channel_upgrade_init"; +const CHANNEL_UPGRADE_TRY_EVENT: &str = "channel_upgrade_try"; +const CHANNEL_UPGRADE_ACK_EVENT: &str = "channel_upgrade_ack"; +const CHANNEL_UPGRADE_CONFIRM_EVENT: &str = "channel_upgrade_confirm"; +const CHANNEL_UPGRADE_OPEN_EVENT: &str = "channel_upgrade_open"; +const CHANNEL_UPGRADE_CANCEL_EVENT: &str = "channel_upgrade_cancelled"; +const CHANNEL_UPGRADE_TIMEOUT_EVENT: &str = "channel_upgrade_timeout"; +const CHANNEL_UPGRADE_ERROR_EVENT: &str = "channel_upgrade_error"; /// Packet event types const SEND_PACKET_EVENT: &str = "send_packet"; const RECEIVE_PACKET_EVENT: &str = "receive_packet"; @@ -160,6 +172,14 @@ pub enum IbcEventType { OpenConfirmChannel, CloseInitChannel, CloseConfirmChannel, + UpgradeInitChannel, + UpgradeTryChannel, + UpgradeAckChannel, + UpgradeConfirmChannel, + UpgradeOpenChannel, + UpgradeCancelChannel, + UpgradeTimeoutChannel, + UpgradeErrorChannel, SendPacket, ReceivePacket, WriteAck, @@ -192,6 +212,14 @@ impl IbcEventType { IbcEventType::OpenConfirmChannel => CHANNEL_OPEN_CONFIRM_EVENT, IbcEventType::CloseInitChannel => CHANNEL_CLOSE_INIT_EVENT, IbcEventType::CloseConfirmChannel => CHANNEL_CLOSE_CONFIRM_EVENT, + IbcEventType::UpgradeInitChannel => CHANNEL_UPGRADE_INIT_EVENT, + IbcEventType::UpgradeTryChannel => CHANNEL_UPGRADE_TRY_EVENT, + IbcEventType::UpgradeAckChannel => CHANNEL_UPGRADE_ACK_EVENT, + IbcEventType::UpgradeConfirmChannel => CHANNEL_UPGRADE_CONFIRM_EVENT, + IbcEventType::UpgradeOpenChannel => CHANNEL_UPGRADE_OPEN_EVENT, + IbcEventType::UpgradeCancelChannel => CHANNEL_UPGRADE_CANCEL_EVENT, + IbcEventType::UpgradeTimeoutChannel => CHANNEL_UPGRADE_TIMEOUT_EVENT, + IbcEventType::UpgradeErrorChannel => CHANNEL_UPGRADE_ERROR_EVENT, IbcEventType::SendPacket => SEND_PACKET_EVENT, IbcEventType::ReceivePacket => RECEIVE_PACKET_EVENT, IbcEventType::WriteAck => WRITE_ACK_EVENT, @@ -228,6 +256,14 @@ impl FromStr for IbcEventType { CHANNEL_OPEN_CONFIRM_EVENT => Ok(IbcEventType::OpenConfirmChannel), CHANNEL_CLOSE_INIT_EVENT => Ok(IbcEventType::CloseInitChannel), CHANNEL_CLOSE_CONFIRM_EVENT => Ok(IbcEventType::CloseConfirmChannel), + CHANNEL_UPGRADE_INIT_EVENT => Ok(IbcEventType::UpgradeInitChannel), + CHANNEL_UPGRADE_TRY_EVENT => Ok(IbcEventType::UpgradeTryChannel), + CHANNEL_UPGRADE_ACK_EVENT => Ok(IbcEventType::UpgradeAckChannel), + CHANNEL_UPGRADE_CONFIRM_EVENT => Ok(IbcEventType::UpgradeConfirmChannel), + CHANNEL_UPGRADE_OPEN_EVENT => Ok(IbcEventType::UpgradeOpenChannel), + CHANNEL_UPGRADE_CANCEL_EVENT => Ok(IbcEventType::UpgradeCancelChannel), + CHANNEL_UPGRADE_TIMEOUT_EVENT => Ok(IbcEventType::UpgradeTimeoutChannel), + CHANNEL_UPGRADE_ERROR_EVENT => Ok(IbcEventType::UpgradeErrorChannel), SEND_PACKET_EVENT => Ok(IbcEventType::SendPacket), RECEIVE_PACKET_EVENT => Ok(IbcEventType::ReceivePacket), WRITE_ACK_EVENT => Ok(IbcEventType::WriteAck), @@ -266,6 +302,14 @@ pub enum IbcEvent { OpenConfirmChannel(ChannelEvents::OpenConfirm), CloseInitChannel(ChannelEvents::CloseInit), CloseConfirmChannel(ChannelEvents::CloseConfirm), + UpgradeInitChannel(ChannelEvents::UpgradeInit), + UpgradeTryChannel(ChannelEvents::UpgradeTry), + UpgradeAckChannel(ChannelEvents::UpgradeAck), + UpgradeConfirmChannel(ChannelEvents::UpgradeConfirm), + UpgradeOpenChannel(ChannelEvents::UpgradeOpen), + UpgradeCancelChannel(ChannelEvents::UpgradeCancel), + UpgradeTimeoutChannel(ChannelEvents::UpgradeTimeout), + UpgradeErrorChannel(ChannelEvents::UpgradeError), SendPacket(ChannelEvents::SendPacket), ReceivePacket(ChannelEvents::ReceivePacket), @@ -305,6 +349,14 @@ impl Display for IbcEvent { IbcEvent::OpenConfirmChannel(ev) => write!(f, "OpenConfirmChannel({ev})"), IbcEvent::CloseInitChannel(ev) => write!(f, "CloseInitChannel({ev})"), IbcEvent::CloseConfirmChannel(ev) => write!(f, "CloseConfirmChannel({ev})"), + IbcEvent::UpgradeInitChannel(ev) => write!(f, "UpgradeInitChannel({ev})"), + IbcEvent::UpgradeTryChannel(ev) => write!(f, "UpgradeTryChannel({ev})"), + IbcEvent::UpgradeAckChannel(ev) => write!(f, "UpgradeAckChannel({ev})"), + IbcEvent::UpgradeConfirmChannel(ev) => write!(f, "UpgradeConfirmChannel({ev})"), + IbcEvent::UpgradeOpenChannel(ev) => write!(f, "UpgradeOpenChannel({ev})"), + IbcEvent::UpgradeCancelChannel(ev) => write!(f, "UpgradeCancelChannel({ev})"), + IbcEvent::UpgradeTimeoutChannel(ev) => write!(f, "UpgradeTimeoutChannel({ev})"), + IbcEvent::UpgradeErrorChannel(ev) => write!(f, "UpgradeErrorChannel({ev})"), IbcEvent::SendPacket(ev) => write!(f, "SendPacket({ev})"), IbcEvent::ReceivePacket(ev) => write!(f, "ReceivePacket({ev})"), @@ -350,6 +402,14 @@ impl IbcEvent { IbcEvent::OpenConfirmChannel(_) => IbcEventType::OpenConfirmChannel, IbcEvent::CloseInitChannel(_) => IbcEventType::CloseInitChannel, IbcEvent::CloseConfirmChannel(_) => IbcEventType::CloseConfirmChannel, + IbcEvent::UpgradeInitChannel(_) => IbcEventType::UpgradeInitChannel, + IbcEvent::UpgradeTryChannel(_) => IbcEventType::UpgradeTryChannel, + IbcEvent::UpgradeAckChannel(_) => IbcEventType::UpgradeAckChannel, + IbcEvent::UpgradeConfirmChannel(_) => IbcEventType::UpgradeConfirmChannel, + IbcEvent::UpgradeOpenChannel(_) => IbcEventType::UpgradeOpenChannel, + IbcEvent::UpgradeCancelChannel(_) => IbcEventType::UpgradeCancelChannel, + IbcEvent::UpgradeTimeoutChannel(_) => IbcEventType::UpgradeTimeoutChannel, + IbcEvent::UpgradeErrorChannel(_) => IbcEventType::UpgradeErrorChannel, IbcEvent::SendPacket(_) => IbcEventType::SendPacket, IbcEvent::ReceivePacket(_) => IbcEventType::ReceivePacket, IbcEvent::WriteAcknowledgement(_) => IbcEventType::WriteAck, @@ -374,6 +434,20 @@ impl IbcEvent { } } + pub fn channel_upgrade_attributes(self) -> Option { + match self { + IbcEvent::UpgradeInitChannel(ev) => Some(ev.into()), + IbcEvent::UpgradeTryChannel(ev) => Some(ev.into()), + IbcEvent::UpgradeAckChannel(ev) => Some(ev.into()), + IbcEvent::UpgradeConfirmChannel(ev) => Some(ev.into()), + IbcEvent::UpgradeOpenChannel(ev) => Some(ev.into()), + IbcEvent::UpgradeCancelChannel(ev) => Some(ev.into()), + IbcEvent::UpgradeTimeoutChannel(ev) => Some(ev.into()), + IbcEvent::UpgradeErrorChannel(ev) => Some(ev.into()), + _ => None, + } + } + pub fn connection_attributes(&self) -> Option<&ConnectionAttributes> { match self { IbcEvent::OpenInitConnection(ev) => Some(ev.attributes()), diff --git a/crates/relayer-types/src/lib.rs b/crates/relayer-types/src/lib.rs index 7684e0b41a..eee880d3cb 100644 --- a/crates/relayer-types/src/lib.rs +++ b/crates/relayer-types/src/lib.rs @@ -4,11 +4,9 @@ #![allow(clippy::large_enum_variant)] #![deny( - // warnings, trivial_casts, trivial_numeric_casts, unused_import_braces, - unused_qualifications, rust_2018_idioms )] #![forbid(unsafe_code)] @@ -60,13 +58,10 @@ pub mod utils; mod serializers; /// Re-export of ICS 002 Height domain type -pub type Height = crate::core::ics02_client::height::Height; +pub type Height = core::ics02_client::height::Height; #[cfg(test)] mod test; -#[cfg(any(test, feature = "mocks"))] +#[cfg(test)] pub mod test_utils; - -#[cfg(any(test, feature = "mocks"))] -pub mod mock; // Context mock, the underlying host chain, and client types: for testing all handlers. diff --git a/crates/relayer-types/src/mock/client_state.rs b/crates/relayer-types/src/mock/client_state.rs deleted file mode 100644 index c4081ab3bf..0000000000 --- a/crates/relayer-types/src/mock/client_state.rs +++ /dev/null @@ -1,133 +0,0 @@ -use std::time::Duration; - -use serde::{Deserialize, Serialize}; - -use ibc_proto::google::protobuf::Any; -use ibc_proto::ibc::mock::ClientState as RawMockClientState; -use ibc_proto::Protobuf; - -use crate::core::ics02_client::client_state::ClientState; -use crate::core::ics02_client::client_type::ClientType; -use crate::core::ics02_client::error::Error; - -use crate::core::ics24_host::identifier::ChainId; - -use crate::mock::consensus_state::MockConsensusState; -use crate::mock::header::MockHeader; - -use crate::Height; - -pub const MOCK_CLIENT_STATE_TYPE_URL: &str = "/ibc.mock.ClientState"; - -/// 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. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct MockClientState { - pub header: MockHeader, - pub frozen_height: Option, -} - -impl MockClientState { - pub fn new(header: MockHeader) -> Self { - Self { - header, - frozen_height: None, - } - } - - pub fn latest_height(&self) -> Height { - self.header.height() - } -} - -impl Protobuf for MockClientState {} - -impl TryFrom for MockClientState { - type Error = Error; - - fn try_from(raw: RawMockClientState) -> Result { - Ok(Self::new(raw.header.unwrap().try_into()?)) - } -} - -impl From for RawMockClientState { - fn from(value: MockClientState) -> Self { - RawMockClientState { - header: Some(ibc_proto::ibc::mock::Header { - height: Some(value.header.height().into()), - timestamp: value.header.timestamp.nanoseconds(), - }), - } - } -} - -impl Protobuf for MockClientState {} - -impl TryFrom for MockClientState { - type Error = Error; - - fn try_from(raw: Any) -> Result { - use bytes::Buf; - use core::ops::Deref; - use prost::Message; - - fn decode_client_state(buf: B) -> Result { - RawMockClientState::decode(buf) - .map_err(Error::decode)? - .try_into() - } - - match raw.type_url.as_str() { - MOCK_CLIENT_STATE_TYPE_URL => { - decode_client_state(raw.value.deref()).map_err(Into::into) - } - _ => Err(Error::unexpected_client_state_type( - MOCK_CLIENT_STATE_TYPE_URL.to_string(), - raw.type_url, - )), - } - } -} - -impl From for Any { - fn from(client_state: MockClientState) -> Self { - Any { - type_url: MOCK_CLIENT_STATE_TYPE_URL.to_string(), - value: Protobuf::::encode_vec(client_state), - } - } -} - -impl ClientState for MockClientState { - type UpgradeOptions = (); - - fn chain_id(&self) -> ChainId { - unimplemented!() - } - - fn client_type(&self) -> ClientType { - ClientType::Mock - } - - fn latest_height(&self) -> Height { - self.header.height() - } - - fn frozen_height(&self) -> Option { - self.frozen_height - } - - fn upgrade(&mut self, _upgrade_height: Height, _upgrade_options: (), _chain_id: ChainId) { - unimplemented!() - } - - fn expired(&self, _elapsed: Duration) -> bool { - false - } -} - -impl From for MockClientState { - fn from(cs: MockConsensusState) -> Self { - Self::new(cs.header) - } -} diff --git a/crates/relayer-types/src/mock/consensus_state.rs b/crates/relayer-types/src/mock/consensus_state.rs deleted file mode 100644 index 0237d50074..0000000000 --- a/crates/relayer-types/src/mock/consensus_state.rs +++ /dev/null @@ -1,106 +0,0 @@ -use ibc_proto::google::protobuf::Any; -use ibc_proto::ibc::mock::ConsensusState as RawMockConsensusState; -use ibc_proto::Protobuf; -use serde::{Deserialize, Serialize}; - -use crate::core::ics02_client::client_type::ClientType; -use crate::core::ics02_client::consensus_state::ConsensusState; -use crate::core::ics02_client::error::Error; -use crate::core::ics23_commitment::commitment::CommitmentRoot; -use crate::mock::header::MockHeader; -use crate::timestamp::Timestamp; - -pub const MOCK_CONSENSUS_STATE_TYPE_URL: &str = "/ibc.mock.ConsensusState"; - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct MockConsensusState { - pub header: MockHeader, - pub root: CommitmentRoot, -} - -impl MockConsensusState { - pub fn new(header: MockHeader) -> Self { - MockConsensusState { - header, - root: CommitmentRoot::from(vec![0]), - } - } - - pub fn timestamp(&self) -> Timestamp { - self.header.timestamp - } -} - -impl Protobuf for MockConsensusState {} - -impl TryFrom for MockConsensusState { - type Error = Error; - - fn try_from(raw: RawMockConsensusState) -> Result { - let raw_header = raw.header.ok_or_else(Error::missing_raw_consensus_state)?; - - Ok(Self { - header: MockHeader::try_from(raw_header)?, - root: CommitmentRoot::from(vec![0]), - }) - } -} - -impl From for RawMockConsensusState { - fn from(value: MockConsensusState) -> Self { - RawMockConsensusState { - header: Some(ibc_proto::ibc::mock::Header { - height: Some(value.header.height().into()), - timestamp: value.header.timestamp.nanoseconds(), - }), - } - } -} - -impl Protobuf for MockConsensusState {} - -impl TryFrom for MockConsensusState { - type Error = Error; - - fn try_from(raw: Any) -> Result { - use bytes::Buf; - use core::ops::Deref; - use prost::Message; - - fn decode_consensus_state(buf: B) -> Result { - RawMockConsensusState::decode(buf) - .map_err(Error::decode)? - .try_into() - } - - match raw.type_url.as_str() { - MOCK_CONSENSUS_STATE_TYPE_URL => { - decode_consensus_state(raw.value.deref()).map_err(Into::into) - } - _ => Err(Error::unknown_consensus_state_type(raw.type_url)), - } - } -} - -impl From for Any { - fn from(consensus_state: MockConsensusState) -> Self { - Any { - type_url: MOCK_CONSENSUS_STATE_TYPE_URL.to_string(), - value: Protobuf::::encode_vec(consensus_state), - } - } -} - -impl ConsensusState for MockConsensusState { - fn client_type(&self) -> ClientType { - ClientType::Mock - } - - fn root(&self) -> &CommitmentRoot { - &self.root - } - - fn timestamp(&self) -> Timestamp { - self.header.timestamp - } -} diff --git a/crates/relayer-types/src/mock/header.rs b/crates/relayer-types/src/mock/header.rs deleted file mode 100644 index 2f5c931201..0000000000 --- a/crates/relayer-types/src/mock/header.rs +++ /dev/null @@ -1,140 +0,0 @@ -use std::fmt::{Display, Error as FmtError, Formatter}; - -use ibc_proto::google::protobuf::Any; -use ibc_proto::ibc::mock::Header as RawMockHeader; -use ibc_proto::Protobuf; -use serde_derive::{Deserialize, Serialize}; - -use crate::core::ics02_client::client_type::ClientType; -use crate::core::ics02_client::error::Error; -use crate::core::ics02_client::header::Header; -use crate::timestamp::Timestamp; -use crate::Height; - -pub const MOCK_HEADER_TYPE_URL: &str = "/ibc.mock.Header"; - -#[derive(Copy, Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] -pub struct MockHeader { - pub height: Height, - pub timestamp: Timestamp, -} - -impl Default for MockHeader { - fn default() -> Self { - Self { - height: Height::new(0, 1).unwrap(), - timestamp: Default::default(), - } - } -} - -impl Display for MockHeader { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!( - f, - "MockHeader {{ height: {}, timestamp: {} }}", - self.height, self.timestamp - ) - } -} - -impl Protobuf for MockHeader {} - -impl TryFrom for MockHeader { - type Error = Error; - - fn try_from(raw: RawMockHeader) -> Result { - Ok(MockHeader { - height: raw - .height - .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or_else(Error::missing_raw_header)?, - - timestamp: Timestamp::from_nanoseconds(raw.timestamp) - .map_err(Error::invalid_packet_timestamp)?, - }) - } -} - -impl From for RawMockHeader { - fn from(value: MockHeader) -> Self { - RawMockHeader { - height: Some(value.height.into()), - timestamp: value.timestamp.nanoseconds(), - } - } -} - -impl MockHeader { - pub fn height(&self) -> Height { - self.height - } - - pub fn new(height: Height) -> Self { - Self { - height, - timestamp: Timestamp::now(), - } - } - - pub fn with_timestamp(self, timestamp: Timestamp) -> Self { - Self { timestamp, ..self } - } -} - -impl Header for MockHeader { - fn client_type(&self) -> ClientType { - ClientType::Mock - } - - fn height(&self) -> Height { - self.height - } - - fn timestamp(&self) -> Timestamp { - self.timestamp - } -} - -impl Protobuf for MockHeader {} - -impl TryFrom for MockHeader { - type Error = Error; - - fn try_from(raw: Any) -> Result { - match raw.type_url.as_str() { - MOCK_HEADER_TYPE_URL => Ok(Protobuf::::decode_vec(&raw.value) - .map_err(Error::invalid_raw_header)?), - _ => Err(Error::unknown_header_type(raw.type_url)), - } - } -} - -impl From for Any { - fn from(header: MockHeader) -> Self { - Any { - type_url: MOCK_HEADER_TYPE_URL.to_string(), - value: Protobuf::::encode_vec(header), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use ibc_proto::Protobuf; - - #[test] - fn encode_any() { - let header = MockHeader::new(Height::new(1, 10).unwrap()).with_timestamp(Timestamp::none()); - let bytes = >::encode_vec(header); - - 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 - ] - ); - } -} diff --git a/crates/relayer-types/src/mock/misbehaviour.rs b/crates/relayer-types/src/mock/misbehaviour.rs deleted file mode 100644 index 17e303940c..0000000000 --- a/crates/relayer-types/src/mock/misbehaviour.rs +++ /dev/null @@ -1,57 +0,0 @@ -use ibc_proto::ibc::mock::Misbehaviour as RawMisbehaviour; -use ibc_proto::Protobuf; -use serde::{Deserialize, Serialize}; - -use crate::core::ics02_client::error::Error; -use crate::core::ics24_host::identifier::ClientId; -use crate::mock::header::MockHeader; -use crate::Height; - -pub const MOCK_MISBEHAVIOUR_TYPE_URL: &str = "/ibc.mock.Misbehavior"; - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct Misbehaviour { - pub client_id: ClientId, - pub header1: MockHeader, - pub header2: MockHeader, -} - -impl crate::core::ics02_client::misbehaviour::Misbehaviour for Misbehaviour { - fn client_id(&self) -> &ClientId { - &self.client_id - } - - fn height(&self) -> Height { - self.header1.height() - } -} - -impl Protobuf for Misbehaviour {} - -impl TryFrom for Misbehaviour { - type Error = Error; - - fn try_from(raw: RawMisbehaviour) -> Result { - Ok(Self { - client_id: Default::default(), - header1: raw - .header1 - .ok_or_else(Error::missing_raw_misbehaviour)? - .try_into()?, - header2: raw - .header2 - .ok_or_else(Error::missing_raw_misbehaviour)? - .try_into()?, - }) - } -} - -impl From for RawMisbehaviour { - fn from(value: Misbehaviour) -> Self { - RawMisbehaviour { - client_id: value.client_id.to_string(), - header1: Some(value.header1.into()), - header2: Some(value.header2.into()), - } - } -} diff --git a/crates/relayer-types/src/mock/mod.rs b/crates/relayer-types/src/mock/mod.rs deleted file mode 100644 index 340dacdaef..0000000000 --- a/crates/relayer-types/src/mock/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -//! Implementation of mocks for context, host chain, and client. - -pub mod client_state; -pub mod consensus_state; -pub mod header; -pub mod misbehaviour; diff --git a/crates/relayer-types/src/utils/pretty.rs b/crates/relayer-types/src/utils/pretty.rs index d2f2ab5f79..895d0e1958 100644 --- a/crates/relayer-types/src/utils/pretty.rs +++ b/crates/relayer-types/src/utils/pretty.rs @@ -13,7 +13,7 @@ impl Display for PrettyDuration<'_> { pub struct PrettyOption<'a, T>(pub &'a Option); -impl<'a, T: Display> Display for PrettyOption<'a, T> { +impl Display for PrettyOption<'_, T> { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { match &self.0 { Some(v) => write!(f, "{v}"), @@ -62,7 +62,7 @@ impl Display for PrettyValidatorSet<'_> { pub struct PrettySlice<'a, T>(pub &'a [T]); -impl<'a, T: Display> Display for PrettySlice<'a, T> { +impl Display for PrettySlice<'_, T> { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { write!(f, "[ ")?; let mut vec_iterator = self.0.iter().peekable(); @@ -81,7 +81,7 @@ impl<'a, T: Display> Display for PrettySlice<'a, T> { mod tests { use super::*; - use std::{string::String, vec}; + use std::vec; #[test] fn test_pretty_duration_micros() { diff --git a/crates/relayer/Cargo.toml b/crates/relayer/Cargo.toml index 5ed88c5893..5bda943405 100644 --- a/crates/relayer/Cargo.toml +++ b/crates/relayer/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "ibc-relayer" -version = "0.27.0" +version = "0.29.5" edition = "2021" license = "Apache-2.0" readme = "README.md" keywords = ["blockchain", "consensus", "cosmos", "ibc", "tendermint"] repository = "https://github.com/informalsystems/hermes" authors = ["Informal Systems "] -rust-version = "1.71" +rust-version = "1.76.0" description = """ Implementation of an IBC Relayer in Rust, as a library """ @@ -17,103 +17,74 @@ all-features = true [features] default = ["flex-error/std", "flex-error/eyre_tracer"] -telemetry = ["ibc-telemetry"] [dependencies] -ibc-proto = { version = "0.41.0", features = ["serde"] } -ibc-telemetry = { version = "0.27.0", path = "../telemetry", optional = true } -ibc-relayer-types = { version = "0.27.0", path = "../relayer-types", features = ["mocks"] } +ibc-proto = { workspace = true, features = ["serde"] } +ibc-telemetry = { workspace = true } +ibc-relayer-types = { workspace = true, features = ["clock"] } -subtle-encoding = "0.5" -humantime-serde = "1.1.1" -serde = "1.0" -serde_derive = "1.0" -thiserror = "1.0.56" -toml = "0.8" -tracing = "0.1.36" -tokio = { version = "1.0", features = ["rt-multi-thread", "time", "sync"] } -serde_json = { version = "1" } -bytes = "1.4.0" -prost = { version = "0.12" } -tonic = { version = "0.10", features = ["tls", "tls-roots"] } -futures = "0.3.27" -crossbeam-channel = "0.5.11" -hex = "0.4" -bitcoin = { version = "0.31.1", features = ["serde"] } -tiny-bip39 = "1.0.0" -hdpath = "0.6.3" -sha2 = "0.10.6" -tiny-keccak = { version = "2.0.2", features = ["keccak"], default-features = false } -ripemd = "0.1.3" -bech32 = "0.9.1" -itertools = "0.10.5" -dirs-next = "2.0.0" -retry = { version = "2.0.0", default-features = false } -async-stream = "0.3.5" -http = "0.2.9" -reqwest = { version = "0.11", features = ["rustls-tls-native-roots", "json"], default-features = false } -flex-error = { version = "0.4.4", default-features = false } -signature = "2.1.0" -anyhow = "1.0" -semver = "1.0" -humantime = "2.1.0" -regex = "1" -moka = { version = "0.12.0", features = ["sync"] } -uuid = { version = "1.7.0", features = ["v4"] } -bs58 = "0.5.0" -digest = "0.10.6" -ed25519 = "2.2.2" -ed25519-dalek = { version = "2.0.0", features = ["serde"] } -ed25519-dalek-bip32 = "0.3.0" -generic-array = "0.14.7" -secp256k1 = { version = "0.28.1", features = ["rand-std"] } -strum = { version = "0.25", features = ["derive"] } -tokio-stream = "0.1.14" -once_cell = "1.19.0" -tracing-subscriber = { version = "0.3.14", features = ["fmt", "env-filter", "json"] } - -[dependencies.byte-unit] -version = "4.0.19" -default-features = false -features = ["serde"] - -[dependencies.num-bigint] -version = "0.4" -features = ["serde"] - -[dependencies.num-rational] -version = "0.4.1" -features = ["num-bigint", "serde"] - -[dependencies.tendermint] -version = "0.34.0" -features = ["secp256k1"] - -[dependencies.tendermint-proto] -version = "0.34.0" - -[dependencies.tendermint-rpc] -version = "0.34.0" -features = ["http-client", "websocket-client"] - -[dependencies.tendermint-light-client] -version = "0.34.0" -default-features = false -features = ["rpc-client", "secp256k1", "unstable"] - -[dependencies.tendermint-light-client-detector] -version = "0.34.0" -default-features = false - -[dependencies.tendermint-light-client-verifier] -version = "0.34.0" -default-features = false +anyhow = { workspace = true } +async-stream = { workspace = true } +bech32 = { workspace = true } +bitcoin = { workspace = true, features = ["serde"] } +bs58 = { workspace = true } +byte-unit = { workspace = true, features = ["serde"] } +bytes = { workspace = true } +crossbeam-channel = { workspace = true } +digest = { workspace = true } +dirs-next = { workspace = true } +ed25519 = { workspace = true } +ed25519-dalek = { workspace = true, features = ["serde"] } +ed25519-dalek-bip32 = { workspace = true } +flex-error = { workspace = true } +futures = { workspace = true } +generic-array = { workspace = true } +hdpath = { workspace = true } +hex = { workspace = true } +http = { workspace = true } +humantime = { workspace = true } +humantime-serde = { workspace = true } +itertools = { workspace = true } +moka = { workspace = true, features = ["sync"] } +num-bigint = { workspace = true, features = ["serde"] } +num-rational = { workspace = true, features = ["num-bigint", "serde"] } +once_cell = { workspace = true } +prost = { workspace = true } +regex = { workspace = true } +reqwest = { workspace = true, features = ["rustls-tls-native-roots", "json"] } +retry = { workspace = true } +ripemd = { workspace = true } +secp256k1 = { workspace = true, features = ["rand-std"] } +semver = { workspace = true } +serde = { workspace = true } +serde_derive = { workspace = true } +serde_json = { workspace = true } +sha2 = { workspace = true } +signature = { workspace = true } +strum = { workspace = true, features = ["derive"] } +subtle-encoding = { workspace = true } +tendermint = { workspace = true, features = ["secp256k1"] } +tendermint-light-client = { workspace = true, features = ["rpc-client", "secp256k1", "unstable"] } +tendermint-light-client-detector = { workspace = true } +tendermint-light-client-verifier = { workspace = true } +tendermint-proto = { workspace = true } +tendermint-rpc = { workspace = true, features = ["http-client", "websocket-client"] } +thiserror = { workspace = true } +tiny-bip39 = { workspace = true } +tiny-keccak = { workspace = true, features = ["keccak"] } +tokio = { workspace = true, features = ["rt-multi-thread", "time", "sync"] } +tokio-stream = { workspace = true } +toml = { workspace = true } +tonic = { workspace = true, features = ["tls", "tls-roots"] } +tracing = { workspace = true } +tracing-subscriber = { workspace = true, features = ["fmt", "env-filter", "json"] } +uuid = { workspace = true, features = ["v4"] } [dev-dependencies] -ibc-relayer-types = { version = "0.27.0", path = "../relayer-types", features = ["mocks"] } -serial_test = "3.0.0" -env_logger = "0.11.1" -test-log = { version = "0.2.14", features = ["trace"] } +ibc-relayer-types = { workspace = true } +serial_test = { workspace = true } +env_logger = { workspace = true } +test-log = { workspace = true, features = ["trace"] } # Needed for generating (synthetic) light blocks. -tendermint-testgen = { version = "0.34.0" } +tendermint-testgen = { workspace = true } diff --git a/crates/relayer/src/cache.rs b/crates/relayer/src/cache.rs index 474f44ab4f..73038e7245 100644 --- a/crates/relayer/src/cache.rs +++ b/crates/relayer/src/cache.rs @@ -99,6 +99,9 @@ impl Cache { where F: FnOnce() -> Result, { + // FIXME: If a channel being upgraded is queried using Latest + // Height, it might return the wrong Channel End information. + // Find an alternative to avoid this issue if let Some(chan) = self.channels.get(id) { // If cache hit, return it. Ok((chan, CacheStatus::Hit)) diff --git a/crates/relayer/src/chain/cosmos.rs b/crates/relayer/src/chain/cosmos.rs index d5ccc13242..1dc99d6923 100644 --- a/crates/relayer/src/chain/cosmos.rs +++ b/crates/relayer/src/chain/cosmos.rs @@ -1,27 +1,29 @@ use alloc::sync::Arc; -use bytes::{Buf, Bytes}; -use core::{ - convert::{TryFrom, TryInto}, - future::Future, - str::FromStr, - time::Duration, -}; +use bytes::Buf; +use bytes::Bytes; +use config::CosmosSdkConfig; +use core::{future::Future, str::FromStr, time::Duration}; use futures::future::join_all; +use ibc_proto::interchain_security::ccv::provider::v1::QueryConsumerIdFromClientIdRequest; +use itertools::Itertools; use num_bigint::BigInt; -use std::{cmp::Ordering, thread}; - +use prost::Message; +use std::cmp::Ordering; +use std::thread; use tokio::runtime::Runtime as TokioRuntime; use tonic::codegen::http::Uri; use tonic::metadata::AsciiMetadataValue; -use tracing::{debug, error, info, instrument, trace, warn}; +use tracing::{debug, error, instrument, trace, warn}; use ibc_proto::cosmos::base::node::v1beta1::ConfigResponse; -use ibc_proto::cosmos::staking::v1beta1::Params as StakingParams; +use ibc_proto::cosmos::staking::v1beta1::{Params as StakingParams, QueryParamsResponse}; use ibc_proto::ibc::apps::fee::v1::{ QueryIncentivizedPacketRequest, QueryIncentivizedPacketResponse, }; +use ibc_proto::ibc::core::channel::v1::{QueryUpgradeErrorRequest, QueryUpgradeRequest}; use ibc_proto::interchain_security::ccv::v1::ConsumerParams as CcvConsumerParams; use ibc_proto::Protobuf; +use ibc_relayer_types::applications::ics28_ccv::msgs::{ConsumerChain, ConsumerId}; use ibc_relayer_types::applications::ics31_icq::response::CrossChainQueryResponse; use ibc_relayer_types::clients::ics07_tendermint::client_state::{ AllowUpdate, ClientState as TmClientState, @@ -35,6 +37,7 @@ use ibc_relayer_types::core::ics03_connection::connection::{ ConnectionEnd, IdentifiedConnectionEnd, }; use ibc_relayer_types::core::ics04_channel::channel::{ChannelEnd, IdentifiedChannelEnd}; +use ibc_relayer_types::core::ics04_channel::channel::{State, UpgradeState}; use ibc_relayer_types::core::ics04_channel::packet::Sequence; use ibc_relayer_types::core::ics23_commitment::commitment::CommitmentPrefix; use ibc_relayer_types::core::ics23_commitment::merkle::MerkleProof; @@ -42,12 +45,17 @@ use ibc_relayer_types::core::ics24_host::identifier::{ ChainId, ChannelId, ClientId, ConnectionId, PortId, }; use ibc_relayer_types::core::ics24_host::path::{ - AcksPath, ChannelEndsPath, ClientConsensusStatePath, ClientStatePath, CommitmentsPath, - ConnectionsPath, ReceiptsPath, SeqRecvsPath, + AcksPath, ChannelEndsPath, ChannelUpgradeErrorPath, ChannelUpgradePath, + ClientConsensusStatePath, ClientStatePath, CommitmentsPath, ConnectionsPath, ReceiptsPath, + SeqRecvsPath, }; use ibc_relayer_types::core::ics24_host::{ ClientUpgradePath, Path, IBC_QUERY_PATH, SDK_UPGRADE_QUERY_PATH, }; +use ibc_relayer_types::core::{ + ics02_client::height::Height, ics04_channel::upgrade::ErrorReceipt, + ics04_channel::upgrade::Upgrade, +}; use ibc_relayer_types::signer::Signer; use ibc_relayer_types::Height as ICSHeight; @@ -61,6 +69,7 @@ use tendermint_rpc::endpoint::status; use tendermint_rpc::{Client, HttpClient, Order}; use crate::account::Balance; +use crate::chain::client::ClientSettings; use crate::chain::cosmos::batch::{ send_batched_messages_and_wait_check_tx, send_batched_messages_and_wait_commit, sequential_send_batched_messages_and_wait_commit, @@ -70,6 +79,7 @@ use crate::chain::cosmos::fee::maybe_register_counterparty_payee; use crate::chain::cosmos::gas::{calculate_fee, mul_ceil}; use crate::chain::cosmos::query::account::get_or_fetch_account; use crate::chain::cosmos::query::balance::{query_all_balances, query_balance}; +use crate::chain::cosmos::query::connection::query_connection_params; use crate::chain::cosmos::query::consensus_state::query_consensus_state_heights; use crate::chain::cosmos::query::custom::cross_chain_query_via_rpc; use crate::chain::cosmos::query::denom_trace::query_denom_trace; @@ -89,6 +99,7 @@ use crate::chain::handle::Subscription; use crate::chain::requests::*; use crate::chain::tracking::TrackedMsgs; use crate::client_state::{AnyClientState, IdentifiedAnyClientState}; +use crate::config::Error as ConfigError; use crate::config::{parse_gas_prices, ChainConfig, GasPrice}; use crate::consensus_state::AnyConsensusState; use crate::denom::DenomTrace; @@ -99,14 +110,14 @@ use crate::keyring::{KeyRing, Secp256k1KeyPair, SigningKeyPair}; use crate::light_client::tendermint::LightClient as TmLightClient; use crate::light_client::{LightClient, Verified}; use crate::misbehaviour::MisbehaviourEvidence; -use crate::util::compat_mode::compat_mode_from_version; +use crate::util::collate::CollatedIterExt; +use crate::util::create_grpc_client; use crate::util::pretty::{ PrettyIdentifiedChannel, PrettyIdentifiedClientState, PrettyIdentifiedConnection, }; -use crate::{chain::client::ClientSettings, config::Error as ConfigError}; +use crate::HERMES_VERSION; use self::gas::dynamic_gas_price; -use self::types::app_state::GenesisAppState; use self::types::gas::GasConfig; use self::version::Specs; @@ -142,6 +153,7 @@ pub mod wait; /// /// [tm-37-max]: https://github.com/tendermint/tendermint/blob/v0.37.0-rc1/types/params.go#L79 pub const BLOCK_MAX_BYTES_MAX_FRACTION: f64 = 0.9; + pub struct CosmosSdkChain { config: config::CosmosSdkConfig, tx_config: TxConfig, @@ -288,23 +300,30 @@ impl CosmosSdkChain { )); } - // Query /genesis RPC endpoint to retrieve the `max_expected_time_per_block` value - // to use as `max_block_time`. - // If it is not found, keep the configured `max_block_time`. - match self.block_on(self.rpc_client.genesis::()) { - Ok(genesis_reponse) => { - let old_max_block_time = self.config.max_block_time; - self.config.max_block_time = - Duration::from_nanos(genesis_reponse.app_state.max_expected_time_per_block()); - info!( - "Updated `max_block_time` using /genesis endpoint. Old value: `{}s`, new value: `{}s`", - old_max_block_time.as_secs(), - self.config.max_block_time.as_secs() + // Query Connection Params with gRPC endpoint to retrieve the `max_expected_time_per_block` value and verify the + // configured `max_block_time`. + // If it is not found, the verification for the configured `max_block_time` is skipped. + match self.block_on(query_connection_params(&self.grpc_addr)) { + Ok(params) => { + debug!( + "queried `max_expected_time_per_block`: `{}ns`", + params.max_expected_time_per_block ); + let new_max_block_time = Duration::from_nanos(params.max_expected_time_per_block); + + if new_max_block_time != self.config.max_block_time { + warn!( + "configured `max_block_time` value of `{}s` does not match queried value of `{}s`. \ + `max_block_time` will be updated with queried value", + self.config.max_block_time.as_secs(), + new_max_block_time.as_secs(), + ); + self.config.max_block_time = new_max_block_time; + } } Err(e) => { warn!( - "Will use fallback value for max_block_time: `{}s`. Error: {e}", + "configured value for max_block_time: `{}s` could not be verified. Error: {e}", self.config.max_block_time.as_secs() ); } @@ -331,10 +350,14 @@ impl CosmosSdkChain { *batch_delay, self.rt.clone(), ), - Mode::Pull { interval } => EventSource::rpc( + Mode::Pull { + interval, + max_retries, + } => EventSource::rpc( self.config.id.clone(), self.rpc_client.clone(), *interval, + *max_retries, self.rt.clone(), ), } @@ -346,6 +369,7 @@ impl CosmosSdkChain { } /// Performs a gRPC query to fetch CCV Consumer chain staking parameters. + /// Assumes we are the consumer chain. pub fn query_ccv_consumer_chain_params(&self) -> Result { crate::time!( "query_ccv_consumer_chain_params", @@ -355,13 +379,10 @@ impl CosmosSdkChain { ); crate::telemetry!(query, self.id(), "query_ccv_consumer_chain_params"); - let mut client = self - .block_on( - ibc_proto::interchain_security::ccv::consumer::v1::query_client::QueryClient::connect( - self.grpc_addr.clone() - ), - ) - .map_err(Error::grpc_transport)?; + let mut client = self.block_on(create_grpc_client( + &self.grpc_addr, + ibc_proto::interchain_security::ccv::consumer::v1::query_client::QueryClient::new, + ))?; client = client .max_decoding_message_size(self.config().max_grpc_decoding_size.get_bytes() as usize); @@ -392,26 +413,20 @@ impl CosmosSdkChain { ); crate::telemetry!(query, self.id(), "query_staking_params"); - let mut client = self - .block_on( - ibc_proto::cosmos::staking::v1beta1::query_client::QueryClient::connect( - self.grpc_addr.clone(), - ), - ) - .map_err(Error::grpc_transport)?; - - client = client - .max_decoding_message_size(self.config().max_grpc_decoding_size.get_bytes() as usize); - - let request = - tonic::Request::new(ibc_proto::cosmos::staking::v1beta1::QueryParamsRequest {}); - - let response = self - .block_on(client.params(request)) - .map_err(|e| Error::grpc_status(e, "query_staking_params".to_owned()))?; + let query_response = self.block_on(abci_query( + &self.rpc_client, + &self.config().rpc_addr, + "/cosmos.staking.v1beta1.Query/Params".to_owned(), + "".to_owned(), + QueryHeight::Latest.into(), + false, + ))?; + let params_response = + QueryParamsResponse::decode(query_response.value.as_ref()).map_err(|e| { + Error::protobuf_decode("cosmos.staking.v1beta1.Query/Params".to_owned(), e) + })?; - let params = response - .into_inner() + let params = params_response .params .ok_or_else(|| Error::grpc_response_param("no staking params".to_string()))?; @@ -435,49 +450,24 @@ impl CosmosSdkChain { ); crate::telemetry!(query, self.id(), "query_config_params"); - // Helper function to diagnose if the node config query is unimplemented - // by matching on the error details. - fn is_unimplemented_node_query(err_status: &tonic::Status) -> bool { - if err_status.code() != tonic::Code::Unimplemented { - return false; - } - - err_status - .message() - .contains("unknown service cosmos.base.node.v1beta1.Service") - } - - let mut client = self - .block_on( - ibc_proto::cosmos::base::node::v1beta1::service_client::ServiceClient::connect( - self.grpc_addr.clone(), - ), - ) - .map_err(Error::grpc_transport)?; - - client = client - .max_decoding_message_size(self.config().max_grpc_decoding_size.get_bytes() as usize); - - let request = tonic::Request::new(ibc_proto::cosmos::base::node::v1beta1::ConfigRequest {}); - - match self.block_on(client.config(request)) { - Ok(response) => { - let params = response.into_inner(); + let query_response = self.block_on(abci_query( + &self.rpc_client, + &self.config().rpc_addr, + "/cosmos.base.node.v1beta1.Service/Config".to_owned(), + "".to_owned(), + QueryHeight::Latest.into(), + false, + ))?; + let config_response = + ConfigResponse::decode(query_response.value.as_ref()).map_err(|e| { + Error::protobuf_decode("cosmos.base.node.v1beta1.Service/Config".to_owned(), e) + })?; - Ok(Some(params)) - } - Err(e) => { - if is_unimplemented_node_query(&e) { - Ok(None) - } else { - Err(Error::grpc_status(e, "query_config_params".to_owned())) - } - } - } + Ok(Some(config_response)) } /// The minimum gas price that this node accepts - pub fn min_gas_price(&self) -> Result, Error> { + pub fn min_gas_price(&self) -> Result>, Error> { crate::time!( "min_gas_price", { @@ -485,10 +475,9 @@ impl CosmosSdkChain { } ); - let min_gas_price: Vec = - self.query_config_params()?.map_or(vec![], |cfg_response| { - parse_gas_prices(cfg_response.minimum_gas_price) - }); + let min_gas_price: Option> = self + .query_config_params()? + .map(|cfg_response| parse_gas_prices(cfg_response.minimum_gas_price)); Ok(min_gas_price) } @@ -562,11 +551,6 @@ impl CosmosSdkChain { height_query: QueryHeight, prove: bool, ) -> Result { - crate::time!("query", - { - "src_chain": self.config().id.to_string(), - }); - let data = data.into(); if !data.is_provable() & prove { return Err(Error::private_store()); @@ -628,27 +612,51 @@ impl CosmosSdkChain { /// /// Returns an error if the node is still syncing and has not caught up, /// ie. if `sync_info.catching_up` is `true`. - fn chain_status(&self) -> Result { + fn chain_rpc_status(&self) -> Result { crate::time!( - "chain_status", + "chain_rpc_status", { "src_chain": self.config().id.to_string(), } ); - crate::telemetry!(query, self.id(), "status"); + crate::telemetry!(query, self.id(), "rpc_status"); let status = self .block_on(self.rpc_client.status()) .map_err(|e| Error::rpc(self.config.rpc_addr.clone(), e))?; if status.sync_info.catching_up { + Err(Error::chain_not_caught_up( + self.config.rpc_addr.to_string(), + self.config().id.clone(), + )) + } else { + Ok(status) + } + } + + /// Query the chain status of the RPC and gRPC nodes. + /// + /// Returns an error if any of the node is still syncing and has not caught up. + fn chain_status(&self) -> Result { + crate::time!( + "chain_status", + { + "src_chain": self.config().id.to_string(), + } + ); + crate::telemetry!(query, self.id(), "status"); + + let rpc_status = self.chain_rpc_status()?; + + if rpc_status.sync_info.catching_up { return Err(Error::chain_not_caught_up( self.config.rpc_addr.to_string(), self.config().id.clone(), )); } - Ok(status) + Ok(rpc_status) } /// Query the chain's latest height @@ -698,13 +706,19 @@ impl CosmosSdkChain { let account = get_or_fetch_account(&self.grpc_addr, &key_account, &mut self.account).await?; + let memo_prefix = if let Some(memo_overwrite) = &self.config.memo_overwrite { + memo_overwrite.clone() + } else { + self.config.memo_prefix.clone() + }; + if self.config.sequential_batch_tx { sequential_send_batched_messages_and_wait_commit( &self.rpc_client, &self.tx_config, &key_pair, account, - &self.config.memo_prefix, + &memo_prefix, proto_msgs, ) .await @@ -714,7 +728,7 @@ impl CosmosSdkChain { &self.tx_config, &key_pair, account, - &self.config.memo_prefix, + &memo_prefix, proto_msgs, ) .await @@ -749,12 +763,18 @@ impl CosmosSdkChain { let account = get_or_fetch_account(&self.grpc_addr, &key_account, &mut self.account).await?; + let memo_prefix = if let Some(memo_overwrite) = &self.config.memo_overwrite { + memo_overwrite.clone() + } else { + self.config.memo_prefix.clone() + }; + send_batched_messages_and_wait_check_tx( &self.rpc_client, &self.tx_config, &key_pair, account, - &self.config.memo_prefix, + &memo_prefix, proto_msgs, ) .await @@ -896,14 +916,15 @@ impl ChainEndpoint for CosmosSdkChain { return Err(Error::config(ConfigError::wrong_type())); }; - let mut rpc_client = HttpClient::new(config.rpc_addr.clone()) + let mut rpc_client = HttpClient::builder(config.rpc_addr.clone().try_into().unwrap()) + .user_agent(format!("hermes/{}", HERMES_VERSION)) + .build() .map_err(|e| Error::rpc(config.rpc_addr.clone(), e))?; - let node_info = rt.block_on(fetch_node_info(&rpc_client, &config))?; - - let compat_mode = compat_mode_from_version(&config.compat_mode, node_info.version)?.into(); + let compat_mode = rt.block_on(fetch_compat_mode(&rpc_client, &config))?; rpc_client.set_compat_mode(compat_mode); + let node_info = rt.block_on(fetch_node_info(&rpc_client, &config))?; let light_client = TmLightClient::from_cosmos_sdk_config(&config, node_info.id)?; // Initialize key store and load key @@ -991,17 +1012,17 @@ impl ChainEndpoint for CosmosSdkChain { /// further checks. fn health_check(&mut self) -> Result { if let Err(e) = do_health_check(self) { - warn!("Health checkup for chain '{}' failed", self.id()); - warn!(" Reason: {}", e.detail()); - warn!(" Some Hermes features may not work in this mode!"); + warn!("health check failed for chain '{}'", self.id()); + warn!("reason: {}", e.detail()); + warn!("some Hermes features may not work in this mode!"); return Ok(HealthCheck::Unhealthy(Box::new(e))); } if let Err(e) = self.validate_params() { - warn!("Hermes might be misconfigured for chain '{}'", self.id()); - warn!(" Reason: {}", e.detail()); - warn!(" Some Hermes features may not work in this mode!"); + warn!("found potential misconfiguration for chain '{}'", self.id()); + warn!("reason: {}", e.detail()); + warn!("some Hermes features may not work in this mode!"); return Ok(HealthCheck::Unhealthy(Box::new(e))); } @@ -1093,11 +1114,22 @@ impl ChainEndpoint for CosmosSdkChain { } fn version_specs(&self) -> Result { - let version_specs = self.block_on(fetch_version_specs(self.id(), &self.grpc_addr))?; + let version_specs = self.block_on(fetch_version_specs( + self.id(), + &self.rpc_client, + &self.config.rpc_addr, + ))?; + Ok(version_specs) } fn query_balance(&self, key_name: Option<&str>, denom: Option<&str>) -> Result { + crate::time!( + "query_balance", + { + "src_chain": self.config().id.to_string(), + } + ); // If a key_name is given, extract the account hash. // Else retrieve the account from the configuration file. let key = match key_name { @@ -1113,6 +1145,12 @@ impl ChainEndpoint for CosmosSdkChain { } fn query_all_balances(&self, key_name: Option<&str>) -> Result, Error> { + crate::time!( + "query_all_balances", + { + "src_chain": self.config().id.to_string(), + } + ); // If a key_name is given, extract the account hash. // Else retrieve the account from the configuration file. let key = match key_name { @@ -1192,13 +1230,10 @@ impl ChainEndpoint for CosmosSdkChain { ); crate::telemetry!(query, self.id(), "query_clients"); - let mut client = self - .block_on( - ibc_proto::ibc::core::client::v1::query_client::QueryClient::connect( - self.grpc_addr.clone(), - ), - ) - .map_err(Error::grpc_transport)?; + let mut client = self.block_on(create_grpc_client( + &self.grpc_addr, + ibc_proto::ibc::core::client::v1::query_client::QueryClient::new, + ))?; client = client .max_decoding_message_size(self.config().max_grpc_decoding_size.get_bytes() as usize); @@ -1383,13 +1418,10 @@ impl ChainEndpoint for CosmosSdkChain { ); crate::telemetry!(query, self.id(), "query_client_connections"); - let mut client = self - .block_on( - ibc_proto::ibc::core::connection::v1::query_client::QueryClient::connect( - self.grpc_addr.clone(), - ), - ) - .map_err(Error::grpc_transport)?; + let mut client = self.block_on(create_grpc_client( + &self.grpc_addr, + ibc_proto::ibc::core::connection::v1::query_client::QueryClient::new, + ))?; client = client .max_decoding_message_size(self.config().max_grpc_decoding_size.get_bytes() as usize); @@ -1429,13 +1461,10 @@ impl ChainEndpoint for CosmosSdkChain { ); crate::telemetry!(query, self.id(), "query_connections"); - let mut client = self - .block_on( - ibc_proto::ibc::core::connection::v1::query_client::QueryClient::connect( - self.grpc_addr.clone(), - ), - ) - .map_err(Error::grpc_transport)?; + let mut client = self.block_on(create_grpc_client( + &self.grpc_addr, + ibc_proto::ibc::core::connection::v1::query_client::QueryClient::new, + ))?; client = client .max_decoding_message_size(self.config().max_grpc_decoding_size.get_bytes() as usize); @@ -1488,9 +1517,8 @@ impl ChainEndpoint for CosmosSdkChain { use tonic::IntoRequest; let mut client = - connection::query_client::QueryClient::connect(chain.grpc_addr.clone()) - .await - .map_err(Error::grpc_transport)?; + create_grpc_client(&chain.grpc_addr, connection::query_client::QueryClient::new) + .await?; client = client.max_decoding_message_size( chain.config().max_grpc_decoding_size.get_bytes() as usize, @@ -1568,13 +1596,10 @@ impl ChainEndpoint for CosmosSdkChain { ); crate::telemetry!(query, self.id(), "query_connection_channels"); - let mut client = self - .block_on( - ibc_proto::ibc::core::channel::v1::query_client::QueryClient::connect( - self.grpc_addr.clone(), - ), - ) - .map_err(Error::grpc_transport)?; + let mut client = self.block_on(create_grpc_client( + &self.grpc_addr, + ibc_proto::ibc::core::channel::v1::query_client::QueryClient::new, + ))?; client = client .max_decoding_message_size(self.config().max_grpc_decoding_size.get_bytes() as usize); @@ -1586,7 +1611,9 @@ impl ChainEndpoint for CosmosSdkChain { .map_err(|e| Error::grpc_status(e, "query_connection_channels".to_owned()))? .into_inner(); - let channels = response + let height = self.query_chain_latest_height()?; + + let channels: Vec = response .channels .into_iter() .filter_map(|ch| { @@ -1600,7 +1627,27 @@ impl ChainEndpoint for CosmosSdkChain { }) .ok() }) + .map(|mut channel| { + // If the channel is open, look for an upgrade in order to correctly set the + // state to Open(Upgrading) or Open(NotUpgrading) + if channel.channel_end.is_open() + && self + .query_upgrade( + QueryUpgradeRequest { + port_id: channel.port_id.to_string(), + channel_id: channel.channel_id.to_string(), + }, + height, + IncludeProof::No, + ) + .is_ok() + { + channel.channel_end.state = State::Open(UpgradeState::Upgrading); + } + channel + }) .collect(); + Ok(channels) } @@ -1618,13 +1665,10 @@ impl ChainEndpoint for CosmosSdkChain { ); crate::telemetry!(query, self.id(), "query_channels"); - let mut client = self - .block_on( - ibc_proto::ibc::core::channel::v1::query_client::QueryClient::connect( - self.grpc_addr.clone(), - ), - ) - .map_err(Error::grpc_transport)?; + let mut client = self.block_on(create_grpc_client( + &self.grpc_addr, + ibc_proto::ibc::core::channel::v1::query_client::QueryClient::new, + ))?; client = client .max_decoding_message_size(self.config().max_grpc_decoding_size.get_bytes() as usize); @@ -1636,6 +1680,8 @@ impl ChainEndpoint for CosmosSdkChain { .map_err(|e| Error::grpc_status(e, "query_channels".to_owned()))? .into_inner(); + let height = self.query_chain_latest_height()?; + let channels = response .channels .into_iter() @@ -1650,6 +1696,25 @@ impl ChainEndpoint for CosmosSdkChain { }) .ok() }) + .map(|mut channel| { + // If the channel is open, look for an upgrade in order to correctly set the + // state to Open(Upgrading) or Open(NotUpgrading) + if channel.channel_end.is_open() + && self + .query_upgrade( + QueryUpgradeRequest { + port_id: channel.port_id.to_string(), + channel_id: channel.channel_id.to_string(), + }, + height, + IncludeProof::No, + ) + .is_ok() + { + channel.channel_end.state = State::Open(UpgradeState::Upgrading); + } + channel + }) .collect(); Ok(channels) @@ -1669,12 +1734,34 @@ impl ChainEndpoint for CosmosSdkChain { crate::telemetry!(query, self.id(), "query_channel"); let res = self.query( - ChannelEndsPath(request.port_id, request.channel_id), + ChannelEndsPath(request.port_id.clone(), request.channel_id.clone()), request.height, matches!(include_proof, IncludeProof::Yes), )?; - let channel_end = ChannelEnd::decode_vec(&res.value).map_err(Error::decode)?; + let mut channel_end = ChannelEnd::decode_vec(&res.value).map_err(Error::decode)?; + + if channel_end.is_open() { + let height = match request.height { + QueryHeight::Latest => self.query_chain_latest_height()?, + QueryHeight::Specific(height) => height, + }; + // In order to determine if the channel is Open upgrading or not the Upgrade is queried. + // If an upgrade is ongoing then the query will succeed in finding an Upgrade. + if self + .query_upgrade( + QueryUpgradeRequest { + port_id: request.port_id.to_string(), + channel_id: request.channel_id.to_string(), + }, + height, + IncludeProof::No, + ) + .is_ok() + { + channel_end.state = State::Open(UpgradeState::Upgrading); + } + } match include_proof { IncludeProof::Yes => { @@ -1699,13 +1786,10 @@ impl ChainEndpoint for CosmosSdkChain { ); crate::telemetry!(query, self.id(), "query_channel_client_state"); - let mut client = self - .block_on( - ibc_proto::ibc::core::channel::v1::query_client::QueryClient::connect( - self.grpc_addr.clone(), - ), - ) - .map_err(Error::grpc_transport)?; + let mut client = self.block_on(create_grpc_client( + &self.grpc_addr, + ibc_proto::ibc::core::channel::v1::query_client::QueryClient::new, + ))?; client = client .max_decoding_message_size(self.config().max_grpc_decoding_size.get_bytes() as usize); @@ -1729,6 +1813,12 @@ impl ChainEndpoint for CosmosSdkChain { request: QueryPacketCommitmentRequest, include_proof: IncludeProof, ) -> Result<(Vec, Option), Error> { + crate::time!( + "query_packet_commitment", + { + "src_chain": self.config().id.to_string(), + } + ); let res = self.query( CommitmentsPath { port_id: request.port_id, @@ -1764,36 +1854,130 @@ impl ChainEndpoint for CosmosSdkChain { crate::telemetry!(query, self.id(), "query_packet_commitments"); let mut client = self - .block_on( - ibc_proto::ibc::core::channel::v1::query_client::QueryClient::connect( - self.grpc_addr.clone(), - ), - ) - .map_err(Error::grpc_transport)?; + .block_on(create_grpc_client( + &self.grpc_addr, + ibc_proto::ibc::core::channel::v1::query_client::QueryClient::new, + )) + .map(|client| { + client.max_decoding_message_size( + self.config().max_grpc_decoding_size.get_bytes() as usize + ) + })?; - client = client - .max_decoding_message_size(self.config().max_grpc_decoding_size.get_bytes() as usize); + let height_param = AsciiMetadataValue::try_from(request.query_height)?; - let request = tonic::Request::new(request.into()); + if request.pagination.is_enabled() { + let mut results = Vec::new(); + let mut page_key = Vec::new(); - let response = self - .block_on(client.packet_commitments(request)) - .map_err(|e| Error::grpc_status(e, "query_packet_commitments".to_owned()))? - .into_inner(); + let pagination_information = request.pagination.get_values(); + let mut current_results = 0; - let mut commitment_sequences: Vec = response - .commitments - .into_iter() - .map(|v| v.sequence.into()) - .collect(); - commitment_sequences.sort_unstable(); + loop { + crate::time!( + "query_packet_commitments_loop_iteration", + { + "src_chain": self.config().id.to_string(), + } + ); + let mut raw_request = + ibc_proto::ibc::core::channel::v1::QueryPacketCommitmentsRequest::from( + request.clone(), + ); + + if let Some(pagination) = raw_request.pagination.as_mut() { + pagination.key = page_key; + } + + let mut tonic_request = tonic::Request::new(raw_request); + // TODO: This should either be configurable or inferred from the pagination + tonic_request.set_timeout(Duration::from_secs(10)); + + tonic_request + .metadata_mut() + .insert("x-cosmos-block-height", height_param.clone()); + + let response = self.rt.block_on(async { + client + .packet_commitments(tonic_request) + .await + .map_err(|e| Error::grpc_status(e, "query_packet_commitments".to_owned())) + }); + + match response { + Ok(response) => { + let inner_response = response.into_inner().clone(); + let next_key = inner_response + .pagination + .as_ref() + .map(|p| p.next_key.clone()); + + results.push(Ok(inner_response)); + current_results += pagination_information.0; + + match next_key { + Some(next_key) if !next_key.is_empty() => { + page_key = next_key; + } + _ => break, + } + } + Err(e) => { + results.push(Err(e)); + break; + } + } + if current_results >= pagination_information.1 { + break; + } + } + + let responses = results.into_iter().collect::, _>>()?; + + let mut commitment_sequences = Vec::new(); - let height = response - .height - .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or_else(|| Error::grpc_response_param("height".to_string()))?; + for response in &responses { + commitment_sequences.extend( + response + .commitments + .iter() + .map(|commit| Sequence::from(commit.sequence)), + ); + } + + let height = responses + .first() + .and_then(|res| res.height) + .and_then(|raw_height| raw_height.try_into().ok()) + .ok_or_else(|| Error::grpc_response_param("height".to_string()))?; - Ok((commitment_sequences, height)) + Ok((commitment_sequences, height)) + } else { + let mut tonic_request = tonic::Request::new(request.clone().into()); + + tonic_request + .metadata_mut() + .insert("x-cosmos-block-height", height_param); + + let response = self + .block_on(client.packet_commitments(tonic_request)) + .map_err(|e| Error::grpc_status(e, "query_packet_commitments".to_owned()))? + .into_inner(); + + let mut commitment_sequences: Vec = response + .commitments + .into_iter() + .map(|v| v.sequence.into()) + .collect(); + commitment_sequences.sort_unstable(); + + let height = response + .height + .and_then(|raw_height| raw_height.try_into().ok()) + .ok_or_else(|| Error::grpc_response_param("height".to_string()))?; + + Ok((commitment_sequences, height)) + } } fn query_packet_receipt( @@ -1801,6 +1985,12 @@ impl ChainEndpoint for CosmosSdkChain { request: QueryPacketReceiptRequest, include_proof: IncludeProof, ) -> Result<(Vec, Option), Error> { + crate::time!( + "query_packet_receipt", + { + "src_chain": self.config().id.to_string(), + } + ); let res = self.query( ReceiptsPath { port_id: request.port_id, @@ -1835,13 +2025,10 @@ impl ChainEndpoint for CosmosSdkChain { ); crate::telemetry!(query, self.id(), "query_unreceived_packets"); - let mut client = self - .block_on( - ibc_proto::ibc::core::channel::v1::query_client::QueryClient::connect( - self.grpc_addr.clone(), - ), - ) - .map_err(Error::grpc_transport)?; + let mut client = self.block_on(create_grpc_client( + &self.grpc_addr, + ibc_proto::ibc::core::channel::v1::query_client::QueryClient::new, + ))?; client = client .max_decoding_message_size(self.config().max_grpc_decoding_size.get_bytes() as usize); @@ -1866,6 +2053,12 @@ impl ChainEndpoint for CosmosSdkChain { request: QueryPacketAcknowledgementRequest, include_proof: IncludeProof, ) -> Result<(Vec, Option), Error> { + crate::time!( + "query_packet_acknowledgement", + { + "src_chain": self.config().id.to_string(), + } + ); let res = self.query( AcksPath { port_id: request.port_id, @@ -1905,35 +2098,108 @@ impl ChainEndpoint for CosmosSdkChain { } let mut client = self - .block_on( - ibc_proto::ibc::core::channel::v1::query_client::QueryClient::connect( - self.grpc_addr.clone(), - ), - ) - .map_err(Error::grpc_transport)?; + .block_on(create_grpc_client( + &self.grpc_addr, + ibc_proto::ibc::core::channel::v1::query_client::QueryClient::new, + )) + .map(|client| { + client.max_decoding_message_size( + self.config().max_grpc_decoding_size.get_bytes() as usize + ) + })?; - client = client - .max_decoding_message_size(self.config().max_grpc_decoding_size.get_bytes() as usize); + if request.pagination.is_enabled() { + let mut results = Vec::new(); + let mut page_key = Vec::new(); - let request = tonic::Request::new(request.into()); + loop { + let mut raw_request = + ibc_proto::ibc::core::channel::v1::QueryPacketAcknowledgementsRequest::from( + request.clone(), + ); - let response = self - .block_on(client.packet_acknowledgements(request)) - .map_err(|e| Error::grpc_status(e, "query_packet_acknowledgements".to_owned()))? - .into_inner(); + if let Some(pagination) = raw_request.pagination.as_mut() { + pagination.key = page_key; + } - let acks_sequences = response - .acknowledgements - .into_iter() - .map(|v| v.sequence.into()) - .collect(); + let mut tonic_request = tonic::Request::new(raw_request); + // TODO: This should either be configurable or inferred from the pagination + tonic_request.set_timeout(Duration::from_secs(10)); + + let response = self.rt.block_on(async { + client + .packet_acknowledgements(tonic_request) + .await + .map_err(|e| { + Error::grpc_status(e, "query_packet_acknowledgements".to_owned()) + }) + }); + + match response { + Ok(response) => { + let inner_response = response.into_inner().clone(); + let next_key = inner_response + .pagination + .as_ref() + .map(|p| p.next_key.clone()); + + results.push(Ok(inner_response)); + + match next_key { + Some(next_key) if !next_key.is_empty() => { + page_key = next_key; + } + _ => break, + } + } + Err(e) => { + results.push(Err(e)); + break; + } + } + } + + let responses = results.into_iter().collect::, _>>()?; - let height = response - .height - .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or_else(|| Error::grpc_response_param("height".to_string()))?; + let mut acks_sequences = Vec::new(); - Ok((acks_sequences, height)) + for response in &responses { + acks_sequences.extend( + response + .acknowledgements + .iter() + .map(|commit| Sequence::from(commit.sequence)), + ); + } + + let height = responses + .first() + .and_then(|res| res.height) + .and_then(|raw_height| raw_height.try_into().ok()) + .ok_or_else(|| Error::grpc_response_param("height".to_string()))?; + + Ok((acks_sequences, height)) + } else { + let request = tonic::Request::new(request.into()); + let response = self + .block_on(client.packet_acknowledgements(request)) + .map_err(|e| Error::grpc_status(e, "query_packet_commitments".to_owned()))? + .into_inner(); + + let mut acks_sequences: Vec = response + .acknowledgements + .into_iter() + .map(|v| v.sequence.into()) + .collect(); + acks_sequences.sort_unstable(); + + let height = response + .height + .and_then(|raw_height| raw_height.try_into().ok()) + .ok_or_else(|| Error::grpc_response_param("height".to_string()))?; + + Ok((acks_sequences, height)) + } } /// Performs a `QueryUnreceivedAcksRequest` gRPC query to fetch the unreceived acknowledgements @@ -1950,13 +2216,10 @@ impl ChainEndpoint for CosmosSdkChain { ); crate::telemetry!(query, self.id(), "query_unreceived_acknowledgements"); - let mut client = self - .block_on( - ibc_proto::ibc::core::channel::v1::query_client::QueryClient::connect( - self.grpc_addr.clone(), - ), - ) - .map_err(Error::grpc_transport)?; + let mut client = self.block_on(create_grpc_client( + &self.grpc_addr, + ibc_proto::ibc::core::channel::v1::query_client::QueryClient::new, + ))?; client = client .max_decoding_message_size(self.config().max_grpc_decoding_size.get_bytes() as usize); @@ -2023,10 +2286,6 @@ impl ChainEndpoint for CosmosSdkChain { /// 1. Client Update request - returns a vector with at most one update client event /// 2. Transaction event request - returns all IBC events resulted from a Tx execution fn query_txs(&self, request: QueryTxRequest) -> Result, Error> { - crate::time!("query_txs", - { - "src_chain": self.config().id.to_string(), - }); crate::telemetry!(query, self.id(), "query_txs"); self.block_on(query_txs( @@ -2122,6 +2381,12 @@ impl ChainEndpoint for CosmosSdkChain { &self, request: QueryHostConsensusStateRequest, ) -> Result { + crate::time!( + "query_host_consensus_state", + { + "src_chain": self.config().id.to_string(), + } + ); let height = match request.height { QueryHeight::Latest => TmHeight::from(0u32), QueryHeight::Specific(ibc_height) => TmHeight::from(ibc_height), @@ -2152,6 +2417,12 @@ impl ChainEndpoint for CosmosSdkChain { height: ICSHeight, settings: ClientSettings, ) -> Result { + crate::time!( + "build_client_state", + { + "src_chain": self.config().id.to_string(), + } + ); let ClientSettings::Tendermint(settings) = settings; let unbonding_period = self.unbonding_period()?; let trusting_period = settings @@ -2227,12 +2498,18 @@ impl ChainEndpoint for CosmosSdkChain { let address = self.get_signer()?; let key_pair = self.key()?; + let memo_prefix = if let Some(memo_overwrite) = &self.config.memo_overwrite { + memo_overwrite.clone() + } else { + self.config.memo_prefix.clone() + }; + self.rt.block_on(maybe_register_counterparty_payee( &self.rpc_client, &self.tx_config, &key_pair, &mut self.account, - &self.config.memo_prefix, + &memo_prefix, channel_id, port_id, &address, @@ -2268,7 +2545,10 @@ impl ChainEndpoint for CosmosSdkChain { Ok(incentivized_response) } - fn query_consumer_chains(&self) -> Result, Error> { + fn query_consumer_chains(&self) -> Result, Error> { + use ibc_proto::interchain_security::ccv::provider::v1::ConsumerPhase; + use ibc_proto::interchain_security::ccv::provider::v1::QueryConsumerChainsRequest; + crate::time!( "query_consumer_chains", { @@ -2277,16 +2557,15 @@ impl ChainEndpoint for CosmosSdkChain { ); crate::telemetry!(query, self.id(), "query_consumer_chains"); - let mut client = self.block_on( - ibc_proto::interchain_security::ccv::provider::v1::query_client::QueryClient::connect( - self.grpc_addr.clone(), - ), - ) - .map_err(Error::grpc_transport)?; + let mut client = self.block_on(create_grpc_client( + &self.grpc_addr, + ibc_proto::interchain_security::ccv::provider::v1::query_client::QueryClient::new, + ))?; - let request = tonic::Request::new( - ibc_proto::interchain_security::ccv::provider::v1::QueryConsumerChainsRequest {}, - ); + let request = tonic::Request::new(QueryConsumerChainsRequest { + phase: ConsumerPhase::Launched as i32, + pagination: Some(PageRequest::all().into()), + }); let response = self .block_on(client.query_consumer_chains(request)) @@ -2296,11 +2575,103 @@ impl ChainEndpoint for CosmosSdkChain { let result = response .chains .into_iter() - .map(|c| (c.chain_id.parse().unwrap(), c.client_id.parse().unwrap())) - .collect(); + .map(|c| ConsumerChain::try_from(c).map_err(Error::ics24_host_validation_error)) + .collect::, _>>()?; Ok(result) } + + fn query_upgrade( + &self, + request: QueryUpgradeRequest, + height: Height, + include_proof: IncludeProof, + ) -> Result<(Upgrade, Option), Error> { + let port_id = PortId::from_str(&request.port_id) + .map_err(|_| Error::invalid_port_string(request.port_id))?; + let channel_id = ChannelId::from_str(&request.channel_id) + .map_err(|_| Error::invalid_channel_string(request.channel_id))?; + let res = self.query( + ChannelUpgradePath { + port_id, + channel_id, + }, + QueryHeight::Specific(height), + true, + )?; + let upgrade = Upgrade::decode_vec(&res.value).map_err(Error::decode)?; + + match include_proof { + IncludeProof::Yes => { + let proof = res.proof.ok_or_else(Error::empty_response_proof)?; + Ok((upgrade, Some(proof))) + } + IncludeProof::No => Ok((upgrade, None)), + } + } + + fn query_upgrade_error( + &self, + request: QueryUpgradeErrorRequest, + height: Height, + include_proof: IncludeProof, + ) -> Result<(ErrorReceipt, Option), Error> { + let port_id = PortId::from_str(&request.port_id) + .map_err(|_| Error::invalid_port_string(request.port_id))?; + let channel_id = ChannelId::from_str(&request.channel_id) + .map_err(|_| Error::invalid_channel_string(request.channel_id))?; + let res = self.query( + ChannelUpgradeErrorPath { + port_id, + channel_id, + }, + QueryHeight::Specific(height), + true, + )?; + let error_receipt = ErrorReceipt::decode_vec(&res.value).map_err(Error::decode)?; + + match include_proof { + IncludeProof::Yes => { + let proof = res.proof.ok_or_else(Error::empty_response_proof)?; + Ok((error_receipt, Some(proof))) + } + IncludeProof::No => Ok((error_receipt, None)), + } + } + + /// Performs a gRPC query to fetch the CCV ConsumerID corresponding + /// to the given ClientID. + /// + /// Assumes we are the provider chain. + fn query_ccv_consumer_id(&self, client_id: ClientId) -> Result { + use ibc_proto::interchain_security::ccv::provider::v1::query_client::QueryClient; + + crate::telemetry!(query, &self.config.id, "query_ccv_consumer_id"); + crate::time!( + "query_ccv_consumer_id", + { + "src_chain": &self.config.id, + } + ); + + let grpc_addr = Uri::from_str(&self.config.grpc_addr.to_string()) + .map_err(|e| Error::invalid_uri(self.config.grpc_addr.to_string(), e))?; + + let mut client = self + .block_on(create_grpc_client(&grpc_addr, QueryClient::new))? + .max_decoding_message_size(self.config.max_grpc_decoding_size.get_bytes() as usize); + + let request = tonic::Request::new(QueryConsumerIdFromClientIdRequest { + client_id: client_id.to_string(), + }); + + let response = self + .block_on(client.query_consumer_id_from_client_id(request)) + .map_err(|e| Error::grpc_status(e, "query_ccv_consumer_id".to_owned()))?; + + let consumer_id = response.into_inner().consumer_id; + Ok(ConsumerId::new(consumer_id)) + } } fn sort_events_by_sequence(events: &mut [IbcEventWithHeight]) { @@ -2357,6 +2728,17 @@ fn do_health_check(chain: &CosmosSdkChain) -> Result<(), Error> { let grpc_address = chain.grpc_addr.to_string(); let rpc_address = chain.config.rpc_addr.to_string(); + if !chain.config.excluded_sequences.map.is_empty() { + for (channel_id, seqs) in chain.config.excluded_sequences.map.iter() { + if !seqs.is_empty() { + warn!( + "chain '{chain_id}' will not clear packets on channel '{channel_id}' with sequences: {}. \ + Ignore this warning if this configuration is correct.", seqs.iter().copied().collated().format(", ") + ); + } + } + } + chain.block_on(chain.rpc_client.health()).map_err(|e| { Error::health_check_json_rpc( chain_id.clone(), @@ -2382,44 +2764,53 @@ fn do_health_check(chain: &CosmosSdkChain) -> Result<(), Error> { } let relayer_gas_price = &chain.config.gas_price; - let node_min_gas_prices = chain.min_gas_price()?; - - if !node_min_gas_prices.is_empty() { - let mut found_matching_denom = false; - - for price in node_min_gas_prices { - match relayer_gas_price.partial_cmp(&price) { - Some(Ordering::Less) => return Err(Error::gas_price_too_low(chain_id.clone())), - Some(_) => { - found_matching_denom = true; - break; + let node_min_gas_prices_result = chain.min_gas_price()?; + + match node_min_gas_prices_result { + Some(node_min_gas_prices) if !node_min_gas_prices.is_empty() => { + let mut found_matching_denom = false; + + for price in node_min_gas_prices { + match relayer_gas_price.partial_cmp(&price) { + Some(Ordering::Less) => return Err(Error::gas_price_too_low(chain_id.clone())), + Some(_) => { + found_matching_denom = true; + break; + } + None => continue, } - None => continue, } - } - if !found_matching_denom { - warn!( - "Chain '{}' has no minimum gas price of denomination '{}' \ - that is strictly less than the `gas_price` specified for \ - that chain in the Hermes configuration. \ - This is usually a sign of misconfiguration, please check your chain and Hermes configurations", - chain_id, relayer_gas_price.denom - ); + if !found_matching_denom { + warn!( + "chain '{}' does not provide a minimum gas price for denomination '{}'.\ + This is usually a sign of misconfiguration, please check your chain configuration", + chain_id, relayer_gas_price.denom + ); + } } - } else { - warn!( - "Chain '{}' has no minimum gas price value configured for denomination '{}'. \ - This is usually a sign of misconfiguration, please check your chain and \ - relayer configurations", + + Some(_) => warn!( + "chain '{}' does not provide a minimum gas price for denomination '{}'. \ + This is usually a sign of misconfiguration, please check your chain configuration", chain_id, relayer_gas_price.denom - ); + ), + + None => warn!( + "chain '{}' does not implement the `cosmos.base.node.v1beta1.Service/Params` endpoint. \ + It is impossible to check whether the chain's minimum-gas-prices matches the ones specified in config", + chain_id, + ), } - let version_specs = chain.block_on(fetch_version_specs(&chain.config.id, &chain.grpc_addr))?; + let version_specs = chain.block_on(fetch_version_specs( + &chain.config.id, + &chain.rpc_client, + &chain.config.rpc_addr, + ))?; if let Err(diagnostic) = compatibility::run_diagnostic(&version_specs) { - return Err(Error::sdk_module_version( + return Err(Error::compat_check_failed( chain_id.clone(), grpc_address, diagnostic.to_string(), @@ -2433,19 +2824,44 @@ fn do_health_check(chain: &CosmosSdkChain) -> Result<(), Error> { Ok(()) } -#[cfg(test)] -mod tests { - use ibc_relayer_types::{ - core::{ics02_client::client_type::ClientType, ics24_host::identifier::ClientId}, - mock::client_state::MockClientState, - mock::header::MockHeader, - Height, - }; +pub async fn fetch_compat_mode( + client: &HttpClient, + config: &CosmosSdkConfig, +) -> Result { + use crate::util::compat_mode::compat_mode_from_node_version; + use crate::util::compat_mode::compat_mode_from_version_specs; - use crate::client_state::{AnyClientState, IdentifiedAnyClientState}; - use crate::{chain::cosmos::client_id_suffix, config::GasPrice}; + let version_specs = fetch_version_specs(&config.id, client, &config.rpc_addr).await; + let compat_mode = match version_specs { + Ok(specs) => compat_mode_from_version_specs(&config.compat_mode, specs.consensus), + Err(e) => { + warn!( + "Failed to fetch version specs for chain '{}': {e}", + config.id + ); + + let status = client + .status() + .await + .map_err(|e| Error::rpc(config.rpc_addr.clone(), e))?; + + warn!( + "Will fall back on using the node version: {}", + status.node_info.version + ); + + compat_mode_from_node_version(&config.compat_mode, status.node_info.version) + } + }?; + + Ok(compat_mode) +} + +#[cfg(test)] +mod tests { use super::calculate_fee; + use crate::config::GasPrice; #[test] fn mul_ceil() { @@ -2483,38 +2899,4 @@ mod tests { let fee = calculate_fee(gas_amount, &gas_price); assert_eq!(&fee.amount, "90000000000000000000000000"); } - - #[test] - fn sort_clients_id_suffix() { - let mut clients: Vec = vec![ - IdentifiedAnyClientState::new( - ClientId::new(ClientType::Tendermint, 4).unwrap(), - AnyClientState::Mock(MockClientState::new(MockHeader::new( - Height::new(0, 1).unwrap(), - ))), - ), - IdentifiedAnyClientState::new( - ClientId::new(ClientType::Tendermint, 1).unwrap(), - AnyClientState::Mock(MockClientState::new(MockHeader::new( - Height::new(0, 1).unwrap(), - ))), - ), - IdentifiedAnyClientState::new( - ClientId::new(ClientType::Tendermint, 7).unwrap(), - AnyClientState::Mock(MockClientState::new(MockHeader::new( - Height::new(0, 1).unwrap(), - ))), - ), - ]; - clients.sort_by_cached_key(|c| client_id_suffix(&c.client_id).unwrap_or(0)); - assert_eq!( - client_id_suffix(&clients.first().unwrap().client_id).unwrap(), - 1 - ); - assert_eq!(client_id_suffix(&clients[1].client_id).unwrap(), 4); - assert_eq!( - client_id_suffix(&clients.last().unwrap().client_id).unwrap(), - 7 - ); - } } diff --git a/crates/relayer/src/chain/cosmos/compatibility.rs b/crates/relayer/src/chain/cosmos/compatibility.rs index 990fc0b60a..f997081d92 100644 --- a/crates/relayer/src/chain/cosmos/compatibility.rs +++ b/crates/relayer/src/chain/cosmos/compatibility.rs @@ -24,12 +24,18 @@ const IBC_GO_MODULE_VERSION_REQ: &str = ">=4.1.1, <9"; #[derive(Error, Debug)] pub enum Diagnostic { + #[error("SDK module version not found, required {requirements}")] + MissingSdkModuleVersion { requirements: String }, + + #[error("IBC-Go module version not found, required {requirements}")] + MissingIbcGoModuleVersion { requirements: String }, + #[error( "SDK module at version '{found}' does not meet compatibility requirements {requirements}" )] MismatchingSdkModuleVersion { requirements: String, found: String }, - #[error("Ibc-Go module at version '{found}' does not meet compatibility requirements {requirements}")] + #[error("IBC-Go module at version '{found}' does not meet compatibility requirements {requirements}")] MismatchingIbcGoModuleVersion { requirements: String, found: String }, } @@ -44,40 +50,44 @@ pub enum Diagnostic { /// Sdk module by name, as well as the constants /// [`SDK_MODULE_VERSION_REQ`] and [`IBC_GO_MODULE_VERSION_REQ`] /// for establishing compatibility requirements. -pub(crate) fn run_diagnostic(v: &version::Specs) -> Result<(), Diagnostic> { - debug!("running diagnostic on version info {}", v); +pub(crate) fn run_diagnostic(specs: &version::Specs) -> Result<(), Diagnostic> { + debug!("running diagnostic on version specs: {specs}"); - sdk_diagnostic(&v.cosmos_sdk)?; - ibc_go_diagnostic(v.ibc_go.as_ref())?; + sdk_diagnostic(specs.cosmos_sdk.as_ref())?; + ibc_go_diagnostic(specs.ibc_go.as_ref())?; Ok(()) } -fn sdk_diagnostic(version: &semver::Version) -> Result<(), Diagnostic> { +fn sdk_diagnostic(version: Option<&semver::Version>) -> Result<(), Diagnostic> { // Parse the SDK requirements into a semver let sdk_reqs = semver::VersionReq::parse(SDK_MODULE_VERSION_REQ) .expect("parsing the SDK module requirements into semver"); - // Finally, check the version requirements - match sdk_reqs.matches(version) { - true => Ok(()), - false => Err(Diagnostic::MismatchingSdkModuleVersion { + match version { + None => Err(Diagnostic::MissingSdkModuleVersion { requirements: SDK_MODULE_VERSION_REQ.to_string(), - found: version.to_string(), }), + + Some(version) => match sdk_reqs.matches(version) { + true => Ok(()), + false => Err(Diagnostic::MismatchingSdkModuleVersion { + requirements: SDK_MODULE_VERSION_REQ.to_string(), + found: version.to_string(), + }), + }, } } -fn ibc_go_diagnostic(version_info: Option<&semver::Version>) -> Result<(), Diagnostic> { +fn ibc_go_diagnostic(version: Option<&semver::Version>) -> Result<(), Diagnostic> { // Parse the IBC-go module requirements into a semver let ibc_reqs = semver::VersionReq::parse(IBC_GO_MODULE_VERSION_REQ) .expect("parsing the IBC-Go module requirements into semver"); - // Find the Ibc-Go module - match version_info { - // If binary lacks the ibc-go dependency it is _not_ an error, - // we support chains without the standalone ibc-go module. - None => Ok(()), + match version { + None => Err(Diagnostic::MissingIbcGoModuleVersion { + requirements: IBC_GO_MODULE_VERSION_REQ.to_string(), + }), Some(version) => match ibc_reqs.matches(version) { true => Ok(()), false => Err(Diagnostic::MismatchingIbcGoModuleVersion { diff --git a/crates/relayer/src/chain/cosmos/config.rs b/crates/relayer/src/chain/cosmos/config.rs index 57314bccf5..911e147f32 100644 --- a/crates/relayer/src/chain/cosmos/config.rs +++ b/crates/relayer/src/chain/cosmos/config.rs @@ -18,6 +18,7 @@ use crate::config::{ }; use crate::config::{default, RefreshRate}; use crate::keyring::Store; +use crate::util::excluded_sequences::ExcludedSequences; pub mod error; @@ -54,7 +55,7 @@ pub struct CosmosSdkConfig { pub max_gas: Option, // This field is only meant to be set via the `update client` command, - // for when we need to ugprade a client across a genesis restart and + // for when we need to upgrade a client across a genesis restart and // therefore need and archive node to fetch blocks from. pub genesis_restart: Option, @@ -106,6 +107,9 @@ pub struct CosmosSdkConfig { #[serde(default)] pub memo_prefix: Memo, + #[serde(default)] + pub memo_overwrite: Option, + // This is an undocumented and hidden config to make the relayer wait for // DeliverTX before sending the next transaction when sending messages in // multiple batches. We will instruct relayer operators to turn this on @@ -143,6 +147,11 @@ pub struct CosmosSdkConfig { pub extension_options: Vec, pub compat_mode: Option, pub clear_interval: Option, + #[serde(default)] + pub excluded_sequences: ExcludedSequences, + + #[serde(default = "default::allow_ccq")] + pub allow_ccq: bool, } impl CosmosSdkConfig { diff --git a/crates/relayer/src/chain/cosmos/config/error.rs b/crates/relayer/src/chain/cosmos/config/error.rs index 5980ad9ac4..545f845609 100644 --- a/crates/relayer/src/chain/cosmos/config/error.rs +++ b/crates/relayer/src/chain/cosmos/config/error.rs @@ -1,4 +1,6 @@ use flex_error::define_error; +use flex_error::TraceError; + use ibc_relayer_types::core::ics02_client::trust_threshold::TrustThreshold; use ibc_relayer_types::core::ics24_host::identifier::ChainId; @@ -28,5 +30,41 @@ define_error! { e.chain_id, e.gas_adjustment, e.gas_multiplier ) }, + + ExpectedExcludedSequencesArray + |_| { "expected excluded_sequences to be an array of values" }, + + InvalidExcludedSequencesSeparator + { separator: String } + |e| { + format!("excluded_sequences range `{}` is invalid, only '..', '..=' and '-' are valid separators", e.separator) + }, + + MissingStartExcludedSequence + { entry: String } + |e| { + format!("missing the excluded sequence value before the separator in the entry `{}`", e.entry) + }, + + MissingEndExcludedSequence + { entry: String } + |e| { + format!("missing the excluded sequence value after the separator in the entry `{}`", e.entry) + }, + + ParsingStartExcludedSequenceFailed + { entry: String } + [ TraceError ] + |e| { + format!("Error parsing starting sequence as integer in entry `{}`", e.entry) + }, + + + ParsingEndExcludedSequenceFailed + { entry: String } + [ TraceError ] + |e| { + format!("Error parsing ending sequence as integer in entry `{}`", e.entry) + }, } } diff --git a/crates/relayer/src/chain/cosmos/eip_base_fee.rs b/crates/relayer/src/chain/cosmos/eip_base_fee.rs index 75cc9eedd4..5c91fc7ad6 100644 --- a/crates/relayer/src/chain/cosmos/eip_base_fee.rs +++ b/crates/relayer/src/chain/cosmos/eip_base_fee.rs @@ -5,17 +5,35 @@ use std::str::FromStr; use serde::Deserialize; use subtle_encoding::base64; use tendermint_rpc::Url; -use tracing::debug; +use tracing::{debug, trace}; -use ibc_proto::cosmos::base::v1beta1::DecProto; +use ibc_proto::cosmos::base::v1beta1::{DecCoin, DecProto}; +use ibc_relayer_types::core::ics24_host::identifier::ChainId; use crate::error::Error; -pub async fn query_eip_base_fee(rpc_address: &Url) -> Result { +pub async fn query_eip_base_fee( + rpc_address: &Url, + gas_price_denom: &str, + chain_id: &ChainId, +) -> Result { debug!("Querying Omosis EIP-1559 base fee from {rpc_address}"); - let url = - format!("{rpc_address}/abci_query?path=\"/osmosis.txfees.v1beta1.Query/GetEipBaseFee\""); + let chain_name = chain_id.name(); + + let is_osmosis = chain_name.starts_with("osmosis") || chain_name.starts_with("osmo-test"); + + let url = if is_osmosis { + format!( + "{}abci_query?path=\"/osmosis.txfees.v1beta1.Query/GetEipBaseFee\"", + rpc_address + ) + } else { + format!( + "{}abci_query?path=\"/feemarket.feemarket.v1.Query/GasPrices\"&denom={}", + rpc_address, gas_price_denom + ) + }; let response = reqwest::get(&url).await.map_err(Error::http_request)?; @@ -40,7 +58,34 @@ pub async fn query_eip_base_fee(rpc_address: &Url) -> Result { let result: EipBaseFeeHTTPResult = response.json().await.map_err(Error::http_response_body)?; - let encoded = result.result.response.value; + let amount = if is_osmosis { + extract_dynamic_gas_price_osmosis(result.result.response.value)? + } else { + extract_dynamic_gas_price(result.result.response.value)? + }; + + trace!("EIP-1559 base fee: {amount}"); + + Ok(amount) +} + +/// This method extracts the gas base fee from Skip's feemarket +fn extract_dynamic_gas_price(encoded: String) -> Result { + let decoded = base64::decode(encoded).map_err(Error::base64_decode)?; + + let gas_price_response: GasPriceResponse = + prost::Message::decode(decoded.as_ref()).map_err(|e| { + Error::protobuf_decode("feemarket.feemarket.v1.GasPricesResponse".to_string(), e) + })?; + let dec_coin = gas_price_response.price.unwrap().clone(); + let base_fee_uint128 = Uint128::from_str(&dec_coin.amount).map_err(Error::parse_int)?; + + let dec = Decimal::new(base_fee_uint128); + f64::from_str(dec.to_string().as_str()).map_err(Error::parse_float) +} + +/// This method extracts the gas base fee from Osmosis EIP-1559 +fn extract_dynamic_gas_price_osmosis(encoded: String) -> Result { let decoded = base64::decode(encoded).map_err(Error::base64_decode)?; let dec_proto: DecProto = prost::Message::decode(decoded.as_ref()) @@ -49,11 +94,16 @@ pub async fn query_eip_base_fee(rpc_address: &Url) -> Result { let base_fee_uint128 = Uint128::from_str(&dec_proto.dec).map_err(Error::parse_int)?; let dec = Decimal::new(base_fee_uint128); - let base_fee = f64::from_str(dec.to_string().as_str()).map_err(Error::parse_float)?; - - debug!("Omosis EIP-1559 base fee is {}", base_fee); + f64::from_str(dec.to_string().as_str()).map_err(Error::parse_float) +} - Ok(base_fee) +/// GasPriceResponse is the response type for the Query/GasPrice RPC method. +/// Returns a gas price in specified denom. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GasPriceResponse { + #[prost(message, optional, tag = "1")] + pub price: ::core::option::Option, } /// Extracted from `cosmwasm-std` diff --git a/crates/relayer/src/chain/cosmos/encode.rs b/crates/relayer/src/chain/cosmos/encode.rs index 3743c769f5..a64ebd51e8 100644 --- a/crates/relayer/src/chain/cosmos/encode.rs +++ b/crates/relayer/src/chain/cosmos/encode.rs @@ -111,7 +111,7 @@ pub fn sign_tx( fn encode_key_bytes(key_pair: &Secp256k1KeyPair) -> Result, Error> { let mut pk_buf = Vec::new(); - prost::Message::encode(&key_pair.public_key.serialize().to_vec(), &mut pk_buf) + Message::encode(&key_pair.public_key.serialize().to_vec(), &mut pk_buf) .map_err(|e| Error::protobuf_encode("PublicKey".into(), e))?; Ok(pk_buf) @@ -133,7 +133,7 @@ fn encode_sign_doc( // A protobuf serialization of a SignDoc let mut signdoc_buf = Vec::new(); - prost::Message::encode(&sign_doc, &mut signdoc_buf).unwrap(); + Message::encode(&sign_doc, &mut signdoc_buf).unwrap(); let signed = key_pair.sign(&signdoc_buf).map_err(Error::key_base)?; @@ -168,7 +168,7 @@ fn encode_signer_info( fn encode_tx_raw(tx_raw: TxRaw) -> Result, Error> { let mut tx_bytes = Vec::new(); - prost::Message::encode(&tx_raw, &mut tx_bytes) + Message::encode(&tx_raw, &mut tx_bytes) .map_err(|e| Error::protobuf_encode("Transaction".to_string(), e))?; Ok(tx_bytes) @@ -185,6 +185,7 @@ pub fn encode_to_bech32(address: &str, account_prefix: &str) -> Result Result<(AuthInfo, Vec), Error> { + #[allow(deprecated)] let auth_info = AuthInfo { signer_infos: vec![signer_info], fee: Some(fee), @@ -196,7 +197,7 @@ fn auth_info_and_bytes(signer_info: SignerInfo, fee: Fee) -> Result<(AuthInfo, V // A protobuf serialization of a AuthInfo let mut auth_buf = Vec::new(); - prost::Message::encode(&auth_info, &mut auth_buf) + Message::encode(&auth_info, &mut auth_buf) .map_err(|e| Error::protobuf_encode(String::from("AuthInfo"), e))?; Ok((auth_info, auth_buf)) @@ -219,7 +220,7 @@ fn tx_body_and_bytes( // A protobuf serialization of a TxBody let mut body_buf = Vec::new(); - prost::Message::encode(&body, &mut body_buf) + Message::encode(&body, &mut body_buf) .map_err(|e| Error::protobuf_encode(String::from("TxBody"), e))?; Ok((body, body_buf)) diff --git a/crates/relayer/src/chain/cosmos/estimate.rs b/crates/relayer/src/chain/cosmos/estimate.rs index 87a18a26b4..e68ea86b2b 100644 --- a/crates/relayer/src/chain/cosmos/estimate.rs +++ b/crates/relayer/src/chain/cosmos/estimate.rs @@ -14,15 +14,29 @@ use crate::chain::cosmos::types::gas::GasConfig; use crate::config::types::Memo; use crate::error::Error; use crate::keyring::Secp256k1KeyPair; +use crate::telemetry; use crate::util::pretty::PrettyFee; +pub enum EstimatedGas { + Simulated(u64), + Default(u64), +} + +impl EstimatedGas { + pub fn get_amount(&self) -> u64 { + match self { + Self::Simulated(amount) | Self::Default(amount) => *amount, + } + } +} + pub async fn estimate_tx_fees( config: &TxConfig, key_pair: &Secp256k1KeyPair, account: &Account, tx_memo: &Memo, messages: &[Any], -) -> Result { +) -> Result<(Fee, EstimatedGas), Error> { let gas_config = &config.gas_config; debug!( @@ -45,16 +59,17 @@ pub async fn estimate_tx_fees( signatures: signed_tx.signatures, }; - let estimated_fee = estimate_fee_with_tx( + let estimated_fee_and_gas = estimate_fee_with_tx( gas_config, &config.grpc_address, &config.rpc_address, &config.chain_id, tx, + account, ) .await?; - Ok(estimated_fee) + Ok(estimated_fee_and_gas) } async fn estimate_fee_with_tx( @@ -63,7 +78,8 @@ async fn estimate_fee_with_tx( rpc_address: &Url, chain_id: &ChainId, tx: Tx, -) -> Result { + account: &Account, +) -> Result<(Fee, EstimatedGas), Error> { let estimated_gas = { crate::time!( "estimate_gas_with_tx", @@ -72,32 +88,35 @@ async fn estimate_fee_with_tx( } ); - estimate_gas_with_tx(gas_config, grpc_address, tx).await + estimate_gas_with_tx(gas_config, grpc_address, tx, account).await }?; - if estimated_gas > gas_config.max_gas { + let estimated_gas_amount = estimated_gas.get_amount(); + + if estimated_gas_amount > gas_config.max_gas { debug!( - id = %chain_id, estimated = ?estimated_gas, max = ?gas_config.max_gas, + id = %chain_id, estimated = ?estimated_gas_amount, max = ?gas_config.max_gas, "send_tx: estimated gas is higher than max gas" ); return Err(Error::tx_simulate_gas_estimate_exceeded( chain_id.clone(), - estimated_gas, + estimated_gas_amount, gas_config.max_gas, )); } - let adjusted_fee = gas_amount_to_fee(gas_config, estimated_gas, chain_id, rpc_address).await; + let adjusted_fee = + gas_amount_to_fee(gas_config, estimated_gas_amount, chain_id, rpc_address).await; debug!( id = %chain_id, "send_tx: using {} gas, fee {}", - estimated_gas, + estimated_gas_amount, PrettyFee(&adjusted_fee) ); - Ok(adjusted_fee) + Ok((adjusted_fee, estimated_gas)) } /// Try to simulate the given tx in order to estimate how much gas will be needed to submit it. @@ -112,7 +131,8 @@ async fn estimate_gas_with_tx( gas_config: &GasConfig, grpc_address: &Uri, tx: Tx, -) -> Result { + _account: &Account, +) -> Result { let simulated_gas = send_tx_simulate(grpc_address, tx) .await .map(|sr| sr.gas_info); @@ -126,7 +146,7 @@ async fn estimate_gas_with_tx( gas_info.gas_used ); - Ok(gas_info.gas_used) + Ok(EstimatedGas::Simulated(gas_info.gas_used)) } Ok(None) => { @@ -135,7 +155,7 @@ async fn estimate_gas_with_tx( gas_config.default_gas ); - Ok(gas_config.default_gas) + Ok(EstimatedGas::Default(gas_config.default_gas)) } // If there is a chance that the tx will be accepted once actually submitted, we fall @@ -147,7 +167,14 @@ async fn estimate_gas_with_tx( e.detail() ); - Ok(gas_config.default_gas) + telemetry!( + simulate_errors, + &_account.address.to_string(), + true, + get_error_text(&e), + ); + + Ok(EstimatedGas::Default(gas_config.default_gas)) } Err(e) => { @@ -155,6 +182,14 @@ async fn estimate_gas_with_tx( "failed to simulate tx. propagating error to caller: {}", e.detail() ); + + telemetry!( + simulate_errors, + &_account.address.to_string(), + false, + get_error_text(&e), + ); + // Propagate the error, the retrying mechanism at caller may catch & retry. Err(e) } @@ -171,7 +206,17 @@ fn can_recover_from_simulation_failure(e: &Error) -> bool { detail.is_client_state_height_too_low() || detail.is_account_sequence_mismatch_that_can_be_ignored() || detail.is_out_of_order_packet_sequence_error() + || detail.is_empty_tx_error() } _ => false, } } + +fn get_error_text(e: &Error) -> String { + use crate::error::ErrorDetail::*; + + match e.detail() { + GrpcStatus(detail) => detail.status.code().to_string(), + detail => detail.to_string(), + } +} diff --git a/crates/relayer/src/chain/cosmos/gas.rs b/crates/relayer/src/chain/cosmos/gas.rs index 07b4b6a20f..2106da3375 100644 --- a/crates/relayer/src/chain/cosmos/gas.rs +++ b/crates/relayer/src/chain/cosmos/gas.rs @@ -43,7 +43,7 @@ pub async fn dynamic_gas_price( rpc_address: &Url, ) -> GasPrice { if config.dynamic_gas_price.enabled { - let dynamic_gas_price = query_eip_base_fee(rpc_address) + let dynamic_gas_price = query_eip_base_fee(rpc_address, &config.gas_price.denom, chain_id) .await .map(|base_fee| base_fee * config.dynamic_gas_price.multiplier) .map(|new_price| GasPrice { diff --git a/crates/relayer/src/chain/cosmos/query.rs b/crates/relayer/src/chain/cosmos/query.rs index 4869056b7b..ad6a2c91b8 100644 --- a/crates/relayer/src/chain/cosmos/query.rs +++ b/crates/relayer/src/chain/cosmos/query.rs @@ -1,21 +1,22 @@ -use http::uri::Uri; -use ibc_proto::cosmos::base::tendermint::v1beta1::service_client::ServiceClient; -use ibc_proto::cosmos::base::tendermint::v1beta1::GetNodeInfoRequest; +use ibc_proto::cosmos::base::tendermint::v1beta1::GetNodeInfoResponse; use ibc_relayer_types::core::ics04_channel::packet::Sequence; use ibc_relayer_types::core::ics23_commitment::merkle::{ convert_tm_to_ics_merkle_proof, MerkleProof, }; use ibc_relayer_types::core::ics24_host::identifier::ChainId; +use prost::Message; use tendermint::block::Height; use tendermint_rpc::query::Query; use tendermint_rpc::{Client, HttpClient, Url}; use crate::chain::cosmos::version::Specs; +use crate::chain::requests::QueryHeight; use crate::chain::requests::{QueryClientEventRequest, QueryPacketEventDataRequest, QueryTxHash}; use crate::error::Error; pub mod account; pub mod balance; +pub mod connection; pub mod consensus_state; pub mod custom; pub mod denom_trace; @@ -120,36 +121,32 @@ pub async fn abci_query( } /// Queries the chain to obtain the version information. -pub async fn fetch_version_specs(chain_id: &ChainId, grpc_address: &Uri) -> Result { - let grpc_addr_string = grpc_address.to_string(); - - // Construct a gRPC client - let mut client = ServiceClient::connect(grpc_address.clone()) - .await - .map_err(|e| { - Error::fetch_version_grpc_transport( - chain_id.clone(), - grpc_addr_string.clone(), - "tendermint::ServiceClient".to_string(), +pub async fn fetch_version_specs( + chain_id: &ChainId, + rpc_client: &HttpClient, + rpc_addr: &Url, +) -> Result { + let query_response = abci_query( + rpc_client, + rpc_addr, + "/cosmos.base.tendermint.v1beta1.Service/GetNodeInfo".to_owned(), + "".to_owned(), + QueryHeight::Latest.into(), + false, + ) + .await?; + let node_info_response = + GetNodeInfoResponse::decode(query_response.value.as_ref()).map_err(|e| { + Error::protobuf_decode( + "cosmos.base.tendermint.v1beta1.Service/GetNodeInfo".to_owned(), e, ) })?; - let request = tonic::Request::new(GetNodeInfoRequest {}); - - let response = client.get_node_info(request).await.map_err(|e| { - Error::fetch_version_grpc_status( - chain_id.clone(), - grpc_addr_string.clone(), - "tendermint::ServiceClient".to_string(), - e, - ) - })?; - - let version = response.into_inner().application_version.ok_or_else(|| { + let version = node_info_response.application_version.ok_or_else(|| { Error::fetch_version_invalid_version_response( chain_id.clone(), - grpc_addr_string.clone(), + rpc_addr.to_string(), "tendermint::GetNodeInfoRequest".to_string(), ) })?; @@ -157,5 +154,5 @@ pub async fn fetch_version_specs(chain_id: &ChainId, grpc_address: &Uri) -> Resu // Parse the raw version info into a domain-type `version::Specs` version .try_into() - .map_err(|e| Error::fetch_version_parsing(chain_id.clone(), grpc_addr_string.clone(), e)) + .map_err(|e| Error::fetch_version_parsing(chain_id.clone(), rpc_addr.to_string(), e)) } diff --git a/crates/relayer/src/chain/cosmos/query/account.rs b/crates/relayer/src/chain/cosmos/query/account.rs index e24c414ff7..eb8e1dc8b8 100644 --- a/crates/relayer/src/chain/cosmos/query/account.rs +++ b/crates/relayer/src/chain/cosmos/query/account.rs @@ -1,12 +1,26 @@ use http::uri::Uri; use ibc_proto::cosmos::auth::v1beta1::query_client::QueryClient; -use ibc_proto::cosmos::auth::v1beta1::{BaseAccount, EthAccount, QueryAccountRequest}; +use ibc_proto::cosmos::auth::v1beta1::{BaseAccount, QueryAccountRequest}; use prost::Message; use tracing::info; use crate::chain::cosmos::types::account::Account; use crate::config::default::max_grpc_decoding_size; use crate::error::Error; +use crate::util::create_grpc_client; + +/// EthAccount defines an Ethermint account. +/// TODO: remove when/if a canonical `EthAccount` +/// lands in the next Cosmos SDK release +/// (note +/// only adds the PubKey type) +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct EthAccount { + #[prost(message, optional, tag = "1")] + pub base_account: ::core::option::Option, + #[prost(bytes = "vec", tag = "2")] + pub code_hash: ::prost::alloc::vec::Vec, +} /// Get a `&mut Account` from an `&mut Option` if it is `Some(Account)`. /// Otherwise query for the account information, update the `Option` to `Some`, @@ -54,9 +68,7 @@ pub async fn query_account( grpc_address: &Uri, account_address: &str, ) -> Result { - let mut client = QueryClient::connect(grpc_address.clone()) - .await - .map_err(Error::grpc_transport)?; + let mut client = create_grpc_client(grpc_address, QueryClient::new).await?; client = client.max_decoding_message_size(max_grpc_decoding_size().get_bytes() as usize); diff --git a/crates/relayer/src/chain/cosmos/query/balance.rs b/crates/relayer/src/chain/cosmos/query/balance.rs index 114bd27e74..23053fd807 100644 --- a/crates/relayer/src/chain/cosmos/query/balance.rs +++ b/crates/relayer/src/chain/cosmos/query/balance.rs @@ -7,6 +7,7 @@ use ibc_proto::cosmos::bank::v1beta1::{ use crate::account::Balance; use crate::config::default::max_grpc_decoding_size; use crate::error::Error; +use crate::util::create_grpc_client; /// Uses the GRPC client to retrieve the account balance for a specific denom pub async fn query_balance( @@ -14,9 +15,7 @@ pub async fn query_balance( account_address: &str, denom: &str, ) -> Result { - let mut client = QueryClient::connect(grpc_address.clone()) - .await - .map_err(Error::grpc_transport)?; + let mut client = create_grpc_client(grpc_address, QueryClient::new).await?; client = client.max_decoding_message_size(max_grpc_decoding_size().get_bytes() as usize); @@ -47,15 +46,14 @@ pub async fn query_all_balances( grpc_address: &Uri, account_address: &str, ) -> Result, Error> { - let mut client = QueryClient::connect(grpc_address.clone()) - .await - .map_err(Error::grpc_transport)?; + let mut client = create_grpc_client(grpc_address, QueryClient::new).await?; client = client.max_decoding_message_size(max_grpc_decoding_size().get_bytes() as usize); let request = tonic::Request::new(QueryAllBalancesRequest { address: account_address.to_string(), pagination: None, + resolve_denom: false, // TODO: Correctly handle resolve_denom argument }); let response = client diff --git a/crates/relayer/src/chain/cosmos/query/connection.rs b/crates/relayer/src/chain/cosmos/query/connection.rs new file mode 100644 index 0000000000..7ae553f31e --- /dev/null +++ b/crates/relayer/src/chain/cosmos/query/connection.rs @@ -0,0 +1,29 @@ +use http::uri::Uri; + +use ibc_proto::ibc::core::connection::v1::query_client::QueryClient; +use ibc_proto::ibc::core::connection::v1::Params; +use ibc_proto::ibc::core::connection::v1::QueryConnectionParamsRequest; + +use crate::config::default::max_grpc_decoding_size; +use crate::error::Error; +use crate::util::create_grpc_client; + +/// Uses the GRPC client to retrieve the connection params +pub async fn query_connection_params(grpc_address: &Uri) -> Result { + let mut client = create_grpc_client(grpc_address, QueryClient::new).await?; + + client = client.max_decoding_message_size(max_grpc_decoding_size().get_bytes() as usize); + + let request = tonic::Request::new(QueryConnectionParamsRequest {}); + + let response = client + .connection_params(request) + .await + .map(|r| r.into_inner()) + .map_err(|e| Error::grpc_status(e, "query_connection_params".to_owned()))?; + + // Querying connection params might not be found + let params = response.params.ok_or_else(Error::empty_connection_params)?; + + Ok(params) +} diff --git a/crates/relayer/src/chain/cosmos/query/consensus_state.rs b/crates/relayer/src/chain/cosmos/query/consensus_state.rs index 54c9f7905d..f844082ec0 100644 --- a/crates/relayer/src/chain/cosmos/query/consensus_state.rs +++ b/crates/relayer/src/chain/cosmos/query/consensus_state.rs @@ -7,6 +7,7 @@ use crate::chain::requests::{QueryConsensusStateHeightsRequest, QueryConsensusSt use crate::config::default::max_grpc_decoding_size; use crate::consensus_state::AnyConsensusStateWithHeight; use crate::error::Error; +use crate::util::create_grpc_client; use crate::util::pretty::{PrettyConsensusStateWithHeight, PrettyHeight}; /// Performs a `QueryConsensusStateHeightsRequest` gRPC query to fetch all the consensus state @@ -36,10 +37,11 @@ pub async fn query_consensus_state_heights( .contains("unknown method ConsensusStateHeights") } - let mut client = - ibc_proto::ibc::core::client::v1::query_client::QueryClient::connect(grpc_addr.clone()) - .await - .map_err(Error::grpc_transport)?; + let mut client = create_grpc_client( + grpc_addr, + ibc_proto::ibc::core::client::v1::query_client::QueryClient::new, + ) + .await?; client = client.max_decoding_message_size(max_grpc_decoding_size().get_bytes() as usize); @@ -72,7 +74,7 @@ pub async fn query_consensus_state_heights( .consensus_state_heights .into_iter() .filter_map(|h| { - Height::try_from(h.clone()) + Height::try_from(h) .map_err(|e| { warn!( "failed to parse consensus state height {}. Error: {}", @@ -105,10 +107,11 @@ pub async fn query_consensus_states( } ); - let mut client = - ibc_proto::ibc::core::client::v1::query_client::QueryClient::connect(grpc_addr.clone()) - .await - .map_err(Error::grpc_transport)?; + let mut client = create_grpc_client( + grpc_addr, + ibc_proto::ibc::core::client::v1::query_client::QueryClient::new, + ) + .await?; client = client.max_decoding_message_size(max_grpc_decoding_size().get_bytes() as usize); diff --git a/crates/relayer/src/chain/cosmos/query/custom.rs b/crates/relayer/src/chain/cosmos/query/custom.rs index e842510b1b..a31c64db47 100644 --- a/crates/relayer/src/chain/cosmos/query/custom.rs +++ b/crates/relayer/src/chain/cosmos/query/custom.rs @@ -1,16 +1,17 @@ use crate::chain::requests::CrossChainQueryRequest; use crate::error::Error; -use hex; + use ibc_relayer_types::applications::ics31_icq::{ error::Error as CrossChainQueryError, response::CrossChainQueryResponse, }; + use tendermint_rpc::{Client, HttpClient}; pub async fn cross_chain_query_via_rpc( client: &HttpClient, cross_chain_query_request: CrossChainQueryRequest, ) -> Result { - let hex_decoded_request = hex::decode(cross_chain_query_request.request) + let hex_decoded_request = hex::decode(cross_chain_query_request.request.to_lowercase()) .map_err(|_| Error::ics31(CrossChainQueryError::parse()))?; let response = client diff --git a/crates/relayer/src/chain/cosmos/query/denom_trace.rs b/crates/relayer/src/chain/cosmos/query/denom_trace.rs index a0ef33cff0..27f9c7ca58 100644 --- a/crates/relayer/src/chain/cosmos/query/denom_trace.rs +++ b/crates/relayer/src/chain/cosmos/query/denom_trace.rs @@ -7,12 +7,11 @@ use ibc_proto::ibc::applications::transfer::v1::{ use crate::config::default::max_grpc_decoding_size; use crate::denom::DenomTrace; use crate::error::Error; +use crate::util::create_grpc_client; // Uses the GRPC client to retrieve the denom trace for a specific hash pub async fn query_denom_trace(grpc_address: &Uri, hash: &str) -> Result { - let mut client = QueryClient::connect(grpc_address.clone()) - .await - .map_err(Error::grpc_transport)?; + let mut client = create_grpc_client(grpc_address, QueryClient::new).await?; client = client.max_decoding_message_size(max_grpc_decoding_size().get_bytes() as usize); diff --git a/crates/relayer/src/chain/cosmos/query/fee.rs b/crates/relayer/src/chain/cosmos/query/fee.rs index fab58fcc2a..79e9d8175b 100644 --- a/crates/relayer/src/chain/cosmos/query/fee.rs +++ b/crates/relayer/src/chain/cosmos/query/fee.rs @@ -13,15 +13,14 @@ use tonic::Code; use crate::config::default::max_grpc_decoding_size; use crate::error::Error; +use crate::util::create_grpc_client; pub async fn query_counterparty_payee( grpc_address: &Uri, channel_id: &ChannelId, address: &Signer, ) -> Result, Error> { - let mut client = QueryClient::connect(grpc_address.clone()) - .await - .map_err(Error::grpc_transport)?; + let mut client = create_grpc_client(grpc_address, QueryClient::new).await?; client = client.max_decoding_message_size(max_grpc_decoding_size().get_bytes() as usize); @@ -53,9 +52,7 @@ pub async fn query_incentivized_packets( channel_id: &ChannelId, port_id: &PortId, ) -> Result, Error> { - let mut client = QueryClient::connect(grpc_address.clone()) - .await - .map_err(Error::grpc_transport)?; + let mut client = create_grpc_client(grpc_address, QueryClient::new).await?; client = client.max_decoding_message_size(max_grpc_decoding_size().get_bytes() as usize); @@ -87,9 +84,7 @@ pub async fn query_incentivized_packet( grpc_address: &Uri, request: QueryIncentivizedPacketRequest, ) -> Result { - let mut client = QueryClient::connect(grpc_address.clone()) - .await - .map_err(Error::grpc_transport)?; + let mut client = create_grpc_client(grpc_address, QueryClient::new).await?; client = client.max_decoding_message_size(max_grpc_decoding_size().get_bytes() as usize); diff --git a/crates/relayer/src/chain/cosmos/query/tx.rs b/crates/relayer/src/chain/cosmos/query/tx.rs index e6897c02a4..317ea9e6d0 100644 --- a/crates/relayer/src/chain/cosmos/query/tx.rs +++ b/crates/relayer/src/chain/cosmos/query/tx.rs @@ -75,6 +75,12 @@ pub async fn query_txs( } QueryTxRequest::Transaction(tx) => { + crate::time!( + "query_txs: transaction hash", + { + "src_chain": chain_id, + } + ); let mut response = rpc_client .tx_search( tx_hash_query(&tx), diff --git a/crates/relayer/src/chain/cosmos/retry.rs b/crates/relayer/src/chain/cosmos/retry.rs index 305edf3d92..45c4074ba3 100644 --- a/crates/relayer/src/chain/cosmos/retry.rs +++ b/crates/relayer/src/chain/cosmos/retry.rs @@ -1,7 +1,7 @@ use core::time::Duration; use std::thread; -use tracing::{debug, error, instrument, warn}; +use tracing::{debug, error, info, instrument, warn}; use ibc_proto::google::protobuf::Any; use tendermint::abci::Code; @@ -103,7 +103,7 @@ async fn do_send_tx_with_account_sequence_retry( // NOTE: The error code could potentially overlap between Cosmos SDK and Ibc-go channel // error codes. This is currently not the case of incorrect account sequence error //which is the Cosmos SDK code 32 and Ibc-go channel errors only go up to 25. - Ok(ref response) if response.code == Code::from(INCORRECT_ACCOUNT_SEQUENCE_ERR) => { + Ok((ref response, _)) if response.code == Code::from(INCORRECT_ACCOUNT_SEQUENCE_ERR) => { warn!( ?response, "failed to broadcast tx because of a mismatched account sequence number, \ @@ -125,7 +125,7 @@ async fn do_send_tx_with_account_sequence_retry( // Gas estimation succeeded and broadcast_tx_sync was either successful or has failed with // an unrecoverable error. - Ok(response) => { + Ok((response, estimated_gas)) => { debug!("gas estimation succeeded"); // Gas estimation and broadcast_tx_sync were successful. @@ -149,13 +149,24 @@ async fn do_send_tx_with_account_sequence_retry( Ok(response) } + Code::Err(code) if response.log.contains("packet messages are redundant") => { + info!( + ?response, + diagnostic = response.log, + ?code, + "broadcast tx was not completed, all packets in tx have been relayed already, no fees were consumed" + ); + + Ok(response) + } + // Gas estimation succeeded, but broadcast_tx_sync failed with unrecoverable error. Code::Err(code) => { // Do not increase the account s.n. since CheckTx step of broadcast_tx_sync has failed. // Log the error. error!( ?response, - diagnostic = ?sdk_error_from_tx_sync_error_code(code.into()), + diagnostic = ?sdk_error_from_tx_sync_error_code(code.into(), estimated_gas), "failed to broadcast tx with unrecoverable error" ); @@ -195,7 +206,10 @@ async fn refresh_account_and_retry_send_tx_with_account_sequence( // Retry after delay thread::sleep(Duration::from_millis(ACCOUNT_SEQUENCE_RETRY_DELAY)); - estimate_fee_and_send_tx(rpc_client, config, key_pair, account, tx_memo, messages).await + let (estimate_result, _) = + estimate_fee_and_send_tx(rpc_client, config, key_pair, account, tx_memo, messages).await?; + + Ok(estimate_result) } /// Determine whether the given error yielded by `tx_simulate` diff --git a/crates/relayer/src/chain/cosmos/simulate.rs b/crates/relayer/src/chain/cosmos/simulate.rs index 0cb142d698..6b2661363f 100644 --- a/crates/relayer/src/chain/cosmos/simulate.rs +++ b/crates/relayer/src/chain/cosmos/simulate.rs @@ -4,6 +4,7 @@ use tonic::codegen::http::Uri; use crate::config::default::max_grpc_decoding_size; use crate::error::Error; +use crate::util::create_grpc_client; pub async fn send_tx_simulate(grpc_address: &Uri, tx: Tx) -> Result { let mut tx_bytes = vec![]; @@ -15,9 +16,7 @@ pub async fn send_tx_simulate(grpc_address: &Uri, tx: Tx) -> Result Result { - let fee = estimate_tx_fees(config, key_pair, account, tx_memo, messages).await?; +) -> Result<(Response, EstimatedGas), Error> { + let (fee, estimated_gas) = + estimate_tx_fees(config, key_pair, account, tx_memo, messages).await?; - send_tx_with_fee( + let tx_result = send_tx_with_fee( rpc_client, config, key_pair, account, tx_memo, messages, &fee, ) - .await + .await?; + + Ok((tx_result, estimated_gas)) } async fn send_tx_with_fee( @@ -87,7 +91,7 @@ pub async fn simple_send_tx( .await? .into(); - let response = estimate_fee_and_send_tx( + let (response, _) = estimate_fee_and_send_tx( rpc_client, config, key_pair, diff --git a/crates/relayer/src/chain/cosmos/types/app_state.rs b/crates/relayer/src/chain/cosmos/types/app_state.rs deleted file mode 100644 index 256a1017a2..0000000000 --- a/crates/relayer/src/chain/cosmos/types/app_state.rs +++ /dev/null @@ -1,47 +0,0 @@ -//! Structure used to parse queried Genesis state using -//! /genesis RPC endpoint. - -use serde::Deserialize as SerdeDeserialize; -use serde_derive::Deserialize; -use serde_derive::Serialize; - -#[derive(Debug, Deserialize, Serialize)] -pub struct GenesisAppState { - ibc: IbcConfig, -} - -impl GenesisAppState { - pub fn max_expected_time_per_block(&self) -> u64 { - self.ibc - .connection_genesis - .params - .max_expected_time_per_block - } -} - -#[derive(Debug, Deserialize, Serialize)] -struct IbcConfig { - connection_genesis: ConnectionGenesisConfig, -} - -#[derive(Debug, Deserialize, Serialize)] -struct ConnectionGenesisConfig { - params: ConnectionGenesisParams, -} - -#[derive(Debug, Deserialize, Serialize)] -struct ConnectionGenesisParams { - #[serde(deserialize_with = "deserialize_max_expected_per_block")] - max_expected_time_per_block: u64, -} - -fn deserialize_max_expected_per_block<'de, T, D>(de: D) -> Result -where - D: serde::Deserializer<'de>, - T: std::str::FromStr, - ::Err: std::fmt::Display, -{ - String::deserialize(de)? - .parse() - .map_err(serde::de::Error::custom) -} diff --git a/crates/relayer/src/chain/cosmos/types/events/channel.rs b/crates/relayer/src/chain/cosmos/types/events/channel.rs index fa09493913..7a1313ae00 100644 --- a/crates/relayer/src/chain/cosmos/types/events/channel.rs +++ b/crates/relayer/src/chain/cosmos/types/events/channel.rs @@ -1,17 +1,20 @@ use alloc::collections::btree_map::BTreeMap as HashMap; +use ibc_relayer_types::applications::ics31_icq::events::CrossChainQueryPacket; use ibc_relayer_types::core::ics02_client::height::HeightErrorDetail; use ibc_relayer_types::core::ics04_channel::error::Error; use ibc_relayer_types::core::ics04_channel::events::{ AcknowledgePacket, Attributes, CloseConfirm, CloseInit, EventType, OpenAck, OpenConfirm, - OpenInit, OpenTry, SendPacket, TimeoutPacket, WriteAcknowledgement, PKT_ACK_ATTRIBUTE_KEY, - PKT_DATA_ATTRIBUTE_KEY, PKT_DST_CHANNEL_ATTRIBUTE_KEY, PKT_DST_PORT_ATTRIBUTE_KEY, - PKT_SEQ_ATTRIBUTE_KEY, PKT_SRC_CHANNEL_ATTRIBUTE_KEY, PKT_SRC_PORT_ATTRIBUTE_KEY, - PKT_TIMEOUT_HEIGHT_ATTRIBUTE_KEY, PKT_TIMEOUT_TIMESTAMP_ATTRIBUTE_KEY, + OpenInit, OpenTry, SendPacket, TimeoutPacket, UpgradeAttributes, UpgradeInit, + WriteAcknowledgement, PKT_ACK_ATTRIBUTE_KEY, PKT_DATA_ATTRIBUTE_KEY, + PKT_DST_CHANNEL_ATTRIBUTE_KEY, PKT_DST_PORT_ATTRIBUTE_KEY, PKT_SEQ_ATTRIBUTE_KEY, + PKT_SRC_CHANNEL_ATTRIBUTE_KEY, PKT_SRC_PORT_ATTRIBUTE_KEY, PKT_TIMEOUT_HEIGHT_ATTRIBUTE_KEY, + PKT_TIMEOUT_TIMESTAMP_ATTRIBUTE_KEY, }; use ibc_relayer_types::core::ics04_channel::events::{ReceivePacket, TimeoutOnClosePacket}; use ibc_relayer_types::core::ics04_channel::packet::Packet; use ibc_relayer_types::core::ics04_channel::timeout::TimeoutHeight; +use ibc_relayer_types::core::ics24_host::identifier::ChainId; use ibc_relayer_types::events::Error as EventError; use ibc_relayer_types::Height; @@ -39,6 +42,46 @@ fn extract_attributes(object: &RawObject<'_>, namespace: &str) -> Result, + namespace: &str, +) -> Result { + Ok(UpgradeAttributes { + port_id: extract_attribute(object, &format!("{namespace}.port_id"))? + .parse() + .map_err(EventError::parse)?, + channel_id: extract_attribute(object, &format!("{namespace}.channel_id"))? + .parse() + .map_err(EventError::parse)?, + counterparty_port_id: extract_attribute( + object, + &format!("{namespace}.counterparty_port_id"), + )? + .parse() + .map_err(EventError::parse)?, + counterparty_channel_id: maybe_extract_attribute( + object, + &format!("{namespace}.counterparty_channel_id"), + ) + .and_then(|v| v.parse().ok()), + upgrade_sequence: extract_attribute(object, &format!("{namespace}.upgrade_sequence"))? + .parse() + .map_err(|_| EventError::missing_action_string())?, + upgrade_timeout_height: maybe_extract_attribute( + object, + &format!("{namespace}.timeout_height"), + ) + .and_then(|v| v.parse().ok()), + upgrade_timeout_timestamp: maybe_extract_attribute( + object, + &format!("{namespace}.timeout_timestamp"), + ) + .and_then(|v| v.parse().ok()), + error_receipt: maybe_extract_attribute(object, &format!("{namespace}.error_receipt")) + .and_then(|v| v.parse().ok()), + }) +} + macro_rules! impl_try_from_raw_obj_for_event { ($($event:ty),+) => { $(impl TryFrom> for $event { @@ -66,11 +109,7 @@ macro_rules! impl_try_from_raw_obj_for_packet { type Error = EventError; fn try_from(obj: RawObject<'_>) -> Result { - 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()); - + let packet = Packet::try_from(obj)?; Ok(Self { packet }) } })+ @@ -89,18 +128,26 @@ impl TryFrom> for WriteAcknowledgement { type Error = EventError; fn try_from(obj: RawObject<'_>) -> Result { - 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 ack_str = + extract_attribute(&obj, &format!("{}.{}", obj.action, PKT_ACK_ATTRIBUTE_KEY))?; + + let ack = hex::decode(ack_str.to_lowercase()) + .map_err(|_| EventError::invalid_packet_ack(ack_str))?; - let mut packet = Packet::try_from(obj)?; - packet.data = Vec::from(data_str.as_bytes()); + let packet = Packet::try_from(obj)?; Ok(Self { packet, ack }) } } +impl TryFrom> for UpgradeInit { + type Error = EventError; + + fn try_from(obj: RawObject<'_>) -> Result { + extract_upgrade_attributes(&obj, Self::event_type().as_str())?.try_into() + } +} + /// Parse a string into a timeout height expected to be stored in /// `Packet.timeout_height`. We need to parse the timeout height differently /// because of a quirk introduced in ibc-go. See comment in @@ -117,7 +164,14 @@ pub fn parse_timeout_height(s: &str) -> Result { impl TryFrom> for Packet { type Error = EventError; + fn try_from(obj: RawObject<'_>) -> Result { + let data_str = + extract_attribute(&obj, &format!("{}.{}", obj.action, PKT_DATA_ATTRIBUTE_KEY))?; + + let data = hex::decode(data_str.to_lowercase()) + .map_err(|_| EventError::invalid_packet_data(data_str))?; + Ok(Packet { sequence: extract_attribute( &obj, @@ -125,31 +179,37 @@ impl TryFrom> for Packet { )? .parse() .map_err(EventError::channel)?, + source_port: extract_attribute( &obj, &format!("{}.{}", obj.action, PKT_SRC_PORT_ATTRIBUTE_KEY), )? .parse() .map_err(EventError::parse)?, + source_channel: extract_attribute( &obj, &format!("{}.{}", obj.action, PKT_SRC_CHANNEL_ATTRIBUTE_KEY), )? .parse() .map_err(EventError::parse)?, + destination_port: extract_attribute( &obj, &format!("{}.{}", obj.action, PKT_DST_PORT_ATTRIBUTE_KEY), )? .parse() .map_err(EventError::parse)?, + destination_channel: extract_attribute( &obj, &format!("{}.{}", obj.action, PKT_DST_CHANNEL_ATTRIBUTE_KEY), )? .parse() .map_err(EventError::parse)?, - data: vec![], + + data, + timeout_height: { let timeout_height_str = extract_attribute( &obj, @@ -167,6 +227,28 @@ impl TryFrom> for Packet { } } +impl TryFrom> for CrossChainQueryPacket { + type Error = EventError; + + fn try_from(obj: RawObject<'_>) -> Result { + Ok(Self { + module: extract_attribute(&obj, &format!("{}.module", obj.action))?, + action: extract_attribute(&obj, &format!("{}.action", obj.action))?, + query_id: extract_attribute(&obj, &format!("{}.query_id", obj.action))?, + chain_id: extract_attribute(&obj, &format!("{}.chain_id", obj.action)) + .map(|s| ChainId::from_string(&s))?, + connection_id: extract_attribute(&obj, &format!("{}.connection_id", obj.action))? + .parse() + .map_err(EventError::parse)?, + query_type: extract_attribute(&obj, &format!("{}.type", obj.action))?, + request: extract_attribute(&obj, &format!("{}.request", obj.action))?, + height: extract_attribute(&obj, &format!("{}.height", obj.action))? + .parse() + .map_err(|_| EventError::height())?, + }) + } +} + #[derive(Debug, Clone)] pub struct RawObject<'a> { pub height: Height, diff --git a/crates/relayer/src/chain/cosmos/types/events/client.rs b/crates/relayer/src/chain/cosmos/types/events/client.rs index f4e27264bc..fcb1415ef7 100644 --- a/crates/relayer/src/chain/cosmos/types/events/client.rs +++ b/crates/relayer/src/chain/cosmos/types/events/client.rs @@ -77,50 +77,3 @@ pub fn extract_header_from_tx(event: &AbciEvent) -> Result, Erro } Err(Error::missing_raw_header()) } - -#[cfg(test)] -mod tests { - use ibc_relayer_types::core::ics02_client::client_type::ClientType; - use ibc_relayer_types::mock::header::MockHeader; - use ibc_relayer_types::Height; - - use super::*; - - #[test] - fn client_event_to_abci_event() { - let height = Height::new(1, 1).unwrap(); - 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 = AnyHeader::Mock(MockHeader::new(height)); - update_client.header = Some(header.into_box()); - 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/crates/relayer/src/chain/cosmos/types/mod.rs b/crates/relayer/src/chain/cosmos/types/mod.rs index 9951b58784..8877d47c36 100644 --- a/crates/relayer/src/chain/cosmos/types/mod.rs +++ b/crates/relayer/src/chain/cosmos/types/mod.rs @@ -1,5 +1,4 @@ pub mod account; -pub mod app_state; pub mod config; pub mod events; pub mod gas; diff --git a/crates/relayer/src/chain/cosmos/version.rs b/crates/relayer/src/chain/cosmos/version.rs index e6987eebb5..5db1b56961 100644 --- a/crates/relayer/src/chain/cosmos/version.rs +++ b/crates/relayer/src/chain/cosmos/version.rs @@ -7,7 +7,7 @@ use core::fmt::{Display, Error as FmtError, Formatter}; use flex_error::define_error; use tracing::trace; -use ibc_proto::cosmos::base::tendermint::v1beta1::VersionInfo; +use ibc_proto::cosmos::base::tendermint::v1beta1::{Module, VersionInfo}; /// Specifies the SDK, IBC-go, and Tendermint modules path, as expected /// to appear in the application version information of a @@ -22,69 +22,63 @@ use ibc_proto::cosmos::base::tendermint::v1beta1::VersionInfo; /// sum: "h1:yaD4PyOx0LnyfiWasC5egg1U76lT83GRxjJjupPo7Gk=", /// }, /// ``` -const SDK_MODULE_NAME: &str = "cosmos/cosmos-sdk"; -const IBC_GO_MODULE_NAME: &str = "cosmos/ibc-go"; -const TENDERMINT_MODULE_NAME: &str = "tendermint/tendermint"; -const COMET_MODULE_NAME: &str = "cometbft/cometbft"; +const SDK_MODULE_NAME: &str = "github.com/cosmos/cosmos-sdk"; +const IBC_GO_MODULE_PREFIX: &str = "github.com/cosmos/ibc-go/v"; +const TENDERMINT_MODULE_NAME: &str = "github.com/tendermint/tendermint"; +const COMET_MODULE_NAME: &str = "github.com/cometbft/cometbft"; -/// Captures the version(s) specification of different -/// modules of a network. -/// -/// Assumes that the network runs on Cosmos SDK. -/// Stores both the SDK version as well as -/// the IBC-go module version (if existing). -#[derive(Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum ConsensusVersion { + Tendermint(semver::Version), + Comet(semver::Version), +} + +/// Captures the version(s) specification of different modules of a network. +#[derive(Clone, Debug, PartialEq, Eq)] pub struct Specs { - pub cosmos_sdk: semver::Version, + pub cosmos_sdk: Option, pub ibc_go: Option, - pub tendermint: Option, - pub comet: Option, + pub consensus: Option, } impl Display for Specs { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - let ibc_go = self - .ibc_go + let cosmos_sdk = self + .cosmos_sdk .as_ref() .map(|v| v.to_string()) .unwrap_or_else(|| "UNKNOWN".to_string()); - let tendermint = self - .tendermint + let ibc_go = self + .ibc_go .as_ref() .map(|v| v.to_string()) .unwrap_or_else(|| "UNKNOWN".to_string()); - let comet = self - .comet - .as_ref() - .map(|v| v.to_string()) - .unwrap_or_else(|| "UNKNOWN".to_string()); + let consensus = match self.consensus { + Some(ConsensusVersion::Tendermint(ref v)) => format!("Tendermint {v}"), + Some(ConsensusVersion::Comet(ref v)) => format!("CometBFT {v}"), + None => "Tendermint: UNKNOWN, CometBFT: UNKNOWN".to_string(), + }; write!( f, - "Cosmos SDK {}, IBC-Go {}, Tendermint {}, CometBFT {}", - self.cosmos_sdk, ibc_go, tendermint, comet + "Cosmos SDK {}, IBC-Go {}, {}", + cosmos_sdk, ibc_go, consensus ) } } define_error! { Error { - SdkModuleNotFound - { - address: String, - app: AppInfo, - } - |e| { format!("failed to find the SDK module dependency ('{}') for application {}", e.address, e.app) }, - ConsensusModuleNotFound { tendermint: String, comet: String, app: AppInfo, } - |e| { format!("failed to find the Tendermint ('{}') or CometBFT ('{}') dependency for application {}", e.tendermint, e.comet, e.app) }, + |e| { format!("failed to find the Tendermint ('{}') or CometBFT ('{}') dependency for application {}", + e.tendermint, e.comet, e.app) }, VersionParsingFailed { @@ -108,8 +102,14 @@ impl TryFrom for Specs { let tendermint_version = parse_tendermint_version(&raw_version)?; let comet_version = parse_comet_version(&raw_version)?; + let consensus_version = match (tendermint_version, comet_version) { + (_, Some(comet)) => Some(ConsensusVersion::Comet(comet)), + (Some(tendermint), _) => Some(ConsensusVersion::Tendermint(tendermint)), + _ => None, + }; + // Ensure that either Tendermint or CometBFT are being used. - if tendermint_version.is_none() && comet_version.is_none() { + if consensus_version.is_none() { return Err(Error::consensus_module_not_found( TENDERMINT_MODULE_NAME.to_string(), COMET_MODULE_NAME.to_string(), @@ -121,77 +121,50 @@ impl TryFrom for Specs { application = %raw_version.app_name, version = %raw_version.version, git_commit = %raw_version.git_commit, - sdk_version = %sdk_version, + sdk_version = ?sdk_version, ibc_go_status = ?ibc_go_version, - tendermint_version = ?tendermint_version, - comet_version = ?comet_version, + consensus_version = ?consensus_version, "parsed version specification" ); Ok(Self { cosmos_sdk: sdk_version, ibc_go: ibc_go_version, - tendermint: tendermint_version, - comet: comet_version, + consensus: consensus_version, }) } } -fn parse_sdk_version(version_info: &VersionInfo) -> Result { - let module = version_info - .build_deps - .iter() - .find(|&m| m.path.contains(SDK_MODULE_NAME)) - .ok_or_else(|| { - Error::sdk_module_not_found(SDK_MODULE_NAME.to_string(), AppInfo::from(version_info)) - })?; - - // The raw version number has a leading 'v', trim it out; - let plain_version = module.version.trim_start_matches('v'); - - // Parse the module version - let mut version = semver::Version::parse(plain_version).map_err(|e| { - Error::version_parsing_failed( - module.path.clone(), - module.version.clone(), - e.to_string(), - AppInfo::from(version_info), - ) - })?; - - // Remove the pre-release version to ensure we treat pre-releases of the SDK - // as their normal version, eg. 0.42.0-rc2 should satisfy >=0.41.3, <= 0.42.6. - version.pre = semver::Prerelease::EMPTY; - - Ok(version) +fn parse_sdk_version(version_info: &VersionInfo) -> Result, Error> { + parse_optional_version(version_info, |m| m.path == SDK_MODULE_NAME) } fn parse_ibc_go_version(version_info: &VersionInfo) -> Result, Error> { - parse_optional_version(version_info, IBC_GO_MODULE_NAME) + parse_optional_version(version_info, |m| m.path.starts_with(IBC_GO_MODULE_PREFIX)) } fn parse_tendermint_version(version_info: &VersionInfo) -> Result, Error> { - parse_optional_version(version_info, TENDERMINT_MODULE_NAME) + parse_optional_version(version_info, |m| m.path == TENDERMINT_MODULE_NAME) } fn parse_comet_version(version_info: &VersionInfo) -> Result, Error> { - parse_optional_version(version_info, COMET_MODULE_NAME) + parse_optional_version(version_info, |m| m.path == COMET_MODULE_NAME) } fn parse_optional_version( version_info: &VersionInfo, - module_name: &str, + predicate: impl Fn(&Module) -> bool, ) -> Result, Error> { - match version_info - .build_deps - .iter() - .find(|&m| m.path.contains(module_name)) - { + let module = version_info.build_deps.iter().find(|&m| predicate(m)); + + match module { None => Ok(None), + Some(module) => { let plain_version = module.version.trim_start_matches('v'); semver::Version::parse(plain_version) + // Discard the pre-release version, if any .map(|mut version| { version.pre = semver::Prerelease::EMPTY; Some(version) @@ -210,7 +183,7 @@ fn parse_optional_version( /// Helper struct to capture all the reported information of an /// IBC application, e.g., `gaiad`. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct AppInfo { app_name: String, version: String, @@ -232,3 +205,171 @@ impl From<&VersionInfo> for AppInfo { } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn cosmoshub() { + let version_info = VersionInfo { + name: "gaia".to_string(), + app_name: "gaiad".to_string(), + version: "v14.2.0".to_string(), + git_commit: "3aa6e5058b4cbb4729300b239abfabd9a5b5691f".to_string(), + build_tags: "netgo,ledger".to_string(), + go_version: "go version go1.20.3 linux/amd64".to_string(), + cosmos_sdk_version: "v0.45.16".to_string(), + build_deps: vec![ + Module { + path: "github.com/cometbft/cometbft-db".to_string(), + version: "v0.7.0".to_string(), + sum: "h1:uBjbrBx4QzU0zOEnU8KxoDl18dMNgDh+zZRUE0ucsbo=".to_string(), + }, + Module { + path: "github.com/confio/ics23/go".to_string(), + version: "v0.9.0".to_string(), + sum: "h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4=".to_string(), + }, + Module { + path: "github.com/cosmos/cosmos-db".to_string(), + version: "v0.0.0-20221226095112-f3c38ecb5e32".to_string(), + sum: "h1:zlCp9n3uwQieELltZWHRmwPmPaZ8+XoL2Sj+A2YJlr8=".to_string(), + }, + Module { + path: "github.com/cosmos/cosmos-proto".to_string(), + version: "v1.0.0-beta.1".to_string(), + sum: "h1:iDL5qh++NoXxG8hSy93FdYJut4XfgbShIocllGaXx/0=".to_string(), + }, + Module { + path: "github.com/cosmos/cosmos-sdk".to_string(), + version: "v0.45.16".to_string(), + sum: "".to_string(), + }, + Module { + path: "github.com/cosmos/go-bip39".to_string(), + version: "v1.0.0".to_string(), + sum: "h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY=".to_string(), + }, + Module { + path: "github.com/cosmos/iavl".to_string(), + version: "v0.19.5".to_string(), + sum: "h1:rGA3hOrgNxgRM5wYcSCxgQBap7fW82WZgY78V9po/iY=".to_string(), + }, + Module { + path: "github.com/tendermint/tendermint".to_string(), + version: "v0.34.27".to_string(), + sum: "".to_string(), + }, + Module { + path: "github.com/cosmos/ibc-go/v4".to_string(), + version: "v4.4.2".to_string(), + sum: "h1:PG4Yy0/bw6Hvmha3RZbc53KYzaCwuB07Ot4GLyzcBvo=".to_string(), + }, + Module { + path: "github.com/cosmos/interchain-security/v2".to_string(), + version: "v2.0.0".to_string(), + sum: "".to_string(), + }, + ], + }; + + let app_info = AppInfo::from(&version_info); + + assert_eq!( + app_info, + AppInfo { + app_name: "gaiad".to_string(), + version: "v14.2.0".to_string(), + git_commit: "3aa6e5058b4cbb4729300b239abfabd9a5b5691f".to_string() + } + ); + + let specs = Specs::try_from(version_info).unwrap(); + + assert_eq!( + specs, + Specs { + cosmos_sdk: Some(semver::Version::parse("0.45.16").unwrap()), + ibc_go: Some(semver::Version::parse("4.4.2").unwrap()), + consensus: Some(ConsensusVersion::Tendermint( + semver::Version::parse("0.34.27").unwrap() + )) + } + ); + } + + #[test] + fn phoenix() { + let version_info = VersionInfo { + name: "terra".to_string(), + app_name: "terrad".to_string(), + version: "20210603".to_string(), + git_commit: "7cbb1f555b661a6ebec55231e563d2f94effc40e".to_string(), + build_tags: "netgo,ledger".to_string(), + go_version: "go version go1.20 linux/amd64".to_string(), + cosmos_sdk_version: "v0.47.5".to_string(), + build_deps: vec![ + Module { + path: "github.com/confio/ics23/go".to_string(), + version: "v0.9.0".to_string(), + sum: "h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4=".to_string(), + }, + Module { + path: "github.com/cometbft/cometbft-db".to_string(), + version: "v0.8.0".to_string(), + sum: "h1:vUMDaH3ApkX8m0KZvOFFy9b5DZHBAjsnEuo9AKVZpjo=".to_string(), + }, + Module { + path: "github.com/cosmos/cosmos-proto".to_string(), + version: "v1.0.0-beta.3".to_string(), + sum: "h1:VitvZ1lPORTVxkmF2fAp3IiA61xVwArQYKXTdEcpW6o=".to_string(), + }, + Module { + path: "github.com/cosmos/cosmos-sdk".to_string(), + version: "v0.47.5".to_string(), + sum: "".to_string(), + }, + Module { + path: "github.com/cosmos/ibc-go/v7".to_string(), + version: "v7.3.0".to_string(), + sum: "".to_string(), + }, + Module { + path: "github.com/cosmos/ics23/go".to_string(), + version: "v0.10.0".to_string(), + sum: "h1:iXqLLgp2Lp+EdpIuwXTYIQU+AiHj9mOC2X9ab++bZDM=".to_string(), + }, + Module { + path: "github.com/cometbft/cometbft".to_string(), + version: "v0.37.2".to_string(), + sum: "h1:XB0yyHGT0lwmJlFmM4+rsRnczPlHoAKFX6K8Zgc2/Jc=".to_string(), + }, + ], + }; + + let app_info = AppInfo::from(&version_info); + + assert_eq!( + app_info, + AppInfo { + app_name: "terrad".to_string(), + version: "20210603".to_string(), + git_commit: "7cbb1f555b661a6ebec55231e563d2f94effc40e".to_string() + } + ); + + let specs = Specs::try_from(version_info).unwrap(); + + assert_eq!( + specs, + Specs { + cosmos_sdk: Some(semver::Version::parse("0.47.5").unwrap()), + ibc_go: Some(semver::Version::parse("7.3.0").unwrap()), + consensus: Some(ConsensusVersion::Comet( + semver::Version::parse("0.37.2").unwrap() + )) + } + ); + } +} diff --git a/crates/relayer/src/chain/counterparty.rs b/crates/relayer/src/chain/counterparty.rs index b99699d3b0..118c118a62 100644 --- a/crates/relayer/src/chain/counterparty.rs +++ b/crates/relayer/src/chain/counterparty.rs @@ -19,7 +19,7 @@ use serde::{Deserialize, Serialize}; use tracing::{error, trace}; use super::requests::{ - IncludeProof, PageRequest, QueryChannelRequest, QueryClientConnectionsRequest, + IncludeProof, PageRequest, Paginate, QueryChannelRequest, QueryClientConnectionsRequest, QueryClientStateRequest, QueryConnectionRequest, QueryPacketAcknowledgementsRequest, QueryUnreceivedAcksRequest, QueryUnreceivedPacketsRequest, }; @@ -167,7 +167,7 @@ pub fn channel_connection_client_no_checks( channel_id: channel_id.clone(), height: QueryHeight::Latest, }, - IncludeProof::No, + IncludeProof::Yes, ) .map_err(Error::relayer)?; @@ -295,7 +295,11 @@ pub fn channel_on_destination( channel_id: remote_channel_id.clone(), height: QueryHeight::Latest, }, - IncludeProof::No, + // IncludeProof::Yes forces a new query when the CachingChainHandle + // is used. + // TODO: Pass the BaseChainHandle instead of the CachingChainHandle + // to the channel worker to avoid querying for a Proof . + IncludeProof::Yes, ) .map(|(c, _)| IdentifiedChannelEnd { port_id: channel.channel_end.counterparty().port_id().clone(), @@ -375,15 +379,18 @@ pub fn check_channel_counterparty( /// - received on counterparty chain but not yet acknowledged by this chain, pub fn commitments_on_chain( chain: &impl ChainHandle, + query_height: &QueryHeight, port_id: &PortId, channel_id: &ChannelId, + paginate: Paginate, ) -> Result<(Vec, Height), Error> { // get the packet commitments on the counterparty/ source chain let (mut commit_sequences, response_height) = chain .query_packet_commitments(QueryPacketCommitmentsRequest { + query_height: *query_height, port_id: port_id.clone(), channel_id: channel_id.clone(), - pagination: Some(PageRequest::all()), + pagination: paginate, }) .map_err(Error::relayer)?; @@ -420,6 +427,7 @@ pub fn packet_acknowledgements( port_id: &PortId, channel_id: &ChannelId, commit_sequences: Vec, + pagination: Paginate, ) -> Result, Height)>, Error> { // If there aren't any sequences to query for, return early. // Otherwise we end up with the full list of acknowledgements on chain, @@ -435,7 +443,7 @@ pub fn packet_acknowledgements( .query_packet_acknowledgements(QueryPacketAcknowledgementsRequest { port_id: port_id.clone(), channel_id: channel_id.clone(), - pagination: Some(PageRequest::all()), + pagination, packet_commitment_sequences: commit_sequences, }) .map_err(Error::relayer)?; @@ -496,11 +504,14 @@ pub fn unreceived_packets( chain: &impl ChainHandle, counterparty_chain: &impl ChainHandle, path: &PathIdentifiers, + paginate: Paginate, ) -> Result<(Vec, Height), Error> { let (commit_sequences, h) = commitments_on_chain( counterparty_chain, + &QueryHeight::Latest, &path.counterparty_port_id, &path.counterparty_channel_id, + paginate, )?; telemetry!( @@ -535,8 +546,10 @@ pub fn acknowledgements_on_chain( let (commitments_on_counterparty, _) = commitments_on_chain( counterparty_chain, + &QueryHeight::Latest, &counterparty.port_id, counterparty_channel_id, + Paginate::All, )?; let sequences_and_height = packet_acknowledgements( @@ -544,6 +557,7 @@ pub fn acknowledgements_on_chain( &channel.port_id, &channel.channel_id, commitments_on_counterparty, + Paginate::All, )?; Ok(sequences_and_height) @@ -582,14 +596,22 @@ pub fn unreceived_acknowledgements( chain: &impl ChainHandle, counterparty_chain: &impl ChainHandle, path: &PathIdentifiers, + pagination: Paginate, ) -> Result, Height)>, Error> { - let (commitments_on_src, _) = commitments_on_chain(chain, &path.port_id, &path.channel_id)?; + let (commitments_on_src, _) = commitments_on_chain( + chain, + &QueryHeight::Latest, + &path.port_id, + &path.channel_id, + pagination, + )?; let acks_and_height_on_counterparty = packet_acknowledgements( counterparty_chain, &path.counterparty_port_id, &path.counterparty_channel_id, commitments_on_src, + pagination, )?; if let Some((acks_on_counterparty, height)) = acks_and_height_on_counterparty { @@ -621,6 +643,7 @@ pub fn pending_packet_summary( chain: &impl ChainHandle, counterparty_chain: &impl ChainHandle, channel: &IdentifiedChannelEnd, + pagination: Paginate, ) -> Result { let counterparty = channel.channel_end.counterparty(); let counterparty_channel_id = counterparty @@ -628,8 +651,13 @@ pub fn pending_packet_summary( .as_ref() .ok_or_else(Error::missing_counterparty_channel_id)?; - let (commitments_on_src, _) = - commitments_on_chain(chain, &channel.port_id, &channel.channel_id)?; + let (commitments_on_src, _) = commitments_on_chain( + chain, + &QueryHeight::Latest, + &channel.port_id, + &channel.channel_id, + pagination, + )?; let unreceived = unreceived_packets_sequences( counterparty_chain, @@ -643,6 +671,7 @@ pub fn pending_packet_summary( &counterparty.port_id, counterparty_channel_id, commitments_on_src, + Paginate::All, )?; let pending_acks = if let Some((acks_on_counterparty, _)) = acks_on_counterparty { diff --git a/crates/relayer/src/chain/endpoint.rs b/crates/relayer/src/chain/endpoint.rs index 11f47a7486..387ff0b8d6 100644 --- a/crates/relayer/src/chain/endpoint.rs +++ b/crates/relayer/src/chain/endpoint.rs @@ -1,6 +1,8 @@ use alloc::sync::Arc; -use core::convert::TryFrom; +use ibc_proto::ibc::core::channel::v1::{QueryUpgradeErrorRequest, QueryUpgradeRequest}; +use ibc_relayer_types::applications::ics28_ccv::msgs::{ConsumerChain, ConsumerId}; +use ibc_relayer_types::core::ics02_client::height::Height; use tokio::runtime::Runtime as TokioRuntime; use ibc_proto::ibc::apps::fee::v1::{ @@ -17,6 +19,7 @@ use ibc_relayer_types::core::ics03_connection::connection::{ use ibc_relayer_types::core::ics03_connection::version::{get_compatible_versions, Version}; use ibc_relayer_types::core::ics04_channel::channel::{ChannelEnd, IdentifiedChannelEnd}; use ibc_relayer_types::core::ics04_channel::packet::{PacketMsgType, Sequence}; +use ibc_relayer_types::core::ics04_channel::upgrade::{ErrorReceipt, Upgrade}; use ibc_relayer_types::core::ics23_commitment::commitment::{ CommitmentPrefix, CommitmentProofBytes, }; @@ -686,5 +689,21 @@ pub trait ChainEndpoint: Sized { request: QueryIncentivizedPacketRequest, ) -> Result; - fn query_consumer_chains(&self) -> Result, Error>; + fn query_consumer_chains(&self) -> Result, Error>; + + fn query_upgrade( + &self, + request: QueryUpgradeRequest, + height: Height, + include_proof: IncludeProof, + ) -> Result<(Upgrade, Option), Error>; + + fn query_upgrade_error( + &self, + request: QueryUpgradeErrorRequest, + height: Height, + include_proof: IncludeProof, + ) -> Result<(ErrorReceipt, Option), Error>; + + fn query_ccv_consumer_id(&self, client_id: ClientId) -> Result; } diff --git a/crates/relayer/src/chain/handle.rs b/crates/relayer/src/chain/handle.rs index 1ff6aae63f..b4aae48916 100644 --- a/crates/relayer/src/chain/handle.rs +++ b/crates/relayer/src/chain/handle.rs @@ -7,6 +7,8 @@ use tracing::Span; use ibc_proto::ibc::apps::fee::v1::{ QueryIncentivizedPacketRequest, QueryIncentivizedPacketResponse, }; +use ibc_proto::ibc::core::channel::v1::{QueryUpgradeErrorRequest, QueryUpgradeRequest}; +use ibc_relayer_types::applications::ics28_ccv::msgs::{ConsumerChain, ConsumerId}; use ibc_relayer_types::{ applications::ics31_icq::response::CrossChainQueryResponse, core::{ @@ -18,6 +20,7 @@ use ibc_relayer_types::{ ics04_channel::{ channel::{ChannelEnd, IdentifiedChannelEnd}, packet::{PacketMsgType, Sequence}, + upgrade::{ErrorReceipt, Upgrade}, }, ics23_commitment::{commitment::CommitmentPrefix, merkle::MerkleProof}, ics24_host::identifier::{ChainId, ChannelId, ClientId, ConnectionId, PortId}, @@ -369,7 +372,26 @@ pub enum ChainRequest { }, QueryConsumerChains { - reply_to: ReplyTo>, + reply_to: ReplyTo>, + }, + + QueryUpgrade { + request: QueryUpgradeRequest, + height: Height, + include_proof: IncludeProof, + reply_to: ReplyTo<(Upgrade, Option)>, + }, + + QueryUpgradeError { + request: QueryUpgradeErrorRequest, + height: Height, + include_proof: IncludeProof, + reply_to: ReplyTo<(ErrorReceipt, Option)>, + }, + + QueryConsumerId { + client_id: ClientId, + reply_to: ReplyTo, }, } @@ -683,5 +705,21 @@ pub trait ChainHandle: Clone + Display + Send + Sync + Debug + 'static { request: QueryIncentivizedPacketRequest, ) -> Result; - fn query_consumer_chains(&self) -> Result, Error>; + fn query_consumer_chains(&self) -> Result, Error>; + + fn query_upgrade( + &self, + request: QueryUpgradeRequest, + height: Height, + include_proof: IncludeProof, + ) -> Result<(Upgrade, Option), Error>; + + fn query_upgrade_error( + &self, + request: QueryUpgradeErrorRequest, + height: Height, + include_proof: IncludeProof, + ) -> Result<(ErrorReceipt, Option), Error>; + + fn query_ccv_consumer_id(&self, client_id: &ClientId) -> Result; } diff --git a/crates/relayer/src/chain/handle/base.rs b/crates/relayer/src/chain/handle/base.rs index 220c9ce7a3..64d7d7d30e 100644 --- a/crates/relayer/src/chain/handle/base.rs +++ b/crates/relayer/src/chain/handle/base.rs @@ -3,21 +3,28 @@ use core::fmt::{Debug, Display, Error as FmtError, Formatter}; use crossbeam_channel as channel; use tracing::Span; -use ibc_proto::ibc::apps::fee::v1::{ - QueryIncentivizedPacketRequest, QueryIncentivizedPacketResponse, +use ibc_proto::ibc::{ + apps::fee::v1::{QueryIncentivizedPacketRequest, QueryIncentivizedPacketResponse}, + core::channel::v1::{QueryUpgradeErrorRequest, QueryUpgradeRequest}, }; use ibc_relayer_types::{ - applications::ics31_icq::response::CrossChainQueryResponse, + applications::{ + ics28_ccv::msgs::{ConsumerChain, ConsumerId}, + ics31_icq::response::CrossChainQueryResponse, + }, core::{ ics02_client::{events::UpdateClient, header::AnyHeader}, - ics03_connection::connection::{ConnectionEnd, IdentifiedConnectionEnd}, - ics03_connection::version::Version, - ics04_channel::channel::{ChannelEnd, IdentifiedChannelEnd}, - ics04_channel::packet::{PacketMsgType, Sequence}, + ics03_connection::{ + connection::{ConnectionEnd, IdentifiedConnectionEnd}, + version::Version, + }, + ics04_channel::{ + channel::{ChannelEnd, IdentifiedChannelEnd}, + packet::{PacketMsgType, Sequence}, + upgrade::{ErrorReceipt, Upgrade}, + }, ics23_commitment::{commitment::CommitmentPrefix, merkle::MerkleProof}, - ics24_host::identifier::ChainId, - ics24_host::identifier::ChannelId, - ics24_host::identifier::{ClientId, ConnectionId, PortId}, + ics24_host::identifier::{ChainId, ChannelId, ClientId, ConnectionId, PortId}, }, proofs::Proofs, signer::Signer, @@ -518,7 +525,42 @@ impl ChainHandle for BaseChainHandle { self.send(|reply_to| ChainRequest::QueryIncentivizedPacket { request, reply_to }) } - fn query_consumer_chains(&self) -> Result, Error> { + fn query_consumer_chains(&self) -> Result, Error> { self.send(|reply_to| ChainRequest::QueryConsumerChains { reply_to }) } + + fn query_upgrade( + &self, + request: QueryUpgradeRequest, + height: Height, + include_proof: IncludeProof, + ) -> Result<(Upgrade, Option), Error> { + self.send(|reply_to| ChainRequest::QueryUpgrade { + request, + height, + include_proof, + reply_to, + }) + } + + fn query_upgrade_error( + &self, + request: QueryUpgradeErrorRequest, + height: Height, + include_proof: IncludeProof, + ) -> Result<(ErrorReceipt, Option), Error> { + self.send(|reply_to| ChainRequest::QueryUpgradeError { + request, + height, + include_proof, + reply_to, + }) + } + + fn query_ccv_consumer_id(&self, client_id: &ClientId) -> Result { + self.send(|reply_to| ChainRequest::QueryConsumerId { + client_id: client_id.clone(), + reply_to, + }) + } } diff --git a/crates/relayer/src/chain/handle/cache.rs b/crates/relayer/src/chain/handle/cache.rs index 3c4762b3ae..403fee0bb2 100644 --- a/crates/relayer/src/chain/handle/cache.rs +++ b/crates/relayer/src/chain/handle/cache.rs @@ -1,18 +1,23 @@ use core::fmt::{Display, Error as FmtError, Formatter}; use crossbeam_channel as channel; -use ibc_relayer_types::core::ics02_client::header::AnyHeader; +use ibc_relayer_types::applications::ics28_ccv::msgs::ConsumerId; use tracing::Span; use ibc_proto::ibc::apps::fee::v1::QueryIncentivizedPacketRequest; use ibc_proto::ibc::apps::fee::v1::QueryIncentivizedPacketResponse; +use ibc_proto::ibc::core::channel::v1::{QueryUpgradeErrorRequest, QueryUpgradeRequest}; +use ibc_relayer_types::applications::ics28_ccv::msgs::ConsumerChain; use ibc_relayer_types::applications::ics31_icq::response::CrossChainQueryResponse; use ibc_relayer_types::core::ics02_client::events::UpdateClient; +use ibc_relayer_types::core::ics02_client::header::AnyHeader; use ibc_relayer_types::core::ics03_connection::connection::ConnectionEnd; use ibc_relayer_types::core::ics03_connection::connection::IdentifiedConnectionEnd; use ibc_relayer_types::core::ics03_connection::version::Version; use ibc_relayer_types::core::ics04_channel::channel::ChannelEnd; use ibc_relayer_types::core::ics04_channel::channel::IdentifiedChannelEnd; use ibc_relayer_types::core::ics04_channel::packet::{PacketMsgType, Sequence}; +use ibc_relayer_types::core::ics04_channel::upgrade::ErrorReceipt; +use ibc_relayer_types::core::ics04_channel::upgrade::Upgrade; use ibc_relayer_types::core::ics23_commitment::commitment::CommitmentPrefix; use ibc_relayer_types::core::ics23_commitment::merkle::MerkleProof; use ibc_relayer_types::core::ics24_host::identifier::{ @@ -512,7 +517,30 @@ impl ChainHandle for CachingChainHandle { self.inner.query_incentivized_packet(request) } - fn query_consumer_chains(&self) -> Result, Error> { + fn query_consumer_chains(&self) -> Result, Error> { self.inner.query_consumer_chains() } + + fn query_upgrade( + &self, + request: QueryUpgradeRequest, + height: Height, + include_proof: IncludeProof, + ) -> Result<(Upgrade, Option), Error> { + self.inner.query_upgrade(request, height, include_proof) + } + + fn query_upgrade_error( + &self, + request: QueryUpgradeErrorRequest, + height: Height, + include_proof: IncludeProof, + ) -> Result<(ErrorReceipt, Option), Error> { + self.inner + .query_upgrade_error(request, height, include_proof) + } + + fn query_ccv_consumer_id(&self, client_id: &ClientId) -> Result { + self.inner.query_ccv_consumer_id(client_id) + } } diff --git a/crates/relayer/src/chain/handle/counting.rs b/crates/relayer/src/chain/handle/counting.rs index 2211cc3551..4fe7685a9e 100644 --- a/crates/relayer/src/chain/handle/counting.rs +++ b/crates/relayer/src/chain/handle/counting.rs @@ -8,6 +8,8 @@ use tracing::{debug, Span}; use ibc_proto::ibc::apps::fee::v1::{ QueryIncentivizedPacketRequest, QueryIncentivizedPacketResponse, }; +use ibc_proto::ibc::core::channel::v1::{QueryUpgradeErrorRequest, QueryUpgradeRequest}; +use ibc_relayer_types::applications::ics28_ccv::msgs::{ConsumerChain, ConsumerId}; use ibc_relayer_types::applications::ics31_icq::response::CrossChainQueryResponse; use ibc_relayer_types::core::ics02_client::events::UpdateClient; use ibc_relayer_types::core::ics02_client::header::AnyHeader; @@ -17,6 +19,7 @@ use ibc_relayer_types::core::ics03_connection::version::Version; use ibc_relayer_types::core::ics04_channel::channel::ChannelEnd; use ibc_relayer_types::core::ics04_channel::channel::IdentifiedChannelEnd; use ibc_relayer_types::core::ics04_channel::packet::{PacketMsgType, Sequence}; +use ibc_relayer_types::core::ics04_channel::upgrade::{ErrorReceipt, Upgrade}; use ibc_relayer_types::core::ics23_commitment::commitment::CommitmentPrefix; use ibc_relayer_types::core::ics23_commitment::merkle::MerkleProof; use ibc_relayer_types::core::ics24_host::identifier::{ @@ -505,8 +508,34 @@ impl ChainHandle for CountingChainHandle { self.inner.query_incentivized_packet(request) } - fn query_consumer_chains(&self) -> Result, Error> { + fn query_consumer_chains(&self) -> Result, Error> { self.inc_metric("query_consumer_chains"); self.inner.query_consumer_chains() } + + fn query_upgrade( + &self, + request: QueryUpgradeRequest, + height: Height, + include_proof: IncludeProof, + ) -> Result<(Upgrade, Option), Error> { + self.inc_metric("query_upgrade"); + self.inner.query_upgrade(request, height, include_proof) + } + + fn query_upgrade_error( + &self, + request: QueryUpgradeErrorRequest, + height: Height, + include_proof: IncludeProof, + ) -> Result<(ErrorReceipt, Option), Error> { + self.inc_metric("query_upgrade_error"); + self.inner + .query_upgrade_error(request, height, include_proof) + } + + fn query_ccv_consumer_id(&self, client_id: &ClientId) -> Result { + self.inc_metric("query_ccv_consumer_id"); + self.inner.query_ccv_consumer_id(client_id) + } } diff --git a/crates/relayer/src/chain/requests.rs b/crates/relayer/src/chain/requests.rs index cc45908172..80162ee6e8 100644 --- a/crates/relayer/src/chain/requests.rs +++ b/crates/relayer/src/chain/requests.rs @@ -66,7 +66,7 @@ impl TryFrom for AsciiMetadataValue { } impl Display for QueryHeight { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { QueryHeight::Latest => write!(f, "latest height"), QueryHeight::Specific(height) => write!(f, "{height}"), @@ -93,7 +93,7 @@ pub struct PageRequest { /// key is a value returned in PageResponse.next_key to begin /// querying the next page most efficiently. Only one of offset or key /// should be set. - pub key: ::prost::alloc::vec::Vec, + pub key: Vec, /// offset is a numeric offset that can be used when key is unavailable. /// It is less efficient than using key. Only one of offset or key should /// be set. @@ -115,8 +115,12 @@ impl PageRequest { // Note: do not use u64::MAX as the limit, as it may have unintended consequences // See https://github.com/informalsystems/hermes/pull/2950#issuecomment-1373733744 + Self::per_page(u32::MAX as u64) + } + + pub fn per_page(limit: u64) -> Self { PageRequest { - limit: u32::MAX as u64, + limit, ..Default::default() } } @@ -134,6 +138,39 @@ impl From for RawPageRequest { } } +#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] +pub enum Paginate { + #[default] + All, + + PerPage { + per_page: u64, + total: u64, + }, +} + +impl Paginate { + pub fn is_enabled(&self) -> bool { + !matches!(self, Self::All) + } + + pub fn get_values(&self) -> (u64, u64) { + match self { + Paginate::PerPage { total, per_page } => (*per_page, *total), + _ => (0, 0), + } + } +} + +impl From for PageRequest { + fn from(value: Paginate) -> Self { + match value { + Paginate::All => PageRequest::all(), + Paginate::PerPage { per_page, .. } => PageRequest::per_page(per_page), + } + } +} + #[derive(Clone, Debug, Serialize, Deserialize)] pub struct QueryClientStateRequest { pub client_id: ClientId, @@ -301,9 +338,10 @@ pub struct QueryPacketCommitmentRequest { /// gRPC query to fetch the packet commitment hashes associated with the specified channel. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct QueryPacketCommitmentsRequest { + pub query_height: QueryHeight, pub port_id: PortId, pub channel_id: ChannelId, - pub pagination: Option, + pub pagination: Paginate, } impl From for RawQueryPacketCommitmentsRequest { @@ -311,7 +349,7 @@ impl From for RawQueryPacketCommitmentsRequest { RawQueryPacketCommitmentsRequest { port_id: request.port_id.to_string(), channel_id: request.channel_id.to_string(), - pagination: request.pagination.map(|pagination| pagination.into()), + pagination: Some(PageRequest::from(request.pagination).into()), } } } @@ -359,7 +397,7 @@ pub struct QueryPacketAcknowledgementRequest { pub struct QueryPacketAcknowledgementsRequest { pub port_id: PortId, pub channel_id: ChannelId, - pub pagination: Option, + pub pagination: Paginate, pub packet_commitment_sequences: Vec, } @@ -368,7 +406,7 @@ impl From for RawQueryPacketAcknowledgements RawQueryPacketAcknowledgementsRequest { port_id: request.port_id.to_string(), channel_id: request.channel_id.to_string(), - pagination: request.pagination.map(|pagination| pagination.into()), + pagination: Some(PageRequest::from(request.pagination).into()), packet_commitment_sequences: request .packet_commitment_sequences .into_iter() diff --git a/crates/relayer/src/chain/runtime.rs b/crates/relayer/src/chain/runtime.rs index d19fbd9cfe..0aff1cb248 100644 --- a/crates/relayer/src/chain/runtime.rs +++ b/crates/relayer/src/chain/runtime.rs @@ -5,14 +5,17 @@ use crossbeam_channel as channel; use tokio::runtime::Runtime as TokioRuntime; use tracing::{error, Span}; -use ibc_proto::ibc::apps::fee::v1::{ - QueryIncentivizedPacketRequest, QueryIncentivizedPacketResponse, +use ibc_proto::ibc::{ + apps::fee::v1::{QueryIncentivizedPacketRequest, QueryIncentivizedPacketResponse}, + core::channel::v1::{QueryUpgradeErrorRequest, QueryUpgradeRequest}, }; use ibc_relayer_types::{ - applications::ics31_icq::response::CrossChainQueryResponse, + applications::{ + ics28_ccv::msgs::{ConsumerChain, ConsumerId}, + ics31_icq::response::CrossChainQueryResponse, + }, core::{ - ics02_client::events::UpdateClient, - ics02_client::header::AnyHeader, + ics02_client::{events::UpdateClient, header::AnyHeader}, ics03_connection::{ connection::{ConnectionEnd, IdentifiedConnectionEnd}, version::Version, @@ -20,9 +23,10 @@ use ibc_relayer_types::{ ics04_channel::{ channel::{ChannelEnd, IdentifiedChannelEnd}, packet::{PacketMsgType, Sequence}, + upgrade::{ErrorReceipt, Upgrade}, }, ics23_commitment::{commitment::CommitmentPrefix, merkle::MerkleProof}, - ics24_host::identifier::{ChainId, ChannelId, ClientId, ConnectionId, PortId}, + ics24_host::identifier::{ChannelId, ClientId, ConnectionId, PortId}, }, proofs::Proofs, signer::Signer, @@ -31,7 +35,6 @@ use ibc_relayer_types::{ use crate::{ account::Balance, - chain::requests::QueryPacketEventDataRequest, client_state::{AnyClientState, IdentifiedAnyClientState}, config::ChainConfig, connection::ConnectionMsgType, @@ -354,6 +357,18 @@ where ChainRequest::QueryConsumerChains { reply_to } => { self.query_consumer_chains(reply_to)? }, + + ChainRequest::QueryUpgrade { request, height, include_proof, reply_to } => { + self.query_upgrade(request, height, include_proof, reply_to)? + }, + + ChainRequest::QueryUpgradeError { request, height, include_proof, reply_to } => { + self.query_upgrade_error(request, height, include_proof, reply_to)? + }, + + ChainRequest::QueryConsumerId { client_id, reply_to } => { + self.query_ccv_consumer_id(client_id, reply_to)? + }, } }, } @@ -856,11 +871,47 @@ where Ok(()) } - fn query_consumer_chains( + fn query_consumer_chains(&self, reply_to: ReplyTo>) -> Result<(), Error> { + let result = self.chain.query_consumer_chains(); + reply_to.send(result).map_err(Error::send)?; + + Ok(()) + } + + fn query_upgrade( &self, - reply_to: ReplyTo>, + request: QueryUpgradeRequest, + height: Height, + include_proof: IncludeProof, + reply_to: ReplyTo<(Upgrade, Option)>, ) -> Result<(), Error> { - let result = self.chain.query_consumer_chains(); + let result = self.chain.query_upgrade(request, height, include_proof); + reply_to.send(result).map_err(Error::send)?; + + Ok(()) + } + + fn query_upgrade_error( + &self, + request: QueryUpgradeErrorRequest, + height: Height, + include_proof: IncludeProof, + reply_to: ReplyTo<(ErrorReceipt, Option)>, + ) -> Result<(), Error> { + let result = self + .chain + .query_upgrade_error(request, height, include_proof); + reply_to.send(result).map_err(Error::send)?; + + Ok(()) + } + + fn query_ccv_consumer_id( + &self, + client_id: ClientId, + reply_to: ReplyTo, + ) -> Result<(), Error> { + let result = self.chain.query_ccv_consumer_id(client_id); reply_to.send(result).map_err(Error::send)?; Ok(()) diff --git a/crates/relayer/src/chain/tracking.rs b/crates/relayer/src/chain/tracking.rs index 62f89ca096..589ad305f2 100644 --- a/crates/relayer/src/chain/tracking.rs +++ b/crates/relayer/src/chain/tracking.rs @@ -15,7 +15,7 @@ pub enum TrackingId { /// the CLI or during packet clearing. Static(&'static str), /// Random identifier used to track latency of packet clearing. - ClearedUuid(Uuid), + PacketClearing(Uuid), } impl TrackingId { @@ -29,8 +29,13 @@ impl TrackingId { Self::Static(s) } - pub fn new_cleared_uuid() -> Self { - Self::ClearedUuid(Uuid::new_v4()) + pub fn new_packet_clearing() -> Self { + Self::PacketClearing(Uuid::new_v4()) + } + + /// Indicates whether a packet clearing process is currently in-progress. + pub fn is_clearing(&self) -> bool { + matches!(self, Self::PacketClearing(_)) } } @@ -43,7 +48,7 @@ impl Display for TrackingId { s.fmt(f) } TrackingId::Static(s) => s.fmt(f), - TrackingId::ClearedUuid(u) => { + TrackingId::PacketClearing(u) => { let mut uuid = "cleared/".to_owned(); let mut s = u.to_string(); s.truncate(8); diff --git a/crates/relayer/src/channel.rs b/crates/relayer/src/channel.rs index c2a9880262..eb9a5a70a6 100644 --- a/crates/relayer/src/channel.rs +++ b/crates/relayer/src/channel.rs @@ -5,9 +5,16 @@ use ibc_proto::google::protobuf::Any; use serde::Serialize; use tracing::{debug, error, info, warn}; -pub use error::ChannelError; +use ibc_proto::ibc::core::channel::v1::{QueryUpgradeErrorRequest, QueryUpgradeRequest}; +use ibc_relayer_types::core::ics04_channel::msgs::chan_upgrade_ack::MsgChannelUpgradeAck; +use ibc_relayer_types::core::ics04_channel::msgs::chan_upgrade_cancel::MsgChannelUpgradeCancel; +use ibc_relayer_types::core::ics04_channel::msgs::chan_upgrade_confirm::MsgChannelUpgradeConfirm; +use ibc_relayer_types::core::ics04_channel::msgs::chan_upgrade_open::MsgChannelUpgradeOpen; +use ibc_relayer_types::core::ics04_channel::msgs::chan_upgrade_timeout::MsgChannelUpgradeTimeout; +use ibc_relayer_types::core::ics04_channel::packet::Sequence; + use ibc_relayer_types::core::ics04_channel::channel::{ - ChannelEnd, Counterparty, IdentifiedChannelEnd, Ordering, State, + ChannelEnd, Counterparty, IdentifiedChannelEnd, Ordering, State, UpgradeState, }; use ibc_relayer_types::core::ics04_channel::msgs::chan_close_confirm::MsgChannelCloseConfirm; use ibc_relayer_types::core::ics04_channel::msgs::chan_close_init::MsgChannelCloseInit; @@ -15,6 +22,8 @@ use ibc_relayer_types::core::ics04_channel::msgs::chan_open_ack::MsgChannelOpenA use ibc_relayer_types::core::ics04_channel::msgs::chan_open_confirm::MsgChannelOpenConfirm; use ibc_relayer_types::core::ics04_channel::msgs::chan_open_init::MsgChannelOpenInit; use ibc_relayer_types::core::ics04_channel::msgs::chan_open_try::MsgChannelOpenTry; +use ibc_relayer_types::core::ics04_channel::msgs::chan_upgrade_try::MsgChannelUpgradeTry; +use ibc_relayer_types::core::ics23_commitment::commitment::CommitmentProofBytes; use ibc_relayer_types::core::ics24_host::identifier::{ ChainId, ChannelId, ClientId, ConnectionId, PortId, }; @@ -38,38 +47,40 @@ use crate::util::retry::retry_with_index; use crate::util::retry::RetryResult; use crate::util::task::Next; -pub mod error; pub mod version; use version::Version; +pub mod error; +pub use error::ChannelError; + pub mod channel_handshake_retry { //! Provides utility methods and constants to configure the retry behavior //! for the channel handshake algorithm. use crate::channel::ChannelError; - use crate::util::retry::{clamp_total, ConstantGrowth}; + use crate::util::retry::{clamp, ConstantGrowth}; use core::time::Duration; /// Approximate number of retries per block. - const PER_BLOCK_RETRIES: u32 = 10; + const PER_BLOCK_RETRIES: u32 = 5; /// Defines the increment in delay between subsequent retries. /// A value of `0` will make the retry delay constant. - const DELAY_INCREMENT: u64 = 0; + const DELAY_INCREMENT: Duration = Duration::from_secs(0); - /// Maximum retry delay expressed in number of blocks - const BLOCK_NUMBER_DELAY: u32 = 10; + /// Maximum number of retries + const MAX_RETRIES: u32 = 10; /// The default retry strategy. /// We retry with a constant backoff strategy. The strategy is parametrized by the /// maximum block time expressed as a `Duration`. - pub fn default_strategy(max_block_times: Duration) -> impl Iterator { - let retry_delay = max_block_times / PER_BLOCK_RETRIES; + pub fn default_strategy(max_block_time: Duration) -> impl Iterator { + let retry_delay = max_block_time / PER_BLOCK_RETRIES; - clamp_total( - ConstantGrowth::new(retry_delay, Duration::from_secs(DELAY_INCREMENT)), - retry_delay, - max_block_times * BLOCK_NUMBER_DELAY, + clamp( + ConstantGrowth::new(retry_delay, DELAY_INCREMENT), + retry_delay + DELAY_INCREMENT * MAX_RETRIES, + MAX_RETRIES as usize, ) } @@ -289,16 +300,20 @@ impl Channel { chain: ChainA, counterparty_chain: ChainB, channel: WorkerChannelObject, - height: Height, + height: QueryHeight, ) -> Result<(Channel, State), ChannelError> { let (a_channel, _) = chain .query_channel( QueryChannelRequest { port_id: channel.src_port_id.clone(), channel_id: channel.src_channel_id.clone(), - height: QueryHeight::Specific(height), + height, }, - IncludeProof::No, + // IncludeProof::Yes forces a new query when the CachingChainHandle + // is used. + // TODO: Pass the BaseChainHandle instead of the CachingChainHandle + // to the channel worker to avoid querying for a Proof . + IncludeProof::Yes, ) .map_err(ChannelError::relayer)?; @@ -446,7 +461,7 @@ impl Channel { channel_id: id.clone(), height: QueryHeight::Latest, }, - IncludeProof::No, + IncludeProof::Yes, ) .map(|(channel_end, _)| channel_end) .map_err(|e| ChannelError::chain_query(self.a_chain().id(), e)) @@ -610,7 +625,7 @@ impl Channel { ); match (a_state, b_state) { - // send the Init message to chain a (source) + // send the Init message to chain A (source) (State::Uninitialized, State::Uninitialized) => { let event = self .flipped() @@ -623,7 +638,7 @@ impl Channel { self.a_side.channel_id = Some(channel_id.clone()); } - // send the Try message to chain a (source) + // send the Try message to chain A (source) (State::Uninitialized, State::Init) | (State::Init, State::Init) => { let event = self.flipped().build_chan_open_try_and_send().map_err(|e| { error!("failed ChanOpenTry {}: {}", self.a_side, e); @@ -634,7 +649,7 @@ impl Channel { self.a_side.channel_id = Some(channel_id.clone()); } - // send the Try message to chain b (destination) + // send the Try message to chain B (destination) (State::Init, State::Uninitialized) => { let event = self.build_chan_open_try_and_send().map_err(|e| { error!("failed ChanOpenTry {}: {}", self.b_side, e); @@ -645,7 +660,7 @@ impl Channel { self.b_side.channel_id = Some(channel_id.clone()); } - // send the Ack message to chain a (source) + // send the Ack message to chain A (source) (State::Init, State::TryOpen) | (State::TryOpen, State::TryOpen) => { self.flipped().build_chan_open_ack_and_send().map_err(|e| { error!("failed ChanOpenAck {}: {}", self.a_side, e); @@ -653,7 +668,7 @@ impl Channel { })?; } - // send the Ack message to chain b (destination) + // send the Ack message to chain B (destination) (State::TryOpen, State::Init) => { self.build_chan_open_ack_and_send().map_err(|e| { error!("failed ChanOpenAck {}: {}", self.b_side, e); @@ -661,16 +676,16 @@ impl Channel { })?; } - // send the Confirm message to chain b (destination) - (State::Open, State::TryOpen) => { + // send the Confirm message to chain B (destination) + (State::Open(UpgradeState::NotUpgrading), State::TryOpen) => { self.build_chan_open_confirm_and_send().map_err(|e| { error!("failed ChanOpenConfirm {}: {}", self.b_side, e); e })?; } - // send the Confirm message to chain a (source) - (State::TryOpen, State::Open) => { + // send the Confirm message to chain A (source) + (State::TryOpen, State::Open(UpgradeState::NotUpgrading)) => { self.flipped() .build_chan_open_confirm_and_send() .map_err(|e| { @@ -679,7 +694,7 @@ impl Channel { })?; } - (State::Open, State::Open) => { + (State::Open(UpgradeState::NotUpgrading), State::Open(UpgradeState::NotUpgrading)) => { info!("channel handshake already finished for {}", self); return Ok(()); } @@ -756,17 +771,58 @@ impl Channel { (State::Init, State::Init) => Some(self.build_chan_open_try_and_send()?), (State::TryOpen, State::Init) => Some(self.build_chan_open_ack_and_send()?), (State::TryOpen, State::TryOpen) => Some(self.build_chan_open_ack_and_send()?), - (State::Open, State::TryOpen) => Some(self.build_chan_open_confirm_and_send()?), - (State::Open, State::Open) => return Ok((None, Next::Abort)), + (State::Open(UpgradeState::NotUpgrading), State::TryOpen) => { + Some(self.build_chan_open_confirm_and_send()?) + } + (State::Open(UpgradeState::NotUpgrading), State::Open(UpgradeState::NotUpgrading)) => { + return Ok((None, Next::Abort)) + } // If the counterparty state is already Open but current state is TryOpen, // return anyway as the final step is to be done by the counterparty worker. - (State::TryOpen, State::Open) => return Ok((None, Next::Abort)), + (State::TryOpen, State::Open(UpgradeState::NotUpgrading)) => { + return Ok((None, Next::Abort)) + } // Close handshake steps (State::Closed, State::Closed) => return Ok((None, Next::Abort)), (State::Closed, _) => Some(self.build_chan_close_confirm_and_send()?), + // Channel Upgrade handshake steps + (State::Open(UpgradeState::Upgrading), State::Open(UpgradeState::NotUpgrading)) => { + Some(self.build_chan_upgrade_try_and_send()?) + } + (State::Open(UpgradeState::Upgrading), State::Open(UpgradeState::Upgrading)) => { + Some(self.build_chan_upgrade_try_and_send()?) + } + (State::Open(UpgradeState::NotUpgrading), State::Open(UpgradeState::Upgrading)) => { + Some(self.build_chan_upgrade_try_and_send()?) + } + (State::Flushing, State::Open(UpgradeState::Upgrading)) => { + Some(self.build_chan_upgrade_ack_and_send()?) + } + (State::Flushing, State::Flushing) => Some(self.build_chan_upgrade_ack_and_send()?), + (State::FlushComplete, State::Flushing) => { + Some(self.build_chan_upgrade_confirm_and_send()?) + } + + (State::Flushing, State::Open(UpgradeState::NotUpgrading)) => { + Some(self.flipped().build_chan_upgrade_cancel_and_send()?) + } + (State::Open(UpgradeState::NotUpgrading), State::Flushing) => { + Some(self.build_chan_upgrade_cancel_and_send()?) + } + + (State::FlushComplete, State::FlushComplete) => { + Some(self.build_chan_upgrade_open_and_send()?) + } + (State::FlushComplete, State::Open(UpgradeState::NotUpgrading)) => self + .flipped() + .build_chan_upgrade_open_or_cancel_and_send()?, + (State::Open(UpgradeState::NotUpgrading), State::FlushComplete) => { + self.build_chan_upgrade_open_or_cancel_and_send()? + } + _ => None, }; @@ -775,7 +831,10 @@ impl Channel { match event { Some(IbcEvent::OpenConfirmChannel(_)) | Some(IbcEvent::OpenAckChannel(_)) - | Some(IbcEvent::CloseConfirmChannel(_)) => Ok((event, Next::Abort)), + | Some(IbcEvent::CloseConfirmChannel(_)) + | Some(IbcEvent::UpgradeConfirmChannel(_)) + | Some(IbcEvent::UpgradeOpenChannel(_)) + | Some(IbcEvent::UpgradeCancelChannel(_)) => Ok((event, Next::Abort)), _ => Ok((event, Next::Continue)), } } @@ -806,9 +865,14 @@ impl Channel { let state = match event { IbcEvent::OpenInitChannel(_) => State::Init, IbcEvent::OpenTryChannel(_) => State::TryOpen, - IbcEvent::OpenAckChannel(_) => State::Open, - IbcEvent::OpenConfirmChannel(_) => State::Open, + IbcEvent::OpenAckChannel(_) => State::Open(UpgradeState::NotUpgrading), + IbcEvent::OpenConfirmChannel(_) => State::Open(UpgradeState::NotUpgrading), IbcEvent::CloseInitChannel(_) => State::Closed, + IbcEvent::UpgradeInitChannel(_) => State::Open(UpgradeState::Upgrading), + IbcEvent::UpgradeTryChannel(_) => State::Flushing, + IbcEvent::UpgradeAckChannel(_) => State::FlushComplete, + IbcEvent::UpgradeConfirmChannel(_) => State::FlushComplete, + IbcEvent::UpgradeOpenChannel(_) => State::Open(UpgradeState::NotUpgrading), _ => State::Uninitialized, }; @@ -859,6 +923,7 @@ impl Channel { counterparty, vec![self.dst_connection_id().clone()], version, + Sequence::from(0), ); // Build the domain type message @@ -903,7 +968,7 @@ impl Channel { } /// Retrieves the channel from destination and compares it - /// against the expected channel. built from the message type [`ChannelMsgType`]. + /// against the expected channel. Built from the message type [`ChannelMsgType`]. /// /// If the expected and the destination channels are compatible, /// returns the expected channel @@ -928,7 +993,7 @@ impl Channel { let highest_state = match msg_type { ChannelMsgType::OpenAck => State::TryOpen, ChannelMsgType::OpenConfirm => State::TryOpen, - ChannelMsgType::CloseConfirm => State::Open, + ChannelMsgType::CloseConfirm => State::Open(UpgradeState::NotUpgrading), _ => State::Uninitialized, }; @@ -938,6 +1003,7 @@ impl Channel { counterparty, vec![self.dst_connection_id().clone()], Version::empty(), + Sequence::from(0), ); // Retrieve existing channel @@ -1029,6 +1095,7 @@ impl Channel { counterparty, vec![self.dst_connection_id().clone()], version, + Sequence::from(0), ); // Get signer @@ -1381,7 +1448,8 @@ impl Channel { self.validated_expected_channel(ChannelMsgType::CloseConfirm)?; // Channel must exist on source - self.src_chain() + let (src_channel_end, _) = self + .src_chain() .query_channel( QueryChannelRequest { port_id: self.src_port_id().clone(), @@ -1413,6 +1481,8 @@ impl Channel { .build_channel_proofs(self.src_port_id(), src_channel_id, query_height) .map_err(ChannelError::channel_proof)?; + let counterparty_upgrade_sequence = src_channel_end.upgrade_sequence; + // Build message(s) to update client on destination let mut msgs = self.build_update_client_on_dst(proofs.height())?; @@ -1428,6 +1498,7 @@ impl Channel { channel_id: dst_channel_id.clone(), proofs, signer, + counterparty_upgrade_sequence, }; msgs.push(new_msg.to_any()); @@ -1465,6 +1536,679 @@ impl Channel { } } + pub fn build_chan_upgrade_try(&self) -> Result, ChannelError> { + let src_channel_id = self + .src_channel_id() + .ok_or_else(ChannelError::missing_local_channel_id)?; + let src_port_id = self.src_port_id(); + let src_latest_height = self + .src_chain() + .query_latest_height() + .map_err(|e| ChannelError::chain_query(self.src_chain().id(), e))?; + + let dst_channel_id = self + .dst_channel_id() + .ok_or_else(ChannelError::missing_local_channel_id)?; + let dst_port_id = self.dst_port_id(); + + // Fetch the src channel end that will be upgraded by the upgrade handshake + // Querying for the Channel End now includes the upgrade sequence number + let (channel_end, _) = self + .src_chain() + .query_channel( + QueryChannelRequest { + port_id: src_port_id.clone(), + channel_id: src_channel_id.clone(), + height: QueryHeight::Specific(src_latest_height), + }, + IncludeProof::Yes, + ) + .map_err(|e| ChannelError::query(self.src_chain().id(), e))?; + + // Building the channel proof at the queried height + let src_proof = self + .src_chain() + .build_channel_proofs( + &src_port_id.clone(), + &src_channel_id.clone(), + src_latest_height, + ) + .map_err(ChannelError::channel_proof)?; + + let (dst_channel_end, _) = self + .dst_chain() + .query_channel( + QueryChannelRequest { + port_id: dst_port_id.clone(), + channel_id: dst_channel_id.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::Yes, + ) + .map_err(|e| ChannelError::query(self.src_chain().id(), e))?; + + let (upgrade, maybe_upgrade_proof) = self + .src_chain() + .query_upgrade( + QueryUpgradeRequest { + port_id: self.src_port_id().to_string(), + channel_id: src_channel_id.to_string(), + }, + src_latest_height, + IncludeProof::Yes, + ) + .map_err(|e| ChannelError::chain_query(self.src_chain().id(), e))?; + + let upgrade_proof = maybe_upgrade_proof.ok_or(ChannelError::missing_upgrade_proof())?; + + let proof_upgrade = + CommitmentProofBytes::try_from(upgrade_proof).map_err(ChannelError::malformed_proof)?; + + if !matches!(channel_end.state, State::Open(_)) { + return Err(ChannelError::invalid_channel_upgrade_state( + State::Open(UpgradeState::NotUpgrading).to_string(), + channel_end.state.to_string(), + )); + } + + let signer = self + .dst_chain() + .get_signer() + .map_err(|e| ChannelError::fetch_signer(self.dst_chain().id(), e))?; + + // Build the domain type message + let new_msg = MsgChannelUpgradeTry { + port_id: dst_port_id.clone(), + channel_id: dst_channel_id.clone(), + proposed_upgrade_connection_hops: dst_channel_end.connection_hops, + counterparty_upgrade_fields: upgrade.fields, + counterparty_upgrade_sequence: channel_end.upgrade_sequence, + proof_channel: src_proof.object_proof().clone(), + proof_upgrade, + proof_height: src_proof.height(), + signer, + }; + + let mut chain_a_msgs = self.build_update_client_on_dst(src_proof.height())?; + + chain_a_msgs.push(new_msg.to_any()); + + Ok(chain_a_msgs) + } + + pub fn build_chan_upgrade_try_and_send(&self) -> Result { + let dst_msgs = self.build_chan_upgrade_try()?; + + let tm = TrackedMsgs::new_static(dst_msgs, "ChannelUpgradeTry"); + + let events = self + .dst_chain() + .send_messages_and_wait_commit(tm) + .map_err(|e| ChannelError::submit(self.dst_chain().id(), e))?; + + // Find the relevant event for channel upgrade try + let result = events + .into_iter() + .find(|events_with_height| { + matches!(events_with_height.event, IbcEvent::UpgradeTryChannel(_)) + || matches!(events_with_height.event, IbcEvent::UpgradeErrorChannel(_)) + || matches!(events_with_height.event, IbcEvent::ChainError(_)) + }) + .ok_or_else(|| { + ChannelError::missing_event( + "no chan upgrade try or upgrade error event was in the response".to_string(), + ) + })?; + + match result.event { + IbcEvent::UpgradeTryChannel(_) => { + info!("👋 {} => {}", self.dst_chain().id(), result); + Ok(result.event) + } + IbcEvent::UpgradeErrorChannel(ref ev) => { + warn!( + "Channel Upgrade Try failed with error: {}", + ev.error_receipt + ); + Ok(result.event) + } + IbcEvent::ChainError(e) => Err(ChannelError::tx_response(e.clone())), + _ => Err(ChannelError::invalid_event(result.event)), + } + } + + pub fn build_chan_upgrade_ack(&self) -> Result, ChannelError> { + // Destination channel ID must exist + + let src_channel_id = self + .src_channel_id() + .ok_or_else(ChannelError::missing_counterparty_channel_id)?; + + let dst_channel_id = self + .dst_channel_id() + .ok_or_else(ChannelError::missing_counterparty_channel_id)?; + + let src_port_id = self.src_port_id(); + + let dst_port_id = self.dst_port_id(); + + let src_latest_height = self + .src_chain() + .query_latest_height() + .map_err(|e| ChannelError::chain_query(self.src_chain().id(), e))?; + + let (upgrade, maybe_upgrade_proof) = self + .src_chain() + .query_upgrade( + QueryUpgradeRequest { + port_id: self.src_port_id().to_string(), + channel_id: src_channel_id.to_string(), + }, + src_latest_height, + IncludeProof::Yes, + ) + .map_err(|e| ChannelError::chain_query(self.src_chain().id(), e))?; + + let upgrade_proof = maybe_upgrade_proof.ok_or(ChannelError::missing_upgrade_proof())?; + + let proof_upgrade = + CommitmentProofBytes::try_from(upgrade_proof).map_err(ChannelError::malformed_proof)?; + + // Building the channel proof at the queried height + let proof = self + .src_chain() + .build_channel_proofs( + &src_port_id.clone(), + &src_channel_id.clone(), + src_latest_height, + ) + .map_err(ChannelError::channel_proof)?; + + let signer = self + .dst_chain() + .get_signer() + .map_err(|e| ChannelError::fetch_signer(self.dst_chain().id(), e))?; + + // Build the domain type message + let new_msg = MsgChannelUpgradeAck { + port_id: dst_port_id.clone(), + channel_id: dst_channel_id.clone(), + counterparty_upgrade: upgrade, + proof_channel: proof.object_proof().clone(), + proof_upgrade, + proof_height: proof.height(), + signer, + }; + + let mut chain_a_msgs = self.build_update_client_on_dst(proof.height())?; + + chain_a_msgs.push(new_msg.to_any()); + + Ok(chain_a_msgs) + } + + pub fn build_chan_upgrade_ack_and_send(&self) -> Result { + let dst_msgs = self.build_chan_upgrade_ack()?; + + let tm = TrackedMsgs::new_static(dst_msgs, "ChannelUpgradeAck"); + + let events = self + .dst_chain() + .send_messages_and_wait_commit(tm) + .map_err(|e| ChannelError::submit(self.dst_chain().id(), e))?; + + // Find the relevant event for channel upgrade ack + let result = events + .into_iter() + .find(|events_with_height| { + matches!(events_with_height.event, IbcEvent::UpgradeAckChannel(_)) + || matches!(events_with_height.event, IbcEvent::UpgradeErrorChannel(_)) + || matches!(events_with_height.event, IbcEvent::ChainError(_)) + }) + .ok_or_else(|| { + ChannelError::missing_event( + "no chan upgrade ack or upgrade error event was in the response".to_string(), + ) + })?; + + match result.event { + IbcEvent::UpgradeAckChannel(_) => { + info!("👋 {} => {}", self.dst_chain().id(), result); + Ok(result.event) + } + IbcEvent::UpgradeErrorChannel(ref ev) => { + warn!( + "Channel Upgrade Ack failed with error: {}", + ev.error_receipt + ); + Ok(result.event) + } + IbcEvent::ChainError(e) => Err(ChannelError::tx_response(e.clone())), + _ => Err(ChannelError::invalid_event(result.event)), + } + } + + pub fn build_chan_upgrade_confirm(&self) -> Result, ChannelError> { + // Destination channel ID must exist + + let src_channel_id = self + .src_channel_id() + .ok_or_else(ChannelError::missing_counterparty_channel_id)?; + + let dst_channel_id = self + .dst_channel_id() + .ok_or_else(ChannelError::missing_counterparty_channel_id)?; + + let src_port_id = self.src_port_id(); + + let dst_port_id = self.dst_port_id(); + + let src_latest_height = self + .src_chain() + .query_latest_height() + .map_err(|e| ChannelError::chain_query(self.src_chain().id(), e))?; + + // Fetch the src channel end that will be upgraded by the upgrade handshake + // Querying for the Channel End now includes the upgrade sequence number + let (channel_end, _) = self + .src_chain() + .query_channel( + QueryChannelRequest { + port_id: src_port_id.clone(), + channel_id: src_channel_id.clone(), + height: QueryHeight::Specific(src_latest_height), + }, + IncludeProof::Yes, + ) + .map_err(|e| ChannelError::query(self.src_chain().id(), e))?; + + let (upgrade, maybe_upgrade_proof) = self + .src_chain() + .query_upgrade( + QueryUpgradeRequest { + port_id: self.src_port_id().to_string(), + channel_id: src_channel_id.to_string(), + }, + src_latest_height, + IncludeProof::Yes, + ) + .map_err(|e| ChannelError::chain_query(self.src_chain().id(), e))?; + + let upgrade_proof = maybe_upgrade_proof.ok_or(ChannelError::missing_upgrade_proof())?; + + let proof_upgrade = + CommitmentProofBytes::try_from(upgrade_proof).map_err(ChannelError::malformed_proof)?; + + // Building the channel proof at the queried height + let proof = self + .src_chain() + .build_channel_proofs( + &src_port_id.clone(), + &src_channel_id.clone(), + src_latest_height, + ) + .map_err(ChannelError::channel_proof)?; + + let signer = self + .dst_chain() + .get_signer() + .map_err(|e| ChannelError::fetch_signer(self.dst_chain().id(), e))?; + + // Build the domain type message + let new_msg = MsgChannelUpgradeConfirm { + port_id: dst_port_id.clone(), + channel_id: dst_channel_id.clone(), + counterparty_channel_state: channel_end.state, + counterparty_upgrade: upgrade, + proof_channel: proof.object_proof().clone(), + proof_upgrade, + proof_height: proof.height(), + signer, + }; + + let mut chain_a_msgs = self.build_update_client_on_dst(proof.height())?; + + chain_a_msgs.push(new_msg.to_any()); + + Ok(chain_a_msgs) + } + + pub fn build_chan_upgrade_confirm_and_send(&self) -> Result { + let dst_msgs = self.build_chan_upgrade_confirm()?; + + let tm = TrackedMsgs::new_static(dst_msgs, "ChannelUpgradeConfirm"); + + let events = self + .dst_chain() + .send_messages_and_wait_commit(tm) + .map_err(|e| ChannelError::submit(self.dst_chain().id(), e))?; + + // Find the relevant event for channel upgrade confirm + let result = events + .into_iter() + .find(|events_with_height| { + matches!(events_with_height.event, IbcEvent::UpgradeConfirmChannel(_)) + || matches!(events_with_height.event, IbcEvent::UpgradeErrorChannel(_)) + || matches!(events_with_height.event, IbcEvent::ChainError(_)) + }) + .ok_or_else(|| { + ChannelError::missing_event( + "no chan upgrade ack or upgrade error event was in the response".to_string(), + ) + })?; + + match result.event { + IbcEvent::UpgradeConfirmChannel(_) => { + info!("👋 {} => {}", self.dst_chain().id(), result); + Ok(result.event) + } + IbcEvent::UpgradeErrorChannel(ref ev) => { + warn!( + "Channel Upgrade Confirm failed with error: {}", + ev.error_receipt + ); + Ok(result.event) + } + IbcEvent::ChainError(e) => Err(ChannelError::tx_response(e.clone())), + _ => Err(ChannelError::invalid_event(result.event)), + } + } + + pub fn build_chan_upgrade_open(&self) -> Result, ChannelError> { + // Destination channel ID must exist + let src_channel_id = self + .src_channel_id() + .ok_or_else(ChannelError::missing_counterparty_channel_id)?; + + let dst_channel_id = self + .dst_channel_id() + .ok_or_else(ChannelError::missing_counterparty_channel_id)?; + + let src_port_id = self.src_port_id(); + + let dst_port_id = self.dst_port_id(); + + let src_latest_height = self + .src_chain() + .query_latest_height() + .map_err(|e| ChannelError::chain_query(self.src_chain().id(), e))?; + + let (src_channel_end, _) = self + .src_chain() + .query_channel( + QueryChannelRequest { + port_id: src_port_id.clone(), + channel_id: src_channel_id.clone(), + height: QueryHeight::Specific(src_latest_height), + }, + IncludeProof::Yes, + ) + .map_err(|e| ChannelError::query(self.src_chain().id(), e))?; + + let counterparty_upgrade_sequence = src_channel_end.upgrade_sequence; + + // Building the channel proof at the queried height + let proofs = self + .src_chain() + .build_channel_proofs( + &src_port_id.clone(), + &src_channel_id.clone(), + src_latest_height, + ) + .map_err(ChannelError::channel_proof)?; + + // Build message(s) to update client on destination + let mut msgs = self.build_update_client_on_dst(proofs.height())?; + + let signer = self + .dst_chain() + .get_signer() + .map_err(|e| ChannelError::fetch_signer(self.dst_chain().id(), e))?; + + // Build the domain type message + let new_msg = MsgChannelUpgradeOpen { + port_id: dst_port_id.clone(), + channel_id: dst_channel_id.clone(), + counterparty_channel_state: src_channel_end.state, + counterparty_upgrade_sequence, + proof_channel: proofs.object_proof().clone(), + proof_height: proofs.height(), + signer, + }; + + msgs.push(new_msg.to_any()); + Ok(msgs) + } + + pub fn build_chan_upgrade_open_and_send(&self) -> Result { + let dst_msgs = self.build_chan_upgrade_open()?; + + let tm = TrackedMsgs::new_static(dst_msgs, "ChannelUpgradeOpen"); + + let events = self + .dst_chain() + .send_messages_and_wait_commit(tm) + .map_err(|e| ChannelError::submit(self.dst_chain().id(), e))?; + + let result = events + .into_iter() + .find(|event_with_height| { + matches!(event_with_height.event, IbcEvent::UpgradeOpenChannel(_)) + || matches!(event_with_height.event, IbcEvent::ChainError(_)) + }) + .ok_or_else(|| { + ChannelError::missing_event( + "no channel upgrade open event was in the response".to_string(), + ) + })?; + + match &result.event { + IbcEvent::UpgradeOpenChannel(_) => { + info!("👋 {} => {}", self.dst_chain().id(), result); + Ok(result.event) + } + IbcEvent::ChainError(e) => Err(ChannelError::tx_response(e.clone())), + _ => Err(ChannelError::invalid_event(result.event)), + } + } + + pub fn build_chan_upgrade_cancel(&self) -> Result, ChannelError> { + // Destination channel ID must exist + let src_channel_id = self + .src_channel_id() + .ok_or_else(ChannelError::missing_counterparty_channel_id)?; + + let dst_channel_id = self + .dst_channel_id() + .ok_or_else(ChannelError::missing_counterparty_channel_id)?; + + let src_port_id = self.src_port_id(); + + let dst_port_id = self.dst_port_id(); + + let src_latest_height = self + .src_chain() + .query_latest_height() + .map_err(|e| ChannelError::chain_query(self.src_chain().id(), e))?; + + let (error_receipt, maybe_error_receipt_proof) = self + .src_chain() + .query_upgrade_error( + QueryUpgradeErrorRequest { + port_id: src_port_id.to_string(), + channel_id: src_channel_id.to_string(), + }, + src_latest_height, + IncludeProof::Yes, + ) + .map_err(|e| ChannelError::chain_query(self.src_chain().id(), e))?; + + let error_receipt_proof = + maybe_error_receipt_proof.ok_or(ChannelError::missing_upgrade_error_receipt_proof())?; + + let proof_error_receipt = CommitmentProofBytes::try_from(error_receipt_proof) + .map_err(ChannelError::malformed_proof)?; + + // Building the channel proof at the queried height + let proofs = self + .src_chain() + .build_channel_proofs( + &src_port_id.clone(), + &src_channel_id.clone(), + src_latest_height, + ) + .map_err(ChannelError::channel_proof)?; + + // Build message(s) to update client on destination + let mut msgs = self.build_update_client_on_dst(proofs.height())?; + + let signer = self + .dst_chain() + .get_signer() + .map_err(|e| ChannelError::fetch_signer(self.dst_chain().id(), e))?; + + // Build the domain type message + let new_msg = MsgChannelUpgradeCancel { + port_id: dst_port_id.clone(), + channel_id: dst_channel_id.clone(), + error_receipt, + proof_error_receipt, + proof_height: proofs.height(), + signer, + }; + + msgs.push(new_msg.to_any()); + Ok(msgs) + } + + pub fn build_chan_upgrade_cancel_and_send(&self) -> Result { + let dst_msgs = self.build_chan_upgrade_cancel()?; + + let tm = TrackedMsgs::new_static(dst_msgs, "ChannelUpgradeCancel"); + + let events = self + .dst_chain() + .send_messages_and_wait_commit(tm) + .map_err(|e| ChannelError::submit(self.dst_chain().id(), e))?; + + let result = events + .into_iter() + .find(|event_with_height| { + matches!(event_with_height.event, IbcEvent::UpgradeCancelChannel(_)) + || matches!(event_with_height.event, IbcEvent::ChainError(_)) + }) + .ok_or_else(|| { + ChannelError::missing_event( + "no channel upgrade cancel event was in the response".to_string(), + ) + })?; + + match &result.event { + IbcEvent::UpgradeCancelChannel(_) => { + info!("👋 {} => {}", self.dst_chain().id(), result); + Ok(result.event) + } + IbcEvent::ChainError(e) => Err(ChannelError::tx_response(e.clone())), + _ => Err(ChannelError::invalid_event(result.event)), + } + } + + pub fn build_chan_upgrade_timeout(&self) -> Result, ChannelError> { + // Destination channel ID must exist + let src_channel_id = self + .src_channel_id() + .ok_or_else(ChannelError::missing_counterparty_channel_id)?; + + let dst_channel_id = self + .dst_channel_id() + .ok_or_else(ChannelError::missing_counterparty_channel_id)?; + + let src_port_id = self.src_port_id(); + + let dst_port_id = self.dst_port_id(); + + let src_latest_height = self + .src_chain() + .query_latest_height() + .map_err(|e| ChannelError::chain_query(self.src_chain().id(), e))?; + + // Retrieve counterparty channel + let (counterparty_channel, _) = self + .src_chain() + .query_channel( + QueryChannelRequest { + port_id: src_port_id.clone(), + channel_id: src_channel_id.clone(), + height: QueryHeight::Specific(src_latest_height), + }, + IncludeProof::Yes, + ) + .map_err(|e| ChannelError::query(self.src_chain().id(), e))?; + + // Building the channel proof at the queried height + let proofs = self + .src_chain() + .build_channel_proofs( + &src_port_id.clone(), + &src_channel_id.clone(), + src_latest_height, + ) + .map_err(ChannelError::channel_proof)?; + + // Build message(s) to update client on destination + let mut msgs = self.build_update_client_on_dst(proofs.height())?; + + let signer = self + .dst_chain() + .get_signer() + .map_err(|e| ChannelError::fetch_signer(self.dst_chain().id(), e))?; + + // Build the domain type message + let new_msg = MsgChannelUpgradeTimeout { + port_id: dst_port_id.clone(), + channel_id: dst_channel_id.clone(), + counterparty_channel, + proof_channel: proofs.object_proof().clone(), + proof_height: proofs.height(), + signer, + }; + + msgs.push(new_msg.to_any()); + Ok(msgs) + } + + pub fn build_chan_upgrade_timeout_and_send(&self) -> Result { + let dst_msgs = self.build_chan_upgrade_timeout()?; + + let tm = TrackedMsgs::new_static(dst_msgs, "ChannelUpgradeTimeout"); + + let events = self + .dst_chain() + .send_messages_and_wait_commit(tm) + .map_err(|e| ChannelError::submit(self.dst_chain().id(), e))?; + + let result = events + .into_iter() + .find(|event_with_height| { + matches!(event_with_height.event, IbcEvent::UpgradeTimeoutChannel(_)) + || matches!(event_with_height.event, IbcEvent::ChainError(_)) + }) + .ok_or_else(|| { + ChannelError::missing_event( + "no channel upgrade timeout event was in the response".to_string(), + ) + })?; + + match &result.event { + IbcEvent::UpgradeTimeoutChannel(_) => { + info!("👋 {} => {}", self.dst_chain().id(), result); + Ok(result.event) + } + IbcEvent::ChainError(e) => Err(ChannelError::tx_response(e.clone())), + _ => Err(ChannelError::invalid_event(result.event)), + } + } + pub fn map_chain( self, mapper_a: impl Fn(ChainA) -> ChainC, @@ -1477,6 +2221,38 @@ impl Channel { connection_delay: self.connection_delay, } } + + pub fn build_chan_upgrade_open_or_cancel_and_send( + &self, + ) -> Result, ChannelError> { + // Check if error query_upgrade_error + let height = self.a_chain().query_latest_height().unwrap(); + let upgrade_error = self + .a_chain() + .query_upgrade_error( + QueryUpgradeErrorRequest { + port_id: self.a_side.port_id.clone().to_string(), + channel_id: self.a_side.channel_id.clone().unwrap().clone().to_string(), + }, + height, + IncludeProof::No, + ) + .map_err(|_| ChannelError::missing_upgrade_error_receipt_proof()); + + let channel_end = self.b_channel(self.b_channel_id())?; + + if let Ok((upgrade_error, _)) = upgrade_error { + if upgrade_error.sequence > 0.into() + && upgrade_error.sequence == channel_end.upgrade_sequence + { + Ok(Some(self.build_chan_upgrade_cancel_and_send()?)) + } else { + Ok(Some(self.build_chan_upgrade_open_and_send()?)) + } + } else { + Ok(Some(self.build_chan_upgrade_open_and_send()?)) + } + } } pub fn extract_channel_id(event: &IbcEvent) -> Result<&ChannelId, ChannelError> { @@ -1485,6 +2261,7 @@ pub fn extract_channel_id(event: &IbcEvent) -> Result<&ChannelId, ChannelError> IbcEvent::OpenTryChannel(ev) => ev.channel_id(), IbcEvent::OpenAckChannel(ev) => ev.channel_id(), IbcEvent::OpenConfirmChannel(ev) => ev.channel_id(), + IbcEvent::UpgradeInitChannel(ev) => Some(ev.channel_id()), _ => None, } .ok_or_else(|| ChannelError::missing_event("cannot extract channel_id from result".to_string())) @@ -1508,7 +2285,9 @@ fn check_destination_channel_state( existing_channel.connection_hops() == expected_channel.connection_hops(); // TODO: Refactor into a method - let good_state = *existing_channel.state() as u32 <= *expected_channel.state() as u32; + let good_state = existing_channel + .state() + .less_or_equal_progress(*expected_channel.state()); let good_channel_port_ids = existing_channel.counterparty().channel_id().is_none() || existing_channel.counterparty().channel_id() == expected_channel.counterparty().channel_id() diff --git a/crates/relayer/src/channel/error.rs b/crates/relayer/src/channel/error.rs index c6d3b40391..e25b1898bf 100644 --- a/crates/relayer/src/channel/error.rs +++ b/crates/relayer/src/channel/error.rs @@ -3,11 +3,12 @@ use core::time::Duration; use flex_error::{define_error, ErrorMessageTracer}; use ibc_relayer_types::core::ics02_client::error::Error as ClientError; -use ibc_relayer_types::core::ics04_channel::channel::State; +use ibc_relayer_types::core::ics04_channel::channel::{Ordering, State}; use ibc_relayer_types::core::ics24_host::identifier::{ ChainId, ChannelId, ClientId, PortChannelId, PortId, }; use ibc_relayer_types::events::IbcEvent; +use ibc_relayer_types::proofs::ProofError; use crate::error::Error as RelayerError; use crate::foreign_client::{ForeignClientError, HasExpiredOrFrozenError}; @@ -34,6 +35,16 @@ define_error! { e.reason) }, + InvalidChannelUpgradeOrdering + |_| { "attempted to upgrade a channel to a more strict ordring, which is not allowed" }, + + InvalidChannelUpgradeState + { expected: String, actual: String } + |e| { format_args!("channel state should be {} but is {}", e.expected, e.actual) }, + + InvalidChannelUpgradeTimeout + |_| { "attempted to upgrade a channel without supplying at least one of timeout height or timeout timestamp" }, + MissingLocalChannelId |_| { "failed due to missing local channel id" }, @@ -53,10 +64,33 @@ define_error! { MissingChannelOnDestination |_| { "missing channel on destination chain" }, + MissingChannelProof + |_| { "missing channel proof" }, + + MissingUpgradeProof + |_| { "missing upgrade proof" }, + + MissingUpgradeErrorReceiptProof + |_| { "missing upgrade error receipt proof" }, + + MalformedProof + [ ProofError ] + |_| { "malformed proof" }, + ChannelProof [ RelayerError ] |_| { "failed to build channel proofs" }, + InvalidOrdering + { + channel_ordering: Ordering, + counterparty_ordering: Ordering, + } + | e | { + format_args!("channel ordering '{0}' does not match counterparty ordering '{1}'", + e.channel_ordering, e.counterparty_ordering) + }, + ClientOperation { client_id: ClientId, diff --git a/crates/relayer/src/channel/version.rs b/crates/relayer/src/channel/version.rs index 2aaf0b36ea..bbca71403e 100644 --- a/crates/relayer/src/channel/version.rs +++ b/crates/relayer/src/channel/version.rs @@ -8,7 +8,7 @@ use ibc_relayer_types::{applications::transfer, core::ics24_host::identifier::Po pub use ibc_relayer_types::core::ics04_channel::version::Version; -/// Returns the default channel version, depending on the the given [`PortId`]. +/// Returns the default channel version, depending on the given [`PortId`]. pub fn default_by_port(port_id: &PortId) -> Option { if port_id.as_str() == transfer::PORT_ID_STR { // https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer#forwards-compatibility diff --git a/crates/relayer/src/client_state.rs b/crates/relayer/src/client_state.rs index 814abddff6..85f5b83dc4 100644 --- a/crates/relayer/src/client_state.rs +++ b/crates/relayer/src/client_state.rs @@ -1,4 +1,4 @@ -use core::time::Duration; +use std::time::Duration; use serde::{Deserialize, Serialize}; @@ -7,8 +7,7 @@ use ibc_proto::ibc::core::client::v1::IdentifiedClientState; use ibc_proto::ibc::lightclients::tendermint::v1::ClientState as RawTmClientState; use ibc_proto::Protobuf; use ibc_relayer_types::clients::ics07_tendermint::client_state::{ - ClientState as TmClientState, UpgradeOptions as TmUpgradeOptions, - TENDERMINT_CLIENT_STATE_TYPE_URL, + ClientState as TmClientState, TENDERMINT_CLIENT_STATE_TYPE_URL, }; use ibc_relayer_types::core::ics02_client::client_state::ClientState; use ibc_relayer_types::core::ics02_client::client_type::ClientType; @@ -18,102 +17,58 @@ use ibc_relayer_types::core::ics24_host::error::ValidationError; use ibc_relayer_types::core::ics24_host::identifier::{ChainId, ClientId}; use ibc_relayer_types::Height; -#[cfg(test)] -use ibc_proto::ibc::mock::ClientState as RawMockClientState; -#[cfg(test)] -use ibc_relayer_types::mock::client_state::MockClientState; -#[cfg(test)] -use ibc_relayer_types::mock::client_state::MOCK_CLIENT_STATE_TYPE_URL; - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(tag = "type")] -pub enum AnyUpgradeOptions { - Tendermint(TmUpgradeOptions), - - #[cfg(test)] - Mock(()), -} - -impl AnyUpgradeOptions { - fn into_tm_upgrade_options(self) -> Option { - match self { - AnyUpgradeOptions::Tendermint(tm) => Some(tm), - #[cfg(test)] - AnyUpgradeOptions::Mock(_) => None, - } - } -} - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(tag = "type")] pub enum AnyClientState { Tendermint(TmClientState), - - #[cfg(test)] - Mock(MockClientState), } impl AnyClientState { pub fn chain_id(&self) -> ChainId { match self { AnyClientState::Tendermint(tm_state) => tm_state.chain_id(), - - #[cfg(test)] - AnyClientState::Mock(mock_state) => mock_state.chain_id(), } } pub fn latest_height(&self) -> Height { match self { Self::Tendermint(tm_state) => tm_state.latest_height(), - - #[cfg(test)] - Self::Mock(mock_state) => mock_state.latest_height(), } } pub fn frozen_height(&self) -> Option { match self { Self::Tendermint(tm_state) => tm_state.frozen_height(), - - #[cfg(test)] - Self::Mock(mock_state) => mock_state.frozen_height(), } } pub fn trust_threshold(&self) -> Option { match self { AnyClientState::Tendermint(state) => Some(state.trust_threshold), - - #[cfg(test)] - AnyClientState::Mock(_) => None, } } pub fn trusting_period(&self) -> Duration { match self { AnyClientState::Tendermint(state) => state.trusting_period, - - #[cfg(test)] - AnyClientState::Mock(_) => Duration::from_secs(14 * 24 * 60 * 60), // 2 weeks } } pub fn max_clock_drift(&self) -> Duration { match self { AnyClientState::Tendermint(state) => state.max_clock_drift, - - #[cfg(test)] - AnyClientState::Mock(_) => Duration::new(0, 0), } } pub fn client_type(&self) -> ClientType { match self { Self::Tendermint(state) => state.client_type(), + } + } - #[cfg(test)] - Self::Mock(state) => state.client_type(), + pub fn expired(&self, elapsed: Duration) -> bool { + match self { + Self::Tendermint(state) => state.expired(elapsed), } } } @@ -132,12 +87,6 @@ impl TryFrom for AnyClientState { .map_err(Error::decode_raw_client_state)?, )), - #[cfg(test)] - MOCK_CLIENT_STATE_TYPE_URL => Ok(AnyClientState::Mock( - Protobuf::::decode_vec(&raw.value) - .map_err(Error::decode_raw_client_state)?, - )), - _ => Err(Error::unknown_client_state_type(raw.type_url)), } } @@ -150,68 +99,29 @@ impl From for Any { type_url: TENDERMINT_CLIENT_STATE_TYPE_URL.to_string(), value: Protobuf::::encode_vec(value), }, - #[cfg(test)] - AnyClientState::Mock(value) => Any { - type_url: MOCK_CLIENT_STATE_TYPE_URL.to_string(), - value: Protobuf::::encode_vec(value), - }, } } } impl ClientState for AnyClientState { - type UpgradeOptions = AnyUpgradeOptions; - fn chain_id(&self) -> ChainId { - match self { - AnyClientState::Tendermint(tm_state) => tm_state.chain_id(), - - #[cfg(test)] - AnyClientState::Mock(mock_state) => mock_state.chain_id(), - } + AnyClientState::chain_id(self) } fn client_type(&self) -> ClientType { - self.client_type() + AnyClientState::client_type(self) } fn latest_height(&self) -> Height { - self.latest_height() + AnyClientState::latest_height(self) } fn frozen_height(&self) -> Option { - self.frozen_height() + AnyClientState::frozen_height(self) } - fn upgrade( - &mut self, - upgrade_height: Height, - upgrade_options: AnyUpgradeOptions, - chain_id: ChainId, - ) { - match self { - AnyClientState::Tendermint(tm_state) => { - if let Some(upgrade_options) = upgrade_options.into_tm_upgrade_options() { - tm_state.upgrade(upgrade_height, upgrade_options, chain_id); - } - // TODO: Handle case where upgrade options are not of the right type, - // not a problem in practice for now but good to have. - } - - #[cfg(test)] - AnyClientState::Mock(mock_state) => { - mock_state.upgrade(upgrade_height, (), chain_id); - } - } - } - - fn expired(&self, elapsed_since_latest: Duration) -> bool { - match self { - AnyClientState::Tendermint(tm_state) => tm_state.expired(elapsed_since_latest), - - #[cfg(test)] - AnyClientState::Mock(mock_state) => mock_state.expired(elapsed_since_latest), - } + fn expired(&self, elapsed: Duration) -> bool { + AnyClientState::expired(self, elapsed) } } @@ -221,13 +131,6 @@ impl From for AnyClientState { } } -#[cfg(test)] -impl From for AnyClientState { - fn from(cs: MockClientState) -> Self { - Self::Mock(cs) - } -} - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(tag = "type")] pub struct IdentifiedAnyClientState { @@ -270,23 +173,3 @@ impl From for IdentifiedClientState { } } } - -#[cfg(test)] -mod tests { - use ibc_proto::google::protobuf::Any; - use ibc_relayer_types::clients::ics07_tendermint::client_state::test_util::get_dummy_tendermint_client_state; - use ibc_relayer_types::clients::ics07_tendermint::header::test_util::get_dummy_tendermint_header; - use test_log::test; - - use super::AnyClientState; - - #[test] - fn any_client_state_serialization() { - let tm_client_state: AnyClientState = - get_dummy_tendermint_client_state(get_dummy_tendermint_header()).into(); - - let raw: Any = tm_client_state.clone().into(); - let tm_client_state_back = AnyClientState::try_from(raw).unwrap(); - assert_eq!(tm_client_state, tm_client_state_back); - } -} diff --git a/crates/relayer/src/config.rs b/crates/relayer/src/config.rs index 2f335e13d0..fa4725a6d2 100644 --- a/crates/relayer/src/config.rs +++ b/crates/relayer/src/config.rs @@ -14,6 +14,8 @@ use core::cmp::Ordering; use core::fmt::{Display, Error as FmtError, Formatter}; use core::str::FromStr; use core::time::Duration; +use ibc_relayer_types::core::ics04_channel::packet::Sequence; +use std::borrow::Cow; use std::{fs, fs::File, io::Write, ops::Range, path::Path}; use byte_unit::Byte; @@ -104,7 +106,7 @@ impl PartialOrd for GasPrice { /// the parsing of other prices. pub fn parse_gas_prices(prices: String) -> Vec { prices - .split(|c| c == ',' || c == ';') + .split([',', ';']) .filter_map(|gp| GasPrice::from_str(gp).ok()) .collect() } @@ -173,7 +175,11 @@ pub mod default { } pub fn poll_interval() -> Duration { - Duration::from_secs(1) + Duration::from_millis(500) + } + + pub fn max_retries() -> u32 { + 4 } pub fn batch_delay() -> Duration { @@ -240,6 +246,14 @@ pub mod default { pub fn ics20_max_receiver_size() -> Ics20FieldSizeLimit { Ics20FieldSizeLimit::new(true, Byte::from_bytes(2048)) } + + pub fn allow_ccq() -> bool { + true + } + + pub fn clear_limit() -> usize { + 50 + } } #[derive(Clone, Debug, Default, Deserialize, Serialize)] @@ -414,6 +428,11 @@ pub struct Packets { pub ics20_max_memo_size: Ics20FieldSizeLimit, #[serde(default = "default::ics20_max_receiver_size")] pub ics20_max_receiver_size: Ics20FieldSizeLimit, + #[serde(default = "default::clear_limit")] + pub clear_limit: usize, + + #[serde(skip)] + pub force_disable_clear_on_start: bool, } impl Default for Packets { @@ -426,6 +445,8 @@ impl Default for Packets { auto_register_counterparty_payee: default::auto_register_counterparty_payee(), ics20_max_memo_size: default::ics20_max_memo_size(), ics20_max_receiver_size: default::ics20_max_receiver_size(), + clear_limit: default::clear_limit(), + force_disable_clear_on_start: false, } } } @@ -616,6 +637,11 @@ pub enum EventSourceMode { /// The polling interval #[serde(default = "default::poll_interval", with = "humantime_serde")] interval: Duration, + + /// The maximum retries to collect the block results + /// before giving up and moving to the next block + #[serde(default = "default::max_retries")] + max_retries: u32, }, } @@ -699,6 +725,23 @@ impl ChainConfig { Self::CosmosSdk(config) => config.query_packets_chunk_size = query_packets_chunk_size, } } + + pub fn excluded_sequences(&self, channel_id: &ChannelId) -> Cow<'_, [Sequence]> { + match self { + Self::CosmosSdk(config) => config + .excluded_sequences + .map + .get(channel_id) + .map(|seqs| Cow::Borrowed(seqs.as_slice())) + .unwrap_or_else(|| Cow::Owned(Vec::new())), + } + } + + pub fn allow_ccq(&self) -> bool { + match self { + Self::CosmosSdk(config) => config.allow_ccq, + } + } } // /!\ Update me when adding a new chain type! @@ -738,7 +781,7 @@ impl<'de> Deserialize<'de> for ChainConfig { /// Attempt to load and parse the TOML config file as a `Config`. pub fn load(path: impl AsRef) -> Result { - let config_toml = std::fs::read_to_string(&path).map_err(Error::io)?; + let config_toml = fs::read_to_string(&path).map_err(Error::io)?; let config = toml::from_str::(&config_toml[..]).map_err(Error::decode)?; @@ -809,7 +852,7 @@ impl From for Error { mod tests { use core::str::FromStr; - use super::{load, parse_gas_prices, store_writer}; + use super::{load, parse_gas_prices, store_writer, ChainConfig}; use crate::config::GasPrice; use test_log::test; @@ -900,6 +943,39 @@ mod tests { store_writer(&config, &mut buffer).unwrap(); } + #[test] + fn serialize_valid_excluded_sequences_config() { + let path = concat!( + env!("CARGO_MANIFEST_DIR"), + "/tests/config/fixtures/relayer_conf_example.toml" + ); + + let config = load(path).expect("could not parse config"); + + let excluded_sequences1 = match config.chains.first().unwrap() { + ChainConfig::CosmosSdk(chain_config) => chain_config.excluded_sequences.clone(), + }; + + let excluded_sequences2 = match config.chains.last().unwrap() { + ChainConfig::CosmosSdk(chain_config) => chain_config.excluded_sequences.clone(), + }; + + assert_eq!(excluded_sequences1, excluded_sequences2); + + let mut buffer = Vec::new(); + store_writer(&config, &mut buffer).unwrap(); + } + + #[test] + fn serialize_invalid_excluded_sequences_config() { + let path = concat!( + env!("CARGO_MANIFEST_DIR"), + "/tests/config/fixtures/relayer_conf_example_invalid_excluded_sequences.toml" + ); + + assert!(load(path).is_err()); + } + #[test] fn gas_price_from_str() { let gp_original = GasPrice::new(10.0, "atom".to_owned()); diff --git a/crates/relayer/src/config/compat_mode.rs b/crates/relayer/src/config/compat_mode.rs index 79323888f7..795081ea6f 100644 --- a/crates/relayer/src/config/compat_mode.rs +++ b/crates/relayer/src/config/compat_mode.rs @@ -1,97 +1 @@ -use core::fmt::{Display, Error as FmtError, Formatter}; -use core::str::FromStr; -use serde::Deserialize; -use serde::Deserializer; -use serde::Serialize; -use serde::Serializer; - -use tendermint_rpc::client::CompatMode as TmCompatMode; - -use crate::config::Error; - -/// CometBFT RPC compatibility mode -/// -/// Can be removed in favor of the one in tendermint-rs, once -/// is merged. -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum CompatMode { - /// Use version 0.34 of the protocol. - V0_34, - /// Use version 0.37 of the protocol. - V0_37, -} - -impl Display for CompatMode { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - match self { - Self::V0_34 => write!(f, "v0.34"), - Self::V0_37 => write!(f, "v0.37"), - } - } -} - -impl FromStr for CompatMode { - type Err = Error; - - fn from_str(s: &str) -> Result { - const VALID_COMPAT_MODES: &str = "0.34, 0.37"; - - // Trim leading 'v', if present - match s.trim_start_matches('v') { - "0.34" => Ok(CompatMode::V0_34), - "0.37" => Ok(CompatMode::V0_37), - _ => Err(Error::invalid_compat_mode( - s.to_string(), - VALID_COMPAT_MODES, - )), - } - } -} - -impl<'de> Deserialize<'de> for CompatMode { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - use serde::de; - - let s = String::deserialize(deserializer)?; - FromStr::from_str(&s).map_err(de::Error::custom) - } -} - -impl Serialize for CompatMode { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - self.to_string().serialize(serializer) - } -} - -impl From for CompatMode { - fn from(value: TmCompatMode) -> Self { - match value { - TmCompatMode::V0_34 => Self::V0_34, - TmCompatMode::V0_37 => Self::V0_37, - } - } -} - -impl From for TmCompatMode { - fn from(value: CompatMode) -> Self { - match value { - CompatMode::V0_34 => Self::V0_34, - CompatMode::V0_37 => Self::V0_37, - } - } -} - -impl CompatMode { - pub fn equal_to_tm_compat_mode(&self, tm_compat_mode: TmCompatMode) -> bool { - match self { - Self::V0_34 => tm_compat_mode == TmCompatMode::V0_34, - Self::V0_37 => tm_compat_mode == TmCompatMode::V0_37, - } - } -} +pub use tendermint_rpc::client::CompatMode; diff --git a/crates/relayer/src/config/filter.rs b/crates/relayer/src/config/filter.rs index 9733671b0c..002a19b0f9 100644 --- a/crates/relayer/src/config/filter.rs +++ b/crates/relayer/src/config/filter.rs @@ -1,5 +1,7 @@ //! Custom `serde` deserializer for `FilterMatch` +#![allow(clippy::mutable_key_type)] + use core::fmt; use core::str::FromStr; use itertools::Itertools; @@ -206,7 +208,7 @@ impl Serialize for ChannelFilters { b: &'a FilterPattern, } - impl<'a> Serialize for Pair<'a> { + impl Serialize for Pair<'_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -373,11 +375,10 @@ impl<'de> Deserialize<'de> for ChannelFilterMatch { pub(crate) mod port { use super::*; - use ibc_relayer_types::core::ics24_host::identifier::PortId; pub struct PortFilterMatchVisitor; - impl<'de> de::Visitor<'de> for PortFilterMatchVisitor { + impl de::Visitor<'_> for PortFilterMatchVisitor { type Value = PortFilterMatch; fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -385,11 +386,13 @@ pub(crate) mod port { } fn visit_str(self, v: &str) -> Result { - if let Ok(port_id) = PortId::from_str(v) { - Ok(PortFilterMatch::Exact(port_id)) - } else { - let wildcard = v.parse().map_err(E::custom)?; + let trimmed_v = v.trim(); + if trimmed_v.contains('*') { + let wildcard = trimmed_v.parse().map_err(E::custom)?; Ok(PortFilterMatch::Wildcard(wildcard)) + } else { + let port_id = PortId::from_str(trimmed_v).map_err(E::custom)?; + Ok(PortFilterMatch::Exact(port_id)) } } @@ -401,11 +404,10 @@ pub(crate) mod port { pub(crate) mod channel { use super::*; - use ibc_relayer_types::core::ics24_host::identifier::ChannelId; pub struct ChannelFilterMatchVisitor; - impl<'de> de::Visitor<'de> for ChannelFilterMatchVisitor { + impl de::Visitor<'_> for ChannelFilterMatchVisitor { type Value = ChannelFilterMatch; fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -413,11 +415,13 @@ pub(crate) mod channel { } fn visit_str(self, v: &str) -> Result { - if let Ok(channel_id) = ChannelId::from_str(v) { - Ok(ChannelFilterMatch::Exact(channel_id)) - } else { - let wildcard = v.parse().map_err(E::custom)?; + let trimmed_v = v.trim(); + if trimmed_v.contains('*') { + let wildcard = trimmed_v.parse().map_err(E::custom)?; Ok(ChannelFilterMatch::Wildcard(wildcard)) + } else { + let channel_id = ChannelId::from_str(trimmed_v.trim()).map_err(E::custom)?; + Ok(ChannelFilterMatch::Exact(channel_id)) } } @@ -430,7 +434,6 @@ pub(crate) mod channel { #[cfg(test)] mod tests { use super::*; - use crate::config::filter::ChannelPolicy; #[test] fn deserialize_packet_filter_policy() { @@ -605,4 +608,21 @@ mod tests { let wildcard = "ica*".parse::().unwrap(); assert_eq!(wildcard.to_string(), "ica*".to_string()); } + + #[test] + fn test_exact_matches() { + let allow_policy = r#" + policy = "allow" + list = [ + [ "transfer", "channel-88", ], # Standard exact match + [ "transfer", "channel-476 ", ], # Whitespace abstraction + ] + "#; + + let pf: ChannelPolicy = + toml::from_str(allow_policy).expect("could not parse filter policy"); + + let assert_allow = matches!(pf, ChannelPolicy::Allow(filters) if filters.is_exact()); + assert!(assert_allow); + } } diff --git a/crates/relayer/src/config/proof_specs.rs b/crates/relayer/src/config/proof_specs.rs index d7c7f80cce..33fa2f8a78 100644 --- a/crates/relayer/src/config/proof_specs.rs +++ b/crates/relayer/src/config/proof_specs.rs @@ -19,7 +19,7 @@ pub fn serialize( struct ProofSpecsVisitor; -impl<'de> de::Visitor<'de> for ProofSpecsVisitor { +impl de::Visitor<'_> for ProofSpecsVisitor { type Value = Option; fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/crates/relayer/src/connection.rs b/crates/relayer/src/connection.rs index 5e1ee140be..7f968bcdcf 100644 --- a/crates/relayer/src/connection.rs +++ b/crates/relayer/src/connection.rs @@ -42,29 +42,29 @@ mod handshake_retry { //! for the connection handshake algorithm. use crate::connection::ConnectionError; - use crate::util::retry::{clamp_total, ConstantGrowth}; + use crate::util::retry::{clamp, ConstantGrowth}; use core::time::Duration; /// Approximate number of retries per block. - const PER_BLOCK_RETRIES: u32 = 10; + const PER_BLOCK_RETRIES: u32 = 5; /// Defines the increment in delay between subsequent retries. /// A value of `0` will make the retry delay constant. - const DELAY_INCREMENT: u64 = 0; + const DELAY_INCREMENT: Duration = Duration::from_secs(0); - /// Maximum retry delay expressed in number of blocks - const BLOCK_NUMBER_DELAY: u32 = 10; + /// Maximum number of retries + const MAX_RETRIES: u32 = 10; /// The default retry strategy. /// We retry with a constant backoff strategy. The strategy is parametrized by the /// maximum block time expressed as a `Duration`. - pub fn default_strategy(max_block_times: Duration) -> impl Iterator { - let retry_delay = max_block_times / PER_BLOCK_RETRIES; + pub fn default_strategy(max_block_time: Duration) -> impl Iterator { + let retry_delay = max_block_time / PER_BLOCK_RETRIES; - clamp_total( - ConstantGrowth::new(retry_delay, Duration::from_secs(DELAY_INCREMENT)), - retry_delay, - max_block_times * BLOCK_NUMBER_DELAY, + clamp( + ConstantGrowth::new(retry_delay, DELAY_INCREMENT), + retry_delay + DELAY_INCREMENT * MAX_RETRIES, + MAX_RETRIES as usize, ) } @@ -1365,7 +1365,9 @@ fn check_destination_connection_state( && existing_connection.counterparty().client_id() == expected_connection.counterparty().client_id(); - let good_state = *existing_connection.state() as u32 <= *expected_connection.state() as u32; + let good_state = existing_connection + .state() + .less_or_equal_progress(*expected_connection.state()); let good_connection_ids = existing_connection.counterparty().connection_id().is_none() || existing_connection.counterparty().connection_id() diff --git a/crates/relayer/src/connection/error.rs b/crates/relayer/src/connection/error.rs index ee017b5cc9..d22c19aea1 100644 --- a/crates/relayer/src/connection/error.rs +++ b/crates/relayer/src/connection/error.rs @@ -112,7 +112,7 @@ define_error! { destination_chain_id: ChainId } |e| { - format!("the source chain of client a ({}) does not not match the destination chain of client b ({})", + format!("the source chain of client a ({}) does not match the destination chain of client b ({})", e.source_chain_id, e.destination_chain_id) }, diff --git a/crates/relayer/src/consensus_state.rs b/crates/relayer/src/consensus_state.rs index c6b6f8114e..500fb3bcef 100644 --- a/crates/relayer/src/consensus_state.rs +++ b/crates/relayer/src/consensus_state.rs @@ -14,39 +14,22 @@ use ibc_relayer_types::core::ics23_commitment::commitment::CommitmentRoot; use ibc_relayer_types::timestamp::Timestamp; use ibc_relayer_types::Height; -#[cfg(test)] -use ibc_proto::ibc::mock::ConsensusState as RawMockConsensusState; -#[cfg(test)] -use ibc_relayer_types::mock::consensus_state::MockConsensusState; -#[cfg(test)] -use ibc_relayer_types::mock::consensus_state::MOCK_CONSENSUS_STATE_TYPE_URL; - #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(tag = "type")] -#[non_exhaustive] pub enum AnyConsensusState { Tendermint(TmConsensusState), - - #[cfg(test)] - Mock(MockConsensusState), } impl AnyConsensusState { pub fn timestamp(&self) -> Timestamp { match self { Self::Tendermint(cs_state) => cs_state.timestamp.into(), - - #[cfg(test)] - Self::Mock(mock_state) => mock_state.timestamp(), } } pub fn client_type(&self) -> ClientType { match self { AnyConsensusState::Tendermint(_cs) => ClientType::Tendermint, - - #[cfg(test)] - AnyConsensusState::Mock(_cs) => ClientType::Mock, } } } @@ -65,12 +48,6 @@ impl TryFrom for AnyConsensusState { .map_err(Error::decode_raw_client_state)?, )), - #[cfg(test)] - MOCK_CONSENSUS_STATE_TYPE_URL => Ok(AnyConsensusState::Mock( - Protobuf::::decode_vec(&value.value) - .map_err(Error::decode_raw_client_state)?, - )), - _ => Err(Error::unknown_consensus_state_type(value.type_url)), } } @@ -83,22 +60,10 @@ impl From for Any { type_url: TENDERMINT_CONSENSUS_STATE_TYPE_URL.to_string(), value: Protobuf::::encode_vec(value), }, - #[cfg(test)] - AnyConsensusState::Mock(value) => Any { - type_url: MOCK_CONSENSUS_STATE_TYPE_URL.to_string(), - value: Protobuf::::encode_vec(value), - }, } } } -#[cfg(test)] -impl From for AnyConsensusState { - fn from(cs: MockConsensusState) -> Self { - Self::Mock(cs) - } -} - impl From for AnyConsensusState { fn from(cs: TmConsensusState) -> Self { Self::Tendermint(cs) @@ -150,9 +115,6 @@ impl ConsensusState for AnyConsensusState { fn root(&self) -> &CommitmentRoot { match self { Self::Tendermint(cs_state) => cs_state.root(), - - #[cfg(test)] - Self::Mock(mock_state) => mock_state.root(), } } diff --git a/crates/relayer/src/error.rs b/crates/relayer/src/error.rs index 2f3a964547..c8ac6d656d 100644 --- a/crates/relayer/src/error.rs +++ b/crates/relayer/src/error.rs @@ -30,6 +30,7 @@ use ibc_relayer_types::clients::ics07_tendermint::error as tendermint_error; use ibc_relayer_types::core::ics02_client::{client_type::ClientType, error as client_error}; use ibc_relayer_types::core::ics03_connection::error as connection_error; use ibc_relayer_types::core::ics23_commitment::error as commitment_error; +use ibc_relayer_types::core::ics24_host::error::ValidationError; use ibc_relayer_types::core::ics24_host::identifier::{ChainId, ChannelId, ConnectionId}; use ibc_relayer_types::proofs::ProofError; @@ -143,6 +144,9 @@ define_error! { EmptyUpgradedClientState |_| { "found no upgraded client state" }, + EmptyConnectionParams + |_| { "connection params not found" }, + ConsensusStateTypeMismatch { expected: ClientType, @@ -390,7 +394,6 @@ define_error! { address: String, endpoint: String, } - [ DisplayOnly ] |e| { format!("failed while fetching version info from endpoint {0} on the gRPC interface of chain {1}:{2}", e.endpoint, e.chain_id, e.address) @@ -494,14 +497,14 @@ define_error! { format!("semantic config validation failed for option `gas_multiplier` of chain '{}', reason: gas multiplier ({}) is smaller than `1.1`, which could trigger gas fee errors in production", e.chain_id, e.gas_multiplier) }, - SdkModuleVersion + CompatCheckFailed { chain_id: ChainId, address: String, cause: String } |e| { - format!("Hermes health check failed while verifying the application compatibility for chain {0}:{1}; caused by: {2}", + format!("compatibility check failed for chain '{0}' at '{1}': {2}", e.chain_id, e.address, e.cause) }, @@ -520,6 +523,10 @@ define_error! { { address: String } |e| { format!("Query/Account RPC returned an empty account for address: {}", e.address) }, + EmptyProposal + { proposal_id: String } + |e| { format!("Query/Proposal RPC returned an empty proposal for proposal id: {}", e.proposal_id) }, + NoHistoricalEntries { chain_id: ChainId } |e| { @@ -585,7 +592,8 @@ define_error! { InvalidCompatMode [ TendermintRpcError ] - |_| { "Invalid CompatMode queried from chain and no `compat_mode` configured in Hermes. This can be fixed by specifying a `compat_mode` in Hermes config.toml" }, + |_| { "Invalid compatibility mode queried from chain and no `compat_mode` configured in Hermes. \ + This can be fixed by specifying a `compat_mode` for chain '{}' in Hermes config.toml" }, HttpRequest [ TraceError ] @@ -599,6 +607,10 @@ define_error! { [ TraceError ] |_| { "HTTP response body error" }, + InvalidHttpHost + { endpoint: String } + |e| { format!("HTTP host is invalid for the endpoint `{}`", e.endpoint) }, + JsonDeserialize [ TraceError ] |_| { "JSON deserialization error" }, @@ -618,6 +630,18 @@ define_error! { Base64Decode [ TraceError ] |_| { "Error decoding base64-encoded data" }, + + InvalidPortString + { port: String } + |e| { format!("invalid port string {}", e.port) }, + + InvalidChannelString + { channel: String } + |e| { format!("invalid channel string {}", e.channel) }, + + Ics24HostValidationError + [ ValidationError ] + |_| { "ICS24 host validation error" }, } } @@ -709,6 +733,14 @@ impl GrpcStatusSubdetail { Some((expected, got)) => expected < got, } } + + /// Check whether this gRPC error message contains the string "invalid empty tx". + /// + /// ## Note + /// This error may happen for older chains that does not properly support simulation. + pub fn is_empty_tx_error(&self) -> bool { + self.status.message().contains("invalid empty tx") + } } /// Assumes that the cosmos-sdk account sequence mismatch error message, that may be seen diff --git a/crates/relayer/src/event.rs b/crates/relayer/src/event.rs index 401a2b5ecd..f5219f4750 100644 --- a/crates/relayer/src/event.rs +++ b/crates/relayer/src/event.rs @@ -1,27 +1,37 @@ use core::fmt::{Display, Error as FmtError, Formatter}; use serde::Serialize; +use std::str::FromStr; +use subtle_encoding::hex; use tendermint::abci::Event as AbciEvent; use ibc_relayer_types::{ - applications::ics29_fee::events::{DistributeFeePacket, IncentivizedPacket}, - applications::ics31_icq::events::CrossChainQueryPacket, - core::ics02_client::{ - error::Error as ClientError, - events::{self as client_events, Attributes as ClientAttributes, HEADER_ATTRIBUTE_KEY}, - header::{decode_header, AnyHeader}, - height::HeightErrorDetail, + applications::{ + ics29_fee::events::{DistributeFeePacket, IncentivizedPacket}, + ics31_icq::events::CrossChainQueryPacket, }, - core::ics03_connection::{ - error::Error as ConnectionError, - events::{self as connection_events, Attributes as ConnectionAttributes}, - }, - core::ics04_channel::{ - error::Error as ChannelError, - events::{self as channel_events, Attributes as ChannelAttributes}, - packet::Packet, - timeout::TimeoutHeight, + core::{ + ics02_client::{ + error::Error as ClientError, + events::{self as client_events, Attributes as ClientAttributes, HEADER_ATTRIBUTE_KEY}, + header::{decode_header, AnyHeader}, + height::HeightErrorDetail, + }, + ics03_connection::{ + error::Error as ConnectionError, + events::{self as connection_events, Attributes as ConnectionAttributes}, + }, + ics04_channel::{ + error::Error as ChannelError, + events::{ + self as channel_events, Attributes as ChannelAttributes, + UpgradeAttributes as ChannelUpgradeAttributes, + }, + packet::{Packet, Sequence}, + timeout::TimeoutHeight, + }, }, events::{Error as IbcEventError, IbcEvent, IbcEventType}, + timestamp::Timestamp, Height, }; @@ -108,6 +118,34 @@ pub fn ibc_event_try_from_abci_event(abci_event: &AbciEvent) -> Result Ok(IbcEvent::UpgradeInitChannel( + channel_upgrade_init_try_from_abci_event(abci_event).map_err(IbcEventError::channel)?, + )), + Ok(IbcEventType::UpgradeTryChannel) => Ok(IbcEvent::UpgradeTryChannel( + channel_upgrade_try_try_from_abci_event(abci_event).map_err(IbcEventError::channel)?, + )), + Ok(IbcEventType::UpgradeAckChannel) => Ok(IbcEvent::UpgradeAckChannel( + channel_upgrade_ack_try_from_abci_event(abci_event).map_err(IbcEventError::channel)?, + )), + Ok(IbcEventType::UpgradeConfirmChannel) => Ok(IbcEvent::UpgradeConfirmChannel( + channel_upgrade_confirm_try_from_abci_event(abci_event) + .map_err(IbcEventError::channel)?, + )), + Ok(IbcEventType::UpgradeOpenChannel) => Ok(IbcEvent::UpgradeOpenChannel( + channel_upgrade_open_try_from_abci_event(abci_event).map_err(IbcEventError::channel)?, + )), + Ok(IbcEventType::UpgradeCancelChannel) => Ok(IbcEvent::UpgradeCancelChannel( + channel_upgrade_cancelled_try_from_abci_event(abci_event) + .map_err(IbcEventError::channel)?, + )), + Ok(IbcEventType::UpgradeTimeoutChannel) => Ok(IbcEvent::UpgradeTimeoutChannel( + channel_upgrade_timeout_try_from_abci_event(abci_event) + .map_err(IbcEventError::channel)?, + )), + Ok(IbcEventType::UpgradeErrorChannel) => Ok(IbcEvent::UpgradeErrorChannel( + channel_upgrade_error_try_from_abci_event(abci_event) + .map_err(IbcEventError::channel)?, + )), Ok(IbcEventType::SendPacket) => Ok(IbcEvent::SendPacket( send_packet_try_from_abci_event(abci_event).map_err(IbcEventError::channel)?, )), @@ -249,6 +287,86 @@ pub fn channel_close_confirm_try_from_abci_event( } } +pub fn channel_upgrade_init_try_from_abci_event( + abci_event: &AbciEvent, +) -> Result { + match channel_upgrade_extract_attributes_from_tx(abci_event) { + Ok(attrs) => channel_events::UpgradeInit::try_from(attrs) + .map_err(|_| ChannelError::implementation_specific()), + Err(e) => Err(e), + } +} + +pub fn channel_upgrade_try_try_from_abci_event( + abci_event: &AbciEvent, +) -> Result { + match channel_upgrade_extract_attributes_from_tx(abci_event) { + Ok(attrs) => channel_events::UpgradeTry::try_from(attrs) + .map_err(|_| ChannelError::implementation_specific()), + Err(e) => Err(e), + } +} + +pub fn channel_upgrade_ack_try_from_abci_event( + abci_event: &AbciEvent, +) -> Result { + match channel_upgrade_extract_attributes_from_tx(abci_event) { + Ok(attrs) => channel_events::UpgradeAck::try_from(attrs) + .map_err(|_| ChannelError::implementation_specific()), + Err(e) => Err(e), + } +} + +pub fn channel_upgrade_confirm_try_from_abci_event( + abci_event: &AbciEvent, +) -> Result { + match channel_upgrade_extract_attributes_from_tx(abci_event) { + Ok(attrs) => channel_events::UpgradeConfirm::try_from(attrs) + .map_err(|_| ChannelError::implementation_specific()), + Err(e) => Err(e), + } +} + +pub fn channel_upgrade_open_try_from_abci_event( + abci_event: &AbciEvent, +) -> Result { + match channel_upgrade_extract_attributes_from_tx(abci_event) { + Ok(attrs) => channel_events::UpgradeOpen::try_from(attrs) + .map_err(|_| ChannelError::implementation_specific()), + Err(e) => Err(e), + } +} + +pub fn channel_upgrade_cancelled_try_from_abci_event( + abci_event: &AbciEvent, +) -> Result { + match channel_upgrade_extract_attributes_from_tx(abci_event) { + Ok(attrs) => channel_events::UpgradeCancel::try_from(attrs) + .map_err(|_| ChannelError::implementation_specific()), + Err(e) => Err(e), + } +} + +pub fn channel_upgrade_timeout_try_from_abci_event( + abci_event: &AbciEvent, +) -> Result { + match channel_upgrade_extract_attributes_from_tx(abci_event) { + Ok(attrs) => channel_events::UpgradeTimeout::try_from(attrs) + .map_err(|_| ChannelError::implementation_specific()), + Err(e) => Err(e), + } +} + +pub fn channel_upgrade_error_try_from_abci_event( + abci_event: &AbciEvent, +) -> Result { + match channel_upgrade_extract_attributes_from_tx(abci_event) { + Ok(attrs) => channel_events::UpgradeError::try_from(attrs) + .map_err(|_| ChannelError::implementation_specific()), + Err(e) => Err(e), + } +} + pub fn send_packet_try_from_abci_event( abci_event: &AbciEvent, ) -> Result { @@ -300,8 +418,14 @@ fn client_extract_attributes_from_tx(event: &AbciEvent) -> Result { attr.client_id = value @@ -327,9 +451,13 @@ fn client_extract_attributes_from_tx(event: &AbciEvent) -> Result Result { for tag in &event.attributes { - if tag.key == HEADER_ATTRIBUTE_KEY { - let header_bytes = - hex::decode(&tag.value).map_err(|_| ClientError::malformed_header())?; + if tag.key_bytes() == HEADER_ATTRIBUTE_KEY.as_bytes() { + let header_bytes = hex::decode( + tag.value_str() + .map_err(|_| ClientError::malformed_header())? + .to_lowercase(), + ) + .map_err(|_| ClientError::malformed_header())?; return decode_header(&header_bytes); } } @@ -343,8 +471,14 @@ fn connection_extract_attributes_from_tx( let mut attr = ConnectionAttributes::default(); for tag in &event.attributes { - let key = tag.key.as_str(); - let value = tag.value.as_str(); + let key = tag + .key_str() + .map_err(|_| ConnectionError::malformed_event_attribute_key())?; + + let value = tag + .value_str() + .map_err(|_| ConnectionError::malformed_event_attribute_value(key.to_owned()))?; + match key { connection_events::CONN_ID_ATTRIBUTE_KEY => { attr.connection_id = value.parse().ok(); @@ -372,8 +506,14 @@ fn channel_extract_attributes_from_tx( let mut attr = ChannelAttributes::default(); for tag in &event.attributes { - let key = tag.key.as_str(); - let value = tag.value.as_str(); + let key = tag + .key_str() + .map_err(|_| ChannelError::malformed_event_attribute_key())?; + + let value = tag + .value_str() + .map_err(|_| ChannelError::malformed_event_attribute_value(key.to_owned()))?; + match key { channel_events::PORT_ID_ATTRIBUTE_KEY => { attr.port_id = value.parse().map_err(ChannelError::identifier)? @@ -397,14 +537,73 @@ fn channel_extract_attributes_from_tx( Ok(attr) } +fn channel_upgrade_extract_attributes_from_tx( + event: &AbciEvent, +) -> Result { + let mut attr = ChannelUpgradeAttributes::default(); + + for tag in &event.attributes { + let key = tag + .key_str() + .map_err(|_| ChannelError::malformed_event_attribute_key())?; + + let value = tag + .value_str() + .map_err(|_| ChannelError::malformed_event_attribute_value(key.to_owned()))?; + + match key { + channel_events::PORT_ID_ATTRIBUTE_KEY => { + attr.port_id = value.parse().map_err(ChannelError::identifier)? + } + channel_events::CHANNEL_ID_ATTRIBUTE_KEY => { + attr.channel_id = value.parse().map_err(ChannelError::identifier)?; + } + channel_events::COUNTERPARTY_PORT_ID_ATTRIBUTE_KEY => { + attr.counterparty_port_id = value.parse().map_err(ChannelError::identifier)?; + } + channel_events::COUNTERPARTY_CHANNEL_ID_ATTRIBUTE_KEY => { + attr.counterparty_channel_id = value.parse().ok(); + } + channel_events::UPGRADE_SEQUENCE => { + attr.upgrade_sequence = + Sequence::from(value.parse::().map_err(|e| { + ChannelError::invalid_string_as_sequence(value.to_string(), e) + })?); + } + channel_events::UPGRADE_TIMEOUT_HEIGHT => { + let maybe_height = Height::from_str(value).ok(); + attr.upgrade_timeout_height = maybe_height; + } + channel_events::UPGRADE_TIMEOUT_TIMESTAMP => { + let maybe_timestamp = Timestamp::from_str(value).ok(); + attr.upgrade_timeout_timestamp = maybe_timestamp; + } + channel_events::UPGRADE_ERROR_RECEIPT => { + let maybe_error_receipt = value.to_string(); + attr.error_receipt = Some(maybe_error_receipt); + } + _ => {} + } + } + + Ok(attr) +} + pub fn extract_packet_and_write_ack_from_tx( event: &AbciEvent, ) -> Result<(Packet, Vec), ChannelError> { let mut packet = Packet::default(); let mut write_ack: Vec = Vec::new(); + for tag in &event.attributes { - let key = tag.key.as_str(); - let value = tag.value.as_str(); + let key = tag + .key_str() + .map_err(|_| ChannelError::malformed_event_attribute_key())?; + + let value = tag + .value_str() + .map_err(|_| ChannelError::malformed_event_attribute_value(key.to_owned()))?; + match key { channel_events::PKT_SRC_PORT_ATTRIBUTE_KEY => { packet.source_port = value.parse().map_err(ChannelError::identifier)?; @@ -431,10 +630,12 @@ pub fn extract_packet_and_write_ack_from_tx( packet.timeout_timestamp = value.parse().unwrap(); } channel_events::PKT_DATA_ATTRIBUTE_KEY => { - packet.data = Vec::from(value.as_bytes()); + packet.data = hex::decode(value.to_lowercase()) + .map_err(|_| ChannelError::invalid_packet_data(value.to_string()))?; } channel_events::PKT_ACK_ATTRIBUTE_KEY => { - write_ack = Vec::from(value.as_bytes()); + write_ack = hex::decode(value.to_lowercase()) + .map_err(|_| ChannelError::invalid_packet_ack(value.to_string()))?; } _ => {} } @@ -461,23 +662,6 @@ pub fn parse_timeout_height(s: &str) -> Result { mod tests { use super::*; - use ibc_proto::google::protobuf::Any; - use ibc_proto::Protobuf; - use ibc_relayer_types::clients::ics07_tendermint::header::test_util::get_dummy_ics07_header; - use ibc_relayer_types::core::ics02_client::header::{decode_header, AnyHeader}; - - #[test] - fn extract_header() { - let header = get_dummy_ics07_header(); - let mut header_bytes = Vec::new(); - Protobuf::::encode(header.clone(), &mut header_bytes).unwrap(); - - let decoded_dyn_header = decode_header(&header_bytes).unwrap(); - let AnyHeader::Tendermint(decoded_tm_header) = decoded_dyn_header; - - assert_eq!(header, decoded_tm_header); - } - #[test] fn connection_event_to_abci_event() { let attributes = ConnectionAttributes { diff --git a/crates/relayer/src/event/source.rs b/crates/relayer/src/event/source.rs index 49e76441e8..c114ac5e51 100644 --- a/crates/relayer/src/event/source.rs +++ b/crates/relayer/src/event/source.rs @@ -47,9 +47,11 @@ impl EventSource { chain_id: ChainId, rpc_client: HttpClient, poll_interval: Duration, + max_retries: u32, rt: Arc, ) -> Result<(Self, TxEventSourceCmd)> { - let (source, tx) = rpc::EventSource::new(chain_id, rpc_client, poll_interval, rt)?; + let (source, tx) = + rpc::EventSource::new(chain_id, rpc_client, poll_interval, max_retries, rt)?; Ok((Self::Rpc(source), tx)) } diff --git a/crates/relayer/src/event/source/rpc.rs b/crates/relayer/src/event/source/rpc.rs index b684cc6590..db64e2d111 100644 --- a/crates/relayer/src/event/source/rpc.rs +++ b/crates/relayer/src/event/source/rpc.rs @@ -23,7 +23,7 @@ use ibc_relayer_types::{ use crate::{ chain::tracking::TrackingId, - event::{bus::EventBus, source::Error, IbcEventWithHeight}, + event::{bus::EventBus, error::ErrorDetail, source::Error, IbcEventWithHeight}, telemetry, util::retry::ConstantGrowth, }; @@ -45,6 +45,9 @@ pub struct EventSource { /// Poll interval poll_interval: Duration, + /// Max retries to collect events + max_retries: u32, + /// Event bus for broadcasting events event_bus: EventBus>>, @@ -63,6 +66,7 @@ impl EventSource { chain_id: ChainId, rpc_client: HttpClient, poll_interval: Duration, + max_retries: u32, rt: Arc, ) -> Result<(Self, TxEventSourceCmd)> { let event_bus = EventBus::new(); @@ -73,6 +77,7 @@ impl EventSource { chain_id, rpc_client, poll_interval, + max_retries, event_bus, rx_cmd, last_fetched_height: BlockHeight::from(0_u32), @@ -203,19 +208,38 @@ impl EventSource { for height in heights { trace!("collecting events at height {height}"); - let result = collect_events(&self.rpc_client, &self.chain_id, height).await; + let mut attempts = 0; + let mut backoff = retries_backoff(self.max_retries); + + // NOTE: Even if we failed to collect events after max retries, + // we still need to update to move on next block + self.last_fetched_height = height; - match result { - Ok(batch) => { - self.last_fetched_height = height; + loop { + attempts += 1; - if let Some(batch) = batch { - batches.push(batch); + match collect_events(&self.rpc_client, &self.chain_id, height).await { + Ok(batch) => { + if let Some(batch) = batch { + batches.push(batch); + } + break; } - } - Err(e) => { - error!(%height, "failed to collect events: {e}"); - break; + Err(e) => match e.detail() { + ErrorDetail::Rpc(_) if attempts < self.max_retries => { + let delay = backoff.next().expect( + "backoff has attempted to make more iterates than is expected", + ); + + error!(%height, "failed to collect events: {e}, retrying in {delay:?}..."); + sleep(delay).await; + } + + _ => { + error!(%height, "failed to collect events after {attempts} attempts: {e}"); + break; + } + }, } } } @@ -244,6 +268,11 @@ fn poll_backoff(poll_interval: Duration) -> impl Iterator { .clamp(poll_interval * 5, usize::MAX) } +fn retries_backoff(collect_retries: u32) -> impl Iterator { + ConstantGrowth::new(Duration::from_secs(1), Duration::from_millis(500)) + .clamp(Duration::from_secs(4), collect_retries as usize) +} + fn dedupe(events: Vec) -> Vec { use itertools::Itertools; use std::hash::{Hash, Hasher}; @@ -263,7 +292,9 @@ fn dedupe(events: Vec) -> Vec { .attributes .iter() .zip(other.0.attributes.iter()) - .all(|(a, b)| a.key == b.key && a.value == b.value) + .all(|(a, b)| { + a.key_bytes() == b.key_bytes() && a.value_bytes() == b.value_bytes() + }) } } @@ -275,8 +306,8 @@ fn dedupe(events: Vec) -> Vec { for attr in &self.0.attributes { // NOTE: We don't hash the index because it is not deterministic - attr.key.hash(state); - attr.value.hash(state); + attr.key_bytes().hash(state); + attr.value_bytes().hash(state); } } } @@ -350,6 +381,8 @@ async fn fetch_all_events( events.append(end_block_events); } + events.append(&mut response.finalize_block_events); + Ok(events) } diff --git a/crates/relayer/src/event/source/rpc/extract.rs b/crates/relayer/src/event/source/rpc/extract.rs index 7df189cd38..819194c4b0 100644 --- a/crates/relayer/src/event/source/rpc/extract.rs +++ b/crates/relayer/src/event/source/rpc/extract.rs @@ -1,6 +1,6 @@ -use ibc_relayer_types::applications::ics29_fee::events::DistributionType; use tendermint::abci; +use ibc_relayer_types::applications::ics29_fee::events::DistributionType; use ibc_relayer_types::core::ics02_client::height::Height; use ibc_relayer_types::core::ics24_host::identifier::ChainId; use ibc_relayer_types::events::IbcEvent; diff --git a/crates/relayer/src/event/source/websocket.rs b/crates/relayer/src/event/source/websocket.rs index 7993440267..de5194031e 100644 --- a/crates/relayer/src/event/source/websocket.rs +++ b/crates/relayer/src/event/source/websocket.rs @@ -131,7 +131,7 @@ impl EventSource { rx_cmd, ws_url, rpc_compat, - subscriptions: Box::new(futures::stream::empty()), + subscriptions: Box::new(stream::empty()), }; Ok((source, TxEventSourceCmd(tx_cmd))) @@ -297,8 +297,7 @@ impl EventSource { async fn run_loop(&mut self) -> Next { // Take ownership of the subscriptions - let subscriptions = - core::mem::replace(&mut self.subscriptions, Box::new(futures::stream::empty())); + let subscriptions = core::mem::replace(&mut self.subscriptions, Box::new(stream::empty())); // Convert the stream of RPC events into a stream of event batches. let batches = stream_batches(subscriptions, self.chain_id.clone(), self.batch_delay); diff --git a/crates/relayer/src/event/source/websocket/extract.rs b/crates/relayer/src/event/source/websocket/extract.rs index 18f6bfa07a..ddc692054d 100644 --- a/crates/relayer/src/event/source/websocket/extract.rs +++ b/crates/relayer/src/event/source/websocket/extract.rs @@ -1,7 +1,7 @@ use alloc::collections::BTreeMap as HashMap; -use core::convert::TryFrom; use ibc_relayer_types::applications::ics29_fee::events::DistributionType; +use ibc_relayer_types::applications::ics31_icq; use tendermint_rpc::{event::Event as RpcEvent, event::EventData as RpcEventData}; use ibc_relayer_types::applications::ics31_icq::events::CrossChainQueryPacket; @@ -235,6 +235,12 @@ fn event_is_type_channel(ev: &IbcEvent) -> bool { | IbcEvent::OpenConfirmChannel(_) | IbcEvent::CloseInitChannel(_) | IbcEvent::CloseConfirmChannel(_) + | IbcEvent::UpgradeInitChannel(_) + | IbcEvent::UpgradeTryChannel(_) + | IbcEvent::UpgradeAckChannel(_) + | IbcEvent::UpgradeConfirmChannel(_) + | IbcEvent::UpgradeOpenChannel(_) + | IbcEvent::UpgradeErrorChannel(_) | IbcEvent::SendPacket(_) | IbcEvent::ReceivePacket(_) | IbcEvent::WriteAcknowledgement(_) @@ -314,9 +320,14 @@ fn extract_block_events( extract_events(height, block_events, "channel_open_confirm", "channel_id"), height, ); + append_events::( + &mut events, + extract_events(height, block_events, "channel_upgrade_init", "channel_id"), + height, + ); append_events::( &mut events, - extract_events(height, block_events, "send_packet", "packet_data"), + extract_events(height, block_events, "send_packet", "packet_data_hex"), height, ); append_events::( @@ -329,10 +340,17 @@ fn extract_block_events( extract_events(height, block_events, "channel_close_confirm", "channel_id"), height, ); - // extract cross chain query event from block_events - if let Ok(ccq) = CrossChainQueryPacket::extract_query_event(block_events) { - events.push(IbcEventWithHeight::new(ccq, height)); - } + + append_events::( + &mut events, + extract_events( + height, + block_events, + ics31_icq::events::EVENT_TYPE_PREFIX, + "query_id", + ), + height, + ); events } diff --git a/crates/relayer/src/extension_options.rs b/crates/relayer/src/extension_options.rs index b796a5cbbe..f5eda5c08c 100644 --- a/crates/relayer/src/extension_options.rs +++ b/crates/relayer/src/extension_options.rs @@ -9,7 +9,7 @@ use crate::error::Error; #[derive(Clone, PartialEq, Eq, Message, Serialize, Deserialize)] pub struct ExtensionOptionDynamicFeeTx { #[prost(string, tag = "1")] - pub max_priority_price: ::prost::alloc::string::String, + pub max_priority_price: String, } impl ExtensionOptionDynamicFeeTx { diff --git a/crates/relayer/src/foreign_client.rs b/crates/relayer/src/foreign_client.rs index 46268b94d4..1120ee2dda 100644 --- a/crates/relayer/src/foreign_client.rs +++ b/crates/relayer/src/foreign_client.rs @@ -9,6 +9,7 @@ use std::thread; use std::time::Instant; use ibc_proto::google::protobuf::Any; +use ibc_relayer_types::applications::ics28_ccv::msgs::ConsumerId; use itertools::Itertools; use tracing::{debug, error, info, instrument, trace, warn}; @@ -365,7 +366,7 @@ pub enum ConsensusStateTrusted { NotTrusted { elapsed: Duration, network_timestamp: Timestamp, - consensus_state_timestmap: Timestamp, + consensus_state_timestamp: Timestamp, }, Trusted { elapsed: Duration, @@ -767,12 +768,12 @@ impl ForeignClient { error!( latest_height = %client_state.latest_height(), - network_timestmap = %network_timestamp, - consensus_state_timestamp = %consensus_state_timestmap, + network_timestamp = %network_timestamp, + consensus_state_timestamp = %consensus_state_timestamp, elapsed = ?elapsed, "client state is not valid: latest height is outside of trusting period!", ); @@ -829,7 +830,7 @@ impl ForeignClient ForeignClient ForeignClient ForeignClient, ) -> Result, ForeignClientError> { + crate::time!( + "build_update_client_with_trusted", + { + "src_chain": self.src_chain().id(), + "dst_chain": self.dst_chain().id(), + } + ); // Get the latest client state on destination. let (client_state, _) = self.validated_client_state()?; @@ -1229,14 +1237,14 @@ impl ForeignClient ForeignClient Some(tm_misbehaviour.clone()), - #[cfg(test)] - _ => None, } .ok_or_else(|| { ForeignClientError::misbehaviour_desc(format!( @@ -1781,13 +1787,24 @@ impl ForeignClient { + msgs.push( + MsgSubmitIcsConsumerMisbehaviour { + submitter: signer.clone(), + misbehaviour: tm_misbehaviour, + consumer_id, + } + .to_any(), + ); } - .to_any(), - ); + Err(e) => { + error!( + "cannot build CCV misbehaviour evidence: failed to fetch CCV consumer id for client {}: {}", + self.id, e + ); + } + } } msgs.push( @@ -1926,3 +1943,21 @@ pub fn extract_client_id(event: &IbcEvent) -> Result<&ClientId, ForeignClientErr )), } } + +pub fn fetch_ccv_consumer_id( + provider: &impl ChainHandle, + client_id: &ClientId, +) -> Result { + let consumer_id = provider.query_ccv_consumer_id(client_id).map_err(|e| { + ForeignClientError::misbehaviour( + format!( + "failed to query CCV consumer id corresponding to client {} from provider {}", + client_id, + provider.id() + ), + e, + ) + })?; + + Ok(consumer_id) +} diff --git a/crates/relayer/src/keyring/any_signing_key_pair.rs b/crates/relayer/src/keyring/any_signing_key_pair.rs index b9dd880c10..f6aa27bd0b 100644 --- a/crates/relayer/src/keyring/any_signing_key_pair.rs +++ b/crates/relayer/src/keyring/any_signing_key_pair.rs @@ -30,7 +30,7 @@ impl AnySigningKeyPair { Self::Ed25519(key_pair) => key_pair.as_any(), } .downcast_ref::() - .map(T::clone) + .cloned() } } diff --git a/crates/relayer/src/lib.rs b/crates/relayer/src/lib.rs index 64173df993..48ed4cf9b1 100644 --- a/crates/relayer/src/lib.rs +++ b/crates/relayer/src/lib.rs @@ -3,7 +3,6 @@ trivial_casts, trivial_numeric_casts, unused_import_braces, - unused_qualifications, rust_2018_idioms )] #![allow(clippy::too_many_arguments)] @@ -15,7 +14,7 @@ //! //! For the IBC relayer binary, please see [Hermes] (`ibc-relayer-cli` crate). //! -//! [Hermes]: https://docs.rs/ibc-relayer-cli/1.8.0/ +//! [Hermes]: https://docs.rs/ibc-relayer-cli/1.10.5/ extern crate alloc; @@ -48,3 +47,5 @@ pub mod transfer; pub mod upgrade_chain; pub mod util; pub mod worker; + +pub const HERMES_VERSION: &str = "1.10.5"; diff --git a/crates/relayer/src/light_client/tendermint.rs b/crates/relayer/src/light_client/tendermint.rs index 1927b0558e..808c616235 100644 --- a/crates/relayer/src/light_client/tendermint.rs +++ b/crates/relayer/src/light_client/tendermint.rs @@ -27,15 +27,12 @@ use ibc_relayer_types::core::ics02_client::header::AnyHeader; use ibc_relayer_types::core::ics24_host::identifier::ChainId; use ibc_relayer_types::Height as ICSHeight; -#[cfg(test)] -use ibc_relayer_types::core::ics02_client::client_type::ClientType; - use crate::{ - chain::cosmos::config::CosmosSdkConfig, - chain::cosmos::CosmosSdkChain, + chain::cosmos::{config::CosmosSdkConfig, CosmosSdkChain}, client_state::AnyClientState, error::Error, misbehaviour::{AnyMisbehaviour, MisbehaviourEvidence}, + HERMES_VERSION, }; use super::{ @@ -58,6 +55,12 @@ impl super::LightClient for LightClient { client_state: &AnyClientState, now: Time, ) -> Result, Error> { + crate::time!( + "light_client.tendermint.header_and_minimal_set", + { + "src_chain": self.chain_id.to_string(), + } + ); let Verified { target, supporting } = self.verify(trusted_height, target_height, client_state, now)?; @@ -84,6 +87,12 @@ impl super::LightClient for LightClient { client_state: &AnyClientState, now: Time, ) -> Result, Error> { + crate::time!( + "light_client.tendermint.verify", + { + "src_chain": self.chain_id.to_string(), + } + ); trace!(%trusted_height, %target_height, "light client verification"); if !self.enable_verification { @@ -150,12 +159,6 @@ impl super::LightClient for LightClient { let client_state = match client_state { AnyClientState::Tendermint(client_state) => Ok(client_state), - - #[cfg(test)] - _ => Err(Error::misbehaviour(format!( - "client type incompatible for chain {}", - self.chain_id - ))), }?; let next_validators = self @@ -264,7 +267,10 @@ fn io_for_addr( peer_id: PeerId, timeout: Option, ) -> Result { - let rpc_client = rpc::HttpClient::new(addr.clone()).map_err(|e| Error::rpc(addr.clone(), e))?; + let rpc_client = rpc::HttpClient::builder(addr.clone().try_into().unwrap()) + .user_agent(format!("hermes/{}", HERMES_VERSION)) + .build() + .map_err(|e| Error::rpc(addr.clone(), e))?; Ok(ProdIo::new(peer_id, rpc_client, timeout)) } @@ -317,12 +323,6 @@ impl LightClient { let client_state = match client_state { AnyClientState::Tendermint(client_state) => Ok(client_state), - - #[cfg(test)] - _ => Err(Error::client_type_mismatch( - ClientType::Tendermint, - client_state.client_type(), - )), }?; Ok(TmLightClient::new( diff --git a/crates/relayer/src/link.rs b/crates/relayer/src/link.rs index 4c0fc849b2..3d87499480 100644 --- a/crates/relayer/src/link.rs +++ b/crates/relayer/src/link.rs @@ -1,6 +1,8 @@ use ibc_relayer_types::core::{ ics03_connection::connection::State as ConnectionState, ics04_channel::channel::State as ChannelState, + ics04_channel::channel::UpgradeState, + ics04_channel::packet::Sequence, ics24_host::identifier::{ChannelId, PortChannelId, PortId}, }; use tracing::info; @@ -38,6 +40,7 @@ pub struct LinkParameters { pub src_channel_id: ChannelId, pub max_memo_size: Ics20FieldSizeLimit, pub max_receiver_size: Ics20FieldSizeLimit, + pub exclude_src_sequences: Vec, } pub struct Link { @@ -83,7 +86,10 @@ impl Link { ) })?; - if !a_channel.state_matches(&ChannelState::Open) + if !a_channel.state_matches(&ChannelState::Open(UpgradeState::NotUpgrading)) + && !a_channel.state_matches(&ChannelState::Open(UpgradeState::Upgrading)) + && !a_channel.state_matches(&ChannelState::Flushing) + && !a_channel.state_matches(&ChannelState::FlushComplete) && !a_channel.state_matches(&ChannelState::Closed) { return Err(LinkError::invalid_channel_state( @@ -177,31 +183,4 @@ impl Link { Link::new(channel, with_tx_confirmation, opts) } - - /// Constructs a link around the channel that is reverse to the channel - /// in this link. - pub fn reverse( - &self, - with_tx_confirmation: bool, - auto_register_counterparty_payee: bool, - ) -> Result, LinkError> { - let opts = LinkParameters { - src_port_id: self.a_to_b.dst_port_id().clone(), - src_channel_id: self.a_to_b.dst_channel_id().clone(), - max_memo_size: self.a_to_b.max_memo_size, - max_receiver_size: self.a_to_b.max_receiver_size, - }; - let chain_b = self.a_to_b.dst_chain().clone(); - let chain_a = self.a_to_b.src_chain().clone(); - - // Some of the checks and initializations may be redundant; - // going slowly, but reliably. - Link::new_from_opts( - chain_b, - chain_a, - opts, - with_tx_confirmation, - auto_register_counterparty_payee, - ) - } } diff --git a/crates/relayer/src/link/cli.rs b/crates/relayer/src/link/cli.rs index d5f896cc6e..f07cd39e23 100644 --- a/crates/relayer/src/link/cli.rs +++ b/crates/relayer/src/link/cli.rs @@ -1,4 +1,3 @@ -use std::convert::TryInto; use std::ops::RangeInclusive; use std::thread; use std::time::{Duration, Instant}; @@ -12,7 +11,7 @@ use ibc_relayer_types::Height; use crate::chain::counterparty::{unreceived_acknowledgements, unreceived_packets}; use crate::chain::handle::ChainHandle; -use crate::chain::requests::Qualified; +use crate::chain::requests::{Paginate, Qualified}; use crate::chain::tracking::TrackingId; use crate::error::Error; use crate::event::IbcEventWithHeight; @@ -98,6 +97,7 @@ impl Link { self.a_to_b.dst_chain(), self.a_to_b.src_chain(), &self.a_to_b.path_id, + Paginate::All, ) .map_err(LinkError::supervisor)?; @@ -110,10 +110,16 @@ impl Link { sequences.retain(|seq| sequence_filter.iter().any(|range| range.contains(seq))); } + // Retain only sequences which should not be filtered out + let raw_sequences: Vec = sequences + .into_iter() + .filter(|sequence| !self.a_to_b.exclude_src_sequences.contains(sequence)) + .collect(); + info!( "{} unreceived packets found: {} ", - sequences.len(), - PrettySlice(&sequences) + raw_sequences.len(), + PrettySlice(&raw_sequences) ); let query_height = match packet_data_query_height { @@ -128,7 +134,7 @@ impl Link { .map_or(50, |cfg| cfg.query_packets_chunk_size()); self.relay_packet_messages( - sequences, + raw_sequences, query_height, chunk_size, query_send_packet_events, @@ -163,6 +169,7 @@ impl Link { self.a_to_b.dst_chain(), self.a_to_b.src_chain(), &self.a_to_b.path_id, + Paginate::All, ) .map_err(LinkError::supervisor)? else { @@ -178,10 +185,16 @@ impl Link { sequences.retain(|seq| sequence_filter.iter().any(|range| range.contains(seq))); } + // Retain only sequences which should not be filtered out + let raw_sequences: Vec = sequences + .into_iter() + .filter(|sequence| !self.a_to_b.exclude_src_sequences.contains(sequence)) + .collect(); + info!( "{} unreceived acknowledgements found: {} ", - sequences.len(), - sequences.iter().copied().collated().format(", "), + raw_sequences.len(), + raw_sequences.iter().copied().collated().format(", "), ); let query_height = match packet_data_query_height { @@ -196,7 +209,7 @@ impl Link { .map_or(50, |cfg| cfg.query_packets_chunk_size()); self.relay_packet_messages( - sequences, + raw_sequences, query_height, chunk_size, query_write_ack_events, diff --git a/crates/relayer/src/link/error.rs b/crates/relayer/src/link/error.rs index adf8142ec8..694bc22f70 100644 --- a/crates/relayer/src/link/error.rs +++ b/crates/relayer/src/link/error.rs @@ -73,7 +73,7 @@ define_error! { Send { event: IbcEvent } |e| { - format!("chain error when sending messages: {0}", e.event) + format!("failed to send message: {0}", e.event) }, MissingChannelId diff --git a/crates/relayer/src/link/operational_data.rs b/crates/relayer/src/link/operational_data.rs index 5c5315b09a..38d8495119 100644 --- a/crates/relayer/src/link/operational_data.rs +++ b/crates/relayer/src/link/operational_data.rs @@ -2,9 +2,9 @@ use core::fmt::{Display, Error as FmtError, Formatter}; use std::ops::Add; use std::time::{Duration, Instant}; -use ibc_proto::google::protobuf::Any; use tracing::{debug, info}; +use ibc_proto::google::protobuf::Any; use ibc_relayer_types::core::ics02_client::client_state::ClientState; use ibc_relayer_types::Height; diff --git a/crates/relayer/src/link/packet_events.rs b/crates/relayer/src/link/packet_events.rs index a1e78ad980..0d105ed645 100644 --- a/crates/relayer/src/link/packet_events.rs +++ b/crates/relayer/src/link/packet_events.rs @@ -41,14 +41,21 @@ where Ok(events) => { events_left -= chunk.len(); - info!( - events.total = %events_total, - events.left = %events_left, - "pulled packet data for {} events out of {} sequences: {};", - events.len(), - chunk.len(), - chunk.iter().copied().collated().format(", "), - ); + if events.is_empty() && !chunk.is_empty() { + warn!("no packet data was pulled at height {query_height} for sequences {}, this might be due to the data not being available on the configured endpoint. \ + Please verify that the RPC endpoint has the required packet data, for more details see https://hermes.informal.systems/advanced/troubleshooting/cross-comp-config.html#uncleared-pending-packets", + chunk.iter().copied().collated().format(", ")); + } else { + info!( + events.total = %events_total, + events.left = %events_left, + "pulled packet data for {} out of {} events: {}", + events.len(), + chunk.len(), + chunk.iter().copied().collated().format(", "), + ); + } + // Because we use the first event height to do the client update, // if the heights of the events differ, we get proof verification failures. diff --git a/crates/relayer/src/link/pending.rs b/crates/relayer/src/link/pending.rs index 30b3d6a9b4..8abc47bbd9 100644 --- a/crates/relayer/src/link/pending.rs +++ b/crates/relayer/src/link/pending.rs @@ -1,4 +1,3 @@ -use core::iter::Iterator; use core::time::Duration; use std::time::Instant; diff --git a/crates/relayer/src/link/relay_path.rs b/crates/relayer/src/link/relay_path.rs index 6abdd59620..ff16acd086 100644 --- a/crates/relayer/src/link/relay_path.rs +++ b/crates/relayer/src/link/relay_path.rs @@ -1,5 +1,6 @@ use alloc::collections::BTreeMap as HashMap; use alloc::collections::VecDeque; +use ibc_relayer_types::core::ics04_channel::packet::Sequence; use std::ops::Sub; use std::time::{Duration, Instant}; @@ -29,6 +30,7 @@ use crate::chain::counterparty::unreceived_acknowledgements; use crate::chain::counterparty::unreceived_packets; use crate::chain::endpoint::ChainStatus; use crate::chain::handle::ChainHandle; +use crate::chain::requests::Paginate; use crate::chain::requests::QueryChannelRequest; use crate::chain::requests::QueryClientEventRequest; use crate::chain::requests::QueryHeight; @@ -115,6 +117,7 @@ pub struct RelayPath { pub max_memo_size: Ics20FieldSizeLimit, pub max_receiver_size: Ics20FieldSizeLimit, + pub exclude_src_sequences: Vec, } impl RelayPath { @@ -163,6 +166,8 @@ impl RelayPath { max_memo_size: link_parameters.max_memo_size, max_receiver_size: link_parameters.max_receiver_size, + + exclude_src_sequences: link_parameters.exclude_src_sequences, }) } @@ -350,10 +355,9 @@ impl RelayPath { } // Nothing to do if channel on destination is already closed - if self - .dst_channel(QueryHeight::Latest)? - .state_matches(&ChannelState::Closed) - { + let dst_channel = self.dst_channel(QueryHeight::Latest)?; + + if dst_channel.state_matches(&ChannelState::Closed) { return Ok(None); } @@ -363,12 +367,15 @@ impl RelayPath { .build_channel_proofs(self.src_port_id(), src_channel_id, event.height) .map_err(|e| LinkError::channel(ChannelError::channel_proof(e)))?; + let counterparty_upgrade_sequence = self.src_channel(QueryHeight::Latest)?.upgrade_sequence; + // Build the domain type message let new_msg = MsgChannelCloseConfirm { port_id: self.dst_port_id().clone(), channel_id: self.dst_channel_id().clone(), proofs, signer: self.dst_signer()?, + counterparty_upgrade_sequence, }; Ok(Some(new_msg.to_any())) @@ -423,20 +430,29 @@ impl RelayPath { TrackedEvents::new(result, tracking_id) } - fn relay_pending_packets(&self, height: Option) -> Result<(), LinkError> { + fn relay_pending_packets( + &self, + height: Option, + clear_limit: usize, + ) -> Result<(), LinkError> { let _span = span!(Level::ERROR, "relay_pending_packets", ?height).entered(); - let tracking_id = TrackingId::new_cleared_uuid(); + let tracking_id = TrackingId::new_packet_clearing(); telemetry!(received_event_batch, tracking_id); let src_config = self.src_chain().config().map_err(LinkError::relayer)?; let chunk_size = src_config.query_packets_chunk_size(); for i in 1..=MAX_RETRIES { - let cleared_recv = - self.schedule_recv_packet_and_timeout_msgs(height, chunk_size, tracking_id); + let cleared_recv = self.schedule_recv_packet_and_timeout_msgs( + height, + chunk_size, + clear_limit, + tracking_id, + ); - let cleared_ack = self.schedule_packet_ack_msgs(height, chunk_size, tracking_id); + let cleared_ack = + self.schedule_packet_ack_msgs(height, chunk_size, clear_limit, tracking_id); match cleared_recv.and(cleared_ack) { Ok(()) => return Ok(()), @@ -452,14 +468,18 @@ impl RelayPath { /// Clears any packets that were sent before `height`. /// If no height is passed in, then the latest height of the source chain is used. - pub fn schedule_packet_clearing(&self, height: Option) -> Result<(), LinkError> { + pub fn schedule_packet_clearing( + &self, + height: Option, + clear_limit: usize, + ) -> Result<(), LinkError> { let _span = span!(Level::ERROR, "schedule_packet_clearing", ?height).entered(); let clear_height = height .map(|h| h.decrement().map_err(|e| LinkError::decrement_height(h, e))) .transpose()?; - self.relay_pending_packets(clear_height)?; + self.relay_pending_packets(clear_height, clear_limit)?; debug!(height = ?clear_height, "done relaying pending packets at clear height"); @@ -537,7 +557,7 @@ impl RelayPath { let dst_latest_info = self .dst_chain() .query_application_status() - .map_err(|e| LinkError::query(self.src_chain().id(), e))?; + .map_err(|e| LinkError::query(self.dst_chain().id(), e))?; let dst_latest_height = dst_latest_info.height; @@ -709,12 +729,12 @@ impl RelayPath { return Ok(reply); } - Err(LinkError(error::LinkErrorDetail::Send(e), _)) => { - // This error means we could retry - error!("error {}", e.event); + Err(LinkError(error::LinkErrorDetail::Send(_), _)) => { if i + 1 == MAX_RETRIES { - error!("{}/{} retries exhausted. giving up", i + 1, MAX_RETRIES) + error!("{}/{} retries exhausted, giving up", i + 1, MAX_RETRIES) } else { + debug!("{}/{} retries exhausted, retrying with newly-generated operational data", i + 1, MAX_RETRIES); + // If we haven't exhausted all retries, regenerate the op. data & retry match self.regenerate_operational_data(odata.clone()) { None => return Ok(S::Reply::empty()), // Nothing to retry @@ -738,7 +758,7 @@ impl RelayPath { /// Return value: /// - `Some(..)`: a new operational data from which to retry sending, /// - `None`: all the events in the initial operational data were exhausted (i.e., turned - /// into timeouts), so there is nothing to retry. + /// into timeouts), so there is nothing to retry. /// /// Side effects: may schedule a new operational data targeting the source chain, comprising /// new timeout messages. @@ -1133,6 +1153,7 @@ impl RelayPath { &self, opt_query_height: Option, chunk_size: usize, + clear_limit: usize, tracking_id: TrackingId, ) -> Result<(), LinkError> { let _span = span!( @@ -1143,9 +1164,13 @@ impl RelayPath { .entered(); // Pull the s.n. of all packets that the destination chain has not yet received. - let (sequences, src_response_height) = - unreceived_packets(self.dst_chain(), self.src_chain(), &self.path_id) - .map_err(LinkError::supervisor)?; + let (sequences, src_response_height) = unreceived_packets( + self.dst_chain(), + self.src_chain(), + &self.path_id, + Paginate::All, + ) + .map_err(LinkError::supervisor)?; let query_height = opt_query_height.unwrap_or(src_response_height); @@ -1154,6 +1179,14 @@ impl RelayPath { return Ok(()); } + // Retain only sequences which should not be filtered out + let raw_sequences: Vec = sequences + .into_iter() + .filter(|sequence| !self.exclude_src_sequences.contains(sequence)) + .collect(); + + let sequences = &raw_sequences[..raw_sequences.len().min(clear_limit)]; + debug!( dst_chain = %self.dst_chain().id(), src_chain = %self.src_chain().id(), @@ -1165,7 +1198,7 @@ impl RelayPath { // Chunk-up the list of sequence nrs. into smaller parts, // and schedule operational data incrementally across each chunk. for events_chunk in query_packet_events_with( - &sequences, + sequences, Qualified::SmallerEqual(query_height), self.src_chain(), &self.path_id, @@ -1194,6 +1227,7 @@ impl RelayPath { &self, opt_query_height: Option, chunk_size: usize, + clear_limit: usize, tracking_id: TrackingId, ) -> Result<(), LinkError> { let _span = span!( @@ -1203,9 +1237,13 @@ impl RelayPath { ) .entered(); - let sequences_and_height = - unreceived_acknowledgements(self.dst_chain(), self.src_chain(), &self.path_id) - .map_err(LinkError::supervisor)?; + let sequences_and_height = unreceived_acknowledgements( + self.dst_chain(), + self.src_chain(), + &self.path_id, + Paginate::All, + ) + .map_err(LinkError::supervisor)?; let Some((sequences, src_response_height)) = sequences_and_height else { return Ok(()); @@ -1218,6 +1256,14 @@ impl RelayPath { return Ok(()); } + // Retain only sequences which should not be filtered out + let raw_sequences: Vec = sequences + .into_iter() + .filter(|sequence| !self.exclude_src_sequences.contains(sequence)) + .collect(); + + let sequences = &raw_sequences[..raw_sequences.len().min(clear_limit)]; + debug!( dst_chain = %self.dst_chain().id(), src_chain = %self.src_chain().id(), @@ -1228,7 +1274,7 @@ impl RelayPath { // Incrementally process all the available sequence numbers in chunks for events_chunk in query_packet_events_with( - &sequences, + sequences, Qualified::SmallerEqual(query_height), self.src_chain(), &self.path_id, @@ -1378,11 +1424,14 @@ impl RelayPath { ) .map_err(|e| LinkError::packet_proofs_constructor(self.dst_chain().id(), e))?; + let counterparty_upgrade_sequence = self.src_channel(QueryHeight::Latest)?.upgrade_sequence; + let msg = MsgTimeoutOnClose::new( packet.clone(), next_sequence_received, proofs.clone(), self.src_signer()?, + counterparty_upgrade_sequence, ); trace!(packet = %msg.packet, height = %proofs.height(), "built timeout on close msg"); @@ -1623,7 +1672,7 @@ impl RelayPath { let dst_status = self .dst_chain() .query_application_status() - .map_err(|e| LinkError::query(self.src_chain().id(), e))?; + .map_err(|e| LinkError::query(self.dst_chain().id(), e))?; let dst_current_height = dst_status.height; @@ -1828,7 +1877,6 @@ impl RelayPath { } // we need fully qualified ChainId to avoid unneeded imports warnings - #[cfg(feature = "telemetry")] fn target_info( &self, target: OperationalDataTarget, @@ -1854,7 +1902,6 @@ impl RelayPath { } } - #[cfg(feature = "telemetry")] fn backlog_update(&self, event: &IbcEvent) { match event { IbcEvent::SendPacket(send_packet_ev) => { @@ -1888,7 +1935,6 @@ impl RelayPath { } } - #[cfg(feature = "telemetry")] fn record_cleared_send_packet(&self, event_with_height: &IbcEventWithHeight) { if let IbcEvent::SendPacket(send_packet_ev) = &event_with_height.event { ibc_telemetry::global().send_packet_events( @@ -1910,7 +1956,6 @@ impl RelayPath { } } - #[cfg(feature = "telemetry")] fn record_cleared_acknowledgments<'a>( &self, events_with_heights: impl Iterator, @@ -1930,7 +1975,7 @@ impl RelayPath { } } -#[tracing::instrument(skip(data))] +#[tracing::instrument(skip_all)] fn check_ics20_fields_size( data: &[u8], memo_limit: Ics20FieldSizeLimit, @@ -1945,9 +1990,9 @@ fn check_ics20_fields_size( (ValidationResult::Valid, ValidationResult::Valid) => true, (memo_validity, receiver_validity) => { - debug!("found invalid ICS-20 packet data, not relaying packet!"); - debug!(" ICS-20 memo: {memo_validity}"); - debug!(" ICS-20 receiver: {receiver_validity}"); + warn!("found invalid ICS-20 packet data, not relaying packet!"); + warn!(" ICS-20 memo: {memo_validity}"); + warn!(" ICS-20 receiver: {receiver_validity}"); false } diff --git a/crates/relayer/src/link/relay_sender.rs b/crates/relayer/src/link/relay_sender.rs index c4d29fe91a..a8c70cb9f0 100644 --- a/crates/relayer/src/link/relay_sender.rs +++ b/crates/relayer/src/link/relay_sender.rs @@ -95,10 +95,11 @@ impl Submit for AsyncSender { type Reply = AsyncReply; fn submit(target: &impl ChainHandle, msgs: TrackedMsgs) -> Result { - let a = target + let responses = target .send_messages_and_wait_check_tx(msgs) .map_err(LinkError::relayer)?; - let reply = AsyncReply { responses: a }; + + let reply = AsyncReply { responses }; // Note: There may be errors in the reply, for example: // `Response { code: Err(11), data: Data([]), log: Log("Too much gas wanted: 35000000, maximum is 25000000: out of gas")` diff --git a/crates/relayer/src/misbehaviour.rs b/crates/relayer/src/misbehaviour.rs index 4d11974149..69b533f462 100644 --- a/crates/relayer/src/misbehaviour.rs +++ b/crates/relayer/src/misbehaviour.rs @@ -11,11 +11,6 @@ use ibc_relayer_types::core::ics24_host::identifier::ClientId; use ibc_relayer_types::Height; use tendermint_proto::Protobuf; -#[cfg(test)] -use ibc_relayer_types::mock::misbehaviour::Misbehaviour as MockMisbehaviour; -#[cfg(test)] -use ibc_relayer_types::mock::misbehaviour::MOCK_MISBEHAVIOUR_TYPE_URL; - #[derive(Clone, Debug, PartialEq, Eq)] pub struct MisbehaviourEvidence { pub misbehaviour: AnyMisbehaviour, @@ -26,27 +21,18 @@ pub struct MisbehaviourEvidence { #[allow(clippy::large_enum_variant)] pub enum AnyMisbehaviour { Tendermint(TmMisbehaviour), - - #[cfg(test)] - Mock(MockMisbehaviour), } impl Misbehaviour for AnyMisbehaviour { fn client_id(&self) -> &ClientId { match self { Self::Tendermint(misbehaviour) => misbehaviour.client_id(), - - #[cfg(test)] - Self::Mock(misbehaviour) => misbehaviour.client_id(), } } fn height(&self) -> Height { match self { Self::Tendermint(misbehaviour) => misbehaviour.height(), - - #[cfg(test)] - Self::Mock(misbehaviour) => misbehaviour.height(), } } } @@ -62,11 +48,6 @@ impl TryFrom for AnyMisbehaviour { TmMisbehaviour::decode_vec(&raw.value).map_err(Error::decode_raw_misbehaviour)?, )), - #[cfg(test)] - MOCK_MISBEHAVIOUR_TYPE_URL => Ok(AnyMisbehaviour::Mock( - MockMisbehaviour::decode_vec(&raw.value).map_err(Error::decode_raw_misbehaviour)?, - )), - _ => Err(Error::unknown_misbehaviour_type(raw.type_url)), } } @@ -79,12 +60,6 @@ impl From for Any { type_url: TENDERMINT_MISBEHAVIOR_TYPE_URL.to_string(), value: misbehaviour.encode_vec(), }, - - #[cfg(test)] - AnyMisbehaviour::Mock(misbehaviour) => Any { - type_url: MOCK_MISBEHAVIOUR_TYPE_URL.to_string(), - value: misbehaviour.encode_vec(), - }, } } } @@ -93,9 +68,6 @@ impl core::fmt::Display for AnyMisbehaviour { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { match self { AnyMisbehaviour::Tendermint(tm) => write!(f, "{tm}"), - - #[cfg(test)] - AnyMisbehaviour::Mock(mock) => write!(f, "{mock:?}"), } } } @@ -105,10 +77,3 @@ impl From for AnyMisbehaviour { Self::Tendermint(misbehaviour) } } - -#[cfg(test)] -impl From for AnyMisbehaviour { - fn from(misbehaviour: MockMisbehaviour) -> Self { - Self::Mock(misbehaviour) - } -} diff --git a/crates/relayer/src/object.rs b/crates/relayer/src/object.rs index 333212c6ec..aac3efb257 100644 --- a/crates/relayer/src/object.rs +++ b/crates/relayer/src/object.rs @@ -8,7 +8,7 @@ use ibc_relayer_types::core::{ ics02_client::events::UpdateClient, ics03_connection::events::Attributes as ConnectionAttributes, ics04_channel::events::{ - Attributes, CloseInit, SendPacket, TimeoutPacket, WriteAcknowledgement, + Attributes, CloseInit, SendPacket, TimeoutPacket, UpgradeAttributes, WriteAcknowledgement, }, ics24_host::identifier::{ChainId, ChannelId, ClientId, ConnectionId, PortId}, }; @@ -447,6 +447,38 @@ impl Object { .into()) } + pub fn channel_from_chan_upgrade_events( + attributes: &UpgradeAttributes, + src_chain: &impl ChainHandle, + allow_non_open_connection: bool, + ) -> Result { + let channel_id = attributes.channel_id(); + + let port_id = attributes.port_id(); + + let dst_chain_id = if allow_non_open_connection { + // Get the destination chain allowing for the possibility that the connection is not yet open. + // This is to support the optimistic channel handshake by allowing the channel worker to get + // the channel events while the connection is being established. + // The channel worker will eventually finish the channel handshake via the retry mechanism. + channel_connection_client_no_checks(src_chain, port_id, channel_id) + .map(|c| c.client.client_state.chain_id()) + .map_err(ObjectError::supervisor)? + } else { + channel_connection_client(src_chain, port_id, channel_id) + .map(|c| c.client.client_state.chain_id()) + .map_err(ObjectError::supervisor)? + }; + + Ok(Channel { + dst_chain_id, + src_chain_id: src_chain.id(), + src_channel_id: channel_id.clone(), + src_port_id: port_id.clone(), + } + .into()) + } + /// Build the object associated with the given [`SendPacket`] event. pub fn for_send_packet( e: &SendPacket, diff --git a/crates/relayer/src/sdk_error.rs b/crates/relayer/src/sdk_error.rs index ef48c06be9..f9694716a3 100644 --- a/crates/relayer/src/sdk_error.rs +++ b/crates/relayer/src/sdk_error.rs @@ -1,6 +1,8 @@ use flex_error::define_error; use tendermint::abci::Code; +use crate::chain::cosmos::estimate::EstimatedGas; + // Provides mapping for errors returned from ibc-go and cosmos-sdk define_error! { SdkError { @@ -24,9 +26,13 @@ define_error! { { code: u32 } | e | { format_args!("unknown TX sync response error: {}", e.code) }, - OutOfGas - { code: u32 } - |_| { "the gas requirement is higher than the configured maximum gas! please check the Hermes config.toml".to_string() }, + OutOfGasDefault + { code: u32, amount: u64 } + |e| { format_args!("due to the Tx simulation failing, the configured default gas was used. Please check the Hermes config.toml and increase the configured `default_gas`. Current value is `{}`", e.amount) }, + + OutOfGasSimulated + { code: u32, amount: u64 } + |e| { format_args!("the issue might have been caused by a misconfiguration of Hermes. Please check the Hermes config.toml and increase either the `max_gas` or `gas_multiplier` settings. Simulated gas was: {}", e.amount) }, InsufficientFee { code: u32 } @@ -186,12 +192,15 @@ pub fn sdk_error_from_tx_result(code: Code, codespace: &str) -> SdkError { /// into IBC relayer domain-type errors. /// See [`tendermint_rpc::endpoint::broadcast::tx_sync::Response`]. /// Cf: -pub fn sdk_error_from_tx_sync_error_code(code: u32) -> SdkError { +pub fn sdk_error_from_tx_sync_error_code(code: u32, estimated_gas: EstimatedGas) -> SdkError { match code { // The primary reason (we know of) causing broadcast_tx_sync to fail // is due to "out of gas" errors. These are unrecoverable at the moment // on Hermes side. We'll inform the user to check for misconfiguration. - 11 => SdkError::out_of_gas(code), + 11 => match estimated_gas { + EstimatedGas::Default(amount) => SdkError::out_of_gas_default(code, amount), + EstimatedGas::Simulated(amount) => SdkError::out_of_gas_simulated(code, amount), + }, 13 => SdkError::insufficient_fee(code), _ => SdkError::unknown_tx_sync(code), } diff --git a/crates/relayer/src/supervisor.rs b/crates/relayer/src/supervisor.rs index cab6f55c82..c994ac6585 100644 --- a/crates/relayer/src/supervisor.rs +++ b/crates/relayer/src/supervisor.rs @@ -374,13 +374,15 @@ fn relay_on_object( }; // Then, apply the client filter + // If the object is a CrossChain query discard it if the destination chain + // is not configured let client_filter_outcome = match object { Object::Client(client) => client_state_filter.control_client_object(registry, client), Object::Connection(conn) => client_state_filter.control_conn_object(registry, conn), Object::Channel(chan) => client_state_filter.control_chan_object(registry, chan), Object::Packet(packet) => client_state_filter.control_packet_object(registry, packet), + Object::CrossChainQuery(_ccq) => Ok(Permission::Allow), Object::Wallet(_wallet) => Ok(Permission::Allow), - Object::CrossChainQuery(_) => Ok(Permission::Allow), }; match client_filter_outcome { @@ -539,6 +541,31 @@ pub fn collect_events( || Object::client_from_chan_open_events(&attributes, src_chain).ok(), ); } + IbcEvent::UpgradeInitChannel(..) + | IbcEvent::UpgradeTryChannel(..) + | IbcEvent::UpgradeAckChannel(..) + | IbcEvent::UpgradeOpenChannel(..) + | IbcEvent::UpgradeErrorChannel(..) => { + collect_event( + &mut collected, + event_with_height.clone(), + mode.channels.enabled, + || { + event_with_height + .event + .clone() + .channel_upgrade_attributes() + .and_then(|attr| { + Object::channel_from_chan_upgrade_events( + &attr, + src_chain, + mode.connections.enabled, + ) + .ok() + }) + }, + ); + } IbcEvent::SendPacket(ref packet) => { collect_event( &mut collected, @@ -789,8 +816,33 @@ fn process_batch( workers.notify_new_block(&src_chain.id(), batch.height, new_block); } - // Forward the IBC events. + // Forward the IBC events to the appropriate workers for (object, events_with_heights) in collected.per_object.into_iter() { + if events_with_heights.is_empty() { + // Event batch is empty, nothing to do + continue; + } + + let Ok(src_chain) = registry.get_or_spawn(object.src_chain_id()) else { + trace!( + "skipping events for '{}': source chain '{}' is not registered", + object.short_name(), + object.src_chain_id() + ); + + continue; + }; + + let Ok(dst_chain) = registry.get_or_spawn(object.dst_chain_id()) else { + trace!( + "skipping events for '{}': destination chain '{}' is not registered", + object.short_name(), + object.src_chain_id() + ); + + continue; + }; + if !relay_on_object( config, registry, @@ -799,32 +851,23 @@ fn process_batch( &object, ) { trace!( - "skipping events for '{}'. \ - reason: filtering is enabled and channel does not match any allowed channels", + "skipping events for '{}': rejected by filtering policy", object.short_name() ); continue; } - if events_with_heights.is_empty() { - continue; - } - - let src = registry - .get_or_spawn(object.src_chain_id()) - .map_err(Error::spawn)?; - - let dst = registry - .get_or_spawn(object.dst_chain_id()) - .map_err(Error::spawn)?; - if let Object::Packet(ref _path) = object { - // Update telemetry info - telemetry!(send_telemetry(&src, &dst, &events_with_heights, _path)); + telemetry!(send_telemetry( + &src_chain, + &dst_chain, + &events_with_heights, + _path + )); } - let worker = workers.get_or_spawn(object, src, dst, config); + let worker = workers.get_or_spawn(object, src_chain, dst_chain, config); worker.send_events( batch.height, @@ -848,7 +891,6 @@ fn process_batch( /// So successfully sending a packet from chain A to chain B will result in first a SendPacket /// event with `chain_id = A` and `counterparty_chain_id = B` and then a WriteAcknowlegment /// event with `chain_id = B` and `counterparty_chain_id = A`. -#[cfg(feature = "telemetry")] fn send_telemetry( src: &Src, dst: &Dst, diff --git a/crates/relayer/src/supervisor/scan.rs b/crates/relayer/src/supervisor/scan.rs index d5dd77d364..3431f30881 100644 --- a/crates/relayer/src/supervisor/scan.rs +++ b/crates/relayer/src/supervisor/scan.rs @@ -18,9 +18,9 @@ use crate::{ counterparty::{channel_on_destination, connection_state_on_destination}, handle::ChainHandle, requests::{ - IncludeProof, PageRequest, QueryChannelRequest, QueryClientConnectionsRequest, - QueryClientStateRequest, QueryClientStatesRequest, QueryConnectionChannelsRequest, - QueryConnectionRequest, QueryHeight, + IncludeProof, PageRequest, Paginate, QueryChannelRequest, + QueryClientConnectionsRequest, QueryClientStateRequest, QueryClientStatesRequest, + QueryConnectionChannelsRequest, QueryConnectionRequest, QueryHeight, }, }, client_state::IdentifiedAnyClientState, @@ -236,9 +236,17 @@ impl ChannelScan { .as_ref() .and_then(|c| PathIdentifiers::from_channel_end(c.clone())) .map(|ids| { - unreceived_packets(counterparty_chain, chain, &ids) - .map(|(seq, _)| seq) - .unwrap_or_default() + unreceived_packets( + counterparty_chain, + chain, + &ids, + Paginate::PerPage { + per_page: 1, + total: 1, + }, + ) + .map(|(seq, _)| seq) + .unwrap_or_default() }) } @@ -252,9 +260,17 @@ impl ChannelScan { .as_ref() .and_then(|c| PathIdentifiers::from_channel_end(c.clone()))?; - let acks = unreceived_acknowledgements(counterparty_chain, chain, &ids) - .map(|sns| sns.map_or(vec![], |(sns, _)| sns)) - .unwrap_or_default(); + let acks = unreceived_acknowledgements( + counterparty_chain, + chain, + &ids, + Paginate::PerPage { + per_page: 1, + total: 1, + }, + ) + .map(|sns| sns.map_or(vec![], |(sns, _)| sns)) + .unwrap_or_default(); Some(acks) } diff --git a/crates/relayer/src/supervisor/spawn.rs b/crates/relayer/src/supervisor/spawn.rs index b1b608875c..769ac2b9d3 100644 --- a/crates/relayer/src/supervisor/spawn.rs +++ b/crates/relayer/src/supervisor/spawn.rs @@ -244,9 +244,12 @@ impl<'a, Chain: ChainHandle> SpawnContext<'a, Chain> { chan_state_dst ); + let is_channel_upgrading = channel_scan.channel.channel_end.is_upgrading(); + if (mode.clients.enabled || mode.packets.enabled) && chan_state_src.is_open() && (chan_state_dst.is_open() || chan_state_dst.is_closed()) + && !is_channel_upgrading { if mode.clients.enabled { // Spawn the client worker @@ -303,7 +306,7 @@ impl<'a, Chain: ChainHandle> SpawnContext<'a, Chain> { } Ok(mode.clients.enabled) - } else if mode.channels.enabled { + } else if mode.channels.enabled && !is_channel_upgrading { let has_packets = || { !channel_scan .unreceived_packets_on_counterparty(&counterparty_chain, &chain) @@ -339,6 +342,35 @@ impl<'a, Chain: ChainHandle> SpawnContext<'a, Chain> { } else { Ok(false) } + } else if is_channel_upgrading { + let path_object = Object::Packet(Packet { + dst_chain_id: counterparty_chain.id(), + src_chain_id: chain.id(), + src_channel_id: channel_scan.channel.channel_id.clone(), + src_port_id: channel_scan.channel.port_id.clone(), + }); + + self.workers + .spawn( + chain.clone(), + counterparty_chain.clone(), + &path_object, + self.config, + ) + .then(|| info!("spawned packet worker: {}", path_object.short_name())); + + let channel_object = Object::Channel(Channel { + dst_chain_id: counterparty_chain.id(), + src_chain_id: chain.id(), + src_channel_id: channel_scan.channel.channel_id, + src_port_id: channel_scan.channel.port_id, + }); + + self.workers + .spawn(chain, counterparty_chain, &channel_object, self.config) + .then(|| info!("spawned channel worker: {}", channel_object.short_name())); + + Ok(true) } else { Ok(false) } diff --git a/crates/relayer/src/telemetry.rs b/crates/relayer/src/telemetry.rs index 0734ee454b..bc8bc77ae6 100644 --- a/crates/relayer/src/telemetry.rs +++ b/crates/relayer/src/telemetry.rs @@ -1,15 +1,6 @@ // If the `telemetry` feature is enabled, re-export the `ibc-telemetry` state. -#[cfg(feature = "telemetry")] pub type Telemetry = alloc::sync::Arc; -// Otherwise, define and export a dummy type. -#[cfg(not(feature = "telemetry"))] -#[derive(Clone, Debug)] -pub struct TelemetryDisabled; - -#[cfg(not(feature = "telemetry"))] -pub type Telemetry = TelemetryDisabled; - /// A macro to send metric updates via a telemetry handle, /// only if the `telemetry` feature is enabled. /// Otherwise, it compiles to a no-op. @@ -32,7 +23,6 @@ pub type Telemetry = TelemetryDisabled; #[macro_export] macro_rules! telemetry { ($id:ident, $($args:expr),* $(,)*) => { - #[cfg(feature = "telemetry")] #[allow(unused_imports, unused_variables)] { use ::ibc_telemetry::state::WorkerType; @@ -42,7 +32,6 @@ macro_rules! telemetry { }; ($e:expr) => { - #[cfg(feature = "telemetry")] #[allow(unused_imports, unused_variables)] { use ::ibc_telemetry::state::WorkerType; diff --git a/crates/relayer/src/upgrade_chain.rs b/crates/relayer/src/upgrade_chain.rs index 3c6b407f5c..318f35130b 100644 --- a/crates/relayer/src/upgrade_chain.rs +++ b/crates/relayer/src/upgrade_chain.rs @@ -14,9 +14,10 @@ use ibc_proto::cosmos::upgrade::v1beta1::Plan; use ibc_proto::google::protobuf::Any; use ibc_proto::ibc::core::client::v1::{MsgIbcSoftwareUpgrade, UpgradeProposal}; use ibc_relayer_types::clients::ics07_tendermint::client_state::UpgradeOptions; -use ibc_relayer_types::core::ics02_client::client_state::ClientState; +use ibc_relayer_types::core::ics02_client::client_state::UpgradableClientState; use ibc_relayer_types::core::ics24_host::identifier::{ChainId, ClientId}; use ibc_relayer_types::{downcast, Height}; +use tracing::warn; use crate::chain::handle::ChainHandle; use crate::chain::requests::{IncludeProof, QueryClientStateRequest, QueryHeight}; @@ -96,22 +97,32 @@ pub fn build_and_send_ibc_upgrade_proposal( /// Looks at the ibc-go version to determine if the legacy `UpgradeProposal` message /// or if the newer `MsgIBCSoftwareUpdate` message should be used to upgrade the chain. /// If the ibc-go version returned isn't reliable, a deprecated version, then the version -/// of Cosmos SDK is used. +/// of Cosmos SDK is used, if any. If there is no SDK version, we assume that the legacy upgrade is required. pub fn requires_legacy_upgrade_proposal(dst_chain: impl ChainHandle) -> bool { - let version_specs = dst_chain.version_specs().unwrap(); + let Ok(version_specs) = dst_chain.version_specs() else { + warn!("failed to get version specs, assuming legacy upgrade proposal is required"); + return true; + }; + + let sdk_before_50 = version_specs + .cosmos_sdk + .as_ref() + .map(|s| s.minor < 50) + .unwrap_or(true); + match version_specs.ibc_go { + None => sdk_before_50, Some(ibc_version) => { // Some ibc-go simapps return unreliable ibc-go versions, such as simapp v8.0.0 // returns version v1.0.0. So if the ibc-go version matches which is not maintained // anymore, use the Cosmos SDK version to determine if the legacy upgrade proposal // has to be used if ibc_version.major < 4 { - version_specs.cosmos_sdk.minor < 50 + sdk_before_50 } else { ibc_version.major < 8 } } - None => version_specs.cosmos_sdk.minor < 50, } } @@ -285,6 +296,7 @@ fn build_upgrade_proposal( metadata: "".to_string(), title: "proposal 0".to_string(), summary: "upgrade the chain software and unbonding period".to_string(), + expedited: false, }; let mut buf_msg = Vec::new(); diff --git a/crates/relayer/src/util.rs b/crates/relayer/src/util.rs index e589e8c7c8..9799e6cc4e 100644 --- a/crates/relayer/src/util.rs +++ b/crates/relayer/src/util.rs @@ -5,6 +5,7 @@ pub mod collate; pub mod compat_mode; pub mod debug_section; pub mod diff; +pub mod excluded_sequences; pub mod iter; pub mod lock; pub mod pretty; @@ -14,3 +15,33 @@ pub mod retry; pub mod seq_range; pub mod stream; pub mod task; + +/// Helper function to create a gRPC client. +pub async fn create_grpc_client( + grpc_addr: &tonic::transport::Uri, + client_constructor: impl FnOnce(tonic::transport::Channel) -> T, +) -> Result { + let builder = tonic::transport::Channel::builder(grpc_addr.clone()); + + // Don't configures TLS for the endpoint if using IPv6 + let builder = if grpc_addr.scheme() == Some(&http::uri::Scheme::HTTPS) { + let domain = grpc_addr + .host() + .map(|d| d.replace(['[', ']'], "")) + .ok_or_else(|| crate::error::Error::invalid_http_host(grpc_addr.to_string()))?; + let tls_config = tonic::transport::ClientTlsConfig::new() + .with_native_roots() + .domain_name(domain); + builder + .tls_config(tls_config) + .map_err(crate::error::Error::grpc_transport)? + } else { + builder + }; + + let channel = builder + .connect() + .await + .map_err(crate::error::Error::grpc_transport)?; + Ok(client_constructor(channel)) +} diff --git a/crates/relayer/src/util/compat_mode.rs b/crates/relayer/src/util/compat_mode.rs index fd4bc1ed1a..c637d5a247 100644 --- a/crates/relayer/src/util/compat_mode.rs +++ b/crates/relayer/src/util/compat_mode.rs @@ -1,27 +1,82 @@ use tracing::warn; use tendermint::Version; -use tendermint_rpc::client::CompatMode as TmCompatMode; +use crate::chain::cosmos::version::ConsensusVersion; use crate::config::compat_mode::CompatMode; use crate::error::Error; -/// This is a wrapper around tendermint-rs CompatMode::from_version() method. -/// -pub fn compat_mode_from_version( +pub fn compat_mode_from_node_version( configured_version: &Option, version: Version, ) -> Result { - let queried_version = TmCompatMode::from_version(version); + let queried_version = CompatMode::from_version(version); // This will prioritize the use of the CompatMode specified in Hermes configuration file match (configured_version, queried_version) { - (Some(configured), Ok(queried)) if !configured.equal_to_tm_compat_mode(queried) => { - warn!("be wary of potential `compat_mode` misconfiguration. Configured version: {}, chain version: {}. Hermes will use the configured `compat_mode` version `{}`. If this configuration is done on purpose this message can be ignored.", configured, queried, configured); - Ok(configured.clone()) + (Some(configured), Ok(queried)) if configured != &queried => { + warn!( + "potential `compat_mode` misconfiguration! Configured version '{configured}' does not match chain version '{queried}'. \ + Hermes will use the configured `compat_mode` version '{configured}'. \ + If this configuration is done on purpose this message can be ignored.", + ); + + Ok(*configured) } - (Some(configured), _) => Ok(configured.clone()), - (_, Ok(queried)) => Ok(queried.into()), + (Some(configured), _) => Ok(*configured), + (_, Ok(queried)) => Ok(queried), (_, Err(e)) => Err(Error::invalid_compat_mode(e)), } } + +pub fn compat_mode_from_version_specs( + configured_mode: &Option, + version: Option, +) -> Result { + let queried_mode = match version { + Some(ConsensusVersion::Tendermint(v) | ConsensusVersion::Comet(v)) => { + compat_mode_from_semver(v) + } + None => None, + }; + + match (configured_mode, queried_mode) { + (Some(configured), Some(queried)) if configured == &queried => Ok(queried), + (Some(configured), Some(queried)) => { + warn!( + "potential `compat_mode` misconfiguration! Configured version: {configured}, chain version: {queried}. \ + Hermes will use the configured `compat_mode` version `{configured}`. \ + If this configuration is done on purpose this message can be ignored." + ); + + Ok(*configured) + } + (Some(configured), None) => { + warn!( + "Hermes could not infer the compatibility mode for this chain, \ + and will use the configured `compat_mode` version `{configured}`." + ); + + Ok(*configured) + } + (None, Some(queried)) => Ok(queried), + (None, None) => { + warn!( + "Hermes could not infer the compatibility mode for this chain, and no `compat_mode` was configured, \ + and will use the default compatibility mode `0.37`. \ + Please consider configuring the `compat_mode` in the Hermes configuration file." + ); + + Ok(CompatMode::V0_37) + } + } +} + +fn compat_mode_from_semver(v: semver::Version) -> Option { + match (v.major, v.minor) { + (0, 34) => Some(CompatMode::V0_34), + (0, 37) => Some(CompatMode::V0_37), + (0, 38) => Some(CompatMode::V0_38), + _ => None, + } +} diff --git a/crates/relayer/src/util/excluded_sequences.rs b/crates/relayer/src/util/excluded_sequences.rs new file mode 100644 index 0000000000..800a4c8c15 --- /dev/null +++ b/crates/relayer/src/util/excluded_sequences.rs @@ -0,0 +1,113 @@ +use serde::de::{Error, MapAccess, Visitor}; +use serde::ser::SerializeMap; +use serde::Deserializer; +use serde::Serializer; +use serde_derive::Deserialize; +use serde_derive::Serialize; +use std::collections::BTreeMap; +use std::fmt; +use std::str::FromStr; + +use ibc_relayer_types::core::ics04_channel::packet::Sequence; +use ibc_relayer_types::core::ics24_host::identifier::ChannelId; + +use crate::chain::cosmos::config::error::Error as ConfigError; + +#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)] +pub struct ExcludedSequences { + #[serde( + deserialize_with = "deserialize_excluded_sequences", + serialize_with = "serialize_excluded_sequences", + flatten + )] + pub map: BTreeMap>, +} + +impl ExcludedSequences { + pub fn new(map: BTreeMap>) -> Self { + Self { map } + } +} + +fn serialize_excluded_sequences( + map: &BTreeMap>, + serializer: S, +) -> Result +where + S: Serializer, +{ + let mut seq = serializer.serialize_map(Some(map.len()))?; + for (k, v) in map { + seq.serialize_entry(k, v)?; + } + seq.end() +} + +fn deserialize_excluded_sequences<'de, D>( + deserializer: D, +) -> Result>, D::Error> +where + D: Deserializer<'de>, +{ + deserializer.deserialize_map(ExcludedSequencesVisitor) +} + +struct ExcludedSequencesVisitor; + +impl<'de> Visitor<'de> for ExcludedSequencesVisitor { + type Value = BTreeMap>; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("expected list of excluded sequences") + } + + fn visit_map(self, mut access: M) -> Result + where + M: MapAccess<'de>, + { + let mut map = BTreeMap::new(); + while let Some((key, value)) = access.next_entry::()? { + let channel_id = ChannelId::from_str(&key).map_err(|e| Error::custom(e.to_string()))?; + let sequences = + parse_sequence_range(&value).map_err(|e| Error::custom(e.to_string()))?; + map.insert(channel_id, sequences); + } + Ok(map) + } +} + +fn parse_sequence_range(value: &toml::Value) -> Result, ConfigError> { + let mut res = Vec::new(); + let sequences = value + .as_array() + .ok_or_else(ConfigError::expected_excluded_sequences_array)?; + for sequence in sequences.iter() { + if let Some(seq_str) = sequence.as_str() { + let (start, end) = get_start_and_end(seq_str)?; + for i in start..=end { + let seq = Sequence::from(i); + res.push(seq); + } + } else if let Some(seq) = sequence.as_integer() { + let seq = Sequence::from(seq as u64); + res.push(seq); + } + } + Ok(res) +} + +fn get_start_and_end(value: &str) -> Result<(u64, u64), ConfigError> { + let split: Vec<&str> = value.split('-').collect(); + let start: u64 = split + .first() + .ok_or_else(|| ConfigError::missing_start_excluded_sequence(value.to_string()))? + .parse() + .map_err(|e| ConfigError::parsing_start_excluded_sequence_failed(value.to_string(), e))?; + let end: u64 = split + .last() + .ok_or_else(|| ConfigError::missing_end_excluded_sequence(value.to_string()))? + .parse() + .map_err(|e| ConfigError::parsing_end_excluded_sequence_failed(value.to_string(), e))?; + + Ok((start, end)) +} diff --git a/crates/relayer/src/util/pretty.rs b/crates/relayer/src/util/pretty.rs index 0b433bd289..9561188fe0 100644 --- a/crates/relayer/src/util/pretty.rs +++ b/crates/relayer/src/util/pretty.rs @@ -16,7 +16,7 @@ use crate::event::IbcEventWithHeight; pub struct PrettyAny<'a>(pub &'a Any); -impl<'a> Display for PrettyAny<'a> { +impl Display for PrettyAny<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { write!(f, "Any {{ type_url: {} }}", self.0.type_url) } @@ -97,7 +97,7 @@ impl Display for PrettyDuration<'_> { /// For use in debug messages pub struct PrettyEvents<'a>(pub &'a [IbcEventWithHeight]); -impl<'a> Display for PrettyEvents<'a> { +impl Display for PrettyEvents<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { writeln!(f, "events:")?; for v in self.0 { @@ -180,7 +180,7 @@ impl Display for PrettyIdentifiedConnection<'_> { pub struct PrettyOption<'a, T>(pub &'a Option); -impl<'a, T: Display> Display for PrettyOption<'a, T> { +impl Display for PrettyOption<'_, T> { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { match &self.0 { Some(v) => write!(f, "{v}"), @@ -191,7 +191,7 @@ impl<'a, T: Display> Display for PrettyOption<'a, T> { pub struct PrettySlice<'a, T>(pub &'a [T]); -impl<'a, T: Display> Display for PrettySlice<'a, T> { +impl Display for PrettySlice<'_, T> { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { write!(f, "[ ")?; let mut vec_iterator = self.0.iter().peekable(); diff --git a/crates/relayer/src/util/profiling.rs b/crates/relayer/src/util/profiling.rs index c6310f95fc..7aabd06c75 100644 --- a/crates/relayer/src/util/profiling.rs +++ b/crates/relayer/src/util/profiling.rs @@ -8,7 +8,7 @@ use serde_derive::Serialize; use serde_json::Value; std::thread_local! { - pub static DEPTH: AtomicUsize = AtomicUsize::new(0); + pub static DEPTH: AtomicUsize = const { AtomicUsize::new(0) }; } static FILE: OnceCell> = OnceCell::new(); @@ -98,7 +98,6 @@ impl Drop for Timer { pub fn open_or_create_profile_file(file_name: &Path) { let file = OpenOptions::new() - .write(true) .append(true) .create(true) .open(file_name) diff --git a/crates/relayer/src/util/seq_range.rs b/crates/relayer/src/util/seq_range.rs index d569d156ef..229ab124e6 100644 --- a/crates/relayer/src/util/seq_range.rs +++ b/crates/relayer/src/util/seq_range.rs @@ -18,7 +18,7 @@ pub enum Error { /// - A range is specified as `start..end`, where `start` and `end` are sequence numbers. /// - If `start` is omitted, the range starts at the minimum sequence number. /// - If `end` is omitted, the range ends at the maximum sequence number. -/// - If both `start` and `end` are omitted, the range sastifies any sequence number. +/// - If both `start` and `end` are omitted, the range satisfies any sequence number. /// /// # Examples /// - `1` Single sequence number `1` @@ -39,7 +39,7 @@ pub fn parse_seq_ranges(s: &str) -> Result>, Error> /// - A range is specified as `start..end`, where `start` and `end` are sequence numbers. /// - If `start` is omitted, the range starts at the minimum sequence number. /// - If `end` is omitted, the range ends at the maximum sequence number.` -/// - If both `start` and `end` are omitted, the range sastifies any sequence number. +/// - If both `start` and `end` are omitted, the range satisfies any sequence number. /// /// # Examples /// - `1` Single sequence number `1` diff --git a/crates/relayer/src/worker.rs b/crates/relayer/src/worker.rs index 400ff811af..f2ef11f533 100644 --- a/crates/relayer/src/worker.rs +++ b/crates/relayer/src/worker.rs @@ -110,6 +110,12 @@ pub fn spawn_worker_tasks( (Some(cmd_tx), None) } Object::Packet(path) => { + let exclude_src_sequences = config + .find_chain(&chains.a.id()) + .map(|chain_config| chain_config.excluded_sequences(&path.src_channel_id)) + .unwrap_or_default() + .to_vec(); + let packets_config = config.mode.packets; let link_res = Link::new_from_opts( chains.a.clone(), @@ -119,6 +125,7 @@ pub fn spawn_worker_tasks( src_channel_id: path.src_channel_id.clone(), max_memo_size: packets_config.ics20_max_memo_size, max_receiver_size: packets_config.ics20_max_receiver_size, + exclude_src_sequences, }, packets_config.tx_confirmation, packets_config.auto_register_counterparty_payee, @@ -128,7 +135,7 @@ pub fn spawn_worker_tasks( Ok(link) => { let channel_ordering = link.a_to_b.channel().ordering; let should_clear_on_start = - packets_config.clear_on_start || channel_ordering == Ordering::Ordered; + should_clear_on_start(&packets_config, channel_ordering); let (cmd_tx, cmd_rx) = crossbeam_channel::unbounded(); let link = Arc::new(Mutex::new(link)); @@ -162,19 +169,31 @@ pub fn spawn_worker_tasks( let resubmit = Resubmit::from_clear_interval(clear_interval); + let (clear_cmd_tx, clear_cmd_rx) = crossbeam_channel::unbounded(); + let clear_task = packet::spawn_clear_cmd_worker( + cmd_rx, + link.clone(), + should_clear_on_start, + clear_interval, + config.mode.packets.clear_limit, + clear_cmd_tx, + ); + task_handles.push(clear_task); + // Only spawn the incentivized worker if a fee filter is specified in the configuration let packet_task = match fee_filter { Some(filter) => packet::spawn_incentivized_packet_cmd_worker( - cmd_rx, + clear_cmd_rx, link.clone(), path.clone(), filter, ), None => packet::spawn_packet_cmd_worker( - cmd_rx, + clear_cmd_rx, link.clone(), should_clear_on_start, clear_interval, + config.mode.packets.clear_limit, path.clone(), ), }; @@ -202,18 +221,34 @@ pub fn spawn_worker_tasks( } Object::CrossChainQuery(cross_chain_query) => { - let (cmd_tx, cmd_rx) = crossbeam_channel::unbounded(); - let cross_chain_query_task = cross_chain_query::spawn_cross_chain_query_worker( - chains.a.clone(), - chains.b, - cmd_rx, - cross_chain_query.clone(), - ); - task_handles.push(cross_chain_query_task); - - (Some(cmd_tx), None) + if config + .chains + .iter() + .any(|chain| chain.id() == &cross_chain_query.dst_chain_id && chain.allow_ccq()) + { + let (cmd_tx, cmd_rx) = crossbeam_channel::unbounded(); + let cross_chain_query_task = cross_chain_query::spawn_cross_chain_query_worker( + chains.a.clone(), + chains.b, + cmd_rx, + cross_chain_query.clone(), + ); + task_handles.push(cross_chain_query_task); + + (Some(cmd_tx), None) + } else { + (None, None) + } } }; WorkerHandle::new(id, object, data, cmd_tx, task_handles) } + +fn should_clear_on_start(config: &crate::config::Packets, channel_ordering: Ordering) -> bool { + if config.force_disable_clear_on_start { + false + } else { + config.clear_on_start || channel_ordering == Ordering::Ordered + } +} diff --git a/crates/relayer/src/worker/channel.rs b/crates/relayer/src/worker/channel.rs index df80e9252b..5c722cb262 100644 --- a/crates/relayer/src/worker/channel.rs +++ b/crates/relayer/src/worker/channel.rs @@ -1,7 +1,9 @@ use core::time::Duration; use crossbeam_channel::Receiver; -use tracing::{debug, error_span}; +use ibc_relayer_types::events::IbcEventType; +use tracing::{debug, error_span, warn}; +use crate::chain::requests::QueryHeight; use crate::channel::{channel_handshake_retry, Channel as RelayChannel}; use crate::util::retry::RetryResult; use crate::util::task::{spawn_background_task, Next, TaskError, TaskHandle}; @@ -34,6 +36,7 @@ pub fn spawn_channel_worker( cmd_rx: Receiver, ) -> TaskHandle { let mut complete_handshake_on_new_block = true; + spawn_background_task( error_span!("worker.channel", channel = %channel.short_name()), Some(Duration::from_millis(200)), @@ -48,20 +51,68 @@ pub fn spawn_channel_worker( debug!("starts processing {:?}", last_event); complete_handshake_on_new_block = false; + if let Some(event_with_height) = last_event { - retry_with_index( - channel_handshake_retry::default_strategy(max_block_times), - |index| match RelayChannel::restore_from_event( - chains.a.clone(), - chains.b.clone(), - event_with_height.event.clone(), - ) { - Ok(mut handshake_channel) => handshake_channel - .step_event(&event_with_height.event, index), - Err(_) => RetryResult::Retry(index), - }, - ) - .map_err(|e| TaskError::Fatal(RunError::retry(e))) + match event_with_height.event.event_type() { + IbcEventType::UpgradeInitChannel + | IbcEventType::UpgradeTryChannel + | IbcEventType::UpgradeAckChannel + | IbcEventType::UpgradeConfirmChannel + | IbcEventType::UpgradeOpenChannel + | IbcEventType::UpgradeTimeoutChannel => retry_with_index( + channel_handshake_retry::default_strategy(max_block_times), + |index| match RelayChannel::restore_from_state( + chains.a.clone(), + chains.b.clone(), + channel.clone(), + QueryHeight::Latest, + ) { + Ok((mut handshake_channel, state)) => { + handshake_channel.step_state(state, index) + } + Err(_) => RetryResult::Retry(index), + }, + ) + .map_err(|e| TaskError::Fatal(RunError::retry(e))), + + IbcEventType::UpgradeErrorChannel => retry_with_index( + channel_handshake_retry::default_strategy(max_block_times), + |index| match RelayChannel::restore_from_state( + chains.a.clone(), + chains.b.clone(), + channel.clone(), + QueryHeight::Latest, + ) { + Ok((handshake_channel, _)) => { + match handshake_channel + .build_chan_upgrade_cancel_and_send() + { + Ok(_) => RetryResult::Ok(Next::Abort), + Err(e) => { + warn!("Channel upgrade cancel failed: {e}"); + RetryResult::Retry(index) + } + } + } + Err(_) => RetryResult::Retry(index), + }, + ) + .map_err(|e| TaskError::Fatal(RunError::retry(e))), + + _ => retry_with_index( + channel_handshake_retry::default_strategy(max_block_times), + |index| match RelayChannel::restore_from_event( + chains.a.clone(), + chains.b.clone(), + event_with_height.event.clone(), + ) { + Ok(mut handshake_channel) => handshake_channel + .step_event(&event_with_height.event, index), + Err(_) => RetryResult::Retry(index), + }, + ) + .map_err(|e| TaskError::Fatal(RunError::retry(e))), + } } else { Ok(Next::Continue) } @@ -73,18 +124,15 @@ pub fn spawn_channel_worker( } if complete_handshake_on_new_block => { debug!("starts processing block event at {:#?}", current_height); - let height = current_height - .decrement() - .map_err(|e| TaskError::Fatal(RunError::ics02(e)))?; - complete_handshake_on_new_block = false; + retry_with_index( channel_handshake_retry::default_strategy(max_block_times), |index| match RelayChannel::restore_from_state( chains.a.clone(), chains.b.clone(), channel.clone(), - height, + QueryHeight::Latest, ) { Ok((mut handshake_channel, state)) => { handshake_channel.step_state(state, index) diff --git a/crates/relayer/src/worker/cross_chain_query.rs b/crates/relayer/src/worker/cross_chain_query.rs index 811bb14b36..29f1f69db6 100644 --- a/crates/relayer/src/worker/cross_chain_query.rs +++ b/crates/relayer/src/worker/cross_chain_query.rs @@ -8,6 +8,7 @@ use crate::error::Error; use crate::event::IbcEventWithHeight; use crate::foreign_client::ForeignClient; use crate::object::CrossChainQuery; +use crate::telemetry; use crate::util::task::{spawn_background_task, Next, TaskError, TaskHandle}; use crate::worker::WorkerCmd; @@ -74,6 +75,12 @@ fn handle_cross_chain_query( // Handle of queried chain has to query data from it's RPC info!("request: {}", cross_chain_query.short_name()); + telemetry!( + cross_chain_queries, + &cross_chain_query.src_chain_id, + &cross_chain_query.dst_chain_id, + queries.len() + ); let response = chain_b_handle.cross_chain_query(queries); if let Ok(cross_chain_query_responses) = response { // Run only when cross chain query response is not empty @@ -87,7 +94,7 @@ fn handle_cross_chain_query( }, IncludeProof::No, ) - .map_err(|_| TaskError::Fatal(RunError::query()))? + .map_err(|e| TaskError::Fatal(RunError::relayer(e)))? .0; // Retrieve client based on client id @@ -96,19 +103,21 @@ fn handle_cross_chain_query( chain_a_handle.clone(), connection_end.client_id(), ) - .map_err(|_| TaskError::Fatal(RunError::query()))?; + .map_err(|e| TaskError::Fatal(RunError::foreign_client(e)))?; let target_height = Height::new( chain_b_handle.id().version(), cross_chain_query_responses.first().unwrap().height as u64, ) - .map_err(|_| TaskError::Fatal(RunError::query()))? + .map_err(|e| TaskError::Fatal(RunError::ics02(e)))? .increment(); // Push update client msg let mut chain_a_msgs = client_a .wait_and_build_update_client(target_height) - .map_err(|_| TaskError::Fatal(RunError::query()))?; + .map_err(|e| TaskError::Fatal(RunError::foreign_client(e)))?; + + let num_cross_chain_query_responses = cross_chain_query_responses.len(); for response in cross_chain_query_responses { info!("response arrived: query_id: {}", response.query_id); @@ -118,18 +127,40 @@ fn handle_cross_chain_query( .try_to_any( chain_a_handle .get_signer() - .map_err(|_| TaskError::Fatal(RunError::query()))?, + .map_err(|e| TaskError::Fatal(RunError::relayer(e)))?, ) - .map_err(|_| TaskError::Fatal(RunError::query()))?, + .map_err(|e| TaskError::Fatal(RunError::ics31(e)))?, ); } - chain_a_handle + let ccq_responses = chain_a_handle .send_messages_and_wait_check_tx(TrackedMsgs::new_uuid( chain_a_msgs, Uuid::new_v4(), )) - .map_err(|_| TaskError::Ignore(RunError::query()))?; + .map_err(|e| { + // Since all the CCQs failed, generate a failure code for the telemetry + let failed_codes = + vec![tendermint::abci::Code::from(1); num_cross_chain_query_responses]; + telemetry!( + cross_chain_query_responses, + &cross_chain_query.dst_chain_id, + &cross_chain_query.src_chain_id, + failed_codes + ); + + TaskError::Ignore(RunError::relayer(e)) + })?; + + telemetry!( + cross_chain_query_responses, + &cross_chain_query.dst_chain_id, + &cross_chain_query.src_chain_id, + ccq_responses + .iter() + .map(|ccq_response| ccq_response.code) + .collect() + ); } } } diff --git a/crates/relayer/src/worker/error.rs b/crates/relayer/src/worker/error.rs index a694678539..e95b2290ed 100644 --- a/crates/relayer/src/worker/error.rs +++ b/crates/relayer/src/worker/error.rs @@ -1,9 +1,12 @@ use crossbeam_channel::RecvError; use flex_error::{define_error, DisplayOnly}; +use ibc_relayer_types::applications::ics31_icq::error::Error as Ics31Error; use ibc_relayer_types::core::ics02_client::error::Error as Ics02Error; use crate::channel::ChannelError; use crate::connection::ConnectionError; +use crate::error::Error as RelayerError; +use crate::foreign_client::ForeignClientError; use crate::link::error::LinkError; define_error! { @@ -12,6 +15,10 @@ define_error! { [ Ics02Error ] | _ | { "client error" }, + Ics31 + [ Ics31Error ] + | _ | { "cross chain query error" }, + Connection [ ConnectionError ] | _ | { "connection error" }, @@ -20,10 +27,18 @@ define_error! { [ ChannelError ] | _ | { "channel error" }, + ForeignClient + [ ForeignClientError ] + | _ | { "foreign client error" }, + Link [ LinkError ] | _ | { "link error" }, + Relayer + [ RelayerError ] + | _ | { "relayer error" }, + Retry { retries: retry::Error } | e | { format_args!("worker failed after {} retries", e.retries) }, @@ -31,8 +46,5 @@ define_error! { Recv [ DisplayOnly ] | _ | { "error receiving from channel: sender end has been closed" }, - - Query - | _ | { "error occurred during querying" } } } diff --git a/crates/relayer/src/worker/map.rs b/crates/relayer/src/worker/map.rs index c5305f52cb..eb498c8f69 100644 --- a/crates/relayer/src/worker/map.rs +++ b/crates/relayer/src/worker/map.rs @@ -252,7 +252,6 @@ impl Drop for WorkerMap { } } -#[cfg(feature = "telemetry")] fn metric_type(o: &Object) -> ibc_telemetry::state::WorkerType { use ibc_telemetry::state::WorkerType; diff --git a/crates/relayer/src/worker/packet.rs b/crates/relayer/src/worker/packet.rs index 2eb85f633c..fdfa0022e9 100644 --- a/crates/relayer/src/worker/packet.rs +++ b/crates/relayer/src/worker/packet.rs @@ -1,14 +1,8 @@ -#[cfg(feature = "telemetry")] -use { - ibc_relayer_types::core::ics24_host::identifier::ChannelId, - ibc_relayer_types::core::ics24_host::identifier::PortId, -}; - use core::time::Duration; use std::borrow::BorrowMut; use std::sync::{Arc, Mutex}; -use crossbeam_channel::Receiver; +use crossbeam_channel::{Receiver, Sender}; use itertools::Itertools; use moka::sync::Cache; use tracing::{debug, error, error_span, info, trace, warn}; @@ -17,14 +11,19 @@ use ibc_proto::ibc::apps::fee::v1::{IdentifiedPacketFees, QueryIncentivizedPacke use ibc_proto::ibc::core::channel::v1::PacketId; use ibc_relayer_types::applications::ics29_fee::events::IncentivizedPacket; use ibc_relayer_types::applications::transfer::{Amount, Coin, RawCoin}; +use ibc_relayer_types::core::ics04_channel::channel::Ordering; use ibc_relayer_types::core::ics04_channel::events::WriteAcknowledgement; use ibc_relayer_types::core::ics04_channel::packet::Sequence; +use ibc_relayer_types::core::ics24_host::identifier::ChannelId; +use ibc_relayer_types::core::ics24_host::identifier::PortId; use ibc_relayer_types::events::{IbcEvent, IbcEventType}; use ibc_relayer_types::Height; use crate::chain::handle::ChainHandle; +use crate::chain::requests::QueryHeight; use crate::config::filter::FeePolicy; use crate::event::source::EventBatch; +use crate::event::IbcEventWithHeight; use crate::foreign_client::HasExpiredOrFrozenError; use crate::link::Resubmit; use crate::link::{error::LinkError, Link}; @@ -84,6 +83,7 @@ pub fn spawn_packet_cmd_worker( link: Arc>>, mut should_clear_on_start: bool, clear_interval: u64, + clear_limit: usize, path: Packet, ) -> TaskHandle { let span = { @@ -118,6 +118,7 @@ pub fn spawn_packet_cmd_worker( &mut link.lock().unwrap(), &mut should_clear_on_start, clear_interval, + clear_limit, &path, cmd, )?; @@ -162,7 +163,7 @@ pub fn spawn_incentivized_packet_cmd_worker> = RwArc::new_lock( - moka::sync::Cache::builder() + Cache::builder() .time_to_live(INCENTIVIZED_CACHE_TTL) .max_capacity(INCENTIVIZED_CACHE_MAX_CAPACITY) .build(), @@ -183,13 +184,79 @@ pub fn spawn_incentivized_packet_cmd_worker( + cmd_rx: Receiver, + // Mutex is used to prevent race condition between the packet workers + link: Arc>>, + mut should_clear_on_start: bool, + clear_interval: u64, + clear_limit: usize, + clear_cmd_tx: Sender, +) -> TaskHandle { + let span = { + let relay_path = &link.lock().unwrap().a_to_b; + error_span!( + "worker.clear.cmd", + src_chain = %relay_path.src_chain().id(), + src_port = %relay_path.src_port_id(), + src_channel = %relay_path.src_channel_id(), + dst_chain = %relay_path.dst_chain().id(), + ) + }; + + let clear_cmd_worker_idle_timeout = if clear_interval > 0 { + clear_interval * 5 + } else { + IDLE_TIMEOUT_BLOCKS + }; + + let mut idle_worker_timer = 0; + + spawn_background_task(span, Some(Duration::from_millis(200)), move || { + if let Ok(cmd) = cmd_rx.try_recv() { + match clear_cmd_tx.send(cmd.clone()) { + Ok(_) => trace!("Successfully sent cmd to packet worker"), + Err(e) => { + error!("Failed to forward cmd from clear worker to packet worker. Cause: {e}") + } + } + let is_new_batch = cmd.is_ibc_events(); + + // Try to clear pending packets. At different levels down in `handle_clear_cmd` there + // are retries mechanisms for MAX_RETRIES (current value hardcoded at 5). + // If clearing fails after all these retries with ignorable error the task continues + // (see `handle_link_error_in_task`) and clearing is retried with the next + // (`NewBlock`) `cmd` that matches the clearing interval. + handle_clear_cmd( + &mut link.lock().unwrap(), + &mut should_clear_on_start, + clear_interval, + clear_limit, + cmd, + )?; + + if is_new_batch { + idle_worker_timer = 0; + trace!("clear worker processed an event batch, resetting idle timer"); + } else { + idle_worker_timer += 1; + trace!("clear worker has not processed an event batch after {idle_worker_timer} blocks, incrementing idle timer"); + } + + if idle_worker_timer > clear_cmd_worker_idle_timeout { + warn!("clear worker has been idle for more than {clear_cmd_worker_idle_timeout} blocks, aborting"); + + return Ok(Next::Abort); + } + } + + Ok(Next::Continue) + }) +} + /// Receives worker commands and handles them accordingly. /// -/// Given an `IbcEvent` command, updates the schedule and initiates -/// packet clearing if the `should_clear_on_start` flag has been toggled. -/// -/// Given a `NewBlock` command, checks if packet clearing should occur -/// and performs it if so. +/// Given an `IbcEvent` command, updates the schedule. /// /// Given a `ClearPendingPackets` command, clears pending packets. /// @@ -199,11 +266,60 @@ fn handle_packet_cmd( link: &mut Link, should_clear_on_start: &mut bool, clear_interval: u64, + clear_limit: usize, path: &Packet, cmd: WorkerCmd, +) -> Result<(), TaskError> { + // If the channel is Ordered, verify if clearing is required before proceeding + // to relaying. + match &cmd { + WorkerCmd::IbcEvents { batch } if link.a_to_b.channel().ordering == Ordering::Ordered => { + let lowest_sequence = lowest_sequence(&batch.events); + + let next_sequence = query_next_sequence_receive( + link.a_to_b.dst_chain(), + link.a_to_b.dst_port_id(), + link.a_to_b.dst_channel_id(), + QueryHeight::Specific(batch.height), + ) + .ok(); + + if *should_clear_on_start || next_sequence < lowest_sequence { + handle_clear_packet(link, clear_interval, path, Some(batch.height), clear_limit)?; + } + } + _ => {} + } + + // Handle command-specific task + if let WorkerCmd::IbcEvents { batch } = cmd { + handle_update_schedule(link, clear_interval, path, batch)?; + } + + Ok(()) +} + +/// Given an `IbcEvent` command, schedule packet clearing if the +/// `should_clear_on_start` flag has been toggled. +/// +/// Given a `NewBlock` command, checks if packet clearing should occur +/// and performs it if so. +fn handle_clear_cmd( + link: &mut Link, + should_clear_on_start: &mut bool, + clear_interval: u64, + clear_limit: usize, + cmd: WorkerCmd, ) -> Result<(), TaskError> { // Handle packet clearing which is triggered from a command let (do_clear, maybe_height) = match &cmd { + // Clearing for Ordered channels is handled by the packet_cmd_worker + WorkerCmd::IbcEvents { batch: _batch } + if link.a_to_b.channel().ordering == Ordering::Ordered => + { + (false, None) + } + WorkerCmd::IbcEvents { batch } => { if *should_clear_on_start { (true, Some(batch.height)) @@ -226,7 +342,7 @@ fn handle_packet_cmd( }; if do_clear { - info!("clearing packets"); + info!("packets clearing triggered, looking for packets to clear"); // Reset the `clear_on_start` flag and attempt packet clearing once now. // More clearing will be done at clear interval. @@ -234,12 +350,9 @@ fn handle_packet_cmd( *should_clear_on_start = false; } - handle_clear_packet(link, clear_interval, path, maybe_height)?; - } - - // Handle command-specific task - if let WorkerCmd::IbcEvents { batch } = cmd { - handle_update_schedule(link, clear_interval, path, batch)?; + link.a_to_b + .schedule_packet_clearing(maybe_height, clear_limit) + .map_err(handle_link_error_in_task)?; } Ok(()) @@ -360,7 +473,7 @@ fn retrieve_all_fees_from_incentivized_packet( incentivized_packet .total_recv_fee .iter() - .group_by(|a| &a.denom) + .chunk_by(|a| &a.denom) .into_iter() .map(|(key, group)| { let total_amount: Amount = group.map(|v| v.amount).sum::(); @@ -397,9 +510,10 @@ fn handle_clear_packet( clear_interval: u64, path: &Packet, height: Option, + clear_limit: usize, ) -> Result<(), TaskError> { link.a_to_b - .schedule_packet_clearing(height) + .schedule_packet_clearing(height, clear_limit) .map_err(handle_link_error_in_task)?; handle_execute_schedule(link, path, Resubmit::from_clear_interval(clear_interval)) @@ -439,10 +553,36 @@ fn handle_execute_schedule( Ok(()) } -#[cfg(feature = "telemetry")] +fn query_next_sequence_receive( + chain: &Chain, + port_id: &PortId, + channel_id: &ChannelId, + height: QueryHeight, +) -> Result { + use crate::chain::requests::{IncludeProof, QueryNextSequenceReceiveRequest}; + + chain + .query_next_sequence_receive( + QueryNextSequenceReceiveRequest { + port_id: port_id.clone(), + channel_id: channel_id.clone(), + height, + }, + IncludeProof::No, + ) + .map(|(seq, _height)| seq) + .map_err(|e| LinkError::query(chain.id(), e)) +} + +fn lowest_sequence(events: &[IbcEventWithHeight]) -> Option { + events + .iter() + .flat_map(|event| event.event.packet().map(|p| p.sequence)) + .min() +} + use crate::link::RelaySummary; -#[cfg(feature = "telemetry")] fn packet_metrics( path: &Packet, summary: &RelaySummary, @@ -454,7 +594,6 @@ fn packet_metrics( timeout_metrics(path, summary, dst_channel, dst_port); } -#[cfg(feature = "telemetry")] fn receive_packet_metrics( path: &Packet, summary: &RelaySummary, @@ -481,7 +620,6 @@ fn receive_packet_metrics( ); } -#[cfg(feature = "telemetry")] fn acknowledgment_metrics( path: &Packet, summary: &RelaySummary, @@ -508,7 +646,6 @@ fn acknowledgment_metrics( ); } -#[cfg(feature = "telemetry")] fn timeout_metrics( path: &Packet, summary: &RelaySummary, diff --git a/crates/relayer/tests/config/fixtures/relayer_conf_example.toml b/crates/relayer/tests/config/fixtures/relayer_conf_example.toml index f864efecda..6033872b07 100644 --- a/crates/relayer/tests/config/fixtures/relayer_conf_example.toml +++ b/crates/relayer/tests/config/fixtures/relayer_conf_example.toml @@ -39,7 +39,10 @@ max_tx_size = 1048576 clock_drift = '5s' trusting_period = '14days' trust_threshold = { numerator = '1', denominator = '3' } -address_type = { derivation = 'cosmos' } + +[chains.excluded_sequences] +channel-0 = [1, "3-5", 7, "9-12", 14, "17-19"] +channel-1 = ["3-6"] [chains.packet_filter] policy = 'allow' @@ -62,4 +65,5 @@ gas_price = { price = 0.001, denom = 'stake' } clock_drift = '5s' trusting_period = '14days' trust_threshold = { numerator = '1', denominator = '3' } -address_type = { derivation = 'ethermint', proto_type = { pk_type = '/injective.crypto.v1beta1.ethsecp256k1.PubKey' } } \ No newline at end of file +address_type = { derivation = 'ethermint', proto_type = { pk_type = '/injective.crypto.v1beta1.ethsecp256k1.PubKey' } } +excluded_sequences = { 'channel-0' = [1, 3, 4, 5, 7, 9, 10, 11, 12, 14, 17, 18, 19], 'channel-1' = [3, 4, 5, 6] } \ No newline at end of file diff --git a/crates/relayer/tests/config/fixtures/relayer_conf_example_invalid_excluded_sequences.toml b/crates/relayer/tests/config/fixtures/relayer_conf_example_invalid_excluded_sequences.toml new file mode 100644 index 0000000000..1e72497055 --- /dev/null +++ b/crates/relayer/tests/config/fixtures/relayer_conf_example_invalid_excluded_sequences.toml @@ -0,0 +1,68 @@ +[global] +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 +ics20_max_memo_size = { enabled = true, size = "32KiB" } +ics20_max_receiver_size = { enabled = true, size = "2KiB" } + +[[chains]] +type = "CosmosSdk" +id = 'chain_A' +rpc_addr = 'http://127.0.0.1:26657' +grpc_addr = 'http://127.0.0.1:9090' +event_source = { mode = 'push', url = 'ws://localhost:26657/websocket', batch_delay = '500ms' } +rpc_timeout = '10s' +account_prefix = 'cosmos' +key_name = 'testkey' +store_prefix = 'ibc' +max_gas = 200000 +gas_price = { price = 0.001, denom = 'stake' } +max_msg_num = 4 +max_tx_size = 1048576 +clock_drift = '5s' +trusting_period = '14days' +trust_threshold = { numerator = '1', denominator = '3' } +excluded_sequences = [ + ['channel-0', [1, 2, 3]], + ['channel-1', [4, 5, 6]] +] + +[chains.packet_filter] +policy = 'allow' +list = [ + ['ica*', '*'], + ['transfer', 'channel-0'], +] + +[[chains]] +type = "CosmosSdk" +id = 'chain_B' +rpc_addr = 'http://127.0.0.1:26557' +grpc_addr = 'http://127.0.0.1:9090' +event_source = { mode = 'push', url = 'ws://localhost:26557/websocket', batch_delay = '500ms' } +rpc_timeout = '10s' +account_prefix = 'cosmos' +key_name = 'testkey' +store_prefix = 'ibc' +gas_price = { price = 0.001, denom = 'stake' } +clock_drift = '5s' +trusting_period = '14days' +trust_threshold = { numerator = '1', denominator = '3' } +address_type = { derivation = 'ethermint', proto_type = { pk_type = '/injective.crypto.v1beta1.ethsecp256k1.PubKey' } } \ No newline at end of file diff --git a/crates/telemetry/Cargo.toml b/crates/telemetry/Cargo.toml index 60d3357d71..2a31d961f9 100644 --- a/crates/telemetry/Cargo.toml +++ b/crates/telemetry/Cargo.toml @@ -1,32 +1,29 @@ [package] name = "ibc-telemetry" -version = "0.27.0" +version = "0.29.5" edition = "2021" license = "Apache-2.0" readme = "README.md" keywords = ["cosmos", "ibc", "relayer", "telemetry"] repository = "https://github.com/informalsystems/hermes" authors = ["Informal Systems "] -rust-version = "1.71" +rust-version = "1.76.0" description = """ Telemetry service for the Hermes IBC relayer """ [dependencies] -ibc-relayer-types = { version = "0.27.0", path = "../relayer-types" } +ibc-relayer-types = { workspace = true } -once_cell = "1.19.0" -opentelemetry = { version = "0.19.0", features = ["metrics"] } -opentelemetry-prometheus = "0.12.0" -prometheus = "0.13.2" -moka = { version = "0.12.0", features = ["sync"] } -dashmap = "5.4.0" -serde_json = "1.0.111" -serde = "1.0.195" -axum = "0.6.18" -tokio = "1.26.0" -tracing = "0.1.36" - -[dependencies.tendermint] -version = "0.34.0" -default-features = false +axum = { workspace = true } +dashmap = { workspace = true } +moka = { workspace = true, features = ["sync"] } +once_cell = { workspace = true } +opentelemetry = { workspace = true, features = ["metrics"] } +opentelemetry-prometheus = { workspace = true } +prometheus = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +tendermint = { workspace = true } +tokio = { workspace = true } +tracing = { workspace = true } diff --git a/crates/telemetry/src/state.rs b/crates/telemetry/src/state.rs index bf48381d1f..136b414077 100644 --- a/crates/telemetry/src/state.rs +++ b/crates/telemetry/src/state.rs @@ -171,7 +171,7 @@ pub struct TelemetryState { backlog_oldest_sequence: ObservableGauge, /// Record the timestamp of the last time the `backlog_*` metrics have been updated. - /// The timestamp is the time passed since since the unix epoch in seconds. + /// The timestamp is the time passed since the unix epoch in seconds. backlog_latest_update_timestamp: ObservableGauge, /// Records the length of the backlog, i.e., how many packets are pending. @@ -201,6 +201,9 @@ pub struct TelemetryState { /// Number of errors observed by Hermes when broadcasting a Tx broadcast_errors: Counter, + /// Number of errors observed by Hermes when simulating a Tx + simulate_errors: Counter, + /// The EIP-1559 base fee queried dynamic_gas_queried_fees: ObservableGauge, @@ -212,6 +215,15 @@ pub struct TelemetryState { /// Number of ICS-20 packets filtered because the memo and/or the receiver fields were exceeding the configured limits filtered_packets: Counter, + + /// Observed ICS31 CrossChainQueries + cross_chain_queries: Counter, + + /// Observed ICS31 CrossChainQuery successful Responses + cross_chain_query_responses: Counter, + + /// Observed ICS31 CrossChainQuery error Responses + cross_chain_query_error_responses: Counter, } impl TelemetryState { @@ -394,6 +406,13 @@ impl TelemetryState { ) .init(), + simulate_errors: meter + .u64_counter("simulate_errors") + .with_description( + "Number of errors observed by Hermes when simulating a Tx", + ) + .init(), + dynamic_gas_queried_fees: meter .f64_observable_gauge("dynamic_gas_queried_fees") .with_description("The EIP-1559 base fee queried") @@ -405,7 +424,7 @@ impl TelemetryState { .init(), dynamic_gas_queried_success_fees: meter - .f64_observable_gauge("dynamic_gas_queried_fees") + .f64_observable_gauge("dynamic_gas_queried_success_fees") .with_description("The EIP-1559 base fee successfully queried") .init(), @@ -413,6 +432,21 @@ impl TelemetryState { .u64_counter("filtered_packets") .with_description("Number of ICS-20 packets filtered because the memo and/or the receiver fields were exceeding the configured limits") .init(), + + cross_chain_queries: meter + .u64_counter("cross_chain_queries") + .with_description("Number of ICS-31 queries received") + .init(), + + cross_chain_query_responses: meter + .u64_counter("cross_chain_query_responses") + .with_description("Number of ICS-31 successful query responses") + .init(), + + cross_chain_query_error_responses: meter + .u64_counter("cross_chain_query_error_responses") + .with_description("Number of ICS-31 error query responses") + .init(), } } @@ -1160,6 +1194,20 @@ impl TelemetryState { self.broadcast_errors.add(&cx, 1, labels); } + /// Add an error and its description to the list of errors observed after simulating + /// a Tx with a specific account. + pub fn simulate_errors(&self, address: &String, recoverable: bool, error_description: String) { + let cx = Context::current(); + + let labels = &[ + KeyValue::new("account", address.to_string()), + KeyValue::new("recoverable", recoverable.to_string()), + KeyValue::new("error_description", error_description.to_owned()), + ]; + + self.simulate_errors.add(&cx, 1, labels); + } + pub fn dynamic_gas_queried_fees(&self, chain_id: &ChainId, amount: f64) { let cx = Context::current(); @@ -1212,6 +1260,41 @@ impl TelemetryState { self.filtered_packets.add(&cx, count, labels); } } + + pub fn cross_chain_queries(&self, src_chain: &ChainId, dst_chain: &ChainId, count: usize) { + let cx = Context::current(); + + if count > 0 { + let labels = &[ + KeyValue::new("src_chain", src_chain.to_string()), + KeyValue::new("dst_chain", dst_chain.to_string()), + ]; + + self.cross_chain_queries.add(&cx, count as u64, labels); + } + } + + pub fn cross_chain_query_responses( + &self, + src_chain: &ChainId, + dst_chain: &ChainId, + ccq_responses_codes: Vec, + ) { + let cx = Context::current(); + + let labels = &[ + KeyValue::new("src_chain", src_chain.to_string()), + KeyValue::new("dst_chain", dst_chain.to_string()), + ]; + + for code in ccq_responses_codes.iter() { + if code.is_ok() { + self.cross_chain_query_responses.add(&cx, 1, labels); + } else { + self.cross_chain_query_error_responses.add(&cx, 1, labels); + } + } + } } use std::sync::Arc; diff --git a/docs/architecture/adr-002-ibc-relayer.md b/docs/architecture/adr-002-ibc-relayer.md index 983ff24805..0ed5e63439 100644 --- a/docs/architecture/adr-002-ibc-relayer.md +++ b/docs/architecture/adr-002-ibc-relayer.md @@ -45,12 +45,12 @@ IBC protocol defines the minimal data set that must be made available to relayer #### Query Functionality IBC host state machines MUST expose an interface for inspecting their state. For Cosmos/Tendermint chains this means: - the IBC modules on chain correctly implement and respond to queries - - [IBC-Modules-Rust] an implementation for some queries currently exist in Cosmos-SDK and same and more need to be implemented in Rust. The full requirements are detailed in section Relayer Queries. + - [IBC-Modules-Rust] an implementation for some queries currently exists in Cosmos-SDK and the same and more need to be implemented in Rust. The full requirements are detailed in section Relayer Queries. - the relayer needs the ability to send rpc/http ABCI queries to and receive replies from Tendermint/Cosmos-SDK - [[ABCI Rust](https://github.com/tendermint/rust-abci)] - ABCI Rust implementation - [IBC-Modules-Rust] identifier validation is required (ICS-024) - [IBC-Modules-Rust] requires Rust types for all query responses - - [[Merkle-Proofs-Rust](https://github.com/confio/ics23/tree/master/rust)] (candidate implementation) - some query responses include proofs and included in IBC transactions by the relayer (some may be validated, TBD) + - [[Merkle-Proofs-Rust](https://github.com/confio/ics23/tree/master/rust)] (candidate implementation) - some query responses include proofs and are included in IBC transactions by the relayer (some may be validated, TBD) #### IBC Messages The relayer creates transactions that include IBC messages to manage clients, connections and channels, and send application packets to destination chains. These messages must be defined in the IBC Rust implementation [IBC-Modules-Rust]. diff --git a/docs/architecture/adr-003-handler-implementation.md b/docs/architecture/adr-003-handler-implementation.md index e552f7672e..dc78a0f56d 100644 --- a/docs/architecture/adr-003-handler-implementation.md +++ b/docs/architecture/adr-003-handler-implementation.md @@ -369,7 +369,7 @@ to deal with chain-specific datatypes, such as `Header`, `ClientState`, and To abstract over chain-specific datatypes, we introduce a trait which specifies both which types we need to abstract over, and their interface. -For the ICS 002 Client submodule, this trait looks as follow: +For the ICS 002 Client submodule, this trait looks as follows: ```rust pub trait ClientDef { @@ -379,7 +379,7 @@ pub trait ClientDef { } ``` -The `ClientDef` trait specifies three datatypes, and their corresponding interface, which is provided +The `ClientDef` trait specifies three datatypes, and their corresponding interface, which are provided via a trait defined in the same submodule. A production implementation of this interface would instantiate these types with the concrete @@ -632,4 +632,4 @@ Proposed ### Neutral -## References \ No newline at end of file +## References diff --git a/docs/architecture/adr-004-relayer-domain-decomposition.md b/docs/architecture/adr-004-relayer-domain-decomposition.md index b97f376339..c65aa638a3 100644 --- a/docs/architecture/adr-004-relayer-domain-decomposition.md +++ b/docs/architecture/adr-004-relayer-domain-decomposition.md @@ -91,7 +91,7 @@ Channel datagrams are built similarly. Packet datagrams are triggered by events, ### IBC Module -For every a transaction in a block of height H: +For every transaction in a block of height H: - call appropriate handler (this is realized by ICS26 routing sub-module), - If handler succeeds (transaction does not abort), then @@ -236,7 +236,7 @@ fn main() -> Result<(), Box> { let src_chain = ChainRuntime::new(); let dst_chain = ChainRuntime::new(); - /// chains expose handlers for commuicating with the chain related runtime + /// chains expose handlers for communicating with the chain related runtime /// which move into their own threads let src_chain_handle = src_chain.handle(); thread::spawn(move || { diff --git a/docs/architecture/adr-005-relayer-v0-implementation.md b/docs/architecture/adr-005-relayer-v0-implementation.md index bc35c3e1f0..78d381ba7b 100644 --- a/docs/architecture/adr-005-relayer-v0-implementation.md +++ b/docs/architecture/adr-005-relayer-v0-implementation.md @@ -221,7 +221,7 @@ Accepted [comment](https://github.com/informalsystems/hermes/pull/449#issuecomment-750248113) provides additional insights into development-time relayer `v0.1` environment. -- __Mock__: Has been removed after splittin the ibc-rs repository +- __Mock__: Has been removed after splitting the ibc-rs repository diff --git a/docs/architecture/adr-006-hermes-v0.2-usecases.md b/docs/architecture/adr-006-hermes-v0.2-usecases.md index e6e6488fec..2b4bad5dc3 100644 --- a/docs/architecture/adr-006-hermes-v0.2-usecases.md +++ b/docs/architecture/adr-006-hermes-v0.2-usecases.md @@ -80,7 +80,7 @@ connection, or reuse a connection in the creation of a new channel). #### Patterns -We propose two basic patterns that Hermes should be able to fulfil. +We propose two basic patterns that Hermes should be able to fulfill. 1. Simple invocations to perform basic actions. - By _action_ here we mean doing the complete handshake for an object from diff --git a/docs/architecture/adr-008-ics20-implementation.md b/docs/architecture/adr-008-ics20-implementation.md index afbdaa1531..8c8d872f1d 100644 --- a/docs/architecture/adr-008-ics20-implementation.md +++ b/docs/architecture/adr-008-ics20-implementation.md @@ -195,7 +195,7 @@ pub fn on_timeout_packet(ctx: &Ctx, data: &FungibleTokenPacketData) -> Resu refund_packet_token(ctx, data) } -/// Responds to the the success or failure of a packet +/// Responds to the success or failure of a packet /// acknowledgement written on the receiving chain. If the acknowledgement /// was a success then nothing occurs. If the acknowledgement failed, then /// the sender is refunded their tokens. diff --git a/docs/spec/relayer/Definitions.md b/docs/spec/relayer/Definitions.md index 5d8830a717..ce3ad90b2f 100644 --- a/docs/spec/relayer/Definitions.md +++ b/docs/spec/relayer/Definitions.md @@ -224,7 +224,7 @@ CreateUpdateClientDatagrams(shs []SignedHeader) IBCDatagram[] // Submit given datagram to a given chain Submit(chain Chain, datagram IBCDatagram) Error -// Return the correspondin chain for a given chainID +// Return the corresponding chain for a given chainID // We assume that the relayer maintains a map of known chainIDs and the corresponding chains. GetChain(chainID String) Chain ``` diff --git a/e2e/e2e/channel.py b/e2e/e2e/channel.py index 0036ae7fa3..75b5d23dd8 100644 --- a/e2e/e2e/channel.py +++ b/e2e/e2e/channel.py @@ -472,15 +472,16 @@ def handshake( split() a_chan_end = query_channel_end(c, side_a, port_id, a_chan_id) - if a_chan_end.state != 'Open': + if str(a_chan_end.state) != 'Open': l.error( - f'Channel end with id {a_chan_id} on chain {side_a} is not in Open state, got: {a_chan_end.state}') + f"Channel end with id {a_chan_id} on chain {side_a} is not in `Open` state, got: {a_chan_end.state}") exit(1) b_chan_end = query_channel_end(c, side_b, port_id, b_chan_id) - if b_chan_end.state != 'Open': + print(b_chan_end.state) + if str(b_chan_end.state) != 'Open': l.error( - f'Channel end with id {b_chan_id} on chain {side_b} is not in Open state, got: {b_chan_end.state}') + f'Channel end with id {b_chan_id} on chain {side_b} is not in `Open` state, got: {b_chan_end.state}') exit(1) a_chan_ends = query_channel_ends(c, side_a, port_id, a_chan_id) diff --git a/flake.lock b/flake.lock index a0dbfb5653..5081f49548 100644 --- a/flake.lock +++ b/flake.lock @@ -3,7 +3,6 @@ "akash-src": { "flake": false, "locked": { - "lastModified": 1648485085, "narHash": "sha256-33FPy0dn6QuqneEqZYkFoCRm9agG7PE+9C/pYH9Gwx4=", "owner": "ovrclk", "repo": "akash", @@ -17,19 +16,35 @@ "type": "github" } }, + "andromeda-src": { + "flake": false, + "locked": { + "narHash": "sha256-8nKekKLBZR7nDNXZ1UL0J7YOMRv6HbzT7pj0W+fV+4U=", + "owner": "andromedaprotocol", + "repo": "andromedad", + "rev": "a72f010f8e3f9db183da0ddaf4ef65069b690981", + "type": "github" + }, + "original": { + "owner": "andromedaprotocol", + "ref": "andromeda-1", + "repo": "andromedad", + "type": "github" + } + }, "apalache-src": { "flake": false, "locked": { - "lastModified": 1692625213, - "narHash": "sha256-Z/tmBMv+QshFJLo2kBgBdkqfKwF93CgURVIbYF3dwJE=", + "lastModified": 1714996894, + "narHash": "sha256-3xw7bajvhGL+wGne4MRh/HpDFdp+HGfnfzqq8YSx9tc=", "owner": "informalsystems", "repo": "apalache", - "rev": "ec979d4554360faf9d73ddf72dccf350614076d5", + "rev": "5dee24e4d05dc3476977a2e49f4963e3802fae2f", "type": "github" }, "original": { "owner": "informalsystems", - "ref": "v0.42.0", + "ref": "v0.44.11", "repo": "apalache", "type": "github" } @@ -37,84 +52,101 @@ "beaker-src": { "flake": false, "locked": { - "lastModified": 1686823358, - "narHash": "sha256-bQiN5Q7RV4Uupc7rk1rGurRvCTy+5EiiB4p3bHct7M0=", + "narHash": "sha256-ZLDuTwB8PG0rMiDcLRxCf/xuoFowgK+aat9mSZVp+Dw=", "owner": "osmosis-labs", "repo": "beaker", - "rev": "f3c7a9fc6886aa2b4e0d259f70058d6c23c225e5", + "rev": "fc046f8fe9d8baecdd76404b57b31f5a4e100301", "type": "github" }, "original": { "owner": "osmosis-labs", - "ref": "v0.1.6", + "ref": "v0.1.8", "repo": "beaker", "type": "github" } }, - "celestia-src": { + "celestia-app-src": { "flake": false, "locked": { - "lastModified": 1700494564, - "narHash": "sha256-O6KrCStrZLmWy3xybQUNsWEb3O7vIRCFDE9MsEtsFro=", + "lastModified": 1722019080, + "narHash": "sha256-NN3O1nN+LTxDzYBzXjksfKl9DMCbFy+MsuxPBKgv9Dc=", "owner": "celestiaorg", "repo": "celestia-app", - "rev": "2dbfabf1849e166974c1287c35b43e5e07727643", + "rev": "b6db108a444c234e4b4656031d876bc45421c5f3", "type": "github" }, "original": { "owner": "celestiaorg", - "ref": "v1.4.0", + "ref": "v1.14.0", "repo": "celestia-app", "type": "github" } }, - "centauri-src": { + "celestia-node-src": { "flake": false, "locked": { - "lastModified": 1701431373, - "narHash": "sha256-EpZ1CQN0gMU8W1u3CMbqlaHeeVpQO2i1GPg6pOyOQTc=", - "owner": "ComposableFi", - "repo": "composable-cosmos", - "rev": "387c96b434db9d96b0506aa7f14536d9bdec968c", + "narHash": "sha256-O5a8Dy7WOSaLzYHTZAZFHFeJwqOLyajcHmGEcphOpKg=", + "owner": "celestiaorg", + "repo": "celestia-node", + "rev": "e55e1c88708b46839867bcbbed9bcdd8a3ffa830", "type": "github" }, "original": { - "owner": "ComposableFi", - "repo": "composable-cosmos", - "rev": "387c96b434db9d96b0506aa7f14536d9bdec968c", + "owner": "celestiaorg", + "ref": "v0.13.0", + "repo": "celestia-node", "type": "github" } }, "cometbft-src": { "flake": false, "locked": { - "lastModified": 1694550324, - "narHash": "sha256-G5gchJMn/BFzwYx8/ikPDL5fS/TuFIBF4DKJbkalp/M=", + "lastModified": 1723450629, + "narHash": "sha256-2QO4KeEUX4HHT1AKhEdPplJHjBhalfM11Dn3/urIVig=", "owner": "cometbft", "repo": "cometbft", - "rev": "66a5a9da9f7a3306f382eb9142ccb9c9f7997d3f", + "rev": "e1b4453baf0af6487ad187c7f17dc50517126673", "type": "github" }, "original": { "owner": "cometbft", - "ref": "v0.38.0", + "ref": "v0.38.11", "repo": "cometbft", "type": "github" } }, + "composable-cosmos-src": { + "flake": false, + "locked": { + "lastModified": 1710970443, + "narHash": "sha256-7h+vLGFxj2QvcTfXgHqS3pfnYzIzyf8DhO7adJKRe8c=", + "owner": "ComposableFi", + "repo": "composable-cosmos", + "rev": "a76ebd371059b778aa3e9799366b09e8453f114b", + "type": "github" + }, + "original": { + "owner": "ComposableFi", + "ref": "v6.4.88", + "repo": "composable-cosmos", + "type": "github" + } + }, "cosmos-nix": { "inputs": { "akash-src": "akash-src", + "andromeda-src": "andromeda-src", "apalache-src": "apalache-src", "beaker-src": "beaker-src", - "celestia-src": "celestia-src", - "centauri-src": "centauri-src", + "celestia-app-src": "celestia-app-src", + "celestia-node-src": "celestia-node-src", "cometbft-src": "cometbft-src", + "composable-cosmos-src": "composable-cosmos-src", "cosmos-sdk-src": "cosmos-sdk-src", "cosmwasm-src": "cosmwasm-src", - "crescent-src": "crescent-src", "cw-plus-src": "cw-plus-src", "dydx-src": "dydx-src", + "dymension-src": "dymension-src", "evmos-src": "evmos-src", "flake-parts": "flake-parts", "gaia-main-src": "gaia-main-src", @@ -123,6 +155,11 @@ "gaia12-src": "gaia12-src", "gaia13-src": "gaia13-src", "gaia14-src": "gaia14-src", + "gaia15-src": "gaia15-src", + "gaia17-src": "gaia17-src", + "gaia18-src": "gaia18-src", + "gaia19-src": "gaia19-src", + "gaia20-src": "gaia20-src", "gaia5-src": "gaia5-src", "gaia6-ordered-src": "gaia6-ordered-src", "gaia6-src": "gaia6-src", @@ -131,6 +168,7 @@ "gaia9-src": "gaia9-src", "gex-src": "gex-src", "gomod2nix": "gomod2nix", + "haqq-src": "haqq-src", "hermes-src": "hermes-src", "ibc-go-v2-src": "ibc-go-v2-src", "ibc-go-v3-src": "ibc-go-v3-src", @@ -138,11 +176,14 @@ "ibc-go-v5-src": "ibc-go-v5-src", "ibc-go-v6-src": "ibc-go-v6-src", "ibc-go-v7-src": "ibc-go-v7-src", - "ibc-go-v8-channel-upgrade-src": "ibc-go-v8-channel-upgrade-src", + "ibc-go-v7-wasm-src": "ibc-go-v7-wasm-src", "ibc-go-v8-src": "ibc-go-v8-src", + "ibc-go-v8-wasm-src": "ibc-go-v8-wasm-src", + "ibc-go-v9-src": "ibc-go-v9-src", "ibc-rs-src": "ibc-rs-src", "ica-src": "ica-src", "ignite-cli-src": "ignite-cli-src", + "injective-src": "injective-src", "interchain-security-src": "interchain-security-src", "iris-src": "iris-src", "ixo-src": "ixo-src", @@ -151,38 +192,47 @@ "namada-src": "namada-src", "neutron-src": "neutron-src", "nix-std": "nix-std", + "nix2container": "nix2container", "nixpkgs": "nixpkgs_2", "osmosis-src": "osmosis-src", "provenance-src": "provenance-src", "regen-src": "regen-src", "relayer-src": "relayer-src", + "rollapp-evm-src": "rollapp-evm-src", "rust-overlay": "rust-overlay", "sbt-derivation": "sbt-derivation", "sconfig-src": "sconfig-src", "sentinel-src": "sentinel-src", "sifchain-src": "sifchain-src", + "slinky-src": "slinky-src", "stargaze-src": "stargaze-src", "stoml-src": "stoml-src", - "stride-consumer-src": "stride-consumer-src", "stride-src": "stride-src", "umee-src": "umee-src", "wasmd-src": "wasmd-src", - "wasmd_next-src": "wasmd_next-src", "wasmvm_1-src": "wasmvm_1-src", "wasmvm_1_1_1-src": "wasmvm_1_1_1-src", "wasmvm_1_1_2-src": "wasmvm_1_1_2-src", "wasmvm_1_2_3-src": "wasmvm_1_2_3-src", "wasmvm_1_2_4-src": "wasmvm_1_2_4-src", + "wasmvm_1_2_6-src": "wasmvm_1_2_6-src", "wasmvm_1_3_0-src": "wasmvm_1_3_0-src", "wasmvm_1_5_0-src": "wasmvm_1_5_0-src", - "wasmvm_1_beta7-src": "wasmvm_1_beta7-src" - }, - "locked": { - "lastModified": 1705315275, - "narHash": "sha256-XnjvjdTdXkwWFWx1nRflbsDyazSBV09QOmr/aiAuZ1M=", + "wasmvm_1_5_2-src": "wasmvm_1_5_2-src", + "wasmvm_1_5_4-src": "wasmvm_1_5_4-src", + "wasmvm_1_5_5-src": "wasmvm_1_5_5-src", + "wasmvm_1_beta7-src": "wasmvm_1_beta7-src", + "wasmvm_2_0_0-src": "wasmvm_2_0_0-src", + "wasmvm_2_0_3-src": "wasmvm_2_0_3-src", + "wasmvm_2_1_0-src": "wasmvm_2_1_0-src", + "wasmvm_2_1_2-src": "wasmvm_2_1_2-src" + }, + "locked": { + "lastModified": 1729681912, + "narHash": "sha256-Ym4WfC/Iogqft2KOoHEv2FlWlgsxOAA5CZCbGXPf65o=", "owner": "informalsystems", "repo": "cosmos.nix", - "rev": "04ef5159b4262b7dd445544838468a84a1d987cf", + "rev": "04a2efd0e01206b5df601b205d7662db79a765f0", "type": "github" }, "original": { @@ -194,7 +244,6 @@ "cosmos-sdk-src": { "flake": false, "locked": { - "lastModified": 1658846655, "narHash": "sha256-Xs83vbgt4+YH2LRJx7692nIjRBr5QCYoUHI17njsjlw=", "owner": "cosmos", "repo": "cosmos-sdk", @@ -211,41 +260,22 @@ "cosmwasm-src": { "flake": false, "locked": { - "lastModified": 1698745412, - "narHash": "sha256-41s5jLFzw9Jo+dirAVOad1dtUqCBY6rIz/6TRc0frMw=", + "narHash": "sha256-F+INGtJZj272HZkj/lUPlskNqAPe9x5itNYXCQsezkA=", "owner": "CosmWasm", "repo": "cosmwasm", - "rev": "89891f0bb2de2c83d00600208695d0d5e1b617ac", + "rev": "3c33a0a5dfa5d1c30f474011c77117ec3bf4dc04", "type": "github" }, "original": { "owner": "CosmWasm", - "ref": "v1.5.0", + "ref": "v1.5.3", "repo": "cosmwasm", "type": "github" } }, - "crescent-src": { - "flake": false, - "locked": { - "lastModified": 1647869429, - "narHash": "sha256-c1xiTB/HgtQJSwD3ccFQIoSHPbJK6rf1nSjnM3r0oCE=", - "owner": "crescent-network", - "repo": "crescent", - "rev": "01980cfd06b06786109eaba78c154e6db1adc3d6", - "type": "github" - }, - "original": { - "owner": "crescent-network", - "ref": "v1.0.0-rc3", - "repo": "crescent", - "type": "github" - } - }, "cw-plus-src": { "flake": false, "locked": { - "lastModified": 1700757493, "narHash": "sha256-E5vkY+B4BDoTDtvuB+7Tm3k/5dCYPSjUujMWcgYsWf0=", "owner": "CosmWasm", "repo": "cw-plus", @@ -259,10 +289,33 @@ "type": "github" } }, + "devenv": { + "inputs": { + "flake-compat": "flake-compat", + "nix": "nix", + "nixpkgs": [ + "cosmos-nix", + "haqq-src", + "nixpkgs-unstable" + ], + "pre-commit-hooks": "pre-commit-hooks" + }, + "locked": { + "narHash": "sha256-NLvhvXBmX+WuqDN9PbRbQCsA+y57yGaf+jCWuJVdaIQ=", + "owner": "cachix", + "repo": "devenv", + "rev": "0c41b86406e910a75fbde28f81ec7f6fda74f7e1", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "devenv", + "type": "github" + } + }, "dydx-src": { "flake": false, "locked": { - "lastModified": 1702405483, "narHash": "sha256-NiC+Nol8Cye0z/U5cgQ+zhvlbDJX6DouaMo8oYsRGDQ=", "owner": "dydxprotocol", "repo": "v4-chain", @@ -276,10 +329,25 @@ "type": "github" } }, + "dymension-src": { + "flake": false, + "locked": { + "narHash": "sha256-K1F0kL4/HVxOJvXNvLJsZUFXS3MyuqrUotyyd5u6QTQ=", + "owner": "dymensionxyz", + "repo": "dymension", + "rev": "c3294dc8d2dce1aa8efbc967b1dfd3b0e965b095", + "type": "github" + }, + "original": { + "owner": "dymensionxyz", + "ref": "v3.0.0", + "repo": "dymension", + "type": "github" + } + }, "evmos-src": { "flake": false, "locked": { - "lastModified": 1702504794, "narHash": "sha256-ECXXQ0hx/MXascMP6aXf880zts/dNPpQM9jOCIHTLZQ=", "owner": "evmos", "repo": "evmos", @@ -293,12 +361,26 @@ "type": "github" } }, + "flake-compat": { + "flake": false, + "locked": { + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, "flake-parts": { "inputs": { "nixpkgs-lib": "nixpkgs-lib" }, "locked": { - "lastModified": 1701473968, "narHash": "sha256-YcVE5emp1qQ8ieHUnxt1wCZCC3ZfAS+SRRWZ2TMda7E=", "owner": "hercules-ci", "repo": "flake-parts", @@ -334,11 +416,10 @@ "systems": "systems_2" }, "locked": { - "lastModified": 1681202837, - "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", + "narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=", "owner": "numtide", "repo": "flake-utils", - "rev": "cfacdce06f30d2b68473a46042957675eebb3401", + "rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef", "type": "github" }, "original": { @@ -348,12 +429,14 @@ } }, "flake-utils_3": { + "inputs": { + "systems": "systems_3" + }, "locked": { - "lastModified": 1667395993, - "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", + "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", "owner": "numtide", "repo": "flake-utils", - "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", + "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", "type": "github" }, "original": { @@ -364,7 +447,25 @@ }, "flake-utils_4": { "inputs": { - "systems": "systems_3" + "systems": "systems_4" + }, + "locked": { + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_5": { + "inputs": { + "systems": "systems_5" }, "locked": { "lastModified": 1705309234, @@ -380,10 +481,41 @@ "type": "github" } }, + "flake-utils_6": { + "locked": { + "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_7": { + "inputs": { + "systems": "systems_6" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, "gaia-main-src": { "flake": false, "locked": { - "lastModified": 1702388853, "narHash": "sha256-1O8ncSd0mUNEUHSTi2U9d21Dv1yszQKohjp/AS6IxcU=", "owner": "cosmos", "repo": "gaia", @@ -399,7 +531,6 @@ "gaia10-src": { "flake": false, "locked": { - "lastModified": 1688401730, "narHash": "sha256-F72AxDI1OdleE8If5s4HJbORqMsDVsdEO5q7nrK07E8=", "owner": "cosmos", "repo": "gaia", @@ -416,7 +547,6 @@ "gaia11-src": { "flake": false, "locked": { - "lastModified": 1690464504, "narHash": "sha256-bIegGSPDdDRbznfgsrojsGCwCPSesNknpffTFskc7fE=", "owner": "cosmos", "repo": "gaia", @@ -433,7 +563,6 @@ "gaia12-src": { "flake": false, "locked": { - "lastModified": 1692870038, "narHash": "sha256-KqpkazhGGQWzvHiiwCiE7ciA8+L2t2HgxN8270zuGd0=", "owner": "cosmos", "repo": "gaia", @@ -450,7 +579,6 @@ "gaia13-src": { "flake": false, "locked": { - "lastModified": 1699370179, "narHash": "sha256-bvJ33JL1Fr7ilnnYEjrjnbS/dbFkyhZ2uq6u39CeTa0=", "owner": "cosmos", "repo": "gaia", @@ -467,7 +595,6 @@ "gaia14-src": { "flake": false, "locked": { - "lastModified": 1700067649, "narHash": "sha256-7AnaIy/SElf/Uj2xTbHzLSgPY68SgQqqJZ2BPmt6czo=", "owner": "cosmos", "repo": "gaia", @@ -481,10 +608,94 @@ "type": "github" } }, + "gaia15-src": { + "flake": false, + "locked": { + "lastModified": 1712522710, + "narHash": "sha256-2LsF++HkbVpX9h4DgkNea5nnyEuhDQSlNOAICdhAggU=", + "owner": "cosmos", + "repo": "gaia", + "rev": "7281c9b9dc4e3087ee87f5b24e416802b52e8661", + "type": "github" + }, + "original": { + "owner": "cosmos", + "ref": "v15.2.0", + "repo": "gaia", + "type": "github" + } + }, + "gaia17-src": { + "flake": false, + "locked": { + "lastModified": 1717626378, + "narHash": "sha256-FiCnGz5ZQQv2NyPW/Z7puZw6oFKcdoNsspSCK8Nkc44=", + "owner": "cosmos", + "repo": "gaia", + "rev": "17f2ba0b90d1d2884f7b67518ec08dfd37f001a7", + "type": "github" + }, + "original": { + "owner": "cosmos", + "ref": "v17.2.0", + "repo": "gaia", + "type": "github" + } + }, + "gaia18-src": { + "flake": false, + "locked": { + "lastModified": 1720430036, + "narHash": "sha256-wATunCFeMgCP9usv2TK/IKDGZIWfOKx2zWip5qWDuqk=", + "owner": "cosmos", + "repo": "gaia", + "rev": "58b4e54a95c7fc6a64272ccd0f09f46213c005ad", + "type": "github" + }, + "original": { + "owner": "cosmos", + "ref": "v18.1.0", + "repo": "gaia", + "type": "github" + } + }, + "gaia19-src": { + "flake": false, + "locked": { + "lastModified": 1724235134, + "narHash": "sha256-iAljnCnviTZ0wpgUYtTj+adH6imx6g6+niLq72yuoTk=", + "owner": "cosmos", + "repo": "gaia", + "rev": "4106e7a673da18b518fd81231a8e8b99bbf0fd0d", + "type": "github" + }, + "original": { + "owner": "cosmos", + "ref": "v19.1.0", + "repo": "gaia", + "type": "github" + } + }, + "gaia20-src": { + "flake": false, + "locked": { + "lastModified": 1726853009, + "narHash": "sha256-N7x3k56AtPbIbbJjqKmlEJIytKElALJwj14lZ2pewZg=", + "owner": "cosmos", + "repo": "gaia", + "rev": "2dba9d471ef73b0a99e844bf55a44ddae700ea06", + "type": "github" + }, + "original": { + "owner": "cosmos", + "ref": "v20.0.0", + "repo": "gaia", + "type": "github" + } + }, "gaia5-src": { "flake": false, "locked": { - "lastModified": 1634231239, "narHash": "sha256-NfR9GRBNBlm5hB3lFea+Vlf4dkapZIZg0sZuyOX2cn8=", "owner": "cosmos", "repo": "gaia", @@ -501,7 +712,6 @@ "gaia6-ordered-src": { "flake": false, "locked": { - "lastModified": 1648034337, "narHash": "sha256-yw3WUCLRvn46xlWAnk6nBmvc3T91aryvBcOOfJ2ocPA=", "owner": "informalsystems", "repo": "gaia", @@ -518,7 +728,6 @@ "gaia6-src": { "flake": false, "locked": { - "lastModified": 1646904235, "narHash": "sha256-JdD0DTdMo05ggGvpHN5hugEEtGA0/WQ4bhbryDlfGXo=", "owner": "cosmos", "repo": "gaia", @@ -535,7 +744,6 @@ "gaia7-src": { "flake": false, "locked": { - "lastModified": 1665762684, "narHash": "sha256-hsDqDASwTPIb1BGOqa9nu4C5Y5q3hBoXYhkAFY7B9Cs=", "owner": "cosmos", "repo": "gaia", @@ -552,7 +760,6 @@ "gaia8-src": { "flake": false, "locked": { - "lastModified": 1676667875, "narHash": "sha256-8XPcJRQEQDtTbGFg0pWexkNdWESn1FoKvz4T2Z8UPDw=", "owner": "cosmos", "repo": "gaia", @@ -569,7 +776,6 @@ "gaia9-src": { "flake": false, "locked": { - "lastModified": 1681924944, "narHash": "sha256-UIM6yfqs1yZZ2BO/bBB43pPYSW1IzaYsk2f500tDYzA=", "owner": "cosmos", "repo": "gaia", @@ -586,7 +792,6 @@ "gex-src": { "flake": false, "locked": { - "lastModified": 1697704475, "narHash": "sha256-lgJVxn7Q2I8TBdvbzyn7bl1MN5StEw3NvRzCvBFFuB8=", "owner": "cosmos", "repo": "gex", @@ -600,30 +805,103 @@ "type": "github" } }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "cosmos-nix", + "haqq-src", + "devenv", + "pre-commit-hooks", + "nixpkgs" + ] + }, + "locked": { + "narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "a20de23b925fd8264fd7fad6454652e142fd7f73", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, "gomod2nix": { "inputs": { "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs" + "nixpkgs": [ + "cosmos-nix", + "nixpkgs" + ] }, "locked": { - "lastModified": 1702956934, - "narHash": "sha256-f1NuMA2mZ3Chw2CjlUkRAzNgDw0TYyj1i5YZJRByDdo=", - "owner": "JonathanLorimer", + "lastModified": 1722589758, + "narHash": "sha256-sbbA8b6Q2vB/t/r1znHawoXLysCyD4L/6n6/RykiSnA=", + "owner": "nix-community", + "repo": "gomod2nix", + "rev": "4e08ca09253ef996bd4c03afa383b23e35fe28a1", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "gomod2nix", + "type": "github" + } + }, + "gomod2nix_2": { + "inputs": { + "flake-utils": [ + "cosmos-nix", + "haqq-src", + "flake-utils" + ], + "nixpkgs": [ + "cosmos-nix", + "haqq-src", + "nixpkgs-unstable" + ] + }, + "locked": { + "narHash": "sha256-yfQQ67dLejP0FLK76LKHbkzcQqNIrux6MFe32MMFGNQ=", + "owner": "nix-community", "repo": "gomod2nix", - "rev": "6d2fce6003d08eee42648f2931de8449d3de1f5f", + "rev": "30e3c3a9ec4ac8453282ca7f67fca9e1da12c3e6", "type": "github" }, "original": { - "owner": "JonathanLorimer", - "ref": "jonathan/update-go", + "owner": "nix-community", + "ref": "master", "repo": "gomod2nix", "type": "github" } }, + "haqq-src": { + "inputs": { + "devenv": "devenv", + "flake-utils": "flake-utils_3", + "gomod2nix": "gomod2nix_2", + "nixpkgs": "nixpkgs", + "nixpkgs-unstable": "nixpkgs-unstable" + }, + "locked": { + "narHash": "sha256-pXbLGvq6ZyZbtKYoe8GbgaxGV0SIbARrT6DkDmPwlYE=", + "owner": "haqq-network", + "repo": "haqq", + "rev": "18370cfb2f9aab35d311c4c75ab5586f50213830", + "type": "github" + }, + "original": { + "owner": "haqq-network", + "repo": "haqq", + "rev": "18370cfb2f9aab35d311c4c75ab5586f50213830", + "type": "github" + } + }, "hermes-src": { "flake": false, "locked": { - "lastModified": 1702629809, "narHash": "sha256-JTZMp4By/pGsMdKzfi4H1LQS1RKYQHBq5NEju5ADX/s=", "owner": "informalsystems", "repo": "hermes", @@ -640,7 +918,6 @@ "ibc-go-v2-src": { "flake": false, "locked": { - "lastModified": 1663274791, "narHash": "sha256-LuJvlXmGRyJAiM6+uk+NuamjIsEqMqF20twBmB0p8+k=", "owner": "cosmos", "repo": "ibc-go", @@ -657,7 +934,6 @@ "ibc-go-v3-src": { "flake": false, "locked": { - "lastModified": 1663683283, "narHash": "sha256-Er24B1unLYR/gG4JSrV+vZ/cPD6t7OFvtqp7AJCtDSE=", "owner": "cosmos", "repo": "ibc-go", @@ -674,16 +950,16 @@ "ibc-go-v4-src": { "flake": false, "locked": { - "lastModified": 1667809128, - "narHash": "sha256-R1/AH6laXdaMftgwnV4t/pL3QoKnZ1UaBGoqOipOvQI=", + "lastModified": 1712304740, + "narHash": "sha256-CNv3uBCALT21ZczOmXcQaavOy7KsR0VTBahw5DrvO4w=", "owner": "cosmos", "repo": "ibc-go", - "rev": "ecb845d5e43f53decf48f8ed88c7847a9a4375cb", + "rev": "5480cf7fac99882a8833ddb7c95e8b4820ab7d4f", "type": "github" }, "original": { "owner": "cosmos", - "ref": "v4.2.0", + "ref": "v4.6.0", "repo": "ibc-go", "type": "github" } @@ -691,16 +967,16 @@ "ibc-go-v5-src": { "flake": false, "locked": { - "lastModified": 1668024626, - "narHash": "sha256-+Z78PyGODLr2Y5G8evubsoQE3tyUcxCHJDsLXKTmdlI=", + "lastModified": 1712304845, + "narHash": "sha256-CE6Nv6U3Jqn4c+5JB/rek9LHD+AXEnkS0FVJYz4/uSc=", "owner": "cosmos", "repo": "ibc-go", - "rev": "c0acd5bd1778f2b7ecdf593006f56bd3e273bd49", + "rev": "40cacfe075947f21520b014294f1f7948e4eda7c", "type": "github" }, "original": { "owner": "cosmos", - "ref": "v5.1.0", + "ref": "v5.4.0", "repo": "ibc-go", "type": "github" } @@ -708,16 +984,16 @@ "ibc-go-v6-src": { "flake": false, "locked": { - "lastModified": 1671525236, - "narHash": "sha256-V8kUNwgNfx1tZJazlnaTF6wBb7ztueh1KrAGgiP8hCM=", + "lastModified": 1713970631, + "narHash": "sha256-MpBZ/V8agG3/GFJXEY3kSp+FnUw8rX5C613l5D8HXs4=", "owner": "cosmos", "repo": "ibc-go", - "rev": "d34cef7e075dda1a24a0a3e9b6d3eff406cc606c", + "rev": "8cd96f4169ebee21d50ef69417203b21cf4238ab", "type": "github" }, "original": { "owner": "cosmos", - "ref": "v6.1.0", + "ref": "v6.3.1", "repo": "ibc-go", "type": "github" } @@ -725,33 +1001,33 @@ "ibc-go-v7-src": { "flake": false, "locked": { - "lastModified": 1693509694, - "narHash": "sha256-umh/ckDALt0ugXwN8glcaCkGfAQvXY7S3Jd95Do2XeA=", + "lastModified": 1725009574, + "narHash": "sha256-6Wpxu4mQaSrQKOLSb3kUpzRrr0aIHVMVEHVwpGJw3sM=", "owner": "cosmos", "repo": "ibc-go", - "rev": "c75650a1a037a9fecba5a9005df380f707520ff7", + "rev": "a5dde80a4ba1c4601aa055a311bf46779104627f", "type": "github" }, "original": { "owner": "cosmos", - "ref": "v7.3.0", + "ref": "v7.8.0", "repo": "ibc-go", "type": "github" } }, - "ibc-go-v8-channel-upgrade-src": { + "ibc-go-v7-wasm-src": { "flake": false, "locked": { - "lastModified": 1703189903, - "narHash": "sha256-vxzv+b40TKqCIN4FAkeIu+jmlPP5XRLR+P0uEIjr7AE=", + "lastModified": 1722365763, + "narHash": "sha256-ZYGCvm1Ek1RaXKzkkwQCc56I2HzmbrLR/lFD5IZZdLc=", "owner": "cosmos", "repo": "ibc-go", - "rev": "7a89e5d5b5ebb7643ce3992c34008c35373ecf34", + "rev": "13c071f0b34d67342f0b7a8874d84d2e68b887e1", "type": "github" }, "original": { "owner": "cosmos", - "ref": "04-channel-upgrades-rc.0", + "ref": "modules/light-clients/08-wasm/v0.3.1+ibc-go-v7.4-wasmvm-v1.5", "repo": "ibc-go", "type": "github" } @@ -759,16 +1035,50 @@ "ibc-go-v8-src": { "flake": false, "locked": { - "lastModified": 1699602904, - "narHash": "sha256-BcP3y874QviVsV+04p9CioolyvmWH82ORbb5EB2GyRI=", + "lastModified": 1726232417, + "narHash": "sha256-oIfVmXIOkRqDF4NGmHsh5BELCIzPydAqiz+7urnZ7A4=", "owner": "cosmos", "repo": "ibc-go", - "rev": "2551dea41cd3c512845007ca895c8402afa9b79f", + "rev": "6b2554360c0e3f0bbaa59da5b16b29fc05675c57", "type": "github" }, "original": { "owner": "cosmos", - "ref": "v8.0.0", + "ref": "v8.5.1", + "repo": "ibc-go", + "type": "github" + } + }, + "ibc-go-v8-wasm-src": { + "flake": false, + "locked": { + "lastModified": 1722365433, + "narHash": "sha256-mgfbibipk09LtO0h0hQDfnVA0cQADaI6Bq+ruyP6xI4=", + "owner": "cosmos", + "repo": "ibc-go", + "rev": "ccd4dc278e720be87418028026ebd93a80fa5ac0", + "type": "github" + }, + "original": { + "owner": "cosmos", + "ref": "modules/light-clients/08-wasm/v0.4.1+ibc-go-v8.4-wasmvm-v2.0", + "repo": "ibc-go", + "type": "github" + } + }, + "ibc-go-v9-src": { + "flake": false, + "locked": { + "lastModified": 1725262239, + "narHash": "sha256-F2p/lIs2/ropKdm0Pebz1kjhRlgwYK0BmDGe/sYec3Y=", + "owner": "cosmos", + "repo": "ibc-go", + "rev": "8983f91e519fb1c43d9c9481ba60f11e4ae2b2b0", + "type": "github" + }, + "original": { + "owner": "cosmos", + "ref": "v9.0.0-rc.0", "repo": "ibc-go", "type": "github" } @@ -776,7 +1086,6 @@ "ibc-rs-src": { "flake": false, "locked": { - "lastModified": 1661171856, "narHash": "sha256-M9KsPQdvyTArDe3sTi29+gfs69KHtpoNYLgI7IHYo9U=", "owner": "informalsystems", "repo": "ibc-rs", @@ -793,7 +1102,6 @@ "ica-src": { "flake": false, "locked": { - "lastModified": 1695202199, "narHash": "sha256-8RwZSnqqZzVjQsSMTckNhmTy3VYyubVmgE/hU6ntq9M=", "owner": "cosmos", "repo": "interchain-accounts-demo", @@ -823,19 +1131,36 @@ "type": "github" } }, + "injective-src": { + "flake": false, + "locked": { + "lastModified": 1722874193, + "narHash": "sha256-zDG32ogXMep0wKegDN8zm1YmadcVpwlrY+ITokefcVI=", + "owner": "OpenDeFiFoundation", + "repo": "injective-core", + "rev": "725af8f9ca6809d6b1026d5e8dddeb309ff97b42", + "type": "github" + }, + "original": { + "owner": "OpenDeFiFoundation", + "ref": "v1.13.1", + "repo": "injective-core", + "type": "github" + } + }, "interchain-security-src": { "flake": false, "locked": { - "lastModified": 1700577019, - "narHash": "sha256-adBzn51PKoRsCL9gIzC5Tcqmu7u3GjxTcDj2jpZ/da8=", + "lastModified": 1726849313, + "narHash": "sha256-1WEvV3LoXfGvZC9fXOb8mBLKVGCVBiXZcwUewSPit+8=", "owner": "cosmos", "repo": "interchain-security", - "rev": "03aada4af3243dbf739a12adfacc7b37232df694", + "rev": "1e60637f9d8f3505208282416abfbb87fabc4795", "type": "github" }, "original": { "owner": "cosmos", - "ref": "feat/ics-misbehaviour-handling", + "ref": "v6.1.0", "repo": "interchain-security", "type": "github" } @@ -843,7 +1168,6 @@ "iris-src": { "flake": false, "locked": { - "lastModified": 1618986686, "narHash": "sha256-1nPJOuYeGjzBYFCS0IiC5j9TJd5KVa9IL0kROks328E=", "owner": "irisnet", "repo": "irishub", @@ -860,7 +1184,6 @@ "ixo-src": { "flake": false, "locked": { - "lastModified": 1645476442, "narHash": "sha256-Ewp9UyoH6z7YGrcXVpYJveRvDq02c1mNZj2hzlOoW8s=", "owner": "ixofoundation", "repo": "ixo-blockchain", @@ -877,33 +1200,48 @@ "juno-src": { "flake": false, "locked": { - "lastModified": 1697166503, - "narHash": "sha256-z9TOeDyUnn1T8Z662XqQJ9ydVIKKB54YISt7ms4xvos=", + "lastModified": 1727102451, + "narHash": "sha256-UaTCcK+I6Wl4yCpbNckx+lRi55kTSucJxzw5irJOVh4=", "owner": "CosmosContracts", "repo": "juno", - "rev": "48507ed9b83511089cbf1fdc5bae54cae4a7f4b2", + "rev": "de3c4d145c7a96c31e3fca6fe8850ce4ab559e33", "type": "github" }, "original": { "owner": "CosmosContracts", - "ref": "v17.1.1", + "ref": "v25.0.0", "repo": "juno", "type": "github" } }, + "lowdown-src": { + "flake": false, + "locked": { + "narHash": "sha256-Dw32tiMjdK9t3ETl5fzGrutQTzh2rufgZV4A/BbxuD4=", + "owner": "kristapsdz", + "repo": "lowdown", + "rev": "d2c2b44ff6c27b936ec27358a2653caaef8f73b8", + "type": "github" + }, + "original": { + "owner": "kristapsdz", + "repo": "lowdown", + "type": "github" + } + }, "migaloo-src": { "flake": false, "locked": { - "lastModified": 1699273936, - "narHash": "sha256-O+vGWFnV3+bvXinxl1QjVyDnQskp5H1VnlL+TaMfiSs=", + "lastModified": 1720168667, + "narHash": "sha256-vOzOBNGaIOhTjTnycLp6sQKGAklkPVZdJLPPqdjufnM=", "owner": "White-Whale-Defi-Platform", "repo": "migaloo-chain", - "rev": "de98de2dd96917ae1ab79161d573fc0b4ee1facf", + "rev": "076c6d12ecadcf4db42592a8340cb3be2ed23349", "type": "github" }, "original": { "owner": "White-Whale-Defi-Platform", - "ref": "v3.0.2", + "ref": "v4.2.0", "repo": "migaloo-chain", "type": "github" } @@ -911,7 +1249,6 @@ "namada-src": { "flake": false, "locked": { - "lastModified": 1702488720, "narHash": "sha256-WyIVffqszY3rz3ClQJlpDaexLGQk8pVK+Y3k/D9Lvxg=", "owner": "anoma", "repo": "namada", @@ -928,27 +1265,52 @@ "neutron-src": { "flake": false, "locked": { - "lastModified": 1701174344, - "narHash": "sha256-NuoOlrciBeL2f/A7wlQBqYlYJhSYucXRhLgxdasfyhI=", + "lastModified": 1724773633, + "narHash": "sha256-pHubObIv3p6IrzI/U7aeDjdF5kWBpI9qgDoH/Hjk+i8=", "owner": "neutron-org", "repo": "neutron", - "rev": "e605ed3db4381994ee8185ba4a0ff0877d34e67f", + "rev": "1b10cd282d5809ccdd87208918fd175aebec2b0b", "type": "github" }, "original": { "owner": "neutron-org", - "ref": "v2.0.0", + "ref": "v4.2.2", "repo": "neutron", "type": "github" } }, + "nix": { + "inputs": { + "lowdown-src": "lowdown-src", + "nixpkgs": [ + "cosmos-nix", + "haqq-src", + "devenv", + "nixpkgs" + ], + "nixpkgs-regression": "nixpkgs-regression" + }, + "locked": { + "narHash": "sha256-EK4rZ+Hd5hsvXnzSzk2ikhStJnD63odF7SzsQ8CuSPU=", + "owner": "domenkozar", + "repo": "nix", + "rev": "7c91803598ffbcfe4a55c44ac6d49b2cf07a527f", + "type": "github" + }, + "original": { + "owner": "domenkozar", + "ref": "relaxed-flakes", + "repo": "nix", + "type": "github" + } + }, "nix-std": { "locked": { - "lastModified": 1701658249, - "narHash": "sha256-KIt1TUuBvldhaVRta010MI5FeQlB8WadjqljybjesN0=", + "lastModified": 1710870712, + "narHash": "sha256-e+7MJF2gsgTBuOWv4mCimSP0D9+naeFSw9a7N3yEmv4=", "owner": "chessai", "repo": "nix-std", - "rev": "715db541ffff4194620e48d210b76f73a74b5b5d", + "rev": "31bbc925750cc9d8f828fe55cee1a2bd985e0c00", "type": "github" }, "original": { @@ -957,26 +1319,44 @@ "type": "github" } }, - "nixpkgs": { + "nix2container": { + "inputs": { + "flake-utils": "flake-utils_4", + "nixpkgs": [ + "cosmos-nix", + "nixpkgs" + ] + }, "locked": { - "lastModified": 1702272962, - "narHash": "sha256-D+zHwkwPc6oYQ4G3A1HuadopqRwUY/JkMwHz1YF7j4Q=", - "owner": "nixos", - "repo": "nixpkgs", - "rev": "e97b3e4186bcadf0ef1b6be22b8558eab1cdeb5d", + "lastModified": 1712990762, + "narHash": "sha256-hO9W3w7NcnYeX8u8cleHiSpK2YJo7ecarFTUlbybl7k=", + "owner": "nlewo", + "repo": "nix2container", + "rev": "20aad300c925639d5d6cbe30013c8357ce9f2a2e", "type": "github" }, "original": { - "owner": "NixOS", - "ref": "master", - "repo": "nixpkgs", + "owner": "nlewo", + "repo": "nix2container", "type": "github" } }, + "nixpkgs": { + "locked": { + "narHash": "sha256-LahKBAfGbY836gtpVNnWwBTIzN7yf/uYM/S0g393r0Y=", + "rev": "9f2ee8c91ac42da3ae6c6a1d21555f283458247e", + "revCount": 555392, + "type": "tarball", + "url": "https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.2311.555392%2Brev-9f2ee8c91ac42da3ae6c6a1d21555f283458247e/018d7c73-3161-76d5-aca1-5929105b0aa0/source.tar.gz" + }, + "original": { + "type": "tarball", + "url": "https://flakehub.com/f/NixOS/nixpkgs/0.2311.%2A.tar.gz" + } + }, "nixpkgs-lib": { "locked": { "dir": "lib", - "lastModified": 1701253981, "narHash": "sha256-ztaDIyZ7HrTAfEEUt9AtTDNoCYxUdSd6NrRHaYOIxtk=", "owner": "NixOS", "repo": "nixpkgs", @@ -991,13 +1371,58 @@ "type": "github" } }, + "nixpkgs-regression": { + "locked": { + "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + } + }, + "nixpkgs-stable": { + "locked": { + "narHash": "sha256-otaSUoFEMM+LjBI1XL/xGB5ao6IwnZOXc47qhIgJe8U=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "c37ca420157f4abc31e26f436c1145f8951ff373", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-23.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-unstable": { + "locked": { + "narHash": "sha256-ZbHsm+mGk/izkWtT4xwwqz38fdlwu7nUUKXTOmm4SyE=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "faf912b086576fd1a15fca610166c98d47bc667e", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, "nixpkgs_2": { "locked": { - "lastModified": 1701040486, - "narHash": "sha256-vawYwoHA5CwvjfqaT3A5CT9V36Eq43gxdwpux32Qkjw=", + "lastModified": 1723603349, + "narHash": "sha256-VMg6N7MryOuvSJ8Sj6YydarnUCkL7cvMdrMcnsJnJCE=", "owner": "nixos", "repo": "nixpkgs", - "rev": "45827faa2132b8eade424f6bdd48d8828754341a", + "rev": "daf7bb95821b789db24fc1ac21f613db0c1bf2cb", "type": "github" }, "original": { @@ -1009,11 +1434,11 @@ }, "nixpkgs_3": { "locked": { - "lastModified": 1681358109, - "narHash": "sha256-eKyxW4OohHQx9Urxi7TQlFBTDWII+F+x2hklDOQPB50=", + "lastModified": 1706487304, + "narHash": "sha256-LE8lVX28MV2jWJsidW13D2qrHU/RUUONendL2Q/WlJg=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "96ba1c52e54e74c3197f4d43026b3f3d92e83ff9", + "rev": "90f456026d284c22b3e3497be980b2e47d0b28ac", "type": "github" }, "original": { @@ -1025,7 +1450,6 @@ }, "nixpkgs_4": { "locked": { - "lastModified": 1674990008, "narHash": "sha256-4zOyp+hFW2Y7imxIpZqZGT8CEqKmDjwgfD6BzRUE0mQ=", "owner": "NixOS", "repo": "nixpkgs", @@ -1041,11 +1465,11 @@ }, "nixpkgs_5": { "locked": { - "lastModified": 1705505490, - "narHash": "sha256-HS+Zg50Zm1Ehfat/OgGS2YJqU7/4ohsQhK+ClwcKmVA=", + "lastModified": 1731531548, + "narHash": "sha256-sz8/v17enkYmfpgeeuyzniGJU0QQBfmAjlemAUYhfy8=", "owner": "nixos", "repo": "nixpkgs", - "rev": "f36047a5a4b5631f75210859abac7f97ba1ba7a7", + "rev": "24f0d4acd634792badd6470134c387a3b039dace", "type": "github" }, "original": { @@ -1058,33 +1482,64 @@ "osmosis-src": { "flake": false, "locked": { - "lastModified": 1702398856, - "narHash": "sha256-4uLO7izIZ8JvKTfUXbYkxQFpIjwMEcO81WvhklrzI9E=", + "lastModified": 1719537675, + "narHash": "sha256-8Lb2SppNfq3+JwP3uanmCxuCek6tXOO/GcG27XGxRrE=", "owner": "osmosis-labs", "repo": "osmosis", - "rev": "b0aee0006ce55d0851773084bd7880db7e32ad70", + "rev": "b973bffdf127866f45624d7e5a81f31fdc8e8e0b", "type": "github" }, "original": { "owner": "osmosis-labs", - "ref": "v21.0.0", + "ref": "v25.2.0", "repo": "osmosis", "type": "github" } }, + "pre-commit-hooks": { + "inputs": { + "flake-compat": [ + "cosmos-nix", + "haqq-src", + "devenv", + "flake-compat" + ], + "flake-utils": "flake-utils_2", + "gitignore": "gitignore", + "nixpkgs": [ + "cosmos-nix", + "haqq-src", + "devenv", + "nixpkgs" + ], + "nixpkgs-stable": "nixpkgs-stable" + }, + "locked": { + "narHash": "sha256-2+SDlNRTKsgo3LBRiMUcoEUb6sDViRNQhzJquZ4koOI=", + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "rev": "5843cf069272d92b60c3ed9e55b7a8989c01d4c7", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "type": "github" + } + }, "provenance-src": { "flake": false, "locked": { - "lastModified": 1699901286, - "narHash": "sha256-dTX3kg2QUsC9SwsaommP4IFgIdQgWZrGQNtp/B+fzys=", + "lastModified": 1721946876, + "narHash": "sha256-4RAyX3ORmbojnmDlMQMWF7mdmbaiBbqegZt0SMd9cXE=", "owner": "provenance-io", "repo": "provenance", - "rev": "91b0813de2f93d03cefe8efb226dc32f02690840", + "rev": "d1119ab02c423d86a0f485a8f124e73511ec1b9b", "type": "github" }, "original": { "owner": "provenance-io", - "ref": "v1.17.0", + "ref": "v1.19.1", "repo": "provenance", "type": "github" } @@ -1092,7 +1547,6 @@ "regen-src": { "flake": false, "locked": { - "lastModified": 1645832054, "narHash": "sha256-lDb0/Bw4hAX71jsCQJUju1mKYNacWEVezx6+KdIdu6Q=", "owner": "regen-network", "repo": "regen-ledger", @@ -1109,7 +1563,6 @@ "relayer-src": { "flake": false, "locked": { - "lastModified": 1635197290, "narHash": "sha256-xD+xZG4Gb6557y/jkXTGdbt8qJ6izMgC4H3uo2/j5vU=", "owner": "cosmos", "repo": "relayer", @@ -1123,24 +1576,40 @@ "type": "github" } }, + "rollapp-evm-src": { + "flake": false, + "locked": { + "narHash": "sha256-bOH7QsNYjZVVHW7x5ysrO0IJmRNEUeE+bJRVPwdb5U8=", + "owner": "dymensionxyz", + "repo": "rollapp-evm", + "rev": "21b29f6e77f5c11a2036252d60819810abbbd7b8", + "type": "github" + }, + "original": { + "owner": "dymensionxyz", + "repo": "rollapp-evm", + "rev": "21b29f6e77f5c11a2036252d60819810abbbd7b8", + "type": "github" + } + }, "root": { "inputs": { "cosmos-nix": "cosmos-nix", - "flake-utils": "flake-utils_4", + "flake-utils": "flake-utils_7", "nixpkgs": "nixpkgs_5" } }, "rust-overlay": { "inputs": { - "flake-utils": "flake-utils_2", + "flake-utils": "flake-utils_5", "nixpkgs": "nixpkgs_3" }, "locked": { - "lastModified": 1702347444, - "narHash": "sha256-ueDw7aQf4Xyk69XnDD0YNWDlFdlOgJGPeWFa7uu/cfw=", + "lastModified": 1710468700, + "narHash": "sha256-YGN6R0nLfB2L57J8T/DX+LcB06QipyYzHSz7AD8B0n0=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "bc13176f27cf3be724d18924b4f6aa47686ca2e3", + "rev": "7ff8e9a04ac7777a3446788cb4018b452157ab8a", "type": "github" }, "original": { @@ -1151,11 +1620,10 @@ }, "sbt-derivation": { "inputs": { - "flake-utils": "flake-utils_3", + "flake-utils": "flake-utils_6", "nixpkgs": "nixpkgs_4" }, "locked": { - "lastModified": 1698464090, "narHash": "sha256-Pnej7WZIPomYWg8f/CZ65sfW85IfIUjYhphMMg7/LT0=", "owner": "zaninime", "repo": "sbt-derivation", @@ -1171,7 +1639,6 @@ "sconfig-src": { "flake": false, "locked": { - "lastModified": 1679585941, "narHash": "sha256-ywh9IcqMWbRHqJkGJezcDCvfbBYNJH7ualKvPJQRcHA=", "owner": "freshautomations", "repo": "sconfig", @@ -1187,7 +1654,6 @@ "sentinel-src": { "flake": false, "locked": { - "lastModified": 1647195309, "narHash": "sha256-+ZobsjLNxVL3+zi6OEFQhff6Gbd9kng8B0haqcOoiP0=", "owner": "sentinel-official", "repo": "hub", @@ -1204,7 +1670,6 @@ "sifchain-src": { "flake": false, "locked": { - "lastModified": 1648486445, "narHash": "sha256-n5fmWtdrc0Rhs6Uo+zjcSXmyEFVIsA5L9dlrbRXGDmU=", "owner": "Sifchain", "repo": "sifnode", @@ -1218,10 +1683,25 @@ "type": "github" } }, + "slinky-src": { + "flake": false, + "locked": { + "narHash": "sha256-gto9l+zeM1WLIv/VtVlrhTpUTMLN+niQTo5zlrbkx30=", + "owner": "skip-mev", + "repo": "slinky", + "rev": "642846e3517f4aa4ffe1cd29180fef4d459bfbfe", + "type": "github" + }, + "original": { + "owner": "skip-mev", + "ref": "v0.2.0", + "repo": "slinky", + "type": "github" + } + }, "stargaze-src": { "flake": false, "locked": { - "lastModified": 1645539964, "narHash": "sha256-5I5pdnBJHwNaI2Soet+zH3aH+pUbYdC9TgHBjOd1TmA=", "owner": "public-awesome", "repo": "stargaze", @@ -1238,7 +1718,6 @@ "stoml-src": { "flake": false, "locked": { - "lastModified": 1666796497, "narHash": "sha256-Adjag1/Hd2wrar2/anD6jQEMDvUc2TOIG7DlEgxpTXc=", "owner": "freshautomations", "repo": "stoml", @@ -1251,41 +1730,67 @@ "type": "github" } }, - "stride-consumer-src": { + "stride-src": { "flake": false, "locked": { - "lastModified": 1689464372, - "narHash": "sha256-DByig9ISs9x9Kvakc8LFL558VKhM+UBiaESWgyVzI0w=", + "lastModified": 1721921071, + "narHash": "sha256-EtsK7sjzQ2XfYt3DSV85IbKj7HEMy2Apt0m8kfgCEuk=", "owner": "Stride-Labs", "repo": "stride", - "rev": "bbf0bb7f52878f3205c76bb1e96662fe7bd7af8d", + "rev": "d6e4e686e54a6a3c41d3ca0645f91ee1dc3ec441", "type": "github" }, "original": { "owner": "Stride-Labs", - "ref": "v12.1.0", + "ref": "v23.0.1", "repo": "stride", "type": "github" } }, - "stride-src": { - "flake": false, + "systems": { "locked": { - "lastModified": 1679819302, - "narHash": "sha256-fdjnFHPBZNnhDyVoMuPfqNb6YUYRdcMO73FlZHjIuzA=", - "owner": "Stride-Labs", - "repo": "stride", - "rev": "3c69e7644859981b1fd9313eb1f0c5e5886e4a0d", + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", "type": "github" }, "original": { - "owner": "Stride-Labs", - "ref": "v8.0.0", - "repo": "stride", + "owner": "nix-systems", + "repo": "default", "type": "github" } }, - "systems": { + "systems_2": { + "locked": { + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_3": { + "locked": { + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_4": { "locked": { "lastModified": 1681028828, "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", @@ -1300,7 +1805,7 @@ "type": "github" } }, - "systems_2": { + "systems_5": { "locked": { "lastModified": 1681028828, "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", @@ -1315,7 +1820,7 @@ "type": "github" } }, - "systems_3": { + "systems_6": { "locked": { "lastModified": 1681028828, "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", @@ -1333,7 +1838,6 @@ "umee-src": { "flake": false, "locked": { - "lastModified": 1649261156, "narHash": "sha256-hydRL/88fHCW/k7z7GoqAwvynZuvLEDLyA6A9Cm+6UY=", "owner": "umee-network", "repo": "umee", @@ -1350,33 +1854,16 @@ "wasmd-src": { "flake": false, "locked": { - "lastModified": 1669987561, - "narHash": "sha256-F0p555FEeA405tuLn82yUEbRZpJLs85GrUKvSrjTdjk=", + "lastModified": 1724231006, + "narHash": "sha256-X8Q93gqk+gBJwn4EIxFVeWqRpHcIxNAplfARejHwfbk=", "owner": "CosmWasm", "repo": "wasmd", - "rev": "a347ace2ff41539fe06c68168bc6f28d6ca9fa52", + "rev": "de7db0dc672e7beb201e06e7eb12b2de356ac7c9", "type": "github" }, "original": { "owner": "CosmWasm", - "ref": "v0.30.0", - "repo": "wasmd", - "type": "github" - } - }, - "wasmd_next-src": { - "flake": false, - "locked": { - "lastModified": 1682094944, - "narHash": "sha256-b+6XhBdKyQlrzsYxVRrDf4vHpv8GAJkGwHVfJ9sdf3U=", - "owner": "CosmWasm", - "repo": "wasmd", - "rev": "c2bb27d289f7f72f1471a4b33cb08fdfc8d66f63", - "type": "github" - }, - "original": { - "owner": "CosmWasm", - "ref": "v0.40.0-rc.1", + "ref": "v0.53.0", "repo": "wasmd", "type": "github" } @@ -1384,7 +1871,6 @@ "wasmvm_1-src": { "flake": false, "locked": { - "lastModified": 1652698028, "narHash": "sha256-4m64mPwFLz7aZEKVxM2lJQtX98BkhdKTZb3evpDOk/4=", "owner": "CosmWasm", "repo": "wasmvm", @@ -1401,7 +1887,6 @@ "wasmvm_1_1_1-src": { "flake": false, "locked": { - "lastModified": 1663600745, "narHash": "sha256-9K/G7Wu/TfW4Z+lseEutXbdtr+A40nbVejBphegF5z4=", "owner": "CosmWasm", "repo": "wasmvm", @@ -1418,7 +1903,6 @@ "wasmvm_1_1_2-src": { "flake": false, "locked": { - "lastModified": 1681833975, "narHash": "sha256-EbzMNkZUO94jEdX0WgAdy5qfhlCG3lpHpVHyT2FcSDw=", "owner": "CosmWasm", "repo": "wasmvm", @@ -1435,7 +1919,6 @@ "wasmvm_1_2_3-src": { "flake": false, "locked": { - "lastModified": 1681831436, "narHash": "sha256-GscUMJ0Tkg77S9IYA9komyKKoa1AyVXSSaU8hw3ZNwk=", "owner": "CosmWasm", "repo": "wasmvm", @@ -1452,7 +1935,6 @@ "wasmvm_1_2_4-src": { "flake": false, "locked": { - "lastModified": 1685977963, "narHash": "sha256-/GOvkKLQwsPms7h7yEZYLwbZn9Lzk5qQnBXXoZ/R6JM=", "owner": "CosmWasm", "repo": "wasmvm", @@ -1466,10 +1948,26 @@ "type": "github" } }, + "wasmvm_1_2_6-src": { + "flake": false, + "locked": { + "lastModified": 1704896412, + "narHash": "sha256-W0WuC9eRxp67UeQZ0HDZ9/iIC5JKsylB2g6YpYFjMGM=", + "owner": "CosmWasm", + "repo": "wasmvm", + "rev": "66763124d7dd49b775cb86b637376eecb1e3f56a", + "type": "github" + }, + "original": { + "owner": "CosmWasm", + "ref": "v1.2.6", + "repo": "wasmvm", + "type": "github" + } + }, "wasmvm_1_3_0-src": { "flake": false, "locked": { - "lastModified": 1689589428, "narHash": "sha256-rsTYvbkYpDkUE4IvILdSL3hXMgAWxz5ltGotJB2t1e4=", "owner": "CosmWasm", "repo": "wasmvm", @@ -1486,7 +1984,6 @@ "wasmvm_1_5_0-src": { "flake": false, "locked": { - "lastModified": 1698746477, "narHash": "sha256-l0cNF0YjviEl/JLJ4VdvDtIGuAYyFfncVo83ROfQFD8=", "owner": "CosmWasm", "repo": "wasmvm", @@ -1500,10 +1997,60 @@ "type": "github" } }, + "wasmvm_1_5_2-src": { + "flake": false, + "locked": { + "lastModified": 1705576719, + "narHash": "sha256-3KJq5jFllFSqlm85/iRWYMhu99iuokvR3Ib9Gq3gIjc=", + "owner": "CosmWasm", + "repo": "wasmvm", + "rev": "b742b2623cce98f04ae5d8bfb488c73988f3dd61", + "type": "github" + }, + "original": { + "owner": "CosmWasm", + "ref": "v1.5.2", + "repo": "wasmvm", + "type": "github" + } + }, + "wasmvm_1_5_4-src": { + "flake": false, + "locked": { + "lastModified": 1723135235, + "narHash": "sha256-DGQHC20eMa1CDIx9fWYTTBxdFDCPoS/SsEDJnWJ+7bA=", + "owner": "CosmWasm", + "repo": "wasmvm", + "rev": "9f85c0f44fb8a5573be8e461cad12f784c544c4b", + "type": "github" + }, + "original": { + "owner": "CosmWasm", + "ref": "v1.5.4", + "repo": "wasmvm", + "type": "github" + } + }, + "wasmvm_1_5_5-src": { + "flake": false, + "locked": { + "lastModified": 1727088523, + "narHash": "sha256-ysS2pMMm+s1JsHVv9RhiMHt5g4UGcE5jqOI5YKdC4vU=", + "owner": "CosmWasm", + "repo": "wasmvm", + "rev": "0c5b9ce8446189f07d2bf65fbb902817cf57a563", + "type": "github" + }, + "original": { + "owner": "CosmWasm", + "ref": "v1.5.5", + "repo": "wasmvm", + "type": "github" + } + }, "wasmvm_1_beta7-src": { "flake": false, "locked": { - "lastModified": 1646675433, "narHash": "sha256-tt9aAPLxtIRsG1VFM1YAIHSotuBl170EiBcHSWTtARI=", "owner": "CosmWasm", "repo": "wasmvm", @@ -1516,6 +2063,74 @@ "repo": "wasmvm", "type": "github" } + }, + "wasmvm_2_0_0-src": { + "flake": false, + "locked": { + "lastModified": 1710250586, + "narHash": "sha256-OmETCXyhCXWOEW/emf1ZruLMPlH8iLvM8xrqFoDaxnw=", + "owner": "CosmWasm", + "repo": "wasmvm", + "rev": "5307690b77a5fef2da3747ec72abe8f29664aeca", + "type": "github" + }, + "original": { + "owner": "CosmWasm", + "ref": "v2.0.0", + "repo": "wasmvm", + "type": "github" + } + }, + "wasmvm_2_0_3-src": { + "flake": false, + "locked": { + "lastModified": 1723134607, + "narHash": "sha256-fFFP9sqlfgFbjAPP6VVXEcDQ3is2RHZYNE003Ls8Sfk=", + "owner": "CosmWasm", + "repo": "wasmvm", + "rev": "64b8c846dadb664eeb9da765a98fc370eb594f6d", + "type": "github" + }, + "original": { + "owner": "CosmWasm", + "ref": "v2.0.3", + "repo": "wasmvm", + "type": "github" + } + }, + "wasmvm_2_1_0-src": { + "flake": false, + "locked": { + "lastModified": 1720688907, + "narHash": "sha256-Ev/2cUKT0i9ytvfrzh15Ibja4TBXjoeB7RLHn28yRCY=", + "owner": "CosmWasm", + "repo": "wasmvm", + "rev": "d7906b3030061a959c54ee57c88e3256b8e90a0c", + "type": "github" + }, + "original": { + "owner": "CosmWasm", + "ref": "v2.1.0", + "repo": "wasmvm", + "type": "github" + } + }, + "wasmvm_2_1_2-src": { + "flake": false, + "locked": { + "lastModified": 1723135029, + "narHash": "sha256-Y3BVRR2T5MLOtXdPK38W8MX8etIuqGcTjvxkaEOyvVM=", + "owner": "CosmWasm", + "repo": "wasmvm", + "rev": "d8f06b73e4d49f8246e1569f032962122427882b", + "type": "github" + }, + "original": { + "owner": "CosmWasm", + "ref": "v2.1.2", + "repo": "wasmvm", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 7e2f5756e3..ce0e9b787d 100644 --- a/flake.nix +++ b/flake.nix @@ -2,9 +2,9 @@ description = "Nix development dependencies for ibc-rs"; inputs = { - nixpkgs.url = github:nixos/nixpkgs/nixpkgs-unstable; - flake-utils.url = github:numtide/flake-utils; - cosmos-nix.url = github:informalsystems/cosmos.nix; + nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + cosmos-nix.url = "github:informalsystems/cosmos.nix"; }; outputs = inputs: let @@ -32,8 +32,8 @@ cometbft evmos gaia6-ordered - gaia13 - gaia14 + gaia18 + gaia20 ibc-go-v2-simapp ibc-go-v3-simapp ibc-go-v4-simapp @@ -41,6 +41,7 @@ ibc-go-v6-simapp ibc-go-v7-simapp ibc-go-v8-simapp + ibc-go-v9-simapp interchain-security migaloo neutron @@ -49,9 +50,8 @@ provenance stride stride-no-admin - stride-consumer-no-admin - stride-consumer wasmd + injective ; python = nixpkgs.python3.withPackages (p: [ diff --git a/guide/README.md b/guide/README.md index 0c2a7bf993..e6cd915fda 100644 --- a/guide/README.md +++ b/guide/README.md @@ -10,7 +10,7 @@ mdBook is a utility to create modern online books from Markdown files. This guide should be permanently deployed at its latest stable version at [hermes.informal.systems](https://hermes.informal.systems). -Current version: `v1.8.0`. +Current version: `v1.10.5`. The version of this guide is aligned with the [versioning of the ibc crates](../README.md). diff --git a/guide/src/SUMMARY.md b/guide/src/SUMMARY.md index 86b06ace7e..295d9abe26 100644 --- a/guide/src/SUMMARY.md +++ b/guide/src/SUMMARY.md @@ -1,6 +1,6 @@ # Summary -# Hermes v1.8.0 +# Hermes v1.10.5 --- - [Introduction](./index.md) @@ -53,6 +53,7 @@ - [Cross Stack Misconfiguration](./advanced/troubleshooting/cross-comp-config.md) - [Genesis restart without IBC upgrade proposal](./advanced/troubleshooting/genesis-restart.md) - [Handling Clock Drift](./advanced/troubleshooting/clock-drift.md) + - [Gas Errors](./advanced/troubleshooting/gas-errors.md) - [Commands Reference](./documentation/commands/index.md) - [Global options and JSON output](./documentation/commands/global.md) diff --git a/guide/src/advanced/troubleshooting/gas-errors.md b/guide/src/advanced/troubleshooting/gas-errors.md new file mode 100644 index 0000000000..220e0f8d0d --- /dev/null +++ b/guide/src/advanced/troubleshooting/gas-errors.md @@ -0,0 +1,48 @@ +# Gas errors + +This section will expand on the out of gas error which can happen when simulating or sending Txs. The related configurations are: + +```toml +default_gas = 100000 +max_gas = 4000000 +gas_multiplier = 1.1 +``` + +Before sending a transaction, Hermes will retrieve an estimation of the gas required with the simulation capability of the chain. After retrieving the gas amount from the simulation, the `gas_multiplier` will be applied since the simulation might be slightly lower than the required amount of gas. +Since the `max_gas` is applied after the gas_multiplier, it can happen that the value `simulated_gas * gas_multiplier > max_gas`, in which case the `max_gas` value is used. + +Note that if the simulation fails with a recoverable error, Hermes will use the configured `default_gas`. + +## Simulating Tx + +The first instance where an error can happen is when the tracasction simulation succeeds but the gas amount retrieved exceeds the configured `max_gas`, Hermes will throw an unrecoverable error: + +``` + gas estimate from simulated Tx exceeds the maximum configured +``` + +This can be fixed by increasing the configured `max_gas`. + +## Broadcasting Tx + +> __NOTE__: This issue will only arise with Cosmos chains as this is a Cosmos SDK error. + +The second instance when an error can happen is when sending the transaction. If the gas included for the transaction is not enough Hermes will throw an error: + +``` +out of gas in location: ; gasWanted: , gasUsed: : out of gas +``` + +Two cases need to be verified in order to fix this issue. + +### Caused by max_gas + +If simulated gas is close to the `max_gas` configured, after multiplying the value with the `gas_multiplier`, it can be the case that the `max_gas` is used instead. And since the simulated gas might be slightly lower than the required gas, this can cause an out of gas error. +This can be fixed by increasing the configured `max_gas`. + +### Caused by default_gas + +When the transaction simulation fails with a recoverable error, the `default_gas` will be used. If the `default_gas` is too low an out of gas error will be thrown. This can be fixed by increasing the `default_gas`. +But there can also be a case similar to the one explained in the previous section [Caused by max_gas](./gas-errors.md#caused-by-max_gas). + +If the `default_gas` is too close to the `max_gas`, the `max_gas` will be used instead of `default_gas * gas_multiplier`, causing an out of gas error. In this situation both `max_gas` and `default_gas` need to be verified, and one or both need to be increased. \ No newline at end of file diff --git a/guide/src/documentation/configuration/configure-hermes.md b/guide/src/documentation/configuration/configure-hermes.md index c63fab7200..c5cb5ec0ee 100644 --- a/guide/src/documentation/configuration/configure-hermes.md +++ b/guide/src/documentation/configuration/configure-hermes.md @@ -136,7 +136,7 @@ needs in order to relay on behalf of consumer chains. ## Connecting to a full node protected by HTTP Basic Authentication To connect to a full node protected by [HTTP Basic Authentication][http-basic-auth], -specify the username and password in the `rpc_addr`, `grpc_addr` and `event_source` settings +specify the username and password in the `rpc_addr` and `event_source` settings under the chain configuration in `config.toml`. Here is an example with username `hello` and password `world`, assuming the RPC, WebSocket and gRPC servers @@ -149,7 +149,6 @@ id = 'my-chain-0' # ... rpc_addr = 'https://hello:world@mydomain.com:26657' -grpc_addr = 'https://hello:world@mydomain.com:9090' event_source = { mode = 'push', url = 'wss://hello:world@mydomain.com:26657/websocket', batch_delay = '500ms' } # ... diff --git a/guide/src/documentation/configuration/packet-clearing.md b/guide/src/documentation/configuration/packet-clearing.md index b12dd4d27d..805c061b31 100644 --- a/guide/src/documentation/configuration/packet-clearing.md +++ b/guide/src/documentation/configuration/packet-clearing.md @@ -2,7 +2,7 @@ Hermes can be configured in order to clear packets which haven't been relayed. This can happen if there wasn't a relayer instance running when the packet event was submitted or if there was an issue relaying the packet. -There are three different configurations to determine when Hermes will clear packets. +There are four different configurations to determine when Hermes will clear packets. ## Global configurations @@ -32,7 +32,7 @@ This configuration defines how often Hermes will verify if there are pending pac ## Chain specific configuration -The third configuration is specific for each chain. +The third and fourth configurations are specific for each chain. ### 3. `clear_interval` @@ -42,4 +42,17 @@ The third configuration is specific for each chain. clear_interval = 50 ``` -An additional `clear_interval` can be specified for each chain, this value is also in number of blocks. This configuration will override the clear interval value for the specific chain and can be used if chains need to have different clear values. This configuration is optional, if it is not set the global value will be used. \ No newline at end of file +An additional `clear_interval` can be specified for each chain, this value is also in number of blocks. This configuration will override the clear interval value for the specific chain and can be used if chains need to have different clear values. This configuration is optional, if it is not set the global value will be used. + +### 4. `excluded_sequences` + +```toml +[[chains]] +... +excluded_sequences = [ + ['channel-0', [1, 2, 3]], + ['channel-1', [4, 5, 6]] +] +``` + +It is possible to specify which packet sequences should be ignored when clearing packets for specific channels. This can be used when there are stuck packets which need to be handled in a specific way, but it is still required to clear the other stuck packets. This configuration will only filter packet when clearing, standard relaying will not filter the sequences configured in `excluded_sequences`. \ No newline at end of file diff --git a/guide/src/documentation/telemetry/operators.md b/guide/src/documentation/telemetry/operators.md index 2496b6e91a..dd0d137d2e 100644 --- a/guide/src/documentation/telemetry/operators.md +++ b/guide/src/documentation/telemetry/operators.md @@ -142,6 +142,7 @@ If this metric is increasing, it signals that the packet queue is increasing and | `cleared_send_packet_count_total`  | Number of SendPacket events received during the initial and periodic clearing, per chain, counterparty chain, channel and port | `u64` Counter | Packet workers enabled, and periodic packet clearing or clear on start enabled | | `cleared_acknowledgment_count_total` | Number of WriteAcknowledgement events received during the initial and periodic clearing, per chain, counterparty chain, channel and port | `u64` Counter | Packet workers enabled, and periodic packet clearing or clear on start enabled | | `broadcast_errors_total` | Number of errors observed by Hermes when broadcasting a Tx, per error type and account | `u64` Counter | Packet workers enabled | +| `simulate_errors_total` | Number of errors observed by Hermes when simulating a Tx, per error type, account and whether the error is recoverable or not | `u64` Counter | Packet workers enabled | | `filtered_packets` | Number of ICS-20 packets filtered because the memo and/or the receiver fields were exceeding the configured limits | `u64` Counter | Packet workers enabled, and `ics20_max_memo_size` and/or `ics20_max_receiver_size` enabled | Notes: diff --git a/guide/src/index.md b/guide/src/index.md index 0b364cd9f9..329ec05641 100644 --- a/guide/src/index.md +++ b/guide/src/index.md @@ -74,7 +74,7 @@ Hermes is actively developed and maintained by [Informal Systems](https://inform - The official GitHub repository for Hermes. - [IBC GitHub repository](https://github.com/cosmos/ics) - The official repository for the Inter-blockchain protocol (IBC). - - [IBC Protocol](https://ibcprotocol.org) + - [IBC Protocol](https://www.ibcprotocol.dev) - The official IBC protocol page. ## Contact diff --git a/guide/src/quick-start/pre-requisites.md b/guide/src/quick-start/pre-requisites.md index aefafe2c18..fa430166d8 100644 --- a/guide/src/quick-start/pre-requisites.md +++ b/guide/src/quick-start/pre-requisites.md @@ -12,8 +12,7 @@ The provided instructions will install all the Rust tool chain including `rustc` ### Version requirements -Hermes is developed and tested using the latest version of Rust, `1.71` at -the moment. To check that your tool chain is up-to-date run: +Hermes is developed and tested using the latest stable version of Rust. To check that your tool chain is up-to-date run: ```shell rustc --version diff --git a/guide/src/templates/commands/hermes/query/packet/commitments_1.md b/guide/src/templates/commands/hermes/query/packet/commitments_1.md index 57b807de52..32d0ca5476 100644 --- a/guide/src/templates/commands/hermes/query/packet/commitments_1.md +++ b/guide/src/templates/commands/hermes/query/packet/commitments_1.md @@ -1 +1 @@ -[[#BINARY hermes]][[#GLOBALOPTIONS]] query packet commitments --chain [[#CHAIN_ID]] --port [[#PORT_ID]] --channel [[#CHANNEL_ID]] +[[#BINARY hermes]][[#GLOBALOPTIONS]] query packet commitments[[#OPTIONS]] --chain [[#CHAIN_ID]] --port [[#PORT_ID]] --channel [[#CHANNEL_ID]] diff --git a/guide/src/templates/commands/hermes/tx/chan-upgrade-ack_1.md b/guide/src/templates/commands/hermes/tx/chan-upgrade-ack_1.md new file mode 100644 index 0000000000..c39115bdf9 --- /dev/null +++ b/guide/src/templates/commands/hermes/tx/chan-upgrade-ack_1.md @@ -0,0 +1 @@ +[[#BINARY hermes]][[#GLOBALOPTIONS]] tx chan-upgrade-ack --dst-chain [[#DST_CHAIN_ID]] --src-chain [[#SRC_CHAIN_ID]] --dst-connection [[#DST_CONNECTION_ID]] --dst-port [[#DST_PORT_ID]] --src-port [[#SRC_PORT_ID]] --src-channel [[#SRC_CHANNEL_ID]] --dst-channel [[#DST_CHANNEL_ID]] diff --git a/guide/src/templates/commands/hermes/tx/chan-upgrade-cancel_1.md b/guide/src/templates/commands/hermes/tx/chan-upgrade-cancel_1.md new file mode 100644 index 0000000000..5f7fc7e0e1 --- /dev/null +++ b/guide/src/templates/commands/hermes/tx/chan-upgrade-cancel_1.md @@ -0,0 +1 @@ +[[#BINARY hermes]][[#GLOBALOPTIONS]] tx chan-upgrade-cancel --dst-chain [[#DST_CHAIN_ID]] --src-chain [[#SRC_CHAIN_ID]] --dst-connection [[#DST_CONNECTION_ID]] --dst-port [[#DST_PORT_ID]] --src-port [[#SRC_PORT_ID]] --src-channel [[#SRC_CHANNEL_ID]] --dst-channel [[#DST_CHANNEL_ID]] diff --git a/guide/src/templates/commands/hermes/tx/chan-upgrade-confirm_1.md b/guide/src/templates/commands/hermes/tx/chan-upgrade-confirm_1.md new file mode 100644 index 0000000000..4b9434eb3b --- /dev/null +++ b/guide/src/templates/commands/hermes/tx/chan-upgrade-confirm_1.md @@ -0,0 +1 @@ +[[#BINARY hermes]][[#GLOBALOPTIONS]] tx chan-upgrade-confirm --dst-chain [[#DST_CHAIN_ID]] --src-chain [[#SRC_CHAIN_ID]] --dst-connection [[#DST_CONNECTION_ID]] --dst-port [[#DST_PORT_ID]] --src-port [[#SRC_PORT_ID]] --src-channel [[#SRC_CHANNEL_ID]] --dst-channel [[#DST_CHANNEL_ID]] diff --git a/guide/src/templates/commands/hermes/tx/chan-upgrade-open_1.md b/guide/src/templates/commands/hermes/tx/chan-upgrade-open_1.md new file mode 100644 index 0000000000..43fe8ee75a --- /dev/null +++ b/guide/src/templates/commands/hermes/tx/chan-upgrade-open_1.md @@ -0,0 +1 @@ +[[#BINARY hermes]][[#GLOBALOPTIONS]] tx chan-upgrade-open --dst-chain [[#DST_CHAIN_ID]] --src-chain [[#SRC_CHAIN_ID]] --dst-connection [[#DST_CONNECTION_ID]] --dst-port [[#DST_PORT_ID]] --src-port [[#SRC_PORT_ID]] --src-channel [[#SRC_CHANNEL_ID]] --dst-channel [[#DST_CHANNEL_ID]] diff --git a/guide/src/templates/commands/hermes/tx/chan-upgrade-timeout_1.md b/guide/src/templates/commands/hermes/tx/chan-upgrade-timeout_1.md new file mode 100644 index 0000000000..2ccf8b5d99 --- /dev/null +++ b/guide/src/templates/commands/hermes/tx/chan-upgrade-timeout_1.md @@ -0,0 +1 @@ +[[#BINARY hermes]][[#GLOBALOPTIONS]] tx chan-upgrade-timeout --dst-chain [[#DST_CHAIN_ID]] --src-chain [[#SRC_CHAIN_ID]] --dst-connection [[#DST_CONNECTION_ID]] --dst-port [[#DST_PORT_ID]] --src-port [[#SRC_PORT_ID]] --src-channel [[#SRC_CHANNEL_ID]] --dst-channel [[#DST_CHANNEL_ID]] diff --git a/guide/src/templates/commands/hermes/tx/chan-upgrade-try_1.md b/guide/src/templates/commands/hermes/tx/chan-upgrade-try_1.md new file mode 100644 index 0000000000..a2f0e74436 --- /dev/null +++ b/guide/src/templates/commands/hermes/tx/chan-upgrade-try_1.md @@ -0,0 +1 @@ +[[#BINARY hermes]][[#GLOBALOPTIONS]] tx chan-upgrade-try --dst-chain [[#DST_CHAIN_ID]] --src-chain [[#SRC_CHAIN_ID]] --dst-connection [[#DST_CONNECTION_ID]] --dst-port [[#DST_PORT_ID]] --src-port [[#SRC_PORT_ID]] --src-channel [[#SRC_CHANNEL_ID]] --dst-channel [[#DST_CHANNEL_ID]] diff --git a/guide/src/templates/help_templates/health-check.md b/guide/src/templates/help_templates/health-check.md index 75638bd5ee..ad6b954fa2 100644 --- a/guide/src/templates/help_templates/health-check.md +++ b/guide/src/templates/help_templates/health-check.md @@ -1,5 +1,5 @@ DESCRIPTION: -Performs a health check of all chains in the the config +Performs a health check of all chains in the config USAGE: hermes health-check diff --git a/guide/src/templates/help_templates/help.md b/guide/src/templates/help_templates/help.md index 8a0011bd76..0f0038d664 100644 --- a/guide/src/templates/help_templates/help.md +++ b/guide/src/templates/help_templates/help.md @@ -19,7 +19,7 @@ SUBCOMMANDS: create Create objects (client, connection, or channel) on chains evidence Listen to block events and handles evidence fee Interact with the fee middleware - health-check Performs a health check of all chains in the the config + health-check Performs a health check of all chains in the config help Print this message or the help of the given subcommand(s) keys Manage keys in the relayer for each chain listen Listen to and display IBC events emitted by a chain diff --git a/guide/src/templates/help_templates/query/packet/commitments.md b/guide/src/templates/help_templates/query/packet/commitments.md index b12e02d44f..33d211e2bf 100644 --- a/guide/src/templates/help_templates/query/packet/commitments.md +++ b/guide/src/templates/help_templates/query/packet/commitments.md @@ -2,10 +2,11 @@ DESCRIPTION: Query packet commitments USAGE: - hermes query packet commitments --chain --port --channel + hermes query packet commitments [OPTIONS] --chain --port --channel OPTIONS: - -h, --help Print help information + -h, --help Print help information + --height Height of the state to query. Leave unspecified for latest height. REQUIRED: --chain Identifier of the chain to query diff --git a/guide/src/templates/help_templates/tx.md b/guide/src/templates/help_templates/tx.md index 02590775c2..9d83c50de5 100644 --- a/guide/src/templates/help_templates/tx.md +++ b/guide/src/templates/help_templates/tx.md @@ -8,18 +8,24 @@ OPTIONS: -h, --help Print help information SUBCOMMANDS: - chan-close-confirm Confirm the closing of a channel (ChannelCloseConfirm) - chan-close-init Initiate the closing of a channel (ChannelCloseInit) - chan-open-ack Relay acknowledgment of a channel attempt (ChannelOpenAck) - chan-open-confirm Confirm opening of a channel (ChannelOpenConfirm) - chan-open-init Initialize a channel (ChannelOpenInit) - chan-open-try Relay the channel attempt (ChannelOpenTry) - conn-ack Relay acknowledgment of a connection attempt (ConnectionOpenAck) - conn-confirm Confirm opening of a connection (ConnectionOpenConfirm) - conn-init Initialize a connection (ConnectionOpenInit) - conn-try Relay the connection attempt (ConnectionOpenTry) - ft-transfer Send a fungible token transfer test transaction (ICS20 MsgTransfer) - help Print this message or the help of the given subcommand(s) - packet-ack Relay acknowledgment packets - packet-recv Relay receive or timeout packets - upgrade-chain Send an IBC upgrade plan + chan-close-confirm Confirm the closing of a channel (ChannelCloseConfirm) + chan-close-init Initiate the closing of a channel (ChannelCloseInit) + chan-open-ack Relay acknowledgment of a channel attempt (ChannelOpenAck) + chan-open-confirm Confirm opening of a channel (ChannelOpenConfirm) + chan-open-init Initialize a channel (ChannelOpenInit) + chan-open-try Relay the channel attempt (ChannelOpenTry) + chan-upgrade-ack Relay the channel upgrade attempt (ChannelUpgradeAck) + chan-upgrade-cancel Relay the channel upgrade cancellation (ChannelUpgradeCancel) + chan-upgrade-confirm Relay the channel upgrade attempt (ChannelUpgradeConfirm) + chan-upgrade-open Relay the channel upgrade attempt (ChannelUpgradeOpen) + chan-upgrade-timeout Relay the channel upgrade timeout (ChannelUpgradeTimeout) + chan-upgrade-try Relay the channel upgrade attempt (ChannelUpgradeTry) + conn-ack Relay acknowledgment of a connection attempt (ConnectionOpenAck) + conn-confirm Confirm opening of a connection (ConnectionOpenConfirm) + conn-init Initialize a connection (ConnectionOpenInit) + conn-try Relay the connection attempt (ConnectionOpenTry) + ft-transfer Send a fungible token transfer test transaction (ICS20 MsgTransfer) + help Print this message or the help of the given subcommand(s) + packet-ack Relay acknowledgment packets + packet-recv Relay receive or timeout packets + upgrade-chain Send an IBC upgrade plan diff --git a/guide/src/templates/help_templates/tx/chan-upgrade-ack.md b/guide/src/templates/help_templates/tx/chan-upgrade-ack.md new file mode 100644 index 0000000000..6c30bfa913 --- /dev/null +++ b/guide/src/templates/help_templates/tx/chan-upgrade-ack.md @@ -0,0 +1,30 @@ +DESCRIPTION: +Relay the channel upgrade attempt (ChannelUpgradeAck) + +USAGE: + hermes tx chan-upgrade-ack --dst-chain --src-chain --dst-connection --dst-port --src-port --src-channel --dst-channel + +OPTIONS: + -h, --help Print help information + +REQUIRED: + --dst-chain + Identifier of the destination chain + + --dst-channel + Identifier of the destination channel (optional) [aliases: dst-chan] + + --dst-connection + Identifier of the destination connection [aliases: dst-conn] + + --dst-port + Identifier of the destination port + + --src-chain + Identifier of the source chain + + --src-channel + Identifier of the source channel (required) [aliases: src-chan] + + --src-port + Identifier of the source port diff --git a/guide/src/templates/help_templates/tx/chan-upgrade-cancel.md b/guide/src/templates/help_templates/tx/chan-upgrade-cancel.md new file mode 100644 index 0000000000..ceb38a5f12 --- /dev/null +++ b/guide/src/templates/help_templates/tx/chan-upgrade-cancel.md @@ -0,0 +1,30 @@ +DESCRIPTION: +Relay the channel upgrade cancellation (ChannelUpgradeCancel) + +USAGE: + hermes tx chan-upgrade-cancel --dst-chain --src-chain --dst-connection --dst-port --src-port --src-channel --dst-channel + +OPTIONS: + -h, --help Print help information + +REQUIRED: + --dst-chain + Identifier of the destination chain + + --dst-channel + Identifier of the destination channel (optional) [aliases: dst-chan] + + --dst-connection + Identifier of the destination connection [aliases: dst-conn] + + --dst-port + Identifier of the destination port + + --src-chain + Identifier of the source chain + + --src-channel + Identifier of the source channel (required) [aliases: src-chan] + + --src-port + Identifier of the source port diff --git a/guide/src/templates/help_templates/tx/chan-upgrade-confirm.md b/guide/src/templates/help_templates/tx/chan-upgrade-confirm.md new file mode 100644 index 0000000000..e13588c59d --- /dev/null +++ b/guide/src/templates/help_templates/tx/chan-upgrade-confirm.md @@ -0,0 +1,30 @@ +DESCRIPTION: +Relay the channel upgrade attempt (ChannelUpgradeConfirm) + +USAGE: + hermes tx chan-upgrade-confirm --dst-chain --src-chain --dst-connection --dst-port --src-port --src-channel --dst-channel + +OPTIONS: + -h, --help Print help information + +REQUIRED: + --dst-chain + Identifier of the destination chain + + --dst-channel + Identifier of the destination channel (optional) [aliases: dst-chan] + + --dst-connection + Identifier of the destination connection [aliases: dst-conn] + + --dst-port + Identifier of the destination port + + --src-chain + Identifier of the source chain + + --src-channel + Identifier of the source channel (required) [aliases: src-chan] + + --src-port + Identifier of the source port diff --git a/guide/src/templates/help_templates/tx/chan-upgrade-open.md b/guide/src/templates/help_templates/tx/chan-upgrade-open.md new file mode 100644 index 0000000000..fb878cd41d --- /dev/null +++ b/guide/src/templates/help_templates/tx/chan-upgrade-open.md @@ -0,0 +1,30 @@ +DESCRIPTION: +Relay the channel upgrade attempt (ChannelUpgradeOpen) + +USAGE: + hermes tx chan-upgrade-open --dst-chain --src-chain --dst-connection --dst-port --src-port --src-channel --dst-channel + +OPTIONS: + -h, --help Print help information + +REQUIRED: + --dst-chain + Identifier of the destination chain + + --dst-channel + Identifier of the destination channel (optional) [aliases: dst-chan] + + --dst-connection + Identifier of the destination connection [aliases: dst-conn] + + --dst-port + Identifier of the destination port + + --src-chain + Identifier of the source chain + + --src-channel + Identifier of the source channel (required) [aliases: src-chan] + + --src-port + Identifier of the source port diff --git a/guide/src/templates/help_templates/tx/chan-upgrade-timeout.md b/guide/src/templates/help_templates/tx/chan-upgrade-timeout.md new file mode 100644 index 0000000000..3d783f1a3a --- /dev/null +++ b/guide/src/templates/help_templates/tx/chan-upgrade-timeout.md @@ -0,0 +1,30 @@ +DESCRIPTION: +Relay the channel upgrade timeout (ChannelUpgradeTimeout) + +USAGE: + hermes tx chan-upgrade-timeout --dst-chain --src-chain --dst-connection --dst-port --src-port --src-channel --dst-channel + +OPTIONS: + -h, --help Print help information + +REQUIRED: + --dst-chain + Identifier of the destination chain + + --dst-channel + Identifier of the destination channel (optional) [aliases: dst-chan] + + --dst-connection + Identifier of the destination connection [aliases: dst-conn] + + --dst-port + Identifier of the destination port + + --src-chain + Identifier of the source chain + + --src-channel + Identifier of the source channel (required) [aliases: src-chan] + + --src-port + Identifier of the source port diff --git a/guide/src/templates/help_templates/tx/chan-upgrade-try.md b/guide/src/templates/help_templates/tx/chan-upgrade-try.md new file mode 100644 index 0000000000..6a00fbc211 --- /dev/null +++ b/guide/src/templates/help_templates/tx/chan-upgrade-try.md @@ -0,0 +1,30 @@ +DESCRIPTION: +Relay the channel upgrade attempt (ChannelUpgradeTry) + +USAGE: + hermes tx chan-upgrade-try --dst-chain --src-chain --dst-connection --dst-port --src-port --src-channel --dst-channel + +OPTIONS: + -h, --help Print help information + +REQUIRED: + --dst-chain + Identifier of the destination chain + + --dst-channel + Identifier of the destination channel (optional) [aliases: dst-chan] + + --dst-connection + Identifier of the destination connection [aliases: dst-conn] + + --dst-port + Identifier of the destination port + + --src-chain + Identifier of the source chain + + --src-channel + Identifier of the source channel (required) [aliases: src-chan] + + --src-port + Identifier of the source port diff --git a/guide/src/templates/hermes-version.md b/guide/src/templates/hermes-version.md index 804a616da1..731c6c2cdb 100644 --- a/guide/src/templates/hermes-version.md +++ b/guide/src/templates/hermes-version.md @@ -1 +1 @@ -v1.8.0 +v1.10.5 diff --git a/scripts/auto_gen_templates.sh b/scripts/auto_gen_templates.sh index aaf0c605d8..bbf0650a09 100755 --- a/scripts/auto_gen_templates.sh +++ b/scripts/auto_gen_templates.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # This script is used to generate the templates for the guide SCRIPT_NAME="$0" diff --git a/scripts/one-chain b/scripts/one-chain index 47bf41365e..7ad2e0dfe2 100755 --- a/scripts/one-chain +++ b/scripts/one-chain @@ -89,25 +89,25 @@ sleep 1 # Add samoleans to user USER=$($BINARY --home $CHAIN_DIR/$CHAIN_ID keys --keyring-backend="test" show user -a) -$BINARY --home $CHAIN_DIR/$CHAIN_ID add-genesis-account $USER $USER_COINS &> /dev/null +$BINARY --home $CHAIN_DIR/$CHAIN_ID genesis add-genesis-account $USER $USER_COINS &> /dev/null sleep 1 # Add samoleans to user2 USER2=$($BINARY --home $CHAIN_DIR/$CHAIN_ID keys --keyring-backend="test" show user2 -a) -$BINARY --home $CHAIN_DIR/$CHAIN_ID add-genesis-account $USER2 $USER_COINS &> /dev/null +$BINARY --home $CHAIN_DIR/$CHAIN_ID genesis add-genesis-account $USER2 $USER_COINS &> /dev/null sleep 1 # Add stake to validator VALIDATOR=$($BINARY --home $CHAIN_DIR/$CHAIN_ID keys --keyring-backend="test" show validator -a) -$BINARY --home $CHAIN_DIR/$CHAIN_ID add-genesis-account $VALIDATOR $STAKE &> /dev/null +$BINARY --home $CHAIN_DIR/$CHAIN_ID genesis add-genesis-account $VALIDATOR $STAKE &> /dev/null sleep 1 # Stake everything -$BINARY --home $CHAIN_DIR/$CHAIN_ID gentx validator --keyring-backend="test" --chain-id $CHAIN_ID $STAKE &> /dev/null +$BINARY --home $CHAIN_DIR/$CHAIN_ID genesis gentx validator --keyring-backend="test" --chain-id $CHAIN_ID $STAKE &> /dev/null sleep 1 -$BINARY --home $CHAIN_DIR/$CHAIN_ID collect-gentxs &> /dev/null +$BINARY --home $CHAIN_DIR/$CHAIN_ID genesis collect-gentxs &> /dev/null sleep 1 # Check platform @@ -121,23 +121,25 @@ fi echo "Change settings in config.toml file..." if [ $platform = 'linux' ]; then sed -i 's#"172800s"#"200s"#g' $CHAIN_DIR/$CHAIN_ID/config/genesis.json - sed -i 's#"tcp://127.0.0.1:26657"#"tcp://0.0.0.0:'"$RPC_PORT"'"#g' $CHAIN_DIR/$CHAIN_ID/config/config.toml + sed -i 's#"tcp://0.0.0.0:26657"#"tcp://0.0.0.0:'"$RPC_PORT"'"#g' $CHAIN_DIR/$CHAIN_ID/config/config.toml sed -i 's#"tcp://0.0.0.0:26656"#"tcp://0.0.0.0:'"$P2P_PORT"'"#g' $CHAIN_DIR/$CHAIN_ID/config/config.toml sed -i 's#"localhost:6060"#"localhost:'"$PROF_PORT"'"#g' $CHAIN_DIR/$CHAIN_ID/config/config.toml sed -i 's/timeout_commit = "5s"/timeout_commit = "1s"/g' $CHAIN_DIR/$CHAIN_ID/config/config.toml sed -i 's/timeout_propose = "3s"/timeout_propose = "1s"/g' $CHAIN_DIR/$CHAIN_ID/config/config.toml sed -i 's/index_all_keys = false/index_all_keys = true/g' $CHAIN_DIR/$CHAIN_ID/config/config.toml sed -i '/^\[grpc-web\]/,/^\[/s/^enable = true/enable = false/' $CHAIN_DIR/$CHAIN_ID/config/app.toml + sed -i 's/minimum-gas-prices = ""/minimum-gas-prices = "0stake"/g' $CHAIN_DIR/$CHAIN_ID/config/app.toml # sed -i '' 's#index-events = \[\]#index-events = \["message.action","send_packet.packet_src_channel","send_packet.packet_sequence"\]#g' $CHAIN_DIR/$CHAIN_ID/config/app.toml else sed -i '' 's#"172800s"#"200s"#g' $CHAIN_DIR/$CHAIN_ID/config/genesis.json - sed -i '' 's#"tcp://127.0.0.1:26657"#"tcp://0.0.0.0:'"$RPC_PORT"'"#g' $CHAIN_DIR/$CHAIN_ID/config/config.toml + sed -i '' 's#"tcp://0.0.0.0:26657"#"tcp://0.0.0.0:'"$RPC_PORT"'"#g' $CHAIN_DIR/$CHAIN_ID/config/config.toml sed -i '' 's#"tcp://0.0.0.0:26656"#"tcp://0.0.0.0:'"$P2P_PORT"'"#g' $CHAIN_DIR/$CHAIN_ID/config/config.toml sed -i '' 's#"localhost:6060"#"localhost:'"$PROF_PORT"'"#g' $CHAIN_DIR/$CHAIN_ID/config/config.toml sed -i '' 's/timeout_commit = "5s"/timeout_commit = "1s"/g' $CHAIN_DIR/$CHAIN_ID/config/config.toml sed -i '' 's/timeout_propose = "3s"/timeout_propose = "1s"/g' $CHAIN_DIR/$CHAIN_ID/config/config.toml sed -i '' 's/index_all_keys = false/index_all_keys = true/g' $CHAIN_DIR/$CHAIN_ID/config/config.toml sed -i '' '/^\[grpc-web\]/,/^\[/s/^enable = true/enable = false/' $CHAIN_DIR/$CHAIN_ID/config/app.toml + sed -i '' 's/minimum-gas-prices = ""/minimum-gas-prices = "0stake"/g' $CHAIN_DIR/$CHAIN_ID/config/app.toml # sed -i '' 's/min-retain-blocks = 0/min-retain-blocks = 100/g' $CHAIN_DIR/$CHAIN_ID/config/app.toml # sed -i '' 's#index-events = \[\]#index-events = \["message.action","send_packet.packet_src_channel","send_packet.packet_sequence"\]#g' $CHAIN_DIR/$CHAIN_ID/config/app.toml # sed -i '' 's/error/debug/g' $CHAIN_DIR/$CHAIN_ID/config/config.toml @@ -146,7 +148,7 @@ fi # Start gaia echo "Start gaia on grpc port: $GRPC_PORT..." -$BINARY --home $CHAIN_DIR/$CHAIN_ID start --pruning=nothing --grpc.address="0.0.0.0:$GRPC_PORT" --log_level info > $CHAIN_DIR/$CHAIN_ID.log 2>&1 & +$BINARY --home $CHAIN_DIR/$CHAIN_ID start --pruning=nothing --rpc.laddr="tcp://0.0.0.0:$RPC_PORT" --grpc.address="0.0.0.0:$GRPC_PORT" --log_level info > $CHAIN_DIR/$CHAIN_ID.log 2>&1 & # Show validator's and user's balance sleep 3 diff --git a/tools/check-guide/Cargo.lock b/tools/check-guide/Cargo.lock index e5ab2c34a5..645b211df2 100644 --- a/tools/check-guide/Cargo.lock +++ b/tools/check-guide/Cargo.lock @@ -23,7 +23,7 @@ dependencies = [ "termcolor", "toml 0.5.11", "tracing", - "tracing-log", + "tracing-log 0.1.4", "tracing-subscriber", "wait-timeout", ] @@ -58,18 +58,18 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aho-corasick" -version = "1.1.1" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "ammonia" -version = "3.3.0" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e6d1c7838db705c9b756557ee27c384ce695a1c51a6fe528784cb1c6840170" +checksum = "1ab99eae5ee58501ab236beb6f20f6ca39be615267b014899c89b2f0bc18a459" dependencies = [ "html5ever", "maplit", @@ -95,63 +95,76 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.4" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.4" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" [[package]] name = "anstyle-parse" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.1" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" dependencies = [ "anstyle", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "anyhow" -version = "1.0.75" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "arc-swap" -version = "1.6.0" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + +[[package]] +name = "arrayref" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "async-stream" @@ -172,33 +185,34 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.65", ] [[package]] name = "async-trait" -version = "0.1.73" +version = "0.1.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" +checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.65", ] [[package]] name = "async-tungstenite" -version = "0.23.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1e9efbe14612da0a19fb983059a0b621e9cf6225d7018ecab4f9988215540dc" +checksum = "3609af4bbf701ddaf1f6bb4e6257dff4ff8932327d0e685d3f653724c258b1ac" dependencies = [ "futures-io", "futures-util", "log", "pin-project-lite", - "rustls-native-certs", + "rustls-native-certs 0.7.0", + "rustls-pki-types", "tokio", - "tokio-rustls", + "tokio-rustls 0.25.0", "tungstenite", ] @@ -215,9 +229,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "axum" @@ -230,7 +244,7 @@ dependencies = [ "bitflags 1.3.2", "bytes", "futures-util", - "http", + "http 0.2.12", "http-body", "hyper", "itoa", @@ -260,7 +274,7 @@ dependencies = [ "async-trait", "bytes", "futures-util", - "http", + "http 0.2.12", "http-body", "mime", "rustversion", @@ -270,13 +284,13 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ "addr2line", "cc", - "cfg-if 1.0.0", + "cfg-if", "libc", "miniz_oxide", "object", @@ -291,15 +305,15 @@ checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] name = "base64" -version = "0.13.1" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "base64" -version = "0.21.4" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" @@ -336,13 +350,13 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitcoin" -version = "0.31.1" +version = "0.31.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd00f3c09b5f21fb357abe32d29946eb8bb7a0862bae62c0b5e4a692acbbe73c" +checksum = "6c85783c2fe40083ea54a33aa2f0ba58831d90fcd190f5bdc47e74e84d2a96ae" dependencies = [ "bech32 0.10.0-beta", "bitcoin-internals", - "bitcoin_hashes 0.13.0", + "bitcoin_hashes", "hex-conservative", "hex_lit", "secp256k1", @@ -358,21 +372,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bitcoin-private" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73290177011694f38ec25e165d0387ab7ea749a4b81cd4c80dae5988229f7a57" - -[[package]] -name = "bitcoin_hashes" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d7066118b13d4b20b23645932dfb3a81ce7e29f95726c2036fa33cd7b092501" -dependencies = [ - "bitcoin-private", -] - [[package]] name = "bitcoin_hashes" version = "0.13.0" @@ -392,9 +391,31 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.0" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + +[[package]] +name = "blake2" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "blake3" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30cca6d3674597c30ddf2c587bf8d9d65c9a84d2326d941cc79c9842dfe0ef52" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", +] [[package]] name = "block-buffer" @@ -416,29 +437,29 @@ dependencies = [ [[package]] name = "bs58" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" dependencies = [ "tinyvec", ] [[package]] name = "bstr" -version = "1.6.2" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c2f7349907b712260e64b0afe2f84692af14a454be26187d9df565c7f69266a" +checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" dependencies = [ "memchr", - "regex-automata 0.3.9", + "regex-automata 0.4.6", "serde", ] [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byte-unit" @@ -450,32 +471,17 @@ dependencies = [ "utf8-width", ] -[[package]] -name = "bytecount" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad152d03a2c813c80bb94fedbf3a3f02b28f793e39e7c214c8a0bcc196343de7" - [[package]] name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "bytes" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" -dependencies = [ - "serde", -] +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] -name = "camino" -version = "1.1.6" +name = "bytes" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" dependencies = [ "serde", ] @@ -486,42 +492,11 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e9e01327e6c86e92ec72b1c798d4a94810f147209bbe3ffab6a86954937a6f" -[[package]] -name = "cargo-platform" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cfa25e60aea747ec7e1124f238816749faa93759c6ff5b31f1ccdda137f4479" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", -] - [[package]] name = "cc" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] - -[[package]] -name = "cfg-if" -version = "0.1.10" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" [[package]] name = "cfg-if" @@ -543,14 +518,14 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.31" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", "num-traits", - "windows-targets 0.48.5", + "windows-targets 0.52.5", ] [[package]] @@ -565,30 +540,30 @@ dependencies = [ "clap_lex 0.2.4", "indexmap 1.9.3", "once_cell", - "strsim", + "strsim 0.10.0", "termcolor", "textwrap", ] [[package]] name = "clap" -version = "4.4.6" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.4.6" +version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" dependencies = [ "anstream", "anstyle", - "clap_lex 0.5.1", - "strsim", + "clap_lex 0.7.0", + "strsim 0.11.1", "terminal_size", ] @@ -603,11 +578,11 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.4.3" +version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ae8ba90b9d8b007efe66e55e48fb936272f5ca00349b5b0e89877520d35ea7" +checksum = "dd79504325bf38b10165b02e89b4347300f855f273c4cb30c4a3209e6583275e" dependencies = [ - "clap 4.4.6", + "clap 4.5.4", ] [[package]] @@ -634,15 +609,15 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.5.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "color-eyre" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a667583cca8c4f8436db8de46ea8233c42a7d9ae424a82d338f2e4675229204" +checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5" dependencies = [ "backtrace", "color-spantrace", @@ -655,9 +630,9 @@ dependencies = [ [[package]] name = "color-spantrace" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ba75b3d9449ecdccb27ecbc479fdc0b87fa2dd43d2f8298f9bf0e59aacc8dce" +checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2" dependencies = [ "once_cell", "owo-colors", @@ -667,28 +642,34 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" [[package]] name = "console" -version = "0.15.7" +version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" dependencies = [ "encode_unicode", "lazy_static", "libc", "unicode-width", - "windows-sys 0.45.0", + "windows-sys 0.52.0", ] [[package]] name = "const-oid" -version = "0.9.5" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "constant_time_eq" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" [[package]] name = "contracts" @@ -703,9 +684,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", @@ -713,67 +694,52 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "cpufeatures" -version = "0.2.9" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] [[package]] name = "crossbeam-channel" -version = "0.4.4" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" dependencies = [ - "crossbeam-utils 0.7.2", - "maybe-uninit", + "crossbeam-utils", ] [[package]] -name = "crossbeam-channel" -version = "0.5.11" +name = "crossbeam-deque" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ - "crossbeam-utils 0.8.19", + "crossbeam-epoch", + "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.15" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "autocfg", - "cfg-if 1.0.0", - "crossbeam-utils 0.8.19", - "memoffset", - "scopeguard", -] - -[[package]] -name = "crossbeam-utils" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" -dependencies = [ - "autocfg", - "cfg-if 0.1.10", - "lazy_static", + "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" @@ -783,9 +749,9 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-bigint" -version = "0.5.3" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "740fe28e594155f10cfc383984cbefd529d7396050557148f79cb0f621204124" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array", "rand_core", @@ -805,11 +771,11 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.1.1" +version = "4.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89b8c6a2e4b1f45971ad09761aafb85514a84744b67a95e32c3cc1352d1f65c" +checksum = "0a677b8922c94e01bdbb12126b0bc852f00447528dee1782229af9c720c3f348" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "curve25519-dalek-derive", "digest 0.10.7", @@ -822,13 +788,13 @@ dependencies = [ [[package]] name = "curve25519-dalek-derive" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.65", ] [[package]] @@ -850,8 +816,8 @@ version = "5.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ - "cfg-if 1.0.0", - "hashbrown 0.14.1", + "cfg-if", + "hashbrown 0.14.5", "lock_api", "once_cell", "parking_lot_core", @@ -859,15 +825,26 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.4.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + +[[package]] +name = "dbus" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bb21987b9fb1613058ba3843121dd18b163b254d8a6e797e144cbac14d96d1b" +dependencies = [ + "libc", + "libdbus-sys", + "winapi", +] [[package]] name = "der" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", "zeroize", @@ -875,9 +852,12 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.8" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] [[package]] name = "derivation-path" @@ -898,13 +878,14 @@ dependencies = [ [[package]] name = "dialoguer" -version = "0.10.4" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59c6f2989294b9a498d3ad5491a79c6deb604617378e1cdc4bfc1c1361fe2f87" +checksum = "658bce805d770f407bc62102fca7c2c64ceef2fbcb2b8bd19d2765ce093980de" dependencies = [ "console", "shell-words", "tempfile", + "thiserror", "zeroize", ] @@ -935,7 +916,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "dirs-sys-next", ] @@ -952,9 +933,9 @@ dependencies = [ [[package]] name = "ecdsa" -version = "0.16.8" +version = "0.16.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ "der", "digest 0.10.7", @@ -966,9 +947,9 @@ dependencies = [ [[package]] name = "ed25519" -version = "2.2.2" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60f6d271ca33075c88028be6f04d502853d63a5ece419d269c15315d4fc1cf1d" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ "pkcs8", "serde", @@ -990,15 +971,16 @@ dependencies = [ [[package]] name = "ed25519-dalek" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7277392b266383ef8396db7fdeb1e77b6c52fed775f5df15bb24f35b72156980" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" dependencies = [ "curve25519-dalek", "ed25519", "rand_core", "serde", "sha2 0.10.8", + "subtle", "zeroize", ] @@ -1016,9 +998,9 @@ dependencies = [ [[package]] name = "either" -version = "1.9.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" [[package]] name = "elasticlunr-rs" @@ -1034,9 +1016,9 @@ dependencies = [ [[package]] name = "elliptic-curve" -version = "0.13.6" +version = "0.13.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97ca172ae9dc9f9b779a6e3a65d308f2af74e5b8c921299075bdb4a0370e914" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ "base16ct", "crypto-bigint", @@ -1059,11 +1041,21 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "encoding_rs" -version = "0.8.33" +version = "0.8.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", +] + +[[package]] +name = "env_filter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" +dependencies = [ + "log", + "regex", ] [[package]] @@ -1081,15 +1073,15 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.10.0" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" dependencies = [ + "anstream", + "anstyle", + "env_filter", "humantime", - "is-terminal", "log", - "regex", - "termcolor", ] [[package]] @@ -1100,39 +1092,19 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "add4f07d43996f76ef320709726a556a9d4f965d9410d8d0271132d2f8293480" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ - "cc", "libc", -] - -[[package]] -name = "error-chain" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" -dependencies = [ - "version_check", + "windows-sys 0.52.0", ] [[package]] name = "eyre" -version = "0.6.8" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" dependencies = [ "indenter", "once_cell", @@ -1150,9 +1122,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] name = "ff" @@ -1166,20 +1138,20 @@ dependencies = [ [[package]] name = "fiat-crypto" -version = "0.2.1" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0870c84016d4b481be5c9f323c24f65e31e901ae618f0e80f4308fb00de1d2d" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "filetime" -version = "0.2.22" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", - "redox_syscall 0.3.5", - "windows-sys 0.48.0", + "redox_syscall 0.4.1", + "windows-sys 0.52.0", ] [[package]] @@ -1197,7 +1169,6 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c606d892c9de11507fa0dcffc116434f94e105d0bbdc4e405b61519464c49d7b" dependencies = [ - "anyhow", "eyre", "paste", ] @@ -1210,18 +1181,21 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] [[package]] name = "fs-err" -version = "2.9.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0845fa252299212f0389d64ba26f34fa32cfe41588355f21ed507c59a0f64541" +checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" +dependencies = [ + "autocfg", +] [[package]] name = "fsevent-sys" @@ -1244,9 +1218,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", @@ -1259,9 +1233,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", @@ -1269,15 +1243,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", @@ -1286,38 +1260,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.65", ] [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-channel", "futures-core", @@ -1344,11 +1318,11 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "libc", "wasi", @@ -1357,27 +1331,21 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" - -[[package]] -name = "glob" -version = "0.3.1" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "globset" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759c97c1e17c55525b57192c06a267cda0ac5210b222d6b82189a2338fa1c13d" +checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" dependencies = [ "aho-corasick", "bstr", - "fnv", "log", - "regex", + "regex-automata 0.4.6", + "regex-syntax 0.8.3", ] [[package]] @@ -1391,39 +1359,19 @@ dependencies = [ "subtle", ] -[[package]] -name = "gumdrop" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bc700f989d2f6f0248546222d9b4258f5b02a171a431f8285a81c08142629e3" -dependencies = [ - "gumdrop_derive", -] - -[[package]] -name = "gumdrop_derive" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "729f9bd3449d77e7831a18abfb7ba2f99ee813dfd15b8c2167c9a54ba20aa99d" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "h2" -version = "0.3.21" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" dependencies = [ "bytes", "fnv", "futures-core", "futures-sink", "futures-util", - "http", - "indexmap 1.9.3", + "http 0.2.12", + "indexmap 2.2.6", "slab", "tokio", "tokio-util", @@ -1432,15 +1380,15 @@ dependencies = [ [[package]] name = "half" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" +checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" [[package]] name = "handlebars" -version = "4.4.0" +version = "5.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c39b3bc2a8f715298032cf5087e58573809374b08160aa7d750582bdb82d2683" +checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b" dependencies = [ "log", "pest", @@ -1458,9 +1406,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.1" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "hdpath" @@ -1477,10 +1425,10 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" dependencies = [ - "base64 0.21.4", + "base64 0.21.7", "bytes", "headers-core", - "http", + "http 0.2.12", "httpdate", "mime", "sha1", @@ -1492,7 +1440,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" dependencies = [ - "http", + "http 0.2.12", ] [[package]] @@ -1512,9 +1460,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.3" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hex" @@ -1524,9 +1472,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hex-conservative" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2" +checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20" [[package]] name = "hex_lit" @@ -1545,23 +1493,34 @@ dependencies = [ [[package]] name = "html5ever" -version = "0.26.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" +checksum = "c13771afe0e6e846f1e67d038d4cb29998a6779f93c809212e4e9c32efd244d4" dependencies = [ "log", "mac", "markup5ever", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.65", ] [[package]] name = "http" -version = "0.2.9" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" dependencies = [ "bytes", "fnv", @@ -1570,12 +1529,12 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http", + "http 0.2.12", "pin-project-lite", ] @@ -1609,22 +1568,22 @@ dependencies = [ [[package]] name = "hyper" -version = "0.14.27" +version = "0.14.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" dependencies = [ "bytes", "futures-channel", "futures-core", "futures-util", "h2", - "http", + "http 0.2.12", "http-body", "httparse", "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.9", + "socket2", "tokio", "tower-service", "tracing", @@ -1633,16 +1592,16 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", - "http", + "http 0.2.12", "hyper", - "rustls", + "rustls 0.21.12", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", ] [[package]] @@ -1659,16 +1618,16 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.57" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows", + "windows-core", ] [[package]] @@ -1682,15 +1641,15 @@ dependencies = [ [[package]] name = "ibc-chain-registry" -version = "0.26.4" +version = "0.27.2" dependencies = [ "async-trait", "flex-error", "futures", - "http", + "http 0.2.12", "ibc-proto", "ibc-relayer-types", - "itertools 0.10.5", + "itertools", "reqwest", "serde", "serde_json", @@ -1701,14 +1660,15 @@ dependencies = [ [[package]] name = "ibc-proto" -version = "0.39.0" +version = "0.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b5aca9ca863246a2b358e0a1845759780860673e54c0a76335faccc504981c" +checksum = "66080040d5a4800d52966d55b055400f86b79c34b854b935bef03c87aacda62a" dependencies = [ - "base64 0.21.4", + "base64 0.22.1", "bytes", "flex-error", "ics23", + "informalsystems-pbjson", "prost", "serde", "subtle-encoding", @@ -1718,7 +1678,7 @@ dependencies = [ [[package]] name = "ibc-relayer" -version = "0.26.4" +version = "0.27.2" dependencies = [ "anyhow", "async-stream", @@ -1727,7 +1687,7 @@ dependencies = [ "bs58", "byte-unit", "bytes", - "crossbeam-channel 0.5.11", + "crossbeam-channel", "digest 0.10.7", "dirs-next", "ed25519", @@ -1738,15 +1698,14 @@ dependencies = [ "generic-array", "hdpath", "hex", - "http", + "http 0.2.12", "humantime", "humantime-serde", "ibc-proto", "ibc-relayer-types", "ibc-telemetry", - "itertools 0.10.5", + "itertools", "moka", - "monostate", "num-bigint", "num-rational", "once_cell", @@ -1775,37 +1734,37 @@ dependencies = [ "tiny-keccak", "tokio", "tokio-stream", - "toml 0.8.8", + "toml 0.8.13", "tonic", "tracing", "tracing-subscriber", - "uuid 1.7.0", + "uuid", ] [[package]] name = "ibc-relayer-cli" -version = "1.7.4" +version = "1.8.2" dependencies = [ "abscissa_core", "clap 3.2.25", "clap_complete 3.2.5", "color-eyre", "console", - "crossbeam-channel 0.5.11", + "crossbeam-channel", "dialoguer", "dirs-next", "eyre", "flex-error", "futures", "hdpath", - "http", + "http 0.2.12", "humantime", "ibc-chain-registry", "ibc-relayer", "ibc-relayer-rest", "ibc-relayer-types", "ibc-telemetry", - "itertools 0.10.5", + "itertools", "oneline-eyre", "regex", "serde", @@ -1823,10 +1782,10 @@ dependencies = [ [[package]] name = "ibc-relayer-rest" -version = "0.26.4" +version = "0.27.2" dependencies = [ "axum", - "crossbeam-channel 0.5.11", + "crossbeam-channel", "ibc-relayer", "ibc-relayer-types", "serde", @@ -1836,14 +1795,14 @@ dependencies = [ [[package]] name = "ibc-relayer-types" -version = "0.26.4" +version = "0.27.2" dependencies = [ "bytes", "derive_more", "flex-error", "ibc-proto", "ics23", - "itertools 0.10.5", + "itertools", "num-rational", "primitive-types", "prost", @@ -1855,14 +1814,14 @@ dependencies = [ "tendermint", "tendermint-light-client-verifier", "tendermint-proto", - "tendermint-testgen", "time", + "tracing", "uint", ] [[package]] name = "ibc-telemetry" -version = "0.26.4" +version = "0.27.2" dependencies = [ "axum", "dashmap", @@ -1881,11 +1840,13 @@ dependencies = [ [[package]] name = "ics23" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "661e2d6f79952a65bc92b1c81f639ebd37228dae6ff412a5aba7d474bdc4b957" +checksum = "dc3b8be84e7285c73b88effdc3294b552277d6b0ec728ee016c861b7b9a2c19c" dependencies = [ "anyhow", + "blake2", + "blake3", "bytes", "hex", "informalsystems-pbjson", @@ -1904,9 +1865,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -1914,17 +1875,16 @@ dependencies = [ [[package]] name = "ignore" -version = "0.4.20" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492" +checksum = "b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1" dependencies = [ + "crossbeam-deque", "globset", - "lazy_static", "log", "memchr", - "regex", + "regex-automata 0.4.6", "same-file", - "thread_local", "walkdir", "winapi-util", ] @@ -1956,21 +1916,21 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.2" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown 0.14.1", + "hashbrown 0.14.5", ] [[package]] name = "informalsystems-pbjson" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4eecd90f87bea412eac91c6ef94f6b1e390128290898cbe14f2b926787ae1fb" +checksum = "9aa4a0980c8379295100d70854354e78df2ee1c6ca0f96ffe89afeb3140e3a3d" dependencies = [ - "base64 0.13.1", + "base64 0.21.7", "serde", ] @@ -1996,61 +1956,47 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] -name = "is-terminal" -version = "0.4.9" +name = "is_terminal_polyfill" +version = "1.70.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" -dependencies = [ - "hermit-abi 0.3.3", - "rustix", - "windows-sys 0.48.0", -] +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" [[package]] name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] [[package]] name = "k256" -version = "0.13.1" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "ecdsa", "elliptic-curve", "sha2 0.10.8", @@ -2058,9 +2004,9 @@ dependencies = [ [[package]] name = "keccak" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" dependencies = [ "cpufeatures", ] @@ -2093,21 +2039,41 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.148" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libdbus-sys" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" +checksum = "06085512b750d640299b79be4bad3d2fa90a9c00b1fd9e1b46364f66f0485c72" +dependencies = [ + "cc", + "pkg-config", +] + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.5.0", + "libc", +] [[package]] name = "linux-raw-sys" -version = "0.4.8" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3852614a3bd9ca9804678ba6be5e3b8ce76dfc902cae004e3e0c44051b6e88db" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "lock_api" -version = "0.4.10" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -2115,9 +2081,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "mac" @@ -2125,15 +2091,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" -[[package]] -name = "mach2" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d0d1830bcd151a6fc4aea1369af235b36c1528fe976b8ff678683c9995eade8" -dependencies = [ - "libc", -] - [[package]] name = "maplit" version = "1.0.2" @@ -2142,9 +2099,9 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" [[package]] name = "markup5ever" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" +checksum = "16ce3abbeba692c8b8441d036ef91aea6df8da2c6b6e21c7e14d3c18e526be45" dependencies = [ "log", "phf", @@ -2169,25 +2126,19 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" -[[package]] -name = "maybe-uninit" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" - [[package]] name = "mdbook" -version = "0.4.35" +version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c3f88addd34930bc5f01b9dc19f780447e51c92bf2536e3ded058018271775d" +checksum = "b45a38e19bd200220ef07c892b0157ad3d2365e5b5a267ca01ad12182491eea5" dependencies = [ "ammonia", "anyhow", "chrono", - "clap 4.4.6", - "clap_complete 4.4.3", + "clap 4.5.4", + "clap_complete 4.5.2", "elasticlunr-rs", - "env_logger 0.10.0", + "env_logger 0.11.3", "futures-util", "handlebars", "ignore", @@ -2197,6 +2148,7 @@ dependencies = [ "notify-debouncer-mini", "once_cell", "opener", + "pathdiff", "pulldown-cmark", "regex", "serde", @@ -2206,14 +2158,15 @@ dependencies = [ "tokio", "toml 0.5.11", "topological-sort", + "walkdir", "warp", ] [[package]] name = "mdbook-template" -version = "1.1.0" +version = "1.1.1+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "920f69694a682c1100d64ca342278fc289d7d89b905a60c39ca39e0ea04ce0f1" +checksum = "24ababe45effcc8453d4dc68de0d699d6858399b6f20ecfaf616a1ca2e0c6aa3" dependencies = [ "anyhow", "clap 3.2.25", @@ -2228,18 +2181,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.6.4" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" - -[[package]] -name = "memoffset" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" -dependencies = [ - "autocfg", -] +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "mime" @@ -2259,18 +2203,18 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.8.8" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", @@ -2280,59 +2224,37 @@ dependencies = [ [[package]] name = "moka" -version = "0.12.1" +version = "0.12.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8017ec3548ffe7d4cef7ac0e12b044c01164a74c0f3119420faeaf13490ad8b" +checksum = "9e0d88686dc561d743b40de8269b26eaf0dc58781bde087b0984646602021d08" dependencies = [ - "crossbeam-channel 0.5.11", + "crossbeam-channel", "crossbeam-epoch", - "crossbeam-utils 0.8.19", + "crossbeam-utils", "once_cell", "parking_lot", "quanta", "rustc_version", - "skeptic", "smallvec", "tagptr", "thiserror", "triomphe", - "uuid 1.7.0", -] - -[[package]] -name = "monostate" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "878c2a1f1c70e5724fa28f101ca787b6a7e8ad5c5e4ae4ca3b0fa4a419fa9075" -dependencies = [ - "monostate-impl", - "serde", -] - -[[package]] -name = "monostate-impl" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f686d68a09079e63b1d2c64aa305095887ce50565f00a922ebfaeeee0d9ba6ce" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", + "uuid", ] [[package]] name = "new_debug_unreachable" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] name = "normpath" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec60c60a693226186f5d6edf073232bfb6464ed97eb22cf3b01c1e8198fd97f5" +checksum = "5831952a9476f2fed74b77d74182fa5ddc4d21c72ec45a333b250e3ed0272804" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -2341,8 +2263,8 @@ version = "6.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" dependencies = [ - "bitflags 2.4.0", - "crossbeam-channel 0.5.11", + "bitflags 2.5.0", + "crossbeam-channel", "filetime", "fsevent-sys", "inotify", @@ -2356,11 +2278,12 @@ dependencies = [ [[package]] name = "notify-debouncer-mini" -version = "0.3.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e55ee272914f4563a2f8b8553eb6811f3c0caea81c756346bad15b7e3ef969f0" +checksum = "5d40b221972a1fc5ef4d858a2f671fb34c75983eb385463dff3780eeff6a9d43" dependencies = [ - "crossbeam-channel 0.5.11", + "crossbeam-channel", + "log", "notify", ] @@ -2376,44 +2299,36 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" dependencies = [ - "autocfg", "num-integer", "num-traits", "serde", ] [[package]] -name = "num-derive" -version = "0.3.3" +name = "num-conv" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] [[package]] name = "num-rational" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ - "autocfg", "num-bigint", "num-integer", "num-traits", @@ -2422,9 +2337,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] @@ -2435,15 +2350,15 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.3", + "hermit-abi 0.3.9", "libc", ] [[package]] name = "object" -version = "0.32.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ "memchr", ] @@ -2465,19 +2380,20 @@ dependencies = [ [[package]] name = "opaque-debug" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "opener" -version = "0.6.1" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c62dcb6174f9cb326eac248f07e955d5d559c272730b6c03e396b443b562788" +checksum = "f8df34be653210fbe9ffaff41d3b92721c56ce82dfee58ee684f9afb5e3a90c0" dependencies = [ "bstr", + "dbus", "normpath", - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -2530,7 +2446,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b3a2a91fdbfdd4d212c0dcc2ab540de2c2bcbbd90be17de7a7daf8822d010c1" dependencies = [ "async-trait", - "crossbeam-channel 0.5.11", + "crossbeam-channel", "dashmap", "fnv", "futures-channel", @@ -2545,9 +2461,9 @@ dependencies = [ [[package]] name = "os_str_bytes" -version = "6.5.1" +version = "6.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" [[package]] name = "overload" @@ -2563,9 +2479,9 @@ checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" dependencies = [ "lock_api", "parking_lot_core", @@ -2573,22 +2489,28 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.8" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", - "redox_syscall 0.3.5", + "redox_syscall 0.5.1", "smallvec", - "windows-targets 0.48.5", + "windows-targets 0.52.5", ] [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" [[package]] name = "pbkdf2" @@ -2601,9 +2523,9 @@ dependencies = [ [[package]] name = "peg" -version = "0.7.0" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07c0b841ea54f523f7aa556956fbd293bcbe06f2e67d2eb732b7278aaf1d166a" +checksum = "8a625d12ad770914cbf7eff6f9314c3ef803bfe364a1b20bc36ddf56673e71e5" dependencies = [ "peg-macros", "peg-runtime", @@ -2611,9 +2533,9 @@ dependencies = [ [[package]] name = "peg-macros" -version = "0.7.0" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aa52829b8decbef693af90202711348ab001456803ba2a98eb4ec8fb70844c" +checksum = "f241d42067ed3ab6a4fece1db720838e1418f36d868585a27931f95d6bc03582" dependencies = [ "peg-runtime", "proc-macro2", @@ -2622,21 +2544,21 @@ dependencies = [ [[package]] name = "peg-runtime" -version = "0.7.0" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c719dcf55f09a3a7e764c6649ab594c18a177e3599c467983cdf644bfc0a4088" +checksum = "e3aeb8f54c078314c2065ee649a7241f46b9d8e418e1a9581ba0546657d7aa3a" [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.4" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c022f1e7b65d6a24c0dbbd5fb344c66881bc01f3e5ae74a1c8100f2f985d98a4" +checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" dependencies = [ "memchr", "thiserror", @@ -2645,9 +2567,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.4" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35513f630d46400a977c4cb58f78e1bfbe01434316e60c37d27b9ad6139c66d8" +checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459" dependencies = [ "pest", "pest_generator", @@ -2655,22 +2577,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.4" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc9fc1b9e7057baba189b5c626e2d6f40681ae5b6eb064dc7c7834101ec8123a" +checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.65", ] [[package]] name = "pest_meta" -version = "2.7.4" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df74e9e7ec4053ceb980e7c0c8bd3594e977fde1af91daba9c928e8e8c6708d" +checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd" dependencies = [ "once_cell", "pest", @@ -2679,21 +2601,21 @@ dependencies = [ [[package]] name = "phf" -version = "0.10.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" dependencies = [ - "phf_shared", + "phf_shared 0.11.2", ] [[package]] name = "phf_codegen" -version = "0.10.0" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" +checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" dependencies = [ - "phf_generator", - "phf_shared", + "phf_generator 0.11.2", + "phf_shared 0.11.2", ] [[package]] @@ -2702,7 +2624,17 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" dependencies = [ - "phf_shared", + "phf_shared 0.10.0", + "rand", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared 0.11.2", "rand", ] @@ -2715,31 +2647,40 @@ dependencies = [ "siphasher", ] +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project" -version = "1.1.3" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.3" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.65", ] [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -2757,11 +2698,23 @@ dependencies = [ "spki", ] +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + [[package]] name = "platforms" -version = "3.1.2" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db23d408679286588f4d4644f965003d056e3dd5abcaaa938116871d7ce2fee7" + +[[package]] +name = "powerfmt" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4503fa043bf02cee09a9582e9554b4c6403b2ef55e4612e96561d294419429f8" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" @@ -2777,9 +2730,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "primitive-types" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" dependencies = [ "fixed-hash", "impl-serde", @@ -2812,20 +2765,20 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43" dependencies = [ "unicode-ident", ] [[package]] name = "prometheus" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "449811d15fbdf5ceb5c1144416066429cf82316e2ec8ce0c1f6f8a02e7bbcf8c" +checksum = "3d33c28a30771f7f96db69893f78b857f7450d7e0237e9c8fc6427a81bae7ed1" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "fnv", "lazy_static", "memchr", @@ -2836,9 +2789,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.12.1" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fdd22f3b9c31b53c060df4a0613a1c7f062d4115a2b984dd15b1858f7e340d" +checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" dependencies = [ "bytes", "prost-derive", @@ -2846,22 +2799,22 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.12.1" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "265baba7fabd416cf5078179f7d2cbeca4ce7a9041111900675ea7c4cb8a4c32" +checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.65", ] [[package]] name = "prost-types" -version = "0.12.1" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e081b29f63d83a4bc75cfc9f3fe424f9156cf92d8a4f0c9407cce9a1b67327cf" +checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" dependencies = [ "prost", ] @@ -2874,24 +2827,30 @@ checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" [[package]] name = "pulldown-cmark" -version = "0.9.3" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998" +checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", "memchr", + "pulldown-cmark-escape", "unicase", ] +[[package]] +name = "pulldown-cmark-escape" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd348ff538bc9caeda7ee8cad2d1d48236a1f443c1fa3913c6a02fe0043b1dd3" + [[package]] name = "quanta" -version = "0.11.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17e662a7a8291a865152364c20c7abc5e60486ab2001e8ec10b24862de0b9ab" +checksum = "8e5167a477619228a0b284fac2674e3c388cba90631d7b7de620e6f1fcd08da5" dependencies = [ - "crossbeam-utils 0.8.19", + "crossbeam-utils", "libc", - "mach2", "once_cell", "raw-cpuid", "wasi", @@ -2901,9 +2860,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -2940,52 +2899,52 @@ dependencies = [ [[package]] name = "raw-cpuid" -version = "10.7.0" +version = "11.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332" +checksum = "e29830cbb1290e404f24c73af91c5d8d631ce7e128691e9477556b540cd01ecd" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", ] [[package]] name = "redox_syscall" -version = "0.2.16" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "redox_syscall" -version = "0.3.5" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", ] [[package]] name = "redox_users" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" dependencies = [ "getrandom", - "redox_syscall 0.2.16", + "libredox", "thiserror", ] [[package]] name = "regex" -version = "1.9.6" +version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebee201405406dbf528b8b672104ae6d6d63e6d118cb10e4d51abbc7b58044ff" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.3.9", - "regex-syntax 0.7.5", + "regex-automata 0.4.6", + "regex-syntax 0.8.3", ] [[package]] @@ -2999,13 +2958,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.9" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.5", + "regex-syntax 0.8.3", ] [[package]] @@ -3016,23 +2975,23 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.5" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "reqwest" -version = "0.11.22" +version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ - "base64 0.21.4", + "base64 0.21.7", "bytes", "encoding_rs", "futures-core", "futures-util", "h2", - "http", + "http 0.2.12", "http-body", "hyper", "hyper-rustls", @@ -3043,15 +3002,16 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls", - "rustls-native-certs", - "rustls-pemfile", + "rustls 0.21.12", + "rustls-native-certs 0.6.3", + "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", + "sync_wrapper", "system-configuration", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", "tower-service", "url", "wasm-bindgen", @@ -3078,17 +3038,17 @@ dependencies = [ [[package]] name = "ring" -version = "0.16.20" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", + "cfg-if", + "getrandom", "libc", - "once_cell", "spin", "untrusted", - "web-sys", - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -3102,9 +3062,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" @@ -3123,29 +3083,43 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.17" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f25469e9ae0f3d0047ca8b93fc56843f38e6774f0914a107ff8b41be8be8e0b7" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.5.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "rustls" -version = "0.21.7" +version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", "ring", - "rustls-webpki", + "rustls-webpki 0.101.7", "sct", ] +[[package]] +name = "rustls" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" +dependencies = [ + "log", + "ring", + "rustls-pki-types", + "rustls-webpki 0.102.4", + "subtle", + "zeroize", +] + [[package]] name = "rustls-native-certs" version = "0.6.3" @@ -3153,41 +3127,81 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" dependencies = [ "openssl-probe", - "rustls-pemfile", + "rustls-pemfile 1.0.4", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-native-certs" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792" +dependencies = [ + "openssl-probe", + "rustls-pemfile 2.1.2", + "rustls-pki-types", "schannel", "security-framework", ] [[package]] name = "rustls-pemfile" -version = "1.0.3" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustls-pemfile" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +dependencies = [ + "base64 0.22.1", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" + +[[package]] +name = "rustls-webpki" +version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "base64 0.21.4", + "ring", + "untrusted", ] [[package]] name = "rustls-webpki" -version = "0.101.6" +version = "0.102.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c7d5dece342910d9ba34d259310cae3e0154b873b35408b787b59bce53d34fe" +checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" dependencies = [ "ring", + "rustls-pki-types", "untrusted", ] [[package]] name = "rustversion" -version = "1.0.14" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" @@ -3200,11 +3214,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -3221,9 +3235,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sct" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ "ring", "untrusted", @@ -3245,11 +3259,11 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.28.1" +version = "0.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f622567e3b4b38154fb8190bcf6b160d7a4301d70595a49195b48c116007a27" +checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10" dependencies = [ - "bitcoin_hashes 0.12.0", + "bitcoin_hashes", "rand", "secp256k1-sys", "serde", @@ -3276,11 +3290,11 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.9.2" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", "core-foundation", "core-foundation-sys", "libc", @@ -3289,9 +3303,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.9.1" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" dependencies = [ "core-foundation-sys", "libc", @@ -3299,27 +3313,27 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.19" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad977052201c6de01a8ef2aa3378c4bd23217a056337d1d6da40468d267a4fb0" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.195" +version = "1.0.202" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" +checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.12" +version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff" +checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" dependencies = [ "serde", ] @@ -3336,20 +3350,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.195" +version = "1.0.202" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" +checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.65", ] [[package]] name = "serde_json" -version = "1.0.107" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" dependencies = [ "itoa", "ryu", @@ -3358,9 +3372,9 @@ dependencies = [ [[package]] name = "serde_path_to_error" -version = "0.1.14" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4beec8bce849d58d06238cb50db2e1c417cfeafa4c63f692b15c82b7c80f8335" +checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" dependencies = [ "itoa", "serde", @@ -3368,20 +3382,20 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.16" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00" +checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.65", ] [[package]] name = "serde_spanned" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" dependencies = [ "serde", ] @@ -3404,7 +3418,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest 0.10.7", ] @@ -3416,7 +3430,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer 0.9.0", - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest 0.9.0", "opaque-debug", @@ -3428,7 +3442,7 @@ version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest 0.10.7", ] @@ -3460,9 +3474,9 @@ checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" [[package]] name = "shlex" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook" @@ -3476,50 +3490,29 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ "libc", ] [[package]] name = "signature" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest 0.10.7", "rand_core", ] -[[package]] -name = "simple-error" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc47a29ce97772ca5c927f75bac34866b16d64e07f330c3248e2d7226623901b" - [[package]] name = "siphasher" version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" -[[package]] -name = "skeptic" -version = "0.13.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8" -dependencies = [ - "bytecount", - "cargo_metadata", - "error-chain", - "glob", - "pulldown-cmark", - "tempfile", - "walkdir", -] - [[package]] name = "slab" version = "0.4.9" @@ -3531,41 +3524,31 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" - -[[package]] -name = "socket2" -version = "0.4.9" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" -dependencies = [ - "libc", - "winapi", -] +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" -version = "0.5.4" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "spin" -version = "0.5.2" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "spki" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", "der", @@ -3586,7 +3569,7 @@ dependencies = [ "new_debug_unreachable", "once_cell", "parking_lot", - "phf_shared", + "phf_shared 0.10.0", "precomputed-hash", "serde", ] @@ -3597,8 +3580,8 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" dependencies = [ - "phf_generator", - "phf_shared", + "phf_generator 0.10.0", + "phf_shared 0.10.0", "proc-macro2", "quote", ] @@ -3609,6 +3592,12 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "strum" version = "0.25.0" @@ -3620,15 +3609,15 @@ dependencies = [ [[package]] name = "strum_macros" -version = "0.25.2" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad8d03b598d3d0fff69bf533ee3ef19b8eeb342729596df84bcc7e1f96ec4059" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" dependencies = [ "heck", "proc-macro2", "quote", "rustversion", - "syn 2.0.48", + "syn 2.0.65", ] [[package]] @@ -3665,9 +3654,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.48" +version = "2.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "d2863d96a84c6439701d7a38f9de935ec562c8832cc55d1dde0f513b52fad106" dependencies = [ "proc-macro2", "quote", @@ -3721,22 +3710,21 @@ checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" [[package]] name = "tempfile" -version = "3.8.0" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "fastrand", - "redox_syscall 0.3.5", "rustix", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "tendermint" -version = "0.34.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc2294fa667c8b548ee27a9ba59115472d0a09c2ba255771092a7f1dcf03a789" +checksum = "8b50aae6ec24c3429149ad59b5b8d3374d7804d4c7d6125ceb97cb53907fb68d" dependencies = [ "bytes", "digest 0.10.7", @@ -3765,26 +3753,26 @@ dependencies = [ [[package]] name = "tendermint-config" -version = "0.34.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a25dbe8b953e80f3d61789fbdb83bf9ad6c0ef16df5ca6546f49912542cc137" +checksum = "e07b383dc8780ebbec04cfb603f3fdaba6ea6663d8dd861425b1ffa7761fe90d" dependencies = [ "flex-error", "serde", "serde_json", "tendermint", - "toml 0.5.11", + "toml 0.8.13", "url", ] [[package]] name = "tendermint-light-client" -version = "0.34.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94aecbdccbc4b557649b2d1b1a4bfc27ec85205e00fb8020fce044245a4c9e3f" +checksum = "331544139bbcf353acb5f56e733093d8e4bf2522cda0491b4bba7039ef0b944e" dependencies = [ "contracts", - "crossbeam-channel 0.4.4", + "crossbeam-channel", "derive_more", "flex-error", "futures", @@ -3804,12 +3792,11 @@ dependencies = [ [[package]] name = "tendermint-light-client-detector" -version = "0.34.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea83654b03e3ddc6782c9704a3fefd4d0671bd6c5e3f09d29e31fcb45e75636c" +checksum = "73d0ffaf614bd2db605c4762e3a31a536b73cd45488fa5bace050135ca348f28" dependencies = [ - "contracts", - "crossbeam-channel 0.4.4", + "crossbeam-channel", "derive_more", "flex-error", "futures", @@ -3828,9 +3815,9 @@ dependencies = [ [[package]] name = "tendermint-light-client-verifier" -version = "0.34.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74994da9de4b1144837a367ca2c60c650f5526a7c1a54760a3020959b522e474" +checksum = "4216e487165e5dbd7af79952eaa0d5f06c5bde861eb76c690acd7f2d2a19395c" dependencies = [ "derive_more", "flex-error", @@ -3841,14 +3828,12 @@ dependencies = [ [[package]] name = "tendermint-proto" -version = "0.34.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc728a4f9e891d71adf66af6ecaece146f9c7a11312288a3107b3e1d6979aaf" +checksum = "46f193d04afde6592c20fd70788a10b8cb3823091c07456db70d8a93f5fb99c1" dependencies = [ "bytes", "flex-error", - "num-derive", - "num-traits", "prost", "prost-types", "serde", @@ -3859,9 +3844,9 @@ dependencies = [ [[package]] name = "tendermint-rpc" -version = "0.34.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbf0a4753b46a190f367337e0163d0b552a2674a6bac54e74f9f2cdcde2969b" +checksum = "21e3c231a3632cab53f92ad4161c730c468c08cfe4f0aa5a6735b53b390aecbd" dependencies = [ "async-trait", "async-tungstenite", @@ -3871,6 +3856,7 @@ dependencies = [ "getrandom", "peg", "pin-project", + "rand", "reqwest", "semver", "serde", @@ -3886,26 +3872,10 @@ dependencies = [ "tokio", "tracing", "url", - "uuid 0.8.2", + "uuid", "walkdir", ] -[[package]] -name = "tendermint-testgen" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19d4f02b7e38ce790da973fdc9edc71a0e35340ac57737bf278c8379037c1f5" -dependencies = [ - "ed25519-consensus", - "gumdrop", - "serde", - "serde_json", - "simple-error", - "tempfile", - "tendermint", - "time", -] - [[package]] name = "tendril" version = "0.4.3" @@ -3919,9 +3889,9 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.3.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] @@ -3938,47 +3908,49 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" [[package]] name = "thiserror" -version = "1.0.49" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.49" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.65", ] [[package]] name = "thread_local" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "once_cell", ] [[package]] name = "time" -version = "0.3.29" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "426f806f4089c493dcac0d24c29c01e2c38baf8e30f1b716ee37e83d200b18fe" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", + "num-conv", + "powerfmt", "serde", "time-core", "time-macros", @@ -3992,10 +3964,11 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.15" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ + "num-conv", "time-core", ] @@ -4044,9 +4017,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.32.0" +version = "1.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" dependencies = [ "backtrace", "bytes", @@ -4056,7 +4029,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.4", + "socket2", "tokio-macros", "windows-sys 0.48.0", ] @@ -4073,13 +4046,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.65", ] [[package]] @@ -4088,15 +4061,26 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls", + "rustls 0.21.12", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +dependencies = [ + "rustls 0.22.4", + "rustls-pki-types", "tokio", ] [[package]] name = "tokio-stream" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" dependencies = [ "futures-core", "pin-project-lite", @@ -4105,9 +4089,9 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.20.1" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" +checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" dependencies = [ "futures-util", "log", @@ -4117,16 +4101,15 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.9" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" dependencies = [ "bytes", "futures-core", "futures-sink", "pin-project-lite", "tokio", - "tracing", ] [[package]] @@ -4140,9 +4123,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.8" +version = "0.8.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" +checksum = "a4e43f8cc456c9704c851ae29c67e17ef65d2c30017c17a9765b89c382dc8bba" dependencies = [ "serde", "serde_spanned", @@ -4152,20 +4135,20 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.21.0" +version = "0.22.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +checksum = "c127785850e8c20836d49732ae6abfa47616e60bf9d9f57c43c250361a9db96c" dependencies = [ - "indexmap 2.0.2", + "indexmap 2.2.6", "serde", "serde_spanned", "toml_datetime", @@ -4174,28 +4157,28 @@ dependencies = [ [[package]] name = "tonic" -version = "0.10.2" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d560933a0de61cf715926b9cac824d4c883c2c43142f787595e48280c40a1d0e" +checksum = "76c4eb7a4e9ef9d4763600161f12f5070b92a578e1b634db88a6887844c91a13" dependencies = [ "async-stream", "async-trait", "axum", - "base64 0.21.4", + "base64 0.21.7", "bytes", "h2", - "http", + "http 0.2.12", "http-body", "hyper", "hyper-timeout", "percent-encoding", "pin-project", "prost", - "rustls", - "rustls-native-certs", - "rustls-pemfile", + "rustls-native-certs 0.7.0", + "rustls-pemfile 2.1.2", + "rustls-pki-types", "tokio", - "tokio-rustls", + "tokio-rustls 0.25.0", "tokio-stream", "tower", "tower-layer", @@ -4243,11 +4226,10 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if 1.0.0", "log", "pin-project-lite", "tracing-attributes", @@ -4256,20 +4238,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.65", ] [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", "valuable", @@ -4287,12 +4269,23 @@ dependencies = [ [[package]] name = "tracing-log" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ - "lazy_static", "log", + "once_cell", "tracing-core", ] @@ -4308,9 +4301,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "matchers", "nu-ansi-term", @@ -4323,36 +4316,37 @@ dependencies = [ "thread_local", "tracing", "tracing-core", - "tracing-log", + "tracing-log 0.2.0", "tracing-serde", ] [[package]] name = "triomphe" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee8098afad3fb0c54a9007aab6804558410503ad676d4633f9c2559a00ac0f" +checksum = "859eb650cfee7434994602c3a68b25d77ad9e68c8a6cd491616ef86661382eb3" [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tungstenite" -version = "0.20.1" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" dependencies = [ "byteorder", "bytes", "data-encoding", - "http", + "http 1.1.0", "httparse", "log", "rand", - "rustls", + "rustls 0.22.4", + "rustls-pki-types", "sha1", "thiserror", "url", @@ -4394,9 +4388,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" @@ -4406,18 +4400,18 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] [[package]] name = "unicode-width" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" [[package]] name = "unicode-xid" @@ -4427,15 +4421,15 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "untrusted" -version = "0.7.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", @@ -4456,9 +4450,9 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] name = "utf8-width" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5190c9442dcdaf0ddd50f37420417d219ae5261bbf5db120d0f9bab996c9cba1" +checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" [[package]] name = "utf8parse" @@ -4468,15 +4462,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" - -[[package]] -name = "uuid" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" dependencies = [ "getrandom", ] @@ -4504,9 +4492,9 @@ dependencies = [ [[package]] name = "walkdir" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", @@ -4523,28 +4511,26 @@ dependencies = [ [[package]] name = "warp" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1e92e22e03ff1230c03a1a8ee37d2f89cd489e2e541b7550d6afad96faed169" +checksum = "4378d202ff965b011c64817db11d5829506d3404edeadb61f190d111da3f231c" dependencies = [ "bytes", "futures-channel", "futures-util", "headers", - "http", + "http 0.2.12", "hyper", "log", "mime", "mime_guess", "percent-encoding", "pin-project", - "rustls-pemfile", "scoped-tls", "serde", "serde_json", "serde_urlencoded", "tokio", - "tokio-stream", "tokio-tungstenite", "tokio-util", "tower-service", @@ -4559,36 +4545,36 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.65", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "wasm-bindgen", "web-sys", @@ -4596,9 +4582,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4606,28 +4592,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.65", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", @@ -4651,11 +4637,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -4665,21 +4651,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" +name = "windows-core" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.42.2", + "windows-targets 0.52.5", ] [[package]] @@ -4692,18 +4669,12 @@ dependencies = [ ] [[package]] -name = "windows-targets" -version = "0.42.2" +name = "windows-sys" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", + "windows-targets 0.52.5", ] [[package]] @@ -4722,10 +4693,20 @@ dependencies = [ ] [[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" +name = "windows-targets" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", +] [[package]] name = "windows_aarch64_gnullvm" @@ -4734,10 +4715,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" +name = "windows_aarch64_gnullvm" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" @@ -4746,10 +4727,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] -name = "windows_i686_gnu" -version = "0.42.2" +name = "windows_aarch64_msvc" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" @@ -4758,10 +4739,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] -name = "windows_i686_msvc" -version = "0.42.2" +name = "windows_i686_gnu" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" @@ -4770,10 +4757,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" +name = "windows_i686_msvc" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" @@ -4782,10 +4769,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" +name = "windows_x86_64_gnu" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" @@ -4794,10 +4781,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" +name = "windows_x86_64_gnullvm" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" @@ -4805,11 +4792,17 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + [[package]] name = "winnow" -version = "0.5.15" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" +checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d" dependencies = [ "memchr", ] @@ -4820,15 +4813,15 @@ version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "windows-sys 0.48.0", ] [[package]] name = "zeroize" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" dependencies = [ "zeroize_derive", ] @@ -4841,5 +4834,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.65", ] diff --git a/tools/check-guide/Cargo.toml b/tools/check-guide/Cargo.toml index a69316ec10..e5a77be25f 100644 --- a/tools/check-guide/Cargo.toml +++ b/tools/check-guide/Cargo.toml @@ -1,11 +1,9 @@ [package] -name = "check-guide" +name = "check-guide" version = "0.1.0" edition = "2021" publish = false -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] ibc-relayer-cli = { path = "../../crates/relayer-cli" } clap = "3.2" @@ -13,4 +11,3 @@ lazy_static = "1.4.0" mdbook-template = "1.1.0" regex = "1" walkdir = "2.3.3" - diff --git a/tools/integration-test/Cargo.toml b/tools/integration-test/Cargo.toml index 9580ba24bf..f956b20c04 100644 --- a/tools/integration-test/Cargo.toml +++ b/tools/integration-test/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "ibc-integration-test" -version = "0.27.0" +version = "0.29.5" edition = "2021" -rust-version = "1.71" +rust-version = "1.76.0" license = "Apache-2.0" readme = "README.md" keywords = ["blockchain", "consensus", "cosmos", "ibc", "tendermint"] @@ -13,52 +13,44 @@ description = "Integration tests for Hermes" publish = false [dependencies] -ibc-relayer-types = { path = "../../crates/relayer-types" } -ibc-relayer = { path = "../../crates/relayer" } -ibc-test-framework = { path = "../test-framework" } - -http = "0.2.9" -serde_json = "1" -time = "0.3" -toml = "0.8" -prost = { version = "0.12" } -tonic = { version = "0.10", features = ["tls", "tls-roots"] } -serde = "1.0.195" +ibc-relayer-types = { workspace = true } +ibc-relayer = { workspace = true } +ibc-test-framework = { workspace = true } + +byte-unit = { workspace = true, features = ["serde"] } +http = { workspace = true } +prost = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +tendermint-rpc = { workspace = true, features = ["http-client"] } +tendermint = { workspace = true } +time = { workspace = true } +toml = { workspace = true } +tonic = { workspace = true, features = ["tls", "tls-roots"] } [features] -default = [] -example = [] -manual = [] -ordered = [] -ica = [] -ics29-fee = [] -experimental = [] -mbt = [] -forward-packet = [] -ics31 = [] -clean-workers = [] -fee-grant = [] -interchain-security = [] -celestia = [] -async-icq = [] -juno = [] -dynamic-gas-fee = [] +default = [] +example = [] +manual = [] +ordered = [] +ica = [] +ics29-fee = [] +experimental = [] +forward-packet = [] +ics31 = [] +clean-workers = [] +fee-grant = [] +channel-upgrade = [] +interchain-security = [] +celestia = [] +async-icq = [] +juno = [] +dynamic-gas-fee = [] +new-register-interchain-account = [] +authz = [] +benchmark = [] +no-denom-trace = [] [[bin]] name = "test_setup_with_binary_channel" -doc = true - -[dev-dependencies] -tempfile = "3.6.0" - -[dependencies.tendermint] -version = "0.34.0" - -[dependencies.tendermint-rpc] -version = "0.34.0" -features = ["http-client"] - -[dependencies.byte-unit] -version = "4.0.19" -default-features = false -features = ["serde"] \ No newline at end of file +doc = true diff --git a/tools/integration-test/src/bin/test_setup_with_binary_channel.rs b/tools/integration-test/src/bin/test_setup_with_binary_channel.rs index 336b0c1b23..44d6cb40e4 100644 --- a/tools/integration-test/src/bin/test_setup_with_binary_channel.rs +++ b/tools/integration-test/src/bin/test_setup_with_binary_channel.rs @@ -37,7 +37,7 @@ struct Test { impl TestOverrides for Test { fn modify_test_config(&self, config: &mut TestConfig) { - config.chain_store_dir = self.store_dir.clone(); + config.chain_store_dir.clone_from(&self.store_dir); } fn modify_relayer_config(&self, config: &mut Config) { diff --git a/tools/integration-test/src/bin/test_setup_with_fee_enabled_binary_channel.rs b/tools/integration-test/src/bin/test_setup_with_fee_enabled_binary_channel.rs index d7e7c5456f..ac938158d2 100644 --- a/tools/integration-test/src/bin/test_setup_with_fee_enabled_binary_channel.rs +++ b/tools/integration-test/src/bin/test_setup_with_fee_enabled_binary_channel.rs @@ -38,7 +38,7 @@ struct Test { impl TestOverrides for Test { fn modify_test_config(&self, config: &mut TestConfig) { - config.chain_store_dir = self.store_dir.clone(); + config.chain_store_dir.clone_from(&self.store_dir); } fn modify_relayer_config(&self, config: &mut Config) { diff --git a/tools/integration-test/src/bin/test_setup_with_ternary_channel.rs b/tools/integration-test/src/bin/test_setup_with_ternary_channel.rs index 050c81cdcd..1cfcd0f921 100644 --- a/tools/integration-test/src/bin/test_setup_with_ternary_channel.rs +++ b/tools/integration-test/src/bin/test_setup_with_ternary_channel.rs @@ -37,7 +37,7 @@ struct Test { impl TestOverrides for Test { fn modify_test_config(&self, config: &mut TestConfig) { - config.chain_store_dir = self.store_dir.clone(); + config.chain_store_dir.clone_from(&self.store_dir); } fn modify_relayer_config(&self, config: &mut Config) { diff --git a/tools/integration-test/src/lib.rs b/tools/integration-test/src/lib.rs index f4b83a25c4..75d580024e 100644 --- a/tools/integration-test/src/lib.rs +++ b/tools/integration-test/src/lib.rs @@ -1,7 +1,3 @@ #[allow(clippy::too_many_arguments)] #[cfg(test)] pub mod tests; - -#[cfg(any(all(test, feature = "mbt"), doc))] -#[macro_use] -pub mod mbt; diff --git a/tools/integration-test/src/mbt/README.md b/tools/integration-test/src/mbt/README.md deleted file mode 100644 index f2c0311b28..0000000000 --- a/tools/integration-test/src/mbt/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# MBT for Hermes Integration Test - -Make sure [`apalache-mc`](https://github.com/informalsystems/apalache) is installed and setup properly. Check `apalache-mc version`. - -```bash -cargo test -p ibc-integration-test --features mbt mbt::transfer -``` diff --git a/tools/integration-test/src/mbt/handlers.rs b/tools/integration-test/src/mbt/handlers.rs deleted file mode 100644 index b9c362744e..0000000000 --- a/tools/integration-test/src/mbt/handlers.rs +++ /dev/null @@ -1,293 +0,0 @@ -use ibc_relayer::util::task::TaskHandle; -use ibc_relayer::worker::client::spawn_refresh_client; - -use ibc_test_framework::bootstrap::binary::chain::bootstrap_foreign_client_pair; -use ibc_test_framework::bootstrap::binary::connection::bootstrap_connection; -use ibc_test_framework::chain::ext::transfer::ChainTransferMethodsExt; -use ibc_test_framework::chain::tagged::TaggedChainDriverExt; -use ibc_test_framework::ibc::denom::derive_ibc_denom; -use ibc_test_framework::prelude::*; -use ibc_test_framework::relayer::channel::{assert_eventually_channel_established, init_channel}; -use ibc_test_framework::relayer::connection::{ - assert_eventually_connection_established, init_connection, -}; -use ibc_test_framework::types::binary::client::ClientIdPair; -use ibc_test_framework::types::binary::connection::ConnectedConnection; -use ibc_test_framework::types::tagged::mono::Tagged; - -use super::state::Packet; - -use super::utils::{get_denom, get_wallet, wait_for_client}; - -pub fn setup_chains( - chains: &ConnectedChains, -) -> Result<(), Error> { - { - let _refresh_task_a = spawn_refresh_client(chains.foreign_clients.client_b_to_a.clone()) - .ok_or_else(|| eyre!("expect refresh task spawned"))?; - - let _refresh_task_b = spawn_refresh_client(chains.foreign_clients.client_a_to_b.clone()) - .ok_or_else(|| eyre!("expect refresh task spawned"))?; - - bootstrap_connection(&chains.foreign_clients, Default::default())?; - }; - - wait_for_client(); - - Ok(()) -} - -pub fn local_transfer_handler( - node: Tagged, - source: u128, - target: u128, - denom: u128, - amount: u128, -) -> Result<(), Error> { - let wallets = node.wallets(); - - let source_wallet = get_wallet(&wallets, source); - let target_wallet = get_wallet(&wallets, target); - let denom = get_denom(&node, denom); - - node.chain_driver().local_transfer_token( - &source_wallet, - &target_wallet.address(), - &denom.with_amount(amount).as_ref(), - )?; - - Ok(()) -} - -pub fn create_channel( - chain_handle_a: &ChainA, - chain_handle_b: &ChainB, - channel: &mut Option>, - refresh_task_a: &mut Option, - refresh_task_b: &mut Option, -) -> Result<(), Error> { - let port_a = tagged_transfer_port(); - let port_b = tagged_transfer_port(); - - let clients2 = - bootstrap_foreign_client_pair(chain_handle_a, chain_handle_b, Default::default())?; - - *refresh_task_a = Some( - spawn_refresh_client(clients2.client_b_to_a.clone()) - .ok_or_else(|| eyre!("expect refresh task spawned"))?, - ); - - *refresh_task_b = Some( - spawn_refresh_client(clients2.client_a_to_b.clone()) - .ok_or_else(|| eyre!("expect refresh task spawned"))?, - ); - - let (connection_id_b, new_connection_b) = init_connection( - chain_handle_a, - chain_handle_b, - &clients2.client_b_to_a.tagged_client_id(), - &clients2.client_a_to_b.tagged_client_id(), - )?; - - let connection_id_a = assert_eventually_connection_established( - chain_handle_b, - chain_handle_a, - &connection_id_b.as_ref(), - )?; - - let (channel_id_b_2, channel_b_2) = init_channel( - chain_handle_a, - chain_handle_b, - &clients2.client_b_to_a.tagged_client_id(), - &clients2.client_a_to_b.tagged_client_id(), - &connection_id_a.as_ref(), - &connection_id_b.as_ref(), - &port_a.as_ref(), - &port_b.as_ref(), - )?; - - let channel_id_a_2 = assert_eventually_channel_established( - chain_handle_b, - chain_handle_a, - &channel_id_b_2.as_ref(), - &port_b.as_ref(), - )?; - - let client_ids = ClientIdPair::new( - clients2.client_b_to_a.tagged_client_id().cloned(), - clients2.client_a_to_b.tagged_client_id().cloned(), - ); - - let new_connected_connection = ConnectedConnection::new( - client_ids, - new_connection_b.flipped(), - connection_id_a, - connection_id_b, - ); - - let connected_channel = ConnectedChannel { - connection: new_connected_connection, - channel: channel_b_2.flipped(), - channel_id_a: channel_id_a_2, - channel_id_b: channel_id_b_2, - port_a, - port_b, - }; - - *channel = Some(connected_channel); - - info!("Channel is created"); - - Ok(()) -} - -pub fn expire_channel( - channel: &mut Option>, - refresh_task_a: &mut Option, - refresh_task_b: &mut Option, -) -> Result<(), Error> { - // dropping the client handler to expire the clients - super::utils::drop(refresh_task_a.take()); - super::utils::drop(refresh_task_b.take()); - - wait_for_client(); - - super::utils::drop(channel.take()); - - info!("Channel expired"); - - Ok(()) -} - -pub fn ibc_transfer_send_packet( - node_source: Tagged, - node_target: Tagged, - channels: &ConnectedChannel, - packet: &Packet, -) -> Result<(), Error> { - let wallets_source = node_source.wallets(); - let wallets_target = node_target.wallets(); - - let wallet_source = get_wallet(&wallets_source, packet.from); - let wallet_target = get_wallet(&wallets_target, packet.to); - let denom_source = get_denom(&node_source, packet.denom); - let amount_source_to_target = packet.amount; - - let (port_source, channel_id_source) = ( - DualTagged::new(channels.port_a.value()), - DualTagged::new(channels.channel_id_a.value()), - ); - - let balance_source = node_source - .chain_driver() - .query_balance(&wallet_source.address(), &denom_source)?; - - info!( - "Sending IBC transfer from chain {} to chain {} with amount of {} {}", - node_source.chain_id(), - node_target.chain_id(), - amount_source_to_target, - denom_source, - ); - - node_source.chain_driver().ibc_transfer_token( - &port_source, - &channel_id_source, - &wallet_source, - &wallet_target.address(), - &denom_source.with_amount(amount_source_to_target).as_ref(), - )?; - - node_source.chain_driver().assert_eventual_wallet_amount( - &wallet_source.address(), - &(balance_source - amount_source_to_target).as_ref(), - )?; - - Ok(()) -} - -pub fn ibc_transfer_receive_packet( - node_source: Tagged, - node_target: Tagged, - channels: &ConnectedChannel, - packet: &Packet, -) -> Result<(), Error> { - let wallets_target = node_target.wallets(); - - let wallet_target = get_wallet(&wallets_target, packet.to); - let denom_source = get_denom(&node_source, packet.denom); - let amount_source_to_target = packet.amount; - - let (port_target, channel_id_target) = ( - DualTagged::new(channels.port_b.value()), - DualTagged::new(channels.channel_id_b.value()), - ); - - let denom_target = derive_ibc_denom(&port_target, &channel_id_target, &denom_source)?; - - info!( - "Waiting for user on chain {} to receive IBC transferred amount of {} {} (chain {}/{})", - node_target.chain_id(), - amount_source_to_target, - denom_target, - node_source.chain_id(), - denom_source - ); - - node_target.chain_driver().assert_eventual_wallet_amount( - &wallet_target.address(), - &denom_target.with_amount(amount_source_to_target).as_ref(), - )?; - - Ok(()) -} - -pub fn ibc_transfer_acknowledge_packet( - node_source: Tagged, - node_target: Tagged, - _channels: &Option>, - packet: &Packet, -) -> Result<(), Error> { - let denom_source = get_denom(&node_source, packet.denom); - let amount_source_to_target = packet.amount; - - info!( - "Waiting for user on chain {} to confirm IBC transferred amount of {} {}", - node_source.chain_id(), - amount_source_to_target, - denom_source - ); - - info!( - "Successfully performed IBC transfer from chain {} to chain {}", - node_source.chain_id(), - node_target.chain_id(), - ); - - Ok(()) -} - -pub fn ibc_transfer_expire_packet( - node_source: Tagged, - node_target: Tagged, - _channels: &Option>, - packet: &Packet, -) -> Result<(), Error> { - let denom_source = get_denom(&node_source, packet.denom); - let amount_source_to_target = packet.amount; - - info!( - "Waiting for user on chain {} to get refund of previously IBC transferred amount of {} {}", - node_source.chain_id(), - amount_source_to_target, - denom_source - ); - - info!( - "Successfully performed IBC packet expiry intended from chain {} to chain {}", - node_source.chain_id(), - node_target.chain_id(), - ); - - Ok(()) -} diff --git a/tools/integration-test/src/mbt/itf.rs b/tools/integration-test/src/mbt/itf.rs deleted file mode 100644 index 44bb354ed9..0000000000 --- a/tools/integration-test/src/mbt/itf.rs +++ /dev/null @@ -1,132 +0,0 @@ -use serde::{Deserialize, Deserializer, Serialize}; - -#[derive(Debug, Serialize, Deserialize)] -pub struct Meta { - pub format: String, - #[serde(rename = "format-description")] - pub format_description: String, - pub description: String, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct InformalTrace { - #[serde(rename = "#meta")] - pub meta: Meta, - pub vars: Vec, - pub states: Vec, -} - -#[derive(Debug, Serialize)] -pub struct Map(pub Vec<(K, V)>); - -impl<'de, K, V> Deserialize<'de> for Map -where - K: Deserialize<'de>, - V: Deserialize<'de>, -{ - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - #[derive(Debug, Deserialize)] - struct Meta { - #[serde(rename = "#map")] - map: Vec<(K, V)>, - } - let s: Meta<_, _> = Deserialize::deserialize(deserializer)?; - Ok(Self(s.map)) - } -} - -#[derive(Debug, Serialize)] -pub struct Set(pub Vec); - -impl<'de, E> Deserialize<'de> for Set -where - E: Deserialize<'de>, -{ - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - #[derive(Debug, Deserialize)] - pub struct Meta { - #[serde(rename = "#set")] - set: Vec, - } - let s: Meta<_> = Deserialize::deserialize(deserializer)?; - Ok(Self(s.set)) - } -} - -mod test { - use super::{Map, Set}; - - #[test] - fn test_empty_set() { - let itf = r##"{ "#set": [] }"##; - let s: Set = serde_json::from_str(itf).unwrap(); - assert!(s.0.is_empty()); - } - - #[test] - fn test_set() { - let itf = r##"{ "#set": [1,2,3] }"##; - let s: Set = serde_json::from_str(itf).unwrap(); - assert_eq!(s.0, vec![1, 2, 3]); - } - - #[test] - fn test_empty_map() { - let itf = r##"{ "#map": [ ] }"##; - let m: Map = serde_json::from_str(itf).unwrap(); - assert!(m.0.is_empty()); - } - - #[test] - #[should_panic] - fn test_singleton_map() { - let itf = r##"{ "#map": [1, 11] }"##; - let m: Map = serde_json::from_str(itf).unwrap(); - assert_eq!(m.0, vec![(1, 11)]); - } - - #[test] - fn test_normal_map() { - let itf = r##"{ "#map": [[1, 11], [2, 22]] }"##; - let m: Map = serde_json::from_str(itf).unwrap(); - assert_eq!(m.0, vec![(1, 11), (2, 22)]); - } - - #[test] - #[cfg(feature = "manual")] - fn parse_itf() { - use super::super::itf::InformalTrace; - use super::super::state::State; - - let itf_path = concat!( - env!("CARGO_MANIFEST_DIR"), - "/spec/example/counterexample.itf.json" - ); - - let itf_json = std::fs::read_to_string(itf_path).expect("itf file does not exist"); - - let t: InformalTrace = - serde_json::from_str(&itf_json).expect("deserialization error"); - - for state in t.states { - println!( - "action: {}", - serde_json::to_string_pretty(&state.action).unwrap() - ); - println!( - "outcome: {}", - serde_json::to_string_pretty(&state.outcome).unwrap() - ); - println!( - "chains: {}", - serde_json::to_string_pretty(&state.chains).unwrap() - ); - } - } -} diff --git a/tools/integration-test/src/mbt/mod.rs b/tools/integration-test/src/mbt/mod.rs deleted file mode 100644 index 173f132abb..0000000000 --- a/tools/integration-test/src/mbt/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub mod utils; - -pub mod itf; -pub mod state; - -pub mod handlers; - -pub mod transfer; diff --git a/tools/integration-test/src/mbt/state.rs b/tools/integration-test/src/mbt/state.rs deleted file mode 100644 index b9ddf34e9e..0000000000 --- a/tools/integration-test/src/mbt/state.rs +++ /dev/null @@ -1,85 +0,0 @@ -use serde::{Deserialize, Serialize}; - -use super::itf::{Map, Set}; - -pub type ChainId = u128; -pub type DenomId = ChainId; -pub type AccountId = u128; -pub type PacketId = u128; -pub type Balance = u128; - -#[derive(Debug, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct Packet { - pub id: PacketId, - pub from: AccountId, - pub source_chain_id: ChainId, - pub to: AccountId, - pub target_chain_id: ChainId, - pub denom: DenomId, - pub amount: Balance, -} - -#[derive(Debug, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct LocalPackets { - pub list: Map, - pub pending: Set, - pub expired: Set, - pub success: Set, -} - -#[derive(Debug, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct Chain { - pub id: ChainId, - pub bank: Map>, - pub supply: Map, - pub local_packets: LocalPackets, - pub remote_packets: Map>, - pub escrow: Map>, - pub next_packet_id: PacketId, -} - -#[derive(Debug, Serialize, Deserialize)] -#[serde(tag = "name")] -pub enum Action { - Null, - #[serde(rename_all = "camelCase")] - LocalTransfer { - chain_id: ChainId, - source: AccountId, - target: AccountId, - denom: DenomId, - amount: Balance, - }, - RestoreRelay, - InterruptRelay, - IBCTransferSendPacket { - packet: Packet, - }, - IBCTransferReceivePacket { - packet: Packet, - }, - IBCTransferAcknowledgePacket { - packet: Packet, - }, - IBCTransferTimeoutPacket { - packet: Packet, - }, -} - -#[derive(Debug, Serialize, Deserialize)] -#[serde(tag = "name")] -pub enum Outcome { - Success, - Error, -} - -#[derive(Debug, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct State { - pub chains: Map, - pub action: Action, - pub outcome: Outcome, -} diff --git a/tools/integration-test/src/mbt/transfer.rs b/tools/integration-test/src/mbt/transfer.rs deleted file mode 100644 index 846edc822f..0000000000 --- a/tools/integration-test/src/mbt/transfer.rs +++ /dev/null @@ -1,366 +0,0 @@ -use std::io::Write; -use std::panic::{RefUnwindSafe, UnwindSafe}; - -use ibc_relayer::config::{ - ChainConfig, Channels as ConfigChannels, Clients as ConfigClients, - Connections as ConfigConnections, ModeConfig, Packets as ConfigPackets, -}; - -use ibc_test_framework::prelude::*; -use ibc_test_framework::types::tagged::mono::Tagged; - -use super::state::{Action, State}; - -use super::itf::InformalTrace; -use super::utils::{get_chain, CLIENT_EXPIRY}; - -const TEST_NAMES: &[&str] = &[ - "LocalTransferInv", - "IBCTransferAcknowledgePacketInv", - "IBCTransferTimeoutPacketInv", -]; -const NUM_TRACES: Option<&str> = option_env!("MBT_TRACES"); -const APALACHE: Option<&str> = option_env!("APALACHE"); - -const ITF_TRACE_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/data/mbt"); - -fn generate_mbt_traces( - apalache_path: &str, - test_name: &str, - num_traces: usize, -) -> Result, Error> { - let temp_dir = tempfile::TempDir::new()?; - let run_dir = temp_dir.path().join("run"); - let tla_path = concat!(env!("CARGO_MANIFEST_DIR"), "/spec/MC_Transfer.tla"); - let mut cmd = std::process::Command::new(apalache_path); - cmd.arg("check") - .arg("--init=Init") - .arg("--next=Next") - .arg(&format!("--inv={test_name}")) - .arg(&format!("--max-error={num_traces}")) - .arg(&format!( - "--run-dir={}", - run_dir.to_str().expect("no panic") - )) - .arg(&format!( - "--out-dir={}", - temp_dir.path().to_str().expect("no panic") - )) - .arg(tla_path); - let _ = cmd.status().expect("failed to execute process"); - - std::fs::read_dir(run_dir)? - .flatten() - .map(|entry| entry.path()) - .filter(|file_path| file_path.is_file()) - .flat_map(|file_path| { - file_path - .file_name() - .and_then(|file_name| file_name.to_str()) - .and_then(|file_name| { - (file_name != "counterexample.itf.json" - && file_name.starts_with("counterexample") - && file_name.ends_with(".itf.json")) - .then(|| { - let name = format!("{test_name}_{file_name}"); - Ok(( - name, - std::fs::read_to_string(file_path.to_str().expect("should not panic")) - .expect("error while reading counterexample.itf.json"), - )) - }) - }) - }) - .collect() -} - -fn execute_mbt(f: F) -> Result<(), Error> -where - F: FnOnce(Vec) -> Result<(), Error> + UnwindSafe + RefUnwindSafe + Copy, -{ - let apalache = APALACHE.unwrap_or("apalache-mc"); - let num_traces = NUM_TRACES - .unwrap_or("2") - .parse() - .expect("an number for number of traces per test"); - - let success_traces = &format!("{ITF_TRACE_DIRECTORY}/success"); - let failure_traces = &format!("{ITF_TRACE_DIRECTORY}/failure"); - - std::fs::create_dir_all(success_traces)?; - std::fs::create_dir_all(failure_traces)?; - - for test_name in TEST_NAMES { - for (itf_name, itf_json) in generate_mbt_traces(apalache, test_name, num_traces)? { - let itf: InformalTrace = - serde_json::from_str(&itf_json).expect("deserialization error"); - - let result = std::panic::catch_unwind(|| f(itf.states).expect("to fail")); - - let unique_itf_trace_path = if result.is_ok() { - format!("{success_traces}/{itf_name}") - } else { - format!("{failure_traces}/{itf_name}") - }; - - let mut file = std::fs::File::create(unique_itf_trace_path)?; - file.write_all(itf_json.as_bytes())?; - - if let Err(err) = result { - std::panic::resume_unwind(err); - } - } - } - Ok(()) -} - -#[test] -fn test_ibc_transfer() -> Result<(), Error> { - execute_mbt(|trace| run_binary_channel_test(&IbcTransferMBT(trace))) -} - -/** - Test that IBC token transfer can still work with a single - chain that is connected to itself. -*/ -#[test] -#[cfg(feature = "manual")] -fn test_self_connected_ibc_transfer() -> Result<(), Error> { - use ibc_test_framework::framework::binary::chain::run_self_connected_binary_chain_test; - use ibc_test_framework::framework::binary::channel::RunBinaryChannelTest; - - execute_mbt(|trace| { - run_self_connected_binary_chain_test(&RunBinaryConnectionTest::new( - &RunBinaryChannelTest::new(&IbcTransferMBT(trace)), - )) - }) -} - -pub struct IbcTransferMBT(Vec); - -impl TestOverrides for IbcTransferMBT { - fn modify_relayer_config(&self, config: &mut Config) { - config.mode = ModeConfig { - clients: ConfigClients { - enabled: true, - refresh: true, - misbehaviour: true, - }, - connections: ConfigConnections { enabled: true }, - channels: ConfigChannels { enabled: true }, - packets: ConfigPackets { - enabled: true, - clear_interval: 10, - clear_on_start: true, - tx_confirmation: true, - ..Default::default() - }, - }; - - for chain_config in config.chains.iter_mut() { - match chain_config { - ChainConfig::CosmosSdk(chain_config) => { - chain_config.trusting_period = Some(CLIENT_EXPIRY); - } - } - } - } - - fn should_spawn_supervisor(&self) -> bool { - false - } -} - -impl BinaryChannelTest for IbcTransferMBT { - fn run( - &self, - _config: &TestConfig, - relayer: RelayerDriver, - chains: ConnectedChains, - channels: ConnectedChannel, - ) -> Result<(), Error> { - // relayer is spawned - let mut supervisor = Some(relayer.spawn_supervisor()?); - - for state in &self.0 { - match &state.action { - Action::Null => { - info!("[Init] Done"); - } - Action::LocalTransfer { - chain_id, - source, - target, - denom, - amount, - } => { - info!("[LocalTransfer] Init"); - let node: Tagged = get_chain(&chains, *chain_id); - super::handlers::local_transfer_handler( - node, *source, *target, *denom, *amount, - )?; - info!("[LocalTransfer] Done"); - } - Action::RestoreRelay => { - if supervisor.is_none() { - supervisor = Some(relayer.spawn_supervisor()?); - } - - info!("[RestoreRelay] Done"); - } - Action::InterruptRelay => { - supervisor.take().expect("one").shutdown(); - - info!("[InterruptRelay] Done"); - } - Action::IBCTransferSendPacket { packet } => { - info!("[IBCTransferSendPacket] {:?}", packet); - - match (packet.source_chain_id, packet.target_chain_id) { - (1, 2) => { - assert!( - super::utils::get_committed_packets_at_src( - &chains.handle_a, - &channels - )? - .is_empty(), - "no packets present" - ); - - super::handlers::ibc_transfer_send_packet( - chains.node_a.as_ref(), - chains.node_b.as_ref(), - &channels, - packet, - )?; - - assert_eq!( - super::utils::get_committed_packets_at_src( - &chains.handle_a, - &channels, - )? - .len(), - 1, - "one packet is sent" - ); - } - (2, 1) => { - assert!( - super::utils::get_committed_packets_at_src( - &chains.handle_b, - &channels.clone().flip() - )? - .is_empty(), - "no packets present" - ); - - super::handlers::ibc_transfer_send_packet( - chains.node_b.as_ref(), - chains.node_a.as_ref(), - &channels.clone().flip(), - packet, - )?; - - assert_eq!( - super::utils::get_committed_packets_at_src( - &chains.handle_b, - &channels.clone().flip() - )? - .len(), - 1, - "one packet is present" - ); - } - _ => unreachable!(), - } - - info!("[IBCTransferSendPacket] Done"); - } - Action::IBCTransferReceivePacket { packet } => { - info!("[IBCTransferReceivePacket] {:?}", packet); - match (packet.source_chain_id, packet.target_chain_id) { - (1, 2) => { - super::handlers::ibc_transfer_receive_packet( - chains.node_a.as_ref(), - chains.node_b.as_ref(), - &channels, - packet, - )?; - assert_eq!( - super::utils::get_acknowledged_packets_at_dst( - &chains.handle_b, - &channels.clone().flip() - )? - .len(), - 1, - "one packet is received and sent acknowledgement" - ); - } - (2, 1) => { - super::handlers::ibc_transfer_receive_packet( - chains.node_b.as_ref(), - chains.node_a.as_ref(), - &channels.clone().flip(), - packet, - )?; - assert_eq!( - super::utils::get_acknowledged_packets_at_dst( - &chains.handle_a, - &channels - )? - .len(), - 1, - "one packet is received and sent acknowledgement" - ); - } - _ => unreachable!(), - } - - info!("[IBCTransferReceivePacket] Done"); - } - Action::IBCTransferAcknowledgePacket { packet } => { - info!("[IBCTransferAcknowledgePacket] {:?}", packet); - super::utils::wait_for_client(); - match (packet.source_chain_id, packet.target_chain_id) { - (1, 2) => { - assert!( - super::utils::get_committed_packets_at_src( - &chains.handle_a, - &channels - )? - .is_empty(), - "commitment is completed" - ); - } - (2, 1) => { - assert!( - super::utils::get_committed_packets_at_src( - &chains.handle_b, - &channels.clone().flip() - )? - .is_empty(), - "commitment is completed" - ); - } - _ => unreachable!(), - } - - info!("[IBCTransferAcknowledgePacket] Done"); - } - Action::IBCTransferTimeoutPacket { packet } => { - info!("[IBCTransferTimeoutPacket] {:?}", packet); - - match (packet.source_chain_id, packet.target_chain_id) { - (1, 2) => {} - (2, 1) => {} - _ => unreachable!(), - } - - info!("[IBCTransferTimeoutPacket] Done") - } - } - } - - Ok(()) - } -} diff --git a/tools/integration-test/src/mbt/utils.rs b/tools/integration-test/src/mbt/utils.rs deleted file mode 100644 index 1b7d9f0e26..0000000000 --- a/tools/integration-test/src/mbt/utils.rs +++ /dev/null @@ -1,136 +0,0 @@ -use std::thread::sleep; -use std::time::Duration; - -use ibc_relayer::chain::requests::{ - QueryPacketAcknowledgementsRequest, QueryPacketCommitmentsRequest, QueryUnreceivedAcksRequest, - QueryUnreceivedPacketsRequest, -}; -use ibc_relayer_types::core::ics04_channel::packet::Sequence; -use ibc_test_framework::ibc::denom::Denom; -use ibc_test_framework::prelude::*; -use ibc_test_framework::types::tagged::mono::Tagged; - -use super::{ - itf::InformalTrace, - state::{DenomId, State}, -}; - -pub const CLIENT_EXPIRY: Duration = Duration::from_secs(15); - -pub fn get_chain( - chains: &ConnectedChains, - chain_id: u128, -) -> Tagged -where - ChainA: ChainHandle, - ChainB: ChainHandle, - ChainX: ChainHandle, -{ - Tagged::new(match chain_id { - 1 => chains.node_a.value(), - 2 => chains.node_b.value(), - _ => unreachable!(), - }) -} - -pub fn get_wallet<'a, ChainX>( - wallets: &'a Tagged, - user: u128, -) -> Tagged { - match user { - 1 => wallets.user1(), - 2 => wallets.user2(), - _ => unreachable!(), - } -} - -pub fn get_denom<'a, ChainX>( - chain: &'a Tagged, - denom: DenomId, -) -> Tagged { - match denom { - 1 => chain.denom(), - 2 => chain.denom(), - _ => unreachable!(), - } -} - -pub fn wait_for_client() { - let sleep_time = CLIENT_EXPIRY + Duration::from_secs(5); - - info!( - "Sleeping for {} seconds to wait for IBC client to expire", - sleep_time.as_secs() - ); - - sleep(sleep_time); -} - -pub fn parse_itf_from_json(itf_path: &str) -> Vec { - let itf_json = std::fs::read_to_string(itf_path).expect("itf file does not exist. did you run `apalache check --inv=Invariant --run-dir=run main.tla` first?"); - - let trace: InformalTrace = - serde_json::from_str(&itf_json).expect("deserialization error"); - - trace.states -} - -pub fn get_unreceived_packets_at_dst( - chain: &ChainA, - channel: &ConnectedChannel, -) -> Result, Error> { - let port_id_a = channel.port_a.value(); - let channel_id_a = channel.channel_id_a.value(); - let request = QueryUnreceivedPacketsRequest { - port_id: port_id_a.clone(), - channel_id: channel_id_a.clone(), - packet_commitment_sequences: Vec::new(), - }; - Ok(chain.query_unreceived_packets(request)?) -} - -pub fn get_committed_packets_at_src( - chain: &ChainA, - channel: &ConnectedChannel, -) -> Result, Error> { - let port_id_a = channel.port_a.value(); - let channel_id_a = channel.channel_id_a.value(); - let request = QueryPacketCommitmentsRequest { - port_id: port_id_a.clone(), - channel_id: channel_id_a.clone(), - pagination: None, - }; - let (sequences, _) = chain.query_packet_commitments(request)?; - Ok(sequences) -} - -pub fn get_unacknowledged_packets_at_src( - chain: &ChainA, - channel: &ConnectedChannel, -) -> Result, Error> { - let port_id_a = channel.port_a.value(); - let channel_id_a = channel.channel_id_a.value(); - let request = QueryUnreceivedAcksRequest { - port_id: port_id_a.clone(), - channel_id: channel_id_a.clone(), - packet_ack_sequences: Vec::new(), - }; - Ok(chain.query_unreceived_acknowledgements(request)?) -} - -pub fn get_acknowledged_packets_at_dst( - chain: &ChainA, - channel: &ConnectedChannel, -) -> Result, Error> { - let port_id_a = channel.port_a.value(); - let channel_id_a = channel.channel_id_a.value(); - let request = QueryPacketAcknowledgementsRequest { - port_id: port_id_a.clone(), - channel_id: channel_id_a.clone(), - pagination: None, - packet_commitment_sequences: Vec::new(), - }; - Ok(chain.query_packet_acknowledgements(request)?.0) -} - -pub fn drop(_: X) {} diff --git a/tools/integration-test/src/tests/async_icq/contracts/counter.wasm b/tools/integration-test/src/tests/async_icq/contracts/counter.wasm new file mode 100644 index 0000000000..407509573e Binary files /dev/null and b/tools/integration-test/src/tests/async_icq/contracts/counter.wasm differ diff --git a/tools/integration-test/src/tests/async_icq/contracts/echo.wasm b/tools/integration-test/src/tests/async_icq/contracts/echo.wasm new file mode 100644 index 0000000000..e8a1bdeced Binary files /dev/null and b/tools/integration-test/src/tests/async_icq/contracts/echo.wasm differ diff --git a/tools/integration-test/src/tests/async_icq/simple_query.rs b/tools/integration-test/src/tests/async_icq/simple_query.rs index 4d2824d344..493d034b1a 100644 --- a/tools/integration-test/src/tests/async_icq/simple_query.rs +++ b/tools/integration-test/src/tests/async_icq/simple_query.rs @@ -1,8 +1,14 @@ +use std::env; + use ibc_relayer::channel::version::Version; use ibc_relayer::config::ChainConfig; -use ibc_test_framework::chain::config::{set_max_deposit_period, set_voting_period}; +use ibc_test_framework::chain::config::{ + add_allow_message_interchainquery, set_floor_gas_price, set_max_deposit_period, + set_min_deposit_amount, set_voting_period, +}; use ibc_test_framework::chain::ext::async_icq::AsyncIcqMethodsExt; use ibc_test_framework::chain::ext::bootstrap::ChainBootstrapMethodsExt; +use ibc_test_framework::chain::ext::wasm_client::StoreWasmClientCodeMethodsExt; use ibc_test_framework::prelude::*; use ibc_test_framework::relayer::channel::{ assert_eventually_channel_established, init_channel_version, @@ -16,10 +22,21 @@ fn test_async_icq() -> Result<(), Error> { run_binary_connection_test(&AsyncIcqTest) } +#[test] +fn test_failed_async_icq() -> Result<(), Error> { + run_binary_connection_test(&FailedAsyncIcqTest) +} + const MAX_DEPOSIT_PERIOD: &str = "10s"; +const MIN_DEPOSIT: u64 = 10000; const VOTING_PERIOD: u64 = 10; const MAX_RETRIES: usize = 10; +enum EventOracleQueryStatus { + Success(Event), + Error(Event), +} + pub struct AsyncIcqTest; impl TestOverrides for AsyncIcqTest { @@ -30,26 +47,13 @@ impl TestOverrides for AsyncIcqTest { // Allow Oracle message on host side fn modify_genesis_file(&self, genesis: &mut serde_json::Value) -> Result<(), Error> { - use serde_json::Value; - set_max_deposit_period(genesis, MAX_DEPOSIT_PERIOD)?; + set_min_deposit_amount(genesis, MIN_DEPOSIT)?; set_voting_period(genesis, VOTING_PERIOD)?; + add_allow_message_interchainquery(genesis, "/provenance.oracle.v1.Query/Oracle")?; + set_floor_gas_price(genesis, "5", "nhash", "25000")?; - let allow_messages = genesis - .get_mut("app_state") - .and_then(|app_state| app_state.get_mut("interchainquery")) - .and_then(|ica| ica.get_mut("params")) - .and_then(|params| params.get_mut("allow_queries")) - .and_then(|allow_messages| allow_messages.as_array_mut()); - - if let Some(allow_messages) = allow_messages { - allow_messages.push(Value::String( - "/provenance.oracle.v1.Query/Oracle".to_string(), - )); - Ok(()) - } else { - Err(Error::generic(eyre!("failed to update genesis file"))) - } + Ok(()) } fn channel_version(&self) -> Version { @@ -65,8 +69,8 @@ impl BinaryConnectionTest for AsyncIcqTest { chains: ConnectedChains, connection: ConnectedConnection, ) -> Result<(), Error> { - let fee_denom_a: MonoTagged = - MonoTagged::new(Denom::base(&config.native_tokens[0])); + let fee_denom_b: MonoTagged = + MonoTagged::new(Denom::base(config.native_token(1))); let port_a = DualTagged::new(PortId::oracle()); let port_b = DualTagged::new(PortId::icqhost()); let (channel_id_b, channel_id_a) = init_channel_version( @@ -89,39 +93,229 @@ impl BinaryConnectionTest for AsyncIcqTest { &port_b.as_ref(), )?; - let driver = chains.node_a.chain_driver(); + let driver_b = chains.node_b.chain_driver(); let wallet_a = chains.node_a.wallets().user1().cloned(); - let relayer_a = chains.node_a.wallets().relayer().cloned(); + let relayer_b = chains.node_b.wallets().relayer().cloned(); + + let oracle_auth_address = driver_b.query_auth_module("gov")?; + + let current_dir = env::current_dir()?; + let echo_wasm_path = format!( + "{}/src/tests/async_icq/contracts/counter.wasm", + current_dir.display() + ); + + driver_b.store_wasm_contract( + "counter wasm", + "counter wasm", + &echo_wasm_path, + &oracle_auth_address, + &relayer_b.address().to_string(), + &fee_denom_b.with_amount(923290636u64).to_string(), + &fee_denom_b.with_amount(11000000000u64).to_string(), + "14472508", + )?; + + driver_b.value().assert_proposal_status( + driver_b.value().chain_id.as_str(), + &driver_b.value().command_path, + &driver_b.value().home_path, + &driver_b.value().rpc_listen_address(), + ProposalStatus::VotingPeriod, + "1", + )?; + + driver_b.vote_proposal(&fee_denom_b.with_amount(381000000u64).to_string(), "1")?; + + info!("Assert that the wasm contract is successfully uploaded"); + + driver_b.value().assert_proposal_status( + driver_b.value().chain_id.as_str(), + &driver_b.value().command_path, + &driver_b.value().home_path, + &driver_b.value().rpc_listen_address(), + ProposalStatus::Passed, + "1", + )?; + + let init_args = r#"{"count": 1}"#; + driver_b.update_oracle( + &relayer_b.address().to_string(), + &fee_denom_b.with_amount(381000000u64).to_string(), + init_args, + )?; + + driver_b.value().assert_proposal_status( + driver_b.value().chain_id.as_str(), + &driver_b.value().command_path, + &driver_b.value().home_path, + &driver_b.value().rpc_listen_address(), + ProposalStatus::VotingPeriod, + "2", + )?; + + driver_b.vote_proposal(&fee_denom_b.with_amount(381000000u64).to_string(), "2")?; + + info!("Assert that the update oracle proposal is eventually passed"); - driver.update_oracle( - &relayer_a.address().to_string(), + driver_b.value().assert_proposal_status( + driver_b.value().chain_id.as_str(), + &driver_b.value().command_path, + &driver_b.value().home_path, + &driver_b.value().rpc_listen_address(), + ProposalStatus::Passed, + "2", + )?; + + let query = r#"{"get_count":{"addr": "{my_addr}"}}"#; + let query = query.replace("{my_addr}", &relayer_b.address().to_string()); + + chains.node_a.chain_driver().async_icq( + channel_id_a.a_side.channel_id().unwrap(), + &query, &wallet_a.address().to_string(), )?; - driver.value().assert_proposal_status( - driver.value().chain_id.as_str(), - &driver.value().command_path, - &driver.value().home_path, - &driver.value().rpc_listen_address(), + assert_eventual_async_icq_success(&chains, &relayer)?; + + Ok(()) + } +} + +pub struct FailedAsyncIcqTest; + +impl TestOverrides for FailedAsyncIcqTest { + fn modify_relayer_config(&self, config: &mut Config) { + config.mode.channels.enabled = true; + config.mode.clients.misbehaviour = false; + } + + // Allow Oracle message on host side + fn modify_genesis_file(&self, genesis: &mut serde_json::Value) -> Result<(), Error> { + set_max_deposit_period(genesis, MAX_DEPOSIT_PERIOD)?; + set_min_deposit_amount(genesis, MIN_DEPOSIT)?; + set_voting_period(genesis, VOTING_PERIOD)?; + add_allow_message_interchainquery(genesis, "/provenance.oracle.v1.Query/Oracle")?; + set_floor_gas_price(genesis, "5", "nhash", "25000")?; + + Ok(()) + } + + fn channel_version(&self) -> Version { + Version::new("icq-1".to_owned()) + } +} + +impl BinaryConnectionTest for FailedAsyncIcqTest { + fn run( + &self, + config: &TestConfig, + relayer: RelayerDriver, + chains: ConnectedChains, + connection: ConnectedConnection, + ) -> Result<(), Error> { + let fee_denom_b: MonoTagged = + MonoTagged::new(Denom::base(config.native_token(1))); + let port_a = DualTagged::new(PortId::oracle()); + let port_b = DualTagged::new(PortId::icqhost()); + let (channel_id_b, channel_id_a) = init_channel_version( + &chains.handle_a, + &chains.handle_b, + &chains.client_id_a(), + &chains.client_id_b(), + &connection.connection_id_a.as_ref(), + &connection.connection_id_b.as_ref(), + &port_a.as_ref(), + &port_b.as_ref(), + Version::new("icq-1".to_owned()), + )?; + + // Check that the oracle channel is eventually established + let _counterparty_channel_id = assert_eventually_channel_established( + chains.handle_b(), + chains.handle_a(), + &channel_id_b.as_ref(), + &port_b.as_ref(), + )?; + + let driver_b = chains.node_b.chain_driver(); + + let wallet_a = chains.node_a.wallets().user1().cloned(); + + let relayer_b = chains.node_b.wallets().relayer().cloned(); + + let oracle_auth_address = driver_b.query_auth_module("gov")?; + + let current_dir = env::current_dir()?; + let echo_wasm_path = format!( + "{}/src/tests/async_icq/contracts/echo.wasm", + current_dir.display() + ); + + driver_b.store_wasm_contract( + "echo wasm", + "echo wasm", + &echo_wasm_path, + &oracle_auth_address, + &relayer_b.address().to_string(), + &fee_denom_b.with_amount(923290636u64).to_string(), + &fee_denom_b.with_amount(11000000000u64).to_string(), + "9972508", + )?; + + driver_b.value().assert_proposal_status( + driver_b.value().chain_id.as_str(), + &driver_b.value().command_path, + &driver_b.value().home_path, + &driver_b.value().rpc_listen_address(), ProposalStatus::VotingPeriod, "1", )?; - driver.vote_proposal(&fee_denom_a.with_amount(381000000u64).to_string())?; + driver_b.vote_proposal(&fee_denom_b.with_amount(381000000u64).to_string(), "1")?; info!("Assert that the update oracle proposal is eventually passed"); - driver.value().assert_proposal_status( - driver.value().chain_id.as_str(), - &driver.value().command_path, - &driver.value().home_path, - &driver.value().rpc_listen_address(), + driver_b.value().assert_proposal_status( + driver_b.value().chain_id.as_str(), + &driver_b.value().command_path, + &driver_b.value().home_path, + &driver_b.value().rpc_listen_address(), ProposalStatus::Passed, "1", )?; + let init_args = r#"{}"#; + driver_b.update_oracle( + &relayer_b.address().to_string(), + &fee_denom_b.with_amount(381000000u64).to_string(), + init_args, + )?; + + driver_b.value().assert_proposal_status( + driver_b.value().chain_id.as_str(), + &driver_b.value().command_path, + &driver_b.value().home_path, + &driver_b.value().rpc_listen_address(), + ProposalStatus::VotingPeriod, + "2", + )?; + + driver_b.vote_proposal(&fee_denom_b.with_amount(381000000u64).to_string(), "2")?; + + info!("Assert that the update oracle proposal is eventually passed"); + + driver_b.value().assert_proposal_status( + driver_b.value().chain_id.as_str(), + &driver_b.value().command_path, + &driver_b.value().home_path, + &driver_b.value().rpc_listen_address(), + ProposalStatus::Passed, + "2", + )?; + let query = r#"{"query_version":{}}"#; chains.node_a.chain_driver().async_icq( channel_id_a.a_side.channel_id().unwrap(), @@ -129,7 +323,7 @@ impl BinaryConnectionTest for AsyncIcqTest { &wallet_a.address().to_string(), )?; - assert_eventual_async_icq_success(&chains, &relayer)?; + assert_eventual_async_icq_error(&chains, &relayer)?; Ok(()) } @@ -146,11 +340,56 @@ fn assert_eventual_async_icq_success( }; let mut rpc_client = HttpClient::new(rpc_addr).unwrap(); - rpc_client.set_compat_mode(tendermint_rpc::client::CompatMode::V0_34); + rpc_client.set_compat_mode(tendermint_rpc::client::CompatMode::V0_37); + + for _ in 0..MAX_RETRIES { + if let Ok(result) = check_events_for_success(chains, &rpc_client) { + match result { + EventOracleQueryStatus::Success(e) => { + debug!("async query successful with event: {e:#?}"); + return Ok(()); + } + EventOracleQueryStatus::Error(e) => { + return Err(Error::generic(eyre!( + "async query failed with response event: {e:#?}" + ))) + } + } + } + sleep(Duration::from_secs(1)); + } + + Err(Error::generic(eyre!( + "failed to find EventOracleQueryError or EventOracleQuerySuccess after {MAX_RETRIES} tries" + ))) +} + +/// Listen to events on the controller side to assert if the async ICQ is eventually +/// successful +fn assert_eventual_async_icq_error( + chains: &ConnectedChains, + relayer: &RelayerDriver, +) -> Result<(), Error> { + let rpc_addr = match relayer.config.chains.first().unwrap() { + ChainConfig::CosmosSdk(c) => c.rpc_addr.clone(), + }; + + let mut rpc_client = HttpClient::new(rpc_addr).unwrap(); + rpc_client.set_compat_mode(tendermint_rpc::client::CompatMode::V0_37); for _ in 0..MAX_RETRIES { - if check_events(chains, &rpc_client).is_ok() { - return Ok(()); + if let Ok(result) = check_events_for_error(chains, &rpc_client) { + match result { + EventOracleQueryStatus::Success(e) => { + debug!("async query successful with event: {e:#?}"); + return Ok(()); + } + EventOracleQueryStatus::Error(e) => { + return Err(Error::generic(eyre!( + "async query failed with response event: {e:#?}" + ))) + } + } } sleep(Duration::from_secs(1)); } @@ -161,10 +400,10 @@ fn assert_eventual_async_icq_success( } /// Checks if there is an Oracle event in the given events -fn check_events( +fn check_events_for_success( chains: &ConnectedChains, rpc_client: &HttpClient, -) -> Result<(), Error> { +) -> Result { let response = chains .node_a .chain_driver() @@ -178,7 +417,34 @@ fn check_events( .iter() .find_map(|v| find_oracle_event(&v.events)) { - return assert_async_icq_success(events); + return Ok(assert_async_icq_success(events)); + } + } + + Err(Error::generic(eyre!( + "No EventOracleQueryError or EventOracleQuerySuccess" + ))) +} + +/// Checks if there is an Oracle event in the given events +fn check_events_for_error( + chains: &ConnectedChains, + rpc_client: &HttpClient, +) -> Result { + let response = chains + .node_a + .chain_driver() + .value() + .runtime + .block_on(rpc_client.latest_block_results()) + .map_err(|err| Error::generic(eyre!("Failed to fetch block results: {}", err)))?; + + if let Some(txs_results) = response.txs_results { + if let Some(events) = txs_results + .iter() + .find_map(|v| find_oracle_event(&v.events)) + { + return Ok(assert_async_icq_error(events)); } } @@ -192,18 +458,41 @@ fn check_events( fn find_oracle_event(event: &[Event]) -> Option { event .iter() - .find(|&e| e.kind.contains("provenance.oracle.v1.EventOracleQuery")) + .find(|&e| { + e.kind.contains("provenance.oracle.v1.EventOracleQuery") + || e.kind + .contains("provenance.oracle.v1.EventOracleQueryError") + }) .cloned() } /// This method is used to assert if the found Oracle event is successful or not -fn assert_async_icq_success(event: Event) -> Result<(), Error> { +fn assert_async_icq_success(event: Event) -> EventOracleQueryStatus { if event.kind == "provenance.oracle.v1.EventOracleQuerySuccess" { - debug!("async query successful with event: {event:#?}"); - Ok(()) + EventOracleQueryStatus::Success(event) + } else { + EventOracleQueryStatus::Error(event) + } +} + +/// This method is used to assert if the found Oracle event is successful or not +fn assert_async_icq_error(event: Event) -> EventOracleQueryStatus { + if event.kind == "provenance.oracle.v1.EventOracleQueryError" { + let error_message = event + .attributes + .iter() + .find(|attribute| attribute.key_str().unwrap() == "error") + .and_then(|error_attribute| error_attribute.value_str().ok()) + .unwrap(); + // The ABCI error code 29 refers to the following: + // Error calling the VM: Error resolving Wasm function: Could not get export: Missing export query: wasmvm error + // This is caused by the echo.wasm contract not having a query endpoint, causing the ICQ to fail. + assert_eq!( + error_message, + "\"ABCI code: 29: error handling packet: see events for details\"" + ); + EventOracleQueryStatus::Success(event) } else { - Err(Error::generic(eyre!( - "async query failed with response event: {event:#?}" - ))) + EventOracleQueryStatus::Error(event) } } diff --git a/tools/integration-test/src/tests/authz.rs b/tools/integration-test/src/tests/authz.rs new file mode 100644 index 0000000000..28f5c11a18 --- /dev/null +++ b/tools/integration-test/src/tests/authz.rs @@ -0,0 +1,199 @@ +//! This test tests relaying messages from authz: +//! +//! - The `AuthzTest` will grant authorization for `MsgTransfer` from `user2` (granter) +//! to `user1` (grantee). It will then execute an IBC transfer using the chain's +//! `tx authz exec` command and assert that the transfer successfully completes. +//! +//! - The `NoAuthzTest` will skip granting authorization and assert that the +//! `MsgTransfer` is not authorized and that the chain's `tx authz exec` +//! command fails. + +use ibc_test_framework::chain::ext::authz::AuthzMethodsExt; +use ibc_test_framework::prelude::*; + +#[test] +fn test_authz() -> Result<(), Error> { + run_binary_channel_test(&AuthzTest) +} + +#[test] +fn test_no_authz() -> Result<(), Error> { + run_binary_channel_test(&NoAuthzTest) +} + +struct AuthzTest; + +impl TestOverrides for AuthzTest {} + +impl BinaryChannelTest for AuthzTest { + fn run( + &self, + config: &TestConfig, + _relayer: RelayerDriver, + chains: ConnectedChains, + channels: ConnectedChannel, + ) -> Result<(), Error> { + let denom_a = chains.node_a.denom(); + let fee_denom_a: MonoTagged = + MonoTagged::new(Denom::base(config.native_token(0))); + let wallet_b = chains.node_b.wallets().user1().cloned(); + + let a_to_b_amount = 12345u64; + let granter = chains + .node_a + .wallets() + .user2() + .address() + .value() + .to_string(); + let grantee = chains + .node_a + .wallets() + .user1() + .address() + .value() + .to_string(); + + let fees = fee_denom_a.with_amount(390000000u64).to_string(); + + chains.node_a.chain_driver().authz_grant( + &granter, + &grantee, + "/ibc.applications.transfer.v1.MsgTransfer", + &fees, + )?; + + chains.node_a.chain_driver().assert_eventual_grant( + &granter, + &grantee, + "/ibc.applications.transfer.v1.MsgTransfer", + )?; + + let granter_balance = chains + .node_a + .chain_driver() + .query_balance(&chains.node_a.wallets().user2().address(), &denom_a)?; + + let denom_b = derive_ibc_denom( + &channels.port_b.as_ref(), + &channels.channel_id_b.as_ref(), + &denom_a, + )?; + + chains.node_a.chain_driver().exec_ibc_transfer_grant( + &granter, + &grantee, + channels.port_a.value(), + channels.channel_id_a.value(), + &wallet_b.address(), + &denom_a.with_amount(a_to_b_amount).as_ref(), + &fees, + )?; + + // Assert that user on chain B received the tokens + chains.node_b.chain_driver().assert_eventual_wallet_amount( + &wallet_b.address(), + &denom_b.with_amount(a_to_b_amount).as_ref(), + )?; + + // Assert that user on chain A sent the tokens + chains.node_a.chain_driver().assert_eventual_wallet_amount( + &chains.node_a.wallets().user2().address(), + &(granter_balance - a_to_b_amount).as_ref(), + )?; + + Ok(()) + } +} + +struct NoAuthzTest; + +impl TestOverrides for NoAuthzTest {} + +impl BinaryChannelTest for NoAuthzTest { + fn run( + &self, + config: &TestConfig, + _relayer: RelayerDriver, + chains: ConnectedChains, + channels: ConnectedChannel, + ) -> Result<(), Error> { + let denom_a = chains.node_a.denom(); + let fee_denom_a: MonoTagged = + MonoTagged::new(Denom::base(config.native_token(0))); + let wallet_b = chains.node_b.wallets().user1().cloned(); + + let a_to_b_amount = 12345u64; + let granter = chains + .node_a + .wallets() + .user2() + .address() + .value() + .to_string(); + let grantee = chains + .node_a + .wallets() + .user1() + .address() + .value() + .to_string(); + + let denom_b = derive_ibc_denom( + &channels.port_b.as_ref(), + &channels.channel_id_b.as_ref(), + &denom_a, + )?; + + assert!( + chains + .node_a + .chain_driver() + .assert_eventual_grant( + &granter, + &grantee, + "/ibc.applications.transfer.v1.MsgTransfer", + ) + .is_err(), + "there should be no grants" + ); + + let granter_balance = chains + .node_a + .chain_driver() + .query_balance(&chains.node_a.wallets().user2().address(), &denom_a)?; + + let fees = fee_denom_a.with_amount(390000000u64).to_string(); + + assert!( + chains + .node_a + .chain_driver() + .exec_ibc_transfer_grant( + &granter, + &grantee, + channels.port_a.value(), + channels.channel_id_a.value(), + &wallet_b.address(), + &denom_a.with_amount(a_to_b_amount).as_ref(), + &fees, + ) + .is_err(), + "expected authz grant exec to fail" + ); + + // Assert that user on chain B has not received tokens + chains.node_b.chain_driver().assert_eventual_wallet_amount( + &wallet_b.address(), + &denom_b.with_amount(0u128).as_ref(), + )?; + + // Assert that user on chain A has not sent tokens + chains.node_a.chain_driver().assert_eventual_wallet_amount( + &chains.node_a.wallets().user2().address(), + &granter_balance.as_ref(), + )?; + + Ok(()) + } +} diff --git a/tools/integration-test/src/tests/benchmark/mod.rs b/tools/integration-test/src/tests/benchmark/mod.rs new file mode 100644 index 0000000000..169d3ccaca --- /dev/null +++ b/tools/integration-test/src/tests/benchmark/mod.rs @@ -0,0 +1 @@ +pub mod query_commitments; diff --git a/tools/integration-test/src/tests/benchmark/query_commitments.rs b/tools/integration-test/src/tests/benchmark/query_commitments.rs new file mode 100644 index 0000000000..b05b02f5c4 --- /dev/null +++ b/tools/integration-test/src/tests/benchmark/query_commitments.rs @@ -0,0 +1,82 @@ +use ibc_test_framework::prelude::*; + +#[test] +fn benchmark_query_commitments() -> Result<(), Error> { + run_binary_channel_test(&QueryCommitmentsBenchmark) +} + +pub struct QueryCommitmentsBenchmark; + +impl TestOverrides for QueryCommitmentsBenchmark { + fn modify_relayer_config(&self, config: &mut Config) { + config.mode.packets.clear_on_start = false; + config.mode.packets.clear_interval = 0; + } + + fn should_spawn_supervisor(&self) -> bool { + false + } +} + +impl BinaryChannelTest for QueryCommitmentsBenchmark { + fn run( + &self, + config: &TestConfig, + relayer: RelayerDriver, + chains: ConnectedChains, + channel: ConnectedChannel, + ) -> Result<(), Error> { + use std::path::Path; + + use ibc_relayer::util::profiling::open_or_create_profile_file; + + let now = time::OffsetDateTime::now_utc(); + let path_str = format!( + "{}/hermes-{:04}-{:02}-{:02}-{:02}{:02}{:02}-prof.json", + config.chain_store_dir.as_path().display(), + now.year(), + now.month(), + now.day(), + now.hour(), + now.minute(), + now.second() + ); + + open_or_create_profile_file(Path::new(&path_str)); + ibc_relayer::util::profiling::enable(false, true); + + let denom_a = chains.node_a.denom(); + + let wallet_a = chains.node_a.wallets().user1().cloned(); + let wallet_b = chains.node_b.wallets().user1().cloned(); + + let a_to_b_amount = 12u64; + let num_msgs = 1000000u64; + + info!( + "Sending {num_msgs} IBC transfers from chain {} to chain {} with amount of {} {}", + chains.chain_id_a(), + chains.chain_id_b(), + a_to_b_amount, + denom_a + ); + + chains.node_a.chain_driver().ibc_transfer_token_multiple( + &channel.port_a.as_ref(), + &channel.channel_id_a.as_ref(), + &wallet_a.as_ref(), + &wallet_b.address(), + &denom_a.with_amount(a_to_b_amount).as_ref(), + num_msgs as usize, + None, + )?; + + info!("Waiting for profiling to be populated"); + + relayer.with_supervisor(|| { + std::thread::sleep(core::time::Duration::from_secs(180)); + + Ok(()) + }) + } +} diff --git a/tools/integration-test/src/tests/channel_upgrade/flushing.rs b/tools/integration-test/src/tests/channel_upgrade/flushing.rs new file mode 100644 index 0000000000..0e4bdf7143 --- /dev/null +++ b/tools/integration-test/src/tests/channel_upgrade/flushing.rs @@ -0,0 +1,422 @@ +//! Tests that the relayer correctly flushes in-flight packets during channel upgrade. +//! +//! - `ChannelUpgradeFlushing` tests that the channel worker will complete the +//! upgrade handshake when there are pending packets before starting the channel upgrade. +//! +//! - `ChannelUpgradeHandshakeFlushPackets` tests that the channel worker will complete the +//! upgrade handshake when packets need to be flushed during the handshake. + +use ibc_relayer::chain::requests::{IncludeProof, QueryChannelRequest, QueryHeight}; +use ibc_relayer_types::core::ics04_channel::channel::State as ChannelState; +use ibc_relayer_types::core::ics04_channel::packet::Sequence; +use ibc_relayer_types::core::ics04_channel::version::Version; +use ibc_test_framework::chain::config::{set_max_deposit_period, set_voting_period}; +use ibc_test_framework::prelude::*; +use ibc_test_framework::relayer::channel::{ + assert_eventually_channel_established, assert_eventually_channel_upgrade_ack, + assert_eventually_channel_upgrade_init, assert_eventually_channel_upgrade_open, + assert_eventually_channel_upgrade_try, ChannelUpgradableAttributes, +}; +use ibc_test_framework::util::random::random_u128_range; + +#[test] +fn test_channel_upgrade_simple_flushing() -> Result<(), Error> { + run_binary_channel_test(&ChannelUpgradeFlushing) +} + +#[test] +fn test_channel_upgrade_handshake_flush_packets() -> Result<(), Error> { + run_binary_channel_test(&ChannelUpgradeHandshakeFlushPackets) +} + +const MAX_DEPOSIT_PERIOD: &str = "10s"; +const VOTING_PERIOD: u64 = 10; + +pub struct ChannelUpgradeFlushing; + +impl TestOverrides for ChannelUpgradeFlushing { + fn modify_relayer_config(&self, config: &mut Config) { + config.mode.channels.enabled = true; + config.mode.packets.auto_register_counterparty_payee = true; + config.mode.packets.clear_interval = 0; + config.mode.packets.clear_on_start = true; + + config.mode.clients.misbehaviour = false; + } + + fn modify_genesis_file(&self, genesis: &mut serde_json::Value) -> Result<(), Error> { + set_max_deposit_period(genesis, MAX_DEPOSIT_PERIOD)?; + set_voting_period(genesis, VOTING_PERIOD)?; + Ok(()) + } + + fn should_spawn_supervisor(&self) -> bool { + false + } +} + +impl BinaryChannelTest for ChannelUpgradeFlushing { + fn run( + &self, + _config: &TestConfig, + relayer: RelayerDriver, + chains: ConnectedChains, + channels: ConnectedChannel, + ) -> Result<(), Error> { + info!("Check that channels are both in OPEN State"); + + assert_eventually_channel_established( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + )?; + + let channel_end_a = chains + .handle_a + .query_channel( + QueryChannelRequest { + port_id: channels.port_a.0.clone(), + channel_id: channels.channel_id_a.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd A: {e}"))?; + + let channel_end_b = chains + .handle_b + .query_channel( + QueryChannelRequest { + port_id: channels.port_b.0.clone(), + channel_id: channels.channel_id_b.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd B: {e}"))?; + + let chain_driver_a = chains.node_a.chain_driver(); + let chain_driver_b = chains.node_b.chain_driver(); + + let denom_a = chains.node_a.denom(); + + let port_a = channels.port_a.as_ref(); + let channel_id_a = channels.channel_id_a.as_ref(); + + let wallets_a = chains.node_a.wallets(); + let wallets_b = chains.node_b.wallets(); + + let user_a = wallets_a.user1(); + let user_b = wallets_b.user1(); + + let send_amount = random_u128_range(1000, 2000); + + chain_driver_a.ibc_transfer_token( + &port_a, + &channel_id_a, + &user_a, + &user_b.address(), + &denom_a.with_amount(send_amount).as_ref(), + )?; + + sleep(Duration::from_secs(3)); + + chain_driver_a.ibc_transfer_token( + &port_a, + &channel_id_a, + &user_a, + &user_b.address(), + &denom_a.with_amount(send_amount).as_ref(), + )?; + + let old_ordering = channel_end_a.ordering; + let old_connection_hops_a = channel_end_a.connection_hops; + let old_connection_hops_b = channel_end_b.connection_hops; + + let channel = channels.channel; + let new_version = Version::ics20_with_fee(); + + let upgraded_attrs = ChannelUpgradableAttributes::new( + new_version.clone(), + new_version.clone(), + old_ordering, + old_connection_hops_a.clone(), + old_connection_hops_b, + Sequence::from(1), + ); + + info!("Will initialise upgrade handshake with governance proposal..."); + + chains.node_a.chain_driver().initialise_channel_upgrade( + channel.src_port_id().as_str(), + channel.src_channel_id().unwrap().as_str(), + old_ordering.as_str(), + old_connection_hops_a.first().unwrap().as_str(), + &serde_json::to_string(&new_version.0).unwrap(), + chains.handle_a().get_signer().unwrap().as_ref(), + "1", + )?; + + sleep(Duration::from_secs(5)); + + info!("Check that the channel upgrade successfully upgraded the version..."); + + relayer.with_supervisor(|| { + let denom_b = derive_ibc_denom( + &channels.port_b.as_ref(), + &channels.channel_id_b.as_ref(), + &denom_a, + )?; + + chain_driver_b.assert_eventual_wallet_amount( + &user_b.address(), + &denom_b.with_amount(send_amount + send_amount).as_ref(), + )?; + + assert_eventually_channel_upgrade_open( + &chains.handle_a, + &chains.handle_b, + &channels.channel_id_a.as_ref(), + &channels.port_a.as_ref(), + &upgraded_attrs, + )?; + + Ok(()) + }) + } +} + +struct ChannelUpgradeHandshakeFlushPackets; + +impl TestOverrides for ChannelUpgradeHandshakeFlushPackets { + fn modify_genesis_file(&self, genesis: &mut serde_json::Value) -> Result<(), Error> { + set_max_deposit_period(genesis, MAX_DEPOSIT_PERIOD)?; + set_voting_period(genesis, VOTING_PERIOD)?; + Ok(()) + } + + fn modify_relayer_config(&self, config: &mut Config) { + config.mode.channels.enabled = true; + + config.mode.clients.misbehaviour = false; + } + + fn should_spawn_supervisor(&self) -> bool { + false + } +} + +impl BinaryChannelTest for ChannelUpgradeHandshakeFlushPackets { + fn run( + &self, + _config: &TestConfig, + relayer: RelayerDriver, + chains: ConnectedChains, + channels: ConnectedChannel, + ) -> Result<(), Error> { + info!("Check that channels are both in OPEN State"); + + assert_eventually_channel_established( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + )?; + + let channel_end_a = chains + .handle_a + .query_channel( + QueryChannelRequest { + port_id: channels.port_a.0.clone(), + channel_id: channels.channel_id_a.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd A: {e}"))?; + + let channel_end_b = chains + .handle_b + .query_channel( + QueryChannelRequest { + port_id: channels.port_b.0.clone(), + channel_id: channels.channel_id_b.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd B: {e}"))?; + + let old_version = channel_end_a.version; + let old_ordering = channel_end_a.ordering; + let old_connection_hops_a = channel_end_a.connection_hops; + let old_connection_hops_b = channel_end_b.connection_hops; + + let channel = channels.channel; + let new_version = Version::ics20_with_fee(); + + let old_attrs = ChannelUpgradableAttributes::new( + old_version.clone(), + old_version.clone(), + old_ordering, + old_connection_hops_a.clone(), + old_connection_hops_b.clone(), + Sequence::from(1), + ); + + let upgraded_attrs = ChannelUpgradableAttributes::new( + new_version.clone(), + new_version.clone(), + old_ordering, + old_connection_hops_a.clone(), + old_connection_hops_b, + Sequence::from(1), + ); + + info!("Will initialise upgrade handshake with governance proposal..."); + + chains.node_a.chain_driver().initialise_channel_upgrade( + channel.src_port_id().as_str(), + channel.src_channel_id().unwrap().as_str(), + old_ordering.as_str(), + old_connection_hops_a.first().unwrap().as_str(), + &serde_json::to_string(&new_version.0).unwrap(), + chains.handle_a().get_signer().unwrap().as_ref(), + "1", + )?; + + info!("Check that the step ChanUpgradeInit was correctly executed..."); + + assert_eventually_channel_upgrade_init( + &chains.handle_a, + &chains.handle_b, + &channels.channel_id_a.as_ref(), + &channels.port_a.as_ref(), + &old_attrs, + )?; + + // send a IBC transfer message from chain a to chain b + // so that we have an in-flight packet and chain a + // will move to `FLUSHING` during Ack + let denom_a = chains.node_a.denom(); + let wallet_a = chains.node_a.wallets().user1().cloned(); + let wallet_b = chains.node_b.wallets().user1().cloned(); + let a_to_b_amount = random_u128_range(1000, 5000); + + info!( + "Sending IBC transfer from chain {} to chain {} with amount of {} {}", + chains.chain_id_a(), + chains.chain_id_b(), + a_to_b_amount, + denom_a + ); + + chains.node_a.chain_driver().ibc_transfer_token( + &channels.port_a.as_ref(), + &channels.channel_id_a.as_ref(), + &wallet_a.as_ref(), + &wallet_b.address(), + &denom_a.with_amount(a_to_b_amount).as_ref(), + )?; + + // send a IBC transfer message from chain b to chain a + // so that we have an in-flight packet and chain a + // will move to `FLUSHING` during Try + let denom_b = chains.node_b.denom(); + let b_to_a_amount = random_u128_range(1000, 5000); + + info!( + "Sending IBC transfer from chain {} to chain {} with amount of {} {}", + chains.chain_id_b(), + chains.chain_id_a(), + b_to_a_amount, + denom_b + ); + + chains.node_b.chain_driver().ibc_transfer_token( + &channels.port_b.as_ref(), + &channels.channel_id_b.as_ref(), + &wallet_b.as_ref(), + &wallet_a.address(), + &denom_b.with_amount(b_to_a_amount).as_ref(), + )?; + + info!("Will run ChanUpgradeTry step..."); + + channel.build_chan_upgrade_try_and_send()?; + + info!("Check that the step ChanUpgradeTry was correctly executed..."); + + assert_eventually_channel_upgrade_try( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + &old_attrs.flipped(), + )?; + + info!("Will run ChanUpgradeAck step..."); + + channel.flipped().build_chan_upgrade_ack_and_send()?; + + info!("Check that the step ChanUpgradeAck was correctly executed..."); + + // channel a is `FLUSHING` because the packet + // from a to b has not been cleared yet + assert_eventually_channel_upgrade_ack( + &chains.handle_a, + &chains.handle_b, + &channels.channel_id_a.as_ref(), + &channels.port_a.as_ref(), + ChannelState::Flushing, + ChannelState::Flushing, + &old_attrs, + )?; + + info!("Check that the channel upgrade successfully upgraded the version..."); + + // start supervisor to clear in-flight packets + // and move channel ends to `FLUSH_COMPLETE` + relayer.with_supervisor(|| { + let ibc_denom_a = derive_ibc_denom( + &channels.port_a.as_ref(), + &channels.channel_id_a.as_ref(), + &denom_b, + )?; + + chains.node_a.chain_driver().assert_eventual_wallet_amount( + &wallet_a.address(), + &ibc_denom_a.with_amount(b_to_a_amount).as_ref(), + )?; + + let ibc_denom_b = derive_ibc_denom( + &channels.port_b.as_ref(), + &channels.channel_id_b.as_ref(), + &denom_a, + )?; + + chains.node_b.chain_driver().assert_eventual_wallet_amount( + &wallet_b.address(), + &ibc_denom_b.with_amount(a_to_b_amount).as_ref(), + )?; + + // This will assert that both channel ends are eventually + // in Open state, and that the fields targeted by the upgrade + // have been correctly updated. + assert_eventually_channel_upgrade_open( + &chains.handle_a, + &chains.handle_b, + &channels.channel_id_a.as_ref(), + &channels.port_a.as_ref(), + &upgraded_attrs, + )?; + + Ok(()) + }) + } +} diff --git a/tools/integration-test/src/tests/channel_upgrade/ica.rs b/tools/integration-test/src/tests/channel_upgrade/ica.rs new file mode 100644 index 0000000000..8ddd4fb5c7 --- /dev/null +++ b/tools/integration-test/src/tests/channel_upgrade/ica.rs @@ -0,0 +1,526 @@ +//! Tests channel upgrade features: +//! +//! - `ChannelUpgradeICACloseChannel` tests that after the upgrade handshake is completed +//! and the channel version has been updated to ICS29 a packet timeout closes the channel. +//! +//! - `ChannelUpgradeICAUnordered` tests that after the after sending a packet on an ordered +//! ICA channel, the upgrade handshake is completed when the channel is upgraded to unordered. + +use serde_json as json; +use std::collections::HashMap; +use std::str::FromStr; + +use ibc_relayer::chain::requests::{IncludeProof, QueryChannelRequest, QueryHeight}; +use ibc_relayer::chain::tracking::TrackedMsgs; +use ibc_relayer::config::{ + filter::{ChannelFilters, ChannelPolicy, FilterPattern}, + ChainConfig, PacketFilter, +}; +use ibc_relayer::event::IbcEventWithHeight; + +use ibc_relayer_types::applications::{ + ics27_ica, + ics27_ica::{ + cosmos_tx::CosmosTx, msgs::send_tx::MsgSendTx, packet_data::InterchainAccountPacketData, + }, + transfer::{msgs::send::MsgSend, Amount, Coin}, +}; +use ibc_relayer_types::bigint::U256; +use ibc_relayer_types::core::ics04_channel::packet::Sequence; +use ibc_relayer_types::core::ics04_channel::version::Version; +use ibc_relayer_types::signer::Signer; +use ibc_relayer_types::timestamp::Timestamp; +use ibc_relayer_types::tx_msg::Msg; + +use ibc_test_framework::chain::config::{ + add_allow_message_interchainaccounts, set_max_deposit_period, set_voting_period, +}; +use ibc_test_framework::chain::ext::ica::register_ordered_interchain_account; +use ibc_test_framework::prelude::*; +use ibc_test_framework::relayer::channel::{ + assert_eventually_channel_closed, assert_eventually_channel_established, + assert_eventually_channel_upgrade_open, ChannelUpgradableAttributes, +}; + +#[test] +fn test_channel_upgrade_ica_close_channel() -> Result<(), Error> { + run_binary_connection_test(&ChannelUpgradeICACloseChannel) +} + +#[test] +fn test_channel_upgrade_ica_unordered() -> Result<(), Error> { + run_binary_connection_test(&ChannelUpgradeICAUnordered::new(PacketFilter::new( + ChannelPolicy::Allow(ChannelFilters::new(vec![( + FilterPattern::Wildcard("ica*".parse().unwrap()), + FilterPattern::Wildcard("*".parse().unwrap()), + )])), + HashMap::new(), + ))) +} + +const MAX_DEPOSIT_PERIOD: &str = "10s"; +const VOTING_PERIOD: u64 = 10; + +pub struct ChannelUpgradeICACloseChannel; + +impl TestOverrides for ChannelUpgradeICACloseChannel { + fn modify_relayer_config(&self, config: &mut Config) { + config.mode.channels.enabled = true; + + config.mode.clients.misbehaviour = false; + } + + fn modify_genesis_file(&self, genesis: &mut serde_json::Value) -> Result<(), Error> { + set_max_deposit_period(genesis, MAX_DEPOSIT_PERIOD)?; + set_voting_period(genesis, VOTING_PERIOD)?; + + Ok(()) + } + + fn should_spawn_supervisor(&self) -> bool { + false + } +} + +impl BinaryConnectionTest for ChannelUpgradeICACloseChannel { + fn run( + &self, + config: &TestConfig, + relayer: RelayerDriver, + chains: ConnectedChains, + connection: ConnectedConnection, + ) -> Result<(), Error> { + let fee_denom_host: MonoTagged = + MonoTagged::new(Denom::base(config.native_token(1))); + let stake_denom: MonoTagged = MonoTagged::new(Denom::base("stake")); + + // Run the block with supervisor in order to open and then upgrade the ICA channel + let (wallet, ica_address, controller_channel_id, controller_port_id) = relayer + .with_supervisor(|| { + // Register an interchain account on behalf of + // controller wallet `user1` where the counterparty chain is the interchain accounts host. + let (wallet, controller_channel_id, controller_port_id) = + register_ordered_interchain_account( + &chains.node_a, + chains.handle_a(), + &connection, + )?; + + // Check that the corresponding ICA channel is eventually established. + let _counterparty_channel_id = assert_eventually_channel_established( + chains.handle_a(), + chains.handle_b(), + &controller_channel_id.as_ref(), + &controller_port_id.as_ref(), + )?; + + let channel_end_a = chains + .handle_a + .query_channel( + QueryChannelRequest { + port_id: controller_port_id.value().clone(), + channel_id: controller_channel_id.value().clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd A: {e}"))?; + + let host_port_id = channel_end_a.remote.port_id; + let host_channel_id = channel_end_a + .remote + .channel_id + .ok_or_else(|| eyre!("expect to find counterparty channel id"))?; + + let channel_end_b = chains + .handle_b + .query_channel( + QueryChannelRequest { + port_id: host_port_id.clone(), + channel_id: host_channel_id.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd B: {e}"))?; + + let old_ordering = channel_end_a.ordering; + let old_connection_hops_a = channel_end_a.connection_hops; + let old_connection_hops_b = channel_end_b.connection_hops; + + // Query the controller chain for the address of the ICA wallet on the host chain. + let ica_address = chains.node_a.chain_driver().query_interchain_account( + &wallet.address(), + &connection.connection_id_a.as_ref(), + )?; + + chains.node_b.chain_driver().assert_eventual_wallet_amount( + &ica_address.as_ref(), + &stake_denom.with_amount(0u64).as_ref(), + )?; + + let app_version = json::json!({ + "version": ics27_ica::VERSION, + "encoding": "proto3", + "tx_type": "sdk_multi_msg", + "address": ica_address.to_string(), + "controller_connection_id": connection.connection_id_a.0, + "host_connection_id": connection.connection_id_b.0, + }); + let new_version = Version::app_version_with_fee(&app_version.to_string()); + + let upgraded_attrs = ChannelUpgradableAttributes::new( + new_version.clone(), + new_version.clone(), + old_ordering, + old_connection_hops_a.clone(), + old_connection_hops_b.clone(), + Sequence::from(1), + ); + + info!("Will initialise upgrade handshake with governance proposal..."); + + chains.node_a.chain_driver().initialise_channel_upgrade( + controller_port_id.to_string().as_str(), + controller_channel_id.to_string().as_str(), + old_ordering.as_str(), + old_connection_hops_a.first().unwrap().as_str(), + &serde_json::to_string(&new_version.0).unwrap(), + chains.handle_a().get_signer().unwrap().as_ref(), + "1", + )?; + + info!("Check that the channel upgrade successfully upgraded the version..."); + + assert_eventually_channel_upgrade_open( + &chains.handle_a, + &chains.handle_b, + &controller_channel_id.as_ref(), + &controller_port_id.as_ref(), + &upgraded_attrs, + )?; + sleep(Duration::from_secs(5)); + + Ok(( + wallet, + ica_address, + controller_channel_id, + controller_port_id, + )) + })?; + + // Create a pending ICA transfer without supervisor in order to created a timed out + // packet + + // Send funds to the interchain account. + let ica_fund = 42000u64; + + chains.node_b.chain_driver().local_transfer_token( + &chains.node_b.wallets().user1(), + &ica_address.as_ref(), + &stake_denom.with_amount(ica_fund).as_ref(), + &fee_denom_host.with_amount(381000000u64).as_ref(), + )?; + + chains.node_b.chain_driver().assert_eventual_wallet_amount( + &ica_address.as_ref(), + &stake_denom.with_amount(ica_fund).as_ref(), + )?; + + let amount = 12345u64; + + let msg = MsgSend { + from_address: ica_address.to_string(), + to_address: chains.node_b.wallets().user2().address().to_string(), + amount: vec![Coin { + denom: stake_denom.to_string(), + amount: Amount(U256::from(amount)), + }], + }; + + let raw_msg = msg.to_any(); + + let cosmos_tx = CosmosTx { + messages: vec![raw_msg], + }; + + let raw_cosmos_tx = cosmos_tx.to_any(); + + let interchain_account_packet_data = InterchainAccountPacketData::new(raw_cosmos_tx.value); + + let signer = Signer::from_str(&wallet.address().to_string()).unwrap(); + + let balance_user2 = chains.node_b.chain_driver().query_balance( + &chains.node_b.wallets().user2().address(), + &stake_denom.as_ref(), + )?; + sleep(Duration::from_secs(5)); + + interchain_send_tx( + chains.handle_a(), + &signer, + &connection.connection_id_a.0, + interchain_account_packet_data.clone(), + Timestamp::from_nanoseconds(1000000000).unwrap(), + )?; + + sleep(Duration::from_nanos(3000000000)); + + // Start the supervisor which will relay the timed out packet and close the channel + relayer.with_supervisor(|| { + // Check that user2 has not received the sent amount. + chains.node_b.chain_driver().assert_eventual_wallet_amount( + &chains.node_b.wallets().user2().address(), + &(balance_user2).as_ref(), + )?; + sleep(Duration::from_secs(5)); + + // Check that the ICA account's balance has not been debited the sent amount. + chains.node_b.chain_driver().assert_eventual_wallet_amount( + &ica_address.as_ref(), + &stake_denom.with_amount(ica_fund).as_ref(), + )?; + + info!("Check that the channel closed after packet timeout..."); + + assert_eventually_channel_closed( + &chains.handle_a, + &chains.handle_b, + &controller_channel_id.as_ref(), + &controller_port_id.as_ref(), + )?; + + Ok(()) + }) + } +} + +pub struct ChannelUpgradeICAUnordered { + packet_filter: PacketFilter, +} + +impl ChannelUpgradeICAUnordered { + pub fn new(packet_filter: PacketFilter) -> Self { + Self { packet_filter } + } +} + +impl TestOverrides for ChannelUpgradeICAUnordered { + fn modify_relayer_config(&self, config: &mut Config) { + config.mode.channels.enabled = true; + + config.mode.clients.misbehaviour = false; + + for chain in &mut config.chains { + match chain { + ChainConfig::CosmosSdk(chain_config) => { + chain_config.packet_filter = self.packet_filter.clone(); + } + } + } + } + + fn modify_genesis_file(&self, genesis: &mut serde_json::Value) -> Result<(), Error> { + add_allow_message_interchainaccounts(genesis, "/cosmos.bank.v1beta1.MsgSend")?; + set_max_deposit_period(genesis, MAX_DEPOSIT_PERIOD)?; + set_voting_period(genesis, VOTING_PERIOD)?; + + Ok(()) + } + + fn should_spawn_supervisor(&self) -> bool { + true + } +} + +impl BinaryConnectionTest for ChannelUpgradeICAUnordered { + fn run( + &self, + config: &TestConfig, + _relayer: RelayerDriver, + chains: ConnectedChains, + connection: ConnectedConnection, + ) -> Result<(), Error> { + let fee_denom_host: MonoTagged = + MonoTagged::new(Denom::base(config.native_token(1))); + let stake_denom: MonoTagged = MonoTagged::new(Denom::base("stake")); + + info!("Will register interchain account..."); + + // Register an interchain account on behalf of + // controller wallet `user1` where the counterparty chain is the interchain accounts host. + let (wallet, controller_channel_id, controller_port_id) = + register_ordered_interchain_account(&chains.node_a, chains.handle_a(), &connection)?; + + // Check that the corresponding ICA channel is eventually established. + let _counterparty_channel_id = assert_eventually_channel_established( + chains.handle_a(), + chains.handle_b(), + &controller_channel_id.as_ref(), + &controller_port_id.as_ref(), + )?; + + // Query the controller chain for the address of the ICA wallet on the host chain. + let ica_address = chains + .node_a + .chain_driver() + .query_interchain_account(&wallet.address(), &connection.connection_id_a.as_ref())?; + + chains.node_b.chain_driver().assert_eventual_wallet_amount( + &ica_address.as_ref(), + &stake_denom.with_amount(0u64).as_ref(), + )?; + + info!("Will send a message to the interchain account..."); + + // Send funds to the interchain account. + let ica_fund = 42000u64; + + chains.node_b.chain_driver().local_transfer_token( + &chains.node_b.wallets().user1(), + &ica_address.as_ref(), + &stake_denom.with_amount(ica_fund).as_ref(), + &fee_denom_host.with_amount(381000000u64).as_ref(), + )?; + + chains.node_b.chain_driver().assert_eventual_wallet_amount( + &ica_address.as_ref(), + &stake_denom.with_amount(ica_fund).as_ref(), + )?; + + let amount = 12345u64; + + let msg = MsgSend { + from_address: ica_address.to_string(), + to_address: chains.node_b.wallets().user2().address().to_string(), + amount: vec![Coin { + denom: stake_denom.to_string(), + amount: Amount(U256::from(amount)), + }], + }; + + let raw_msg = msg.to_any(); + + let cosmos_tx = CosmosTx { + messages: vec![raw_msg], + }; + + let raw_cosmos_tx = cosmos_tx.to_any(); + + let interchain_account_packet_data = InterchainAccountPacketData::new(raw_cosmos_tx.value); + + let signer = Signer::from_str(&wallet.address().to_string()).unwrap(); + + interchain_send_tx( + chains.handle_a(), + &signer, + &connection.connection_id_a.0, + interchain_account_packet_data.clone(), + Timestamp::from_nanoseconds(10000000000).unwrap(), + )?; + + // Check that the ICA account's balance has been debited the sent amount. + chains.node_b.chain_driver().assert_eventual_wallet_amount( + &ica_address.as_ref(), + &stake_denom.with_amount(ica_fund - amount).as_ref(), + )?; + + let channel_end_a = chains + .handle_a + .query_channel( + QueryChannelRequest { + port_id: controller_port_id.value().clone(), + channel_id: controller_channel_id.value().clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd A: {e}"))?; + + let host_port_id = channel_end_a.remote.port_id; + let host_channel_id = channel_end_a + .remote + .channel_id + .ok_or_else(|| eyre!("expect to find counterparty channel id"))?; + + let channel_end_b = chains + .handle_b + .query_channel( + QueryChannelRequest { + port_id: host_port_id.clone(), + channel_id: host_channel_id.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd B: {e}"))?; + + let old_version_a = channel_end_a.version; + let old_version_b = channel_end_b.version; + let old_connection_hops_a = channel_end_a.connection_hops; + let old_connection_hops_b = channel_end_b.connection_hops; + + let new_ordering = Ordering::Unordered; + + let upgraded_attrs = ChannelUpgradableAttributes::new( + old_version_a.clone(), + old_version_b.clone(), + new_ordering, + old_connection_hops_a.clone(), + old_connection_hops_b.clone(), + Sequence::from(1), + ); + + info!("Will initialise upgrade handshake with governance proposal..."); + + chains.node_a.chain_driver().initialise_channel_upgrade( + controller_port_id.to_string().as_str(), + controller_channel_id.to_string().as_str(), + new_ordering.as_str(), + old_connection_hops_a.first().unwrap().as_str(), + &serde_json::to_string(&old_version_a.0).unwrap(), + &chains.node_a.wallets().user2().address().to_string(), + "1", + )?; + + info!("Check that the channel upgrade successfully upgraded the ordering..."); + + assert_eventually_channel_upgrade_open( + &chains.handle_a, + &chains.handle_b, + &controller_channel_id.as_ref(), + &controller_port_id.as_ref(), + &upgraded_attrs, + )?; + sleep(Duration::from_secs(5)); + + Ok(()) + } +} + +fn interchain_send_tx( + chain: &ChainA, + from: &Signer, + connection: &ConnectionId, + msg: InterchainAccountPacketData, + relative_timeout: Timestamp, +) -> Result, Error> { + let msg = MsgSendTx { + owner: from.clone(), + connection_id: connection.clone(), + packet_data: msg, + relative_timeout, + }; + + let msg_any = msg.to_any(); + + let tm = TrackedMsgs::new_static(vec![msg_any], "SendTx"); + + chain + .send_messages_and_wait_commit(tm) + .map_err(Error::relayer) +} diff --git a/tools/integration-test/src/tests/channel_upgrade/ics29.rs b/tools/integration-test/src/tests/channel_upgrade/ics29.rs new file mode 100644 index 0000000000..02f90b2745 --- /dev/null +++ b/tools/integration-test/src/tests/channel_upgrade/ics29.rs @@ -0,0 +1,227 @@ +//! Tests channel upgrade features: +//! +//! - `ChannelUpgradeICS29` tests that only after the upgrade handshake is completed +//! and the channel version has been updated to ICS29 can Incentivized packets be +//! relayed. + +use ibc_relayer::chain::requests::{IncludeProof, QueryChannelRequest, QueryHeight}; +use ibc_relayer_types::core::ics04_channel::packet::Sequence; +use ibc_relayer_types::core::ics04_channel::version::Version; +use ibc_test_framework::chain::config::{set_max_deposit_period, set_voting_period}; +use ibc_test_framework::prelude::*; +use ibc_test_framework::relayer::channel::{ + assert_eventually_channel_established, assert_eventually_channel_upgrade_open, + ChannelUpgradableAttributes, +}; +use ibc_test_framework::util::random::random_u128_range; + +#[test] +fn test_channel_upgrade_ics29() -> Result<(), Error> { + run_binary_channel_test(&ChannelUpgradeICS29) +} + +const MAX_DEPOSIT_PERIOD: &str = "10s"; +const VOTING_PERIOD: u64 = 10; + +pub struct ChannelUpgradeICS29; + +impl TestOverrides for ChannelUpgradeICS29 { + fn modify_relayer_config(&self, config: &mut Config) { + config.mode.channels.enabled = true; + config.mode.packets.auto_register_counterparty_payee = true; + config.mode.packets.clear_interval = 0; + config.mode.packets.clear_on_start = false; + + config.mode.clients.misbehaviour = false; + } + + fn modify_genesis_file(&self, genesis: &mut serde_json::Value) -> Result<(), Error> { + set_max_deposit_period(genesis, MAX_DEPOSIT_PERIOD)?; + set_voting_period(genesis, VOTING_PERIOD)?; + Ok(()) + } +} + +impl BinaryChannelTest for ChannelUpgradeICS29 { + fn run( + &self, + _config: &TestConfig, + _relayer: RelayerDriver, + chains: ConnectedChains, + channels: ConnectedChannel, + ) -> Result<(), Error> { + info!("Check that channels are both in OPEN State"); + + assert_eventually_channel_established( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + )?; + + let channel_end_a = chains + .handle_a + .query_channel( + QueryChannelRequest { + port_id: channels.port_a.0.clone(), + channel_id: channels.channel_id_a.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd A: {e}"))?; + + let channel_end_b = chains + .handle_b + .query_channel( + QueryChannelRequest { + port_id: channels.port_b.0.clone(), + channel_id: channels.channel_id_b.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd B: {e}"))?; + + let chain_driver_a = chains.node_a.chain_driver(); + let chain_driver_b = chains.node_b.chain_driver(); + + let denom_a = chains.node_a.denom(); + + let port_a = channels.port_a.as_ref(); + let channel_id_a = channels.channel_id_a.as_ref(); + + let wallets_a = chains.node_a.wallets(); + let wallets_b = chains.node_b.wallets(); + + let relayer_a = wallets_a.relayer(); + + let user_a = wallets_a.user1(); + let user_b = wallets_b.user1(); + + let balance_a1 = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; + + let relayer_balance_a = chain_driver_a.query_balance(&relayer_a.address(), &denom_a)?; + + let send_amount = random_u128_range(1000, 2000); + let receive_fee = random_u128_range(300, 400); + let ack_fee = random_u128_range(200, 300); + let timeout_fee = random_u128_range(100, 200); + + let total_sent = send_amount + receive_fee + ack_fee + timeout_fee; + + let balance_a2 = balance_a1 - total_sent; + + let ics29_transfer = chain_driver_a.ibc_token_transfer_with_fee( + &port_a, + &channel_id_a, + &user_a, + &user_b.address(), + &denom_a.with_amount(send_amount).as_ref(), + &denom_a.with_amount(receive_fee).as_ref(), + &denom_a.with_amount(ack_fee).as_ref(), + &denom_a.with_amount(timeout_fee).as_ref(), + Duration::from_secs(60), + ); + + assert!(ics29_transfer.is_err(), "{ics29_transfer:?}"); + + let old_ordering = channel_end_a.ordering; + let old_connection_hops_a = channel_end_a.connection_hops; + let old_connection_hops_b = channel_end_b.connection_hops; + + let channel = channels.channel; + let new_version = Version::ics20_with_fee(); + + let upgraded_attrs = ChannelUpgradableAttributes::new( + new_version.clone(), + new_version.clone(), + old_ordering, + old_connection_hops_a.clone(), + old_connection_hops_b, + Sequence::from(1), + ); + + info!("Will initialise upgrade handshake with governance proposal..."); + + chains.node_a.chain_driver().initialise_channel_upgrade( + channel.src_port_id().as_str(), + channel.src_channel_id().unwrap().as_str(), + old_ordering.as_str(), + old_connection_hops_a.first().unwrap().as_str(), + &serde_json::to_string(&new_version.0).unwrap(), + chains.handle_a().get_signer().unwrap().as_ref(), + "1", + )?; + + info!("Check that the channel upgrade successfully upgraded the version..."); + + assert_eventually_channel_upgrade_open( + &chains.handle_a, + &chains.handle_b, + &channels.channel_id_a.as_ref(), + &channels.port_a.as_ref(), + &upgraded_attrs, + )?; + + // Since the channel has been updated to ICS29 version after the Hermes instance + // was started, the `auto_register_counterparty_payee` has not registered the + // counterparty payee. It is required to register it manually. + chain_driver_b.register_counterparty_payee( + &wallets_b.relayer(), + &relayer_a.address(), + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + )?; + + { + let counterparty_payee = chain_driver_b.query_counterparty_payee( + &channels.channel_id_b.as_ref(), + &wallets_b.relayer().address(), + )?; + + assert_eq( + "counterparty address should match registered address", + &counterparty_payee, + &Some(relayer_a.address().cloned()), + )?; + } + + chain_driver_a.ibc_token_transfer_with_fee( + &port_a, + &channel_id_a, + &user_a, + &user_b.address(), + &denom_a.with_amount(send_amount).as_ref(), + &denom_a.with_amount(receive_fee).as_ref(), + &denom_a.with_amount(ack_fee).as_ref(), + &denom_a.with_amount(timeout_fee).as_ref(), + Duration::from_secs(60), + )?; + + let denom_b = derive_ibc_denom( + &channels.port_b.as_ref(), + &channels.channel_id_b.as_ref(), + &denom_a, + )?; + + chain_driver_b.assert_eventual_wallet_amount( + &user_b.address(), + &denom_b.with_amount(send_amount).as_ref(), + )?; + + chain_driver_a.assert_eventual_wallet_amount( + &user_a.address(), + &(balance_a2 + timeout_fee).as_ref(), + )?; + + chain_driver_a.assert_eventual_wallet_amount( + &relayer_a.address(), + &(relayer_balance_a + ack_fee + receive_fee).as_ref(), + )?; + + Ok(()) + } +} diff --git a/tools/integration-test/src/tests/channel_upgrade/mod.rs b/tools/integration-test/src/tests/channel_upgrade/mod.rs new file mode 100644 index 0000000000..2e40d3bd5e --- /dev/null +++ b/tools/integration-test/src/tests/channel_upgrade/mod.rs @@ -0,0 +1,6 @@ +pub mod flushing; +pub mod ica; +pub mod ics29; +pub mod timeout; +pub mod upgrade_handshake; +pub mod upgrade_handshake_steps; diff --git a/tools/integration-test/src/tests/channel_upgrade/timeout.rs b/tools/integration-test/src/tests/channel_upgrade/timeout.rs new file mode 100644 index 0000000000..42bdd288ed --- /dev/null +++ b/tools/integration-test/src/tests/channel_upgrade/timeout.rs @@ -0,0 +1,1067 @@ +//! Tests channel upgrade: +//! +//! - `ChannelUpgradeTimeoutAckHandshake` tests that the channel worker will timeout the +//! upgrade handshake if too much time passes before relaying the Upgrade Ack. +//! +//! - `ChannelUpgradeTimeoutConfirmHandshake` tests that the channel worker will timeout the +//! upgrade handshake if too much time passes before relaying the Upgrade Confirm. +//! +//! - `ChannelUpgradeManualTimeoutWhenFlushingHandshake` tests that the channel upgrade can be timed out +//! and cancelled if the packets take too much time to be flushed. +//! +//! - `ChannelUpgradeHandshakeTimeoutWhenFlushing` tests that the channel worker will timeout the +//! upgrade handshake if the counterparty does not finish flushing the packets before the upgrade timeout. +//! +//! - `ChannelUpgradeHandshakeTimeoutOnAck` tests that the channel worker will cancel the +//! upgrade handshake if the Ack step fails due to an upgrade timeout. +//! +//! - `ChannelUpgradeHandshakeTimeoutOnPacketAck` tests that the channel worker will cancel the +//! upgrade handshake if the chain acknowledges a packet after the upgrade timeout expired. +//! +//! +//! +use std::thread::sleep; + +use ibc_relayer::chain::requests::{IncludeProof, QueryChannelRequest, QueryHeight}; +use ibc_relayer_types::core::ics04_channel::channel::State as ChannelState; +use ibc_relayer_types::core::ics04_channel::packet::Sequence; +use ibc_relayer_types::core::ics04_channel::version::Version; +use ibc_relayer_types::events::IbcEventType; +use ibc_test_framework::chain::config::{set_max_deposit_period, set_voting_period}; +use ibc_test_framework::prelude::*; +use ibc_test_framework::relayer::channel::{ + assert_eventually_channel_established, assert_eventually_channel_upgrade_ack, + assert_eventually_channel_upgrade_cancel, assert_eventually_channel_upgrade_flushing, + assert_eventually_channel_upgrade_init, assert_eventually_channel_upgrade_try, + ChannelUpgradableAttributes, +}; + +#[test] +fn test_channel_upgrade_timeout_ack_handshake() -> Result<(), Error> { + run_binary_channel_test(&ChannelUpgradeTimeoutAckHandshake) +} + +#[test] +fn test_channel_upgrade_timeout_confirm_handshake() -> Result<(), Error> { + run_binary_channel_test(&ChannelUpgradeTimeoutConfirmHandshake) +} + +#[test] +fn test_channel_upgrade_manual_timeout_when_flushing() -> Result<(), Error> { + run_binary_channel_test(&ChannelUpgradeManualTimeoutWhenFlushing) +} + +#[test] +fn test_channel_upgrade_handshake_timeout_when_flushing() -> Result<(), Error> { + run_binary_channel_test(&ChannelUpgradeHandshakeTimeoutWhenFlushing) +} + +#[test] +fn test_channel_upgrade_handshake_timeout_on_ack() -> Result<(), Error> { + run_binary_channel_test(&ChannelUpgradeHandshakeTimeoutOnAck) +} + +#[test] +fn test_channel_upgrade_handshake_timeout_on_packet_ack() -> Result<(), Error> { + run_binary_channel_test(&ChannelUpgradeHandshakeTimeoutOnPacketAck) +} + +const MAX_DEPOSIT_PERIOD: &str = "10s"; +const VOTING_PERIOD: u64 = 10; + +struct ChannelUpgradeTestOverrides; + +impl TestOverrides for ChannelUpgradeTestOverrides { + fn modify_genesis_file(&self, genesis: &mut serde_json::Value) -> Result<(), Error> { + set_max_deposit_period(genesis, MAX_DEPOSIT_PERIOD)?; + set_voting_period(genesis, VOTING_PERIOD)?; + Ok(()) + } + + fn modify_relayer_config(&self, config: &mut Config) { + config.mode.channels.enabled = true; + + config.mode.clients.misbehaviour = false; + } + + fn should_spawn_supervisor(&self) -> bool { + false + } +} + +struct ChannelUpgradeTimeoutAckHandshake; + +impl BinaryChannelTest for ChannelUpgradeTimeoutAckHandshake { + fn run( + &self, + _config: &TestConfig, + relayer: RelayerDriver, + chains: ConnectedChains, + channels: ConnectedChannel, + ) -> Result<(), Error> { + info!("Check that channels are both in OPEN State"); + + assert_eventually_channel_established( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + )?; + + let channel_end_a = chains + .handle_a + .query_channel( + QueryChannelRequest { + port_id: channels.port_a.0.clone(), + channel_id: channels.channel_id_a.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd A: {e}"))?; + + let channel_end_b = chains + .handle_b + .query_channel( + QueryChannelRequest { + port_id: channels.port_b.0.clone(), + channel_id: channels.channel_id_b.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd B: {e}"))?; + + let old_version = channel_end_a.version; + let old_ordering = channel_end_a.ordering; + let old_connection_hops_a = channel_end_a.connection_hops; + let old_connection_hops_b = channel_end_b.connection_hops; + + let channel = channels.channel; + let new_version = Version::ics20_with_fee(); + + let old_attrs = ChannelUpgradableAttributes::new( + old_version.clone(), + old_version.clone(), + old_ordering, + old_connection_hops_a.clone(), + old_connection_hops_b.clone(), + Sequence::from(1), + ); + + info!("Will update channel params to set a short upgrade timeout..."); + + chains.node_b.chain_driver().update_channel_params( + 5000000000, + chains.handle_b().get_signer().unwrap().as_ref(), + "1", + )?; + + info!("Will initialise upgrade handshake with governance proposal..."); + + chains.node_a.chain_driver().initialise_channel_upgrade( + channel.src_port_id().as_str(), + channel.src_channel_id().unwrap().as_str(), + old_ordering.as_str(), + old_connection_hops_a.first().unwrap().as_str(), + &serde_json::to_string(&new_version.0).unwrap(), + chains.handle_a().get_signer().unwrap().as_ref(), + "1", + )?; + + info!("Will run ChanUpgradeTry step..."); + + channel.build_chan_upgrade_try_and_send()?; + + info!("Check that the step ChanUpgradeTry was correctly executed..."); + + assert_eventually_channel_upgrade_try( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + &old_attrs.flipped(), + )?; + + std::thread::sleep(Duration::from_secs(10)); + + info!("Check that the channel upgrade was successfully cancelled..."); + + // This will assert that both channel ends are eventually + // in Open state, and that the fields have not changed. + relayer.with_supervisor(|| { + assert_eventually_channel_upgrade_cancel( + &chains.handle_a, + &chains.handle_b, + &channels.channel_id_a.as_ref(), + &channels.port_a.as_ref(), + &old_attrs, + )?; + + Ok(()) + }) + } +} + +struct ChannelUpgradeTimeoutConfirmHandshake; + +impl BinaryChannelTest for ChannelUpgradeTimeoutConfirmHandshake { + fn run( + &self, + _config: &TestConfig, + relayer: RelayerDriver, + chains: ConnectedChains, + channels: ConnectedChannel, + ) -> Result<(), Error> { + info!("Check that channels are both in OPEN State"); + + assert_eventually_channel_established( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + )?; + + let channel_end_a = chains + .handle_a + .query_channel( + QueryChannelRequest { + port_id: channels.port_a.0.clone(), + channel_id: channels.channel_id_a.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd A: {e}"))?; + + let channel_end_b = chains + .handle_b + .query_channel( + QueryChannelRequest { + port_id: channels.port_b.0.clone(), + channel_id: channels.channel_id_b.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd B: {e}"))?; + + let old_version = channel_end_a.version; + let old_ordering = channel_end_a.ordering; + let old_connection_hops_a = channel_end_a.connection_hops; + let old_connection_hops_b = channel_end_b.connection_hops; + + let channel = channels.channel; + let new_version = Version::ics20_with_fee(); + + let old_attrs = ChannelUpgradableAttributes::new( + old_version.clone(), + old_version.clone(), + old_ordering, + old_connection_hops_a.clone(), + old_connection_hops_b.clone(), + Sequence::from(1), + ); + + info!("Will update channel params to set a short upgrade timeout..."); + + chains.node_a.chain_driver().update_channel_params( + 5000000000, + chains.handle_a().get_signer().unwrap().as_ref(), + "1", + )?; + + info!("Will initialise upgrade handshake with governance proposal..."); + + chains.node_a.chain_driver().initialise_channel_upgrade( + channel.src_port_id().as_str(), + channel.src_channel_id().unwrap().as_str(), + old_ordering.as_str(), + old_connection_hops_a.first().unwrap().as_str(), + &serde_json::to_string(&new_version.0).unwrap(), + chains.handle_a().get_signer().unwrap().as_ref(), + "2", + )?; + + info!("Will run ChanUpgradeTry step..."); + + channel.build_chan_upgrade_try_and_send()?; + + info!("Check that the step ChanUpgradeTry was correctly executed..."); + + assert_eventually_channel_upgrade_try( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + &old_attrs.flipped(), + )?; + + info!("Will run ChanUpgradeAck step..."); + + channel.flipped().build_chan_upgrade_ack_and_send()?; + + info!("Check that the step ChanUpgradeAck was correctly executed..."); + + assert_eventually_channel_upgrade_ack( + &chains.handle_a, + &chains.handle_b, + &channels.channel_id_a.as_ref(), + &channels.port_a.as_ref(), + ChannelState::FlushComplete, + ChannelState::Flushing, + &old_attrs, + )?; + + std::thread::sleep(Duration::from_secs(10)); + + info!("Check that the channel upgrade was successfully cancelled..."); + + // This will assert that both channel ends are eventually + // in Open state, and that the fields have not changed. + relayer.with_supervisor(|| { + assert_eventually_channel_upgrade_cancel( + &chains.handle_a, + &chains.handle_b, + &channels.channel_id_a.as_ref(), + &channels.port_a.as_ref(), + &old_attrs, + )?; + + Ok(()) + }) + } +} + +struct ChannelUpgradeHandshakeTimeoutWhenFlushing; + +impl BinaryChannelTest for ChannelUpgradeHandshakeTimeoutWhenFlushing { + fn run( + &self, + _config: &TestConfig, + relayer: RelayerDriver, + chains: ConnectedChains, + channels: ConnectedChannel, + ) -> Result<(), Error> { + info!("Check that channels are both in OPEN State"); + + assert_eventually_channel_established( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + )?; + + let channel_end_a = chains + .handle_a + .query_channel( + QueryChannelRequest { + port_id: channels.port_a.0.clone(), + channel_id: channels.channel_id_a.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd A: {e}"))?; + + let channel_end_b = chains + .handle_b + .query_channel( + QueryChannelRequest { + port_id: channels.port_b.0.clone(), + channel_id: channels.channel_id_b.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd B: {e}"))?; + + let old_version = channel_end_a.version; + let old_ordering = channel_end_a.ordering; + let old_connection_hops_a = channel_end_a.connection_hops; + let old_connection_hops_b = channel_end_b.connection_hops; + + let channel = channels.channel; + let new_version = Version::ics20_with_fee(); + + let old_attrs = ChannelUpgradableAttributes::new( + old_version.clone(), + old_version.clone(), + old_ordering, + old_connection_hops_a.clone(), + old_connection_hops_b.clone(), + Sequence::from(1), + ); + + info!("Will update channel params to set a shorter upgrade timeout..."); + + // the upgrade timeout should be long enough for chain a + // to complete Ack successfully so that it goes into `FLUSHING` + chains.node_b.chain_driver().update_channel_params( + 25000000000, + chains.handle_b().get_signer().unwrap().as_ref(), + "1", + )?; + + info!("Will initialise upgrade handshake with governance proposal..."); + + chains.node_a.chain_driver().initialise_channel_upgrade( + channel.src_port_id().as_str(), + channel.src_channel_id().unwrap().as_str(), + old_ordering.as_str(), + old_connection_hops_a.first().unwrap().as_str(), + &serde_json::to_string(&new_version.0).unwrap(), + chains.handle_a().get_signer().unwrap().as_ref(), + "1", + )?; + + info!("Will run ChanUpgradeTry step..."); + + channel.build_chan_upgrade_try_and_send()?; + + info!("Check that the step ChanUpgradeTry was correctly executed..."); + + assert_eventually_channel_upgrade_try( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + &old_attrs.flipped(), + )?; + + // send a IBC transfer message from chain a to chain b + // so that we have an in-flight packet and chain a + // will move to `FLUSHING` during Ack + let denom_a = chains.node_a.denom(); + let wallet_a = chains.node_a.wallets().user1().cloned(); + let wallet_b = chains.node_b.wallets().user1().cloned(); + let a_to_b_amount = 12345u64; + + info!( + "Sending IBC transfer from chain {} to chain {} with amount of {} {}", + chains.chain_id_a(), + chains.chain_id_b(), + a_to_b_amount, + denom_a + ); + + chains.node_a.chain_driver().ibc_transfer_token( + &channels.port_a.as_ref(), + &channels.channel_id_a.as_ref(), + &wallet_a.as_ref(), + &wallet_b.address(), + &denom_a.with_amount(a_to_b_amount).as_ref(), + )?; + + info!("Will run ChanUpgradeAck step..."); + + channel.flipped().build_chan_upgrade_ack_and_send()?; + + info!("Check that the step ChanUpgradeAck was correctly executed..."); + + assert_eventually_channel_upgrade_flushing( + &chains.handle_a, + &chains.handle_b, + &channels.channel_id_a.as_ref(), + &channels.port_a.as_ref(), + &old_attrs, + )?; + + // wait enough time so that timeout expires while chain a is in FLUSHING + sleep(Duration::from_nanos(35000000000)); + + info!("Will run ChanUpgradeTimeout step..."); + + // Since the chain a has not moved to `FLUSH_COMPLETE` before the upgrade timeout + // expired, then we can submit `MsgChannelUpgradeTimeout` on chain b + // to cancel the upgrade and move the channel back to `OPEN` + let timeout_event = channel.build_chan_upgrade_timeout_and_send()?; + assert_eq!( + timeout_event.event_type(), + IbcEventType::UpgradeTimeoutChannel + ); + + relayer.with_supervisor(|| { + info!("Check that the step ChanUpgradeTimeout was correctly executed..."); + + assert_eventually_channel_upgrade_cancel( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + &old_attrs.flipped(), + )?; + + Ok(()) + }) + } +} + +struct ChannelUpgradeManualTimeoutWhenFlushing; + +impl BinaryChannelTest for ChannelUpgradeManualTimeoutWhenFlushing { + fn run( + &self, + _config: &TestConfig, + _relayer: RelayerDriver, + chains: ConnectedChains, + channels: ConnectedChannel, + ) -> Result<(), Error> { + info!("Check that channels are both in OPEN State"); + + assert_eventually_channel_established( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + )?; + + let channel_end_a = chains + .handle_a + .query_channel( + QueryChannelRequest { + port_id: channels.port_a.0.clone(), + channel_id: channels.channel_id_a.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd A: {e}"))?; + + let channel_end_b = chains + .handle_b + .query_channel( + QueryChannelRequest { + port_id: channels.port_b.0.clone(), + channel_id: channels.channel_id_b.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd B: {e}"))?; + + let old_version = channel_end_a.version; + let old_ordering = channel_end_a.ordering; + let old_connection_hops_a = channel_end_a.connection_hops; + let old_connection_hops_b = channel_end_b.connection_hops; + + let channel = channels.channel; + let new_version = Version::ics20_with_fee(); + + let old_attrs = ChannelUpgradableAttributes::new( + old_version.clone(), + old_version.clone(), + old_ordering, + old_connection_hops_a.clone(), + old_connection_hops_b.clone(), + Sequence::from(1), + ); + + info!("Will update channel params to set a shorter upgrade timeout..."); + + // the upgrade timeout should be long enough for chain a + // to complete Ack successfully so that it goes into `FLUSHING` + chains.node_b.chain_driver().update_channel_params( + 25000000000, + chains.handle_b().get_signer().unwrap().as_ref(), + "1", + )?; + + info!("Will initialise upgrade handshake with governance proposal..."); + + chains.node_a.chain_driver().initialise_channel_upgrade( + channel.src_port_id().as_str(), + channel.src_channel_id().unwrap().as_str(), + old_ordering.as_str(), + old_connection_hops_a.first().unwrap().as_str(), + &serde_json::to_string(&new_version.0).unwrap(), + chains.handle_a().get_signer().unwrap().as_ref(), + "1", + )?; + + info!("Check that the step ChanUpgradeInit was correctly executed..."); + + assert_eventually_channel_upgrade_init( + &chains.handle_a, + &chains.handle_b, + &channels.channel_id_a.as_ref(), + &channels.port_a.as_ref(), + &old_attrs, + )?; + + info!("Will run ChanUpgradeTry step..."); + + channel.build_chan_upgrade_try_and_send()?; + + info!("Check that the step ChanUpgradeTry was correctly executed..."); + + assert_eventually_channel_upgrade_try( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + &old_attrs.flipped(), + )?; + + // send a IBC transfer message from chain a to chain b + // so that we have an in-flight packet and chain a + // will move to `FLUSHING` during Ack + let denom_a = chains.node_a.denom(); + let wallet_a = chains.node_a.wallets().user1().cloned(); + let wallet_b = chains.node_b.wallets().user1().cloned(); + let a_to_b_amount = 12345u128; + + info!( + "Sending IBC transfer from chain {} to chain {} with amount of {} {}", + chains.chain_id_a(), + chains.chain_id_b(), + a_to_b_amount, + denom_a + ); + + chains.node_a.chain_driver().ibc_transfer_token( + &channels.port_a.as_ref(), + &channels.channel_id_a.as_ref(), + &wallet_a.as_ref(), + &wallet_b.address(), + &denom_a.with_amount(a_to_b_amount).as_ref(), + )?; + + info!("Will run ChanUpgradeAck step..."); + + channel.flipped().build_chan_upgrade_ack_and_send()?; + + info!("Check that the step ChanUpgradeAck was correctly executed..."); + + assert_eventually_channel_upgrade_flushing( + &chains.handle_a, + &chains.handle_b, + &channels.channel_id_a.as_ref(), + &channels.port_a.as_ref(), + &old_attrs, + )?; + + // wait enough time so that timeout expires while chain a is in FLUSHING + sleep(Duration::from_nanos(35000000000)); + + info!("Will run ChanUpgradeTimeout step..."); + + // Since the chain a has not moved to `FLUSH_COMPLETE` before the upgrade timeout + // expired, then we can submit `MsgChannelUpgradeTimeout` on chain b + // to cancel the upgrade and move the channel back to `OPEN` + let timeout_event = channel.build_chan_upgrade_timeout_and_send()?; + assert_eq!( + timeout_event.event_type(), + IbcEventType::UpgradeTimeoutChannel + ); + + let cancel_event = channel.flipped().build_chan_upgrade_cancel_and_send()?; + assert_eq!( + cancel_event.event_type(), + IbcEventType::UpgradeCancelChannel + ); + + info!("Check that the step ChanUpgradeTimeout was correctly executed..."); + + assert_eventually_channel_upgrade_cancel( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + &old_attrs.flipped(), + )?; + + Ok(()) + } +} + +struct ChannelUpgradeHandshakeTimeoutOnAck; + +impl BinaryChannelTest for ChannelUpgradeHandshakeTimeoutOnAck { + fn run( + &self, + _config: &TestConfig, + _relayer: RelayerDriver, + chains: ConnectedChains, + channels: ConnectedChannel, + ) -> Result<(), Error> { + info!("Check that channels are both in OPEN State"); + + assert_eventually_channel_established( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + )?; + + let channel_end_a = chains + .handle_a + .query_channel( + QueryChannelRequest { + port_id: channels.port_a.0.clone(), + channel_id: channels.channel_id_a.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd A: {e}"))?; + + let channel_end_b = chains + .handle_b + .query_channel( + QueryChannelRequest { + port_id: channels.port_b.0.clone(), + channel_id: channels.channel_id_b.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd B: {e}"))?; + + let old_version = channel_end_a.version; + let old_ordering = channel_end_a.ordering; + let old_connection_hops_a = channel_end_a.connection_hops; + let old_connection_hops_b = channel_end_b.connection_hops; + + let channel = channels.channel; + let new_version = Version::ics20_with_fee(); + + let old_attrs = ChannelUpgradableAttributes::new( + old_version.clone(), + old_version.clone(), + old_ordering, + old_connection_hops_a.clone(), + old_connection_hops_b.clone(), + Sequence::from(1), + ); + + info!("Will update channel params to set a short upgrade timeout..."); + + chains.node_b.chain_driver().update_channel_params( + 5000000000, + chains.handle_b().get_signer().unwrap().as_ref(), + "1", + )?; + + info!("Will initialise upgrade handshake with governance proposal..."); + + chains.node_a.chain_driver().initialise_channel_upgrade( + channel.src_port_id().as_str(), + channel.src_channel_id().unwrap().as_str(), + old_ordering.as_str(), + old_connection_hops_a.first().unwrap().as_str(), + &serde_json::to_string(&new_version.0).unwrap(), + chains.handle_a().get_signer().unwrap().as_ref(), + "1", + )?; + + info!("Check that the step ChanUpgradeInit was correctly executed..."); + + assert_eventually_channel_upgrade_init( + &chains.handle_a, + &chains.handle_b, + &channels.channel_id_a.as_ref(), + &channels.port_a.as_ref(), + &old_attrs, + )?; + + info!("Will run ChanUpgradeTry step..."); + + channel.build_chan_upgrade_try_and_send()?; + + info!("Check that the step ChanUpgradeTry was correctly executed..."); + + assert_eventually_channel_upgrade_try( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + &old_attrs.flipped(), + )?; + + // wait enough time so that ACK fails due to upgrade timeout + sleep(Duration::from_secs(10)); + + info!("Will run ChanUpgradeAck step..."); + + let ack_event = channel.flipped().build_chan_upgrade_ack_and_send()?; + + info!("Check that the step ChanUpgradeAck timed out..."); + + // ACK should fail because the upgrade has timed out + assert_eq!(ack_event.event_type(), IbcEventType::UpgradeErrorChannel); + + info!("Will run ChanUpgradeCancel step..."); + + // Since the following assertion checks that the fields of channel ends + // have not been updated, asserting there is a `UpgradeCancelChannel` event + // avoids having a passing test due to the Upgrade Init step failing + let cancel_event = channel.build_chan_upgrade_cancel_and_send()?; + assert_eq!( + cancel_event.event_type(), + IbcEventType::UpgradeCancelChannel + ); + + info!("Check that the step ChanUpgradeCancel was correctly executed..."); + + assert_eventually_channel_upgrade_cancel( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + &old_attrs.flipped(), + )?; + + Ok(()) + } +} + +struct ChannelUpgradeHandshakeTimeoutOnPacketAck; + +impl BinaryChannelTest for ChannelUpgradeHandshakeTimeoutOnPacketAck { + fn run( + &self, + _config: &TestConfig, + relayer: RelayerDriver, + chains: ConnectedChains, + channels: ConnectedChannel, + ) -> Result<(), Error> { + info!("Check that channels are both in OPEN State"); + + assert_eventually_channel_established( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + )?; + + let channel_end_a = chains + .handle_a + .query_channel( + QueryChannelRequest { + port_id: channels.port_a.0.clone(), + channel_id: channels.channel_id_a.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd A: {e}"))?; + + let channel_end_b = chains + .handle_b + .query_channel( + QueryChannelRequest { + port_id: channels.port_b.0.clone(), + channel_id: channels.channel_id_b.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd B: {e}"))?; + + let old_version = channel_end_a.version; + let old_ordering = channel_end_a.ordering; + let old_connection_hops_a = channel_end_a.connection_hops; + let old_connection_hops_b = channel_end_b.connection_hops; + + let channel = channels.channel; + let new_version = Version::ics20_with_fee(); + + let old_attrs = ChannelUpgradableAttributes::new( + old_version.clone(), + old_version.clone(), + old_ordering, + old_connection_hops_a.clone(), + old_connection_hops_b.clone(), + Sequence::from(1), + ); + + info!("Will update channel params to set a short upgrade timeout..."); + + // the upgrade timeout should be long enough for chain a + // to complete Ack successfully so that it goes into `FLUSHING` + chains.node_b.chain_driver().update_channel_params( + 80000000000, + chains.handle_b().get_signer().unwrap().as_ref(), + "1", + )?; + + info!("Will initialise upgrade handshake with governance proposal..."); + + chains.node_a.chain_driver().initialise_channel_upgrade( + channel.src_port_id().as_str(), + channel.src_channel_id().unwrap().as_str(), + old_ordering.as_str(), + old_connection_hops_a.first().unwrap().as_str(), + &serde_json::to_string(&new_version.0).unwrap(), + chains.handle_a().get_signer().unwrap().as_ref(), + "1", + )?; + + info!("Check that the step ChanUpgradeInit was correctly executed..."); + + assert_eventually_channel_upgrade_init( + &chains.handle_a, + &chains.handle_b, + &channels.channel_id_a.as_ref(), + &channels.port_a.as_ref(), + &old_attrs, + )?; + + // send a IBC transfer message from chain a to chain b + // so that we have an in-flight packet and chain a + // will move to `FLUSHING` during Ack + let denom_a = chains.node_a.denom(); + let wallet_a = chains.node_a.wallets().user1().cloned(); + let wallet_b = chains.node_b.wallets().user1().cloned(); + let a_to_b_amount = 12345u128; + + info!( + "Sending IBC transfer from chain {} to chain {} with amount of {} {}", + chains.chain_id_a(), + chains.chain_id_b(), + a_to_b_amount, + denom_a + ); + + chains + .node_a + .chain_driver() + .ibc_transfer_token_with_memo_and_timeout( + &channels.port_a.as_ref(), + &channels.channel_id_a.as_ref(), + &wallet_a.as_ref(), + &wallet_b.address(), + &denom_a.with_amount(a_to_b_amount).as_ref(), + None, + Some(Duration::from_secs(600)), + )?; + + info!("Will run ChanUpgradeTry step..."); + + channel.build_chan_upgrade_try_and_send()?; + + info!("Check that the step ChanUpgradeTry was correctly executed..."); + + assert_eventually_channel_upgrade_try( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + &old_attrs.flipped(), + )?; + + info!("Will run ChanUpgradeAck step..."); + + channel.flipped().build_chan_upgrade_ack_and_send()?; + + info!("Check that the step ChanUpgradeAck was correctly executed..."); + + // channel a is `FLUSHING` because the packet + // from a to b has not been cleared yet + assert_eventually_channel_upgrade_ack( + &chains.handle_a, + &chains.handle_b, + &channels.channel_id_a.as_ref(), + &channels.port_a.as_ref(), + ChannelState::Flushing, + ChannelState::Flushing, + &old_attrs, + )?; + + // wait enough time so that timeout expires while chain a is in FLUSHING + // and when packet lifecycle completes with acknowledge packet on chain a + // it will abort the upgrade + sleep(Duration::from_nanos(80000000000)); + + info!("Check that the channel upgrade aborted..."); + + // start supervisor to clear in-flight packets + // and move channel ends to `FLUSH_COMPLETE` + relayer.with_supervisor(|| { + let ibc_denom_b = derive_ibc_denom( + &channels.port_b.as_ref(), + &channels.channel_id_b.as_ref(), + &denom_a, + )?; + + chains.node_b.chain_driver().assert_eventual_wallet_amount( + &wallet_b.address(), + &ibc_denom_b.with_amount(a_to_b_amount).as_ref(), + )?; + + // This will assert that both channel ends are eventually + // in Open state, and that the fields targeted by the upgrade + // have NOT been correctly updated, because chain a aborted the upgrade + assert_eventually_channel_upgrade_cancel( + &chains.handle_a, + &chains.handle_b, + &channels.channel_id_a.as_ref(), + &channels.port_a.as_ref(), + &old_attrs, + )?; + + Ok(()) + }) + } +} + +impl HasOverrides for ChannelUpgradeTimeoutAckHandshake { + type Overrides = ChannelUpgradeTestOverrides; + + fn get_overrides(&self) -> &ChannelUpgradeTestOverrides { + &ChannelUpgradeTestOverrides + } +} + +impl HasOverrides for ChannelUpgradeTimeoutConfirmHandshake { + type Overrides = ChannelUpgradeTestOverrides; + + fn get_overrides(&self) -> &ChannelUpgradeTestOverrides { + &ChannelUpgradeTestOverrides + } +} + +impl HasOverrides for ChannelUpgradeManualTimeoutWhenFlushing { + type Overrides = ChannelUpgradeTestOverrides; + + fn get_overrides(&self) -> &ChannelUpgradeTestOverrides { + &ChannelUpgradeTestOverrides + } +} + +impl HasOverrides for ChannelUpgradeHandshakeTimeoutWhenFlushing { + type Overrides = ChannelUpgradeTestOverrides; + + fn get_overrides(&self) -> &ChannelUpgradeTestOverrides { + &ChannelUpgradeTestOverrides + } +} + +impl HasOverrides for ChannelUpgradeHandshakeTimeoutOnAck { + type Overrides = ChannelUpgradeTestOverrides; + + fn get_overrides(&self) -> &ChannelUpgradeTestOverrides { + &ChannelUpgradeTestOverrides + } +} + +impl HasOverrides for ChannelUpgradeHandshakeTimeoutOnPacketAck { + type Overrides = ChannelUpgradeTestOverrides; + + fn get_overrides(&self) -> &ChannelUpgradeTestOverrides { + &ChannelUpgradeTestOverrides + } +} diff --git a/tools/integration-test/src/tests/channel_upgrade/upgrade_handshake.rs b/tools/integration-test/src/tests/channel_upgrade/upgrade_handshake.rs new file mode 100644 index 0000000000..1a8dbe27ed --- /dev/null +++ b/tools/integration-test/src/tests/channel_upgrade/upgrade_handshake.rs @@ -0,0 +1,247 @@ +//! Tests channel upgrade: +//! +//! - `ChannelUpgradeHandshake` tests that after the upgrade handshake is completed +//! after initialising the upgrade with `build_chan_upgrade_init_and_send` without +//! any in-flight packets. +//! +//! - `ChannelUpgradeClearHandshake` tests that if the upgrade handshake is initialised +//! before the relayer, the upgrade will complete upon starting the relayer. +use std::thread::sleep; + +use ibc_relayer::chain::requests::{IncludeProof, QueryChannelRequest, QueryHeight}; +use ibc_relayer_types::core::ics04_channel::packet::Sequence; +use ibc_relayer_types::core::ics04_channel::version::Version; +use ibc_test_framework::chain::config::{set_max_deposit_period, set_voting_period}; +use ibc_test_framework::prelude::*; +use ibc_test_framework::relayer::channel::{ + assert_eventually_channel_established, assert_eventually_channel_upgrade_open, + ChannelUpgradableAttributes, +}; + +#[test] +fn test_channel_upgrade_handshake() -> Result<(), Error> { + run_binary_channel_test(&ChannelUpgradeHandshake) +} + +#[test] +fn test_channel_upgrade_clear_handshake() -> Result<(), Error> { + run_binary_channel_test(&ChannelUpgradeClearHandshake) +} + +const MAX_DEPOSIT_PERIOD: &str = "10s"; +const VOTING_PERIOD: u64 = 10; + +pub struct ChannelUpgradeHandshake; + +impl TestOverrides for ChannelUpgradeHandshake { + fn modify_relayer_config(&self, config: &mut Config) { + config.mode.channels.enabled = true; + config.mode.clients.misbehaviour = false; + } + + fn modify_genesis_file(&self, genesis: &mut serde_json::Value) -> Result<(), Error> { + set_max_deposit_period(genesis, MAX_DEPOSIT_PERIOD)?; + set_voting_period(genesis, VOTING_PERIOD)?; + Ok(()) + } +} + +impl BinaryChannelTest for ChannelUpgradeHandshake { + fn run( + &self, + _config: &TestConfig, + _relayer: RelayerDriver, + chains: ConnectedChains, + channels: ConnectedChannel, + ) -> Result<(), Error> { + info!("Check that channels are both in OPEN State"); + + assert_eventually_channel_established( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + )?; + + let channel_end_a = chains + .handle_a + .query_channel( + QueryChannelRequest { + port_id: channels.port_a.0.clone(), + channel_id: channels.channel_id_a.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd A: {e}"))?; + + let channel_end_b = chains + .handle_b + .query_channel( + QueryChannelRequest { + port_id: channels.port_b.0.clone(), + channel_id: channels.channel_id_b.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd B: {e}"))?; + + let old_ordering = channel_end_a.ordering; + let old_connection_hops_a = channel_end_a.connection_hops; + let old_connection_hops_b = channel_end_b.connection_hops; + + let channel = channels.channel; + let new_version = Version::ics20_with_fee(); + + let upgraded_attrs = ChannelUpgradableAttributes::new( + new_version.clone(), + new_version.clone(), + old_ordering, + old_connection_hops_a.clone(), + old_connection_hops_b, + Sequence::from(1), + ); + + info!("Will initialise upgrade handshake with governance proposal..."); + + chains.node_a.chain_driver().initialise_channel_upgrade( + channel.src_port_id().as_str(), + channel.src_channel_id().unwrap().as_str(), + old_ordering.as_str(), + old_connection_hops_a.first().unwrap().as_str(), + &serde_json::to_string(&new_version.0).unwrap(), + &chains.node_a.wallets().user2().address().to_string(), + "1", + )?; + + info!("Check that the channel upgrade successfully upgraded the version..."); + + // This will assert that both channel ends are eventually + // in Open state, and that the fields targeted by the upgrade + // have been correctly updated. + assert_eventually_channel_upgrade_open( + &chains.handle_a, + &chains.handle_b, + &channels.channel_id_a.as_ref(), + &channels.port_a.as_ref(), + &upgraded_attrs, + )?; + + Ok(()) + } +} + +pub struct ChannelUpgradeClearHandshake; + +impl TestOverrides for ChannelUpgradeClearHandshake { + fn modify_relayer_config(&self, config: &mut Config) { + config.mode.channels.enabled = true; + config.mode.clients.misbehaviour = false; + } + + fn modify_genesis_file(&self, genesis: &mut serde_json::Value) -> Result<(), Error> { + set_max_deposit_period(genesis, MAX_DEPOSIT_PERIOD)?; + set_voting_period(genesis, VOTING_PERIOD)?; + Ok(()) + } + + fn should_spawn_supervisor(&self) -> bool { + false + } +} + +impl BinaryChannelTest for ChannelUpgradeClearHandshake { + fn run( + &self, + _config: &TestConfig, + relayer: RelayerDriver, + chains: ConnectedChains, + channels: ConnectedChannel, + ) -> Result<(), Error> { + info!("Check that channels are both in OPEN State"); + + assert_eventually_channel_established( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + )?; + + let channel_end_a = chains + .handle_a + .query_channel( + QueryChannelRequest { + port_id: channels.port_a.0.clone(), + channel_id: channels.channel_id_a.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd A: {e}"))?; + + let channel_end_b = chains + .handle_b + .query_channel( + QueryChannelRequest { + port_id: channels.port_b.0.clone(), + channel_id: channels.channel_id_b.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd B: {e}"))?; + + let old_ordering = channel_end_a.ordering; + let old_connection_hops_a = channel_end_a.connection_hops; + let old_connection_hops_b = channel_end_b.connection_hops; + + let channel = channels.channel; + let new_version = Version::ics20_with_fee(); + + let upgraded_attrs = ChannelUpgradableAttributes::new( + new_version.clone(), + new_version.clone(), + old_ordering, + old_connection_hops_a.clone(), + old_connection_hops_b, + Sequence::from(1), + ); + + info!("Will initialise upgrade handshake with governance proposal..."); + + chains.node_a.chain_driver().initialise_channel_upgrade( + channel.src_port_id().as_str(), + channel.src_channel_id().unwrap().as_str(), + old_ordering.as_str(), + old_connection_hops_a.first().unwrap().as_str(), + &serde_json::to_string(&new_version.0).unwrap(), + chains.handle_a().get_signer().unwrap().as_ref(), + "1", + )?; + + // After the governance proposal, wait a few blocks before starting the Hermes instance + sleep(Duration::from_secs(5)); + + info!("Check that the channel upgrade successfully upgraded the version..."); + + relayer.with_supervisor(|| { + // This will assert that both channel ends are eventually + // in Open state, and that the fields targeted by the upgrade + // have been correctly updated. + assert_eventually_channel_upgrade_open( + &chains.handle_a, + &chains.handle_b, + &channels.channel_id_a.as_ref(), + &channels.port_a.as_ref(), + &upgraded_attrs, + )?; + + Ok(()) + }) + } +} diff --git a/tools/integration-test/src/tests/channel_upgrade/upgrade_handshake_steps.rs b/tools/integration-test/src/tests/channel_upgrade/upgrade_handshake_steps.rs new file mode 100644 index 0000000000..31b665bc9a --- /dev/null +++ b/tools/integration-test/src/tests/channel_upgrade/upgrade_handshake_steps.rs @@ -0,0 +1,915 @@ +//! Tests channel upgrade: +//! +//! - `ChannelUpgradeManualHandshake` tests each step of the channel upgrade manually, +//! without relaying on the supervisor. +//! +//! - `ChannelUpgradeHandshakeFromTry` tests that the channel worker will finish the +//! upgrade handshake if the channel is being upgraded and is at the Try step. +//! +//! - `ChannelUpgradeHandshakeFromAck` tests that the channel worker will finish the +//! upgrade handshake if the channel is being upgraded and is at the Ack step. +//! +//! - `ChannelUpgradeHandshakeFromConfirm` tests that the channel worker will finish the +//! upgrade handshake if the channel is being upgraded and is at the Confirm step. +//! +//! - `ChannelUpgradeHandshakeTimeoutOnAck` tests that the channel worker will cancel the +//! upgrade handshake if the Ack step fails due to an upgrade timeout. +//! +//! - `ChannelUpgradeHandshakeTimeoutWhenFlushing` tests that the channel worker will timeout the +//! upgrade handshake if the counterparty does not finish flushing the packets before the upgrade timeout. +//! +//! - `ChannelUpgradeHandshakeInitiateNewUpgrade` tests that the channel worker will +//! finish the upgrade handshake if the side that moved to `OPEN` initiates a +//! new upgrade before the counterparty moved to `OPEN`. +//! +//! - `ChannelUpgradeHandshakeTimeoutOnPacketAck` tests that the channel worker will cancel the +//! upgrade handshake if the chain acknowledges a packet after the upgrade timeout expired. + +use ibc_relayer::chain::requests::{IncludeProof, QueryChannelRequest, QueryHeight}; +use ibc_relayer_types::core::ics04_channel::channel::{State as ChannelState, UpgradeState}; +use ibc_relayer_types::core::ics04_channel::packet::Sequence; +use ibc_relayer_types::core::ics04_channel::version::Version; +use ibc_test_framework::chain::config::{set_max_deposit_period, set_voting_period}; +use ibc_test_framework::prelude::*; +use ibc_test_framework::relayer::channel::{ + assert_eventually_channel_established, assert_eventually_channel_upgrade_ack, + assert_eventually_channel_upgrade_confirm, assert_eventually_channel_upgrade_init, + assert_eventually_channel_upgrade_open, assert_eventually_channel_upgrade_try, + ChannelUpgradableAttributes, +}; + +#[test] +fn test_channel_upgrade_manual_handshake() -> Result<(), Error> { + run_binary_channel_test(&ChannelUpgradeManualHandshake) +} + +#[test] +fn test_channel_upgrade_handshake_from_try() -> Result<(), Error> { + run_binary_channel_test(&ChannelUpgradeHandshakeFromTry) +} + +#[test] +fn test_channel_upgrade_handshake_from_ack() -> Result<(), Error> { + run_binary_channel_test(&ChannelUpgradeHandshakeFromAck) +} + +#[test] +fn test_channel_upgrade_handshake_from_confirm() -> Result<(), Error> { + run_binary_channel_test(&ChannelUpgradeHandshakeFromConfirm) +} + +#[test] +fn test_channel_upgrade_handshake_initiate_new_upgrade() -> Result<(), Error> { + run_binary_channel_test(&ChannelUpgradeHandshakeInitiateNewUpgrade) +} + +const MAX_DEPOSIT_PERIOD: &str = "10s"; +const VOTING_PERIOD: u64 = 10; + +struct ChannelUpgradeTestOverrides; + +impl TestOverrides for ChannelUpgradeTestOverrides { + fn modify_genesis_file(&self, genesis: &mut serde_json::Value) -> Result<(), Error> { + set_max_deposit_period(genesis, MAX_DEPOSIT_PERIOD)?; + set_voting_period(genesis, VOTING_PERIOD)?; + Ok(()) + } + + fn modify_relayer_config(&self, config: &mut Config) { + config.mode.channels.enabled = true; + + config.mode.clients.misbehaviour = false; + } + + fn should_spawn_supervisor(&self) -> bool { + false + } +} + +struct ChannelUpgradeManualHandshake; + +impl BinaryChannelTest for ChannelUpgradeManualHandshake { + fn run( + &self, + _config: &TestConfig, + _relayer: RelayerDriver, + chains: ConnectedChains, + channels: ConnectedChannel, + ) -> Result<(), Error> { + info!("Check that channels are both in OPEN State"); + + assert_eventually_channel_established( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + )?; + + let channel_end_a = chains + .handle_a + .query_channel( + QueryChannelRequest { + port_id: channels.port_a.0.clone(), + channel_id: channels.channel_id_a.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd A: {e}"))?; + + let channel_end_b = chains + .handle_b + .query_channel( + QueryChannelRequest { + port_id: channels.port_b.0.clone(), + channel_id: channels.channel_id_b.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd B: {e}"))?; + + let old_version = channel_end_a.version; + let old_ordering = channel_end_a.ordering; + let old_connection_hops_a = channel_end_a.connection_hops; + let old_connection_hops_b = channel_end_b.connection_hops; + + let channel = channels.channel; + let new_version = Version::ics20_with_fee(); + + let old_attrs = ChannelUpgradableAttributes::new( + old_version.clone(), + old_version.clone(), + old_ordering, + old_connection_hops_a.clone(), + old_connection_hops_b.clone(), + Sequence::from(1), + ); + + let interm_attrs = ChannelUpgradableAttributes::new( + old_version, + new_version.clone(), + old_ordering, + old_connection_hops_a.clone(), + old_connection_hops_b.clone(), + Sequence::from(1), + ); + + let upgraded_attrs = ChannelUpgradableAttributes::new( + new_version.clone(), + new_version.clone(), + old_ordering, + old_connection_hops_a.clone(), + old_connection_hops_b, + Sequence::from(1), + ); + + info!("Will initialise upgrade handshake with governance proposal..."); + + chains.node_a.chain_driver().initialise_channel_upgrade( + channel.src_port_id().as_str(), + channel.src_channel_id().unwrap().as_str(), + old_ordering.as_str(), + old_connection_hops_a.first().unwrap().as_str(), + &serde_json::to_string(&new_version.0).unwrap(), + chains.handle_a().get_signer().unwrap().as_ref(), + "1", + )?; + + info!("Check that the step ChanUpgradeInit was correctly executed..."); + + assert_eventually_channel_upgrade_init( + &chains.handle_a, + &chains.handle_b, + &channels.channel_id_a.as_ref(), + &channels.port_a.as_ref(), + &old_attrs, + )?; + + info!("Will run ChanUpgradeTry step..."); + + channel.build_chan_upgrade_try_and_send()?; + + info!("Check that the step ChanUpgradeTry was correctly executed..."); + + assert_eventually_channel_upgrade_try( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + &old_attrs.flipped(), + )?; + + info!("Will run ChanUpgradeAck step..."); + + channel.flipped().build_chan_upgrade_ack_and_send()?; + + info!("Check that the step ChanUpgradeAck was correctly executed..."); + + assert_eventually_channel_upgrade_ack( + &chains.handle_a, + &chains.handle_b, + &channels.channel_id_a.as_ref(), + &channels.port_a.as_ref(), + ChannelState::FlushComplete, + ChannelState::Flushing, + &old_attrs, + )?; + + info!("Will run ChanUpgradeConfirm step..."); + + channel.build_chan_upgrade_confirm_and_send()?; + + info!("Check that the step ChanUpgradeConfirm was correctly executed..."); + + assert_eventually_channel_upgrade_confirm( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + &interm_attrs.flipped(), + )?; + + info!("Will run ChanUpgradeOpen step..."); + + channel.flipped().build_chan_upgrade_open_and_send()?; + + info!("Check that the ChanUpgradeOpen steps were correctly executed..."); + + // This will assert that both channel ends are eventually + // in Open state, and that the fields targeted by the upgrade + // have been correctly updated. + assert_eventually_channel_upgrade_open( + &chains.handle_a, + &chains.handle_b, + &channels.channel_id_a.as_ref(), + &channels.port_a.as_ref(), + &upgraded_attrs, + )?; + + Ok(()) + } +} + +struct ChannelUpgradeHandshakeFromTry; + +impl BinaryChannelTest for ChannelUpgradeHandshakeFromTry { + fn run( + &self, + _config: &TestConfig, + relayer: RelayerDriver, + chains: ConnectedChains, + channels: ConnectedChannel, + ) -> Result<(), Error> { + info!("Check that channels are both in OPEN State"); + + assert_eventually_channel_established( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + )?; + + let channel_end_a = chains + .handle_a + .query_channel( + QueryChannelRequest { + port_id: channels.port_a.0.clone(), + channel_id: channels.channel_id_a.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd A: {e}"))?; + + let channel_end_b = chains + .handle_b + .query_channel( + QueryChannelRequest { + port_id: channels.port_b.0.clone(), + channel_id: channels.channel_id_b.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd B: {e}"))?; + + let old_version = channel_end_a.version; + let old_ordering = channel_end_a.ordering; + let old_connection_hops_a = channel_end_a.connection_hops; + let old_connection_hops_b = channel_end_b.connection_hops; + + let channel = channels.channel; + let new_version = Version::ics20_with_fee(); + + let old_attrs = ChannelUpgradableAttributes::new( + old_version.clone(), + old_version.clone(), + old_ordering, + old_connection_hops_a.clone(), + old_connection_hops_b.clone(), + Sequence::from(1), + ); + + let upgraded_attrs = ChannelUpgradableAttributes::new( + new_version.clone(), + new_version.clone(), + old_ordering, + old_connection_hops_a.clone(), + old_connection_hops_b, + Sequence::from(1), + ); + + info!("Will initialise upgrade handshake with governance proposal..."); + + chains.node_a.chain_driver().initialise_channel_upgrade( + channel.src_port_id().as_str(), + channel.src_channel_id().unwrap().as_str(), + old_ordering.as_str(), + old_connection_hops_a.first().unwrap().as_str(), + &serde_json::to_string(&new_version.0).unwrap(), + chains.handle_a().get_signer().unwrap().as_ref(), + "1", + )?; + + info!("Will run ChanUpgradeTry step..."); + + channel.build_chan_upgrade_try_and_send()?; + + info!("Check that the step ChanUpgradeTry was correctly executed..."); + + assert_eventually_channel_upgrade_try( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + &old_attrs.flipped(), + )?; + + info!("Check that the channel upgrade successfully upgraded the version..."); + + relayer.with_supervisor(|| { + // This will assert that both channel ends are eventually + // in Open state, and that the fields targeted by the upgrade + // have been correctly updated. + assert_eventually_channel_upgrade_open( + &chains.handle_a, + &chains.handle_b, + &channels.channel_id_a.as_ref(), + &channels.port_a.as_ref(), + &upgraded_attrs, + )?; + + Ok(()) + }) + } +} + +struct ChannelUpgradeHandshakeFromAck; + +impl BinaryChannelTest for ChannelUpgradeHandshakeFromAck { + fn run( + &self, + _config: &TestConfig, + relayer: RelayerDriver, + chains: ConnectedChains, + channels: ConnectedChannel, + ) -> Result<(), Error> { + info!("Check that channels are both in OPEN State"); + + assert_eventually_channel_established( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + )?; + + let channel_end_a = chains + .handle_a + .query_channel( + QueryChannelRequest { + port_id: channels.port_a.0.clone(), + channel_id: channels.channel_id_a.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd A: {e}"))?; + + let channel_end_b = chains + .handle_b + .query_channel( + QueryChannelRequest { + port_id: channels.port_b.0.clone(), + channel_id: channels.channel_id_b.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd B: {e}"))?; + + let old_version = channel_end_a.version; + let old_ordering = channel_end_a.ordering; + let old_connection_hops_a = channel_end_a.connection_hops; + let old_connection_hops_b = channel_end_b.connection_hops; + + let channel = channels.channel; + let new_version = Version::ics20_with_fee(); + + let old_attrs = ChannelUpgradableAttributes::new( + old_version.clone(), + old_version.clone(), + old_ordering, + old_connection_hops_a.clone(), + old_connection_hops_b.clone(), + Sequence::from(1), + ); + + let upgraded_attrs = ChannelUpgradableAttributes::new( + new_version.clone(), + new_version.clone(), + old_ordering, + old_connection_hops_a.clone(), + old_connection_hops_b, + Sequence::from(1), + ); + + info!("Will initialise upgrade handshake with governance proposal..."); + + chains.node_a.chain_driver().initialise_channel_upgrade( + channel.src_port_id().as_str(), + channel.src_channel_id().unwrap().as_str(), + old_ordering.as_str(), + old_connection_hops_a.first().unwrap().as_str(), + &serde_json::to_string(&new_version.0).unwrap(), + chains.handle_a().get_signer().unwrap().as_ref(), + "1", + )?; + + info!("Will run ChanUpgradeTry step..."); + + channel.build_chan_upgrade_try_and_send()?; + + info!("Check that the step ChanUpgradeTry was correctly executed..."); + + assert_eventually_channel_upgrade_try( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + &old_attrs.flipped(), + )?; + + info!("Will run ChanUpgradeAck step..."); + + channel.flipped().build_chan_upgrade_ack_and_send()?; + + info!("Check that the step ChanUpgradeAck was correctly executed..."); + + assert_eventually_channel_upgrade_ack( + &chains.handle_a, + &chains.handle_b, + &channels.channel_id_a.as_ref(), + &channels.port_a.as_ref(), + ChannelState::FlushComplete, + ChannelState::Flushing, + &old_attrs, + )?; + + info!("Check that the channel upgrade successfully upgraded the version..."); + + relayer.with_supervisor(|| { + // This will assert that both channel ends are eventually + // in Open state, and that the fields targeted by the upgrade + // have been correctly updated. + assert_eventually_channel_upgrade_open( + &chains.handle_a, + &chains.handle_b, + &channels.channel_id_a.as_ref(), + &channels.port_a.as_ref(), + &upgraded_attrs, + )?; + + Ok(()) + }) + } +} +struct ChannelUpgradeHandshakeFromConfirm; + +impl BinaryChannelTest for ChannelUpgradeHandshakeFromConfirm { + fn run( + &self, + _config: &TestConfig, + relayer: RelayerDriver, + chains: ConnectedChains, + channels: ConnectedChannel, + ) -> Result<(), Error> { + info!("Check that channels are both in OPEN State"); + + assert_eventually_channel_established( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + )?; + + let channel_end_a = chains + .handle_a + .query_channel( + QueryChannelRequest { + port_id: channels.port_a.0.clone(), + channel_id: channels.channel_id_a.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd A: {e}"))?; + + let channel_end_b = chains + .handle_b + .query_channel( + QueryChannelRequest { + port_id: channels.port_b.0.clone(), + channel_id: channels.channel_id_b.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd B: {e}"))?; + + let old_version = channel_end_a.version; + let old_ordering = channel_end_a.ordering; + let old_connection_hops_a = channel_end_a.connection_hops; + let old_connection_hops_b = channel_end_b.connection_hops; + + let channel = channels.channel; + let new_version = Version::ics20_with_fee(); + + let old_attrs = ChannelUpgradableAttributes::new( + old_version.clone(), + old_version.clone(), + old_ordering, + old_connection_hops_a.clone(), + old_connection_hops_b.clone(), + Sequence::from(1), + ); + + let interm_attrs = ChannelUpgradableAttributes::new( + old_version, + new_version.clone(), + old_ordering, + old_connection_hops_a.clone(), + old_connection_hops_b.clone(), + Sequence::from(1), + ); + + let upgraded_attrs = ChannelUpgradableAttributes::new( + new_version.clone(), + new_version.clone(), + old_ordering, + old_connection_hops_a.clone(), + old_connection_hops_b, + Sequence::from(1), + ); + + info!("Will initialise upgrade handshake with governance proposal..."); + + chains.node_a.chain_driver().initialise_channel_upgrade( + channel.src_port_id().as_str(), + channel.src_channel_id().unwrap().as_str(), + old_ordering.as_str(), + old_connection_hops_a.first().unwrap().as_str(), + &serde_json::to_string(&new_version.0).unwrap(), + chains.handle_a().get_signer().unwrap().as_ref(), + "1", + )?; + + info!("Will run ChanUpgradeTry step..."); + + channel.build_chan_upgrade_try_and_send()?; + + info!("Check that the step ChanUpgradeTry was correctly executed..."); + + assert_eventually_channel_upgrade_try( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + &old_attrs.flipped(), + )?; + + info!("Will run ChanUpgradeAck step..."); + + channel.flipped().build_chan_upgrade_ack_and_send()?; + + info!("Check that the step ChanUpgradeAck was correctly executed..."); + + assert_eventually_channel_upgrade_ack( + &chains.handle_a, + &chains.handle_b, + &channels.channel_id_a.as_ref(), + &channels.port_a.as_ref(), + ChannelState::FlushComplete, + ChannelState::Flushing, + &old_attrs, + )?; + + info!("Will run ChanUpgradeConfirm step..."); + + channel.build_chan_upgrade_confirm_and_send()?; + + info!("Check that the step ChanUpgradeConfirm was correctly executed..."); + + assert_eventually_channel_upgrade_confirm( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + &interm_attrs.flipped(), + )?; + + info!("Check that the channel upgrade successfully upgraded the version..."); + + relayer.with_supervisor(|| { + // This will assert that both channel ends are eventually + // in Open state, and that the fields targeted by the upgrade + // have been correctly updated. + assert_eventually_channel_upgrade_open( + &chains.handle_a, + &chains.handle_b, + &channels.channel_id_a.as_ref(), + &channels.port_a.as_ref(), + &upgraded_attrs, + )?; + + Ok(()) + }) + } +} + +struct ChannelUpgradeHandshakeInitiateNewUpgrade; + +impl BinaryChannelTest for ChannelUpgradeHandshakeInitiateNewUpgrade { + fn run( + &self, + _config: &TestConfig, + _relayer: RelayerDriver, + chains: ConnectedChains, + channels: ConnectedChannel, + ) -> Result<(), Error> { + info!("Check that channels are both in OPEN State"); + + assert_eventually_channel_established( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + )?; + + let mut channel_end_a = chains + .handle_a + .query_channel( + QueryChannelRequest { + port_id: channels.port_a.0.clone(), + channel_id: channels.channel_id_a.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd A: {e}"))?; + + let mut channel_end_b = chains + .handle_b + .query_channel( + QueryChannelRequest { + port_id: channels.port_b.0.clone(), + channel_id: channels.channel_id_b.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::No, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd B: {e}"))?; + + let pre_upgrade_1_version = channel_end_a.version; + let pre_upgrade_1_ordering = channel_end_a.ordering; + let pre_upgrade_1_connection_hops_a = channel_end_a.connection_hops.clone(); + let pre_upgrade_1_connection_hops_b = channel_end_b.connection_hops.clone(); + + let channel = channels.channel; + let post_upgrade_1_version = Version::ics20_with_fee(); + + let pre_upgrade_1_attrs = ChannelUpgradableAttributes::new( + pre_upgrade_1_version.clone(), + pre_upgrade_1_version.clone(), + pre_upgrade_1_ordering, + pre_upgrade_1_connection_hops_a.clone(), + pre_upgrade_1_connection_hops_b.clone(), + Sequence::from(1), + ); + + let interm_upgrade_1_attrs = ChannelUpgradableAttributes::new( + pre_upgrade_1_version, + post_upgrade_1_version.clone(), + pre_upgrade_1_ordering, + pre_upgrade_1_connection_hops_a.clone(), + pre_upgrade_1_connection_hops_b.clone(), + Sequence::from(1), + ); + + info!("Will initialise on chain A upgrade handshake with governance proposal..."); + + chains.node_a.chain_driver().initialise_channel_upgrade( + channel.src_port_id().as_str(), + channel.src_channel_id().unwrap().as_str(), + pre_upgrade_1_ordering.as_str(), + pre_upgrade_1_connection_hops_a.first().unwrap().as_str(), + &serde_json::to_string(&post_upgrade_1_version.0).unwrap(), + chains.handle_a().get_signer().unwrap().as_ref(), + "1", + )?; + + info!("Check that the step ChanUpgradeInit was correctly executed..."); + + assert_eventually_channel_upgrade_init( + &chains.handle_a, + &chains.handle_b, + &channels.channel_id_a.as_ref(), + &channels.port_a.as_ref(), + &pre_upgrade_1_attrs, + )?; + + info!("Will run ChanUpgradeTry step..."); + + channel.build_chan_upgrade_try_and_send()?; + + info!("Check that the step ChanUpgradeTry was correctly executed..."); + + assert_eventually_channel_upgrade_try( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + &pre_upgrade_1_attrs.flipped(), + )?; + + info!("Will run ChanUpgradeAck step..."); + + channel.flipped().build_chan_upgrade_ack_and_send()?; + + info!("Check that the step ChanUpgradeAck was correctly executed..."); + + assert_eventually_channel_upgrade_ack( + &chains.handle_a, + &chains.handle_b, + &channels.channel_id_a.as_ref(), + &channels.port_a.as_ref(), + ChannelState::FlushComplete, + ChannelState::Flushing, + &pre_upgrade_1_attrs, + )?; + + info!("Will run ChanUpgradeConfirm step..."); + + channel.build_chan_upgrade_confirm_and_send()?; + + info!("Check that the step ChanUpgradeConfirm was correctly executed..."); + + assert_eventually_channel_upgrade_confirm( + &chains.handle_b, + &chains.handle_a, + &channels.channel_id_b.as_ref(), + &channels.port_b.as_ref(), + &interm_upgrade_1_attrs.flipped(), + )?; + + // ChannelEnd B is now `OPEN` (because both ends did not have in-flight packets) + // Initialise a new upgrade handshake on chain B before ChannelEnd A moves to `OPEN` + + let pre_upgrade_2_ordering = channel_end_a.ordering; + let pre_upgrade_2_connection_hops_b = channel_end_b.connection_hops.clone(); + + let post_upgrade_2_version = Version::ics20(); + + info!("Will initialise on chain B upgrade handshake with governance proposal..."); + + chains.node_b.chain_driver().initialise_channel_upgrade( + channel.dst_port_id().as_str(), + channel.dst_channel_id().unwrap().as_str(), + pre_upgrade_2_ordering.as_str(), + pre_upgrade_2_connection_hops_b.first().unwrap().as_str(), + &serde_json::to_string(&post_upgrade_2_version.0).unwrap(), + chains.handle_b().get_signer().unwrap().as_ref(), + "1", + )?; + + info!("Check that the step ChanUpgradeInit was correctly executed..."); + + channel_end_b = chains + .handle_b + .query_channel( + QueryChannelRequest { + port_id: channels.port_b.0.clone(), + channel_id: channels.channel_id_b.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::Yes, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd B: {e}"))?; + + // upgrade sequence should have been incremented + let upgrade_sequence_b = Sequence::from(2); + assert_eq!( + channel_end_b.upgrade_sequence, upgrade_sequence_b, + "expected channel end B upgrade sequence to be `{}`, but it is instead `{}`", + upgrade_sequence_b, channel_end_b.upgrade_sequence + ); + + // Finish upgrade 1 on ChannelEnd A + + info!("Will run ChanUpgradeOpen step..."); + + channel.flipped().build_chan_upgrade_open_and_send()?; + + info!("Check that the step ChanUpgradeOpen was correctly executed..."); + + channel_end_a = chains + .handle_a + .query_channel( + QueryChannelRequest { + port_id: channels.port_a.0.clone(), + channel_id: channels.channel_id_a.0.clone(), + height: QueryHeight::Latest, + }, + IncludeProof::Yes, + ) + .map(|(channel_end, _)| channel_end) + .map_err(|e| eyre!("Error querying ChannelEnd A: {e}"))?; + + if !channel_end_a.is_open() { + return Err(Error::generic(eyre!( + "expected channel end A state to be `{}`, but is instead `{}`", + ChannelState::Open(UpgradeState::NotUpgrading), + channel_end_a.state() + ))); + } + + assert_eq!( + channel_end_a.version, post_upgrade_1_version, + "expected channel end A version to be `{}`, but is instead `{}`", + post_upgrade_1_version, channel_end_a.version + ); + + Ok(()) + } +} + +impl HasOverrides for ChannelUpgradeManualHandshake { + type Overrides = ChannelUpgradeTestOverrides; + + fn get_overrides(&self) -> &ChannelUpgradeTestOverrides { + &ChannelUpgradeTestOverrides + } +} + +impl HasOverrides for ChannelUpgradeHandshakeFromTry { + type Overrides = ChannelUpgradeTestOverrides; + + fn get_overrides(&self) -> &ChannelUpgradeTestOverrides { + &ChannelUpgradeTestOverrides + } +} + +impl HasOverrides for ChannelUpgradeHandshakeFromAck { + type Overrides = ChannelUpgradeTestOverrides; + + fn get_overrides(&self) -> &ChannelUpgradeTestOverrides { + &ChannelUpgradeTestOverrides + } +} + +impl HasOverrides for ChannelUpgradeHandshakeFromConfirm { + type Overrides = ChannelUpgradeTestOverrides; + + fn get_overrides(&self) -> &ChannelUpgradeTestOverrides { + &ChannelUpgradeTestOverrides + } +} + +impl HasOverrides for ChannelUpgradeHandshakeInitiateNewUpgrade { + type Overrides = ChannelUpgradeTestOverrides; + + fn get_overrides(&self) -> &ChannelUpgradeTestOverrides { + &ChannelUpgradeTestOverrides + } +} diff --git a/tools/integration-test/src/tests/clear_packet.rs b/tools/integration-test/src/tests/clear_packet.rs index 6da6147806..cf09b6dbad 100644 --- a/tools/integration-test/src/tests/clear_packet.rs +++ b/tools/integration-test/src/tests/clear_packet.rs @@ -1,14 +1,14 @@ use std::thread; -use ibc_relayer::chain::counterparty::pending_packet_summary; +use ibc_relayer::chain::{counterparty::pending_packet_summary, requests::Paginate}; use ibc_relayer::config::ChainConfig; use ibc_test_framework::prelude::*; use ibc_test_framework::relayer::channel::query_identified_channel_end; use ibc_test_framework::util::random::random_u128_range; #[test] -fn test_clear_packet() -> Result<(), Error> { - run_binary_channel_test(&ClearPacketTest) +fn test_disabled_clear_packet() -> Result<(), Error> { + run_binary_channel_test(&DisabledClearPacketTest) } #[test] @@ -31,13 +31,19 @@ fn test_clear_packet_sequences() -> Result<(), Error> { run_binary_channel_test(&ClearPacketSequencesTest) } -pub struct ClearPacketTest; +#[test] +fn test_limited_clear_packet() -> Result<(), Error> { + run_binary_channel_test(&LimitedClearPacketTest) +} + +pub struct DisabledClearPacketTest; pub struct ClearPacketRecoveryTest; pub struct ClearPacketNoScanTest; pub struct ClearPacketOverrideTest; pub struct ClearPacketSequencesTest; +pub struct LimitedClearPacketTest; -impl TestOverrides for ClearPacketTest { +impl TestOverrides for DisabledClearPacketTest { fn modify_relayer_config(&self, config: &mut Config) { // Disabling client workers and clear_on_start should make the relayer not // relay any packet it missed before starting. @@ -60,18 +66,7 @@ impl TestOverrides for ClearPacketTest { } } -impl TestOverrides for ClearPacketRecoveryTest { - fn modify_relayer_config(&self, config: &mut Config) { - config.mode.packets.enabled = true; - config.mode.packets.clear_on_start = true; - } - - fn should_spawn_supervisor(&self) -> bool { - false - } -} - -impl BinaryChannelTest for ClearPacketTest { +impl BinaryChannelTest for DisabledClearPacketTest { fn run( &self, _config: &TestConfig, @@ -147,14 +142,27 @@ impl BinaryChannelTest for ClearPacketTest { } } +impl TestOverrides for ClearPacketRecoveryTest { + fn modify_relayer_config(&self, config: &mut Config) { + config.mode.packets.enabled = true; + config.mode.packets.clear_on_start = true; + } + + fn should_spawn_supervisor(&self) -> bool { + false + } +} + impl BinaryChannelTest for ClearPacketRecoveryTest { fn run( &self, - _config: &TestConfig, + config: &TestConfig, relayer: RelayerDriver, chains: ConnectedChains, channel: ConnectedChannel, ) -> Result<(), Error> { + let fee_denom_b: MonoTagged = + MonoTagged::new(Denom::base(config.native_token(1))); let denom_a = chains.node_a.denom(); let denom_b1 = chains.node_b.denom(); @@ -168,6 +176,7 @@ impl BinaryChannelTest for ClearPacketRecoveryTest { &relayer_wallet_b.as_ref(), &wallet_b.address(), &denom_b1.with_amount(100u64).as_ref(), + &fee_denom_b.with_amount(381000000u64).as_ref(), )?; let amount1 = random_u128_range(1000, 5000); @@ -224,7 +233,7 @@ impl BinaryChannelTest for ClearPacketNoScanTest { channel: ConnectedChannel, ) -> Result<(), Error> { let denom_a = chains.node_a.denom(); - let fee_denom_a = MonoTagged::new(Denom::base(&config.native_tokens[0])); + let fee_denom_a = MonoTagged::new(Denom::base(config.native_token(0))); let wallet_a = chains.node_a.wallets().user1().cloned(); let wallet_b = chains.node_b.wallets().user1().cloned(); @@ -344,7 +353,7 @@ impl BinaryChannelTest for ClearPacketOverrideTest { channel: ConnectedChannel, ) -> Result<(), Error> { let denom_a = chains.node_a.denom(); - let fee_denom_a = MonoTagged::new(Denom::base(&config.native_tokens[0])); + let fee_denom_a = MonoTagged::new(Denom::base(config.native_token(0))); let wallet_a = chains.node_a.wallets().user1().cloned(); let wallet_b = chains.node_b.wallets().user1().cloned(); @@ -475,8 +484,12 @@ impl BinaryChannelTest for ClearPacketSequencesTest { channel.port_a.as_ref(), )?; - let pending_packets_a = - pending_packet_summary(chains.handle_a(), chains.handle_b(), channel_end_a.value())?; + let pending_packets_a = pending_packet_summary( + chains.handle_a(), + chains.handle_b(), + channel_end_a.value(), + Paginate::All, + )?; info!("Pending packets: {:?}", pending_packets_a); @@ -487,6 +500,15 @@ impl BinaryChannelTest for ClearPacketSequencesTest { src_channel_id: channel.channel_id_a.clone().into_value(), max_memo_size: packet_config.ics20_max_memo_size, max_receiver_size: packet_config.ics20_max_receiver_size, + exclude_src_sequences: vec![], + }; + + let rev_opts = LinkParameters { + src_port_id: channel.port_b.clone().into_value(), + src_channel_id: channel.channel_id_b.clone().into_value(), + max_memo_size: packet_config.ics20_max_memo_size, + max_receiver_size: packet_config.ics20_max_receiver_size, + exclude_src_sequences: vec![], }; // Clear all even packets @@ -514,8 +536,12 @@ impl BinaryChannelTest for ClearPacketSequencesTest { sleep(Duration::from_secs(10)); - let pending_packets = - pending_packet_summary(chains.handle_a(), chains.handle_b(), channel_end_a.value())?; + let pending_packets = pending_packet_summary( + chains.handle_a(), + chains.handle_b(), + channel_end_a.value(), + Paginate::All, + )?; info!("Pending packets: {pending_packets:?}"); @@ -532,11 +558,22 @@ impl BinaryChannelTest for ClearPacketSequencesTest { info!("Clearing all unreceived ack packets ({})", to_clear.len()); - let rev_link = link.reverse(false, false).unwrap(); - rev_link.relay_ack_packet_messages(to_clear).unwrap(); + let rev_link = Link::new_from_opts( + chains.handle_b().clone(), + chains.handle_a().clone(), + rev_opts, + false, + false, + )?; - let pending_packets_a = - pending_packet_summary(chains.handle_a(), chains.handle_b(), channel_end_a.value())?; + rev_link.relay_ack_packet_messages(to_clear)?; + + let pending_packets_a = pending_packet_summary( + chains.handle_a(), + chains.handle_b(), + channel_end_a.value(), + Paginate::All, + )?; info!("Pending packets: {pending_packets_a:?}"); @@ -554,3 +591,92 @@ impl BinaryChannelTest for ClearPacketSequencesTest { Ok(()) } } + +impl TestOverrides for LimitedClearPacketTest { + fn modify_relayer_config(&self, config: &mut Config) { + // Disabling client workers and clear_on_start should make the relayer not + // relay any packet it missed before starting. + config.mode.clients.enabled = false; + config.mode.connections.enabled = false; + config.mode.channels.enabled = false; + + config.mode.packets.enabled = true; + config.mode.packets.clear_on_start = true; + config.mode.packets.clear_interval = 0; + } + + fn should_spawn_supervisor(&self) -> bool { + false + } + + // Unordered channel: will permit gaps in the sequence of relayed packets + fn channel_order(&self) -> Ordering { + Ordering::Unordered + } +} + +impl BinaryChannelTest for LimitedClearPacketTest { + fn run( + &self, + _config: &TestConfig, + relayer: RelayerDriver, + chains: ConnectedChains, + channel: ConnectedChannel, + ) -> Result<(), Error> { + let denom_a = chains.node_a.denom(); + + let wallet_a = chains.node_a.wallets().user1().cloned(); + let wallet_b = chains.node_b.wallets().user1().cloned(); + + let balance_a = chains + .node_a + .chain_driver() + .query_balance(&wallet_a.address(), &denom_a)?; + + let raw_amount = random_u128_range(1000, 5000); + + let num_transfers = 70; + + let amount = denom_a.with_amount(raw_amount); + let sent_amount = denom_a.with_amount(raw_amount * num_transfers); + let cleared_amount = denom_a.with_amount(raw_amount * 50); + + info!("Performing {num_transfers} IBC transfers with amount {amount}, for a total of {sent_amount}"); + + chains.node_a.chain_driver().ibc_transfer_token_multiple( + &channel.port_a.as_ref(), + &channel.channel_id_a.as_ref(), + &wallet_a.as_ref(), + &wallet_b.address(), + &amount.as_ref(), + 70, + None, + )?; + + sleep(Duration::from_secs(10)); + + // Spawn the supervisor only after the first IBC transfer + relayer.with_supervisor(|| { + let amount_b = cleared_amount + .transfer(&channel.port_b.as_ref(), &channel.channel_id_b.as_ref())?; + + info!("Assert that {sent_amount} was escrowed from sending chain"); + + // Wallet on chain A should have both amount deducted. + chains.node_a.chain_driver().assert_eventual_wallet_amount( + &wallet_a.address(), + &(balance_a - sent_amount.amount()).as_ref(), + )?; + + info!("Assert that only {amount_b} was received"); + + // Wallet on chain B should only receive the second IBC transfer + chains + .node_b + .chain_driver() + .assert_eventual_wallet_amount(&wallet_b.address(), &amount_b.as_ref())?; + + Ok(()) + }) + } +} diff --git a/tools/integration-test/src/tests/client_expiration.rs b/tools/integration-test/src/tests/client_expiration.rs index 007ac0b459..082cacf70a 100644 --- a/tools/integration-test/src/tests/client_expiration.rs +++ b/tools/integration-test/src/tests/client_expiration.rs @@ -1,7 +1,4 @@ -use core::time::Duration; -use std::thread::sleep; - -use ibc_relayer::config::{self, ChainConfig, Config, ModeConfig}; +use ibc_relayer::config::{self, ChainConfig, ModeConfig}; use ibc_relayer_types::core::ics03_connection::connection::State as ConnectionState; use ibc_relayer_types::core::ics04_channel::channel::State as ChannelState; @@ -10,7 +7,6 @@ use ibc_test_framework::bootstrap::binary::channel::{ bootstrap_channel_with_chains, bootstrap_channel_with_connection, }; use ibc_test_framework::bootstrap::binary::connection::bootstrap_connection; -use ibc_test_framework::ibc::denom::derive_ibc_denom; use ibc_test_framework::prelude::*; use ibc_test_framework::relayer::channel::{ assert_eventually_channel_established, init_channel, query_channel_end, diff --git a/tools/integration-test/src/tests/client_filter.rs b/tools/integration-test/src/tests/client_filter.rs index 3378bfcc14..0410a91ba4 100644 --- a/tools/integration-test/src/tests/client_filter.rs +++ b/tools/integration-test/src/tests/client_filter.rs @@ -16,8 +16,6 @@ //! is allowed through the filter. It then asserts that client workers were //! established as a result of the connection being allowed through. -use std::time::Duration; - use ibc_relayer::supervisor::client_state_filter::{FilterPolicy, Permission}; use ibc_relayer_types::core::ics02_client::trust_threshold::TrustThreshold; diff --git a/tools/integration-test/src/tests/client_refresh.rs b/tools/integration-test/src/tests/client_refresh.rs index 8871cab801..e29adbb821 100644 --- a/tools/integration-test/src/tests/client_refresh.rs +++ b/tools/integration-test/src/tests/client_refresh.rs @@ -1,5 +1,3 @@ -use std::time::Duration; - use ibc_relayer::config::gas_multiplier::GasMultiplier; use ibc_relayer::config::ChainConfig; use ibc_relayer::foreign_client::CreateOptions; diff --git a/tools/integration-test/src/tests/client_settings.rs b/tools/integration-test/src/tests/client_settings.rs index cdb7465433..0a3c7656a4 100644 --- a/tools/integration-test/src/tests/client_settings.rs +++ b/tools/integration-test/src/tests/client_settings.rs @@ -1,5 +1,3 @@ -use std::time::Duration; - use ibc_relayer::chain::requests::{IncludeProof, QueryClientStateRequest, QueryHeight}; use ibc_relayer::client_state::AnyClientState; use ibc_relayer::config::ChainConfig; diff --git a/tools/integration-test/src/tests/client_upgrade.rs b/tools/integration-test/src/tests/client_upgrade.rs index 01731e6d8b..9480a4a105 100644 --- a/tools/integration-test/src/tests/client_upgrade.rs +++ b/tools/integration-test/src/tests/client_upgrade.rs @@ -32,6 +32,7 @@ const MAX_DEPOSIT_PERIOD: &str = "10s"; const VOTING_PERIOD: u64 = 10; const DELTA_HEIGHT: u64 = 15; const WAIT_CHAIN_UPGRADE: Duration = Duration::from_secs(4); +const WAIT_CHAIN_HEIGHT: Duration = Duration::from_secs(3); const MIN_DEPOSIT: u64 = 10000000u64; #[test] @@ -82,7 +83,7 @@ impl BinaryChainTest for ClientUpgradeTest { ) -> Result<(), ibc_test_framework::prelude::Error> { let upgraded_chain_id = ChainId::new("upgradedibc".to_owned(), 1); let fee_denom_a: MonoTagged = - MonoTagged::new(Denom::base(&config.native_tokens[0])); + MonoTagged::new(Denom::base(config.native_token(0))); let foreign_clients = chains.clone().foreign_clients; // Create and send an chain upgrade proposal @@ -121,7 +122,7 @@ impl BinaryChainTest for ClientUpgradeTest { .map_err(handle_generic_error)?; // Vote on the proposal so the chain will upgrade - driver.vote_proposal(&fee_denom_a.with_amount(381000000u64).to_string())?; + driver.vote_proposal(&fee_denom_a.with_amount(381000000u64).to_string(), "1")?; info!("Assert that the chain upgrade proposal is eventually passed"); @@ -134,15 +135,28 @@ impl BinaryChainTest for ClientUpgradeTest { "1", )?; - // Wait for the chain to upgrade - std::thread::sleep(WAIT_CHAIN_UPGRADE); + let halt_height = (client_upgrade_height - 1).unwrap(); + + // Wait for the chain to get to the halt height + loop { + let latest_height = chains.handle_a().query_latest_height()?; + info!("latest height: {latest_height}"); + + if latest_height >= halt_height { + break; + } + std::thread::sleep(WAIT_CHAIN_HEIGHT); + } + // Wait for an additional height which is required to fetch + // the header + std::thread::sleep(WAIT_CHAIN_HEIGHT); // Trigger the client upgrade // The error is ignored as the client state will be asserted afterwards. let _ = foreign_clients.client_a_to_b.upgrade(client_upgrade_height); // Wait to seconds before querying the client state - std::thread::sleep(Duration::from_secs(2)); + std::thread::sleep(WAIT_CHAIN_UPGRADE); let (state, _) = chains.handle_b().query_client_state( QueryClientStateRequest { @@ -228,7 +242,7 @@ impl BinaryChainTest for HeightTooHighClientUpgradeTest { ) -> Result<(), ibc_test_framework::prelude::Error> { let upgraded_chain_id = ChainId::new("upgradedibc".to_owned(), 1); let fee_denom_a: MonoTagged = - MonoTagged::new(Denom::base(&config.native_tokens[0])); + MonoTagged::new(Denom::base(config.native_token(0))); let foreign_clients = chains.clone().foreign_clients; // Create and send an chain upgrade proposal @@ -267,7 +281,7 @@ impl BinaryChainTest for HeightTooHighClientUpgradeTest { .map_err(handle_generic_error)?; // Vote on the proposal so the chain will upgrade - driver.vote_proposal(&fee_denom_a.with_amount(381000000u64).to_string())?; + driver.vote_proposal(&fee_denom_a.with_amount(381000000u64).to_string(), "1")?; // The application height reports a height of 1 less than the height according to Tendermint client_upgrade_height.increment(); @@ -326,7 +340,7 @@ impl BinaryChainTest for HeightTooLowClientUpgradeTest { ) -> Result<(), ibc_test_framework::prelude::Error> { let upgraded_chain_id = ChainId::new("upgradedibc".to_owned(), 1); let fee_denom_a: MonoTagged = - MonoTagged::new(Denom::base(&config.native_tokens[0])); + MonoTagged::new(Denom::base(config.native_token(0))); let foreign_clients = chains.clone().foreign_clients; let opts = create_upgrade_plan(config, &chains, &upgraded_chain_id)?; @@ -364,7 +378,7 @@ impl BinaryChainTest for HeightTooLowClientUpgradeTest { .map_err(handle_generic_error)?; // Vote on the proposal so the chain will upgrade - driver.vote_proposal(&fee_denom_a.with_amount(381000000u64).to_string())?; + driver.vote_proposal(&fee_denom_a.with_amount(381000000u64).to_string(), "1")?; // The application height reports a height of 1 less than the height according to Tendermint client_upgrade_height @@ -419,7 +433,7 @@ fn create_upgrade_plan( upgraded_chain_id: &ChainId, ) -> Result { let fee_denom_a: MonoTagged = - MonoTagged::new(Denom::base(&config.native_tokens[0])); + MonoTagged::new(Denom::base(config.native_token(0))); let foreign_clients = chains.clone().foreign_clients; let src_client_id = foreign_clients.client_id_b().0.clone(); diff --git a/tools/integration-test/src/tests/connection_delay.rs b/tools/integration-test/src/tests/connection_delay.rs index d39da949da..0c8ca19e57 100644 --- a/tools/integration-test/src/tests/connection_delay.rs +++ b/tools/integration-test/src/tests/connection_delay.rs @@ -1,7 +1,5 @@ -use core::time::Duration; use time::OffsetDateTime; -use ibc_test_framework::ibc::denom::derive_ibc_denom; use ibc_test_framework::prelude::*; use ibc_test_framework::util::random::random_u128_range; diff --git a/tools/integration-test/src/tests/consensus_states.rs b/tools/integration-test/src/tests/consensus_states.rs index cb7e289038..bfd0891679 100644 --- a/tools/integration-test/src/tests/consensus_states.rs +++ b/tools/integration-test/src/tests/consensus_states.rs @@ -1,5 +1,3 @@ -use std::time::Duration; - use ibc_relayer::chain::{ cosmos::query::consensus_state::query_consensus_states, requests::{PageRequest, QueryConsensusStateHeightsRequest, QueryConsensusStatesRequest}, diff --git a/tools/integration-test/src/tests/denom_trace.rs b/tools/integration-test/src/tests/denom_trace.rs index 695efe2876..3c56efbdcb 100644 --- a/tools/integration-test/src/tests/denom_trace.rs +++ b/tools/integration-test/src/tests/denom_trace.rs @@ -1,4 +1,3 @@ -use ibc_test_framework::ibc::denom::derive_ibc_denom; use ibc_test_framework::prelude::*; #[test] diff --git a/tools/integration-test/src/tests/execute_schedule.rs b/tools/integration-test/src/tests/execute_schedule.rs index cd14968f33..163439afad 100644 --- a/tools/integration-test/src/tests/execute_schedule.rs +++ b/tools/integration-test/src/tests/execute_schedule.rs @@ -49,6 +49,7 @@ impl BinaryChannelTest for ExecuteScheduleTest { src_channel_id: channel.channel_id_a.clone().into_value(), max_memo_size: packet_config.ics20_max_memo_size, max_receiver_size: packet_config.ics20_max_receiver_size, + exclude_src_sequences: vec![], }; let chain_a_link = Link::new_from_opts( @@ -71,7 +72,8 @@ impl BinaryChannelTest for ExecuteScheduleTest { &chains.node_a.denom().with_amount(amount1).as_ref(), )?; - relay_path_a_to_b.schedule_packet_clearing(None)?; + relay_path_a_to_b + .schedule_packet_clearing(None, relayer.config.mode.packets.clear_limit)?; info!("Performing IBC send packet with a token transfer #{} from chain A to be received by chain B", i); } diff --git a/tools/integration-test/src/tests/fee/auto_forward_relayer.rs b/tools/integration-test/src/tests/fee/auto_forward_relayer.rs index 7d0b6bdcc3..ca120394a5 100644 --- a/tools/integration-test/src/tests/fee/auto_forward_relayer.rs +++ b/tools/integration-test/src/tests/fee/auto_forward_relayer.rs @@ -54,7 +54,7 @@ impl BinaryChannelTest for AutoForwardRelayerTest { let user_a = wallets_a.user1(); let user_b = wallets_b.user1(); - let balance_a1 = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; + let balance_a = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; let relayer_balance_a = chain_driver_a.query_balance(&relayer_a.address(), &denom_a)?; @@ -63,10 +63,6 @@ impl BinaryChannelTest for AutoForwardRelayerTest { let ack_fee = random_u128_range(200, 300); let timeout_fee = random_u128_range(100, 200); - let total_sent = send_amount + receive_fee + ack_fee + timeout_fee; - - let balance_a2 = balance_a1 - total_sent; - chain_driver_a.ibc_token_transfer_with_fee( &port_a, &channel_id_a, @@ -85,18 +81,22 @@ impl BinaryChannelTest for AutoForwardRelayerTest { &denom_a, )?; - chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a2.as_ref())?; + info!("Will assert user b received the transferred token"); chain_driver_b.assert_eventual_wallet_amount( &user_b.address(), &denom_b.with_amount(send_amount).as_ref(), )?; + info!("Will assert user a transferred the sent amount, the recv fee and ack fee"); + chain_driver_a.assert_eventual_wallet_amount( &user_a.address(), - &(balance_a2 + timeout_fee).as_ref(), + &(balance_a - send_amount - receive_fee - ack_fee).as_ref(), )?; + info!("Will assert the relayer received the recv fee and ack fee"); + chain_driver_a.assert_eventual_wallet_amount( &relayer_a.address(), &(relayer_balance_a + ack_fee + receive_fee).as_ref(), diff --git a/tools/integration-test/src/tests/fee/filter_fees.rs b/tools/integration-test/src/tests/fee/filter_fees.rs index a6cd76b37d..963e93e2d8 100644 --- a/tools/integration-test/src/tests/fee/filter_fees.rs +++ b/tools/integration-test/src/tests/fee/filter_fees.rs @@ -1,3 +1,5 @@ +#![allow(clippy::mutable_key_type)] + use std::collections::HashMap; use ibc_relayer::config::filter::{ChannelPolicy, FeePolicy, FilterPattern, MinFee}; @@ -75,9 +77,7 @@ impl BinaryChannelTest for FilterIncentivizedFeesRelayerTest { let ack_fee = random_u128_range(200, 300); let timeout_fee = random_u128_range(100, 200); - let total_sent_fail = send_amount + receive_fee_fail + ack_fee + timeout_fee; - - let balance_a2_fail = balance_a1 - total_sent_fail; + let balance_a2 = balance_a1.clone() - send_amount; chain_driver_a.ibc_token_transfer_with_fee( &port_a, @@ -99,17 +99,19 @@ impl BinaryChannelTest for FilterIncentivizedFeesRelayerTest { std::thread::sleep(Duration::from_secs(10)); - chain_driver_a - .assert_eventual_wallet_amount(&user_a.address(), &balance_a2_fail.as_ref())?; + chain_driver_a.assert_eventual_escrowed_amount_ics29( + &user_a.address(), + &balance_a2.as_ref(), + receive_fee_fail, + ack_fee, + timeout_fee, + )?; chain_driver_b.assert_eventual_wallet_amount( &user_b.address(), &denom_b.with_amount(0u128).as_ref(), )?; - chain_driver_a - .assert_eventual_wallet_amount(&user_a.address(), &(balance_a2_fail).as_ref())?; - chain_driver_a.assert_eventual_wallet_amount( &relayer_a.address(), &(relayer_balance_a).as_ref(), @@ -118,7 +120,7 @@ impl BinaryChannelTest for FilterIncentivizedFeesRelayerTest { { info!("Verify that packet with enough fees is relayed"); - let balance_a1 = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; + let balance_a = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; let relayer_balance_a = chain_driver_a.query_balance(&relayer_a.address(), &denom_a)?; let send_amount = random_u128_range(1000, 2000); @@ -126,10 +128,6 @@ impl BinaryChannelTest for FilterIncentivizedFeesRelayerTest { let ack_fee = random_u128_range(200, 300); let timeout_fee = random_u128_range(100, 200); - let total_sent_success = send_amount + receive_fee_success + ack_fee + timeout_fee; - - let balance_a2_success = balance_a1 - total_sent_success; - chain_driver_a.ibc_token_transfer_with_fee( &port_a, &channel_id_a, @@ -148,9 +146,6 @@ impl BinaryChannelTest for FilterIncentivizedFeesRelayerTest { &denom_a, )?; - chain_driver_a - .assert_eventual_wallet_amount(&user_a.address(), &balance_a2_success.as_ref())?; - chain_driver_b.assert_eventual_wallet_amount( &user_b.address(), &denom_b.with_amount(send_amount).as_ref(), @@ -160,6 +155,11 @@ impl BinaryChannelTest for FilterIncentivizedFeesRelayerTest { &relayer_a.address(), &(relayer_balance_a + receive_fee_success + ack_fee).as_ref(), )?; + + chain_driver_a.assert_eventual_wallet_amount( + &user_a.address(), + &(balance_a - send_amount - receive_fee_success - ack_fee).as_ref(), + )?; } Ok(()) @@ -224,9 +224,7 @@ impl BinaryChannelTest for FilterByChannelIncentivizedFeesRelayerTest { let ack_fee = random_u128_range(200, 300); let timeout_fee = random_u128_range(100, 200); - let total_sent = send_amount + receive_fee + ack_fee + timeout_fee; - - let balance_a2 = balance_a1 - total_sent; + let balance_a2 = balance_a1.clone() - send_amount; let denom_b = derive_ibc_denom( &channel.port_b.as_ref(), @@ -248,7 +246,13 @@ impl BinaryChannelTest for FilterByChannelIncentivizedFeesRelayerTest { Duration::from_secs(60), )?; - chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a2.as_ref())?; + chain_driver_a.assert_eventual_escrowed_amount_ics29( + &user_a.address(), + &balance_a2.as_ref(), + receive_fee, + ack_fee, + timeout_fee, + )?; chain_driver_b.assert_eventual_wallet_amount( &user_b.address(), @@ -257,7 +261,7 @@ impl BinaryChannelTest for FilterByChannelIncentivizedFeesRelayerTest { chain_driver_a.assert_eventual_wallet_amount( &user_a.address(), - &(balance_a2 + timeout_fee).as_ref(), + &(balance_a1 - send_amount - receive_fee - ack_fee).as_ref(), )?; chain_driver_a.assert_eventual_wallet_amount( diff --git a/tools/integration-test/src/tests/fee/forward_relayer.rs b/tools/integration-test/src/tests/fee/forward_relayer.rs index f5dc0695fc..daa5bcf317 100644 --- a/tools/integration-test/src/tests/fee/forward_relayer.rs +++ b/tools/integration-test/src/tests/fee/forward_relayer.rs @@ -93,7 +93,7 @@ impl BinaryChannelTest for ForwardRelayerTest { let user_a = wallets_a.user1(); let user_b = wallets_b.user1(); - let balance_a1 = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; + let balance_a = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; let relayer_balance_a = chain_driver_a.query_balance(&relayer_a.address(), &denom_a)?; @@ -102,10 +102,6 @@ impl BinaryChannelTest for ForwardRelayerTest { let ack_fee = random_u128_range(200, 300); let timeout_fee = random_u128_range(100, 200); - let total_sent = send_amount + receive_fee + ack_fee + timeout_fee; - - let balance_a2 = balance_a1 - total_sent; - chain_driver_a.ibc_token_transfer_with_fee( &port_a, &channel_id_a, @@ -124,8 +120,6 @@ impl BinaryChannelTest for ForwardRelayerTest { &denom_a, )?; - chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a2.as_ref())?; - chain_driver_b.assert_eventual_wallet_amount( &user_b.address(), &denom_b.with_amount(send_amount).as_ref(), @@ -133,7 +127,7 @@ impl BinaryChannelTest for ForwardRelayerTest { chain_driver_a.assert_eventual_wallet_amount( &user_a.address(), - &(balance_a2 + timeout_fee).as_ref(), + &(balance_a - send_amount - receive_fee - ack_fee).as_ref(), )?; chain_driver_a.assert_eventual_wallet_amount( diff --git a/tools/integration-test/src/tests/fee/no_forward_relayer.rs b/tools/integration-test/src/tests/fee/no_forward_relayer.rs index f623126b55..8b840640e8 100644 --- a/tools/integration-test/src/tests/fee/no_forward_relayer.rs +++ b/tools/integration-test/src/tests/fee/no_forward_relayer.rs @@ -71,7 +71,7 @@ impl BinaryChannelTest for NoForwardRelayerTest { let user_a = wallets_a.user1(); let user_b = wallets_b.user1(); - let balance_a1 = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; + let balance_a = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; let relayer_balance_a = chain_driver_a.query_balance(&relayer_a.address(), &denom_a)?; @@ -80,10 +80,6 @@ impl BinaryChannelTest for NoForwardRelayerTest { let ack_fee = random_u128_range(200, 300); let timeout_fee = random_u128_range(100, 200); - let total_sent = send_amount + receive_fee + ack_fee + timeout_fee; - - let balance_a2 = balance_a1 - total_sent; - chain_driver_a.ibc_token_transfer_with_fee( &port_a, &channel_id_a, @@ -102,8 +98,6 @@ impl BinaryChannelTest for NoForwardRelayerTest { &denom_a, )?; - chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a2.as_ref())?; - chain_driver_b.assert_eventual_wallet_amount( &user_b.address(), &denom_b.with_amount(send_amount).as_ref(), @@ -113,7 +107,7 @@ impl BinaryChannelTest for NoForwardRelayerTest { // as there is no counterparty address registered. chain_driver_a.assert_eventual_wallet_amount( &user_a.address(), - &(balance_a2 + receive_fee + timeout_fee).as_ref(), + &(balance_a - send_amount - ack_fee).as_ref(), )?; chain_driver_a.assert_eventual_wallet_amount( @@ -153,7 +147,7 @@ impl BinaryChannelTest for InvalidForwardRelayerTest { let user_a = wallets_a.user1(); let user_b = wallets_b.user1(); - let balance_a1 = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; + let balance_a = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; let relayer_balance_a = chain_driver_a.query_balance(&relayer_a.address(), &denom_a)?; @@ -162,10 +156,6 @@ impl BinaryChannelTest for InvalidForwardRelayerTest { let ack_fee = random_u128_range(200, 300); let timeout_fee = random_u128_range(100, 200); - let total_sent = send_amount + receive_fee + ack_fee + timeout_fee; - - let balance_a2 = balance_a1 - total_sent; - let invalid_address = MonoTagged::new(WalletAddress("a very long and invalid address".to_string())); @@ -194,18 +184,16 @@ impl BinaryChannelTest for InvalidForwardRelayerTest { &denom_a, )?; - chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a2.as_ref())?; - chain_driver_b.assert_eventual_wallet_amount( &user_b.address(), &denom_b.with_amount(send_amount).as_ref(), )?; // receive fee and timeout fee should be refunded, - // as thecounterparty address registered is invalid. + // as the counterparty address registered is invalid. chain_driver_a.assert_eventual_wallet_amount( &user_a.address(), - &(balance_a2 + receive_fee + timeout_fee).as_ref(), + &(balance_a - send_amount - ack_fee).as_ref(), )?; chain_driver_a.assert_eventual_wallet_amount( diff --git a/tools/integration-test/src/tests/fee/pay_fee_async.rs b/tools/integration-test/src/tests/fee/pay_fee_async.rs index f62d089ff1..dc8f5a816d 100644 --- a/tools/integration-test/src/tests/fee/pay_fee_async.rs +++ b/tools/integration-test/src/tests/fee/pay_fee_async.rs @@ -105,13 +105,18 @@ impl BinaryChannelTest for PayPacketFeeAsyncTest { &denom_a.with_amount(receive_fee).as_ref(), &denom_a.with_amount(ack_fee).as_ref(), &denom_a.with_amount(timeout_fee).as_ref(), - Duration::from_secs(60), + Duration::from_secs(300), )?; - let total_sent = send_amount + receive_fee + ack_fee + timeout_fee; - let balance_a2 = balance_a1 - total_sent; + let balance_a2 = balance_a1.clone() - send_amount; - chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a2.as_ref())?; + chain_driver_a.assert_eventual_escrowed_amount_ics29( + &user_a.address(), + &balance_a2.clone().as_ref(), + receive_fee, + ack_fee, + timeout_fee, + )?; let sequence = { let send_packet_event = events @@ -207,10 +212,13 @@ impl BinaryChannelTest for PayPacketFeeAsyncTest { &denom_a.with_amount(timeout_fee_2).as_ref(), )?; - let total_sent_2 = receive_fee_2 + ack_fee_2 + timeout_fee_2; - let balance_a3 = balance_a2 - total_sent_2; - - chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a3.as_ref())?; + chain_driver_a.assert_eventual_escrowed_amount_ics29( + &user_a.address(), + &balance_a2.as_ref(), + receive_fee + receive_fee_2, + ack_fee + ack_fee_2, + timeout_fee + timeout_fee_2, + )?; { let event = events2 @@ -259,7 +267,8 @@ impl BinaryChannelTest for PayPacketFeeAsyncTest { chain_driver_a.assert_eventual_wallet_amount( &user_a.address(), - &(balance_a3 + timeout_fee + timeout_fee_2).as_ref(), + &(balance_a1 - send_amount - receive_fee - receive_fee_2 - ack_fee - ack_fee_2) + .as_ref(), )?; chain_driver_a.assert_eventual_wallet_amount( diff --git a/tools/integration-test/src/tests/fee/register_payee.rs b/tools/integration-test/src/tests/fee/register_payee.rs index 0e92dfe4b3..638800c846 100644 --- a/tools/integration-test/src/tests/fee/register_payee.rs +++ b/tools/integration-test/src/tests/fee/register_payee.rs @@ -107,7 +107,7 @@ impl BinaryChannelTest for ForwardRelayerTest { let user_a = wallets_a.user1(); let user_b = wallets_b.user1(); - let balance_a1 = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; + let balance_a = chain_driver_a.query_balance(&user_a.address(), &denom_a)?; let relayer_balance_a = chain_driver_a.query_balance(&relayer_a.address(), &denom_a)?; let payee_balance_a = chain_driver_a.query_balance(&payee_a.address(), &denom_a)?; @@ -117,10 +117,6 @@ impl BinaryChannelTest for ForwardRelayerTest { let ack_fee = random_u128_range(200, 300); let timeout_fee = random_u128_range(100, 200); - let total_sent = send_amount + receive_fee + ack_fee + timeout_fee; - - let balance_a2 = balance_a1 - total_sent; - chain_driver_a.ibc_token_transfer_with_fee( &port_a, &channel_id_a, @@ -139,8 +135,6 @@ impl BinaryChannelTest for ForwardRelayerTest { &denom_a, )?; - chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a2.as_ref())?; - chain_driver_b.assert_eventual_wallet_amount( &user_b.address(), &denom_b.with_amount(send_amount).as_ref(), @@ -148,7 +142,7 @@ impl BinaryChannelTest for ForwardRelayerTest { chain_driver_a.assert_eventual_wallet_amount( &user_a.address(), - &(balance_a2 + timeout_fee).as_ref(), + &(balance_a - send_amount - receive_fee - ack_fee).as_ref(), )?; chain_driver_a.assert_eventual_wallet_amount( diff --git a/tools/integration-test/src/tests/fee/timeout_fee.rs b/tools/integration-test/src/tests/fee/timeout_fee.rs index 1d6131ed89..1d3068db01 100644 --- a/tools/integration-test/src/tests/fee/timeout_fee.rs +++ b/tools/integration-test/src/tests/fee/timeout_fee.rs @@ -72,10 +72,6 @@ impl BinaryChannelTest for TimeoutFeeTest { Duration::from_secs(5), )?; - info!("Expect user A's balance after transfer: {}", balance_a2); - - chain_driver_a.assert_eventual_wallet_amount(&user_a.address(), &balance_a2.as_ref())?; - // Sleep to wait for IBC packet to timeout before start relaying thread::sleep(Duration::from_secs(6)); diff --git a/tools/integration-test/src/tests/fee_grant.rs b/tools/integration-test/src/tests/fee_grant.rs index f12e30a981..a936c02e20 100644 --- a/tools/integration-test/src/tests/fee_grant.rs +++ b/tools/integration-test/src/tests/fee_grant.rs @@ -42,7 +42,7 @@ impl BinaryChannelTest for FeeGrantTest { let denom_a = chains.node_a.denom(); let wallet_a = chains.node_a.wallets().user1().cloned(); let wallet_b = chains.node_b.wallets().user1().cloned(); - let fee_denom_a = MonoTagged::new(Denom::base(&config.native_tokens[0])); + let fee_denom_a = MonoTagged::new(Denom::base(config.native_token(0))); let a_to_b_amount = 12345u64; let granter = chains @@ -185,7 +185,7 @@ impl BinaryChannelTest for NoFeeGrantTest { let wallet_a = chains.node_a.wallets().user1().cloned(); let wallet_a2 = chains.node_a.wallets().user2().cloned(); let wallet_b = chains.node_b.wallets().user1().cloned(); - let fee_denom_a = MonoTagged::new(Denom::base(&config.native_tokens[0])); + let fee_denom_a = MonoTagged::new(Denom::base(config.native_token(0))); let a_to_b_amount = 12345u64; let granter = chains diff --git a/tools/integration-test/src/tests/forward/forward_hop_transfer.rs b/tools/integration-test/src/tests/forward/forward_hop_transfer.rs index 3ae0337aba..f42376c5b7 100644 --- a/tools/integration-test/src/tests/forward/forward_hop_transfer.rs +++ b/tools/integration-test/src/tests/forward/forward_hop_transfer.rs @@ -6,7 +6,7 @@ //! - The `AtomicIbcForwardHopTransferTest` tests the case where the //! hop between chain C and D fails. In this case the sender is still refunded. -use ibc_relayer::config::{self, Config, ModeConfig}; +use ibc_relayer::config::{self, ModeConfig}; use ibc_test_framework::prelude::*; use crate::tests::forward::memo::HopMemoField; @@ -53,7 +53,7 @@ impl NaryChannelTest<4> for IbcForwardHopTransferTest { chains: NaryConnectedChains, channels: NaryConnectedChannels, ) -> Result<(), Error> { - let connected_chains = chains.connected_chains_at::<0, 3>()?; + let connected_chains = chains.connected_chains_at::<0, 1>()?; let node_a = chains.full_node_at::<0>()?; let node_b = chains.full_node_at::<1>()?; @@ -174,7 +174,7 @@ impl NaryChannelTest<4> for AtomicIbcForwardHopTransferTest { chains: NaryConnectedChains, channels: NaryConnectedChannels, ) -> Result<(), Error> { - let connected_chains = chains.connected_chains_at::<0, 3>()?; + let connected_chains = chains.connected_chains_at::<0, 1>()?; let node_a = chains.full_node_at::<0>()?; let node_b = chains.full_node_at::<1>()?; diff --git a/tools/integration-test/src/tests/forward/forward_transfer.rs b/tools/integration-test/src/tests/forward/forward_transfer.rs index 4830ee43b6..a9569c8528 100644 --- a/tools/integration-test/src/tests/forward/forward_transfer.rs +++ b/tools/integration-test/src/tests/forward/forward_transfer.rs @@ -18,7 +18,7 @@ //! the memo fields are misspelled: //! - Misspelled receiver address, port or channel: The intermediary chain will refund the sender. -use ibc_relayer::config::{self, Config, ModeConfig}; +use ibc_relayer::config::{self, ModeConfig}; use ibc_test_framework::prelude::*; use crate::tests::forward::memo::{ @@ -73,7 +73,7 @@ impl NaryChannelTest<3> for IbcForwardTransferTest { chains: NaryConnectedChains, channels: NaryConnectedChannels, ) -> Result<(), Error> { - let connected_chains = chains.connected_chains_at::<0, 2>()?; + let connected_chains = chains.connected_chains_at::<0, 1>()?; let node_a = chains.full_node_at::<0>()?; let node_b = chains.full_node_at::<1>()?; @@ -176,7 +176,7 @@ impl NaryChannelTest<3> for MisspelledMemoFieldsIbcForwardTransferTest { chains: NaryConnectedChains, channels: NaryConnectedChannels, ) -> Result<(), Error> { - let connected_chains = chains.connected_chains_at::<0, 2>()?; + let connected_chains = chains.connected_chains_at::<0, 1>()?; let node_a = chains.full_node_at::<0>()?; let node_b = chains.full_node_at::<1>()?; @@ -422,7 +422,7 @@ impl NaryChannelTest<3> for MisspelledMemoContentIbcForwardTransferTest { chains: NaryConnectedChains, channels: NaryConnectedChannels, ) -> Result<(), Error> { - let connected_chains = chains.connected_chains_at::<0, 2>()?; + let connected_chains = chains.connected_chains_at::<0, 1>()?; let node_a = chains.full_node_at::<0>()?; let node_b = chains.full_node_at::<1>()?; diff --git a/tools/integration-test/src/tests/ica.rs b/tools/integration-test/src/tests/ica.rs index 03d367b675..0fe90d43ad 100644 --- a/tools/integration-test/src/tests/ica.rs +++ b/tools/integration-test/src/tests/ica.rs @@ -1,14 +1,10 @@ use std::collections::HashMap; use std::str::FromStr; -use ibc_relayer::chain::handle::ChainHandle; -use ibc_relayer::chain::tracking::TrackedMsgs; use ibc_relayer::config::{ filter::{ChannelFilters, ChannelPolicy, FilterPattern}, ChainConfig, PacketFilter, }; -use ibc_relayer::event::IbcEventWithHeight; -use ibc_relayer_types::applications::ics27_ica::msgs::send_tx::MsgSendTx; use ibc_relayer_types::applications::ics27_ica::packet_data::InterchainAccountPacketData; use ibc_relayer_types::applications::{ ics27_ica::cosmos_tx::CosmosTx, @@ -20,12 +16,15 @@ use ibc_relayer_types::signer::Signer; use ibc_relayer_types::timestamp::Timestamp; use ibc_relayer_types::tx_msg::Msg; -use ibc_test_framework::chain::ext::ica::register_interchain_account; -use ibc_test_framework::ibc::denom::Denom; +use ibc_test_framework::chain::{ + config::add_allow_message_interchainaccounts, + ext::ica::{register_ordered_interchain_account, register_unordered_interchain_account}, +}; use ibc_test_framework::prelude::*; use ibc_test_framework::relayer::channel::{ assert_eventually_channel_closed, assert_eventually_channel_established, query_channel_end, }; +use ibc_test_framework::util::interchain_security::interchain_send_tx; #[test] fn test_ica_filter_default() -> Result<(), Error> { @@ -48,6 +47,7 @@ fn test_ica_filter_deny() -> Result<(), Error> { run_binary_connection_test(&IcaFilterTestDeny) } +#[cfg(any(doc, feature = "new-register-interchain-account"))] #[test] fn test_ica_close_channel() -> Result<(), Error> { run_binary_connection_test(&ICACloseChannelTest) @@ -67,6 +67,7 @@ impl TestOverrides for IcaFilterTestAllow { // Enable channel workers and allow relaying on ICA channels fn modify_relayer_config(&self, config: &mut Config) { config.mode.channels.enabled = true; + config.mode.clients.misbehaviour = false; for chain in &mut config.chains { match chain { @@ -79,37 +80,26 @@ impl TestOverrides for IcaFilterTestAllow { // Allow MsgSend messages over ICA fn modify_genesis_file(&self, genesis: &mut serde_json::Value) -> Result<(), Error> { - use serde_json::Value; - - let allow_messages = genesis - .get_mut("app_state") - .and_then(|app_state| app_state.get_mut("interchainaccounts")) - .and_then(|ica| ica.get_mut("host_genesis_state")) - .and_then(|state| state.get_mut("params")) - .and_then(|params| params.get_mut("allow_messages")) - .and_then(|allow_messages| allow_messages.as_array_mut()); - - if let Some(allow_messages) = allow_messages { - allow_messages.push(Value::String("/cosmos.bank.v1beta1.MsgSend".to_string())); - Ok(()) - } else { - Err(Error::generic(eyre!("failed to update genesis file"))) - } + add_allow_message_interchainaccounts(genesis, "/cosmos.bank.v1beta1.MsgSend")?; + + Ok(()) } } impl BinaryConnectionTest for IcaFilterTestAllow { fn run( &self, - _config: &TestConfig, + config: &TestConfig, _relayer: RelayerDriver, chains: ConnectedChains, connection: ConnectedConnection, ) -> Result<(), Error> { + let fee_denom_host: MonoTagged = + MonoTagged::new(Denom::base(config.native_token(1))); // Register an interchain account on behalf of // controller wallet `user1` where the counterparty chain is the interchain accounts host. let (wallet, channel_id, port_id) = - register_interchain_account(&chains.node_a, chains.handle_a(), &connection)?; + register_unordered_interchain_account(&chains.node_a, chains.handle_a(), &connection)?; // Check that the corresponding ICA channel is eventually established. let _counterparty_channel_id = assert_eventually_channel_established( @@ -139,6 +129,7 @@ impl BinaryConnectionTest for IcaFilterTestAllow { &chains.node_b.wallets().user1(), &ica_address.as_ref(), &stake_denom.with_amount(ica_fund).as_ref(), + &fee_denom_host.with_amount(381000000u64).as_ref(), )?; chains.node_b.chain_driver().assert_eventual_wallet_amount( @@ -187,6 +178,7 @@ impl BinaryConnectionTest for IcaFilterTestAllow { Ok(()) } } + pub struct IcaFilterTestDeny; impl TestOverrides for IcaFilterTestDeny { @@ -219,7 +211,7 @@ impl BinaryConnectionTest for IcaFilterTestDeny { // Register an interchain account on behalf of controller wallet `user1` // where the counterparty chain is the interchain accounts host. let (_, channel_id, port_id) = - register_interchain_account(&chains.node_a, chains.handle_a(), &connection)?; + register_unordered_interchain_account(&chains.node_a, chains.handle_a(), &connection)?; // Wait a bit, the relayer will refuse to complete the channel handshake // because the port is explicitly disallowed by the filter. @@ -254,18 +246,24 @@ impl TestOverrides for ICACloseChannelTest { impl BinaryConnectionTest for ICACloseChannelTest { fn run( &self, - _config: &TestConfig, + config: &TestConfig, relayer: RelayerDriver, chains: ConnectedChains, connection: ConnectedConnection, ) -> Result<(), Error> { + let fee_denom_host: MonoTagged = + MonoTagged::new(Denom::base(config.native_token(1))); let stake_denom: MonoTagged = MonoTagged::new(Denom::base("stake")); let (wallet, ica_address, controller_channel_id, controller_port_id) = relayer .with_supervisor(|| { // Register an interchain account on behalf of // controller wallet `user1` where the counterparty chain is the interchain accounts host. let (wallet, controller_channel_id, controller_port_id) = - register_interchain_account(&chains.node_a, chains.handle_a(), &connection)?; + register_ordered_interchain_account( + &chains.node_a, + chains.handle_a(), + &connection, + )?; // Check that the corresponding ICA channel is eventually established. let _counterparty_channel_id = assert_eventually_channel_established( @@ -301,6 +299,7 @@ impl BinaryConnectionTest for ICACloseChannelTest { &chains.node_b.wallets().user1(), &ica_address.as_ref(), &stake_denom.with_amount(ica_fund).as_ref(), + &fee_denom_host.with_amount(381000000u64).as_ref(), )?; chains.node_b.chain_driver().assert_eventual_wallet_amount( @@ -373,26 +372,3 @@ impl BinaryConnectionTest for ICACloseChannelTest { }) } } - -fn interchain_send_tx( - chain: &ChainA, - from: &Signer, - connection: &ConnectionId, - msg: InterchainAccountPacketData, - relative_timeout: Timestamp, -) -> Result, Error> { - let msg = MsgSendTx { - owner: from.clone(), - connection_id: connection.clone(), - packet_data: msg, - relative_timeout, - }; - - let msg_any = msg.to_any(); - - let tm = TrackedMsgs::new_static(vec![msg_any], "SendTx"); - - chain - .send_messages_and_wait_commit(tm) - .map_err(Error::relayer) -} diff --git a/tools/integration-test/src/tests/interchain_security/dynamic_gas_fee.rs b/tools/integration-test/src/tests/interchain_security/dynamic_gas_fee.rs new file mode 100644 index 0000000000..3d2f217554 --- /dev/null +++ b/tools/integration-test/src/tests/interchain_security/dynamic_gas_fee.rs @@ -0,0 +1,255 @@ +//! The [`DynamicGasTest`] test ensures that the [`DynamicGas`] +//! configuration works correctly. The test can enable or disable the dynamic +//! gas price for the second chain. +//! +//! To test dynamic gas configuration, it will enable dynamic gas price on the +//! second chain only. It will then create and relay a first IBC transfer with a +//! big memo. The gas fee paid is then recorded. +//! A second IBC transfer without memo will then be relayed. The gas fee paid +//! will also be recorded. The test will assert that the Tx with a big memo +//! and dynamic gas enabled is lower than the Tx without memo and dynamic gas +//! disabled. +//! +//! The second test disables the dynamic gas price on both chains in +//! order to ensure that the first IBC transfer will cost more if dynamic +//! gas is disabled. + +use ibc_relayer::config::dynamic_gas::DynamicGasPrice; +use ibc_relayer::config::gas_multiplier::GasMultiplier; +use ibc_relayer::config::ChainConfig; +use ibc_relayer::config::GasPrice; +use ibc_test_framework::framework::binary::channel::run_binary_interchain_security_channel_test; +use ibc_test_framework::prelude::*; +use ibc_test_framework::util::interchain_security::update_genesis_for_consumer_chain; +use ibc_test_framework::util::interchain_security::update_relayer_config_for_consumer_chain; + +#[test] +fn test_fee_market_dynamic_gas_transfer() -> Result<(), Error> { + run_binary_interchain_security_channel_test(&DynamicGasTest { + dynamic_gas_enabled: true, + }) +} + +#[test] +fn test_fee_market_static_gas_transfer() -> Result<(), Error> { + run_binary_interchain_security_channel_test(&DynamicGasTest { + dynamic_gas_enabled: false, + }) +} + +const MEMO_CHAR: &str = "a"; +const MEMO_SIZE: usize = 10000; + +pub struct DynamicGasTest { + dynamic_gas_enabled: bool, +} + +impl TestOverrides for DynamicGasTest { + fn modify_genesis_file(&self, genesis: &mut serde_json::Value) -> Result<(), Error> { + update_genesis_for_consumer_chain(genesis)?; + // This is a configuration specifically for chains with feemarket + if genesis + .get_mut("app_state") + .and_then(|app_state| app_state.get("feemarket")) + .is_some() + { + let params = genesis + .get_mut("app_state") + .and_then(|app_state| app_state.get_mut("feemarket")) + .and_then(|feemarket| feemarket.get_mut("params")) + .and_then(|params| params.as_object_mut()) + .ok_or_else(|| eyre!("failed to get feemarket params in genesis file"))?; + params.insert( + "min_base_fee".to_owned(), + serde_json::Value::String("0.0025".to_owned()), + ); + } + + Ok(()) + } + + // The `ccv_consumer_chain` must be `true` for the Consumer chain. + // The `trusting_period` must be strictly smaller than the `unbonding_period` + // specified in the Consumer chain proposal. The test framework uses 100s in + // the proposal. + fn modify_relayer_config(&self, config: &mut Config) { + config.mode.clients.misbehaviour = false; + config.mode.clients.refresh = false; + config.mode.packets.clear_interval = 0; + + update_relayer_config_for_consumer_chain(config); + + match &mut config.chains[0] { + ChainConfig::CosmosSdk(chain_config_a) => { + chain_config_a.gas_price = + GasPrice::new(0.3, chain_config_a.gas_price.denom.clone()); + + chain_config_a.dynamic_gas_price = DynamicGasPrice::unsafe_new(false, 1.1, 0.6); + } + } + + match &mut config.chains[1] { + ChainConfig::CosmosSdk(chain_config_b) => { + chain_config_b.gas_price = + GasPrice::new(0.3, chain_config_b.gas_price.denom.clone()); + + chain_config_b.gas_multiplier = Some(GasMultiplier::unsafe_new(1.8)); + + chain_config_b.dynamic_gas_price = + DynamicGasPrice::unsafe_new(self.dynamic_gas_enabled, 1.1, 0.6); + } + } + } + + fn should_spawn_supervisor(&self) -> bool { + false + } +} + +impl BinaryChannelTest for DynamicGasTest { + fn run( + &self, + _config: &TestConfig, + relayer: RelayerDriver, + chains: ConnectedChains, + channel: ConnectedChannel, + ) -> Result<(), Error> { + let denom_a = chains.node_a.denom(); + let wallet_a = chains.node_a.wallets().user1().cloned(); + let wallet_b = chains.node_b.wallets().user1().cloned(); + + let a_to_b_amount = 12345u64; + + let denom_a_to_b = derive_ibc_denom( + &channel.port_b.as_ref(), + &channel.channel_id_b.as_ref(), + &denom_a, + )?; + + let gas_denom_a: MonoTagged = + MonoTagged::new(Denom::Base("stake".to_owned())); + let gas_denom_b: MonoTagged = + MonoTagged::new(Denom::Base("stake".to_owned())); + + let balance_relayer_b_before = chains.node_b.chain_driver().query_balance( + &chains.node_b.wallets().relayer().address(), + &gas_denom_b.as_ref(), + )?; + + let memo: String = MEMO_CHAR.repeat(MEMO_SIZE); + + chains + .node_a + .chain_driver() + .ibc_transfer_token_with_memo_and_timeout( + &channel.port_a.as_ref(), + &channel.channel_id_a.as_ref(), + &wallet_a.as_ref(), + &wallet_b.address(), + &denom_a.with_amount(a_to_b_amount).as_ref(), + Some(memo), + None, + )?; + + // Do a simple IBC transfer with the dynamic gas configuration + let tx1_paid_gas_relayer = relayer.with_supervisor(|| { + // Assert that user on chain B received the tokens + chains.node_b.chain_driver().assert_eventual_wallet_amount( + &wallet_b.address(), + &denom_a_to_b.with_amount(a_to_b_amount).as_ref(), + )?; + + // Wait for a bit before querying the new balance + sleep(Duration::from_secs(5)); + + let balance_relayer_b_after = chains.node_b.chain_driver().query_balance( + &chains.node_b.wallets().relayer().address(), + &gas_denom_b.as_ref(), + )?; + + let paid_fees_relayer_b = balance_relayer_b_before + .amount() + .checked_sub(balance_relayer_b_after.amount()); + + assert!( + paid_fees_relayer_b.is_some(), + "subtraction between queried amounts for relayer should be Some" + ); + + info!("IBC transfer with memo was successful"); + + Ok(paid_fees_relayer_b.unwrap()) + })?; + + let b_to_a_amount = 23456u64; + let denom_b = chains.node_b.denom(); + + let denom_b_to_a = derive_ibc_denom( + &channel.port_a.as_ref(), + &channel.channel_id_a.as_ref(), + &denom_b, + )?; + + let balance_relayer_a_before = chains.node_a.chain_driver().query_balance( + &chains.node_a.wallets().relayer().address(), + &gas_denom_a.as_ref(), + )?; + + info!("Will ibc transfer"); + + chains.node_b.chain_driver().ibc_transfer_token( + &channel.port_b.as_ref(), + &channel.channel_id_b.as_ref(), + &chains.node_b.wallets().user1(), + &chains.node_a.wallets().user1().address(), + &denom_b.with_amount(b_to_a_amount).as_ref(), + )?; + + info!("Done ibc transfer"); + + let tx2_paid_gas_relayer = relayer.with_supervisor(|| { + // Assert that user on chain B received the tokens + chains.node_a.chain_driver().assert_eventual_wallet_amount( + &chains.node_a.wallets().user1().address(), + &denom_b_to_a.with_amount(b_to_a_amount).as_ref(), + )?; + + // Wait for a bit before querying the new balance + sleep(Duration::from_secs(5)); + + let balance_relayer_a_after = chains.node_a.chain_driver().query_balance( + &chains.node_a.wallets().relayer().address(), + &gas_denom_a.as_ref(), + )?; + + let paid_fees_relayer_a = balance_relayer_a_before + .amount() + .checked_sub(balance_relayer_a_after.amount()); + + assert!( + paid_fees_relayer_a.is_some(), + "subtraction between queried amounts for relayer should be Some" + ); + + info!("IBC transfer without memo was successful"); + + Ok(paid_fees_relayer_a.unwrap()) + })?; + + info!("paid gas fees for Tx with memo `{tx1_paid_gas_relayer}`, without memo `{tx2_paid_gas_relayer}`"); + + if self.dynamic_gas_enabled { + assert!( + tx1_paid_gas_relayer < tx2_paid_gas_relayer, + "with dynamic gas enabled, gas paid for the first TX should be lower" + ); + } else { + assert!( + tx1_paid_gas_relayer > tx2_paid_gas_relayer, + "with dynamic gas disabled, gas paid for the second TX should be lower" + ); + } + + Ok(()) + } +} diff --git a/tools/integration-test/src/tests/interchain_security/ica_ordered_channel.rs b/tools/integration-test/src/tests/interchain_security/ica_ordered_channel.rs new file mode 100644 index 0000000000..7498d724f2 --- /dev/null +++ b/tools/integration-test/src/tests/interchain_security/ica_ordered_channel.rs @@ -0,0 +1,217 @@ +//! Verifies the behaviour of ordered channels with Interchain Accounts. +//! +//! In order to ensure that ordered channels correctly clear packets on ICA +//! channels, this test sends some sequential packets with the supervisor enabled, +//! sends the next packet *without* the supervisor enabled, then sends additional +//! packets with the supervisor enabled again. The pending packet that was sent +//! without the supervisor enabled should be relayed in order along with the +//! other packets, as expected of ordered channel behaviour. + +use std::str::FromStr; + +use ibc_relayer_types::applications::ics27_ica::cosmos_tx::CosmosTx; +use ibc_relayer_types::applications::ics27_ica::packet_data::InterchainAccountPacketData; +use ibc_relayer_types::applications::transfer::msgs::send::MsgSend; +use ibc_relayer_types::applications::transfer::{Amount, Coin}; +use ibc_relayer_types::bigint::U256; +use ibc_relayer_types::signer::Signer; +use ibc_relayer_types::timestamp::Timestamp; +use ibc_relayer_types::tx_msg::Msg; +use ibc_test_framework::chain::config::add_allow_message_interchainaccounts; +use ibc_test_framework::chain::ext::ica::register_ordered_interchain_account; +use ibc_test_framework::framework::binary::channel::run_binary_interchain_security_channel_test; +use ibc_test_framework::prelude::*; +use ibc_test_framework::relayer::channel::assert_eventually_channel_established; +use ibc_test_framework::relayer::channel::query_channel_end; +use ibc_test_framework::util::interchain_security::{ + interchain_send_tx, update_genesis_for_consumer_chain, update_relayer_config_for_consumer_chain, +}; + +#[test] +fn test_ica_ordered_channel() -> Result<(), Error> { + run_binary_interchain_security_channel_test(&IcaOrderedChannelTest) +} + +struct IcaOrderedChannelTest; + +impl TestOverrides for IcaOrderedChannelTest { + fn modify_genesis_file(&self, genesis: &mut serde_json::Value) -> Result<(), Error> { + add_allow_message_interchainaccounts(genesis, "/cosmos.bank.v1beta1.MsgSend")?; + update_genesis_for_consumer_chain(genesis)?; + + Ok(()) + } + + fn modify_relayer_config(&self, config: &mut Config) { + config.mode.clients.misbehaviour = false; + + config.mode.channels.enabled = true; + + // Disable packet clearing so that packets sent without the supervisor + // enabled enter a pending state. + config.mode.packets.enabled = true; + config.mode.packets.clear_on_start = false; + config.mode.packets.clear_interval = 0; + // This is needed for ordered channels + config.mode.packets.force_disable_clear_on_start = true; + + update_relayer_config_for_consumer_chain(config); + } + + fn should_spawn_supervisor(&self) -> bool { + false + } +} + +impl BinaryChannelTest for IcaOrderedChannelTest { + fn run( + &self, + config: &TestConfig, + relayer: RelayerDriver, + chains: ConnectedChains, + channel: ConnectedChannel, + ) -> Result<(), Error> { + let fee_denom_a: MonoTagged = + MonoTagged::new(Denom::base(config.native_token(0))); + let connection_b_to_a = channel.connection.clone().flip(); + let (wallet, channel_id, port_id) = register_ordered_interchain_account( + &chains.node_b, + chains.handle_b(), + &connection_b_to_a, + )?; + + relayer.with_supervisor(|| { + // Check that the corresponding ICA channel is eventually established. + let _counterparty_channel_id = assert_eventually_channel_established( + chains.handle_b(), + chains.handle_a(), + &channel_id.as_ref(), + &port_id.as_ref(), + )?; + + Ok(()) + })?; + + // Assert that the channel returned by `register_interchain_account` is an ordered channel + let channel_end = + query_channel_end(chains.handle_b(), &channel_id.as_ref(), &port_id.as_ref())?; + + assert_eq!(channel_end.value().ordering(), &Ordering::Ordered); + + // Query the controller chain for the address of the ICA wallet on the host chain. + let ica_address = chains.node_b.chain_driver().query_interchain_account( + &wallet.address(), + &channel.connection.connection_id_b.as_ref(), + )?; + + let stake_denom: MonoTagged = MonoTagged::new(Denom::base("stake")); + + chains.node_a.chain_driver().assert_eventual_wallet_amount( + &ica_address.as_ref(), + &stake_denom.with_amount(0u64).as_ref(), + )?; + + // Send funds to the interchain account. + let ica_fund = 42000u64; + + chains.node_a.chain_driver().local_transfer_token( + &chains.node_a.wallets().user1(), + &ica_address.as_ref(), + &stake_denom.with_amount(ica_fund).as_ref(), + &fee_denom_a.with_amount(381000000u64).as_ref(), + )?; + + chains.node_a.chain_driver().assert_eventual_wallet_amount( + &ica_address.as_ref(), + &stake_denom.with_amount(ica_fund).as_ref(), + )?; + + let amount = 1200; + + let msg = MsgSend { + from_address: ica_address.to_string(), + to_address: chains.node_a.wallets().user2().address().to_string(), + amount: vec![Coin { + denom: stake_denom.to_string(), + amount: Amount(U256::from(amount)), + }], + }; + + let raw_msg = msg.to_any(); + + let cosmos_tx = CosmosTx { + messages: vec![raw_msg], + }; + + let raw_cosmos_tx = cosmos_tx.to_any(); + + let interchain_account_packet_data = InterchainAccountPacketData::new(raw_cosmos_tx.value); + + let signer = Signer::from_str(&wallet.address().to_string()).unwrap(); + + let user2_balance = chains.node_a.chain_driver().query_balance( + &chains.node_a.wallets().user2().address(), + &stake_denom.as_ref(), + )?; + + relayer.with_supervisor(|| { + let ica_events = interchain_send_tx( + chains.handle_b(), + &signer, + &channel.connection.connection_id_b.0, + interchain_account_packet_data.clone(), + Timestamp::from_nanoseconds(120000000000).unwrap(), + )?; + + // Check that the ICA account's balance has been debited the sent amount. + chains.node_a.chain_driver().assert_eventual_wallet_amount( + &ica_address.as_ref(), + &stake_denom.with_amount(ica_fund - amount).as_ref(), + )?; + + chains.node_a.chain_driver().assert_eventual_wallet_amount( + &chains.node_a.wallets().user2().address(), + &(user2_balance.clone() + amount).as_ref(), + )?; + + info!("First ICA transfer made with supervisor: {ica_events:#?}"); + + Ok(()) + })?; + + let ica_events = interchain_send_tx( + chains.handle_b(), + &signer, + &channel.connection.connection_id_b.0, + interchain_account_packet_data.clone(), + Timestamp::from_nanoseconds(120000000000).unwrap(), + )?; + + info!("Second ICA transfer made without supervisor: {ica_events:#?}"); + + relayer.with_supervisor(|| { + let ica_events = interchain_send_tx( + chains.handle_b(), + &signer, + &channel.connection.connection_id_b.0, + interchain_account_packet_data, + Timestamp::from_nanoseconds(120000000000).unwrap(), + )?; + + // Check that the ICA account's balance has been debited the sent amount. + chains.node_a.chain_driver().assert_eventual_wallet_amount( + &ica_address.as_ref(), + &stake_denom.with_amount(ica_fund - 3 * amount).as_ref(), + )?; + + info!("Third ICA transfer made with supervisor: {ica_events:#?}"); + + chains.node_a.chain_driver().assert_eventual_wallet_amount( + &chains.node_a.wallets().user2().address(), + &(user2_balance + (3 * amount)).as_ref(), + )?; + + Ok(()) + }) + } +} diff --git a/tools/integration-test/src/tests/interchain_security/ica_transfer.rs b/tools/integration-test/src/tests/interchain_security/ica_transfer.rs index fc44ff7fd2..ec12f6b591 100644 --- a/tools/integration-test/src/tests/interchain_security/ica_transfer.rs +++ b/tools/integration-test/src/tests/interchain_security/ica_transfer.rs @@ -3,10 +3,7 @@ //! the second chain a Consumer chain. use std::str::FromStr; -use ibc_relayer::chain::tracking::TrackedMsgs; -use ibc_relayer::event::IbcEventWithHeight; use ibc_relayer_types::applications::ics27_ica::cosmos_tx::CosmosTx; -use ibc_relayer_types::applications::ics27_ica::msgs::send_tx::MsgSendTx; use ibc_relayer_types::applications::ics27_ica::packet_data::InterchainAccountPacketData; use ibc_relayer_types::applications::transfer::msgs::send::MsgSend; use ibc_relayer_types::applications::transfer::{Amount, Coin}; @@ -14,12 +11,13 @@ use ibc_relayer_types::bigint::U256; use ibc_relayer_types::signer::Signer; use ibc_relayer_types::timestamp::Timestamp; use ibc_relayer_types::tx_msg::Msg; -use ibc_test_framework::chain::ext::ica::register_interchain_account; +use ibc_test_framework::chain::config::add_allow_message_interchainaccounts; +use ibc_test_framework::chain::ext::ica::register_unordered_interchain_account; use ibc_test_framework::framework::binary::channel::run_binary_interchain_security_channel_test; use ibc_test_framework::prelude::*; use ibc_test_framework::relayer::channel::assert_eventually_channel_established; use ibc_test_framework::util::interchain_security::{ - update_genesis_for_consumer_chain, update_relayer_config_for_consumer_chain, + interchain_send_tx, update_genesis_for_consumer_chain, update_relayer_config_for_consumer_chain, }; #[test] @@ -31,23 +29,7 @@ struct InterchainSecurityIcaTransferTest; impl TestOverrides for InterchainSecurityIcaTransferTest { fn modify_genesis_file(&self, genesis: &mut serde_json::Value) -> Result<(), Error> { - use serde_json::Value; - - // Allow MsgSend messages over ICA - let allow_messages = genesis - .get_mut("app_state") - .and_then(|app_state| app_state.get_mut("interchainaccounts")) - .and_then(|ica| ica.get_mut("host_genesis_state")) - .and_then(|state| state.get_mut("params")) - .and_then(|params| params.get_mut("allow_messages")) - .and_then(|allow_messages| allow_messages.as_array_mut()); - - if let Some(allow_messages) = allow_messages { - allow_messages.push(Value::String("/cosmos.bank.v1beta1.MsgSend".to_string())); - } else { - return Err(Error::generic(eyre!("failed to update genesis file"))); - } - + add_allow_message_interchainaccounts(genesis, "/cosmos.bank.v1beta1.MsgSend")?; update_genesis_for_consumer_chain(genesis)?; Ok(()) @@ -67,14 +49,19 @@ impl TestOverrides for InterchainSecurityIcaTransferTest { impl BinaryChannelTest for InterchainSecurityIcaTransferTest { fn run( &self, - _config: &TestConfig, + config: &TestConfig, _relayer: RelayerDriver, chains: ConnectedChains, channel: ConnectedChannel, ) -> Result<(), Error> { + let fee_denom_a: MonoTagged = + MonoTagged::new(Denom::base(config.native_token(0))); let connection_b_to_a = channel.connection.clone().flip(); - let (wallet, channel_id, port_id) = - register_interchain_account(&chains.node_b, chains.handle_b(), &connection_b_to_a)?; + let (wallet, channel_id, port_id) = register_unordered_interchain_account( + &chains.node_b, + chains.handle_b(), + &connection_b_to_a, + )?; // Check that the corresponding ICA channel is eventually established. let _counterparty_channel_id = assert_eventually_channel_established( @@ -104,6 +91,7 @@ impl BinaryChannelTest for InterchainSecurityIcaTransferTest { &chains.node_a.wallets().user1(), &ica_address.as_ref(), &stake_denom.with_amount(ica_fund).as_ref(), + &fee_denom_a.with_amount(381000000u64).as_ref(), )?; chains.node_a.chain_driver().assert_eventual_wallet_amount( @@ -151,29 +139,7 @@ impl BinaryChannelTest for InterchainSecurityIcaTransferTest { &ica_address.as_ref(), &stake_denom.with_amount(ica_fund - amount).as_ref(), )?; + Ok(()) } } - -fn interchain_send_tx( - chain: &ChainA, - from: &Signer, - connection: &ConnectionId, - msg: InterchainAccountPacketData, - relative_timeout: Timestamp, -) -> Result, Error> { - let msg = MsgSendTx { - owner: from.clone(), - connection_id: connection.clone(), - packet_data: msg, - relative_timeout, - }; - - let msg_any = msg.to_any(); - - let tm = TrackedMsgs::new_static(vec![msg_any], "SendTx"); - - chain - .send_messages_and_wait_commit(tm) - .map_err(Error::relayer) -} diff --git a/tools/integration-test/src/tests/interchain_security/icq.rs b/tools/integration-test/src/tests/interchain_security/icq.rs index d1fde8a0c9..19f2a84efb 100644 --- a/tools/integration-test/src/tests/interchain_security/icq.rs +++ b/tools/integration-test/src/tests/interchain_security/icq.rs @@ -9,31 +9,36 @@ //! The test then waits for a Cross-chain Query to be pending and //! then processed. -use ibc_relayer::config::{self, ModeConfig}; - +use ibc_relayer::config::ChainConfig; +use ibc_test_framework::chain::cli::host_zone::register_host_zone; +use ibc_test_framework::chain::config::{ + set_crisis_denom, set_mint_mint_denom, set_staking_bond_denom, set_staking_max_entries, + set_voting_period, +}; +use ibc_test_framework::chain::ext::crosschainquery::CrossChainQueryMethodsExt; +use ibc_test_framework::framework::binary::channel::run_binary_interchain_security_channel_test; use ibc_test_framework::prelude::*; +use ibc_test_framework::relayer::channel::{ + assert_eventually_channel_established, query_identified_channel_ends, +}; use ibc_test_framework::util::interchain_security::{ update_genesis_for_consumer_chain, update_relayer_config_for_consumer_chain, }; use ibc_test_framework::util::random::random_u128_range; -use ibc_test_framework::{ - chain::{ - cli::host_zone::register_host_zone, - config::{ - set_crisis_denom, set_mint_mint_denom, set_staking_bond_denom, set_staking_max_entries, - set_voting_period, - }, - ext::crosschainquery::CrossChainQueryMethodsExt, - }, - framework::binary::channel::run_binary_interchain_security_channel_test, -}; #[test] fn test_ics31_cross_chain_queries() -> Result<(), Error> { - run_binary_interchain_security_channel_test(&InterchainSecurityIcqTest) + run_binary_interchain_security_channel_test(&InterchainSecurityIcqTest { allow_ccq: true }) +} + +#[test] +fn test_disable_ics31_cross_chain_queries() -> Result<(), Error> { + run_binary_interchain_security_channel_test(&InterchainSecurityIcqTest { allow_ccq: false }) } -struct InterchainSecurityIcqTest; +struct InterchainSecurityIcqTest { + pub allow_ccq: bool, +} impl TestOverrides for InterchainSecurityIcqTest { fn modify_genesis_file(&self, genesis: &mut serde_json::Value) -> Result<(), Error> { @@ -54,7 +59,14 @@ impl TestOverrides for InterchainSecurityIcqTest { .get_mut("duration") .ok_or_else(|| eyre!("failed to get duration"))?; - *duration = serde_json::Value::String("20s".to_owned()); + *duration = serde_json::Value::String("25s".to_owned()); + } else if identifier.as_str() == Some("day") { + // The stride epoch must be 1/4th the length of the day epoch + let duration = v + .get_mut("duration") + .ok_or_else(|| eyre!("failed to get duration"))?; + + *duration = serde_json::Value::String("100s".to_owned()); } } set_voting_period(genesis, 10)?; @@ -72,13 +84,19 @@ impl TestOverrides for InterchainSecurityIcqTest { // When calling `strided tx stakeibc register-host-zone` new channel // will be created. So the channel worker needs to be enabled. fn modify_relayer_config(&self, config: &mut Config) { - config.mode = ModeConfig { - connections: config::Connections { enabled: false }, - channels: config::Channels { enabled: true }, - ..Default::default() - }; + config.mode.clients.misbehaviour = false; + config.mode.connections.enabled = true; + config.mode.channels.enabled = true; update_relayer_config_for_consumer_chain(config); + + for chain in config.chains.iter_mut() { + match chain { + ChainConfig::CosmosSdk(chain_config) => { + chain_config.allow_ccq = self.allow_ccq; + } + } + } } } @@ -139,6 +157,33 @@ impl BinaryChannelTest for InterchainSecurityIcqTest { &wallet_b.0.id.to_string(), )?; + // Wait for channel to initialise so that the query can find + // all the channels related to registering a host-zone + std::thread::sleep(Duration::from_secs(5)); + + let channels = query_identified_channel_ends::(chains.handle_a())?; + + // Wait for channel created by registering a host-zone to be Open + for channel in channels.iter() { + let tagged_channel_id: TaggedChannelId = + DualTagged::new(channel.0.channel_id.clone()); + let tagged_port_id: TaggedPortId = + DualTagged::new(channel.0.port_id.clone()); + + if channel.0.port_id.as_str() == "icahost" { + info!( + "Will assert that channel {}/{} is eventually Open", + channel.0.channel_id, channel.0.port_id + ); + assert_eventually_channel_established( + chains.handle_a(), + chains.handle_b(), + &tagged_channel_id.as_ref(), + &tagged_port_id.as_ref(), + )?; + } + } + // Wait for the cross chain query to be pending. chains .node_b @@ -146,10 +191,17 @@ impl BinaryChannelTest for InterchainSecurityIcqTest { .assert_pending_cross_chain_query()?; // After there is a pending cross chain query, wait for it to be processed - chains + let processed_ccqs = chains .node_b .chain_driver() - .assert_processed_cross_chain_query()?; + .assert_processed_cross_chain_query(); + + if self.allow_ccq { + assert!(processed_ccqs.is_ok()); + } else { + assert!(processed_ccqs.is_err()); + } + Ok(()) } } diff --git a/tools/integration-test/src/tests/interchain_security/mod.rs b/tools/integration-test/src/tests/interchain_security/mod.rs index a2acc74d92..6081fc7e53 100644 --- a/tools/integration-test/src/tests/interchain_security/mod.rs +++ b/tools/integration-test/src/tests/interchain_security/mod.rs @@ -1,3 +1,7 @@ +#[cfg(any(doc, feature = "dynamic-gas-fee"))] +pub mod dynamic_gas_fee; +#[cfg(any(doc, feature = "ica"))] +pub mod ica_ordered_channel; #[cfg(any(doc, feature = "ica"))] pub mod ica_transfer; #[cfg(any(doc, feature = "ics31"))] diff --git a/tools/integration-test/src/tests/manual/simulation.rs b/tools/integration-test/src/tests/manual/simulation.rs index 71feb2ad6d..30c801bfcf 100644 --- a/tools/integration-test/src/tests/manual/simulation.rs +++ b/tools/integration-test/src/tests/manual/simulation.rs @@ -11,8 +11,7 @@ ``` */ -use core::time::Duration; -use ibc_relayer::config::{types::MaxMsgNum, ChainConfig, Config}; +use ibc_relayer::config::{types::MaxMsgNum, ChainConfig}; use ibc_relayer::transfer::{build_and_send_transfer_messages, TransferOptions}; use ibc_relayer_types::events::IbcEvent; use ibc_test_framework::prelude::*; diff --git a/tools/integration-test/src/tests/memo.rs b/tools/integration-test/src/tests/memo.rs index 2b44b90d48..cf59bb712d 100644 --- a/tools/integration-test/src/tests/memo.rs +++ b/tools/integration-test/src/tests/memo.rs @@ -4,14 +4,15 @@ //! You can find a more thorough walkthrough of this test at //! `tools/test-framework/src/docs/walkthroughs/memo.rs`. +use ibc_relayer::config::types::Memo; use ibc_relayer::config::ChainConfig; -use ibc_relayer::config::{types::Memo, Config}; use serde_json as json; -use ibc_test_framework::ibc::denom::derive_ibc_denom; use ibc_test_framework::prelude::*; use ibc_test_framework::util::random::{random_string, random_u128_range}; +const OVERWRITE_MEMO: &str = "Overwritten memo"; + #[test] fn test_memo() -> Result<(), Error> { let memo = Memo::new(random_string()).unwrap(); @@ -19,6 +20,13 @@ fn test_memo() -> Result<(), Error> { run_binary_channel_test(&test) } +#[test] +fn test_memo_overwrite() -> Result<(), Error> { + let memo = Memo::new(random_string()).unwrap(); + let test = MemoOverwriteTest { memo }; + run_binary_channel_test(&test) +} + pub struct MemoTest { memo: Memo, } @@ -82,6 +90,70 @@ impl BinaryChannelTest for MemoTest { } } +pub struct MemoOverwriteTest { + memo: Memo, +} + +impl TestOverrides for MemoOverwriteTest { + fn modify_relayer_config(&self, config: &mut Config) { + for chain in config.chains.iter_mut() { + match chain { + ChainConfig::CosmosSdk(chain_config) => { + chain_config.memo_prefix = self.memo.clone(); + chain_config.memo_overwrite = Some(Memo::new(OVERWRITE_MEMO).unwrap()) + } + } + } + } +} + +impl BinaryChannelTest for MemoOverwriteTest { + fn run( + &self, + _config: &TestConfig, + _relayer: RelayerDriver, + chains: ConnectedChains, + channel: ConnectedChannel, + ) -> Result<(), Error> { + info!( + "testing IBC transfer with memo configured: \"{}\"", + self.memo + ); + + let denom_a = chains.node_a.denom(); + + let a_to_b_amount = random_u128_range(1000, 5000); + + chains.node_a.chain_driver().ibc_transfer_token( + &channel.port_a.as_ref(), + &channel.channel_id_a.as_ref(), + &chains.node_a.wallets().user1(), + &chains.node_b.wallets().user1().address(), + &denom_a.with_amount(a_to_b_amount).as_ref(), + )?; + + let denom_b = derive_ibc_denom( + &channel.port_b.as_ref(), + &channel.channel_id_b.as_ref(), + &denom_a, + )?; + + chains.node_b.chain_driver().assert_eventual_wallet_amount( + &chains.node_b.wallets().user1().address(), + &denom_b.with_amount(a_to_b_amount).as_ref(), + )?; + + let tx_info = chains + .node_b + .chain_driver() + .query_recipient_transactions(&chains.node_b.wallets().user1().address())?; + + assert_tx_memo_equals(&tx_info, OVERWRITE_MEMO)?; + + Ok(()) + } +} + fn assert_tx_memo_equals(tx_info: &json::Value, expected_memo: &str) -> Result<(), Error> { debug!("comparing memo field from json value {}", tx_info); diff --git a/tools/integration-test/src/tests/mod.rs b/tools/integration-test/src/tests/mod.rs index 373cf4d276..e8812377d6 100644 --- a/tools/integration-test/src/tests/mod.rs +++ b/tools/integration-test/src/tests/mod.rs @@ -10,10 +10,11 @@ pub mod client_expiration; pub mod client_filter; pub mod client_refresh; pub mod client_settings; -#[cfg(not(any(feature = "celestia", feature = "juno")))] +#[cfg(not(feature = "celestia"))] pub mod client_upgrade; pub mod connection_delay; pub mod consensus_states; +#[cfg(not(feature = "no-denom-trace"))] pub mod denom_trace; pub mod error_events; pub mod execute_schedule; @@ -22,6 +23,8 @@ pub mod ics20_filter; pub mod memo; pub mod python; pub mod query_packet; +#[cfg(not(feature = "celestia"))] +pub mod sequence_filter; pub mod supervisor; pub mod tendermint; #[cfg(not(feature = "celestia"))] @@ -31,6 +34,12 @@ pub mod transfer; #[cfg(any(doc, feature = "async-icq"))] pub mod async_icq; +#[cfg(any(doc, feature = "authz"))] +pub mod authz; + +#[cfg(any(doc, feature = "channel-upgrade"))] +pub mod channel_upgrade; + #[cfg(any(doc, feature = "ics29-fee"))] pub mod fee; @@ -66,3 +75,6 @@ pub mod interchain_security; #[cfg(any(doc, feature = "dynamic-gas-fee"))] pub mod dynamic_gas_fee; + +#[cfg(any(doc, feature = "benchmark"))] +pub mod benchmark; diff --git a/tools/integration-test/src/tests/ordered_channel.rs b/tools/integration-test/src/tests/ordered_channel.rs index 25177b4ee8..a72126d3f2 100644 --- a/tools/integration-test/src/tests/ordered_channel.rs +++ b/tools/integration-test/src/tests/ordered_channel.rs @@ -13,7 +13,6 @@ //! A more thorough walkthrough of this test can be found at //! `tools/test-framework/src/docs/walkthroughs/ordered_channel.rs`. -use ibc_test_framework::ibc::denom::derive_ibc_denom; use ibc_test_framework::prelude::*; use ibc_test_framework::util::random::random_u128_range; @@ -74,11 +73,9 @@ impl BinaryChannelTest for OrderedChannelTest { &denom_a.with_amount(amount1).as_ref(), )?; - sleep(Duration::from_secs(1)); + sleep(Duration::from_secs(2)); relayer.with_supervisor(|| { - sleep(Duration::from_secs(1)); - let amount2 = random_u128_range(1000, 5000); info!( diff --git a/tools/integration-test/src/tests/ordered_channel_clear.rs b/tools/integration-test/src/tests/ordered_channel_clear.rs index a005df8f62..ed6e124e64 100644 --- a/tools/integration-test/src/tests/ordered_channel_clear.rs +++ b/tools/integration-test/src/tests/ordered_channel_clear.rs @@ -2,7 +2,6 @@ use ibc_relayer::config::{types::MaxMsgNum, ChainConfig}; use ibc_relayer::link::{Link, LinkParameters}; use ibc_relayer::transfer::{build_and_send_transfer_messages, TransferOptions}; use ibc_relayer_types::events::IbcEvent; -use ibc_test_framework::ibc::denom::derive_ibc_denom; use ibc_test_framework::prelude::*; use ibc_test_framework::util::random::random_u64_range; @@ -48,6 +47,7 @@ impl OrderedChannelClearTest { impl TestOverrides for OrderedChannelClearTest { fn modify_relayer_config(&self, config: &mut Config) { config.mode.packets.tx_confirmation = self.tx_confirmation; + config.mode.packets.clear_limit = 150; { let chain_a = &mut config.chains[0]; match chain_a { @@ -121,6 +121,7 @@ impl BinaryChannelTest for OrderedChannelClearTest { src_channel_id: channel.channel_id_a.clone().into_value(), max_memo_size: packet_config.ics20_max_memo_size, max_receiver_size: packet_config.ics20_max_receiver_size, + exclude_src_sequences: vec![], }; let chain_a_link = Link::new_from_opts( @@ -136,6 +137,7 @@ impl BinaryChannelTest for OrderedChannelClearTest { src_channel_id: channel.channel_id_b.clone().into_value(), max_memo_size: packet_config.ics20_max_memo_size, max_receiver_size: packet_config.ics20_max_receiver_size, + exclude_src_sequences: vec![], }; let chain_b_link = Link::new_from_opts( @@ -148,7 +150,8 @@ impl BinaryChannelTest for OrderedChannelClearTest { // Send the transfer (recv) packets from A to B over the channel. let mut relay_path_a_to_b = chain_a_link.a_to_b; - relay_path_a_to_b.schedule_packet_clearing(None)?; + relay_path_a_to_b + .schedule_packet_clearing(None, relayer.config.mode.packets.clear_limit)?; relay_path_a_to_b.execute_schedule()?; sleep(Duration::from_secs(10)); @@ -167,7 +170,8 @@ impl BinaryChannelTest for OrderedChannelClearTest { // Send the packet acknowledgments from B to A. let mut relay_path_b_to_a = chain_b_link.a_to_b; - relay_path_b_to_a.schedule_packet_clearing(None)?; + relay_path_b_to_a + .schedule_packet_clearing(None, relayer.config.mode.packets.clear_limit)?; relay_path_b_to_a.execute_schedule()?; sleep(Duration::from_secs(10)); @@ -272,6 +276,7 @@ impl BinaryChannelTest for OrderedChannelClearEqualCLITest { src_channel_id: channel.channel_id_a.into_value(), max_memo_size: packet_config.ics20_max_memo_size, max_receiver_size: packet_config.ics20_max_receiver_size, + exclude_src_sequences: vec![], }; let chain_a_link = Link::new_from_opts( diff --git a/tools/integration-test/src/tests/query_packet.rs b/tools/integration-test/src/tests/query_packet.rs index 4ae21ac725..7bd3f7ad1b 100644 --- a/tools/integration-test/src/tests/query_packet.rs +++ b/tools/integration-test/src/tests/query_packet.rs @@ -1,4 +1,5 @@ use ibc_relayer::chain::counterparty::{channel_on_destination, pending_packet_summary}; +use ibc_relayer::chain::requests::Paginate; use ibc_relayer::link::{Link, LinkParameters}; use ibc_test_framework::prelude::*; @@ -62,7 +63,17 @@ impl BinaryChannelTest for QueryPacketPendingTest { src_channel_id: channel.channel_id_a.clone().into_value(), max_memo_size: packet_config.ics20_max_memo_size, max_receiver_size: packet_config.ics20_max_receiver_size, + exclude_src_sequences: vec![], }; + + let rev_opts = LinkParameters { + src_port_id: channel.port_b.clone().into_value(), + src_channel_id: channel.channel_id_b.clone().into_value(), + max_memo_size: packet_config.ics20_max_memo_size, + max_receiver_size: packet_config.ics20_max_receiver_size, + exclude_src_sequences: vec![], + }; + let link = Link::new_from_opts( chains.handle_a().clone(), chains.handle_b().clone(), @@ -77,8 +88,12 @@ impl BinaryChannelTest for QueryPacketPendingTest { channel.port_a.as_ref(), )?; - let summary = - pending_packet_summary(chains.handle_a(), chains.handle_b(), channel_end.value())?; + let summary = pending_packet_summary( + chains.handle_a(), + chains.handle_b(), + channel_end.value(), + Paginate::All, + )?; assert_eq!(summary.unreceived_packets, [1.into()]); assert!(summary.unreceived_acks.is_empty()); @@ -86,18 +101,34 @@ impl BinaryChannelTest for QueryPacketPendingTest { // Receive the packet on the destination chain link.relay_recv_packet_and_timeout_messages(vec![])?; - let summary = - pending_packet_summary(chains.handle_a(), chains.handle_b(), channel_end.value())?; + let summary = pending_packet_summary( + chains.handle_a(), + chains.handle_b(), + channel_end.value(), + Paginate::All, + )?; assert!(summary.unreceived_packets.is_empty()); assert_eq!(summary.unreceived_acks, [1.into()]); // Acknowledge the packet on the source chain - let link = link.reverse(false, false)?; - link.relay_ack_packet_messages(vec![])?; - let summary = - pending_packet_summary(chains.handle_a(), chains.handle_b(), channel_end.value())?; + let rev_link = Link::new_from_opts( + chains.handle_b().clone(), + chains.handle_a().clone(), + rev_opts, + false, + false, + )?; + + rev_link.relay_ack_packet_messages(vec![])?; + + let summary = pending_packet_summary( + chains.handle_a(), + chains.handle_b(), + channel_end.value(), + Paginate::All, + )?; assert!(summary.unreceived_packets.is_empty()); assert!(summary.unreceived_acks.is_empty()); @@ -136,6 +167,7 @@ impl BinaryChannelTest for QueryPacketPendingTest { chains.handle_b(), chains.handle_a(), &counterparty_channel_end, + Paginate::All, )?; assert_eq!(summary.unreceived_packets, [1.into()]); diff --git a/tools/integration-test/src/tests/sequence_filter.rs b/tools/integration-test/src/tests/sequence_filter.rs new file mode 100644 index 0000000000..a880f7720e --- /dev/null +++ b/tools/integration-test/src/tests/sequence_filter.rs @@ -0,0 +1,570 @@ +//! This tests different scenarios for the packet sequence filter. +//! The purpose of this filter is to only filter out packets when clearing, +//! standard relaying should not be affected by this configuration. +//! +//! `FilterClearOnStartTest` tests that the packets sequences configured in +//! `excluded_sequences` are not relayed when clearing packet on start. +//! +//! `FilterClearIntervalTest` tests that the packet sequences configured in +//! `excluded_sequences` are not relayed when the clear interval is triggered. +//! +//! `ClearNoFilterTest` tests that packets are correctly cleared if there is no +//! packet sequence configured in `excluded_sequences`. +//! +//! `StandardRelayingNoFilterTest` tests that even if a packet sequence is +//! configured in the `excluded_sequences` it will be relayed by the running +//! instance. + +use std::collections::BTreeMap; + +use ibc_relayer::config::ChainConfig; +use ibc_relayer::util::excluded_sequences::ExcludedSequences; +use ibc_test_framework::{ + prelude::*, + relayer::channel::{assert_eventually_channel_established, init_channel}, +}; + +#[test] +fn test_filter_clear_on_start() -> Result<(), Error> { + run_binary_channel_test(&FilterClearOnStartTest) +} + +#[test] +fn test_filter_clear_interval() -> Result<(), Error> { + run_binary_channel_test(&FilterClearIntervalTest) +} + +#[test] +fn test_clear_no_filter() -> Result<(), Error> { + run_binary_channel_test(&ClearNoFilterTest) +} + +#[test] +fn test_no_filter_standard_relaying() -> Result<(), Error> { + run_binary_channel_test(&StandardRelayingNoFilterTest) +} + +pub struct FilterClearOnStartTest; + +impl TestOverrides for FilterClearOnStartTest { + fn modify_relayer_config(&self, config: &mut Config) { + let mut excluded_sequences = BTreeMap::new(); + excluded_sequences.insert(ChannelId::new(2), vec![2.into()]); + let chain_a = &mut config.chains[0]; + match chain_a { + ChainConfig::CosmosSdk(chain_config) => { + chain_config.excluded_sequences = ExcludedSequences::new(excluded_sequences); + } + } + config.mode.channels.enabled = true; + + config.mode.packets.clear_on_start = true; + config.mode.packets.clear_interval = 0; + + config.mode.clients.misbehaviour = false; + } + + fn should_spawn_supervisor(&self) -> bool { + false + } +} + +impl BinaryChannelTest for FilterClearOnStartTest { + fn run( + &self, + _config: &TestConfig, + relayer: RelayerDriver, + chains: ConnectedChains, + channels: ConnectedChannel, + ) -> Result<(), Error> { + run_sequence_filter_test(relayer, chains, channels) + } +} + +pub struct FilterClearIntervalTest; + +impl TestOverrides for FilterClearIntervalTest { + fn modify_relayer_config(&self, config: &mut Config) { + let mut excluded_sequences = BTreeMap::new(); + excluded_sequences.insert(ChannelId::new(2), vec![2.into()]); + let chain_a = &mut config.chains[0]; + match chain_a { + ChainConfig::CosmosSdk(chain_config) => { + chain_config.excluded_sequences = ExcludedSequences::new(excluded_sequences); + } + } + config.mode.channels.enabled = true; + + config.mode.packets.clear_on_start = false; + config.mode.packets.clear_interval = 10; + + config.mode.clients.misbehaviour = false; + } + + fn should_spawn_supervisor(&self) -> bool { + false + } +} + +impl BinaryChannelTest for FilterClearIntervalTest { + fn run( + &self, + _config: &TestConfig, + relayer: RelayerDriver, + chains: ConnectedChains, + channels: ConnectedChannel, + ) -> Result<(), Error> { + run_sequence_filter_test(relayer, chains, channels) + } +} + +pub struct ClearNoFilterTest; + +impl TestOverrides for ClearNoFilterTest { + fn modify_relayer_config(&self, config: &mut Config) { + config.mode.channels.enabled = true; + + config.mode.packets.clear_on_start = true; + config.mode.packets.clear_interval = 0; + + config.mode.clients.misbehaviour = false; + } + + fn should_spawn_supervisor(&self) -> bool { + false + } +} + +impl BinaryChannelTest for ClearNoFilterTest { + fn run( + &self, + _config: &TestConfig, + relayer: RelayerDriver, + chains: ConnectedChains, + channels: ConnectedChannel, + ) -> Result<(), Error> { + let denom_a = chains.node_a.denom(); + let denom_a_to_b = derive_ibc_denom( + &channels.port_b.as_ref(), + &channels.channel_id_b.as_ref(), + &denom_a, + )?; + let denom_b = chains.node_b.denom(); + let denom_b_to_a = derive_ibc_denom( + &channels.port_a.as_ref(), + &channels.channel_id_a.as_ref(), + &denom_b, + )?; + + let wallet_a = chains.node_a.wallets().user1().cloned(); + let wallet_b = chains.node_b.wallets().user1().cloned(); + + let a_to_b_amount = 12345u64; + let b_to_a_amount = 54321u64; + + let balance_a = chains + .node_a + .chain_driver() + .query_balance(&wallet_a.address(), &denom_a)?; + + let balance_b = chains + .node_b + .chain_driver() + .query_balance(&wallet_b.address(), &denom_b)?; + + // Create a pending transfer from A to B with sequence 1 + chains.node_a.chain_driver().ibc_transfer_token( + &channels.port_a.as_ref(), + &channels.channel_id_a.as_ref(), + &wallet_a.as_ref(), + &wallet_b.address(), + &denom_a.with_amount(a_to_b_amount).as_ref(), + )?; + + // Create a pending transfer from A to B with sequence 2 + chains.node_a.chain_driver().ibc_transfer_token( + &channels.port_a.as_ref(), + &channels.channel_id_a.as_ref(), + &wallet_a.as_ref(), + &wallet_b.address(), + &denom_a.with_amount(a_to_b_amount).as_ref(), + )?; + + // Create a pending transfer from B to A with sequence 1 + chains.node_b.chain_driver().ibc_transfer_token( + &channels.port_b.as_ref(), + &channels.channel_id_b.as_ref(), + &wallet_b.as_ref(), + &wallet_a.address(), + &denom_b.with_amount(b_to_a_amount).as_ref(), + )?; + + // Create a pending transfer from B to A with sequence 2 + chains.node_b.chain_driver().ibc_transfer_token( + &channels.port_b.as_ref(), + &channels.channel_id_b.as_ref(), + &wallet_b.as_ref(), + &wallet_a.address(), + &denom_b.with_amount(b_to_a_amount).as_ref(), + )?; + + relayer.with_supervisor(|| { + info!("Assert that the send from A escrowed tokens for both transfers"); + + chains.node_a.chain_driver().assert_eventual_wallet_amount( + &wallet_a.address(), + &(balance_a - 2 * a_to_b_amount).as_ref(), + )?; + + info!("Assert that only the first transfer A to B was cleared"); + + chains.node_b.chain_driver().assert_eventual_wallet_amount( + &wallet_b.address(), + &denom_a_to_b.with_amount(2 * a_to_b_amount).as_ref(), + )?; + info!("Assert that the sender from B escrowed tokens for both transfers"); + + chains.node_b.chain_driver().assert_eventual_wallet_amount( + &wallet_b.address(), + &(balance_b - 2 * b_to_a_amount).as_ref(), + )?; + + info!("Assert that both transfers from B to A were cleared"); + + chains.node_a.chain_driver().assert_eventual_wallet_amount( + &wallet_a.address(), + &denom_b_to_a.with_amount(2 * b_to_a_amount).as_ref(), + )?; + Ok(()) + }) + } +} + +pub struct StandardRelayingNoFilterTest; + +impl TestOverrides for StandardRelayingNoFilterTest { + fn modify_relayer_config(&self, config: &mut Config) { + let mut excluded_sequences = BTreeMap::new(); + excluded_sequences.insert(ChannelId::new(2), vec![2.into()]); + let chain_a = &mut config.chains[0]; + match chain_a { + ChainConfig::CosmosSdk(chain_config) => { + chain_config.excluded_sequences = ExcludedSequences::new(excluded_sequences); + } + } + config.mode.packets.clear_on_start = true; + config.mode.packets.clear_interval = 0; + } + + fn should_spawn_supervisor(&self) -> bool { + true + } +} + +impl BinaryChannelTest for StandardRelayingNoFilterTest { + fn run( + &self, + _config: &TestConfig, + _relayer: RelayerDriver, + chains: ConnectedChains, + channels: ConnectedChannel, + ) -> Result<(), Error> { + let denom_a = chains.node_a.denom(); + let denom_a_to_b = derive_ibc_denom( + &channels.port_b.as_ref(), + &channels.channel_id_b.as_ref(), + &denom_a, + )?; + let denom_b = chains.node_b.denom(); + let denom_b_to_a = derive_ibc_denom( + &channels.port_a.as_ref(), + &channels.channel_id_a.as_ref(), + &denom_b, + )?; + + let wallet_a = chains.node_a.wallets().user1().cloned(); + let wallet_b = chains.node_b.wallets().user1().cloned(); + + let a_to_b_amount = 12345u64; + let b_to_a_amount = 54321u64; + + let balance_a = chains + .node_a + .chain_driver() + .query_balance(&wallet_a.address(), &denom_a)?; + + let balance_b = chains + .node_b + .chain_driver() + .query_balance(&wallet_b.address(), &denom_b)?; + + // Create a pending transfer from A to B with sequence 1 + chains.node_a.chain_driver().ibc_transfer_token( + &channels.port_a.as_ref(), + &channels.channel_id_a.as_ref(), + &wallet_a.as_ref(), + &wallet_b.address(), + &denom_a.with_amount(a_to_b_amount).as_ref(), + )?; + + // Create a pending transfer from A to B with sequence 2 + chains.node_a.chain_driver().ibc_transfer_token( + &channels.port_a.as_ref(), + &channels.channel_id_a.as_ref(), + &wallet_a.as_ref(), + &wallet_b.address(), + &denom_a.with_amount(a_to_b_amount).as_ref(), + )?; + + // Create a pending transfer from B to A with sequence 1 + chains.node_b.chain_driver().ibc_transfer_token( + &channels.port_b.as_ref(), + &channels.channel_id_b.as_ref(), + &wallet_b.as_ref(), + &wallet_a.address(), + &denom_b.with_amount(b_to_a_amount).as_ref(), + )?; + + // Create a pending transfer from B to A with sequence 2 + chains.node_b.chain_driver().ibc_transfer_token( + &channels.port_b.as_ref(), + &channels.channel_id_b.as_ref(), + &wallet_b.as_ref(), + &wallet_a.address(), + &denom_b.with_amount(b_to_a_amount).as_ref(), + )?; + + info!("Assert that the send from A escrowed tokens for both transfers"); + + chains.node_a.chain_driver().assert_eventual_wallet_amount( + &wallet_a.address(), + &(balance_a - 2 * a_to_b_amount).as_ref(), + )?; + + info!("Assert that only the first transfer A to B was cleared"); + + chains.node_b.chain_driver().assert_eventual_wallet_amount( + &wallet_b.address(), + &denom_a_to_b.with_amount(2 * a_to_b_amount).as_ref(), + )?; + info!("Assert that the sender from B escrowed tokens for both transfers"); + + chains.node_b.chain_driver().assert_eventual_wallet_amount( + &wallet_b.address(), + &(balance_b - 2 * b_to_a_amount).as_ref(), + )?; + + info!("Assert that both transfers from B to A were cleared"); + + chains.node_a.chain_driver().assert_eventual_wallet_amount( + &wallet_a.address(), + &denom_b_to_a.with_amount(2 * b_to_a_amount).as_ref(), + )?; + Ok(()) + } +} + +fn run_sequence_filter_test( + relayer: RelayerDriver, + chains: ConnectedChains, + channels: ConnectedChannel, +) -> Result<(), Error> { + let (channel_id_a_2, channel_id_b_2, channel_b_2) = relayer.with_supervisor(|| { + // During test bootstrap channel padding initialises a channel with ID 0. + // Before creating the new channel with sequence filter, complete the handshake of + // the pad channel in order to insure that the retrieved channel IDs `channel_id_a_2` and + // `channel_id_b_2` are `channel-2` + let pad_channel_id = DualTagged::new(ChannelId::new(0)); + let _ = assert_eventually_channel_established( + chains.handle_b(), + chains.handle_a(), + &pad_channel_id.as_ref(), + &channels.port_b.as_ref(), + )?; + let (channel_id_b_2, channel_b_2) = init_channel( + chains.handle_a(), + chains.handle_b(), + &chains.client_id_a(), + &chains.client_id_b(), + &channels.connection.connection_id_a.as_ref(), + &channels.connection.connection_id_b.as_ref(), + &channels.port_a.as_ref(), + &channels.port_b.as_ref(), + )?; + + let channel_id_a_2 = assert_eventually_channel_established( + chains.handle_b(), + chains.handle_a(), + &channel_id_b_2.as_ref(), + &channels.port_b.as_ref(), + )?; + Ok((channel_id_a_2, channel_id_b_2, channel_b_2)) + })?; + + let denom_a = chains.node_a.denom(); + let denom_a_to_b_1 = derive_ibc_denom( + &channels.port_b.as_ref(), + &channels.channel_id_b.as_ref(), + &denom_a, + )?; + let denom_a_to_b_2 = derive_ibc_denom( + &channels.port_b.as_ref(), + &channel_id_b_2.as_ref(), + &denom_a, + )?; + let denom_b = chains.node_b.denom(); + let denom_b_to_a_1 = derive_ibc_denom( + &channels.port_a.as_ref(), + &channels.channel_id_a.as_ref(), + &denom_b, + )?; + let denom_b_to_a_2 = derive_ibc_denom( + &channels.port_a.as_ref(), + &channel_id_a_2.as_ref(), + &denom_b, + )?; + + let wallet_a_1 = chains.node_a.wallets().user1().cloned(); + let wallet_a_2 = chains.node_a.wallets().user2().cloned(); + let wallet_b_1 = chains.node_b.wallets().user1().cloned(); + let wallet_b_2 = chains.node_b.wallets().user2().cloned(); + + let a_to_b_amount = 12345u64; + let b_to_a_amount = 54321u64; + + let balance_a_1 = chains + .node_a + .chain_driver() + .query_balance(&wallet_a_1.address(), &denom_a)?; + + let balance_b_1 = chains + .node_b + .chain_driver() + .query_balance(&wallet_b_1.address(), &denom_b)?; + + let balance_a_2 = chains + .node_a + .chain_driver() + .query_balance(&wallet_a_2.address(), &denom_a)?; + + let balance_b_2 = chains + .node_b + .chain_driver() + .query_balance(&wallet_b_2.address(), &denom_b)?; + + // Double transfer from A to B on channel with filter + double_transfer( + chains.node_a.chain_driver(), + &channels.port_a.as_ref(), + &channels.channel_id_a.as_ref(), + &wallet_a_1.as_ref(), + &wallet_b_1.address(), + &denom_a.with_amount(a_to_b_amount).as_ref(), + )?; + + let port_b_2: DualTagged = + DualTagged::new(channel_b_2.a_side.port_id()); + let port_a_2: DualTagged = + DualTagged::new(channel_b_2.clone().flipped().a_side.port_id().clone()); + + // Double transfer from A to B on channel without filter + double_transfer( + chains.node_a.chain_driver(), + &port_a_2.as_ref(), + &channel_id_a_2.as_ref(), + &wallet_a_2.as_ref(), + &wallet_b_2.address(), + &denom_a.with_amount(a_to_b_amount).as_ref(), + )?; + + // Double transfer from B to A on channel with filter + double_transfer( + chains.node_b.chain_driver(), + &channels.port_b.as_ref(), + &channels.channel_id_b.as_ref(), + &wallet_b_1.as_ref(), + &wallet_a_1.address(), + &denom_b.with_amount(b_to_a_amount).as_ref(), + )?; + + // Double transfer from B to A on channel without filter + double_transfer( + chains.node_b.chain_driver(), + &port_b_2, + &channel_id_b_2.as_ref(), + &wallet_b_2.as_ref(), + &wallet_a_2.address(), + &denom_b.with_amount(b_to_a_amount).as_ref(), + )?; + + relayer.with_supervisor(|| { + info!("Assert that the send from A escrowed tokens for both transfers"); + + chains.node_a.chain_driver().assert_eventual_wallet_amount( + &wallet_a_1.address(), + &(balance_a_1 - 2 * a_to_b_amount).as_ref(), + )?; + + chains.node_a.chain_driver().assert_eventual_wallet_amount( + &wallet_a_2.address(), + &(balance_a_2 - 2 * a_to_b_amount).as_ref(), + )?; + + info!("Assert that only the first transfer A to B was cleared on channel with filter"); + + chains.node_b.chain_driver().assert_eventual_wallet_amount( + &wallet_b_2.address(), + &denom_a_to_b_2.with_amount(a_to_b_amount).as_ref(), + )?; + + info!("Assert that both transfer A to B were cleared on channel without filter"); + + chains.node_b.chain_driver().assert_eventual_wallet_amount( + &wallet_b_1.address(), + &denom_a_to_b_1.with_amount(2 * a_to_b_amount).as_ref(), + )?; + + info!("Assert that the sender from B escrowed tokens for both transfers on both channels"); + + chains.node_b.chain_driver().assert_eventual_wallet_amount( + &wallet_b_1.address(), + &(balance_b_1 - 2 * b_to_a_amount).as_ref(), + )?; + + chains.node_b.chain_driver().assert_eventual_wallet_amount( + &wallet_b_2.address(), + &(balance_b_2 - 2 * b_to_a_amount).as_ref(), + )?; + + info!("Assert that both transfers from B to A were cleared on both channels"); + + chains.node_a.chain_driver().assert_eventual_wallet_amount( + &wallet_a_1.address(), + &denom_b_to_a_1.with_amount(2 * b_to_a_amount).as_ref(), + )?; + + chains.node_a.chain_driver().assert_eventual_wallet_amount( + &wallet_a_2.address(), + &denom_b_to_a_2.with_amount(2 * b_to_a_amount).as_ref(), + )?; + + Ok(()) + }) +} + +fn double_transfer( + chain_driver: MonoTagged, + port_id: &TaggedPortIdRef, + channel_id: &TaggedChannelIdRef, + sender: &MonoTagged, + recipient: &MonoTagged, + token: &TaggedTokenRef, +) -> Result<(), Error> { + // Create a pending transfer from B to A with sequence 1 + chain_driver.ibc_transfer_token(port_id, channel_id, sender, recipient, token)?; + + // Create a pending transfer from B to A with sequence 2 + chain_driver.ibc_transfer_token(port_id, channel_id, sender, recipient, token)?; + + Ok(()) +} diff --git a/tools/integration-test/src/tests/supervisor.rs b/tools/integration-test/src/tests/supervisor.rs index 38daad74ed..17ee1b5af7 100644 --- a/tools/integration-test/src/tests/supervisor.rs +++ b/tools/integration-test/src/tests/supervisor.rs @@ -1,5 +1,4 @@ -use ibc_relayer::config::{self, Config, ModeConfig}; -use ibc_test_framework::ibc::denom::derive_ibc_denom; +use ibc_relayer::config::{self, ModeConfig}; use ibc_test_framework::prelude::*; use ibc_test_framework::relayer::channel::{assert_eventually_channel_established, init_channel}; @@ -8,7 +7,7 @@ use ibc_test_framework::relayer::connection::{ }; #[test] -fn test_supervisor() -> Result<(), Error> { +fn test_supervisor1() -> Result<(), Error> { run_binary_chain_test(&SupervisorTest) } @@ -52,10 +51,14 @@ impl TestOverrides for SupervisorTest { impl BinaryChainTest for SupervisorTest { fn run( &self, - _config: &TestConfig, + config: &TestConfig, _relayer: RelayerDriver, chains: ConnectedChains, ) -> Result<(), Error> { + let fee_denom_a: MonoTagged = + MonoTagged::new(Denom::base(config.native_token(0))); + let fee_denom_b: MonoTagged = + MonoTagged::new(Denom::base(config.native_token(1))); let (connection_id_b, _) = init_connection( &chains.handle_a, &chains.handle_b, @@ -113,12 +116,14 @@ impl BinaryChainTest for SupervisorTest { &chains.node_a.wallets().relayer(), &chains.node_a.wallets().user2().address(), &denom_a.with_amount(1000u64).as_ref(), + &fee_denom_a.with_amount(381000000u64).as_ref(), )?; chains.node_b.chain_driver().local_transfer_token( &chains.node_b.wallets().relayer(), &chains.node_b.wallets().user2().address(), &chains.node_b.denom().with_amount(1000u64).as_ref(), + &fee_denom_b.with_amount(381000000u64).as_ref(), )?; info!( @@ -194,7 +199,7 @@ impl BinaryChannelTest for SupervisorScanTest { channels: ConnectedChannel, ) -> Result<(), Error> { let denom_a = chains.node_a.denom(); - let fee_denom_a = MonoTagged::new(Denom::base(&config.native_tokens[0])); + let fee_denom_a = MonoTagged::new(Denom::base(config.native_token(0))); let denom_b = derive_ibc_denom( &channels.port_b.as_ref(), diff --git a/tools/integration-test/src/tests/ternary_transfer.rs b/tools/integration-test/src/tests/ternary_transfer.rs index 2fca34ec8b..527c085629 100644 --- a/tools/integration-test/src/tests/ternary_transfer.rs +++ b/tools/integration-test/src/tests/ternary_transfer.rs @@ -1,5 +1,5 @@ -use ibc_test_framework::ibc::denom::derive_ibc_denom; use ibc_test_framework::prelude::*; +use ibc_test_framework::types::topology::TopologyType; #[test] fn test_ternary_ibc_transfer() -> Result<(), Error> { @@ -12,6 +12,10 @@ impl TestOverrides for TernaryIbcTransferTest { fn modify_relayer_config(&self, config: &mut Config) { config.mode.clients.misbehaviour = false; } + + fn topology(&self) -> Option { + Some(TopologyType::Cyclic) + } } impl PortsOverride<3> for TernaryIbcTransferTest {} diff --git a/tools/query-events/Cargo.lock b/tools/query-events/Cargo.lock new file mode 100644 index 0000000000..2c67070e4e --- /dev/null +++ b/tools/query-events/Cargo.lock @@ -0,0 +1,2197 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" + +[[package]] +name = "async-trait" +version = "0.1.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "461abc97219de0eaaf81fe3ef974a540158f3d079c2ab200f891f1a2ef201e85" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +dependencies = [ + "serde", +] + +[[package]] +name = "cc" +version = "1.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +dependencies = [ + "atty", + "bitflags", + "clap_derive", + "clap_lex", + "indexmap 1.9.3", + "once_cell", + "strsim", + "termcolor", + "textwrap", +] + +[[package]] +name = "clap_derive" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "curve25519-dalek-ng" +version = "4.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c359b7249347e46fb28804470d071c921156ad62b3eef5d34e2ba867533dec8" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core", + "subtle-ng", + "zeroize", +] + +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-consensus" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c8465edc8ee7436ffea81d21a019b16676ee3db267aa8d5a8d729581ecf998b" +dependencies = [ + "curve25519-dalek-ng", + "hex", + "rand_core", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "either" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" + +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "eyre" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "flex-error" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c606d892c9de11507fa0dcffc116434f94e105d0bbdc4e405b61519464c49d7b" +dependencies = [ + "eyre", + "paste", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap 2.2.5", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http", + "hyper", + "rustls", + "tokio", + "tokio-rustls", +] + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[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.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[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 1.0.109", +] + +[[package]] +name = "num-traits" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.9", + "libc", +] + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "os_str_bytes" +version = "6.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.48.5", +] + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "peg" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "400bcab7d219c38abf8bd7cc2054eb9bbbd4312d66f6a5557d572a203f646f61" +dependencies = [ + "peg-macros", + "peg-runtime", +] + +[[package]] +name = "peg-macros" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46e61cce859b76d19090f62da50a9fe92bab7c2a5f09e183763559a2ac392c90" +dependencies = [ + "peg-runtime", + "proc-macro2", + "quote", +] + +[[package]] +name = "peg-runtime" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36bae92c60fa2398ce4678b98b2c4b5a7c61099961ca1fa305aec04a9ad28922" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prost" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" +dependencies = [ + "anyhow", + "itertools 0.11.0", + "proc-macro2", + "quote", + "syn 2.0.53", +] + +[[package]] +name = "prost-types" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "193898f59edcf43c26227dcd4c8427f00d99d61e95dcde58dabd49fa291d470e" +dependencies = [ + "prost", +] + +[[package]] +name = "query-events" +version = "0.1.0" +dependencies = [ + "clap", + "futures", + "itertools 0.10.5", + "tendermint", + "tendermint-rpc", + "tokio", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.6", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-rustls", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls", + "rustls-native-certs", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-rustls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustls" +version = "0.21.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +dependencies = [ + "log", + "ring", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-native-certs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "ryu" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "security-framework" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" + +[[package]] +name = "serde" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + +[[package]] +name = "serde_json" +version = "1.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "subtle-encoding" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dcb1ed7b8330c5eed5441052651dd7a12c75e2ed88f2ec024ae1fa3a5e59945" +dependencies = [ + "zeroize", +] + +[[package]] +name = "subtle-ng" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tendermint" +version = "0.34.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15ab8f0a25d0d2ad49ac615da054d6a76aa6603ff95f7d18bafdd34450a1a04b" +dependencies = [ + "bytes", + "digest 0.10.7", + "ed25519", + "ed25519-consensus", + "flex-error", + "futures", + "num-traits", + "once_cell", + "prost", + "prost-types", + "serde", + "serde_bytes", + "serde_json", + "serde_repr", + "sha2 0.10.8", + "signature", + "subtle", + "subtle-encoding", + "tendermint-proto", + "time", + "zeroize", +] + +[[package]] +name = "tendermint-config" +version = "0.34.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1a02da769166e2052cd537b1a97c78017632c2d9e19266367b27e73910434fc" +dependencies = [ + "flex-error", + "serde", + "serde_json", + "tendermint", + "toml", + "url", +] + +[[package]] +name = "tendermint-proto" +version = "0.34.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b797dd3d2beaaee91d2f065e7bdf239dc8d80bba4a183a288bc1279dd5a69a1e" +dependencies = [ + "bytes", + "flex-error", + "num-derive", + "num-traits", + "prost", + "prost-types", + "serde", + "serde_bytes", + "subtle-encoding", + "time", +] + +[[package]] +name = "tendermint-rpc" +version = "0.34.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71afae8bb5f6b14ed48d4e1316a643b6c2c3cbad114f510be77b4ed20b7b3e42" +dependencies = [ + "async-trait", + "bytes", + "flex-error", + "futures", + "getrandom", + "peg", + "pin-project", + "rand", + "reqwest", + "semver", + "serde", + "serde_bytes", + "serde_json", + "subtle", + "subtle-encoding", + "tendermint", + "tendermint-config", + "tendermint-proto", + "thiserror", + "time", + "tokio", + "tracing", + "url", + "uuid", + "walkdir", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" + +[[package]] +name = "thiserror" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "uuid" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.53", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[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-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[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 = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.4", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] diff --git a/tools/test-framework/Cargo.toml b/tools/test-framework/Cargo.toml index a33bbf74d4..a4e2004906 100644 --- a/tools/test-framework/Cargo.toml +++ b/tools/test-framework/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ibc-test-framework" -version = "0.27.0" +version = "0.29.5" edition = "2021" license = "Apache-2.0" readme = "README.md" @@ -14,31 +14,33 @@ description = """ """ [dependencies] -ibc-relayer-types = { version = "=0.27.0", path = "../../crates/relayer-types" } -ibc-relayer = { version = "=0.27.0", path = "../../crates/relayer" } -ibc-relayer-cli = { version = "=1.8.0", path = "../../crates/relayer-cli" } -ibc-proto = { version = "0.41.0", features = ["serde"] } -tendermint-rpc = { version = "0.34.0", features = ["http-client", "websocket-client"] } +ibc-relayer-types = { workspace = true } +ibc-relayer = { workspace = true } +ibc-relayer-cli = { workspace = true } +ibc-proto = { workspace = true, features = ["serde"] } +tendermint-rpc = { workspace = true, features = ["http-client", "websocket-client"] } -http = "0.2.9" -tokio = { version = "1.0", features = ["full"] } -tracing = "0.1.36" -tracing-subscriber = "0.3.14" -eyre = "0.6.8" -color-eyre = "0.6" -rand = "0.8.5" -hex = "0.4.3" -serde = "1.0" -serde_json = "1" -serde_yaml = "0.9.31" -itertools = "0.10" -toml = "0.8" -subtle-encoding = "0.5.1" -sha2 = "0.10.6" -crossbeam-channel = "0.5.11" -semver = "1.0.21" -flex-error = "0.4.4" -prost = { version = "0.12" } -tonic = { version = "0.10", features = ["tls", "tls-roots"] } -hdpath = "0.6.3" -once_cell = "1.19.0" +color-eyre = { workspace = true } +crossbeam-channel = { workspace = true } +eyre = { workspace = true } +flex-error = { workspace = true } +hdpath = { workspace = true } +hex = { workspace = true } +http = { workspace = true } +itertools = { workspace = true } +once_cell = { workspace = true } +prost = { workspace = true } +rand = { workspace = true } +semver = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +serde_yaml = { workspace = true } +sha2 = { workspace = true } +subtle-encoding = { workspace = true } +tokio = { workspace = true, features = ["full"] } +toml = { workspace = true } +tonic = { workspace = true, features = ["tls", "tls-roots"] } +tracing = { workspace = true } +tracing-subscriber = { workspace = true } + +chrono = "0.4.38" diff --git a/tools/test-framework/src/bootstrap/consumer.rs b/tools/test-framework/src/bootstrap/consumer.rs index 1c46b7e600..c473ab6c28 100644 --- a/tools/test-framework/src/bootstrap/consumer.rs +++ b/tools/test-framework/src/bootstrap/consumer.rs @@ -5,10 +5,10 @@ use eyre::eyre; use std::sync::{Arc, RwLock}; use std::thread; use std::time::Duration; -use toml; use tracing::info; use crate::chain::builder::ChainBuilder; +use crate::chain::cli::provider::validator_opt_in; use crate::chain::config; use crate::chain::ext::bootstrap::ChainBootstrapMethodsExt; use crate::error::Error; @@ -23,6 +23,7 @@ pub fn bootstrap_consumer_node( genesis_modifier: impl FnOnce(&mut serde_json::Value) -> Result<(), Error>, chain_number: usize, provider_chain_driver: &ChainDriver, + provider_fee: &String, ) -> Result { let stake_denom = Denom::base("stake"); @@ -39,7 +40,7 @@ pub fn bootstrap_consumer_node( )))?; let initial_coin = Token::new(denom.clone(), initial_amount); - let chain_driver = builder.new_chain(prefix, false, chain_number)?; + let chain_driver = builder.new_chain("consumer", false, chain_number)?; chain_driver.initialize()?; @@ -54,11 +55,23 @@ pub fn bootstrap_consumer_node( chain_driver.add_genesis_account(&user2.address, &[&initial_stake, &initial_coin])?; // Wait for the consumer chain to be initialized before querying the genesis + thread::sleep(Duration::from_secs(5)); + + validator_opt_in( + provider_chain_driver.chain_id.as_str(), + &provider_chain_driver.command_path, + &provider_chain_driver.home_path, + &provider_chain_driver.rpc_listen_address(), + provider_fee, + prefix, + )?; + + // Wait enough time so that the spawn_time passed thread::sleep(Duration::from_secs(30)); node_a .chain_driver - .query_consumer_genesis(&chain_driver, chain_driver.chain_id.as_str())?; + .query_consumer_genesis(&chain_driver, prefix)?; chain_driver.replace_genesis_state()?; @@ -75,6 +88,7 @@ pub fn bootstrap_consumer_node( config::set_soft_opt_out_threshold(genesis, "0.05")?; config::consensus_params_max_gas(genesis, "3000000")?; config::globalfee_minimum_gas_prices(genesis, globalfee_minimum_gas)?; + config::set_retry_delay_period(genesis, "100s")?; Ok(()) })?; diff --git a/tools/test-framework/src/bootstrap/init.rs b/tools/test-framework/src/bootstrap/init.rs index 795f19787c..07e653771f 100644 --- a/tools/test-framework/src/bootstrap/init.rs +++ b/tools/test-framework/src/bootstrap/init.rs @@ -50,6 +50,11 @@ pub fn init_test() -> Result { let compat_modes = env::var("COMPAT_MODES").ok().map(parse_chain_command_paths); + let ipv6_grpc = env::var("IPV6_GRPC") + .ok() + .map(|val| val == "true") + .unwrap_or(false); + let account_prefixes = parse_chain_command_paths(account_prefix); let native_tokens = parse_chain_command_paths(native_token); @@ -72,6 +77,7 @@ pub fn init_test() -> Result { hang_on_fail, bootstrap_with_random_ids: false, native_tokens, + ipv6_grpc, compat_modes, }) } diff --git a/tools/test-framework/src/bootstrap/nary/chain.rs b/tools/test-framework/src/bootstrap/nary/chain.rs index 795ec74e69..3a758b7446 100644 --- a/tools/test-framework/src/bootstrap/nary/chain.rs +++ b/tools/test-framework/src/bootstrap/nary/chain.rs @@ -2,21 +2,19 @@ Functions for bootstrapping N-ary number of chains. */ -use core::convert::TryInto; use ibc_relayer::chain::handle::ChainHandle; use ibc_relayer::config::Config; -use ibc_relayer::foreign_client::ForeignClient; use ibc_relayer::registry::SharedRegistry; use crate::bootstrap::binary::chain::{ - add_chain_config, add_keys_to_chain_handle, bootstrap_foreign_client, new_registry, - save_relayer_config, + add_chain_config, add_keys_to_chain_handle, new_registry, save_relayer_config, }; use crate::error::{handle_generic_error, Error}; use crate::relayer::driver::RelayerDriver; use crate::types::config::TestConfig; use crate::types::nary::chains::{DynamicConnectedChains, NaryConnectedChains}; use crate::types::single::node::FullNode; +use crate::types::topology::{bootstrap_topology, TopologyType}; /** Bootstrap a fixed number of chains specified by `SIZE`. @@ -24,10 +22,15 @@ use crate::types::single::node::FullNode; pub fn boostrap_chains_with_nodes( test_config: &TestConfig, full_nodes: [FullNode; SIZE], + topology_override: Option, config_modifier: impl FnOnce(&mut Config), ) -> Result<(RelayerDriver, NaryConnectedChains), Error> { - let (relayer, chains) = - boostrap_chains_with_any_nodes(test_config, full_nodes.into(), config_modifier)?; + let (relayer, chains) = boostrap_chains_with_any_nodes( + test_config, + full_nodes.into(), + topology_override, + config_modifier, + )?; Ok((relayer, chains.try_into()?)) } @@ -39,11 +42,16 @@ pub fn boostrap_chains_with_nodes( pub fn boostrap_chains_with_self_connected_node( test_config: &TestConfig, full_node: FullNode, + topology_override: Option, config_modifier: impl FnOnce(&mut Config), ) -> Result<(RelayerDriver, NaryConnectedChains), Error> { let full_nodes = vec![full_node; SIZE]; - let (relayer, chains) = - boostrap_chains_with_any_nodes(test_config, full_nodes, config_modifier)?; + let (relayer, chains) = boostrap_chains_with_any_nodes( + test_config, + full_nodes, + topology_override, + config_modifier, + )?; Ok((relayer, chains.try_into()?)) } @@ -51,10 +59,13 @@ pub fn boostrap_chains_with_self_connected_node( /** Bootstrap a dynamic number of chains, according to the number of full nodes in the `Vec`. + The topology will be retrieved and set in this method, + see [`crate::types::topology`] for more information. */ pub fn boostrap_chains_with_any_nodes( test_config: &TestConfig, full_nodes: Vec, + topology_override: Option, config_modifier: impl FnOnce(&mut Config), ) -> Result<(RelayerDriver, DynamicConnectedChains), Error> { let mut config = Config::default(); @@ -78,19 +89,24 @@ pub fn boostrap_chains_with_any_nodes( chain_handles.push(handle); } - let mut foreign_clients: Vec>> = Vec::new(); - - for handle_a in chain_handles.iter() { - let mut foreign_clients_b = Vec::new(); - - for handle_b in chain_handles.iter() { - let foreign_client = bootstrap_foreign_client(handle_a, handle_b, Default::default())?; - - foreign_clients_b.push(foreign_client); + // Retrieve the topology or fallback to the Linear topology + let topology_type = if let Some(topology_type) = topology_override { + topology_type + } else { + let topology_str = std::env::var("TOPOLOGY").unwrap_or_else(|_| "linear".to_owned()); + match topology_str.parse() { + Ok(topology_type) => topology_type, + Err(_) => { + tracing::warn!( + "Failed to parse topology type `{topology_str}`. Will fallback to Linear topology" + ); + TopologyType::Linear + } } + }; + let topology = bootstrap_topology(topology_type); - foreign_clients.push(foreign_clients_b); - } + let foreign_clients = topology.create_topology(&chain_handles)?; let relayer = RelayerDriver { config_path, diff --git a/tools/test-framework/src/bootstrap/nary/channel.rs b/tools/test-framework/src/bootstrap/nary/channel.rs index a954c23ed7..6c4e65f582 100644 --- a/tools/test-framework/src/bootstrap/nary/channel.rs +++ b/tools/test-framework/src/bootstrap/nary/channel.rs @@ -2,7 +2,6 @@ Functions for bootstrapping N-ary number of channels. */ -use core::convert::TryInto; use core::time::Duration; use ibc_relayer::chain::handle::ChainHandle; use ibc_relayer_types::core::ics04_channel::channel::Ordering; @@ -18,60 +17,46 @@ use crate::types::nary::chains::{DynamicConnectedChains, NaryConnectedChains}; use crate::types::nary::channel::{ConnectedChannels, DynamicConnectedChannels}; use crate::types::nary::connection::{ConnectedConnections, DynamicConnectedConnections}; use crate::types::tagged::*; -use crate::util::array::{assert_same_dimension, into_nested_vec}; +use crate::util::array::into_nested_vec; +use crate::util::two_dim_hash_map::TwoDimMap; /** Bootstrap a dynamic number of channels based on the number of connections in `DynamicConnectedConnections`. + See [`crate::types::topology`] for more information. */ pub fn bootstrap_channels_with_connections_dynamic( connections: DynamicConnectedConnections, - chains: &Vec, ports: &Vec>, order: Ordering, bootstrap_with_random_ids: bool, ) -> Result, Error> { - let size = chains.len(); - - assert_same_dimension(size, connections.connections())?; - assert_same_dimension(size, ports)?; - - let mut channels: Vec>> = Vec::new(); - - for (i, connections_b) in connections.connections().iter().enumerate() { - let mut channels_b: Vec> = Vec::new(); - - for (j, connection) in connections_b.iter().enumerate() { - if i <= j { - let chain_a = &chains[i]; - let chain_b = &chains[j]; - - let port_a = &ports[i][j]; - let port_b = &ports[j][i]; - - let bootstrap_options = BootstrapChannelOptions::default() - .order(order) - .bootstrap_with_random_ids(bootstrap_with_random_ids); - - let channel = bootstrap_channel_with_connection( - chain_a, - chain_b, - connection.clone(), - &DualTagged::new(port_a), - &DualTagged::new(port_b), - bootstrap_options, - )?; - - channels_b.push(channel); - } else { - let counter_channel = &channels[j][i]; - let channel = counter_channel.clone().flip(); - - channels_b.push(channel); - } - } - - channels.push(channels_b); + let mut channels: TwoDimMap> = TwoDimMap::new(); + + for (src_chain, dst_chain, connection) in connections.connections().iter() { + let channel = if let Some(counterparty_channel) = channels.get((dst_chain, src_chain)) { + counterparty_channel.clone().flip() + } else { + // No channel is found, will create one + let chain_a = &connection.connection.a_chain(); + let chain_b = &connection.connection.b_chain(); + let port_a = ports[src_chain][dst_chain].clone(); + let port_b = ports[dst_chain][src_chain].clone(); + + let bootstrap_options = BootstrapChannelOptions::default() + .order(order) + .bootstrap_with_random_ids(bootstrap_with_random_ids); + + bootstrap_channel_with_connection( + chain_a, + chain_b, + connection.clone(), + &DualTagged::new(&port_a), + &DualTagged::new(&port_b), + bootstrap_options, + )? + }; + channels.insert((src_chain, dst_chain), channel); } Ok(DynamicConnectedChannels::new(channels)) @@ -83,14 +68,12 @@ pub fn bootstrap_channels_with_connections_dynamic( */ pub fn bootstrap_channels_with_connections( connections: ConnectedConnections, - chains: [Handle; SIZE], ports: [[PortId; SIZE]; SIZE], order: Ordering, bootstrap_with_random_ids: bool, ) -> Result, Error> { let channels = bootstrap_channels_with_connections_dynamic( connections.into(), - &chains.into(), &into_nested_vec(ports), order, bootstrap_with_random_ids, @@ -119,7 +102,6 @@ pub fn bootstrap_channels_and_connections_dynamic( bootstrap_channels_with_connections_dynamic( connections, - chains.chain_handles(), ports, order, bootstrap_with_random_ids, diff --git a/tools/test-framework/src/bootstrap/nary/connection.rs b/tools/test-framework/src/bootstrap/nary/connection.rs index 932f9fc9be..065ef1385a 100644 --- a/tools/test-framework/src/bootstrap/nary/connection.rs +++ b/tools/test-framework/src/bootstrap/nary/connection.rs @@ -2,8 +2,8 @@ Functions for bootstrapping N-ary number of connections. */ -use core::convert::TryInto; use core::time::Duration; +use eyre::eyre; use ibc_relayer::chain::handle::ChainHandle; use ibc_relayer::foreign_client::ForeignClient; @@ -13,48 +13,44 @@ use crate::types::binary::connection::ConnectedConnection; use crate::types::binary::foreign_client::ForeignClientPair; use crate::types::nary::connection::{ConnectedConnections, DynamicConnectedConnections}; use crate::types::nary::foreign_client::ForeignClientPairs; -use crate::util::array::assert_same_dimension; +use crate::util::two_dim_hash_map::TwoDimMap; /** Bootstrap a dynamic number of connections based on the - given foreign client NxN matrix. + given foreign clients. + See [`crate::types::topology`] for more information. */ pub fn bootstrap_connections_dynamic( - foreign_clients: &Vec>>, + foreign_clients: &TwoDimMap>, connection_delay: Duration, bootstrap_with_random_ids: bool, ) -> Result, Error> { - let size = foreign_clients.len(); + let mut connections: TwoDimMap> = TwoDimMap::new(); - assert_same_dimension(size, foreign_clients)?; + for (src_chain, dst_chain, foreign_client) in foreign_clients.iter() { + let connection = if let Some(counterparty_connection) = + connections.get((dst_chain, src_chain)) + { + counterparty_connection.clone().flip() + } else { + // No connection is found, will create one + let client_a_to_b = foreign_client.clone(); + let client_b_to_a = foreign_clients.get((dst_chain, src_chain)).ok_or_else(|| { + Error::generic(eyre!( + "No client entry found from chain `{}` to `{}`", + dst_chain, + src_chain, + )) + })?; + let foreign_clients = ForeignClientPair::new(client_a_to_b, client_b_to_a.clone()); - let mut connections: Vec>> = Vec::new(); + let bootstrap_options = BootstrapConnectionOptions::default() + .connection_delay(connection_delay) + .bootstrap_with_random_ids(bootstrap_with_random_ids); - for (i, foreign_clients_b) in foreign_clients.iter().enumerate() { - let mut connections_b: Vec> = Vec::new(); - - for (j, foreign_client) in foreign_clients_b.iter().enumerate() { - if i <= j { - let counter_foreign_client = &foreign_clients[j][i]; - let foreign_clients = - ForeignClientPair::new(foreign_client.clone(), counter_foreign_client.clone()); - - let bootstrap_options = BootstrapConnectionOptions::default() - .connection_delay(connection_delay) - .bootstrap_with_random_ids(bootstrap_with_random_ids); - - let connection = bootstrap_connection(&foreign_clients, bootstrap_options)?; - - connections_b.push(connection); - } else { - let counter_connection = &connections[j][i]; - let connection = counter_connection.clone().flip(); - - connections_b.push(connection); - } - } - - connections.push(connections_b); + bootstrap_connection(&foreign_clients, bootstrap_options)? + }; + connections.insert((src_chain, dst_chain), connection); } Ok(DynamicConnectedConnections::new(connections)) diff --git a/tools/test-framework/src/bootstrap/single.rs b/tools/test-framework/src/bootstrap/single.rs index 5fec701964..df87589b35 100644 --- a/tools/test-framework/src/bootstrap/single.rs +++ b/tools/test-framework/src/bootstrap/single.rs @@ -4,7 +4,6 @@ use core::time::Duration; use eyre::eyre; use std::sync::{Arc, RwLock}; -use toml; use tracing::info; use crate::chain::builder::ChainBuilder; @@ -101,6 +100,7 @@ pub fn bootstrap_single_node( config::set_rpc_port(config, chain_driver.rpc_port)?; config::set_p2p_port(config, chain_driver.p2p_port)?; config::set_pprof_port(config, chain_driver.pprof_port)?; + config::set_block_sync(config, true)?; config::set_timeout_commit(config, Duration::from_secs(1))?; config::set_timeout_propose(config, Duration::from_secs(1))?; config::set_mode(config, "validator")?; @@ -113,7 +113,11 @@ pub fn bootstrap_single_node( let minimum_gas = format!("0{}", native_token); chain_driver.update_chain_config("app.toml", |config| { - config::set_grpc_port(config, chain_driver.grpc_port)?; + if builder.ipv6_grpc { + config::set_grpc_port_ipv6(config, chain_driver.grpc_port)?; + } else { + config::set_grpc_port(config, chain_driver.grpc_port)?; + } config::enable_grpc(config)?; config::disable_grpc_web(config)?; config::disable_api(config)?; diff --git a/tools/test-framework/src/chain/builder.rs b/tools/test-framework/src/chain/builder.rs index ff23be521f..89895dd274 100644 --- a/tools/test-framework/src/chain/builder.rs +++ b/tools/test-framework/src/chain/builder.rs @@ -45,6 +45,8 @@ pub struct ChainBuilder { pub compat_modes: Option>, + pub ipv6_grpc: bool, + pub runtime: Arc, } @@ -58,6 +60,7 @@ impl ChainBuilder { account_prefixes: Vec, native_tokens: Vec, compat_modes: Option>, + ipv6_grpc: bool, runtime: Arc, ) -> Self { Self { @@ -66,6 +69,7 @@ impl ChainBuilder { account_prefixes, native_tokens, compat_modes, + ipv6_grpc, runtime, } } @@ -80,6 +84,7 @@ impl ChainBuilder { config.account_prefixes.clone(), config.native_tokens.clone(), config.compat_modes.clone(), + config.ipv6_grpc, runtime, ) } @@ -146,6 +151,7 @@ impl ChainBuilder { self.runtime.clone(), self.native_tokens[native_token_number].clone(), compat_mode, + self.ipv6_grpc, )?; Ok(driver) diff --git a/tools/test-framework/src/chain/chain_type.rs b/tools/test-framework/src/chain/chain_type.rs index 5d5e6bfd08..309a91b00e 100644 --- a/tools/test-framework/src/chain/chain_type.rs +++ b/tools/test-framework/src/chain/chain_type.rs @@ -11,29 +11,39 @@ const PROVENANCE_HD_PATH: &str = "m/44'/505'/0'/0/0"; #[derive(Clone, Debug)] pub enum ChainType { - Cosmos, + Cosmos { dynamic_fee: bool }, + Osmosis, Evmos, Provenance, + Injective, } impl ChainType { pub fn hd_path(&self) -> &str { match self { - Self::Cosmos => COSMOS_HD_PATH, - Self::Evmos => EVMOS_HD_PATH, + Self::Cosmos { dynamic_fee: _ } | Self::Osmosis => COSMOS_HD_PATH, + Self::Evmos | Self::Injective => EVMOS_HD_PATH, Self::Provenance => PROVENANCE_HD_PATH, } } pub fn chain_id(&self, prefix: &str, use_random_id: bool) -> ChainId { match self { - Self::Cosmos => { + Self::Cosmos { dynamic_fee: _ } => { if use_random_id { ChainId::from_string(&format!("ibc-{}-{:x}", prefix, random_u32())) } else { ChainId::from_string(&format!("ibc{prefix}")) } } + Self::Osmosis => { + if use_random_id { + ChainId::from_string(&format!("osmosis-{}-{:x}", prefix, random_u32())) + } else { + ChainId::from_string(&format!("osmosis{prefix}")) + } + } + Self::Injective => ChainId::from_string(&format!("injective-{prefix}")), Self::Evmos => ChainId::from_string(&format!("evmos_9000-{prefix}")), Self::Provenance => ChainId::from_string(&format!("pio-mainnet-{prefix}")), } @@ -44,25 +54,48 @@ impl ChainType { let mut res = vec![]; let json_rpc_port = random_unused_tcp_port(); match self { - Self::Cosmos => {} + Self::Cosmos { dynamic_fee: _ } | Self::Injective | Self::Provenance => {} + Self::Osmosis => { + res.push("--reject-config-defaults".to_owned()); + } Self::Evmos => { res.push("--json-rpc.address".to_owned()); res.push(format!("localhost:{json_rpc_port}")); } - Self::Provenance => {} + } + res + } + + // Extra arguments required to run ` add-genesis-account` + pub fn extra_add_genesis_account_args(&self, chain_id: &ChainId) -> Vec { + let mut res = vec![]; + match self { + Self::Cosmos { dynamic_fee: _ } | Self::Osmosis | Self::Evmos | Self::Provenance => {} + Self::Injective => { + res.push("--chain-id".to_owned()); + res.push(format!("{chain_id}")); + } } res } pub fn address_type(&self) -> AddressType { match self { - Self::Cosmos => AddressType::default(), + Self::Cosmos { dynamic_fee: _ } | Self::Osmosis | Self::Provenance => { + AddressType::default() + } Self::Evmos => AddressType::Ethermint { pk_type: "/ethermint.crypto.v1.ethsecp256k1.PubKey".to_string(), }, - Self::Provenance => AddressType::default(), + Self::Injective => AddressType::Ethermint { + pk_type: "/injective.crypto.v1beta1.ethsecp256k1.PubKey".to_string(), + }, } } + + pub fn enable_dynamic_fee(&self) -> bool { + matches!(self, Self::Cosmos { dynamic_fee } if *dynamic_fee) + } } impl FromStr for ChainType { @@ -70,13 +103,14 @@ impl FromStr for ChainType { fn from_str(s: &str) -> Result { match s { - name if name.contains("gaiad") => Ok(ChainType::Cosmos), - name if name.contains("simd") => Ok(ChainType::Cosmos), - name if name.contains("wasmd") => Ok(ChainType::Cosmos), - name if name.contains("icad") => Ok(ChainType::Cosmos), + name if name.contains("gaiad") || name.contains("neutrond") => { + Ok(ChainType::Cosmos { dynamic_fee: true }) + } name if name.contains("evmosd") => Ok(ChainType::Evmos), + name if name.contains("injectived") => Ok(ChainType::Injective), name if name.contains("provenanced") => Ok(ChainType::Provenance), - _ => Ok(ChainType::Cosmos), + name if name.contains("osmosisd") => Ok(ChainType::Osmosis), + _ => Ok(ChainType::Cosmos { dynamic_fee: false }), } } } diff --git a/tools/test-framework/src/chain/cli/async_icq.rs b/tools/test-framework/src/chain/cli/async_icq.rs index f662a4beb9..345bf80058 100644 --- a/tools/test-framework/src/chain/cli/async_icq.rs +++ b/tools/test-framework/src/chain/cli/async_icq.rs @@ -1,5 +1,4 @@ -use std::str; - +use crate::chain::cli::query::query_tx_hash; use crate::chain::exec::simple_exec; use crate::error::Error; @@ -11,7 +10,7 @@ pub fn update_oracle( account: &str, relayer: &str, ) -> Result<(), Error> { - simple_exec( + let raw_output = simple_exec( chain_id, command_path, &[ @@ -21,8 +20,8 @@ pub fn update_oracle( chain_id, "--node", rpc_listen_address, - "-b", - "block", + "--keyring-backend", + "test", "tx", "oracle", "update", @@ -33,10 +32,26 @@ pub fn update_oracle( relayer, "--fees", "381000000nhash", + "--title", + "Update oracle", + "--summary", + "Update oracle", + "--output", + "json", "--yes", ], )?; + std::thread::sleep(core::time::Duration::from_secs(1)); + + query_tx_hash( + chain_id, + command_path, + home_path, + rpc_listen_address, + &raw_output.stdout, + )?; + Ok(()) } @@ -49,7 +64,7 @@ pub fn async_icq( query_json: &str, from: &str, ) -> Result<(), Error> { - simple_exec( + let raw_output = simple_exec( chain_id, command_path, &[ @@ -59,21 +74,33 @@ pub fn async_icq( chain_id, "--node", rpc_listen_address, + "--keyring-backend", + "test", "tx", "oracle", "send-query", channel_id, query_json, - "-b", - "block", "--from", from, "--fees", "381000000nhash", + "--output", + "json", "--yes", ], )?; + std::thread::sleep(core::time::Duration::from_secs(1)); + + query_tx_hash( + chain_id, + command_path, + home_path, + rpc_listen_address, + &raw_output.stdout, + )?; + Ok(()) } diff --git a/tools/test-framework/src/chain/cli/authz.rs b/tools/test-framework/src/chain/cli/authz.rs new file mode 100644 index 0000000000..d6bcf22a20 --- /dev/null +++ b/tools/test-framework/src/chain/cli/authz.rs @@ -0,0 +1,165 @@ +use eyre::eyre; +use std::collections::HashMap; +use std::thread; + +use crate::chain::exec::simple_exec; +use crate::error::Error; +use crate::prelude::*; + +pub fn authz_grant( + chain_id: &str, + command_path: &str, + home_path: &str, + rpc_listen_address: &str, + granter: &str, + grantee: &str, + msg_type: &str, + fees: &str, +) -> Result<(), Error> { + simple_exec( + chain_id, + command_path, + &[ + "--home", + home_path, + "--node", + rpc_listen_address, + "--chain-id", + chain_id, + "--keyring-backend", + "test", + "tx", + "authz", + "grant", + grantee, + "generic", + "--msg-type", + msg_type, + "--from", + granter, + "--fees", + fees, + "--yes", + "--log_format=json", + ], + )?; + + Ok(()) +} + +pub fn query_authz_grant( + chain_id: &str, + command_path: &str, + home_path: &str, + rpc_listen_address: &str, + granter: &str, + grantee: &str, + msg_type: &str, +) -> Result<(), Error> { + simple_exec( + chain_id, + command_path, + &[ + "--home", + home_path, + "--node", + rpc_listen_address, + "query", + "authz", + "grants", + granter, + grantee, + msg_type, + "--output", + "json", + ], + )?; + + Ok(()) +} + +pub fn exec_grant( + chain_id: &str, + command_path: &str, + home_path: &str, + rpc_listen_address: &str, + ibc_transfer_tx: &str, + grantee: &str, + fees: &str, +) -> Result<(), Error> { + let grant_exec_output = simple_exec( + chain_id, + command_path, + &[ + "--home", + home_path, + "--node", + rpc_listen_address, + "--keyring-backend", + "test", + "--chain-id", + chain_id, + "tx", + "authz", + "exec", + ibc_transfer_tx, + "--from", + grantee, + "--fees", + fees, + "--yes", + "--output", + "json", + ], + )?; + + let json_res: HashMap = + serde_json::from_str(&grant_exec_output.stdout).map_err(handle_generic_error)?; + + let txhash = json_res + .get("txhash") + .ok_or_else(|| eyre!("expect `txhash` string field to be present in json result"))? + .as_str() + .ok_or_else(|| eyre!("expected `txhash` to be an array"))?; + + thread::sleep(Duration::from_secs(2)); + + let query_txhash_output = simple_exec( + chain_id, + command_path, + &[ + "--home", + home_path, + "--node", + rpc_listen_address, + "query", + "tx", + "--type=hash", + txhash, + "--output", + "json", + ], + )?; + + let json_res: HashMap = + serde_json::from_str(&query_txhash_output.stdout).map_err(handle_generic_error)?; + + let raw_log = json_res + .get("raw_log") + .ok_or_else(|| eyre!("expect `raw_log` string field to be present in json result"))? + .as_str() + .ok_or_else(|| eyre!("expected `raw_log` to be a string"))?; + + let code = json_res + .get("code") + .ok_or_else(|| eyre!("expect `code` string field to be present in json result"))? + .as_u64() + .ok_or_else(|| eyre!("expected `code` to be a u64"))?; + + if !raw_log.is_empty() && code != 0 { + return Err(Error::generic(eyre!( + "expected authz exec to succeed but failed with code: {code} and logs: {raw_log}" + ))); + } + Ok(()) +} diff --git a/tools/test-framework/src/chain/cli/bootstrap.rs b/tools/test-framework/src/chain/cli/bootstrap.rs index 65dc1e9ed4..fbe530e2ff 100644 --- a/tools/test-framework/src/chain/cli/bootstrap.rs +++ b/tools/test-framework/src/chain/cli/bootstrap.rs @@ -62,35 +62,37 @@ pub fn add_genesis_account( home_path: &str, wallet_address: &str, amounts: &[String], + extra_start_args: &[&str], ) -> Result<(), Error> { let amounts_str = itertools::join(amounts, ","); + + let legacy_base_args = [ + "--home", + home_path, + "add-genesis-account", + wallet_address, + &amounts_str, + ]; + let mut legacy_args: Vec<&str> = legacy_base_args.to_vec(); + legacy_args.extend(extra_start_args.iter()); + + let base_args = [ + "--home", + home_path, + "genesis", + "add-genesis-account", + wallet_address, + &amounts_str, + ]; + let mut args: Vec<&str> = base_args.to_vec(); + args.extend(extra_start_args.iter()); + // Cosmos SDK v0.47.0 introduced the `genesis` subcommand, this match is required to // support pre and post SDK v0.47.0. https://github.com/cosmos/cosmos-sdk/pull/14149 - match simple_exec( - chain_id, - command_path, - &[ - "--home", - home_path, - "genesis", - "add-genesis-account", - wallet_address, - &amounts_str, - ], - ) { + match simple_exec(chain_id, command_path, &args) { Ok(_) => Ok(()), Err(_) => { - simple_exec( - chain_id, - command_path, - &[ - "--home", - home_path, - "add-genesis-account", - wallet_address, - &amounts_str, - ], - )?; + simple_exec(chain_id, command_path, &legacy_args)?; Ok(()) } } diff --git a/tools/test-framework/src/chain/cli/host_zone.rs b/tools/test-framework/src/chain/cli/host_zone.rs index 5ffb53ad77..94e2400e2a 100644 --- a/tools/test-framework/src/chain/cli/host_zone.rs +++ b/tools/test-framework/src/chain/cli/host_zone.rs @@ -31,13 +31,16 @@ pub fn register_host_zone( bech32_prefix, ibc_denom, channel_id, - "1", + "10", + "false", "--from", sender, "--chain-id", chain_id, "--gas", "auto", + "--gas-adjustment", + "1.3", "--yes", ], )?; diff --git a/tools/test-framework/src/chain/cli/mod.rs b/tools/test-framework/src/chain/cli/mod.rs index 5b2415d964..2d68ec6820 100644 --- a/tools/test-framework/src/chain/cli/mod.rs +++ b/tools/test-framework/src/chain/cli/mod.rs @@ -1,10 +1,13 @@ pub mod async_icq; +pub mod authz; pub mod bootstrap; pub mod fee_grant; pub mod host_zone; pub mod ica; +pub mod proposal; pub mod provider; pub mod query; pub mod transfer; pub mod upgrade; pub mod version; +pub mod wasm; diff --git a/tools/test-framework/src/chain/cli/proposal.rs b/tools/test-framework/src/chain/cli/proposal.rs new file mode 100644 index 0000000000..b8a0bc95e5 --- /dev/null +++ b/tools/test-framework/src/chain/cli/proposal.rs @@ -0,0 +1,181 @@ +/*! + Methods for voting on a proposal. +*/ +use eyre::eyre; +use tracing::warn; + +use crate::chain::cli::query::query_tx_hash; +use crate::chain::exec::simple_exec; +use crate::error::Error; +use crate::prelude::{handle_generic_error, ChainDriver}; + +pub fn vote_proposal(driver: &ChainDriver, proposal_id: &str, fees: &str) -> Result<(), Error> { + let output = simple_exec( + driver.chain_id.as_str(), + &driver.command_path, + &[ + "tx", + "gov", + "vote", + proposal_id, + "yes", + "--chain-id", + driver.chain_id.as_str(), + "--home", + &driver.home_path, + "--node", + &driver.rpc_listen_address(), + "--keyring-backend", + "test", + "--from", + "validator", + "--fees", + fees, + "--yes", + "--output", + "json", + ], + )?; + + std::thread::sleep(core::time::Duration::from_secs(1)); + + query_tx_hash( + driver.chain_id.as_str(), + &driver.command_path, + &driver.home_path, + &driver.rpc_listen_address(), + &output.stdout, + )?; + + Ok(()) +} + +pub fn deposit_proposal( + driver: &ChainDriver, + amount: &str, + proposal_id: &str, + fees: &str, + gas: &str, +) -> Result<(), Error> { + let output = simple_exec( + driver.chain_id.as_str(), + &driver.command_path, + &[ + "tx", + "gov", + "deposit", + proposal_id, + amount, + "--chain-id", + driver.chain_id.as_str(), + "--home", + &driver.home_path, + "--node", + &driver.rpc_listen_address(), + "--keyring-backend", + "test", + "--from", + "validator", + "--gas", + gas, + "--yes", + "--output", + "json", + "--fees", + fees, + ], + )?; + + std::thread::sleep(core::time::Duration::from_secs(1)); + + query_tx_hash( + driver.chain_id.as_str(), + &driver.command_path, + &driver.home_path, + &driver.rpc_listen_address(), + &output.stdout, + )?; + + Ok(()) +} + +pub fn submit_gov_proposal( + chain_id: &str, + command_path: &str, + home_path: &str, + rpc_listen_address: &str, + signer: &str, + proposal_file: &str, +) -> Result<(), Error> { + let proposal_file = format!("{}/{}", home_path, proposal_file); + let output = simple_exec( + chain_id, + command_path, + &[ + "--node", + rpc_listen_address, + "tx", + "gov", + "submit-proposal", + &proposal_file, + "--chain-id", + chain_id, + "--home", + home_path, + "--keyring-backend", + "test", + "--gas", + "20000000", + "--from", + signer, + "--output", + "json", + "--yes", + ], + )?; + + let json_output: serde_json::Value = + serde_json::from_str(&output.stdout).map_err(handle_generic_error)?; + + if json_output + .get("code") + .ok_or_else(|| eyre!("expected `code` field in output"))? + .as_u64() + .ok_or_else(|| eyre!("expected `code` to be a u64"))? + != 0 + { + let raw_log = json_output + .get("raw_log") + .ok_or_else(|| eyre!("expected `code` field in output"))? + .as_str() + .ok_or_else(|| eyre!("expected `raw_log` to be a str"))?; + warn!("failed to submit governance proposal due to `{raw_log}`. Will retry..."); + simple_exec( + chain_id, + command_path, + &[ + "--node", + rpc_listen_address, + "tx", + "gov", + "submit-proposal", + &proposal_file, + "--chain-id", + chain_id, + "--home", + home_path, + "--keyring-backend", + "test", + "--gas", + "20000000", + "--from", + signer, + "--output", + "json", + "--yes", + ], + )?; + } + + Ok(()) +} diff --git a/tools/test-framework/src/chain/cli/provider.rs b/tools/test-framework/src/chain/cli/provider.rs index 6a1c7c34f3..76310a2a6d 100644 --- a/tools/test-framework/src/chain/cli/provider.rs +++ b/tools/test-framework/src/chain/cli/provider.rs @@ -1,26 +1,28 @@ +use eyre::eyre; use std::collections::HashMap; -use std::str; +use std::{str, thread}; use crate::chain::exec::{simple_exec, ExecOutput}; -use crate::error::Error; +use crate::error::{handle_generic_error, Error}; pub fn submit_consumer_chain_proposal( chain_id: &str, command_path: &str, home_path: &str, rpc_listen_address: &str, + fees: &str, ) -> Result<(), Error> { - let proposal_file = format!("{}/consumer_proposal.json", home_path); + let proposal_file = format!("{}/consumer_proposal_topn.json", home_path); + thread::sleep(std::time::Duration::from_secs(3)); // The submission might fail silently if there is not enough gas - simple_exec( + let raw_output = simple_exec( chain_id, command_path, &[ "tx", "gov", "submit-proposal", - "consumer-addition", &proposal_file, "--chain-id", chain_id, @@ -34,10 +36,251 @@ pub fn submit_consumer_chain_proposal( "test", "--gas", "2000000", + "--fees", + fees, + "--output", + "json", + "--yes", + ], + )?; + + let output: serde_json::Value = + serde_json::from_str(&raw_output.stdout).map_err(handle_generic_error)?; + + let output_code = output.get("code").and_then(|code| code.as_u64()).ok_or_else(|| Error::generic(eyre!("failed to extract 'code' from 'tx gov submit-legacy-proposal consumer-addition' command")))?; + + // Proposal submission might fail due to account sequence error. + // Wait a bit and resubmit if the first submission fails + if output_code != 0 { + thread::sleep(std::time::Duration::from_secs(3)); + simple_exec( + chain_id, + command_path, + &[ + "tx", + "gov", + "submit-proposal", + &proposal_file, + "--chain-id", + chain_id, + "--from", + "validator", + "--home", + home_path, + "--node", + rpc_listen_address, + "--keyring-backend", + "test", + "--gas", + "2000000", + "--fees", + fees, + "--output", + "json", + "--yes", + ], + )?; + } + + Ok(()) +} + +pub fn create_consumer( + chain_id: &str, + command_path: &str, + home_path: &str, + rpc_listen_address: &str, + fees: &str, +) -> Result { + let proposal_file = format!("{}/consumer_proposal.json", home_path); + + // The submission might fail silently if there is not enough gas + let raw_output = simple_exec( + chain_id, + command_path, + &[ + "tx", + "provider", + "create-consumer", + &proposal_file, + "--chain-id", + chain_id, + "--from", + "validator", + "--home", + home_path, + "--node", + rpc_listen_address, + "--keyring-backend", + "test", + "--gas", + "2000000", + "--fees", + fees, + "--output", + "json", + "--yes", + ], + )?; + + let output: serde_json::Value = + serde_json::from_str(&raw_output.stdout).map_err(handle_generic_error)?; + + let hash = output.get("txhash").and_then(|code| code.as_str()).unwrap(); + + thread::sleep(std::time::Duration::from_secs(3)); + + let hash_output = simple_exec( + chain_id, + command_path, + &[ + "query", + "tx", + hash, + "--chain-id", + chain_id, + "--home", + home_path, + "--node", + rpc_listen_address, + "--output", + "json", + ], + )?; + + let hash_output_json: serde_json::Value = + serde_json::from_str(&hash_output.stdout).map_err(handle_generic_error)?; + + let output_code = output.get("code").and_then(|code| code.as_u64()).ok_or_else(|| Error::generic(eyre!("failed to extract 'code' from 'tx gov submit-legacy-proposal consumer-addition' command")))?; + + if output_code != 0 { + let output_logs = output.get("raw_log").and_then(|code| code.as_str()).ok_or_else(|| Error::generic(eyre!("failed to extract 'raw_logs' from 'tx gov submit-legacy-proposal consumer-addition' command")))?; + return Err(Error::generic(eyre!("output code for commande 'tx provider create-consumer' should be 0, but is instead '{output_code}'. Detail: {output_logs}", ))); + } + + let events = hash_output_json + .get("events") + .and_then(|code| code.as_array()) + .ok_or_else(|| { + Error::generic(eyre!( + "failed to extract 'events' from the output of `create-consumer` CLI" + )) + })?; + + let create_consumer_event = events + .iter() + .find(|v| v.get("type").and_then(|v| v.as_str()) == Some("create_consumer")) + .ok_or_else(|| Error::generic(eyre!("failed to extract create_consumer event")))?; + + let attributes = create_consumer_event + .get("attributes") + .and_then(|v| v.as_array()) + .ok_or_else(|| { + Error::generic(eyre!( + "failed to extract attributes from create_consumer event" + )) + })?; + + let consumer_id_attribute = attributes + .iter() + .find(|v| v.get("key").and_then(|v| v.as_str()) == Some("consumer_id")) + .ok_or_else(|| Error::generic(eyre!("failed to extract consumer_id attribute")))?; + + let consumer_id = consumer_id_attribute + .get("value") + .and_then(|v| v.as_str()) + .ok_or_else(|| Error::generic(eyre!("failed to extract consumer_id")))?; + + Ok(consumer_id.to_owned()) +} + +pub fn validator_opt_in( + chain_id: &str, + command_path: &str, + home_path: &str, + rpc_listen_address: &str, + fees: &str, + consumer_id: &str, +) -> Result<(), Error> { + simple_exec( + chain_id, + command_path, + &[ + "tx", + "provider", + "opt-in", + consumer_id, + "--chain-id", + chain_id, + "--from", + "validator", + "--home", + home_path, + "--node", + rpc_listen_address, + "--keyring-backend", + "test", + "--gas", + "2000000", + "--fees", + fees, + "--output", + "json", + "--yes", + ], + )?; + + Ok(()) +} + +pub fn update_consumer( + chain_id: &str, + command_path: &str, + home_path: &str, + rpc_listen_address: &str, + fees: &str, +) -> Result<(), Error> { + let proposal_file = format!("{}/consumer_update_proposal.json", home_path); + + // The submission might fail silently if there is not enough gas + let raw_output = simple_exec( + chain_id, + command_path, + &[ + "tx", + "provider", + "update-consumer", + &proposal_file, + "--chain-id", + chain_id, + "--from", + "validator", + "--home", + home_path, + "--node", + rpc_listen_address, + "--keyring-backend", + "test", + "--gas", + "2000000", + "--fees", + fees, + "--output", + "json", "--yes", ], )?; + let output: serde_json::Value = + serde_json::from_str(&raw_output.stdout).map_err(handle_generic_error)?; + + let output_code = output.get("code").and_then(|code| code.as_u64()).ok_or_else(|| Error::generic(eyre!("failed to extract 'code' from 'tx gov submit-legacy-proposal consumer-addition' command")))?; + + if output_code != 0 { + let output_logs = output.get("raw_log").and_then(|code| code.as_str()).ok_or_else(|| Error::generic(eyre!("failed to extract 'raw_logs' from 'tx gov submit-legacy-proposal consumer-addition' command")))?; + return Err(Error::generic(eyre!("output code for commande 'tx gov submit-legacy-proposal consumer-addition' should be 0, but is instead '{output_code}'. Detail: {output_logs}", ))); + } + Ok(()) } diff --git a/tools/test-framework/src/chain/cli/query.rs b/tools/test-framework/src/chain/cli/query.rs index 5bfb0801b5..9c662a7161 100644 --- a/tools/test-framework/src/chain/cli/query.rs +++ b/tools/test-framework/src/chain/cli/query.rs @@ -292,3 +292,59 @@ pub fn query_auth_module( Ok(res.to_owned()) } + +pub fn query_tx_hash( + chain_id: &str, + command_path: &str, + home_path: &str, + rpc_listen_address: &str, + command_output: &str, +) -> Result<(), Error> { + let json_output: serde_json::Value = + serde_json::from_str(command_output).map_err(handle_generic_error)?; + + let output_tx_hash = json_output + .get("txhash") + .and_then(|code| code.as_str()) + .ok_or_else(|| { + Error::generic(eyre!( + "failed to extract 'txhash' from command output: {command_output}" + )) + })?; + + let raw_output = simple_exec( + chain_id, + command_path, + &[ + "--home", + home_path, + "--node", + rpc_listen_address, + "query", + "tx", + output_tx_hash, + "--output", + "json", + ], + )?; + + let json_output: serde_json::Value = + serde_json::from_str(&raw_output.stdout).map_err(handle_generic_error)?; + + let code = json_output + .get("code") + .and_then(|code| code.as_u64()) + .ok_or_else(|| eyre!("Failed to retrieve 'code' from 'query tx' command output"))?; + + if code != 0 { + let raw_log = json_output + .get("raw_log") + .and_then(|code| code.as_str()) + .ok_or_else(|| eyre!("Failed to retrieve 'raw_log' from 'query tx' command output"))?; + return Err(Error::generic(eyre!( + "command failed with error code {code}. Detail: {raw_log}" + ))); + } + + Ok(()) +} diff --git a/tools/test-framework/src/chain/cli/transfer.rs b/tools/test-framework/src/chain/cli/transfer.rs index 53457c04ab..b1da0efb15 100644 --- a/tools/test-framework/src/chain/cli/transfer.rs +++ b/tools/test-framework/src/chain/cli/transfer.rs @@ -1,9 +1,10 @@ /*! Methods for performing IBC token transfer on a chain. */ +use eyre::eyre; use crate::chain::exec::simple_exec; -use crate::error::Error; +use crate::error::{handle_generic_error, Error}; pub fn local_transfer_token( chain_id: &str, @@ -13,8 +14,9 @@ pub fn local_transfer_token( sender: &str, recipient: &str, token: &str, + fees: &str, ) -> Result<(), Error> { - simple_exec( + let raw_output = simple_exec( chain_id, command_path, &[ @@ -32,10 +34,36 @@ pub fn local_transfer_token( home_path, "--keyring-backend", "test", + "--fees", + fees, + "--output", + "json", "--yes", ], )?; + let output: serde_json::Value = + serde_json::from_str(&raw_output.stdout).map_err(handle_generic_error)?; + + let output_code = output + .get("code") + .and_then(|code| code.as_u64()) + .ok_or_else(|| { + Error::generic(eyre!("failed to extract 'code' from 'tx gov vote' command")) + })?; + + if output_code != 0 { + let output_logs = output + .get("raw_log") + .and_then(|code| code.as_str()) + .ok_or_else(|| { + Error::generic(eyre!( + "failed to extract 'raw_logs' from 'tx gov vote' command" + )) + })?; + return Err(Error::generic(eyre!("output code for commande 'tx gov vote' should be 0, but is instead '{output_code}'. Detail: {output_logs}", ))); + } + Ok(()) } @@ -83,3 +111,42 @@ pub fn transfer_from_chain( Ok(()) } + +pub fn generate_transfer_from_chain_tx( + chain_id: &str, + command_path: &str, + home_path: &str, + rpc_listen_address: &str, + sender: &str, + src_port: &str, + src_channel: &str, + recipient: &str, + token: &str, +) -> Result { + let output = simple_exec( + chain_id, + command_path, + &[ + "--node", + rpc_listen_address, + "tx", + "ibc-transfer", + "transfer", + src_port, + src_channel, + recipient, + token, + "--from", + sender, + "--chain-id", + chain_id, + "--home", + home_path, + "--keyring-backend", + "test", + "--generate-only", + ], + )?; + + Ok(output.stdout) +} diff --git a/tools/test-framework/src/chain/cli/upgrade.rs b/tools/test-framework/src/chain/cli/upgrade.rs index ffb66f50b0..a781fbaa38 100644 --- a/tools/test-framework/src/chain/cli/upgrade.rs +++ b/tools/test-framework/src/chain/cli/upgrade.rs @@ -1,8 +1,11 @@ /*! Methods for voting on a proposal. */ +use eyre::eyre; + +use crate::chain::cli::query::query_tx_hash; use crate::chain::exec::simple_exec; -use crate::error::Error; +use crate::prelude::*; pub fn vote_proposal( chain_id: &str, @@ -10,8 +13,9 @@ pub fn vote_proposal( home_path: &str, rpc_listen_address: &str, fees: &str, + proposal_id: &str, ) -> Result<(), Error> { - simple_exec( + let output = simple_exec( chain_id, command_path, &[ @@ -20,7 +24,7 @@ pub fn vote_proposal( "tx", "gov", "vote", - "1", + proposal_id, "yes", "--chain-id", chain_id, @@ -32,9 +36,102 @@ pub fn vote_proposal( "validator", "--fees", fees, + "--output", + "json", "--yes", ], )?; + std::thread::sleep(core::time::Duration::from_secs(1)); + + query_tx_hash( + chain_id, + command_path, + home_path, + rpc_listen_address, + &output.stdout, + )?; + + Ok(()) +} + +pub fn submit_gov_proposal( + chain_id: &str, + command_path: &str, + home_path: &str, + rpc_listen_address: &str, + signer: &str, + proposal_file: &str, +) -> Result<(), Error> { + let proposal_file = format!("{}/{}", home_path, proposal_file); + let output = simple_exec( + chain_id, + command_path, + &[ + "--node", + rpc_listen_address, + "tx", + "gov", + "submit-proposal", + &proposal_file, + "--chain-id", + chain_id, + "--home", + home_path, + "--keyring-backend", + "test", + "--gas", + "20000000", + "--from", + signer, + "--output", + "json", + "--yes", + ], + )?; + + let json_output: serde_json::Value = + serde_json::from_str(&output.stdout).map_err(handle_generic_error)?; + + if json_output + .get("code") + .ok_or_else(|| eyre!("expected `code` field in output"))? + .as_u64() + .ok_or_else(|| eyre!("expected `code` to be a u64"))? + != 0 + { + let raw_log = json_output + .get("raw_log") + .ok_or_else(|| eyre!("expected `code` field in output"))? + .as_str() + .ok_or_else(|| eyre!("expected `raw_log` to be a str"))?; + warn!("failed to submit governance proposal due to `{raw_log}`. Will retry..."); + simple_exec( + chain_id, + command_path, + &[ + "--node", + rpc_listen_address, + "tx", + "gov", + "submit-proposal", + &proposal_file, + "--chain-id", + chain_id, + "--home", + home_path, + "--keyring-backend", + "test", + "--gas", + "20000000", + "--from", + signer, + "--output", + "json", + "--yes", + ], + )?; + } + Ok(()) } diff --git a/tools/test-framework/src/chain/cli/wasm/contract.rs b/tools/test-framework/src/chain/cli/wasm/contract.rs new file mode 100644 index 0000000000..f8dc207b60 --- /dev/null +++ b/tools/test-framework/src/chain/cli/wasm/contract.rs @@ -0,0 +1,162 @@ +use std::path::Path; + +use crate::chain::cli::query::query_tx_hash; +use crate::chain::exec::simple_exec; +use crate::error::Error; +use crate::prelude::ChainDriver; + +pub fn store_wasm_contract( + driver: &ChainDriver, + title: &str, + summary: &str, + wasm_file: &str, + authority: &str, + from: &str, + deposit: &str, + fees: &str, + gas: &str, +) -> Result { + let output = simple_exec( + driver.chain_id.as_str(), + &driver.command_path, + &[ + "--chain-id", + driver.chain_id.as_str(), + "--node", + &driver.rpc_listen_address(), + "--home", + &driver.home_path, + "--keyring-backend", + "test", + "tx", + "wasm", + "submit-proposal", + "wasm-store", + wasm_file, + "--title", + title, + "--summary", + summary, + "--authority", + authority, + "--deposit", + deposit, + "--output", + "json", + "--from", + from, + "--fees", + fees, + "--yes", + "--gas", + gas, + ], + )?; + + std::thread::sleep(core::time::Duration::from_secs(1)); + + query_tx_hash( + driver.chain_id.as_str(), + &driver.command_path, + &driver.home_path, + &driver.rpc_listen_address(), + &output.stdout, + )?; + + Ok(output.stdout) +} + +pub fn store_wasm_client_code( + driver: &ChainDriver, + code_path: &Path, + title: &str, + summary: &str, + signer: &str, +) -> Result { + let output = simple_exec( + driver.chain_id.as_str(), + &driver.command_path, + &[ + "tx", + "ibc-wasm", + "store-code", + code_path.to_str().unwrap(), + "--title", + title, + "--summary", + summary, + "--chain-id", + driver.chain_id.as_str(), + "--node", + &driver.rpc_listen_address(), + "--home", + &driver.home_path, + "--from", + signer, + "--keyring-backend", + "test", + "--gas", + "auto", + "--deposit", + "200000stake", + "-y", + "--output", + "json", + ], + )?; + + Ok(output.stdout) +} + +pub fn instantiate_wasm_contract( + chain_id: &str, + command_path: &str, + home_path: &str, + rpc_listen_address: &str, + address: &str, + fees: &str, + code: &str, + init_args: &str, +) -> Result<(), Error> { + let exec_output = simple_exec( + chain_id, + command_path, + &[ + "--home", + home_path, + "--chain-id", + chain_id, + "--node", + rpc_listen_address, + "--keyring-backend", + "test", + "tx", + "wasm", + "instantiate", + code, + init_args, + "--from", + address, + "--yes", + "--label", + "echo", + "--no-admin", + "--fees", + fees, + "--output", + "json", + ], + )?; + + std::thread::sleep(core::time::Duration::from_secs(1)); + + query_tx_hash( + chain_id, + command_path, + home_path, + rpc_listen_address, + &exec_output.stdout, + )?; + + Ok(()) +} diff --git a/tools/test-framework/src/chain/cli/wasm/mod.rs b/tools/test-framework/src/chain/cli/wasm/mod.rs new file mode 100644 index 0000000000..fec57bbb9f --- /dev/null +++ b/tools/test-framework/src/chain/cli/wasm/mod.rs @@ -0,0 +1,2 @@ +pub mod contract; +pub mod query; diff --git a/tools/test-framework/src/chain/cli/wasm/query.rs b/tools/test-framework/src/chain/cli/wasm/query.rs new file mode 100644 index 0000000000..fb2835c54b --- /dev/null +++ b/tools/test-framework/src/chain/cli/wasm/query.rs @@ -0,0 +1,81 @@ +use eyre::eyre; + +use crate::chain::exec::simple_exec; +use crate::error::{handle_generic_error, Error}; + +pub fn query_wasm_list_code( + chain_id: &str, + command_path: &str, + home_path: &str, + rpc_listen_address: &str, +) -> Result { + let exec_output = simple_exec( + chain_id, + command_path, + &[ + "--home", + home_path, + "--chain-id", + chain_id, + "--node", + rpc_listen_address, + "query", + "wasm", + "list-codes", + "--output", + "json", + ], + )?; + + let json_output: serde_json::Value = + serde_json::from_str(&exec_output.stdout).map_err(handle_generic_error)?; + + let code_id = json_output + .get("code_infos") + .and_then(|code_infos| code_infos.as_array()) + .and_then(|code_infos| code_infos.first()) + .and_then(|code_info| code_info.get("code_id")) + .and_then(|code_infos| code_infos.as_str()) + .ok_or_else(|| eyre!("Failed to retrieve wasm code ID"))?; + + Ok(code_id.to_string()) +} + +pub fn query_wasm_list_contracts_by_code( + chain_id: &str, + command_path: &str, + home_path: &str, + rpc_listen_address: &str, + code_id: &str, +) -> Result { + let exec_output = simple_exec( + chain_id, + command_path, + &[ + "--home", + home_path, + "--chain-id", + chain_id, + "--node", + rpc_listen_address, + "query", + "wasm", + "list-contract-by-code", + code_id, + "--output", + "json", + ], + )?; + + let json_output: serde_json::Value = + serde_json::from_str(&exec_output.stdout).map_err(handle_generic_error)?; + + let contrat = json_output + .get("contracts") + .and_then(|contracts| contracts.as_array()) + .and_then(|contracts| contracts.first()) + .and_then(|contract| contract.as_str()) + .ok_or_else(|| eyre!("Failed to retrieve wasm contract address"))?; + + Ok(contrat.to_string()) +} diff --git a/tools/test-framework/src/chain/config.rs b/tools/test-framework/src/chain/config.rs index 66f4f3a02d..4d76a1cf43 100644 --- a/tools/test-framework/src/chain/config.rs +++ b/tools/test-framework/src/chain/config.rs @@ -45,6 +45,17 @@ pub fn set_grpc_port(config: &mut Value, port: u16) -> Result<(), Error> { Ok(()) } +pub fn set_grpc_port_ipv6(config: &mut Value, port: u16) -> Result<(), Error> { + config + .get_mut("grpc") + .ok_or_else(|| eyre!("expect grpc section"))? + .as_table_mut() + .ok_or_else(|| eyre!("expect object"))? + .insert("address".to_string(), format!("[::]:{port}").into()); + + Ok(()) +} + pub fn disable_grpc_web(config: &mut Value) -> Result<(), Error> { if let Some(field) = config.get_mut("grpc-web") { field @@ -92,6 +103,16 @@ pub fn set_pprof_port(config: &mut Value, port: u16) -> Result<(), Error> { Ok(()) } +/// Set the `pprof_laddr` field in the full node config. +pub fn set_block_sync(config: &mut Value, value: bool) -> Result<(), Error> { + config + .as_table_mut() + .ok_or_else(|| eyre!("expect object"))? + .insert("block_sync".to_string(), value.into()); + + Ok(()) +} + pub fn set_mempool_version(config: &mut Value, version: &str) -> Result<(), Error> { config .get_mut("mempool") @@ -190,6 +211,51 @@ pub fn set_max_deposit_period(genesis: &mut serde_json::Value, period: &str) -> Ok(()) } +pub fn add_allow_message_interchainaccounts( + genesis: &mut serde_json::Value, + message: &str, +) -> Result<(), Error> { + let allow_messages = genesis + .get_mut("app_state") + .and_then(|app_state| app_state.get_mut("interchainaccounts")) + .and_then(|ica| ica.get_mut("host_genesis_state")) + .and_then(|state| state.get_mut("params")) + .and_then(|params| params.get_mut("allow_messages")) + .and_then(|allow_messages| allow_messages.as_array_mut()) + .ok_or_else(|| { + eyre!("failed to retrieve allow_messages as a vector, in the genesis file") + })?; + + // Only add `MsgSend` if the wildcard '*' is not specified + if allow_messages.iter().all(|v| v.as_str() != Some("*")) { + allow_messages.push(serde_json::Value::String(message.to_string())); + } + + Ok(()) +} + +pub fn add_allow_message_interchainquery( + genesis: &mut serde_json::Value, + message: &str, +) -> Result<(), Error> { + let allow_messages = genesis + .get_mut("app_state") + .and_then(|app_state| app_state.get_mut("interchainquery")) + .and_then(|ica| ica.get_mut("params")) + .and_then(|params| params.get_mut("allow_queries")) + .and_then(|allow_messages| allow_messages.as_array_mut()) + .ok_or_else(|| { + eyre!("failed to retrieve allow_messages as a vector, in the genesis file") + })?; + + // Only add `MsgSend` if the wildcard '*' is not specified + if allow_messages.iter().all(|v| v.as_str() != Some("*")) { + allow_messages.push(serde_json::Value::String(message.to_string())); + } + + Ok(()) +} + pub fn set_min_deposit_amount( genesis: &mut serde_json::Value, min_deposit_amount: u64, @@ -359,11 +425,18 @@ pub fn consensus_params_max_gas( genesis: &mut serde_json::Value, max_gas: &str, ) -> Result<(), Error> { - let block = genesis - .get_mut("consensus_params") - .and_then(|consensus_params| consensus_params.get_mut("block")) - .and_then(|block| block.as_object_mut()) - .ok_or_else(|| eyre!("failed to get `block` field in genesis file"))?; + let block = match genesis.get_mut("consensus_params") { + Some(consensus_params) => consensus_params + .get_mut("block") + .and_then(|block| block.as_object_mut()) + .ok_or_else(|| eyre!("failed to get `block` field in genesis file"))?, + None => genesis + .get_mut("consensus") + .and_then(|consensus| consensus.get_mut("params")) + .and_then(|params| params.get_mut("block")) + .and_then(|block| block.as_object_mut()) + .ok_or_else(|| eyre!("failed to get `block` field in genesis file"))?, + }; block.insert( "max_gas".to_owned(), @@ -397,6 +470,60 @@ pub fn globalfee_minimum_gas_prices( Ok(()) } +pub fn set_retry_delay_period( + genesis: &mut serde_json::Value, + retry_delay_period: &str, +) -> Result<(), Error> { + let params = genesis + .get_mut("app_state") + .and_then(|app_state| app_state.get_mut("ccvconsumer")) + .and_then(|ccvconsumer| ccvconsumer.get_mut("params")) + .and_then(|params| params.as_object_mut()) + .ok_or_else(|| eyre!("failed to get ccvconsumer params in genesis file"))?; + + params.insert( + "retry_delay_period".to_owned(), + serde_json::Value::String(retry_delay_period.to_string()), + ); + + Ok(()) +} + +pub fn set_floor_gas_price( + genesis: &mut serde_json::Value, + amount: &str, + denom: &str, + nhash_per_usd_mil: &str, +) -> Result<(), Error> { + let params = genesis + .get_mut("app_state") + .and_then(|app_state| app_state.get_mut("msgfees")) + .and_then(|msgfees| msgfees.get_mut("params")) + .and_then(|params| params.as_object_mut()) + .ok_or_else(|| eyre!("failed to get `msgfees params` in genesis file"))?; + + params.insert( + "nhash_per_usd_mil".to_owned(), + serde_json::Value::String(nhash_per_usd_mil.to_string()), + ); + + let floor_gas_price = params + .get_mut("floor_gas_price") + .and_then(|floor_gas_price| floor_gas_price.as_object_mut()) + .ok_or_else(|| eyre!("failed to get `floor_gas_price` params in genesis file"))?; + + floor_gas_price.insert( + "amount".to_owned(), + serde_json::Value::String(amount.to_string()), + ); + floor_gas_price.insert( + "denom".to_owned(), + serde_json::Value::String(denom.to_string()), + ); + + Ok(()) +} + /// Look up a key in a JSON object, falling back to the second key if the first one cannot be found. /// /// This lets us support both Tendermint 0.34 and 0.37, which sometimes use different keys for the diff --git a/tools/test-framework/src/chain/driver.rs b/tools/test-framework/src/chain/driver.rs index 4b3414c554..bd4aba6543 100644 --- a/tools/test-framework/src/chain/driver.rs +++ b/tools/test-framework/src/chain/driver.rs @@ -2,14 +2,14 @@ Implementation of [`ChainDriver`]. */ -use core::time::Duration; - use alloc::sync::Arc; +use core::time::Duration; use eyre::eyre; -use ibc_relayer::config::compat_mode::CompatMode; +use std::cmp::max; use tokio::runtime::Runtime; use ibc_relayer::chain::cosmos::types::config::TxConfig; +use ibc_relayer::config::compat_mode::CompatMode; use ibc_relayer_types::applications::transfer::amount::Amount; use ibc_relayer_types::core::ics24_host::identifier::ChainId; @@ -98,6 +98,8 @@ pub struct ChainDriver { pub runtime: Arc, pub compat_mode: Option, + + pub ipv6_grpc: bool, } impl ExportEnv for ChainDriver { @@ -125,11 +127,18 @@ impl ChainDriver { runtime: Arc, native_token: String, compat_mode: Option, + ipv6_grpc: bool, ) -> Result { + let grpc_address = if ipv6_grpc { + format!("http://[::1]:{grpc_port}") + } else { + format!("http://localhost:{grpc_port}") + }; let tx_config = new_tx_config_for_test( chain_id.clone(), + chain_type.clone(), format!("http://localhost:{rpc_port}"), - format!("http://localhost:{grpc_port}"), + grpc_address, chain_type.address_type(), native_token, )?; @@ -148,6 +157,7 @@ impl ChainDriver { tx_config, runtime, compat_mode, + ipv6_grpc, }) } @@ -163,7 +173,11 @@ impl ChainDriver { /// Returns the full URL for the GRPC address. pub fn grpc_address(&self) -> String { - format!("http://localhost:{}", self.grpc_port) + if self.ipv6_grpc { + format!("http://[::1]:{}", self.grpc_port) + } else { + format!("http://127.0.0.1:{}", self.grpc_port) + } } /** @@ -185,7 +199,11 @@ impl ChainDriver { as it requires no scheme to be specified. */ pub fn grpc_listen_address(&self) -> String { - format!("localhost:{}", self.grpc_port) + if self.ipv6_grpc { + format!("[::1]:{}", self.grpc_port) + } else { + format!("127.0.0.1:{}", self.grpc_port) + } } /** @@ -232,4 +250,63 @@ impl ChainDriver { Ok(()) } + + /** + Assert that a wallet should eventually have escrowed the amount for ICS29 + fees of a given denomination. + Legacy ICS29 will escrow recv_fee + ack_fee + timeout_fee while more recent + versions will escrow max(recv_fee + ack_fee, timeout_fee). + */ + pub fn assert_eventual_escrowed_amount_ics29( + &self, + wallet: &WalletAddress, + token: &Token, + recv_fee: u128, + ack_fee: u128, + timeout_fee: u128, + ) -> Result<(), Error> { + assert_eventually_succeed( + &format!("wallet reach {wallet} amount {token}"), + WAIT_WALLET_AMOUNT_ATTEMPTS, + Duration::from_secs(1), + || { + let amount: Amount = self.query_balance(wallet, &token.denom)?; + + let legacy_escrow = token + .amount + .checked_sub(recv_fee + ack_fee + timeout_fee) + .ok_or_else(|| { + Error::generic(eyre!( + "error computing the following subtraction: {}-{}", + token.amount, + recv_fee + ack_fee + timeout_fee + )) + })?; + let escrow = token + .amount + .checked_sub(max(recv_fee + ack_fee, timeout_fee)) + .ok_or_else(|| { + Error::generic(eyre!( + "error computing the following subtraction: {}-{}", + token.amount, + max(recv_fee + ack_fee, timeout_fee) + )) + })?; + + // Assert either the legacy or current ICS29 amount has been escrowed + if amount == legacy_escrow || amount == escrow { + Ok(()) + } else { + Err(Error::generic(eyre!( + "current balance of account {} with amount {} does not match the target amount {}", + wallet, + amount, + token + ))) + } + }, + )?; + + Ok(()) + } } diff --git a/tools/test-framework/src/chain/ext/async_icq.rs b/tools/test-framework/src/chain/ext/async_icq.rs index 60998ea5d3..ec0a59fa56 100644 --- a/tools/test-framework/src/chain/ext/async_icq.rs +++ b/tools/test-framework/src/chain/ext/async_icq.rs @@ -1,24 +1,51 @@ use crate::chain::cli::async_icq::{async_icq, update_oracle}; -use crate::chain::driver::ChainDriver; -use crate::error::Error; +use crate::chain::cli::wasm::contract::instantiate_wasm_contract; +use crate::chain::cli::wasm::query::{query_wasm_list_code, query_wasm_list_contracts_by_code}; use crate::prelude::*; use crate::types::tagged::*; pub trait AsyncIcqMethodsExt { - fn update_oracle(&self, relayer: &str, account: &str) -> Result<(), Error>; + fn update_oracle(&self, relayer: &str, fees: &str, init_args: &str) -> Result<(), Error>; fn async_icq(&self, channel_id: &ChannelId, query_json: &str, from: &str) -> Result<(), Error>; } -impl<'a, Chain: Send> AsyncIcqMethodsExt for MonoTagged { - fn update_oracle(&self, relayer: &str, account: &str) -> Result<(), Error> { +impl AsyncIcqMethodsExt for MonoTagged { + fn update_oracle(&self, relayer: &str, fees: &str, init_args: &str) -> Result<(), Error> { let driver = *self.value(); + + let wasm_code = query_wasm_list_code( + driver.chain_id.as_str(), + &driver.command_path, + &driver.home_path, + &driver.rpc_listen_address(), + )?; + + instantiate_wasm_contract( + driver.chain_id.as_str(), + &driver.command_path, + &driver.home_path, + &driver.rpc_listen_address(), + relayer, + fees, + &wasm_code, + init_args, + )?; + + let address = query_wasm_list_contracts_by_code( + driver.chain_id.as_str(), + &driver.command_path, + &driver.home_path, + &driver.rpc_listen_address(), + &wasm_code, + )?; + update_oracle( driver.chain_id.as_str(), &driver.command_path, &driver.home_path, &driver.rpc_listen_address(), - account, + &address, relayer, ) } diff --git a/tools/test-framework/src/chain/ext/authz.rs b/tools/test-framework/src/chain/ext/authz.rs new file mode 100644 index 0000000000..a87cda86b2 --- /dev/null +++ b/tools/test-framework/src/chain/ext/authz.rs @@ -0,0 +1,124 @@ +use crate::chain::cli::authz::{authz_grant, exec_grant, query_authz_grant}; +use crate::chain::cli::transfer::generate_transfer_from_chain_tx; +use crate::error::Error; +use crate::prelude::*; +use crate::types::tagged::MonoTagged; + +use super::bootstrap::ChainBootstrapMethodsExt; + +const WAIT_GRANT_ATTEMPTS: u16 = 5; + +pub trait AuthzMethodsExt { + fn authz_grant( + &self, + granter: &str, + grantee: &str, + msg_type: &str, + fees: &str, + ) -> Result<(), Error>; + + fn assert_eventual_grant( + &self, + granter: &str, + grantee: &str, + msg_type: &str, + ) -> Result<(), Error>; + + fn exec_ibc_transfer_grant( + &self, + granter: &str, + grantee: &str, + port: &PortId, + channel: &ChannelId, + recipient: &MonoTagged, + token: &TaggedTokenRef, + fees: &str, + ) -> Result<(), Error>; +} + +impl AuthzMethodsExt for MonoTagged { + fn authz_grant( + &self, + granter: &str, + grantee: &str, + msg_type: &str, + fees: &str, + ) -> Result<(), Error> { + authz_grant( + self.value().chain_id.as_str(), + &self.value().command_path, + &self.value().home_path, + &self.value().rpc_listen_address(), + granter, + grantee, + msg_type, + fees, + ) + } + + fn assert_eventual_grant( + &self, + granter: &str, + grantee: &str, + msg_type: &str, + ) -> Result<(), Error> { + assert_eventually_succeed( + &format!("successful grant from granter {granter} to grantee {grantee}"), + WAIT_GRANT_ATTEMPTS, + Duration::from_secs(1), + || { + query_authz_grant( + self.value().chain_id.as_str(), + &self.value().command_path, + &self.value().home_path, + &self.value().rpc_listen_address(), + granter, + grantee, + msg_type, + ) + }, + )?; + + Ok(()) + } + + fn exec_ibc_transfer_grant( + &self, + granter: &str, + grantee: &str, + port: &PortId, + channel: &ChannelId, + recipient: &MonoTagged, + token: &TaggedTokenRef, + fees: &str, + ) -> Result<(), Error> { + let ibc_transfer_tx = generate_transfer_from_chain_tx( + self.value().chain_id.as_str(), + &self.value().command_path, + &self.value().home_path, + &self.value().rpc_listen_address(), + granter, + port.as_ref(), + channel.as_ref(), + recipient.value().as_str(), + &token.value().to_string(), + )?; + + let ibc_transfer_tx_filename = "ibc-transfer.json"; + + self.value() + .write_file(ibc_transfer_tx_filename, &ibc_transfer_tx)?; + + exec_grant( + self.value().chain_id.as_str(), + &self.value().command_path, + &self.value().home_path, + &self.value().rpc_listen_address(), + &format!("{}/{ibc_transfer_tx_filename}", self.value().home_path), + grantee, + fees, + )?; + + Ok(()) + } +} diff --git a/tools/test-framework/src/chain/ext/bootstrap.rs b/tools/test-framework/src/chain/ext/bootstrap.rs index 37f7818d75..07103fcd05 100644 --- a/tools/test-framework/src/chain/ext/bootstrap.rs +++ b/tools/test-framework/src/chain/ext/bootstrap.rs @@ -1,3 +1,6 @@ +use chrono::DateTime; +use chrono::Duration as ChronoDuration; +use chrono::Utc; use core::str::FromStr; use eyre::eyre; use hdpath::StandardHDPath; @@ -6,7 +9,6 @@ use std::fs; use std::path::PathBuf; use std::str; use std::time::Duration; -use toml; use tracing::debug; use ibc_relayer::keyring::{Secp256k1KeyPair, SigningKeyPair}; @@ -15,10 +17,12 @@ use crate::chain::cli::bootstrap::{ add_genesis_account, add_genesis_validator, add_wallet, collect_gen_txs, initialize, start_chain, }; +use crate::chain::cli::provider::submit_consumer_chain_proposal; use crate::chain::cli::provider::{ - copy_validator_key_pair, query_consumer_genesis, query_gov_proposal, replace_genesis_state, - submit_consumer_chain_proposal, + copy_validator_key_pair, create_consumer, query_consumer_genesis, query_gov_proposal, + replace_genesis_state, update_consumer, validator_opt_in, }; +use crate::chain::cli::query::query_auth_module; use crate::chain::driver::ChainDriver; use crate::chain::exec::simple_exec; use crate::error::{handle_generic_error, Error}; @@ -107,7 +111,22 @@ pub trait ChainBootstrapMethodsExt { fn submit_consumer_chain_proposal( &self, consumer_chain_id: &str, - spawn_time: &str, + fees: &str, + ) -> Result<(), Error>; + + fn create_permisionless_consumer( + &self, + consumer_chain_id: &str, + fees: &str, + ) -> Result; + + fn validator_opt_in(&self, consumer_chain_id: &str, fees: &str) -> Result<(), Error>; + + fn update_consumer( + &self, + consumer_chain_id: &str, + fees: &str, + validator: &str, ) -> Result<(), Error>; /** @@ -231,6 +250,9 @@ impl ChainBootstrapMethodsExt for ChainDriver { fn add_genesis_account(&self, wallet: &WalletAddress, amounts: &[&Token]) -> Result<(), Error> { let amounts_str = amounts.iter().map(|t| t.to_string()).collect::>(); + let extra_args = self + .chain_type + .extra_add_genesis_account_args(&self.chain_id); add_genesis_account( self.chain_id.as_str(), @@ -238,6 +260,7 @@ impl ChainBootstrapMethodsExt for ChainDriver { &self.home_path, &wallet.0, &amounts_str, + &extra_args.iter().map(|s| s.as_ref()).collect::>(), ) } @@ -273,8 +296,133 @@ impl ChainBootstrapMethodsExt for ChainDriver { fn submit_consumer_chain_proposal( &self, consumer_chain_id: &str, - _spawn_time: &str, + fees: &str, ) -> Result<(), Error> { + let raw_proposal = r#" + { + "chain_id": "{consumer_chain_id}", + "initialization_parameters": { + "initial_height": { + "revision_number": 0, + "revision_height": 1 + }, + "genesis_hash": "Z2VuX2hhc2g=", + "binary_hash": "YmluX2hhc2g=", + "spawn_time": "{spawn_time}", + "unbonding_period": 100000000000, + "ccv_timeout_period": 100000000000, + "transfer_timeout_period": 100000000000, + "consumer_redistribution_fraction": "0.75", + "blocks_per_distribution_transmission": 10, + "historical_entries": 10000, + "distribution_transmission_channel": "" + }, + "power_shaping_parameters": { + "top_N": 100, + "validators_power_cap": 0, + "validator_set_cap": 0, + "allowlist": [], + "denylist": [], + "min_stake": 0, + "allow_inactive_vals": false + }, + "metadata": "ipfs://CID", + "deposit": "10000000stake", + "title": "\"update consumer 0 to top N\"", + "summary": "\"update consumer 0 to top N\"", + "expedited": false + }"#; + + let current_time: DateTime = Utc::now(); + let future_time = current_time + ChronoDuration::seconds(30); + let spawn_time = future_time.to_rfc3339(); + + let proposal = raw_proposal.replace("{consumer_chain_id}", consumer_chain_id); + let proposal = proposal.replace("{spawn_time}", &spawn_time); + + self.write_file("consumer_proposal_topn.json", &proposal)?; + + submit_consumer_chain_proposal( + self.chain_id.as_str(), + &self.command_path, + &self.home_path, + &self.rpc_listen_address(), + fees, + ) + } + + fn create_permisionless_consumer( + &self, + consumer_chain_id: &str, + fees: &str, + ) -> Result { + let raw_proposal = r#" + { + "chain_id": "{consumer_chain_id}", + "metadata": { + "name": "consumer-1-metadata-name", + "description":"consumer-1-metadata-description", + "metadata": "consumer-1-metadata-metadata" + }, + "initialization_parameters": { + "initial_height": { + "revision_number": 0, + "revision_height": 1 + }, + "genesis_hash": "Z2VuX2hhc2g=", + "binary_hash": "YmluX2hhc2g=", + "spawn_time": "{spawn_time}", + "unbonding_period": 100000000000, + "ccv_timeout_period": 100000000000, + "transfer_timeout_period": 100000000000, + "consumer_redistribution_fraction": "0.75", + "blocks_per_distribution_transmission": 10, + "historical_entries": 10000, + "distribution_transmission_channel": "" + } + }"#; + let current_time: DateTime = Utc::now(); + let future_time = current_time + ChronoDuration::seconds(30); + let spawn_time = future_time.to_rfc3339(); + + let proposal = raw_proposal.replace("{consumer_chain_id}", consumer_chain_id); + let proposal = proposal.replace("{spawn_time}", &spawn_time); + + self.write_file("consumer_proposal.json", &proposal)?; + + create_consumer( + self.chain_id.as_str(), + &self.command_path, + &self.home_path, + &self.rpc_listen_address(), + fees, + ) + } + + fn validator_opt_in(&self, consumer_chain_id: &str, fees: &str) -> Result<(), Error> { + validator_opt_in( + self.chain_id.as_str(), + &self.command_path, + &self.home_path, + &self.rpc_listen_address(), + fees, + consumer_chain_id, + ) + } + + fn update_consumer( + &self, + consumer_chain_id: &str, + fees: &str, + validator: &str, + ) -> Result<(), Error> { + let gov_address = query_auth_module( + self.chain_id.as_str(), + &self.command_path, + &self.home_path, + &self.rpc_listen_address(), + "gov", + )?; let res = simple_exec( self.chain_id.as_str(), "jq", @@ -289,36 +437,28 @@ impl ChainBootstrapMethodsExt for ChainDriver { spawn_time.pop(); let raw_proposal = r#" { - "title": "Create consumer chain", - "description": "First consumer chain", - "chain_id": "{consumer_chain_id}", - "initial_height": { - "revision_number": 1, - "revision_height": 1 - }, - "genesis_hash": "Z2VuX2hhc2g=", - "binary_hash": "YmluX2hhc2g=", - "spawn_time": "{spawn_time}", - "blocks_per_distribution_transmission": 10, - "consumer_redistribution_fraction": "0.75", - "distribution_transmission_channel": "", - "historical_entries": 10000, - "transfer_timeout_period": 100000000000, - "ccv_timeout_period": 100000000000, - "unbonding_period": 100000000000, - "deposit": "10000001stake" + "consumer_id": "{consumer_chain_id}", + "owner_address": "{validator}", + "new_owner_address": "{gov_address}", + "metadata": { + "name": "consumer-1-metadata-name", + "description":"consumer-1-metadata-description", + "metadata": "consumer-1-metadata-metadata" + } }"#; let proposal = raw_proposal.replace("{consumer_chain_id}", consumer_chain_id); - let proposal = proposal.replace("{spawn_time}", &spawn_time); + let proposal = proposal.replace("{gov_address}", &gov_address); + let proposal = proposal.replace("{validator}", validator); - self.write_file("consumer_proposal.json", &proposal)?; + self.write_file("consumer_update_proposal.json", &proposal)?; - submit_consumer_chain_proposal( + update_consumer( self.chain_id.as_str(), &self.command_path, &self.home_path, &self.rpc_listen_address(), + fees, ) } @@ -334,7 +474,7 @@ impl ChainBootstrapMethodsExt for ChainDriver { assert_eventually_succeed( &format!("proposal `{}` status: {}", proposal_id, status.as_str()), 10, - Duration::from_secs(2), + Duration::from_secs(3), || match query_gov_proposal( chain_id, command_path, diff --git a/tools/test-framework/src/chain/ext/crosschainquery.rs b/tools/test-framework/src/chain/ext/crosschainquery.rs index 252839c86f..35ad76d116 100644 --- a/tools/test-framework/src/chain/ext/crosschainquery.rs +++ b/tools/test-framework/src/chain/ext/crosschainquery.rs @@ -14,7 +14,7 @@ use crate::types::tagged::MonoTagged; If you encounter retry error, verify the value of `stride_epoch`in the `stride_epoch` configuration in Stride's `genesis.toml` file. */ -const WAIT_CROSS_CHAIN_QUERY_ATTEMPTS: u16 = 60; +const WAIT_CROSS_CHAIN_QUERY_ATTEMPTS: u16 = 30; pub trait CrossChainQueryMethodsExt { fn assert_pending_cross_chain_query(&self) -> Result<(), Error>; @@ -22,7 +22,7 @@ pub trait CrossChainQueryMethodsExt { fn assert_processed_cross_chain_query(&self) -> Result<(), Error>; } -impl<'a, Chain: Send> CrossChainQueryMethodsExt for MonoTagged { +impl CrossChainQueryMethodsExt for MonoTagged { fn assert_pending_cross_chain_query(&self) -> Result<(), Error> { assert_eventually_succeed( "waiting for a cross chain query request", @@ -71,15 +71,14 @@ impl<'a, Chain: Send> CrossChainQueryMethodsExt for MonoTagged(&output) + // Verify that there are no more pending Cross Chain Queries. + if !json::from_str::(&output) .map_err(handle_generic_error)? .get("pending_queries") .ok_or_else(|| eyre!("no pending cross chain queries"))? .as_array() .ok_or_else(|| eyre!("pending cross chain queries is not an array"))? - .first() - .is_some() + .is_empty() { return Err(Error::generic(eyre!( "Pending query has not been processed" diff --git a/tools/test-framework/src/chain/ext/fee.rs b/tools/test-framework/src/chain/ext/fee.rs index b3783304fa..8dc8f81c41 100644 --- a/tools/test-framework/src/chain/ext/fee.rs +++ b/tools/test-framework/src/chain/ext/fee.rs @@ -69,7 +69,7 @@ pub trait ChainFeeMethodsExt { ) -> Result, Error>; } -impl<'a, Chain: Send> ChainFeeMethodsExt for MonoTagged { +impl ChainFeeMethodsExt for MonoTagged { fn ibc_token_transfer_with_fee( &self, port_id: &TaggedPortIdRef<'_, Chain, Counterparty>, diff --git a/tools/test-framework/src/chain/ext/fee_grant.rs b/tools/test-framework/src/chain/ext/fee_grant.rs index ca8dcb156e..e63de5a6fc 100644 --- a/tools/test-framework/src/chain/ext/fee_grant.rs +++ b/tools/test-framework/src/chain/ext/fee_grant.rs @@ -11,7 +11,7 @@ pub trait FeeGrantMethodsExt { ) -> Result<(), Error>; } -impl<'a, Chain: Send> FeeGrantMethodsExt for MonoTagged { +impl FeeGrantMethodsExt for MonoTagged { fn feegrant_grant( &self, granter: &str, diff --git a/tools/test-framework/src/chain/ext/forward.rs b/tools/test-framework/src/chain/ext/forward.rs index 1e0c23ace9..f56a31b72e 100644 --- a/tools/test-framework/src/chain/ext/forward.rs +++ b/tools/test-framework/src/chain/ext/forward.rs @@ -3,7 +3,7 @@ use ibc_relayer_types::core::ics24_host::identifier::{ChannelId, PortId}; use crate::prelude::{DualTagged, MonoTagged, WalletAddress}; /// Build the recipient address as following: -/// {intermediate_refund_address}|{foward_port}/{forward_channel}:{final_destination_address} +/// {intermediate_refund_address}|{forward_port}/{forward_channel}:{final_destination_address} /// See pub fn build_forward_address<'a, ChainB, ChainC>( intermediate_destination_address: MonoTagged, diff --git a/tools/test-framework/src/chain/ext/ica.rs b/tools/test-framework/src/chain/ext/ica.rs index 766f03e1e1..427acd8003 100644 --- a/tools/test-framework/src/chain/ext/ica.rs +++ b/tools/test-framework/src/chain/ext/ica.rs @@ -1,16 +1,17 @@ -use ibc_relayer::chain::handle::ChainHandle; +use ibc_relayer::upgrade_chain::requires_legacy_upgrade_proposal; +use serde_json::json; + use ibc_relayer::chain::tracking::TrackedMsgs; -use ibc_relayer_types::applications::ics27_ica::msgs::register::MsgRegisterInterchainAccount; +use ibc_relayer_types::applications::ics27_ica::msgs::register::{ + LegacyMsgRegisterInterchainAccount, MsgRegisterInterchainAccount, +}; use ibc_relayer_types::core::ics04_channel::version::Version; use ibc_relayer_types::events::IbcEvent; use ibc_relayer_types::tx_msg::Msg; use crate::chain::cli::ica::{query_interchain_account, register_interchain_account_cli}; -use crate::chain::driver::ChainDriver; -use crate::error::Error; use crate::prelude::*; use crate::types::tagged::*; -use crate::types::wallet::WalletAddress; pub trait InterchainAccountMethodsExt { fn register_interchain_account_cli( @@ -26,7 +27,7 @@ pub trait InterchainAccountMethodsExt { ) -> Result, Error>; } -impl<'a, Chain: Send> InterchainAccountMethodsExt for MonoTagged { +impl InterchainAccountMethodsExt for MonoTagged { fn register_interchain_account_cli( &self, from: &MonoTagged, @@ -63,7 +64,7 @@ impl<'a, Chain: Send> InterchainAccountMethodsExt for MonoTagged( +pub fn register_unordered_interchain_account( chain: &MonoTagged, handle: &Chain, connection: &ConnectedConnection, @@ -79,14 +80,97 @@ pub fn register_interchain_account( + chain: &MonoTagged, + handle: &Chain, + connection: &ConnectedConnection, +) -> Result< + ( + MonoTagged, + TaggedChannelId, + TaggedPortId, + ), + Error, +> { + let wallet = chain.wallets().relayer().cloned(); + + let owner = handle.get_signer()?; + + let version_obj = json!({ + "version": "ics27-1", + "encoding": "proto3", + "tx_type": "sdk_multi_msg", + "controller_connection_id": connection.connection_id_a.0, + "host_connection_id": connection.connection_id_b.0 + }); + + let msg_any = if requires_legacy_upgrade_proposal(handle.clone()) { + let msg = LegacyMsgRegisterInterchainAccount { + owner, + connection_id: connection.connection_id_a.0.clone(), + version: Version::new(version_obj.to_string()), + }; + + msg.to_any() + } else { + let msg = MsgRegisterInterchainAccount { + owner, + connection_id: connection.connection_id_a.0.clone(), + version: Version::new(version_obj.to_string()), + ordering: Ordering::Ordered, + }; + msg.to_any() + }; let tm = TrackedMsgs::new_static(vec![msg_any], "RegisterInterchainAccount"); @@ -96,7 +180,10 @@ pub fn register_interchain_account Result; - fn vote_proposal(&self, fees: &str) -> Result<(), Error>; + fn vote_proposal(&self, fees: &str, proposal_id: &str) -> Result<(), Error>; + + fn deposit_proposal( + &self, + amount: &str, + proposal_id: &str, + fees: &str, + gas: &str, + ) -> Result<(), Error>; + + fn initialise_channel_upgrade( + &self, + port_id: &str, + channel_id: &str, + ordering: &str, + connection_hops: &str, + version: &str, + signer: &str, + proposal_id: &str, + ) -> Result<(), Error>; + + fn update_channel_params( + &self, + timestamp: u64, + signer: &str, + proposal_id: &str, + ) -> Result<(), Error>; } -impl<'a, Chain: Send> ChainProposalMethodsExt for MonoTagged { +impl ChainProposalMethodsExt for MonoTagged { fn query_upgrade_proposal_height( &self, grpc_address: &Uri, @@ -34,16 +64,136 @@ impl<'a, Chain: Send> ChainProposalMethodsExt for MonoTagged Result<(), Error> { + fn vote_proposal(&self, fees: &str, proposal_id: &str) -> Result<(), Error> { vote_proposal( self.value().chain_id.as_str(), &self.value().command_path, &self.value().home_path, &self.value().rpc_listen_address(), fees, + proposal_id, )?; Ok(()) } + + fn deposit_proposal( + &self, + amount: &str, + proposal_id: &str, + fees: &str, + gas: &str, + ) -> Result<(), Error> { + deposit_proposal(self.value(), amount, proposal_id, fees, gas)?; + Ok(()) + } + + fn initialise_channel_upgrade( + &self, + port_id: &str, + channel_id: &str, + ordering: &str, + connection_hops: &str, + version: &str, + signer: &str, + proposal_id: &str, + ) -> Result<(), Error> { + let gov_address = self.query_auth_module("gov")?; + let channel_upgrade_proposal = create_channel_upgrade_proposal( + self.value(), + port_id, + channel_id, + ordering, + connection_hops, + version, + &gov_address, + )?; + submit_gov_proposal( + self.value().chain_id.as_str(), + &self.value().command_path, + &self.value().home_path, + &self.value().rpc_listen_address(), + signer, + &channel_upgrade_proposal, + )?; + + self.value().assert_proposal_status( + self.value().chain_id.as_str(), + &self.value().command_path, + &self.value().home_path, + &self.value().rpc_listen_address(), + ProposalStatus::VotingPeriod, + proposal_id, + )?; + + vote_proposal( + self.value().chain_id.as_str(), + &self.value().command_path, + &self.value().home_path, + &self.value().rpc_listen_address(), + "1200stake", + proposal_id, + )?; + + self.value().assert_proposal_status( + self.value().chain_id.as_str(), + &self.value().command_path, + &self.value().home_path, + &self.value().rpc_listen_address(), + ProposalStatus::Passed, + proposal_id, + )?; + + Ok(()) + } + + // The timestamp is in nanoseconds + fn update_channel_params( + &self, + timestamp: u64, + signer: &str, + proposal_id: &str, + ) -> Result<(), Error> { + let gov_address = self.query_auth_module("gov")?; + let channel_update_params_proposal = + create_channel_update_params_proposal(self.value(), timestamp, &gov_address)?; + submit_gov_proposal( + self.value().chain_id.as_str(), + &self.value().command_path, + &self.value().home_path, + &self.value().rpc_listen_address(), + signer, + &channel_update_params_proposal, + )?; + + self.value().assert_proposal_status( + self.value().chain_id.as_str(), + &self.value().command_path, + &self.value().home_path, + &self.value().rpc_listen_address(), + ProposalStatus::VotingPeriod, + proposal_id, + )?; + + vote_proposal( + self.value().chain_id.as_str(), + &self.value().command_path, + &self.value().home_path, + &self.value().rpc_listen_address(), + "1200stake", + proposal_id, + )?; + + self.value().assert_proposal_status( + self.value().chain_id.as_str(), + &self.value().command_path, + &self.value().home_path, + &self.value().rpc_listen_address(), + ProposalStatus::Passed, + proposal_id, + )?; + + Ok(()) + } } /// Query the proposal with the given proposal_id, which is supposed to be an UpgradeProposal. @@ -70,10 +220,10 @@ pub async fn query_upgrade_proposal_height( .map(|r| r.into_inner()) .map_err(|e| RelayerError::grpc_status(e, "query_upgrade_proposal_height".to_owned()))?; - // Querying for a balance might fail, i.e. if the account doesn't actually exist + // Querying for proposal might not exist if the proposal id is incorrect let proposal = response .proposal - .ok_or_else(|| RelayerError::empty_query_account(proposal_id.to_string()))?; + .ok_or_else(|| RelayerError::empty_proposal(proposal_id.to_string()))?; let proposal_content = proposal .content @@ -109,3 +259,77 @@ pub async fn query_upgrade_proposal_height( Ok(height) } + +fn create_channel_upgrade_proposal( + chain_driver: &ChainDriver, + port_id: &str, + channel_id: &str, + ordering: &str, + connection_hops: &str, + version: &str, + gov_address: &str, +) -> Result { + let raw_proposal = r#" + { + "messages": [ + { + "@type": "/ibc.core.channel.v1.MsgChannelUpgradeInit", + "port_id": "{port_id}", + "channel_id": "{channel_id}", + "fields": { + "ordering": "{ordering}", + "connection_hops": ["{connection_hops}"], + "version": {version} + }, + "signer":"{signer}" + } + ], + "deposit": "10000001stake", + "title": "Channel upgrade", + "summary": "Upgrade channel version", + "expedited": false + }"#; + + let proposal = raw_proposal.replace("{port_id}", port_id); + let proposal = proposal.replace("{channel_id}", channel_id); + let proposal = proposal.replace("{ordering}", ordering); + let proposal = proposal.replace("{connection_hops}", connection_hops); + let proposal = proposal.replace("{version}", version); + let proposal = proposal.replace("{signer}", gov_address); + + chain_driver.write_file("channel_upgrade_proposal.json", &proposal)?; + Ok("channel_upgrade_proposal.json".to_owned()) +} + +fn create_channel_update_params_proposal( + chain_driver: &ChainDriver, + timestamp: u64, + gov_address: &str, +) -> Result { + let raw_proposal = r#" + { + "messages": [ + { + "@type": "/ibc.core.channel.v1.MsgUpdateParams", + "params": { + "upgrade_timeout": { + "timestamp": {timestamp} + } + }, + "authority":"{signer}" + } + ], + "deposit": "10000001stake", + "title": "Channel update params", + "summary": "Update channel params", + "expedited": false + }"#; + + let proposal = raw_proposal.replace("{timestamp}", ×tamp.to_string()); + let proposal = proposal.replace("{signer}", gov_address); + + let output_file = "channel_update_params_proposal.json"; + + chain_driver.write_file(output_file, &proposal)?; + Ok(output_file.to_owned()) +} diff --git a/tools/test-framework/src/chain/ext/transfer.rs b/tools/test-framework/src/chain/ext/transfer.rs index 94707ff8da..37f67d3929 100644 --- a/tools/test-framework/src/chain/ext/transfer.rs +++ b/tools/test-framework/src/chain/ext/transfer.rs @@ -71,6 +71,7 @@ pub trait ChainTransferMethodsExt { sender: &MonoTagged, recipient: &MonoTagged, token: &TaggedTokenRef, + fees: &TaggedTokenRef, ) -> Result<(), Error>; fn transfer_from_chain( @@ -85,7 +86,7 @@ pub trait ChainTransferMethodsExt { ) -> Result<(), Error>; } -impl<'a, Chain: Send> ChainTransferMethodsExt for MonoTagged { +impl ChainTransferMethodsExt for MonoTagged { fn ibc_transfer_token( &self, port_id: &TaggedPortIdRef, @@ -161,6 +162,7 @@ impl<'a, Chain: Send> ChainTransferMethodsExt for MonoTagged, recipient: &MonoTagged, token: &TaggedTokenRef, + fees: &TaggedTokenRef, ) -> Result<(), Error> { let driver = *self.value(); local_transfer_token( @@ -171,6 +173,7 @@ impl<'a, Chain: Send> ChainTransferMethodsExt for MonoTagged Result; } -impl<'a, Chain: Send> ChainVersionMethodsExt for MonoTagged { +impl ChainVersionMethodsExt for MonoTagged { fn major_version(&self) -> Result { major_version(&self.value().command_path) } diff --git a/tools/test-framework/src/chain/ext/wasm_client.rs b/tools/test-framework/src/chain/ext/wasm_client.rs new file mode 100644 index 0000000000..70cebfb430 --- /dev/null +++ b/tools/test-framework/src/chain/ext/wasm_client.rs @@ -0,0 +1,85 @@ +use std::path::Path; + +use crate::chain::cli::wasm::contract::{store_wasm_client_code, store_wasm_contract}; +use crate::chain::driver::ChainDriver; +use crate::error::Error; +use crate::types::tagged::*; + +pub trait StoreWasmClientCodeMethodsExt { + fn store_wasm_client_code( + &self, + wasm_path: &Path, + title: &str, + summary: &str, + signer: &str, + ) -> Result; + + fn store_wasm_contract( + &self, + title: &str, + summary: &str, + wasm_file: &str, + authority: &str, + from: &str, + deposit: &str, + fees: &str, + gas: &str, + ) -> Result; +} + +impl StoreWasmClientCodeMethodsExt for MonoTagged { + fn store_wasm_client_code( + &self, + wasm_path: &Path, + title: &str, + summary: &str, + signer: &str, + ) -> Result { + self.value() + .store_wasm_client_code(wasm_path, title, summary, signer) + } + + fn store_wasm_contract( + &self, + title: &str, + summary: &str, + wasm_file: &str, + authority: &str, + from: &str, + deposit: &str, + fees: &str, + gas: &str, + ) -> Result { + self.value().store_wasm_contract( + title, summary, wasm_file, authority, from, deposit, fees, gas, + ) + } +} + +impl StoreWasmClientCodeMethodsExt for ChainDriver { + fn store_wasm_client_code( + &self, + wasm_path: &Path, + title: &str, + summary: &str, + signer: &str, + ) -> Result { + store_wasm_client_code(self, wasm_path, title, summary, signer) + } + + fn store_wasm_contract( + &self, + title: &str, + summary: &str, + wasm_file: &str, + authority: &str, + from: &str, + deposit: &str, + fees: &str, + gas: &str, + ) -> Result { + store_wasm_contract( + self, title, summary, wasm_file, authority, from, deposit, fees, gas, + ) + } +} diff --git a/tools/test-framework/src/chain/tagged.rs b/tools/test-framework/src/chain/tagged.rs index 64b73ef171..d6f2f510ad 100644 --- a/tools/test-framework/src/chain/tagged.rs +++ b/tools/test-framework/src/chain/tagged.rs @@ -5,10 +5,13 @@ use ibc_proto::google::protobuf::Any; use ibc_relayer::chain::cosmos::tx::simple_send_tx; use ibc_relayer::chain::cosmos::types::config::TxConfig; +use ibc_relayer::config::compat_mode::CompatMode; use ibc_relayer::event::IbcEventWithHeight; -use ibc_relayer::util::compat_mode::compat_mode_from_version; +use ibc_relayer_types::core::ics24_host::identifier::ChainId; use serde_json as json; use tendermint_rpc::client::{Client, HttpClient}; +use tendermint_rpc::Url; +use tracing::warn; use crate::chain::cli::query::query_auth_module; use crate::chain::cli::query::query_recipient_transactions; @@ -71,6 +74,23 @@ pub trait TaggedChainDriverExt { token: &TaggedTokenRef, ) -> Result<(), Error>; + /** + Tagged version of [`ChainDriver::assert_eventual_escrowed_amount_ics29`]. + + Assert that a wallet should eventually have escrowed the amount for ICS29 + fees of a given denomination. + Legacy ICS29 will escrow recv_fee + ack_fee + timeout_fee while more recent + versions will escrow max(recv_fee + ack_fee, timeout_fee). + */ + fn assert_eventual_escrowed_amount_ics29( + &self, + user: &MonoTagged, + token: &TaggedTokenRef, + recv_fee: u128, + ack_fee: u128, + timeout_fee: u128, + ) -> Result<(), Error>; + /** Tagged version of [`query_recipient_transactions`]. @@ -90,7 +110,7 @@ pub trait TaggedChainDriverExt { fn query_auth_module(&self, module_name: &str) -> Result; } -impl<'a, Chain: Send> TaggedChainDriverExt for MonoTagged { +impl TaggedChainDriverExt for MonoTagged { fn chain_id(&self) -> TaggedChainIdRef { self.map_ref(|val| &val.chain_id) } @@ -103,11 +123,15 @@ impl<'a, Chain: Send> TaggedChainDriverExt for MonoTagged TaggedChainDriverExt for MonoTagged, + token: &TaggedTokenRef, + recv_fee: u128, + ack_fee: u128, + timeout_fee: u128, + ) -> Result<(), Error> { + self.value().assert_eventual_escrowed_amount_ics29( + user.value(), + token.value(), + recv_fee, + ack_fee, + timeout_fee, + ) + } + fn query_recipient_transactions( &self, recipient_address: &MonoTagged, @@ -175,3 +216,34 @@ impl<'a, Chain: Send> TaggedChainDriverExt for MonoTagged, +) -> Result { + use ibc_relayer::chain::cosmos::query::fetch_version_specs; + use ibc_relayer::util::compat_mode::compat_mode_from_node_version; + use ibc_relayer::util::compat_mode::compat_mode_from_version_specs; + + let version_specs = fetch_version_specs(id, client, rpc_addr).await; + + let compat_mode = match version_specs { + Ok(specs) => compat_mode_from_version_specs(configured_mode, specs.consensus), + Err(e) => { + warn!("Failed to fetch version specs for chain '{id}': {e}"); + + let status = client.status().await.map_err(handle_generic_error)?; + + warn!( + "Will fall back on using the node version: {}", + status.node_info.version + ); + + compat_mode_from_node_version(configured_mode, status.node_info.version) + } + }?; + + Ok(compat_mode) +} diff --git a/tools/test-framework/src/docs/walkthroughs/memo.rs b/tools/test-framework/src/docs/walkthroughs/memo.rs index c13a667df1..7c0887a76c 100644 --- a/tools/test-framework/src/docs/walkthroughs/memo.rs +++ b/tools/test-framework/src/docs/walkthroughs/memo.rs @@ -11,10 +11,12 @@ //! ```no_run //! # use serde_json as json; //! # use ibc_relayer::config::{types::Memo, Config}; +//! # use ibc_relayer::config::ChainConfig; //! # use ibc_test_framework::ibc::denom::derive_ibc_denom; //! # use ibc_test_framework::prelude::*; //! # use ibc_test_framework::util::random::{random_string, random_u128_range}; //! +//! //! #[test] //! fn test_memo() -> Result<(), Error> { //! let memo = Memo::new(random_string()).unwrap(); @@ -29,7 +31,11 @@ //! impl TestOverrides for MemoTest { //! fn modify_relayer_config(&self, config: &mut Config) { //! for mut chain in config.chains.iter_mut() { -//! chain.memo_prefix = self.memo.clone(); +//! match chain { +//! ChainConfig::CosmosSdk(chain_config) => { +//! chain_config.memo_prefix = self.memo.clone(); +//! }, +//! } //! } //! } //! } diff --git a/tools/test-framework/src/error.rs b/tools/test-framework/src/error.rs index d438f88bd9..796660e731 100644 --- a/tools/test-framework/src/error.rs +++ b/tools/test-framework/src/error.rs @@ -1,6 +1,5 @@ //! Error type used for the tests. -use core::convert::{From, Into}; use std::io::{Error as IoError, ErrorKind as IoErrorKind}; use eyre::Report; diff --git a/tools/test-framework/src/framework/base.rs b/tools/test-framework/src/framework/base.rs index 0ba59ea9fb..e7e0415b5d 100644 --- a/tools/test-framework/src/framework/base.rs +++ b/tools/test-framework/src/framework/base.rs @@ -84,7 +84,7 @@ pub struct RunBasicTest<'a, Test> { pub test: &'a Test, } -impl<'a, Test, Overrides> PrimitiveTest for RunBasicTest<'a, Test> +impl PrimitiveTest for RunBasicTest<'_, Test> where Test: BasicTest, Test: HasOverrides, diff --git a/tools/test-framework/src/framework/binary/chain.rs b/tools/test-framework/src/framework/binary/chain.rs index a1a3aae940..5e58a2ef58 100644 --- a/tools/test-framework/src/framework/binary/chain.rs +++ b/tools/test-framework/src/framework/binary/chain.rs @@ -22,6 +22,7 @@ use crate::types::binary::chains::{ConnectedChains, DropChainHandle}; use crate::types::config::TestConfig; use crate::types::env::write_env; use crate::types::single::node::FullNode; +use crate::types::topology::TopologyType; use crate::util::suspend::hang_on_error; /** @@ -113,6 +114,10 @@ pub trait RelayerConfigOverride { fn modify_relayer_config(&self, config: &mut Config); } +pub trait TopologyOverride { + fn topology(&self) -> Option; +} + /// An internal trait that can be implemented by test cases to override the /// settings for the foreign clients bootstrapped for the test. /// @@ -196,7 +201,7 @@ where } } -impl<'a, Test, Overrides> BinaryNodeTest for RunBinaryChainTest<'a, Test> +impl BinaryNodeTest for RunBinaryChainTest<'_, Test> where Test: BinaryChainTest, Test: HasOverrides, @@ -235,7 +240,7 @@ where } } -impl<'a, Test, Overrides> InterchainSecurityChainTest for RunBinaryChainTest<'a, Test> +impl InterchainSecurityChainTest for RunBinaryChainTest<'_, Test> where Test: BinaryChainTest, Test: HasOverrides, @@ -274,7 +279,7 @@ where } } -impl<'a, Test: BinaryChainTest> BinaryChainTest for RunTwoWayBinaryChainTest<'a, Test> { +impl BinaryChainTest for RunTwoWayBinaryChainTest<'_, Test> { fn run( &self, config: &TestConfig, @@ -303,7 +308,7 @@ impl<'a, Test: BinaryChainTest> BinaryChainTest for RunTwoWayBinaryChainTest<'a, } } -impl<'a, Test, Overrides> BinaryChainTest for RunWithSupervisor<'a, Test> +impl BinaryChainTest for RunWithSupervisor<'_, Test> where Test: BinaryChainTest, Test: HasOverrides, @@ -327,7 +332,7 @@ where } } -impl<'a, Test, Overrides> HasOverrides for RunBinaryChainTest<'a, Test> +impl HasOverrides for RunBinaryChainTest<'_, Test> where Test: HasOverrides, { @@ -338,7 +343,7 @@ where } } -impl<'a, Test, Overrides> HasOverrides for RunTwoWayBinaryChainTest<'a, Test> +impl HasOverrides for RunTwoWayBinaryChainTest<'_, Test> where Test: HasOverrides, { diff --git a/tools/test-framework/src/framework/binary/channel.rs b/tools/test-framework/src/framework/binary/channel.rs index 00ae9efd89..6aef65d90c 100644 --- a/tools/test-framework/src/framework/binary/channel.rs +++ b/tools/test-framework/src/framework/binary/channel.rs @@ -205,7 +205,7 @@ where } } -impl<'a, Test, Overrides> BinaryConnectionTest for RunBinaryChannelTest<'a, Test> +impl BinaryConnectionTest for RunBinaryChannelTest<'_, Test> where Test: BinaryChannelTest, Test: HasOverrides, @@ -249,7 +249,7 @@ where } } -impl<'a, Test: BinaryChannelTest> BinaryChannelTest for RunTwoWayBinaryChannelTest<'a, Test> { +impl BinaryChannelTest for RunTwoWayBinaryChannelTest<'_, Test> { fn run( &self, config: &TestConfig, @@ -285,7 +285,7 @@ impl<'a, Test: BinaryChannelTest> BinaryChannelTest for RunTwoWayBinaryChannelTe } } -impl<'a, Test, Overrides> BinaryChannelTest for RunWithSupervisor<'a, Test> +impl BinaryChannelTest for RunWithSupervisor<'_, Test> where Test: BinaryChannelTest, Test: HasOverrides, @@ -310,7 +310,7 @@ where } } -impl<'a, Test, Overrides> HasOverrides for RunBinaryChannelTest<'a, Test> +impl HasOverrides for RunBinaryChannelTest<'_, Test> where Test: HasOverrides, { @@ -321,7 +321,7 @@ where } } -impl<'a, Test, Overrides> HasOverrides for RunTwoWayBinaryChannelTest<'a, Test> +impl HasOverrides for RunTwoWayBinaryChannelTest<'_, Test> where Test: HasOverrides, { diff --git a/tools/test-framework/src/framework/binary/connection.rs b/tools/test-framework/src/framework/binary/connection.rs index 9e96a7665e..e0f999b50d 100644 --- a/tools/test-framework/src/framework/binary/connection.rs +++ b/tools/test-framework/src/framework/binary/connection.rs @@ -142,7 +142,7 @@ where } } -impl<'a, Test, Overrides> BinaryChainTest for RunBinaryConnectionTest<'a, Test> +impl BinaryChainTest for RunBinaryConnectionTest<'_, Test> where Test: BinaryConnectionTest, Test: HasOverrides, @@ -172,9 +172,7 @@ where } } -impl<'a, Test: BinaryConnectionTest> BinaryConnectionTest - for RunTwoWayBinaryConnectionTest<'a, Test> -{ +impl BinaryConnectionTest for RunTwoWayBinaryConnectionTest<'_, Test> { fn run( &self, config: &TestConfig, @@ -210,7 +208,7 @@ impl<'a, Test: BinaryConnectionTest> BinaryConnectionTest } } -impl<'a, Test, Overrides> BinaryConnectionTest for RunWithSupervisor<'a, Test> +impl BinaryConnectionTest for RunWithSupervisor<'_, Test> where Test: BinaryConnectionTest, Test: HasOverrides, @@ -235,7 +233,7 @@ where } } -impl<'a, Test, Overrides> HasOverrides for RunBinaryConnectionTest<'a, Test> +impl HasOverrides for RunBinaryConnectionTest<'_, Test> where Test: HasOverrides, { @@ -246,7 +244,7 @@ where } } -impl<'a, Test, Overrides> HasOverrides for RunTwoWayBinaryConnectionTest<'a, Test> +impl HasOverrides for RunTwoWayBinaryConnectionTest<'_, Test> where Test: HasOverrides, { diff --git a/tools/test-framework/src/framework/binary/ics.rs b/tools/test-framework/src/framework/binary/ics.rs index 8125a541f9..7117fea5c2 100644 --- a/tools/test-framework/src/framework/binary/ics.rs +++ b/tools/test-framework/src/framework/binary/ics.rs @@ -1,17 +1,16 @@ use std::str::FromStr; +use std::thread; use crate::bootstrap::consumer::bootstrap_consumer_node; use crate::bootstrap::single::bootstrap_single_node; use crate::chain::builder::ChainBuilder; use crate::chain::chain_type::ChainType; -use crate::chain::cli::upgrade::vote_proposal; use crate::chain::ext::bootstrap::ChainBootstrapMethodsExt; use crate::error::Error; use crate::framework::base::{run_basic_test, BasicTest, HasOverrides, TestConfigOverride}; use crate::framework::binary::node::{NodeConfigOverride, NodeGenesisOverride}; use crate::prelude::FullNode; use crate::types::config::TestConfig; -use crate::util::proposal_status::ProposalStatus; /** Runs a test case that implements [`InterchainSecurityChainTest`]. @@ -48,7 +47,7 @@ where } } -impl<'a, Test, Overrides> BasicTest for RunInterchainSecurityChainTest<'a, Test> +impl BasicTest for RunInterchainSecurityChainTest<'_, Test> where Test: InterchainSecurityChainTest, Test: HasOverrides, @@ -65,50 +64,35 @@ where 0, )?; let provider_native_token = builder.native_tokens[0].clone(); - let provider_fee = format!("1200{}", provider_native_token); + let provider_fee = format!("381000000{provider_native_token}"); // Get consumer chain id let chain_type = ChainType::from_str(&builder.command_paths[1])?; let chain_id = chain_type.chain_id("consumer", false); - node_a + let consumer_id = node_a .chain_driver - .submit_consumer_chain_proposal(chain_id.as_str(), "2023-05-31T12:09:47.048227Z")?; - - node_a.chain_driver.assert_proposal_status( - node_a.chain_driver.chain_id.as_str(), - &node_a.chain_driver.command_path, - &node_a.chain_driver.home_path, - &node_a.chain_driver.rpc_listen_address(), - ProposalStatus::VotingPeriod, - "1", - )?; + .create_permisionless_consumer(chain_id.as_str(), &provider_fee)?; + + thread::sleep(std::time::Duration::from_secs(3)); - vote_proposal( - node_a.chain_driver.chain_id.as_str(), - &node_a.chain_driver.command_path, - &node_a.chain_driver.home_path, - &node_a.chain_driver.rpc_listen_address(), + node_a.chain_driver.update_consumer( + &consumer_id, &provider_fee, + node_a.wallets.validator.address.as_str(), )?; - node_a.chain_driver.assert_proposal_status( - node_a.chain_driver.chain_id.as_str(), - &node_a.chain_driver.command_path, - &node_a.chain_driver.home_path, - &node_a.chain_driver.rpc_listen_address(), - ProposalStatus::Passed, - "1", - )?; + thread::sleep(std::time::Duration::from_secs(3)); let node_b = bootstrap_consumer_node( builder, - "consumer", + &consumer_id, &node_a, |config| self.test.get_overrides().modify_node_config(config), |genesis| self.test.get_overrides().modify_genesis_file(genesis), 1, &node_a.chain_driver, + &provider_fee, )?; let _node_process_a = node_a.process.clone(); @@ -120,7 +104,7 @@ where } } -impl<'a, Test, Overrides> HasOverrides for RunInterchainSecurityChainTest<'a, Test> +impl HasOverrides for RunInterchainSecurityChainTest<'_, Test> where Test: HasOverrides, { diff --git a/tools/test-framework/src/framework/binary/node.rs b/tools/test-framework/src/framework/binary/node.rs index 745cf57f03..cea2cb1832 100644 --- a/tools/test-framework/src/framework/binary/node.rs +++ b/tools/test-framework/src/framework/binary/node.rs @@ -3,8 +3,6 @@ running without setting up the relayer. */ -use toml; - use crate::bootstrap::single::bootstrap_single_node; use crate::chain::builder::ChainBuilder; use crate::error::Error; @@ -103,7 +101,7 @@ pub struct RunSingleNodeTest<'a, Test> { pub test: &'a Test, } -impl<'a, Test, Overrides> BasicTest for RunBinaryNodeTest<'a, Test> +impl BasicTest for RunBinaryNodeTest<'_, Test> where Test: BinaryNodeTest, Test: HasOverrides, @@ -137,7 +135,7 @@ where } } -impl<'a, Test, Overrides> BasicTest for RunSingleNodeTest<'a, Test> +impl BasicTest for RunSingleNodeTest<'_, Test> where Test: BinaryNodeTest, Test: HasOverrides, @@ -161,7 +159,7 @@ where } } -impl<'a, Test, Overrides> HasOverrides for RunBinaryNodeTest<'a, Test> +impl HasOverrides for RunBinaryNodeTest<'_, Test> where Test: HasOverrides, { @@ -172,7 +170,7 @@ where } } -impl<'a, Test, Overrides> HasOverrides for RunSingleNodeTest<'a, Test> +impl HasOverrides for RunSingleNodeTest<'_, Test> where Test: HasOverrides, { diff --git a/tools/test-framework/src/framework/nary/chain.rs b/tools/test-framework/src/framework/nary/chain.rs index 392114cc5e..7667ac42e4 100644 --- a/tools/test-framework/src/framework/nary/chain.rs +++ b/tools/test-framework/src/framework/nary/chain.rs @@ -11,7 +11,7 @@ use crate::bootstrap::nary::chain::{ }; use crate::error::Error; use crate::framework::base::{HasOverrides, TestConfigOverride}; -use crate::framework::binary::chain::RelayerConfigOverride; +use crate::framework::binary::chain::{RelayerConfigOverride, TopologyOverride}; use crate::framework::binary::node::{NodeConfigOverride, NodeGenesisOverride}; use crate::framework::nary::node::{run_nary_node_test, NaryNodeTest}; use crate::framework::supervisor::{RunWithSupervisor, SupervisorOverride}; @@ -48,7 +48,8 @@ where + NodeConfigOverride + NodeGenesisOverride + RelayerConfigOverride - + SupervisorOverride, + + SupervisorOverride + + TopologyOverride, { run_nary_node_test(&RunNaryChainTest::new(&RunWithSupervisor::new(test))) } @@ -77,7 +78,8 @@ where + NodeConfigOverride + NodeGenesisOverride + RelayerConfigOverride - + SupervisorOverride, + + SupervisorOverride + + TopologyOverride, { run_nary_node_test(&RunSelfConnectedNaryChainTest::new( &RunWithSupervisor::new(test), @@ -121,16 +123,21 @@ pub struct RunSelfConnectedNaryChainTest<'a, Test, const SIZE: usize> { pub test: &'a Test, } -impl<'a, Test, Overrides, const SIZE: usize> NaryNodeTest for RunNaryChainTest<'a, Test, SIZE> +impl NaryNodeTest for RunNaryChainTest<'_, Test, SIZE> where Test: NaryChainTest, Test: HasOverrides, - Overrides: RelayerConfigOverride, + Overrides: RelayerConfigOverride + TopologyOverride, { fn run(&self, config: &TestConfig, nodes: [FullNode; SIZE]) -> Result<(), Error> { - let (relayer, chains) = boostrap_chains_with_nodes(config, nodes, |config| { - self.test.get_overrides().modify_relayer_config(config); - })?; + let (relayer, chains) = boostrap_chains_with_nodes( + config, + nodes, + self.test.get_overrides().topology(), + |config| { + self.test.get_overrides().modify_relayer_config(config); + }, + )?; let env_path = config.chain_store_dir.join("nary-chains.env"); @@ -150,18 +157,22 @@ where } } -impl<'a, Test, Overrides, const SIZE: usize> NaryNodeTest<1> - for RunSelfConnectedNaryChainTest<'a, Test, SIZE> +impl NaryNodeTest<1> + for RunSelfConnectedNaryChainTest<'_, Test, SIZE> where Test: NaryChainTest, Test: HasOverrides, - Overrides: RelayerConfigOverride, + Overrides: RelayerConfigOverride + TopologyOverride, { fn run(&self, config: &TestConfig, nodes: [FullNode; 1]) -> Result<(), Error> { - let (relayer, chains) = - boostrap_chains_with_self_connected_node(config, nodes[0].clone(), |config| { + let (relayer, chains) = boostrap_chains_with_self_connected_node( + config, + nodes[0].clone(), + self.test.get_overrides().topology(), + |config| { self.test.get_overrides().modify_relayer_config(config); - })?; + }, + )?; let env_path = config.chain_store_dir.join("nary-chains.env"); @@ -181,7 +192,7 @@ where } } -impl<'a, Test, Overrides, const SIZE: usize> NaryChainTest for RunWithSupervisor<'a, Test> +impl NaryChainTest for RunWithSupervisor<'_, Test> where Test: NaryChainTest, Test: HasOverrides, @@ -223,7 +234,7 @@ where } } -impl<'a, Test, Overrides, const SIZE: usize> HasOverrides for RunNaryChainTest<'a, Test, SIZE> +impl HasOverrides for RunNaryChainTest<'_, Test, SIZE> where Test: HasOverrides, { @@ -234,8 +245,8 @@ where } } -impl<'a, Test, Overrides, const SIZE: usize> HasOverrides - for RunSelfConnectedNaryChainTest<'a, Test, SIZE> +impl HasOverrides + for RunSelfConnectedNaryChainTest<'_, Test, SIZE> where Test: HasOverrides, { diff --git a/tools/test-framework/src/framework/nary/channel.rs b/tools/test-framework/src/framework/nary/channel.rs index cd7ccdfe78..0f4fe189dd 100644 --- a/tools/test-framework/src/framework/nary/channel.rs +++ b/tools/test-framework/src/framework/nary/channel.rs @@ -11,7 +11,7 @@ use tracing::info; use crate::bootstrap::nary::channel::bootstrap_channels_with_connections; use crate::error::Error; use crate::framework::base::{HasOverrides, TestConfigOverride}; -use crate::framework::binary::chain::RelayerConfigOverride; +use crate::framework::binary::chain::{RelayerConfigOverride, TopologyOverride}; use crate::framework::binary::channel::{BinaryChannelTest, ChannelOrderOverride}; use crate::framework::binary::connection::ConnectionDelayOverride; use crate::framework::binary::node::{NodeConfigOverride, NodeGenesisOverride}; @@ -38,7 +38,8 @@ where + SupervisorOverride + ConnectionDelayOverride + PortsOverride - + ChannelOrderOverride, + + ChannelOrderOverride + + TopologyOverride, { run_nary_node_test(&RunNaryChainTest::new(&RunNaryConnectionTest::new( &RunNaryChannelTest::new(&RunWithSupervisor::new(test)), @@ -56,7 +57,8 @@ where + SupervisorOverride + ConnectionDelayOverride + PortsOverride<2> - + ChannelOrderOverride, + + ChannelOrderOverride + + TopologyOverride, { run_nary_channel_test(&RunBinaryAsNaryChannelTest::new(test)) } @@ -155,8 +157,8 @@ where } } -impl<'a, Test, Overrides, const SIZE: usize> NaryConnectionTest - for RunNaryChannelTest<'a, Test, SIZE> +impl NaryConnectionTest + for RunNaryChannelTest<'_, Test, SIZE> where Test: NaryChannelTest, Test: HasOverrides, @@ -175,7 +177,6 @@ where let channels = bootstrap_channels_with_connections( connections, - chains.chain_handles().clone(), port_ids, order, config.bootstrap_with_random_ids, @@ -193,7 +194,7 @@ where } } -impl<'a, Test> NaryChannelTest<2> for RunBinaryAsNaryChannelTest<'a, Test> +impl NaryChannelTest<2> for RunBinaryAsNaryChannelTest<'_, Test> where Test: BinaryChannelTest, { @@ -209,7 +210,7 @@ where } } -impl<'a, Test, Overrides, const SIZE: usize> NaryChannelTest for RunWithSupervisor<'a, Test> +impl NaryChannelTest for RunWithSupervisor<'_, Test> where Test: NaryChannelTest, Test: HasOverrides, @@ -234,7 +235,7 @@ where } } -impl<'a, Test, Overrides, const SIZE: usize> HasOverrides for RunNaryChannelTest<'a, Test, SIZE> +impl HasOverrides for RunNaryChannelTest<'_, Test, SIZE> where Test: HasOverrides, { @@ -245,7 +246,7 @@ where } } -impl<'a, Test, Overrides> HasOverrides for RunBinaryAsNaryChannelTest<'a, Test> +impl HasOverrides for RunBinaryAsNaryChannelTest<'_, Test> where Test: HasOverrides, { diff --git a/tools/test-framework/src/framework/nary/connection.rs b/tools/test-framework/src/framework/nary/connection.rs index 485b2ecd1b..48f611eb89 100644 --- a/tools/test-framework/src/framework/nary/connection.rs +++ b/tools/test-framework/src/framework/nary/connection.rs @@ -10,7 +10,7 @@ use tracing::info; use crate::bootstrap::nary::connection::bootstrap_connections; use crate::error::Error; use crate::framework::base::{HasOverrides, TestConfigOverride}; -use crate::framework::binary::chain::RelayerConfigOverride; +use crate::framework::binary::chain::{RelayerConfigOverride, TopologyOverride}; use crate::framework::binary::connection::{BinaryConnectionTest, ConnectionDelayOverride}; use crate::framework::binary::node::{NodeConfigOverride, NodeGenesisOverride}; use crate::framework::nary::chain::{NaryChainTest, RunNaryChainTest}; @@ -34,7 +34,8 @@ where + NodeGenesisOverride + RelayerConfigOverride + SupervisorOverride - + ConnectionDelayOverride, + + ConnectionDelayOverride + + TopologyOverride, { run_nary_node_test(&RunNaryChainTest::new(&RunNaryConnectionTest::new( &RunWithSupervisor::new(test), @@ -91,8 +92,8 @@ where } } -impl<'a, Test, Overrides, const SIZE: usize> NaryChainTest - for RunNaryConnectionTest<'a, Test, SIZE> +impl NaryChainTest + for RunNaryConnectionTest<'_, Test, SIZE> where Test: NaryConnectionTest, Test: HasOverrides, @@ -124,7 +125,7 @@ where } } -impl<'a, Test> NaryConnectionTest<2> for RunBinaryAsNaryConnectionTest<'a, Test> +impl NaryConnectionTest<2> for RunBinaryAsNaryConnectionTest<'_, Test> where Test: BinaryConnectionTest, { @@ -140,8 +141,7 @@ where } } -impl<'a, Test, Overrides, const SIZE: usize> NaryConnectionTest - for RunWithSupervisor<'a, Test> +impl NaryConnectionTest for RunWithSupervisor<'_, Test> where Test: NaryConnectionTest, Test: HasOverrides, @@ -166,7 +166,7 @@ where } } -impl<'a, Test, Overrides, const SIZE: usize> HasOverrides for RunNaryConnectionTest<'a, Test, SIZE> +impl HasOverrides for RunNaryConnectionTest<'_, Test, SIZE> where Test: HasOverrides, { @@ -177,7 +177,7 @@ where } } -impl<'a, Test, Overrides> HasOverrides for RunBinaryAsNaryConnectionTest<'a, Test> +impl HasOverrides for RunBinaryAsNaryConnectionTest<'_, Test> where Test: HasOverrides, { diff --git a/tools/test-framework/src/framework/nary/node.rs b/tools/test-framework/src/framework/nary/node.rs index cea7c81ac4..2ea2379e25 100644 --- a/tools/test-framework/src/framework/nary/node.rs +++ b/tools/test-framework/src/framework/nary/node.rs @@ -45,7 +45,7 @@ pub struct RunNaryNodeTest<'a, Test, const SIZE: usize> { pub test: &'a Test, } -impl<'a, Test, Overrides, const SIZE: usize> BasicTest for RunNaryNodeTest<'a, Test, SIZE> +impl BasicTest for RunNaryNodeTest<'_, Test, SIZE> where Test: NaryNodeTest, Test: HasOverrides, @@ -75,7 +75,7 @@ where } } -impl<'a, Test, Overrides, const SIZE: usize> HasOverrides for RunNaryNodeTest<'a, Test, SIZE> +impl HasOverrides for RunNaryNodeTest<'_, Test, SIZE> where Test: HasOverrides, { diff --git a/tools/test-framework/src/framework/overrides.rs b/tools/test-framework/src/framework/overrides.rs index 0338224469..70398de376 100644 --- a/tools/test-framework/src/framework/overrides.rs +++ b/tools/test-framework/src/framework/overrides.rs @@ -22,6 +22,9 @@ use crate::framework::binary::node::{NodeConfigOverride, NodeGenesisOverride}; use crate::framework::nary::channel::PortsOverride as NaryPortsOverride; use crate::framework::supervisor::SupervisorOverride; use crate::types::config::TestConfig; +use crate::types::topology::TopologyType; + +use super::binary::chain::TopologyOverride; /** This trait should be implemented for all test cases to allow overriding @@ -145,6 +148,10 @@ pub trait TestOverrides { fn channel_version(&self) -> Version { Version::ics20() } + + fn topology(&self) -> Option { + None + } } impl HasOverrides for Test { @@ -231,3 +238,9 @@ impl NaryPortsOverride<2> for Test { [[port_a.clone(), port_b.clone()], [port_b, port_a]] } } + +impl TopologyOverride for Test { + fn topology(&self) -> Option { + TestOverrides::topology(self) + } +} diff --git a/tools/test-framework/src/framework/supervisor.rs b/tools/test-framework/src/framework/supervisor.rs index f43ea89536..e5c9f1933b 100644 --- a/tools/test-framework/src/framework/supervisor.rs +++ b/tools/test-framework/src/framework/supervisor.rs @@ -46,7 +46,7 @@ impl<'a, Test> RunWithSupervisor<'a, Test> { } } -impl<'a, Test, Overrides> HasOverrides for RunWithSupervisor<'a, Test> +impl HasOverrides for RunWithSupervisor<'_, Test> where Test: HasOverrides, { diff --git a/tools/test-framework/src/ibc/token.rs b/tools/test-framework/src/ibc/token.rs index ac7b6785ad..7300304d18 100644 --- a/tools/test-framework/src/ibc/token.rs +++ b/tools/test-framework/src/ibc/token.rs @@ -54,7 +54,7 @@ impl TaggedTokenExt for TaggedToken { } } -impl<'a, Chain> TaggedTokenExt for TaggedTokenRef<'a, Chain> { +impl TaggedTokenExt for TaggedTokenRef<'_, Chain> { fn denom(&self) -> TaggedDenomRef { self.map_ref(|t| &t.denom) } @@ -87,7 +87,7 @@ impl TaggedDenomExt for TaggedDenom { } } -impl<'a, Chain> TaggedDenomExt for TaggedDenomRef<'a, Chain> { +impl TaggedDenomExt for TaggedDenomRef<'_, Chain> { fn with_amount(&self, amount: impl Into) -> TaggedToken { self.map(|denom| Token { denom: (*denom).clone(), diff --git a/tools/test-framework/src/relayer/chain.rs b/tools/test-framework/src/relayer/chain.rs index a5c9fac652..4d98354aea 100644 --- a/tools/test-framework/src/relayer/chain.rs +++ b/tools/test-framework/src/relayer/chain.rs @@ -21,7 +21,10 @@ */ use crossbeam_channel as channel; +use ibc_proto::ibc::core::channel::v1::{QueryUpgradeErrorRequest, QueryUpgradeRequest}; use ibc_relayer::chain::cosmos::version::Specs; +use ibc_relayer_types::applications::ics28_ccv::msgs::{ConsumerChain, ConsumerId}; +use ibc_relayer_types::core::ics04_channel::upgrade::{ErrorReceipt, Upgrade}; use tracing::Span; use ibc_proto::ibc::apps::fee::v1::{ @@ -432,7 +435,30 @@ where self.value().query_incentivized_packet(request) } - fn query_consumer_chains(&self) -> Result, Error> { + fn query_consumer_chains(&self) -> Result, Error> { self.value().query_consumer_chains() } + + fn query_upgrade( + &self, + request: QueryUpgradeRequest, + height: Height, + include_proof: IncludeProof, + ) -> Result<(Upgrade, Option), Error> { + self.value().query_upgrade(request, height, include_proof) + } + + fn query_upgrade_error( + &self, + request: QueryUpgradeErrorRequest, + height: Height, + include_proof: IncludeProof, + ) -> Result<(ErrorReceipt, Option), Error> { + self.value() + .query_upgrade_error(request, height, include_proof) + } + + fn query_ccv_consumer_id(&self, client_id: &ClientId) -> Result { + self.value().query_ccv_consumer_id(client_id) + } } diff --git a/tools/test-framework/src/relayer/channel.rs b/tools/test-framework/src/relayer/channel.rs index 2affc07f87..2ea35886c9 100644 --- a/tools/test-framework/src/relayer/channel.rs +++ b/tools/test-framework/src/relayer/channel.rs @@ -1,11 +1,16 @@ use core::time::Duration; use eyre::eyre; use ibc_relayer::chain::handle::ChainHandle; -use ibc_relayer::chain::requests::{IncludeProof, QueryChannelRequest, QueryHeight}; -use ibc_relayer::channel::version::Version; +use ibc_relayer::chain::requests::{ + IncludeProof, QueryChannelRequest, QueryChannelsRequest, QueryHeight, +}; +use ibc_relayer::channel::version::Version as ChannelEndVersion; use ibc_relayer::channel::{extract_channel_id, Channel, ChannelSide}; -use ibc_relayer_types::core::ics04_channel::channel::State as ChannelState; -use ibc_relayer_types::core::ics04_channel::channel::{ChannelEnd, IdentifiedChannelEnd, Ordering}; +use ibc_relayer_types::core::ics04_channel::channel::{ + ChannelEnd, IdentifiedChannelEnd, Ordering, State as ChannelState, UpgradeState, +}; +use ibc_relayer_types::core::ics04_channel::packet::Sequence; +use ibc_relayer_types::core::ics04_channel::version::Version; use ibc_relayer_types::core::ics24_host::identifier::ConnectionId; use crate::error::Error; @@ -34,6 +39,71 @@ impl TaggedChannelEndExt } } +/// This struct contains the attributes which can be modified with a channel upgrade +pub struct ChannelUpgradableAttributes { + version_a: Version, + version_b: Version, + ordering: Ordering, + connection_hops_a: Vec, + connection_hops_b: Vec, + upgrade_sequence: Sequence, +} + +impl ChannelUpgradableAttributes { + pub fn new( + version_a: Version, + version_b: Version, + ordering: Ordering, + connection_hops_a: Vec, + connection_hops_b: Vec, + upgrade_sequence: Sequence, + ) -> Self { + Self { + version_a, + version_b, + ordering, + connection_hops_a, + connection_hops_b, + upgrade_sequence, + } + } + + pub fn flipped(&self) -> Self { + Self { + version_a: self.version_b.clone(), + version_b: self.version_a.clone(), + ordering: self.ordering, + connection_hops_a: self.connection_hops_b.clone(), + connection_hops_b: self.connection_hops_a.clone(), + upgrade_sequence: self.upgrade_sequence, + } + } + + pub fn version_a(&self) -> &Version { + &self.version_a + } + + pub fn version_b(&self) -> &Version { + &self.version_b + } + + pub fn ordering(&self) -> &Ordering { + &self.ordering + } + + pub fn connection_hops_a(&self) -> &Vec { + &self.connection_hops_a + } + + pub fn connection_hops_b(&self) -> &Vec { + &self.connection_hops_b + } + + pub fn upgrade_sequence(&self) -> &Sequence { + &self.upgrade_sequence + } +} + pub fn init_channel( handle_a: &ChainA, handle_b: &ChainB, @@ -81,7 +151,7 @@ pub fn init_channel_version( connection_id_b: &TaggedConnectionIdRef, src_port_id: &TaggedPortIdRef, dst_port_id: &TaggedPortIdRef, - version: Version, + version: ChannelEndVersion, ) -> Result<(TaggedChannelId, Channel), Error> { let channel = Channel { connection_delay: Default::default(), @@ -181,7 +251,7 @@ pub fn query_channel_end( channel_id: channel_id.into_value().clone(), height: QueryHeight::Latest, }, - IncludeProof::No, + IncludeProof::Yes, )?; Ok(DualTagged::new(channel_end)) @@ -207,6 +277,23 @@ pub fn query_identified_channel_end( ))) } +pub fn query_identified_channel_ends( + handle: &ChainA, +) -> Result>, Error> { + let channel_ends = handle.query_channels(QueryChannelsRequest { pagination: None })?; + let identified_channels = channel_ends + .iter() + .map(|c| { + DualTagged::new(IdentifiedChannelEnd::new( + c.port_id.clone(), + c.channel_id.clone(), + c.channel_end.clone(), + )) + }) + .collect(); + Ok(identified_channels) +} + pub fn assert_eventually_channel_established( handle_a: &ChainA, handle_b: &ChainB, @@ -220,7 +307,10 @@ pub fn assert_eventually_channel_established( + handle_a: &ChainA, + handle_b: &ChainB, + channel_id_a: &TaggedChannelIdRef, + port_id_a: &TaggedPortIdRef, + upgrade_attrs: &ChannelUpgradableAttributes, +) -> Result, Error> { + assert_eventually_succeed( + "channel upgrade should be initialised", + 20, + Duration::from_secs(1), + || { + assert_eventually_succeed( + "channel upgrade should be initialised", + 20, + Duration::from_secs(1), + || { + assert_channel_upgrade_state( + ChannelState::Open(UpgradeState::Upgrading), + ChannelState::Open(UpgradeState::NotUpgrading), + handle_a, + handle_b, + channel_id_a, + port_id_a, + upgrade_attrs, + &Sequence::from(1), + &Sequence::from(0), + ) + }, + ) + }, + ) +} + +pub fn assert_eventually_channel_upgrade_try( + handle_a: &ChainA, + handle_b: &ChainB, + channel_id_a: &TaggedChannelIdRef, + port_id_a: &TaggedPortIdRef, + upgrade_attrs: &ChannelUpgradableAttributes, +) -> Result, Error> { + assert_eventually_succeed( + "channel upgrade try step should be done", + 20, + Duration::from_secs(2), + || { + assert_channel_upgrade_state( + ChannelState::Flushing, + ChannelState::Open(UpgradeState::Upgrading), + handle_a, + handle_b, + channel_id_a, + port_id_a, + upgrade_attrs, + &Sequence::from(1), + &Sequence::from(1), + ) + }, + ) +} + +pub fn assert_eventually_channel_upgrade_ack( + handle_a: &ChainA, + handle_b: &ChainB, + channel_id_a: &TaggedChannelIdRef, + port_id_a: &TaggedPortIdRef, + channel_state_a: ChannelState, + channel_state_b: ChannelState, + upgrade_attrs: &ChannelUpgradableAttributes, +) -> Result, Error> { + assert_eventually_succeed( + "channel upgrade ack step should be done", + 20, + Duration::from_secs(1), + || { + assert_channel_upgrade_state( + channel_state_a, + channel_state_b, + handle_a, + handle_b, + channel_id_a, + port_id_a, + upgrade_attrs, + &Sequence::from(1), + &Sequence::from(1), + ) + }, + ) +} + +pub fn assert_eventually_channel_upgrade_flushing( + handle_a: &ChainA, + handle_b: &ChainB, + channel_id_a: &TaggedChannelIdRef, + port_id_a: &TaggedPortIdRef, + upgrade_attrs: &ChannelUpgradableAttributes, +) -> Result, Error> { + assert_eventually_succeed( + "channel upgrade ack step should be done", + 20, + Duration::from_secs(1), + || { + assert_channel_upgrade_state( + ChannelState::Flushing, + ChannelState::Flushing, + handle_a, + handle_b, + channel_id_a, + port_id_a, + upgrade_attrs, + &Sequence::from(1), + &Sequence::from(1), + ) + }, + ) +} + +pub fn assert_eventually_channel_upgrade_confirm( + handle_a: &ChainA, + handle_b: &ChainB, + channel_id_a: &TaggedChannelIdRef, + port_id_a: &TaggedPortIdRef, + upgrade_attrs: &ChannelUpgradableAttributes, +) -> Result, Error> { + assert_eventually_succeed( + "channel upgrade confirm step should be done", + 20, + Duration::from_secs(1), + || { + assert_channel_upgrade_state( + ChannelState::Open(UpgradeState::NotUpgrading), + ChannelState::FlushComplete, + handle_a, + handle_b, + channel_id_a, + port_id_a, + upgrade_attrs, + &Sequence::from(1), + &Sequence::from(1), + ) + }, + ) +} + +pub fn assert_eventually_channel_upgrade_open( + handle_a: &ChainA, + handle_b: &ChainB, + channel_id_a: &TaggedChannelIdRef, + port_id_a: &TaggedPortIdRef, + upgrade_attrs: &ChannelUpgradableAttributes, +) -> Result, Error> { + assert_eventually_succeed( + "channel upgrade open step should be done", + 20, + Duration::from_secs(1), + || { + assert_channel_upgrade_state( + ChannelState::Open(UpgradeState::NotUpgrading), + ChannelState::Open(UpgradeState::NotUpgrading), + handle_a, + handle_b, + channel_id_a, + port_id_a, + upgrade_attrs, + &Sequence::from(1), + &Sequence::from(1), + ) + }, + ) +} + +pub fn assert_eventually_channel_upgrade_cancel( + handle_a: &ChainA, + handle_b: &ChainB, + channel_id_a: &TaggedChannelIdRef, + port_id_a: &TaggedPortIdRef, + upgrade_attrs: &ChannelUpgradableAttributes, +) -> Result, Error> { + assert_eventually_succeed( + "channel upgrade cancel step should be done", + 20, + Duration::from_secs(1), + || { + assert_channel_upgrade_state( + ChannelState::Open(UpgradeState::NotUpgrading), + ChannelState::Open(UpgradeState::NotUpgrading), + handle_a, + handle_b, + channel_id_a, + port_id_a, + upgrade_attrs, + &Sequence::from(1), + &Sequence::from(1), + ) + }, + ) +} + +/// Note that the field modified by the channel upgrade are only updated when +/// the channel returns in the OPEN State +fn assert_channel_upgrade_state( + a_side_state: ChannelState, + b_side_state: ChannelState, + handle_a: &ChainA, + handle_b: &ChainB, + channel_id_a: &TaggedChannelIdRef, + port_id_a: &TaggedPortIdRef, + upgrade_attrs: &ChannelUpgradableAttributes, + upgrade_sequence_a: &Sequence, + upgrade_sequence_b: &Sequence, +) -> Result, Error> { + let channel_end_a = query_channel_end(handle_a, channel_id_a, port_id_a)?; + + if !channel_end_a.value().state_matches(&a_side_state) { + return Err(Error::generic(eyre!( + "expected channel end A state to be `{}`, but is instead `{}`", + a_side_state, + channel_end_a.value().state() + ))); + } + + if !channel_end_a + .value() + .version_matches(upgrade_attrs.version_a()) + { + return Err(Error::generic(eyre!( + "expected channel end A version to be `{}`, but it is instead `{}`", + upgrade_attrs.version_a(), + channel_end_a.value().version() + ))); + } + + if !channel_end_a + .value() + .order_matches(upgrade_attrs.ordering()) + { + return Err(Error::generic(eyre!( + "expected channel end A ordering to be `{}`, but it is instead `{}`", + upgrade_attrs.ordering(), + channel_end_a.value().ordering() + ))); + } + + if !channel_end_a + .value() + .connection_hops_matches(upgrade_attrs.connection_hops_a()) + { + return Err(Error::generic(eyre!( + "expected channel end A connection hops to be `{:?}`, but it is instead `{:?}`", + upgrade_attrs.connection_hops_a(), + channel_end_a.value().connection_hops() + ))); + } + + if !channel_end_a + .value() + .upgrade_sequence + .eq(upgrade_sequence_a) + { + return Err(Error::generic(eyre!( + "expected channel end A upgrade sequence to be `{}`, but it is instead `{}`", + upgrade_sequence_a, + channel_end_a.value().upgrade_sequence + ))); + } + + let channel_id_b = channel_end_a + .tagged_counterparty_channel_id() + .ok_or_else(|| eyre!("expected counterparty channel id to present on open channel"))?; + + let port_id_b = channel_end_a.tagged_counterparty_port_id(); + + let channel_end_b = query_channel_end(handle_b, &channel_id_b.as_ref(), &port_id_b.as_ref())?; + + if !channel_end_b.value().state_matches(&b_side_state) { + return Err(Error::generic(eyre!( + "expected channel end B state to be `{}`, but is instead `{}`", + b_side_state, + channel_end_b.value().state() + ))); + } + + if !channel_end_b + .value() + .version_matches(upgrade_attrs.version_b()) + { + return Err(Error::generic(eyre!( + "expected channel end B version to be `{}`, but it is instead `{}`", + upgrade_attrs.version_b(), + channel_end_b.value().version() + ))); + } + + if !channel_end_b + .value() + .order_matches(upgrade_attrs.ordering()) + { + return Err(Error::generic(eyre!( + "expected channel end B ordering to be `{}`, but it is instead `{}`", + upgrade_attrs.ordering(), + channel_end_b.value().ordering() + ))); + } + + if !channel_end_b + .value() + .connection_hops_matches(upgrade_attrs.connection_hops_b()) + { + return Err(Error::generic(eyre!( + "expected channel end B connection hops to be `{:?}`, but it is instead `{:?}`", + upgrade_attrs.connection_hops_b(), + channel_end_b.value().connection_hops() + ))); + } + + if !channel_end_b + .value() + .upgrade_sequence + .eq(upgrade_sequence_b) + { + return Err(Error::generic(eyre!( + "expected channel end B upgrade sequence to be `{}`, but it is instead `{}`", + upgrade_sequence_b, + channel_end_b.value().upgrade_sequence + ))); + } + + Ok(channel_id_b) +} diff --git a/tools/test-framework/src/relayer/tx.rs b/tools/test-framework/src/relayer/tx.rs index a2d4e41393..90f62a09fb 100644 --- a/tools/test-framework/src/relayer/tx.rs +++ b/tools/test-framework/src/relayer/tx.rs @@ -12,9 +12,10 @@ use ibc_relayer::config::{AddressType, GasPrice}; use ibc_relayer_types::core::ics24_host::identifier::ChainId; use tendermint_rpc::Url; +use crate::chain::chain_type::ChainType; use crate::error::{handle_generic_error, Error}; -pub fn gas_config_for_test(native_token: String) -> GasConfig { +pub fn gas_config_for_test(native_token: String, chain_type: ChainType) -> GasConfig { let max_gas = 3000000; let gas_multiplier = 1.5; @@ -37,6 +38,12 @@ pub fn gas_config_for_test(native_token: String) -> GasConfig { granter: fee_granter.clone(), }; + let dynamic_gas_price = if chain_type.enable_dynamic_fee() { + DynamicGasPrice::unsafe_new(true, 1.3, 5.0) + } else { + DynamicGasPrice::disabled() + }; + GasConfig { default_gas, max_gas, @@ -44,16 +51,13 @@ pub fn gas_config_for_test(native_token: String) -> GasConfig { gas_price, max_fee, fee_granter, - dynamic_gas_price: DynamicGasPrice { - enabled: false, - multiplier: 1.0, - max: 0.6, - }, + dynamic_gas_price, } } pub fn new_tx_config_for_test( chain_id: ChainId, + chain_type: ChainType, raw_rpc_address: String, raw_grpc_address: String, address_type: AddressType, @@ -61,7 +65,7 @@ pub fn new_tx_config_for_test( ) -> Result { let rpc_address = Url::from_str(&raw_rpc_address).map_err(handle_generic_error)?; let grpc_address = Uri::from_str(&raw_grpc_address).map_err(handle_generic_error)?; - let gas_config = gas_config_for_test(native_token); + let gas_config = gas_config_for_test(native_token, chain_type); let rpc_timeout = Duration::from_secs(30); let max_msg_num = Default::default(); let max_tx_size = Default::default(); diff --git a/tools/test-framework/src/types/config.rs b/tools/test-framework/src/types/config.rs index ea3944b3f5..ff0889465b 100644 --- a/tools/test-framework/src/types/config.rs +++ b/tools/test-framework/src/types/config.rs @@ -34,6 +34,8 @@ pub struct TestConfig { pub compat_modes: Option>, + pub ipv6_grpc: bool, + /** The directory path for storing the chain and relayer files. Defaults to `"data"`. This can be overridden with the `$CHAIN_STORE_DIR` @@ -63,3 +65,9 @@ pub struct TestConfig { pub bootstrap_with_random_ids: bool, } + +impl TestConfig { + pub fn native_token(&self, id: usize) -> &String { + &self.native_tokens[id % self.native_tokens.len()] + } +} diff --git a/tools/test-framework/src/types/env.rs b/tools/test-framework/src/types/env.rs index 427d50eaa1..ba0986f442 100644 --- a/tools/test-framework/src/types/env.rs +++ b/tools/test-framework/src/types/env.rs @@ -2,7 +2,6 @@ Types for exporting test setup information into environment variables. */ -use core::convert::AsRef; use itertools::Itertools; use std::collections::BTreeMap; use std::fs::write; @@ -67,7 +66,7 @@ impl EnvWriter for BTreeMap { } } -impl<'a, Writer: EnvWriter> EnvWriter for PrefixEnvWriter<'a, Writer> { +impl EnvWriter for PrefixEnvWriter<'_, Writer> { fn write_env(&mut self, key: &str, value: &str) { self.writer .write_env(&format!("{}_{}", self.prefix, key), value); diff --git a/tools/test-framework/src/types/mod.rs b/tools/test-framework/src/types/mod.rs index a1c1db153d..a107f96d7c 100644 --- a/tools/test-framework/src/types/mod.rs +++ b/tools/test-framework/src/types/mod.rs @@ -16,4 +16,5 @@ pub mod nary; pub mod process; pub mod single; pub mod tagged; +pub mod topology; pub mod wallet; diff --git a/tools/test-framework/src/types/nary/chains.rs b/tools/test-framework/src/types/nary/chains.rs index 74579e8e32..9f727710a5 100644 --- a/tools/test-framework/src/types/nary/chains.rs +++ b/tools/test-framework/src/types/nary/chains.rs @@ -2,7 +2,6 @@ Constructs for N-ary connected chains. */ -use core::convert::{From, TryFrom}; use eyre::eyre; use ibc_relayer::chain::handle::ChainHandle; use ibc_relayer::foreign_client::ForeignClient; @@ -15,12 +14,14 @@ use crate::types::nary::foreign_client::*; use crate::types::single::node::FullNode; use crate::types::tagged::*; use crate::util::array::try_into_array; +use crate::util::two_dim_hash_map::TwoDimMap; /** A fixed-size N-ary connected chains as specified by `SIZE`. Contains `SIZE` number of [`ChainHandle`]s, `SIZE` number of - [`FullNode`]s, and `SIZE`x`SIZE` numbers of [`ForeignClient`] pairs. + [`FullNode`]s, and a numbers of [`ForeignClient`] pairs + depending on `SIZE` and the topology. A `ConnectedChains` can be constructed by first constructing a [`DynamicConnectedChains`], and then calling @@ -45,7 +46,7 @@ pub struct NaryConnectedChains { pub struct DynamicConnectedChains { chain_handles: Vec, full_nodes: Vec, - pub foreign_clients: Vec>>, + pub foreign_clients: TwoDimMap>, } /** @@ -183,7 +184,7 @@ impl DynamicConnectedChains { pub fn new( chain_handles: Vec, full_nodes: Vec, - foreign_clients: Vec>>, + foreign_clients: TwoDimMap>, ) -> Self { Self { chain_handles, @@ -200,7 +201,7 @@ impl DynamicConnectedChains { &self.full_nodes } - pub fn foreign_clients(&self) -> &Vec>> { + pub fn foreign_clients(&self) -> &TwoDimMap> { &self.foreign_clients } } diff --git a/tools/test-framework/src/types/nary/channel.rs b/tools/test-framework/src/types/nary/channel.rs index 68864f4786..097c1579d2 100644 --- a/tools/test-framework/src/types/nary/channel.rs +++ b/tools/test-framework/src/types/nary/channel.rs @@ -1,8 +1,6 @@ /*! Constructs for N-ary connected channels. */ - -use core::convert::TryFrom; use eyre::eyre; use ibc_relayer::chain::handle::ChainHandle; use ibc_relayer::channel::Channel; @@ -13,26 +11,28 @@ use crate::error::Error; use crate::types::binary::channel::ConnectedChannel; use crate::types::env::{EnvWriter, ExportEnv}; use crate::types::tagged::*; -use crate::util::array::try_into_nested_array; +use crate::util::two_dim_hash_map::TwoDimMap; /** - A fixed-size N-ary connected channels as specified by `SIZE`. + A two dimensional BTreeMap of connected channels as specified by `SIZE` + and topology. - Contains `SIZE`x`SIZE` number of binary [`ConnectedChannel`]s. + The number of binary [`ConnectedChannel`]s depends on the topology. */ #[derive(Debug, Clone)] pub struct ConnectedChannels { - channels: [[ConnectedChannel; SIZE]; SIZE], + pub channels: TwoDimMap>, } /** - A dynamic-sized N-ary connected channels, consist of a nested - vector of binary [`ConnectedChannel`]s which must be of the - same length. + A two dimensional BTreeMap of connected channels as specified by `SIZE` + and topology. + + The number of binary [`ConnectedChannel`]s depends on the topology. */ #[derive(Debug, Clone)] pub struct DynamicConnectedChannels { - channels: Vec>>, + channels: TwoDimMap>, } /** @@ -71,32 +71,31 @@ impl ConnectedChannels { pub fn channel_at( &self, ) -> Result, Error> { - if CHAIN_A >= SIZE || CHAIN_B >= SIZE { - Err(Error::generic(eyre!( - "cannot get channel beyond position {}/{}", - CHAIN_A, - CHAIN_B - ))) - } else { - let raw_channel = self.channels[CHAIN_A][CHAIN_B].clone(); - - let channel = raw_channel.map_chain(MonoTagged::new, MonoTagged::new); - - Ok(channel) - } + let raw_channel = self + .channels + .get((CHAIN_A, CHAIN_B)) + .ok_or_else(|| { + Error::generic(eyre!( + "No channel entry found for chain `{CHAIN_A}` to `{CHAIN_B}`" + )) + })? + .clone(); + let channel = raw_channel.map_chain(MonoTagged::new, MonoTagged::new); + + Ok(channel) } - pub fn channels(&self) -> &[[ConnectedChannel; SIZE]; SIZE] { + pub fn channels(&self) -> &TwoDimMap> { &self.channels } } impl DynamicConnectedChannels { - pub fn new(channels: Vec>>) -> Self { + pub fn new(channels: TwoDimMap>) -> Self { Self { channels } } - pub fn channels(&self) -> &Vec>> { + pub fn channels(&self) -> &TwoDimMap> { &self.channels } } @@ -108,7 +107,7 @@ impl TryFrom) -> Result { Ok(ConnectedChannels { - channels: try_into_nested_array(channels.channels)?, + channels: channels.channels, }) } } @@ -121,38 +120,21 @@ impl From> for NthConnectedCha impl ExportEnv for ConnectedChannels { fn export_env(&self, writer: &mut impl EnvWriter) { - for (i, inner_channels) in self.channels.iter().enumerate() { - for (j, channel_i_to_j) in inner_channels.iter().enumerate() { - writer.write_env( - &format!("CONNECTION_ID_{j}_to_{i}"), - &format!("{}", channel_i_to_j.connection.connection_id_a), - ); - - writer.write_env( - &format!("CONNECTION_ID_{i}_to_{j}"), - &format!("{}", channel_i_to_j.connection.connection_id_b), - ); - - writer.write_env( - &format!("CHANNEL_ID_{j}_to_{i}"), - &format!("{}", channel_i_to_j.channel_id_a), - ); - - writer.write_env( - &format!("PORT_{j}_to_{i}"), - &format!("{}", channel_i_to_j.port_a), - ); - - writer.write_env( - &format!("CHANNEL_ID_{i}_to_{j}"), - &format!("{}", channel_i_to_j.channel_id_b), - ); - - writer.write_env( - &format!("PORT_{i}_to_{j}"), - &format!("{}", channel_i_to_j.port_b), - ); - } + for (src_chain, dst_chain, channel) in self.channels.iter() { + writer.write_env( + &format!("CONNECTION_ID_{}_to_{}", src_chain, dst_chain), + &format!("{}", channel.connection.connection_id_a), + ); + + writer.write_env( + &format!("CHANNEL_ID_{}_to_{}", src_chain, dst_chain), + &format!("{}", channel.channel_id_a), + ); + + writer.write_env( + &format!("PORT_{}_to_{}", src_chain, dst_chain), + &format!("{}", channel.port_a), + ); } } } diff --git a/tools/test-framework/src/types/nary/connection.rs b/tools/test-framework/src/types/nary/connection.rs index faa01cff7b..31c5b0e2d8 100644 --- a/tools/test-framework/src/types/nary/connection.rs +++ b/tools/test-framework/src/types/nary/connection.rs @@ -1,8 +1,6 @@ /*! Constructs for N-ary connected connections. */ - -use core::convert::TryFrom; use eyre::eyre; use ibc_relayer::chain::handle::ChainHandle; use ibc_relayer_types::core::ics24_host::identifier::ConnectionId; @@ -12,26 +10,28 @@ use crate::error::Error; use crate::types::binary::connection::ConnectedConnection; use crate::types::env::{EnvWriter, ExportEnv}; use crate::types::tagged::*; -use crate::util::array::{into_nested_vec, try_into_nested_array}; +use crate::util::two_dim_hash_map::TwoDimMap; /** - A fixed-size N-ary connected connections as specified by `SIZE`. + A two dimensional BTreeMap of connected connections as specified by `SIZE` + and topology. - Contains `SIZE`x`SIZE` number of binary [`ConnectedConnection`]s. + The number of binary [`ConnectedConnection`]s depends on the topology. */ #[derive(Debug, Clone)] pub struct ConnectedConnections { - connections: [[ConnectedConnection; SIZE]; SIZE], + connections: TwoDimMap>, } /** - A dynamic-sized N-ary connected connections, made of a - nested vector of binary [`ConnectedConnection`] which must be - in the same dimension. + A two dimensional BTreeMap of connected connections as specified by `SIZE` + and topology. + + The number of binary [`ConnectedConnection`]s depends on the topology. */ #[derive(Debug, Clone)] pub struct DynamicConnectedConnections { - connections: Vec>>, + connections: TwoDimMap>, } /** @@ -56,32 +56,31 @@ impl ConnectedConnections pub fn connection_at( &self, ) -> Result, Error> { - if CHAIN_A >= SIZE || CHAIN_B >= SIZE { - Err(Error::generic(eyre!( - "cannot get connection beyond position {}/{}", - CHAIN_A, - CHAIN_B - ))) - } else { - let raw_connection = self.connections[CHAIN_A][CHAIN_B].clone(); - - let channel = raw_connection.map_chain(MonoTagged::new, MonoTagged::new); - - Ok(channel) - } + let raw_connection = self + .connections + .get((CHAIN_A, CHAIN_B)) + .ok_or_else(|| { + Error::generic(eyre!( + "No connection entry found for chain `{CHAIN_A}` to `{CHAIN_B}`" + )) + })? + .clone(); + let connection = raw_connection.map_chain(MonoTagged::new, MonoTagged::new); + + Ok(connection) } - pub fn connections(&self) -> &[[ConnectedConnection; SIZE]; SIZE] { + pub fn connections(&self) -> &TwoDimMap> { &self.connections } } impl DynamicConnectedConnections { - pub fn new(connections: Vec>>) -> Self { + pub fn new(connections: TwoDimMap>) -> Self { Self { connections } } - pub fn connections(&self) -> &Vec>> { + pub fn connections(&self) -> &TwoDimMap> { &self.connections } } @@ -91,7 +90,7 @@ impl From) -> Self { DynamicConnectedConnections { - connections: into_nested_vec(connections.connections), + connections: connections.connections, } } } @@ -103,7 +102,7 @@ impl TryFrom) -> Result { Ok(ConnectedConnections { - connections: try_into_nested_array(connections.connections)?, + connections: connections.connections, }) } } @@ -118,18 +117,11 @@ impl From> impl ExportEnv for ConnectedConnections { fn export_env(&self, writer: &mut impl EnvWriter) { - for (i, inner_connections) in self.connections.iter().enumerate() { - for (j, connection_i_to_j) in inner_connections.iter().enumerate() { - writer.write_env( - &format!("CONNECTION_ID_{j}_to_{i}"), - &format!("{}", connection_i_to_j.connection_id_a), - ); - - writer.write_env( - &format!("CONNECTION_ID_{i}_to_{j}"), - &format!("{}", connection_i_to_j.connection_id_b), - ); - } + for (src_chain, dst_chain, connection) in self.connections.iter() { + writer.write_env( + &format!("CONNECTION_ID_{}_to_{}", src_chain, dst_chain), + &format!("{}", connection.connection_id_a), + ); } } } diff --git a/tools/test-framework/src/types/nary/foreign_client.rs b/tools/test-framework/src/types/nary/foreign_client.rs index 33080f4944..a9dfd4cd46 100644 --- a/tools/test-framework/src/types/nary/foreign_client.rs +++ b/tools/test-framework/src/types/nary/foreign_client.rs @@ -1,4 +1,3 @@ -use core::convert::TryFrom; use eyre::eyre; use ibc_relayer::chain::handle::ChainHandle; use ibc_relayer::foreign_client::ForeignClient; @@ -8,7 +7,7 @@ use crate::error::Error; use crate::types::binary::foreign_client::ForeignClientPair; use crate::types::env::{EnvWriter, ExportEnv}; use crate::types::tagged::*; -use crate::util::array::{into_nested_vec, try_into_nested_array}; +use crate::util::two_dim_hash_map::TwoDimMap; /** A [`ForeignClient`] that is tagged by a `Handle: ChainHandle` and @@ -22,7 +21,7 @@ pub type NthForeignClientPair = #[derive(Clone)] pub struct ForeignClientPairs { - foreign_clients: [[ForeignClient; SIZE]; SIZE], + foreign_clients: TwoDimMap>, } impl ForeignClientPairs { @@ -34,19 +33,15 @@ impl ForeignClientPairs { pub fn foreign_client_at( &self, ) -> Result, Error> { - if SRC >= SIZE || DEST >= SIZE { - Err(Error::generic(eyre!( - "cannot get foreign client beyond position {}/{}", - SRC, - DEST - ))) - } else { - let client = self.foreign_clients[SRC][DEST] - .clone() - .map_chain(MonoTagged::new, MonoTagged::new); - - Ok(client) - } + let client = self + .foreign_clients + .get((SRC, DEST)) + .ok_or_else(|| { + Error::generic(eyre!("No client entry found for chain `{SRC}` to `{DEST}`")) + })? + .clone() + .map_chain(MonoTagged::new, MonoTagged::new); + Ok(client) } pub fn foreign_client_pair_at( @@ -58,31 +53,29 @@ impl ForeignClientPairs { Ok(ForeignClientPair::new(client_a_to_b, client_b_to_a)) } - pub fn into_nested_vec(self) -> Vec>> { - into_nested_vec(self.foreign_clients) + pub fn into_nested_vec(self) -> TwoDimMap> { + self.foreign_clients } } -impl TryFrom>>> +impl TryFrom>> for ForeignClientPairs { type Error = Error; - fn try_from(clients: Vec>>) -> Result { - let foreign_clients = try_into_nested_array(clients)?; + fn try_from(clients: TwoDimMap>) -> Result { + let foreign_clients = clients; Ok(Self { foreign_clients }) } } impl ExportEnv for ForeignClientPairs { fn export_env(&self, writer: &mut impl EnvWriter) { - for (source, inner_clients) in self.foreign_clients.iter().enumerate() { - for (destination, client) in inner_clients.iter().enumerate() { - writer.write_env( - &format!("CLIENT_ID_{source}_to_{destination}"), - &format!("{}", client.id()), - ); - } + for (src_chain, dst_chain, client) in self.foreign_clients.iter() { + writer.write_env( + &format!("CLIENT_ID_{}_to_{}", src_chain, dst_chain), + &format!("{}", client.id()), + ); } } } diff --git a/tools/test-framework/src/types/single/node.rs b/tools/test-framework/src/types/single/node.rs index 9d4e7ea280..4abdea72b8 100644 --- a/tools/test-framework/src/types/single/node.rs +++ b/tools/test-framework/src/types/single/node.rs @@ -12,7 +12,9 @@ use ibc_relayer::config::compat_mode::CompatMode; use ibc_relayer::config::dynamic_gas::DynamicGasPrice; use ibc_relayer::config::gas_multiplier::GasMultiplier; use ibc_relayer::keyring::Store; +use ibc_relayer::util::excluded_sequences::ExcludedSequences; use ibc_relayer_types::core::ics24_host::identifier::ChainId; +use std::collections::BTreeMap; use std::sync::{Arc, RwLock}; use tendermint_rpc::Url; use tendermint_rpc::WebSocketClientUrl; @@ -101,7 +103,7 @@ impl TaggedFullNodeExt for MonoTagged { } } -impl<'a, Chain> TaggedFullNodeExt for MonoTagged { +impl TaggedFullNodeExt for MonoTagged { fn chain_id(&self) -> MonoTagged { self.map_ref(|c| &c.chain_driver.chain_id) } @@ -130,7 +132,6 @@ impl FullNode { test_config: &TestConfig, chain_number: usize, ) -> Result { - let native_token_number = chain_number % test_config.native_tokens.len(); let hermes_keystore_dir = test_config .chain_store_dir .join("hermes_keyring") @@ -145,14 +146,16 @@ impl FullNode { // Provenance requires a very high gas price let gas_price = match chain_type { - TestedChainType::Provenance => config::GasPrice::new( - 5000.0, - test_config.native_tokens[native_token_number].clone(), - ), - _ => config::GasPrice::new( - 0.003, - test_config.native_tokens[native_token_number].clone(), - ), + TestedChainType::Provenance => { + config::GasPrice::new(5000.0, test_config.native_token(chain_number).clone()) + } + _ => config::GasPrice::new(0.003, test_config.native_token(chain_number).clone()), + }; + + let dynamic_gas_price = if chain_type.enable_dynamic_fee() { + DynamicGasPrice::unsafe_new(true, 1.3, 5.0) + } else { + DynamicGasPrice::disabled() }; Ok(config::ChainConfig::CosmosSdk(CosmosSdkConfig { @@ -175,7 +178,7 @@ impl FullNode { max_gas: Some(3000000), gas_adjustment: None, gas_multiplier: Some(GasMultiplier::unsafe_new(1.5)), - dynamic_gas_price: DynamicGasPrice::default(), + dynamic_gas_price, fee_granter: None, max_msg_num: Default::default(), max_tx_size: Default::default(), @@ -191,11 +194,14 @@ impl FullNode { packet_filter: Default::default(), address_type: chain_type.address_type(), memo_prefix: Default::default(), + memo_overwrite: None, proof_specs: Default::default(), extension_options: Default::default(), sequential_batch_tx: false, compat_mode, clear_interval: None, + excluded_sequences: ExcludedSequences::new(BTreeMap::new()), + allow_ccq: true, })) } diff --git a/tools/test-framework/src/types/tagged/dual.rs b/tools/test-framework/src/types/tagged/dual.rs index ffbafb3133..25eb15eab6 100644 --- a/tools/test-framework/src/types/tagged/dual.rs +++ b/tools/test-framework/src/types/tagged/dual.rs @@ -12,9 +12,8 @@ corresponds to a channel connected to a counterparty chain `ChainB`. */ -use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; +use core::cmp::Ordering; use core::fmt::{self, Debug, Display}; -use core::iter::{IntoIterator, Iterator}; use core::marker::PhantomData; /** @@ -311,7 +310,7 @@ impl Tagged { } } -impl<'a, TagA, TagB, Value: Clone> Tagged { +impl Tagged { /** Convert a [`Clone`]eable tagged reference into a tagged value. @@ -377,7 +376,7 @@ impl Tagged> { } } -impl<'a, TagA, TagB, Value> AsRef for Tagged { +impl AsRef for Tagged { fn as_ref(&self) -> &Value { self.value() } diff --git a/tools/test-framework/src/types/tagged/mod.rs b/tools/test-framework/src/types/tagged/mod.rs index 50f75dc6ca..fed89701e2 100644 --- a/tools/test-framework/src/types/tagged/mod.rs +++ b/tools/test-framework/src/types/tagged/mod.rs @@ -70,7 +70,7 @@ a `ChannelId` value that is used on `ChainA` to identify a channel that is connected to `ChainB`. With the tagged identifier, it is more unlikely for us to accidentally use the `ChannelId` coming from - counterparty chain, as it would have the the type + counterparty chain, as it would have the type `DualTagged` and thus result in type error. diff --git a/tools/test-framework/src/types/tagged/mono.rs b/tools/test-framework/src/types/tagged/mono.rs index ef4a228b93..9611638a55 100644 --- a/tools/test-framework/src/types/tagged/mono.rs +++ b/tools/test-framework/src/types/tagged/mono.rs @@ -17,9 +17,8 @@ */ -use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; +use core::cmp::Ordering; use core::fmt::{self, Debug, Display}; -use core::iter::{IntoIterator, Iterator}; use core::marker::PhantomData; use serde::{Serialize, Serializer}; @@ -221,7 +220,7 @@ impl Tagged { } } -impl<'a, Tag, Value: Clone> Tagged { +impl Tagged { /** Convert a [`Clone`]eable tagged reference into a tagged value. @@ -303,7 +302,7 @@ impl Tagged> { } } -impl<'a, Tag, Value> AsRef for Tagged { +impl AsRef for Tagged { fn as_ref(&self) -> &Value { self.value() } diff --git a/tools/test-framework/src/types/topology.rs b/tools/test-framework/src/types/topology.rs new file mode 100644 index 0000000000..4fb915a834 --- /dev/null +++ b/tools/test-framework/src/types/topology.rs @@ -0,0 +1,198 @@ +/*! + The Topology defines how chains are interconnected when more than two are used in tests. + This setup is managed by the [`crate::bootstrap::nary::chain::boostrap_chains_with_any_nodes`] + function. + + Connections are established by examining the existing clients, and channels are created based + on these connections. Therefore, to define the topology of the chains, it is sufficient to + create the appropriate set of clients. + + Example: Linear Topology + + For a linear topology between chains A, B, and C, the clients are created as follows: + * Chain A: a client referencing chain B + * Chain B: a client referencing chain B and a client referencing chain C + * Chain C: a client referencing chain B + + This setup ensures that: + + * Chain A is connected to Chain B. + * Chain B is connected to both Chain A and Chain C. + * Chain C is connected to Chain B. + + Example: Fully Connected Topology + + In a fully connected topology, every chain has clients referencing all other chains. + For chains A, B, and C, the clients are created as follows: + + * Chain A: Clients referencing chains B and C + * Chain B: Clients referencing chains A and C + * Chain C: Clients referencing chains A and B + * Each chain will also have a self referencing client + + This setup ensures that every chain is directly connected to every other chain, forming + a complete graph. + + Example: Cyclic Topology + + The cyclic topology is similar to the linear topology with the addition of the first and + last chain being connected as well. + For chains A, B, C and D, the clients are created as follows: + + * Chain A: Clients referencing chains B and D + * Chain B: Clients referencing chains A and C + * Chain C: Clients referencing chains B and D + * Chain D: Clients referencing chains A and C + + By defining the appropriate set of clients, you can establish the desired topology for + your tests, whether it be linear, fully connected, or any other configuration. +*/ + +use eyre::eyre; +use std::str::FromStr; + +use ibc_relayer::chain::handle::ChainHandle; +use ibc_relayer::foreign_client::ForeignClient; + +use crate::bootstrap::binary::chain::bootstrap_foreign_client; +use crate::error::Error; +use crate::util::two_dim_hash_map::TwoDimMap; + +pub enum TopologyType { + Linear, + Full, + Cyclic, +} + +impl FromStr for TopologyType { + type Err = Error; + + fn from_str(s: &str) -> Result { + match s { + "linear" => Ok(Self::Linear), + "full" => Ok(Self::Full), + "cyclic" => Ok(Self::Cyclic), + _ => Err(Error::generic(eyre!("The topology `{s}` does not exist"))), + } + } +} + +pub trait Topology { + fn create_topology( + &self, + chain_handles: &Vec, + ) -> Result>, Error>; +} + +pub struct FullyConnectedTopology; + +impl Topology for FullyConnectedTopology { + fn create_topology( + &self, + chain_handles: &Vec, + ) -> Result>, Error> { + let mut foreign_clients: TwoDimMap> = TwoDimMap::new(); + + for (i, handle_a) in chain_handles.iter().enumerate() { + for (j, handle_b) in chain_handles.iter().enumerate() { + let foreign_client = + bootstrap_foreign_client(handle_a, handle_b, Default::default())?; + + foreign_clients.insert((i, j), foreign_client); + } + } + Ok(foreign_clients) + } +} + +pub struct LinearTopology; + +impl Topology for LinearTopology { + fn create_topology( + &self, + chain_handles: &Vec, + ) -> Result>, Error> { + let mut foreign_clients: TwoDimMap> = TwoDimMap::new(); + + let last_index = chain_handles.len() - 1; + for (i, _) in chain_handles.iter().enumerate() { + if i < last_index { + let client = bootstrap_foreign_client( + &chain_handles[i], + &chain_handles[i + 1], + Default::default(), + )?; + foreign_clients.insert((i, i + 1), client); + } + if i > 0 { + let client = bootstrap_foreign_client( + &chain_handles[i], + &chain_handles[i - 1], + Default::default(), + )?; + foreign_clients.insert((i, i - 1), client); + } + } + Ok(foreign_clients) + } +} + +pub struct CyclicTopology; + +impl Topology for CyclicTopology { + fn create_topology( + &self, + chain_handles: &Vec, + ) -> Result>, Error> { + let mut foreign_clients: TwoDimMap> = TwoDimMap::new(); + + let last_index = chain_handles.len() - 1; + for (i, _) in chain_handles.iter().enumerate() { + // Create client from first chain to last + if i == 0 { + let client = bootstrap_foreign_client( + &chain_handles[0], + &chain_handles[last_index], + Default::default(), + )?; + foreign_clients.insert((i, last_index), client); + } + // Create client from last chain to first + if i == last_index { + let client = bootstrap_foreign_client( + &chain_handles[last_index], + &chain_handles[0], + Default::default(), + )?; + foreign_clients.insert((i, 0), client); + } + if i < last_index { + let client = bootstrap_foreign_client( + &chain_handles[i], + &chain_handles[i + 1], + Default::default(), + )?; + foreign_clients.insert((i, i + 1), client); + } + if i > 0 { + let client = bootstrap_foreign_client( + &chain_handles[i], + &chain_handles[i - 1], + Default::default(), + )?; + foreign_clients.insert((i, i - 1), client); + } + } + Ok(foreign_clients) + } +} + +pub fn bootstrap_topology( + topology: TopologyType, +) -> Box> { + match topology { + TopologyType::Full => Box::new(FullyConnectedTopology), + TopologyType::Linear => Box::new(LinearTopology), + TopologyType::Cyclic => Box::new(CyclicTopology), + } +} diff --git a/tools/test-framework/src/types/wallet.rs b/tools/test-framework/src/types/wallet.rs index 9886c19cbe..89b75f5b82 100644 --- a/tools/test-framework/src/types/wallet.rs +++ b/tools/test-framework/src/types/wallet.rs @@ -136,7 +136,7 @@ impl TaggedWallet for MonoTagged { } } -impl<'a, Chain> TaggedWallet for MonoTagged { +impl TaggedWallet for MonoTagged { fn id(&self) -> MonoTagged { self.map_ref(|w| &w.id) } @@ -168,7 +168,7 @@ impl TaggedTestWalletsExt for MonoTagged { } } -impl<'a, Chain> TaggedTestWalletsExt for MonoTagged { +impl TaggedTestWalletsExt for MonoTagged { fn validator(&self) -> MonoTagged { self.map_ref(|w| &w.validator) } diff --git a/tools/test-framework/src/util/array.rs b/tools/test-framework/src/util/array.rs index fc2a2ef88f..df02df2a92 100644 --- a/tools/test-framework/src/util/array.rs +++ b/tools/test-framework/src/util/array.rs @@ -2,7 +2,6 @@ Helpers for manipulating fixed-sized arrays. */ -use core::convert::TryInto; use eyre::eyre; use crate::error::Error; @@ -16,22 +15,6 @@ pub fn try_into_array(list: Vec) -> Result<[T; SIZE], E .map_err(|_| Error::generic(eyre!("vector is not of length {}", SIZE))) } -/** - Converts a dynamic-sized nested vector `Vec>` into a fixed-sized - nested array `[[T; SIZE]; SIZE]`. Fails if the nested vector is not of - `SIZE`x`SIZE` length. -*/ -pub fn try_into_nested_array( - list: Vec>, -) -> Result<[[T; SIZE]; SIZE], Error> { - let list_a = list - .into_iter() - .map(try_into_array) - .collect::, _>>()?; - - try_into_array(list_a) -} - /** Converts a fixed-sized nested array `[[T; SIZE]; SIZE]` into a nested vector `Vec>`. @@ -39,49 +22,3 @@ pub fn try_into_nested_array( pub fn into_nested_vec(array: [[T; SIZE]; SIZE]) -> Vec> { array.map(|array_b| array_b.into()).into() } - -/** - Map the elements in the fixed-sized array `[[T; SIZE]; SIZE]`. -*/ -pub fn map_nested_array( - array: [[T; SIZE]; SIZE], - mapper: impl Fn(T) -> Result, -) -> Result<[[R; SIZE]; SIZE], Error> { - let mapped = into_nested_vec(array) - .into_iter() - .map(|inner| { - inner - .into_iter() - .map(&mapper) - .collect::, _>>() - }) - .collect::, _>>()?; - - try_into_nested_array(mapped) -} - -/** - Asserts that a nested vector `Vec>` has the same dimension - in its inner vectors. -*/ -pub fn assert_same_dimension(size: usize, list: &Vec>) -> Result<(), Error> { - if list.len() != size { - return Err(Error::generic(eyre!( - "expect nested vector to have the dimension {} x {}", - size, - size - ))); - } - - for list_b in list.iter() { - if list_b.len() != size { - return Err(Error::generic(eyre!( - "expect nested vector to have the dimension {} x {}", - size, - size - ))); - } - } - - Ok(()) -} diff --git a/tools/test-framework/src/util/interchain_security.rs b/tools/test-framework/src/util/interchain_security.rs index 035efb3c84..ea66e12f4f 100644 --- a/tools/test-framework/src/util/interchain_security.rs +++ b/tools/test-framework/src/util/interchain_security.rs @@ -1,8 +1,15 @@ -use ibc_relayer::config::ChainConfig; - use crate::chain::config::set_voting_period; use crate::prelude::*; +use ibc_relayer::chain::tracking::TrackedMsgs; +use ibc_relayer::config::ChainConfig; +use ibc_relayer::event::IbcEventWithHeight; +use ibc_relayer_types::applications::ics27_ica::msgs::send_tx::MsgSendTx; +use ibc_relayer_types::applications::ics27_ica::packet_data::InterchainAccountPacketData; +use ibc_relayer_types::signer::Signer; +use ibc_relayer_types::timestamp::Timestamp; +use ibc_relayer_types::tx_msg::Msg; + pub fn update_genesis_for_consumer_chain(genesis: &mut serde_json::Value) -> Result<(), Error> { // Consumer chain doesn't have a gov key. if genesis @@ -32,3 +39,28 @@ pub fn update_relayer_config_for_consumer_chain(config: &mut Config) { } } } + +/// Sends a message containing `InterchainAccountPacketData` from the `Signer` +/// to the `Chain`. +pub fn interchain_send_tx( + chain: &ChainA, + from: &Signer, + connection: &ConnectionId, + msg: InterchainAccountPacketData, + relative_timeout: Timestamp, +) -> Result, Error> { + let msg = MsgSendTx { + owner: from.clone(), + connection_id: connection.clone(), + packet_data: msg, + relative_timeout, + }; + + let msg_any = msg.to_any(); + + let tm = TrackedMsgs::new_static(vec![msg_any], "SendTx"); + + chain + .send_messages_and_wait_commit(tm) + .map_err(Error::relayer) +} diff --git a/tools/test-framework/src/util/mod.rs b/tools/test-framework/src/util/mod.rs index 8fcd82a5dc..7db62f867e 100644 --- a/tools/test-framework/src/util/mod.rs +++ b/tools/test-framework/src/util/mod.rs @@ -10,3 +10,4 @@ pub mod proposal_status; pub mod random; pub mod retry; pub mod suspend; +pub mod two_dim_hash_map; diff --git a/tools/test-framework/src/util/two_dim_hash_map.rs b/tools/test-framework/src/util/two_dim_hash_map.rs new file mode 100644 index 0000000000..678961669f --- /dev/null +++ b/tools/test-framework/src/util/two_dim_hash_map.rs @@ -0,0 +1,113 @@ +use std::collections::{btree_map, BTreeMap}; + +#[derive(Clone, Debug)] +pub struct TwoDimMap { + pub map: BTreeMap>, +} + +impl Default for TwoDimMap { + fn default() -> Self { + TwoDimMap { + map: BTreeMap::new(), + } + } +} + +impl TwoDimMap { + pub fn new() -> Self { + Self::default() + } + pub fn get(&self, (x, y): (usize, usize)) -> Option<&T> { + self.map.get(&x).and_then(|inner| inner.get(&y)) + } + + pub fn insert(&mut self, (x, y): (usize, usize), value: T) -> Option { + if let Some(existing_values) = self.map.get_mut(&x) { + existing_values.insert(y, value) + } else { + let mut new_values = BTreeMap::new(); + new_values.insert(y, value); + self.map.insert(x, new_values); + None + } + } + + pub fn iter(&self) -> Iter { + Iter { + outer_iter: self.map.iter(), + inner_iter: None, + outer_key: 0, + } + } +} + +pub struct Iter<'a, T> { + outer_iter: btree_map::Iter<'a, usize, BTreeMap>, + inner_iter: Option>, + outer_key: usize, +} + +impl<'a, T> Iterator for Iter<'a, T> { + type Item = (usize, usize, &'a T); + + fn next(&mut self) -> Option { + loop { + if let Some(inner_iter) = &mut self.inner_iter { + if let Some((inner_key, inner_value)) = inner_iter.next() { + return Some((self.outer_key, *inner_key, inner_value)); + } + } + + if let Some((outer_key, inner_map)) = self.outer_iter.next() { + self.outer_key = *outer_key; + self.inner_iter = Some(inner_map.iter()); + } else { + return None; + } + } + } +} + +impl From>> for TwoDimMap { + fn from(map: BTreeMap>) -> Self { + Self { map } + } +} + +#[cfg(test)] +mod tests { + use std::collections::BTreeMap; + + use super::*; + + #[test] + fn test_two_dim_hash_map_iterator() { + let mut outer_hashmap = BTreeMap::new(); + let mut inner_hashmap1 = BTreeMap::new(); + let mut inner_hashmap2 = BTreeMap::new(); + let mut inner_hashmap3 = BTreeMap::new(); + + inner_hashmap1.insert(1, "a"); + + inner_hashmap2.insert(2, "c"); + inner_hashmap2.insert(0, "b"); + + inner_hashmap3.insert(1, "d"); + + outer_hashmap.insert(0, inner_hashmap1); + outer_hashmap.insert(1, inner_hashmap2); + outer_hashmap.insert(2, inner_hashmap3); + + let two_dim_hash_map = TwoDimMap::from(outer_hashmap); + let mut two_dim_hash_map_iter = two_dim_hash_map.iter(); + + assert_eq!(two_dim_hash_map_iter.next(), Some((0, 1, &"a"))); + + assert_eq!(two_dim_hash_map_iter.next(), Some((1, 0, &"b"))); + assert_eq!(two_dim_hash_map_iter.next(), Some((1, 2, &"c"))); + + assert_eq!(two_dim_hash_map_iter.next(), Some((2, 1, &"d"))); + + assert_eq!(two_dim_hash_map_iter.next(), None); + } +}