diff --git a/.changelog/config.toml b/.changelog/config.toml index 3ec587408b..e273d4dd86 100644 --- a/.changelog/config.toml +++ b/.changelog/config.toml @@ -72,8 +72,6 @@ entry_indent = 2 # the parent of the `.changelog` folder). [components.all] chain-registry = { name = "Chain Registry", path = "chain-registry" } - ibc = { name = "IBC Modules", path = "modules" } - ibc-proto = { name = "IBC Proto", path = "proto" } ibc-relayer = { name = "Relayer Library", path = "relayer" } ibc-relayer-cli = { name = "Relayer CLI", path = "relayer-cli" } ibc-telemetry = { name = "Telemetry & Metrics", path = "telemetry" } diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 416c404594..0b80d6bbbf 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -17,7 +17,7 @@ ______ ### PR author checklist: - [ ] Added changelog entry, using [`unclog`](https://github.com/informalsystems/unclog). -- [ ] Added tests: integration (for Hermes) or unit/mock tests (for modules). +- [ ] Added (integration or unit) tests. - [ ] Linked to GitHub issue. - [ ] Updated code comments and documentation (e.g., `docs/`). - [ ] Tagged *one* reviewer who will be the one responsible for shepherding this PR. diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 483f1b00b1..60823f529e 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -11,26 +11,6 @@ updates: schedule: interval: "weekly" - - package-ecosystem: "cargo" - directory: "modules" - schedule: - interval: "weekly" - - - package-ecosystem: "cargo" - directory: "proto" - schedule: - interval: "weekly" - -## Disable dependabot for `proto-compiler`. -## Rationale: we maintain the dependencies for proto-compiler -## manually, so that we update the proto-compiler binary -## (and the Cargo.lock file) only when we regenerate -## Rust types from the .proto files. -# - package-ecosystem: "cargo" -# directory: "proto-compiler" -# schedule: -# interval: "weekly" - - package-ecosystem: "cargo" directory: "relayer" schedule: @@ -40,8 +20,3 @@ updates: directory: "relayer-cli" schedule: interval: "weekly" - - - package-ecosystem: "cargo" - directory: "ci/no-std-check" - schedule: - interval: "weekly" diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml index 500c2aff49..1556e3c485 100644 --- a/.github/workflows/integration.yaml +++ b/.github/workflows/integration.yaml @@ -9,8 +9,6 @@ on: - flake.lock - ci/** - e2e/** - - proto/** - - modules/** - relayer/** - relayer-cli/** - relayer-rest/** @@ -26,8 +24,6 @@ on: - flake.lock - ci/** - e2e/** - - proto/** - - modules/** - relayer/** - relayer-cli/** - relayer-rest/** diff --git a/.github/workflows/no-std.yaml b/.github/workflows/no-std.yaml deleted file mode 100644 index d9020d1de1..0000000000 --- a/.github/workflows/no-std.yaml +++ /dev/null @@ -1,47 +0,0 @@ -name: no_std check -on: - pull_request: - paths: - - .github/workflows/no-std.yml - - Cargo.toml - - Cargo.lock - - ci/** - - proto/** - - modules/** - push: - branches: master - paths: - - .github/workflows/no-std.yml - - Cargo.toml - - Cargo.lock - - ci/** - - proto/** - - modules/** - -jobs: - check-no-std-panic-conflict: - name: Check no_std panic conflict - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - override: true - - run: | - cd ci/no-std-check - make check-panic-conflict - - check-substrate: - name: Check no_std substrate support - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - toolchain: nightly - target: wasm32-unknown-unknown - override: true - - run: | - cd ci/no-std-check - make check-substrate diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index d6506276d2..5a38430ccc 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -7,8 +7,6 @@ on: - Cargo.lock - ci/** - e2e/** - - proto/** - - modules/** - relayer/** - relayer-cli/** - relayer-rest/** @@ -22,8 +20,6 @@ on: - Cargo.lock - ci/** - e2e/** - - proto/** - - modules/** - relayer/** - relayer-cli/** - relayer-rest/** diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f6ca79e5c..4f65dd66e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -69,7 +69,7 @@ v1.0.0-rc.2, v1.0.0-rc.1 and v1.0.0-rc.0. - `ibc-telemetry`: 0.19.0 - `ibc-relayer-rest`: 0.19.0 -### Hermes - [`ibc-relayer-cli`](relayer-cli) (v1.0.0) +### Hermes - [`ibc-relayer-cli`](crates/relayer-cli) (v1.0.0) - Release version 1.0.0 of Hermes (`ibc-relayer-cli`) @@ -92,7 +92,7 @@ v1.0.0-rc.2, v1.0.0-rc.1 and v1.0.0-rc.0. ([#2534](https://github.com/informalsystems/ibc-rs/issues/2534)) -### Relayer Library - [`ibc-relayer`](relayer) (v0.19.0) +### Relayer Library - [`ibc-relayer`](crates/relayer) (v0.19.0) - Release version 0.19.0 of `ibc-relayer` @@ -110,7 +110,7 @@ v1.0.0-rc.2, v1.0.0-rc.1 and v1.0.0-rc.0. ([#2548](https://github.com/informalsystems/ibc-rs/issues/2548)) -### Telemetry & Metrics - [`ibc-telemetry`](telemetry) (v0.19.0) +### Telemetry & Metrics - [`ibc-telemetry`](crates/telemetry) (v0.19.0) - Release version 0.18.0 of `ibc-telemetry` @@ -137,7 +137,7 @@ v1.0.0-rc.2, v1.0.0-rc.1 and v1.0.0-rc.0. - Changed telemetry `enabled` to `false` in the default config.toml, to match the default value for this parameter - Changed `misbehaviour` to `false` in the default config.toml, to match the default value for this parameter -### REST API - [`ibc-relayer-rest`](relayer-rest) (v0.19.0) +### REST API - [`ibc-relayer-rest`](crates/relayer-rest) (v0.19.0) - Release version 0.19.0 of `ibc-relayer-rest` @@ -169,7 +169,7 @@ This is the third release candidate for Hermes v1.0.0 🎉 - `ibc-relayer-rest`: 0.18.0 - Bump tendermint-rs dependencies to 0.23.9 -### Hermes - [`ibc-relayer-cli`](relayer-cli) (v1.0.0-rc.2) +### Hermes - [`ibc-relayer-cli`](crates/relayer-cli) (v1.0.0-rc.2) - Release version 1.0.0-rc.2 of Hermes (`ibc-relayer-cli`) @@ -181,7 +181,7 @@ This is the third release candidate for Hermes v1.0.0 🎉 - Release version 0.18.0 of `ibc` -### Relayer Library - [`ibc-relayer`](relayer) (v0.18.0) +### Relayer Library - [`ibc-relayer`](crates/relayer) (v0.18.0) - Release version 0.18.0 of `ibc-relayer` @@ -199,7 +199,7 @@ This is the third release candidate for Hermes v1.0.0 🎉 - Enable connecting to full nodes over IPv6 ([#2380](https://github.com/informalsystems/ibc-rs/issues/2380)) -### Telemetry & Metrics - [`ibc-telemetry`](telemetry) (v0.18.0) +### Telemetry & Metrics - [`ibc-telemetry`](crates/telemetry) (v0.18.0) - Release version 0.18.0 of `ibc-telemetry` @@ -221,7 +221,7 @@ This is the third release candidate for Hermes v1.0.0 🎉 - Fixed a bug with updating of Prometheus metrics in the presence of concurrent relayers ([#2467](https://github.com/informalsystems/ibc-rs/issues/2467)) -### REST API - [`ibc-relayer-rest`](relayer-rest) (v0.18.0) +### REST API - [`ibc-relayer-rest`](crates/relayer-rest) (v0.18.0) - Release version 0.18.0 of `ibc-relayer-rest` @@ -253,7 +253,7 @@ This is the second release candidate for Hermes v1.0.0 🎉 - Bump tendermint-rs dependencies to 0.23.8 ([#2455](https://github.com/informalsystems/ibc-rs/issues/2455)) -### Hermes - [`ibc-relayer-cli`](relayer-cli) (v1.0.0-rc.1) +### Hermes - [`ibc-relayer-cli`](crates/relayer-cli) (v1.0.0-rc.1) #### BREAKING CHANGES @@ -332,7 +332,7 @@ This is the second release candidate for Hermes v1.0.0 🎉 ([#2356](https://github.com/informalsystems/ibc-rs/pull/2356)) -### Relayer Library - [`ibc-relayer`](relayer) (v0.17.0) +### Relayer Library - [`ibc-relayer`](crates/relayer) (v0.17.0) #### BUG FIXES @@ -344,7 +344,7 @@ This is the second release candidate for Hermes v1.0.0 🎉 ([#2444](https://github.com/informalsystems/ibc-rs/issues/2444)) -### Telemetry & Metrics - [`ibc-telemetry`](telemetry) (v0.17.0) +### Telemetry & Metrics - [`ibc-telemetry`](crates/telemetry) (v0.17.0) #### IMPROVEMENTS @@ -379,7 +379,7 @@ The structure of this changelog has therefore changed as well, changes are now grouped first by crate and then by the type of change, eg. feature, bug fix, etc. -### Hermes - [`ibc-relayer-cli`](relayer-cli) (v1.0.0-rc.0) +### Hermes - [`ibc-relayer-cli`](crates/relayer-cli) (v1.0.0-rc.0) #### BREAKING CHANGES @@ -461,7 +461,7 @@ eg. feature, bug fix, etc. ([#2280](https://github.com/informalsystems/ibc-rs/pull/2280)) -### Relayer Library - [`ibc-relayer`](relayer) (v0.16.0) +### Relayer Library - [`ibc-relayer`](crates/relayer) (v0.16.0) #### BUG FIXES @@ -494,7 +494,7 @@ eg. feature, bug fix, etc. - Reduce relaying delay when some account mismatch errors occur during Tx simulation ([#2249](https://github.com/informalsystems/ibc-rs/issues/2249)) -### Telemetry & Metrics - [`ibc-telemetry`](telemetry) (v0.16.0) +### Telemetry & Metrics - [`ibc-telemetry`](crates/telemetry) (v0.16.0) #### FEATURES @@ -521,7 +521,7 @@ for better observability of the relayer's operations. ([#2114](https://github.com/informalsystems/ibc-rs/issues/2114)) - fix connection id mix-up in connection acknowledgement processing ([#2178](https://github.com/informalsystems/ibc-rs/issues/2178)) -- [Relayer Library](relayer) +- [Relayer Library](crates/relayer) - Fix a bug where connection and channel handshakes would fail with non-batching transactions ([#1971](https://github.com/informalsystems/ibc-rs/issues/1971)) - Fixed client expiry computation to avoid using local time. @@ -532,7 +532,7 @@ for better observability of the relayer's operations. - General - Replaced gaia v5 with v7 in E2E tests. ([#1986](https://github.com/informalsystems/ibc-rs/issues/1986)) -- [Relayer Library](relayer) +- [Relayer Library](crates/relayer) - Add six new metrics: `wallet_balance`, `ws_events`, `ws_reconnect`, `tx_latency_submitted`, `tx_latency_confirmed`, `msg_num` ([#2112](https://github.com/informalsystems/ibc-rs/issues/2112)) @@ -542,7 +542,7 @@ for better observability of the relayer's operations. - [IBC Modules](modules) - Remove object capabilities from the modules ([#2159](https://github.com/informalsystems/ibc-rs/issues/2159)) -- [Relayer Library](relayer) +- [Relayer Library](crates/relayer) - Ensure `max_msg_num` is between 1 and 100 with a default of 30 ([#1971](https://github.com/informalsystems/ibc-rs/issues/1971)) - Fixed misleading error message leaking from the misbehavior detection task. @@ -561,7 +561,7 @@ some queries would fail if they reach a full node after a new block is committed ### BUG FIXES -- [Relayer Library](relayer) +- [Relayer Library](crates/relayer) - Fixed query for application status when application state lags behind blockchain state. ([#1970](https://github.com/informalsystems/ibc-rs/issues/1970)) @@ -601,7 +601,7 @@ Please [refer to the guide][create-channel] for more information. ([#2035](https://github.com/informalsystems/ibc-rs/issues/2035)) - Use the version in the message when handling a MsgConnOpenInit ([#2062](https://github.com/informalsystems/ibc-rs/issues/2062)) -- [Relayer Library](relayer) +- [Relayer Library](crates/relayer) - Fix the connection delay logic to use the timestamp of the host block when the client update header was installed. ([#1772](https://github.com/informalsystems/ibc-rs/issues/1772)) - Fixed Hermes retrying mechanism not regenerating operational data for messages ([#1792](https://github.com/informalsystems/ibc-rs/pull/1951)) @@ -611,7 +611,7 @@ Please [refer to the guide][create-channel] for more information. string ([#2075](https://github.com/informalsystems/ibc-rs/issues/2075)) - Fixed target height used in misbehavior detection. ([#2097](https://github.com/informalsystems/ibc-rs/issues/2097)) -- [Relayer CLI](relayer-cli) +- [Relayer CLI](crates/relayer-cli) - Skip waiting for confirmation events on tx raw upgrade-chain ([#1288](https://github.com/informalsystems/ibc-rs/issues/1288)) - Apply client options specified with the `create client` command. @@ -619,7 +619,7 @@ Please [refer to the guide][create-channel] for more information. ### FEATURES -- [Relayer Library](relayer) +- [Relayer Library](crates/relayer) - Add a metric for query cache hits ([#2036](https://github.com/informalsystems/ibc-rs/issues/2036)) @@ -633,7 +633,7 @@ Please [refer to the guide][create-channel] for more information. - [IBC Modules](modules) - Complete ICS26 implementation ([#1758](https://github.com/informalsystems/ibc-rs/issues/1758)) - Improve `ChannelId` validation. ([#2068](https://github.com/informalsystems/ibc-rs/issues/2068)) -- [Relayer CLI](relayer-cli) +- [Relayer CLI](crates/relayer-cli) - Change `create channel` CLI command such that it is more difficult to create clients / connections using it ([#1421](https://github.com/informalsystems/ibc-rs/issues/1421)) - Added `query packet pending` command to list outstanding packet @@ -703,7 +703,7 @@ This information can also be found in the [Hermes guide][guide-ica]. ### BUG FIXES -- [Relayer Library](relayer) +- [Relayer Library](crates/relayer) - Fixed relayer behavior on ordered channels ([#1835](https://github.com/informalsystems/ibc-rs/issues/1835)) - Do not spawn packet worker on chan open ack/confirm events @@ -723,7 +723,7 @@ This information can also be found in the [Hermes guide][guide-ica]. - Derive `Serialize` and `Deserialize` for `ibc-proto::ibc::core` and `ibc_proto::ibc::applications` structs, and switch to Google's Protobuf standard types instead of Prost's types. ([#1988](https://github.com/informalsystems/ibc-rs/issues/1988)) -- [Relayer Library](relayer) +- [Relayer Library](crates/relayer) - Added caching layer for hermes start command ([#1908](https://github.com/informalsystems/ibc-rs/issues/1908)) - Add support for wildcards in port and channel identifiers in the packet filter configuration, @@ -735,11 +735,11 @@ This information can also be found in the [Hermes guide][guide-ica]. - [IBC Modules](modules) - Refactored channels events in ICS 04 module ([#718](https://github.com/informalsystems/ibc-rs/issues/718)) -- [Integration Test Framework](relayer-cli) +- [Integration Test Framework](crates/relayer-cli) - Split out test framework as new crate `ibc-test-framework` from `ibc-integration-test`. ([#1961](https://github.com/informalsystems/ibc-rs/pull/1961)) -- [Relayer Library](relayer) +- [Relayer Library](crates/relayer) - Add documentation for the caching layer implemented in ([#1908](https://github.com/informalsystems/ibc-rs/issues/1908)) -- [Relayer CLI](relayer-cli) +- [Relayer CLI](crates/relayer-cli) - Print packet data on one line ([#1559](https://github.com/informalsystems/ibc-rs/issues/1559)) ## v0.12.0 @@ -768,7 +768,7 @@ has been added for clearing packets in both direction on a given channel. in Tendermint errors ([#1706](https://github.com/informalsystems/ibc-rs/issues/1706)) - IBC handlers now retrieve the host timestamp from the latest host consensus state ([#1770](https://github.com/informalsystems/ibc-rs/issues/1770)) -- [Relayer Library](relayer) +- [Relayer Library](crates/relayer) - Handle non-standard ports in channel handshake ([#1837](https://github.com/informalsystems/ibc-rs/issues/1837)) - Fix duplicate SendPacket events emitted by EndBlock @@ -778,7 +778,7 @@ has been added for clearing packets in both direction on a given channel. [#1837](https://github.com/informalsystems/ibc-rs/issues/1837)) - Fixed bug where Hermes cleared packets at startup, despite `clear_on_start = false` ([#1872](https://github.com/informalsystems/ibc-rs/issues/1872)) -- [Relayer CLI](relayer-cli) +- [Relayer CLI](crates/relayer-cli) - Disable reloading of configuration upon receiving a SIGHUP signal ([#1885](https://github.com/informalsystems/ibc-rs/issues/1885)) @@ -787,7 +787,7 @@ has been added for clearing packets in both direction on a given channel. - General - Upgrade protos and compatibility to IBC v3.0.0-rc.0 and Cosmos SDK v0.45.1 ([#1797](https://github.com/informalsystems/ibc-rs/issues/1797)) -- [Relayer CLI](relayer-cli) +- [Relayer CLI](crates/relayer-cli) - Allow overriding the tracing filter with `RUST_LOG` environment variable ([#1895](https://github.com/informalsystems/ibc-rs/issues/1895)) @@ -798,12 +798,12 @@ has been added for clearing packets in both direction on a given channel. ([#1706](https://github.com/informalsystems/ibc-rs/issues/1706)) - Define CapabilityReader and CapabilityKeeper traits ([#1769](https://github.com/informalsystems/ibc-rs/issues/1769)) -- [Relayer Library](relayer) +- [Relayer Library](crates/relayer) - Add two more health checks: tx indexing enabled and historical entries > 0 ([#1388](https://github.com/informalsystems/ibc-rs/issues/1388)) - Changed `ConnectionEnd::versions` method to be non-allocating by having it return a `&[Version]` instead of `Vec` ([#1880](https://github.com/informalsystems/ibc-rs/pull/1880)) -- [Relayer CLI](relayer-cli) +- [Relayer CLI](crates/relayer-cli) - Added `clear packets` command, combining the effects of `tx raw packet-recv` and `tx raw packet-ack` ([#1834](https://github.com/informalsystems/ibc-rs/pull/1834)) @@ -815,13 +815,13 @@ This release mainly adds support for channel events originating from Tendermint ### BUG FIXES -- [Relayer CLI](relayer-cli) +- [Relayer CLI](crates/relayer-cli) - Do not require a config file to be present for the `completions` command. ([#1822](https://github.com/informalsystems/ibc-rs/pull/1822)) ### IMPROVEMENTS -- [Relayer Library](relayer) +- [Relayer Library](crates/relayer) - Increased tx confirmation timeout to 300s to prevent aggressive tx resubmission ([#1663](https://github.com/informalsystems/ibc-rs/issues/1663)) - Handle channel events originating from Tendermint ABCI's BeginBlock and EndBlock methods @@ -873,7 +873,7 @@ Before running Hermes v0.11.0, make sure you remove the `mode.packets.filter` op - General - Update MSRV to Rust 1.58 ([#1765](https://github.com/informalsystems/ibc-rs/issues/1765)) - Update tendermint-rs dependencies to 0.23.5 ([#1767](https://github.com/informalsystems/ibc-rs/issues/1767)) -- [Relayer Library](relayer) +- [Relayer Library](crates/relayer) - Added a `denom` member to `upgrade_chain::UpgradePlanOptions` ([#1662](https://github.com/informalsystems/ibc-rs/issues/1662)) - [IBC Modules](modules) @@ -903,14 +903,14 @@ Before running Hermes v0.11.0, make sure you remove the `mode.packets.filter` op ([#1760](https://github.com/informalsystems/ibc-rs/issues/1760)) - Disallow empty `CommitmentPrefix` and `CommitmentProofBytes` ([#1761](https://github.com/informalsystems/ibc-rs/issues/1761)) -- [Relayer Library](relayer) +- [Relayer Library](crates/relayer) - Allow `ChainEndpoint` implementations to fetch any types of clients and consensus states ([#1481](https://github.com/informalsystems/ibc-rs/issues/1481)) - More structural logging in relayer, using tracing spans and key-value pairs. ([#1491](https://github.com/informalsystems/ibc-rs/pull/1491)) - Improved documention w.r.t. keys for Ethermint-based chains ([#1785](https://github.com/informalsystems/ibc-rs/issues/1785)) -- [Relayer CLI](relayer-cli) +- [Relayer CLI](crates/relayer-cli) - Add custom options to the `create client` command. ([#836](https://github.com/informalsystems/ibc-rs/issues/836)) - Make the deposit denomination configurable in `tx raw upgrade-chain` via a new `--denom` flag. @@ -951,11 +951,11 @@ The relayer now also supports dynamic versions in channel open handshake (which ([#1665](https://github.com/informalsystems/ibc-rs/pull/1665)): - `Timestamp::from_datetime`; use `From` - `Timestamp::as_datetime`, superseded by `Timestamp::into_datetime` -- [Relayer Library](relayer) +- [Relayer Library](crates/relayer) - Improve spawning of supervisor worker tasks ([#1656](https://github.com/informalsystems/ibc-rs/issues/1656)) - The `Supervisor` struct is removed. - Supervisor is now spawned using the `spawn_supervisor` function. -- [Relayer CLI](relayer-cli) +- [Relayer CLI](crates/relayer-cli) - Update to abscissa framework version 0.6.0-beta.1, adding support for `--help` flags in subcommands and improving help and usage printouts. The `--version` option of the `create channel` subcommand has been renamed @@ -976,7 +976,7 @@ The relayer now also supports dynamic versions in channel open handshake (which ([#1697](https://github.com/informalsystems/ibc-rs/issues/1697)) - Fix conversion to Protocol Buffers of `ClientState`'s `frozen_height` field. ([#1710](https://github.com/informalsystems/ibc-rs/issues/1710)) -- [Relayer Library](relayer) +- [Relayer Library](crates/relayer) - Handle expired client errors in workers ([#1543](https://github.com/informalsystems/ibc-rs/issues/1543)) - Perform `execute_schedule` after handling packet commands in packet worker ([#1715](https://github.com/informalsystems/ibc-rs/issues/1715)) - Do not spawn detect misbehavior task if it is disabled in config [#1750](https://github.com/informalsystems/ibc-rs/issues/1750) @@ -992,7 +992,7 @@ The relayer now also supports dynamic versions in channel open handshake (which - [IBC Modules](modules) - Implement proof verification for Tendermint client (ICS07). ([#1583](https://github.com/informalsystems/ibc-rs/pull/1583)) -- [Relayer Library](relayer) +- [Relayer Library](crates/relayer) - Added a recovery mechanism to automatically retry or drop tx upon account sequence mismatch errors ([#1264](https://github.com/informalsystems/ibc-rs/issues/1264)) - Support dynamic versions in channel open handshake & enable full support for @@ -1010,7 +1010,7 @@ The relayer now also supports dynamic versions in channel open handshake (which ([#1665](https://github.com/informalsystems/ibc-rs/pull/1665)): - `Timestamp::nanoseconds` replaces `Timestamp::as_nanoseconds` - `Timestamp::into_datetime` substitutes `Timestamp::as_datetime` -- [Relayer CLI](relayer-cli) +- [Relayer CLI](crates/relayer-cli) - Improve performance of standalone commands by starting the event monitor on-demand ([#1063](https://github.com/informalsystems/ibc-rs/issues/1063)) - Increase the default for `max_gas` from `300_000` to `400_000` @@ -1085,7 +1085,7 @@ then on top of the changes above, `mode.connections.enabled` and `mode.channels. ([#1408](https://github.com/informalsystems/ibc-rs/issues/1408)) - Optimize the WS client to subscribe to IBC events only (instead of all Tx events) ([#1534](https://github.com/informalsystems/ibc-rs/issues/1534)) -- [Relayer Library](relayer) +- [Relayer Library](crates/relayer) - Allow for more granular control of relaying modes. The `mode` configuration section replaces the `strategy` option. ([#1518](https://github.com/informalsystems/ibc-rs/issues/1518)) @@ -1099,11 +1099,11 @@ then on top of the changes above, `mode.connections.enabled` and `mode.channels. - [IBC Modules](modules) - Derive `PartialEq` and `Eq` on `IbcEvent` and inner types ([#1546](https://github.com/informalsystems/ibc-rs/issues/1546)) -- [Relayer Library](relayer) +- [Relayer Library](crates/relayer) - The relayer will now avoid submitting a tx after the simulation failed (in all but one special case) to avoid wasting fees unnecessarily ([#1479](https://github.com/informalsystems/ibc-rs/issues/1479)) -- [Relayer CLI](relayer-cli) +- [Relayer CLI](crates/relayer-cli) - Output errors on a single line if ANSI output is disabled ([#1529](https://github.com/informalsystems/ibc-rs/issues/1529)) - Compute fee amount using big integers to prevent overflow @@ -1150,7 +1150,7 @@ For Cosmos-SDK chains a good approximation is `timeout_propose` + `timeout_commi ([#1436](https://github.com/informalsystems/ibc-rs/issues/1436)) - Implement `FromStr` to enable string-encoded paths to be converted into Path identifiers ([#1460](https://github.com/informalsystems/ibc-rs/issues/1460)) -- [Relayer Library](relayer) +- [Relayer Library](crates/relayer) - Improve performance of misbehaviour checks triggered by an `UpdateClient` event ([#1417](https://github.com/informalsystems/ibc-rs/issues/1417)) @@ -1188,7 +1188,7 @@ ABCI's `BeginBlock` and `EndBlock` methods ([#1231](https://github.com/informals - [IBC Modules](modules) - Add ICS07 verification functionality by using `tendermint-light-client` ([#1214](https://github.com/informalsystems/ibc-rs/issues/1214)) -- [Relayer Library](relayer) +- [Relayer Library](crates/relayer) - Add a `default_gas` setting to be used for submitting a tx when tx simulation fails ([#1457](https://github.com/informalsystems/ibc-rs/issues/1457)) - Update compatibility check for IBC-Go dependency @@ -1196,7 +1196,7 @@ ABCI's `BeginBlock` and `EndBlock` methods ([#1231](https://github.com/informals ### IMPROVEMENTS -- [Relayer Library](relayer) +- [Relayer Library](crates/relayer) - Handle SendPacket events originating from Tendermint ABCI's BeginBlock and EndBlock methods ([#1231](https://github.com/informalsystems/ibc-rs/issues/1231)) - Improve error message when `create client` fails and add a health @@ -1213,7 +1213,7 @@ It also improves the handling of account sequence numbers ### BUG FIXES -- [Relayer Library](relayer) +- [Relayer Library](crates/relayer) - Fix a bug introduced in Hermes v0.7.0 where tx simulations would fail on chains based on Cosmos SDK 0.42. This would cause Hermes to use the max gas specified in the config when submitted the tx, leading to high fees. @@ -1224,7 +1224,7 @@ It also improves the handling of account sequence numbers ### IMPROVEMENTS -- [Relayer Library](relayer) +- [Relayer Library](crates/relayer) - Set default trusting period to be 2/3 of unbonding period for Cosmos chains ([#1392](https://github.com/informalsystems/ibc-rs/issues/1392)) @@ -1319,11 +1319,11 @@ Additionnally, Hermes now includes a REST server which exposes the relayer's int - General - Update CI to test with gaiad v5.0.5 ([#1175]) -- [ibc-relayer-cli](relayer-cli) +- [ibc-relayer-cli](crates/relayer-cli) - Add `keys delete` CLI command ([#1065]) - Add `--legacy | -l` flag to support upgrades for chains built with Cosmos SDK < v0.43.0 ([#1287]) -- [ibc-relayer](relayer) +- [ibc-relayer](crates/relayer) - Expose the Hermes config and internal state over a REST API ([#843]) - Spawn packet workers only when there are outstanding packets or acknowledgements to relay ([#901]) - Upgrade to Cosmos SDK proto (v0.43.0) & ibc-go proto (v1.0.0) ([#948]) @@ -1340,10 +1340,10 @@ Additionnally, Hermes now includes a REST server which exposes the relayer's int - General - Update Modelator to 0.2.0 ([#1249]) -- [ibc-relayer-cli](relayer-cli) +- [ibc-relayer-cli](crates/relayer-cli) - Add optional destination chain and `--verbose` options for `query channels` CLI ([#1132]) -- [ibc-relayer](relayer) +- [ibc-relayer](crates/relayer) - Improve support for Interchain Accounts (ICS 027) ([#1191]) - Improve performance and reliability of the relayer by asynchronously waiting for tx confirmations ([#1124], [#1265]) diff --git a/Cargo.lock b/Cargo.lock index 038134338d..52fb747a71 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -602,17 +602,6 @@ dependencies = [ "crossbeam-utils 0.8.11", ] -[[package]] -name = "crossbeam-deque" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" -dependencies = [ - "cfg-if 1.0.0", - "crossbeam-epoch", - "crossbeam-utils 0.8.11", -] - [[package]] name = "crossbeam-epoch" version = "0.9.10" @@ -783,15 +772,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "directories" -version = "4.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f51c5d4ddabd36886dd3e1438cb358cdcb0d7c499cb99cb4ac2e38e18b5cb210" -dependencies = [ - "dirs-sys", -] - [[package]] name = "dirs-next" version = "2.0.0" @@ -802,17 +782,6 @@ dependencies = [ "dirs-sys-next", ] -[[package]] -name = "dirs-sys" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - [[package]] name = "dirs-sys-next" version = "0.1.2" @@ -824,12 +793,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "dyn-clone" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f94fa09c2aeea5b8839e414b7b841bf429fd25b9c522116ac97ee87856d88b2" - [[package]] name = "ecdsa" version = "0.14.4" @@ -917,15 +880,6 @@ dependencies = [ "termcolor", ] -[[package]] -name = "erased-serde" -version = "0.3.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54558e0ba96fbe24280072642eceb9d7d442e32c7ec0ea9e7ecd7b4ea2cf4e11" -dependencies = [ - "serde", -] - [[package]] name = "error-chain" version = "0.12.4" @@ -1460,16 +1414,14 @@ dependencies = [ [[package]] name = "ibc" version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7722640fa8af358a2875080301a76cb7642cd9f1e7c2827692d1087f973634ca" dependencies = [ "bytes", "derive_more", - "dyn-clone", - "env_logger", - "erased-serde", "flex-error", "ibc-proto", "ics23", - "modelator", "num-traits", "primitive-types", "prost", @@ -1482,12 +1434,9 @@ dependencies = [ "tendermint", "tendermint-light-client-verifier", "tendermint-proto", - "tendermint-rpc", "tendermint-testgen", - "test-log", "time", "tracing", - "tracing-subscriber", "uint", ] @@ -1532,14 +1481,13 @@ dependencies = [ [[package]] name = "ibc-proto" version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf27ba26c12fa0e270a32f8e54a9d9768e19d0f2e6f36b83a1f274f7fa1c2755" dependencies = [ "base64", "bytes", - "flex-error", "prost", - "schemars", "serde", - "subtle-encoding", "tendermint-proto", "tonic", ] @@ -1921,12 +1869,6 @@ dependencies = [ "unicase", ] -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - [[package]] name = "miniz_oxide" version = "0.5.3" @@ -1948,31 +1890,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "modelator" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "698fbc4b1fd2af323ed1711664a873b332faa4dc740e0f810f40210573ba36fd" -dependencies = [ - "clap", - "clap_complete", - "directories", - "hex", - "lazy_static", - "nom", - "once_cell", - "rayon", - "regex", - "serde", - "serde_json", - "sha2 0.10.5", - "tempfile", - "thiserror", - "tracing", - "tracing-subscriber", - "ureq", -] - [[package]] name = "moka" version = "0.9.4" @@ -2031,16 +1948,6 @@ dependencies = [ "tempfile", ] -[[package]] -name = "nom" -version = "7.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" -dependencies = [ - "memchr", - "minimal-lexical", -] - [[package]] name = "num-bigint" version = "0.4.3" @@ -2544,30 +2451,6 @@ dependencies = [ "bitflags", ] -[[package]] -name = "rayon" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" -dependencies = [ - "autocfg", - "crossbeam-deque", - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" -dependencies = [ - "crossbeam-channel 0.5.6", - "crossbeam-deque", - "crossbeam-utils 0.8.11", - "num_cpus", -] - [[package]] name = "redox_syscall" version = "0.2.16" @@ -2894,30 +2777,6 @@ dependencies = [ "parking_lot", ] -[[package]] -name = "schemars" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1847b767a3d62d95cbf3d8a9f0e421cf57a0d8aa4f411d4b16525afb0284d4ed" -dependencies = [ - "dyn-clone", - "schemars_derive", - "serde", - "serde_json", -] - -[[package]] -name = "schemars_derive" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af4d7e1b012cb3d9129567661a63755ea4b8a7386d339dc945ae187e403c6743" -dependencies = [ - "proc-macro2", - "quote", - "serde_derive_internals", - "syn", -] - [[package]] name = "scopeguard" version = "1.1.0" @@ -3059,17 +2918,6 @@ dependencies = [ "syn", ] -[[package]] -name = "serde_derive_internals" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "serde_json" version = "1.0.85" diff --git a/Cargo.toml b/Cargo.toml index 8abf83f62a..cf50f6d2d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,22 +3,15 @@ resolver = "2" members = [ - "ibc-chain-registry", - "modules", - "relayer", - "relayer-cli", - "relayer-rest", - "telemetry", - "proto", + "crates/ibc-chain-registry", + "crates/relayer", + "crates/relayer-cli", + "crates/relayer-rest", + "crates/telemetry", "tools/integration-test", "tools/test-framework", ] -exclude = [ - "ci/no-std-check", - "proto-compiler" -] - # [patch.crates-io] # tendermint = { git = "https://github.com/informalsystems/tendermint-rs", branch = "v0.23.x" } # tendermint-rpc = { git = "https://github.com/informalsystems/tendermint-rs", branch = "v0.23.x" } diff --git a/README.md b/README.md index 7235ed5214..a7607ab467 100644 --- a/README.md +++ b/README.md @@ -10,19 +10,14 @@ Rust implementation of the Inter-Blockchain Communication (IBC) protocol. -This project comprises primarily seven crates: +This project comprises primarily five crates: -- The [`ibc`][ibc-crate-link] crate defines the main data structures and - on-chain logic for the IBC protocol. - The [`ibc-chain-registry`][ibc-chain-registry-crate-link] provides functions to fetch data from the [chain registry](https://github.com/cosmos/chain-registry) and automatically generate chain configuration for `hermes`. - The [`ibc-relayer`][relayer-crate-link] crate provides an implementation of an IBC relayer, as a _library_. - The [`ibc-relayer-cli`][relayer-cli-crate-link] crate is a CLI (a wrapper over the `ibc-relayer` library), comprising the [`hermes`](https://hermes.informal.systems) binary. -- The [`ibc-proto`][ibc-proto-crate-link] crate is a library with Rust types generated from .proto definitions - necessary for interacting with [Cosmos SDK](https://github.com/cosmos/cosmos-sdk/tree/master/proto/cosmos) - and its [IBC structs](https://github.com/cosmos/ibc-go/tree/main/proto/ibc). - The [`ibc-telemetry`][ibc-telemetry-crate-link] crate is a library for use in the `hermes` CLI, for gathering telemetry data and exposing that in a Prometheus endpoint. - The [`ibc-test-framework`][ibc-test-framework-crate-link] crate provides the infrastructure and framework for writing end-to-end (E2E) tests that include the spawning of the relayer together with Cosmos full nodes. @@ -34,14 +29,12 @@ Includes [TLA+ specifications](docs/spec). | Crate name | Type | Version | Docs | |:-------------:|:------:|:-------------:|:-----:| -| [ibc](./modules) | lib | [![IBC Crate][ibc-crate-image]][ibc-crate-link] | [![IBC Docs][ibc-docs-image]][ibc-docs-link] | -| [ibc-relayer](./relayer) | lib | [![IBC Relayer Crate][relayer-crate-image]][relayer-crate-link] | [![IBC Relayer Docs][relayer-docs-image]][relayer-docs-link] | -| [ibc-relayer-cli](./relayer-cli) | bin: [hermes](relayer-cli/) | [![IBC Relayer CLI Crate][relayer-cli-crate-image]][relayer-cli-crate-link] | [![IBC Relayer CLI Docs][relayer-cli-docs-image]][relayer-cli-docs-link] | -| [ibc-relayer-rest](./relayer-rest) | lib | [![IBC Relayer REST Crate][relayer-rest-crate-image]][relayer-rest-crate-link] | [![IBC Relayer REST Docs][relayer-rest-docs-image]][relayer-rest-docs-link] | -| [ibc-proto](./proto) | lib | [![IBC Proto Crate][ibc-proto-crate-image]][ibc-proto-crate-link] | [![IBC Proto Docs][ibc-proto-docs-image]][ibc-proto-docs-link] | -| [ibc-telemetry](./telemetry) | lib | [![IBC Telemetry Crate][ibc-telemetry-crate-image]][ibc-telemetry-crate-link] | [![IBC Telemetry Docs][ibc-telemetry-docs-image]][ibc-telemetry-docs-link] | -| [ibc-test-framework](./tools/test-framework) | lib | [![IBC Test Framework Crate][ibc-test-framework-crate-image]][ibc-test-framework-crate-link] | [![IBC Test Framework Docs][ibc-test-framework-docs-image]][ibc-test-framework-docs-link] | -| [ibc-chain-registry](./ibc-chain-registry) | lib | [![Chain Registry Crate][ibc-chain-registry-crate-image]][ibc-chain-registry-crate-link] | [![Chain Registry Docs][ibc-chain-registry-docs-image]][ibc-chain-registry-docs-link] | +| [ibc-relayer](crates/relayer) | lib | [![IBC Relayer Crate][relayer-crate-image]][relayer-crate-link] | [![IBC Relayer Docs][relayer-docs-image]][relayer-docs-link] | +| [ibc-relayer-cli](crates/relayer-cli) | bin: [hermes](crates/relayer-cli/) | [![IBC Relayer CLI Crate][relayer-cli-crate-image]][relayer-cli-crate-link] | [![IBC Relayer CLI Docs][relayer-cli-docs-image]][relayer-cli-docs-link] | +| [ibc-relayer-rest](crates/relayer-rest) | lib | [![IBC Relayer REST Crate][relayer-rest-crate-image]][relayer-rest-crate-link] | [![IBC Relayer REST Docs][relayer-rest-docs-image]][relayer-rest-docs-link] | +| [ibc-telemetry](crates/telemetry) | lib | [![IBC Telemetry Crate][ibc-telemetry-crate-image]][ibc-telemetry-crate-link] | [![IBC Telemetry Docs][ibc-telemetry-docs-image]][ibc-telemetry-docs-link] | +| [ibc-test-framework](tools/test-framework) | lib | [![IBC Test Framework Crate][ibc-test-framework-crate-image]][ibc-test-framework-crate-link] | [![IBC Test Framework Docs][ibc-test-framework-docs-image]][ibc-test-framework-docs-link] | +| [ibc-chain-registry](crates/ibc-chain-registry) | lib | [![Chain Registry Crate][ibc-chain-registry-crate-image]][ibc-chain-registry-crate-link] | [![Chain Registry Docs][ibc-chain-registry-docs-image]][ibc-chain-registry-docs-link] | @@ -59,8 +52,8 @@ The relayer CLI binary, called `hermes`, has a comprehensive guide at IBC is specified in English in the [cosmos/ibc repo](https://github.com/cosmos/ibc). Any protocol changes or clarifications should be contributed there. -This repo contains the TLA+ specification and Rust implementation for the IBC -modules and relayer. If you're interested in contributing, please comment on an issue or open a new one! +This repo contains the TLA+ specification and Rust implementation for the IBC relayer. If you're interested in +contributing, please comment on an issue or open a new one! See also [CONTRIBUTING.md](./CONTRIBUTING.md). @@ -87,10 +80,6 @@ Licensed under the Apache License, Version 2.0 (the "License"); you may not use Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -[ibc-crate-image]: https://img.shields.io/crates/v/ibc.svg -[ibc-crate-link]: https://crates.io/crates/ibc -[ibc-docs-image]: https://docs.rs/ibc/badge.svg -[ibc-docs-link]: https://docs.rs/ibc/ [relayer-crate-image]: https://img.shields.io/crates/v/ibc-relayer.svg [relayer-crate-link]: https://crates.io/crates/ibc-relayer [relayer-docs-image]: https://docs.rs/ibc-relayer/badge.svg @@ -103,10 +92,6 @@ Unless required by applicable law or agreed to in writing, software distributed [relayer-rest-crate-link]: https://crates.io/crates/ibc-relayer-rest [relayer-rest-docs-image]: https://docs.rs/ibc-relayer-rest/badge.svg [relayer-rest-docs-link]: https://docs.rs/ibc-relayer-rest/ -[ibc-proto-crate-image]: https://img.shields.io/crates/v/ibc-proto.svg -[ibc-proto-crate-link]: https://crates.io/crates/ibc-proto -[ibc-proto-docs-image]: https://docs.rs/ibc-proto/badge.svg -[ibc-proto-docs-link]: https://docs.rs/ibc-proto/ [ibc-telemetry-crate-image]: https://img.shields.io/crates/v/ibc-telemetry.svg [ibc-telemetry-crate-link]: https://crates.io/crates/ibc-telemetry [ibc-telemetry-docs-image]: https://docs.rs/ibc-telemetry/badge.svg diff --git a/ci/no-std-check/.gitignore b/ci/no-std-check/.gitignore deleted file mode 100644 index 2f7896d1d1..0000000000 --- a/ci/no-std-check/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target/ diff --git a/ci/no-std-check/Cargo.lock b/ci/no-std-check/Cargo.lock deleted file mode 100644 index 583c70a256..0000000000 --- a/ci/no-std-check/Cargo.lock +++ /dev/null @@ -1,2590 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "Inflector" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" -dependencies = [ - "lazy_static", - "regex", -] - -[[package]] -name = "addr2line" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "ahash" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" -dependencies = [ - "getrandom 0.2.7", - "once_cell", - "version_check", -] - -[[package]] -name = "aho-corasick" -version = "0.7.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" -dependencies = [ - "memchr", -] - -[[package]] -name = "android_system_properties" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7ed72e1635e121ca3e79420540282af22da58be50de153d36f81ddc6b83aa9e" -dependencies = [ - "libc", -] - -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - -[[package]] -name = "anyhow" -version = "1.0.62" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1485d4d2cc45e7b201ee3767015c96faa5904387c9d87c6efdd0fb511f12d305" - -[[package]] -name = "arrayref" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" - -[[package]] -name = "arrayvec" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" -dependencies = [ - "nodrop", -] - -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - -[[package]] -name = "arrayvec" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" - -[[package]] -name = "async-trait" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76464446b8bc32758d7e88ee1a804d9914cd9b1cb264c029899680b0be29826f" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[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.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "base58" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" - -[[package]] -name = "base64" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitvec" -version = "0.20.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7774144344a4faa177370406a7ff5f1da24303817368584c6206c8303eb07848" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - -[[package]] -name = "blake2-rfc" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" -dependencies = [ - "arrayvec 0.4.12", - "constant_time_eq", -] - -[[package]] -name = "block-buffer" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -dependencies = [ - "block-padding", - "byte-tools", - "byteorder", - "generic-array 0.12.4", -] - -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "generic-array 0.14.6", -] - -[[package]] -name = "block-buffer" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" -dependencies = [ - "generic-array 0.14.6", -] - -[[package]] -name = "block-padding" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" -dependencies = [ - "byte-tools", -] - -[[package]] -name = "bumpalo" -version = "3.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" - -[[package]] -name = "byte-slice-cast" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87c5fdd0166095e1d463fc6cc01aa8ce547ad77a4e84d42eb6762b084e28067e" - -[[package]] -name = "byte-tools" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "bytes" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" - -[[package]] -name = "cc" -version = "1.0.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" -dependencies = [ - "iana-time-zone", - "num-integer", - "num-traits", - "winapi", -] - -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - -[[package]] -name = "core-foundation-sys" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" - -[[package]] -name = "cpufeatures" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1079fb8528d9f9c888b1e8aa651e6e079ade467323d58f75faf1d30b1808f540" -dependencies = [ - "libc", -] - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array 0.14.6", - "typenum", -] - -[[package]] -name = "crypto-mac" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" -dependencies = [ - "generic-array 0.14.6", - "subtle", -] - -[[package]] -name = "crypto-mac" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" -dependencies = [ - "generic-array 0.14.6", - "subtle", -] - -[[package]] -name = "curve25519-dalek" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a9b85542f99a2dfa2a1b8e192662741c9859a846b296bef1c92ef9b58b5a216" -dependencies = [ - "byteorder", - "digest 0.8.1", - "rand_core 0.5.1", - "subtle", - "zeroize", -] - -[[package]] -name = "curve25519-dalek" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" -dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.5.1", - "subtle", - "zeroize", -] - -[[package]] -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "digest" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" -dependencies = [ - "generic-array 0.12.4", -] - -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array 0.14.6", -] - -[[package]] -name = "digest" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" -dependencies = [ - "block-buffer 0.10.2", - "crypto-common", -] - -[[package]] -name = "downcast-rs" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" - -[[package]] -name = "dyn-clonable" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e9232f0e607a262ceb9bd5141a3dfb3e4db6994b31989bbfd845878cba59fd4" -dependencies = [ - "dyn-clonable-impl", - "dyn-clone", -] - -[[package]] -name = "dyn-clonable-impl" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "558e40ea573c374cf53507fd240b7ee2f5477df7cfebdb97323ec61c719399c5" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "dyn-clone" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f94fa09c2aeea5b8839e414b7b841bf429fd25b9c522116ac97ee87856d88b2" - -[[package]] -name = "ed25519" -version = "1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9c280362032ea4203659fc489832d0204ef09f247a0506f170dafcac08c369" -dependencies = [ - "signature", -] - -[[package]] -name = "ed25519-dalek" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" -dependencies = [ - "curve25519-dalek 3.2.0", - "ed25519", - "rand 0.7.3", - "serde", - "sha2 0.9.9", - "zeroize", -] - -[[package]] -name = "either" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" - -[[package]] -name = "environmental" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b91989ae21441195d7d9b9993a2f9295c7e1a8c96255d8b729accddc124797" - -[[package]] -name = "erased-serde" -version = "0.3.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "003000e712ad0f95857bd4d2ef8d1890069e06554101697d12050668b2f6f020" -dependencies = [ - "serde", -] - -[[package]] -name = "fake-simd" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" - -[[package]] -name = "fixed-hash" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" -dependencies = [ - "byteorder", - "rand 0.8.5", - "rustc-hex", - "static_assertions", -] - -[[package]] -name = "flex-error" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c606d892c9de11507fa0dcffc116434f94e105d0bbdc4e405b61519464c49d7b" -dependencies = [ - "paste", -] - -[[package]] -name = "funty" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" - -[[package]] -name = "futures" -version = "0.3.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab30e97ab6aacfe635fad58f22c2bb06c8b685f7421eb1e064a729e2a5f481fa" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bfc52cbddcfd745bf1740338492bb0bd83d76c67b445f91c5fb29fae29ecaa1" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2acedae88d38235936c3922476b10fced7b2b68136f5e3c03c2d5be348a1115" - -[[package]] -name = "futures-executor" -version = "0.3.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d11aa21b5b587a64682c0094c2bdd4df0076c5324961a40cc3abd7f37930528" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", - "num_cpus", -] - -[[package]] -name = "futures-io" -version = "0.3.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93a66fc6d035a26a3ae255a6d2bca35eda63ae4c5512bef54449113f7a1228e5" - -[[package]] -name = "futures-macro" -version = "0.3.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0db9cce532b0eae2ccf2766ab246f114b56b9cf6d445e00c2549fbc100ca045d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "futures-sink" -version = "0.3.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca0bae1fe9752cf7fd9b0064c674ae63f97b37bc714d745cbde0afb7ec4e6765" - -[[package]] -name = "futures-task" -version = "0.3.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "842fc63b931f4056a24d59de13fb1272134ce261816e063e634ad0c15cdc5306" - -[[package]] -name = "futures-util" -version = "0.3.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0828a5471e340229c11c77ca80017937ce3c58cb788a17e5f1c2d5c485a9577" -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.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" -dependencies = [ - "typenum", -] - -[[package]] -name = "generic-array" -version = "0.14.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", - "wasm-bindgen", -] - -[[package]] -name = "getrandom" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", -] - -[[package]] -name = "gimli" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" - -[[package]] -name = "hash-db" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d23bd4e7b5eda0d0f3a307e8b381fdc8ba9000f26fbe912250c0a4cc3956364a" - -[[package]] -name = "hash256-std-hasher" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92c171d55b98633f4ed3860808f004099b36c1cc29c42cfc53aa8591b21efcf2" -dependencies = [ - "crunchy", -] - -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" -dependencies = [ - "ahash", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash", -] - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hmac" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" -dependencies = [ - "crypto-mac 0.8.0", - "digest 0.9.0", -] - -[[package]] -name = "hmac" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" -dependencies = [ - "crypto-mac 0.11.1", - "digest 0.9.0", -] - -[[package]] -name = "hmac-drbg" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" -dependencies = [ - "digest 0.9.0", - "generic-array 0.14.6", - "hmac 0.8.1", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad2bfd338099682614d3ee3fe0cd72e0b6a41ca6a87f6a74a3bd593c91650501" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "js-sys", - "wasm-bindgen", - "winapi", -] - -[[package]] -name = "ibc" -version = "0.19.0" -dependencies = [ - "bytes", - "derive_more", - "dyn-clone", - "erased-serde", - "flex-error", - "ibc-proto", - "ics23", - "num-traits", - "primitive-types 0.11.1", - "prost", - "safe-regex", - "serde", - "serde_derive", - "serde_json", - "sha2 0.10.2", - "subtle-encoding", - "tendermint", - "tendermint-light-client-verifier", - "tendermint-proto", - "time", - "tracing", - "uint", -] - -[[package]] -name = "ibc-proto" -version = "0.20.1" -dependencies = [ - "base64", - "bytes", - "flex-error", - "prost", - "serde", - "subtle-encoding", - "tendermint-proto", -] - -[[package]] -name = "ics23" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "149f3093d710c18c749ba68de3bc8131927aca00410ab90f3368e0524d01fe90" -dependencies = [ - "anyhow", - "bytes", - "hex", - "prost", - "ripemd", - "sha2 0.10.2", - "sha3", -] - -[[package]] -name = "impl-codec" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "161ebdfec3c8e3b52bf61c4f3550a1eea4f9579d10dc1b936f3171ebdcd6c443" -dependencies = [ - "parity-scale-codec", -] - -[[package]] -name = "impl-serde" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4551f042f3438e64dbd6226b20527fc84a6e1fe65688b58746a2f53623f25f5c" -dependencies = [ - "serde", -] - -[[package]] -name = "impl-trait-for-tuples" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "integer-sqrt" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "276ec31bcb4a9ee45f58bec6f9ec700ae4cf4f4f8f2fa7e06cb406bd5ffdd770" -dependencies = [ - "num-traits", -] - -[[package]] -name = "itertools" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - -[[package]] -name = "itoa" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" - -[[package]] -name = "js-sys" -version = "0.3.59" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "keccak" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9b7d56ba4a8344d6be9729995e6b06f928af29998cdf79fe390cbf6b1fee838" - -[[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.132" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" - -[[package]] -name = "libsecp256k1" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" -dependencies = [ - "arrayref", - "base64", - "digest 0.9.0", - "hmac-drbg", - "libsecp256k1-core", - "libsecp256k1-gen-ecmult", - "libsecp256k1-gen-genmult", - "rand 0.8.5", - "serde", - "sha2 0.9.9", - "typenum", -] - -[[package]] -name = "libsecp256k1-core" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" -dependencies = [ - "crunchy", - "digest 0.9.0", - "subtle", -] - -[[package]] -name = "libsecp256k1-gen-ecmult" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" -dependencies = [ - "libsecp256k1-core", -] - -[[package]] -name = "libsecp256k1-gen-genmult" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" -dependencies = [ - "libsecp256k1-core", -] - -[[package]] -name = "lock_api" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "matchers" -version = "0.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1" -dependencies = [ - "regex-automata", -] - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "memory-db" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d505169b746dacf02f7d14d8c80b34edfd8212159c63d23c977739a0d960c626" -dependencies = [ - "hash-db", - "hashbrown 0.11.2", - "parity-util-mem", -] - -[[package]] -name = "memory_units" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" - -[[package]] -name = "merlin" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e261cf0f8b3c42ded9f7d2bb59dea03aa52bc8a1cbc7482f9fc3fd1229d3b42" -dependencies = [ - "byteorder", - "keccak", - "rand_core 0.5.1", - "zeroize", -] - -[[package]] -name = "miniz_oxide" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" -dependencies = [ - "adler", -] - -[[package]] -name = "no-std-check" -version = "0.1.0" -dependencies = [ - "ibc", - "ibc-proto", - "sp-core", - "sp-io", - "sp-runtime", - "sp-std", - "tendermint", - "tendermint-light-client-verifier", - "tendermint-proto", -] - -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - -[[package]] -name = "num-bigint" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-derive" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "num-format" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bafe4179722c2894288ee77a9f044f02811c86af699344c498b0840c698a2465" -dependencies = [ - "arrayvec 0.4.12", - "itoa 0.4.8", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" -dependencies = [ - "autocfg", - "num-bigint", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "num_threads" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" -dependencies = [ - "libc", -] - -[[package]] -name = "object" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e" - -[[package]] -name = "opaque-debug" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" - -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - -[[package]] -name = "parity-scale-codec" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373b1a4c1338d9cd3d1fa53b3a11bdab5ab6bd80a20f7f7becd76953ae2be909" -dependencies = [ - "arrayvec 0.7.2", - "bitvec", - "byte-slice-cast", - "impl-trait-for-tuples", - "parity-scale-codec-derive", - "serde", -] - -[[package]] -name = "parity-scale-codec-derive" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1557010476e0595c9b568d16dcfb81b93cdeb157612726f5170d31aa707bed27" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "parity-util-mem" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f4cb4e169446179cbc6b8b6320cc9fca49bd2e94e8db25f25f200a8ea774770" -dependencies = [ - "cfg-if", - "hashbrown 0.11.2", - "impl-trait-for-tuples", - "parity-util-mem-derive", - "parking_lot", - "primitive-types 0.10.1", - "winapi", -] - -[[package]] -name = "parity-util-mem-derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f557c32c6d268a07c921471619c0295f5efad3a0e76d4f97a05c091a51d110b2" -dependencies = [ - "proc-macro2", - "syn", - "synstructure", -] - -[[package]] -name = "parity-wasm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be5e13c266502aadf83426d87d81a0f5d1ef45b8027f5a471c360abfe4bfae92" - -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall", - "smallvec", - "winapi", -] - -[[package]] -name = "paste" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9423e2b32f7a043629287a536f21951e8c6a82482d0acb1eeebfc90bc2225b22" - -[[package]] -name = "pbkdf2" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216eaa586a190f0a738f2f918511eecfa90f13295abec0e457cdebcceda80cbd" -dependencies = [ - "crypto-mac 0.8.0", -] - -[[package]] -name = "pbkdf2" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d95f5254224e617595d2cc3cc73ff0a5eaf2637519e25f03388154e9378b6ffa" -dependencies = [ - "crypto-mac 0.11.1", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "ppv-lite86" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" - -[[package]] -name = "primitive-types" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05e4722c697a58a99d5d06a08c30821d7c082a4632198de1eaa5a6c22ef42373" -dependencies = [ - "fixed-hash", - "impl-codec", - "impl-serde", - "scale-info", - "uint", -] - -[[package]] -name = "primitive-types" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28720988bff275df1f51b171e1b2a18c30d194c4d2b61defdacecd625a5d94a" -dependencies = [ - "fixed-hash", - "impl-serde", - "uint", -] - -[[package]] -name = "proc-macro-crate" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" -dependencies = [ - "once_cell", - "thiserror", - "toml", -] - -[[package]] -name = "proc-macro2" -version = "1.0.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "prost" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "399c3c31cdec40583bb68f0b18403400d01ec4289c383aa047560439952c4dd7" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-derive" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7345d5f0e08c0536d7ac7229952590239e77abf0a0100a1b1d890add6ea96364" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "prost-types" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dfaa718ad76a44b3415e6c4d53b17c8f99160dcb3a99b10470fce8ad43f6e3e" -dependencies = [ - "bytes", - "prost", -] - -[[package]] -name = "quote" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "radium" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb" - -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", - "rand_pcg", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.3", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - -[[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 0.6.3", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - -[[package]] -name = "rand_core" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" -dependencies = [ - "getrandom 0.2.7", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "rand_pcg" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - -[[package]] -name = "ref-cast" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed13bcd201494ab44900a96490291651d200730904221832b9547d24a87d332b" -dependencies = [ - "ref-cast-impl", -] - -[[package]] -name = "ref-cast-impl" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5234cd6063258a5e32903b53b1b6ac043a0541c8adc1f610f67b0326c7a578fa" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "regex" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" - -[[package]] -name = "ripemd" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1facec54cb5e0dc08553501fa740091086d0259ad0067e0d4103448e4cb22ed3" -dependencies = [ - "digest 0.10.3", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustc-hex" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" - -[[package]] -name = "ryu" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" - -[[package]] -name = "safe-proc-macro2" -version = "1.0.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "814c536dcd27acf03296c618dab7ad62d28e70abd7ba41d3f34a2ce707a2c666" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "safe-quote" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e530f7831f3feafcd5f1aae406ac205dd998436b4007c8e80f03eca78a88f7" -dependencies = [ - "safe-proc-macro2", -] - -[[package]] -name = "safe-regex" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15289bf322e0673d52756a18194167f2378ec1a15fe884af6e2d2cb934822b0" -dependencies = [ - "safe-regex-macro", -] - -[[package]] -name = "safe-regex-compiler" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fba76fae590a2aa665279deb1f57b5098cbace01a0c5e60e262fcf55f7c51542" -dependencies = [ - "safe-proc-macro2", - "safe-quote", -] - -[[package]] -name = "safe-regex-macro" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c2e96b5c03f158d1b16ba79af515137795f4ad4e8de3f790518aae91f1d127" -dependencies = [ - "safe-proc-macro2", - "safe-regex-compiler", -] - -[[package]] -name = "scale-info" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c55b744399c25532d63a0d2789b109df8d46fc93752d46b0782991a931a782f" -dependencies = [ - "bitvec", - "cfg-if", - "derive_more", - "parity-scale-codec", - "scale-info-derive", -] - -[[package]] -name = "scale-info-derive" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baeb2780690380592f86205aa4ee49815feb2acad8c2f59e6dd207148c3f1fcd" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "schnorrkel" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "021b403afe70d81eea68f6ea12f6b3c9588e5d536a94c3bf80f15e7faa267862" -dependencies = [ - "arrayref", - "arrayvec 0.5.2", - "curve25519-dalek 2.1.3", - "getrandom 0.1.16", - "merlin", - "rand 0.7.3", - "rand_core 0.5.1", - "sha2 0.8.2", - "subtle", - "zeroize", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "secrecy" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" -dependencies = [ - "zeroize", -] - -[[package]] -name = "serde" -version = "1.0.143" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e8e5d5b70924f74ff5c6d64d9a5acd91422117c60f48c4e07855238a254553" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_bytes" -version = "0.11.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfc50e8183eeeb6178dcb167ae34a8051d63535023ae38b5d8d12beae193d37b" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_derive" -version = "1.0.143" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3d8e8de557aee63c26b85b947f5e59b690d0454c753f3adeb5cd7835ab88391" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38dd04e3c8279e75b31ef29dbdceebfe5ad89f4d0937213c53f7d49d01b3d5a7" -dependencies = [ - "itoa 1.0.3", - "ryu", - "serde", -] - -[[package]] -name = "serde_repr" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "sha2" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" -dependencies = [ - "block-buffer 0.7.3", - "digest 0.8.1", - "fake-simd", - "opaque-debug 0.2.3", -] - -[[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 0.3.0", -] - -[[package]] -name = "sha2" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.3", -] - -[[package]] -name = "sha3" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a31480366ec990f395a61b7c08122d99bd40544fdb5abcfc1b06bb29994312c" -dependencies = [ - "digest 0.10.3", - "keccak", -] - -[[package]] -name = "sharded-slab" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "signature" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0ea32af43239f0d353a7dd75a22d94c329c8cdaafdcb4c1c1335aa10c298a4a" - -[[package]] -name = "slab" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" - -[[package]] -name = "sp-application-crypto" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69c8dfffb7a15ac2c802bc9ce972b8449c8ce0a15254ae4d77a012a3a8c278d1" -dependencies = [ - "parity-scale-codec", - "scale-info", - "serde", - "sp-core", - "sp-io", - "sp-std", -] - -[[package]] -name = "sp-arithmetic" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa92b9707afdaa807bcb985fcc70645ebbe6fbb2442620d61dc47e7f3553a7ae" -dependencies = [ - "integer-sqrt", - "num-traits", - "parity-scale-codec", - "scale-info", - "serde", - "sp-debug-derive", - "sp-std", - "static_assertions", -] - -[[package]] -name = "sp-core" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e2a372e6c3a40464f490f76843dfc331d08e43f7672d73377c0458f5b5db7ed" -dependencies = [ - "base58", - "bitflags", - "blake2-rfc", - "byteorder", - "dyn-clonable", - "ed25519-dalek", - "futures", - "hash-db", - "hash256-std-hasher", - "hex", - "impl-serde", - "lazy_static", - "libsecp256k1", - "log", - "merlin", - "num-traits", - "parity-scale-codec", - "parity-util-mem", - "parking_lot", - "primitive-types 0.10.1", - "rand 0.7.3", - "regex", - "scale-info", - "schnorrkel", - "secrecy", - "serde", - "sha2 0.10.2", - "sp-core-hashing", - "sp-debug-derive", - "sp-externalities", - "sp-runtime-interface", - "sp-std", - "sp-storage", - "ss58-registry", - "substrate-bip39", - "thiserror", - "tiny-bip39", - "tiny-keccak", - "twox-hash", - "wasmi", - "zeroize", -] - -[[package]] -name = "sp-core-hashing" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec864a6a67249f0c8dd3d5acab43623a61677e85ff4f2f9b04b802d2fe780e83" -dependencies = [ - "blake2-rfc", - "byteorder", - "sha2 0.9.9", - "sp-std", - "tiny-keccak", - "twox-hash", -] - -[[package]] -name = "sp-debug-derive" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d676664972e22a0796176e81e7bec41df461d1edf52090955cdab55f2c956ff2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "sp-externalities" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54f0fe949490000a97f367dc2acf4d2e7d0473ec0e13ce1775d0804bb64d3c98" -dependencies = [ - "environmental", - "parity-scale-codec", - "sp-std", - "sp-storage", -] - -[[package]] -name = "sp-io" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dece853333a36d405be49d72a5190c1aa3fa6fbc442a8f28c59b50c0351b21d6" -dependencies = [ - "futures", - "hash-db", - "libsecp256k1", - "log", - "parity-scale-codec", - "parking_lot", - "sp-core", - "sp-externalities", - "sp-keystore", - "sp-runtime-interface", - "sp-state-machine", - "sp-std", - "sp-tracing", - "sp-trie", - "sp-wasm-interface", - "tracing", - "tracing-core", -] - -[[package]] -name = "sp-keystore" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3c3376dede1940014254f6d10c9fca20c4deb1fae930a98edfdab0190a06ed4" -dependencies = [ - "async-trait", - "futures", - "merlin", - "parity-scale-codec", - "parking_lot", - "schnorrkel", - "sp-core", - "sp-externalities", - "thiserror", -] - -[[package]] -name = "sp-panic-handler" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2101f3c555fceafcfcfb0e61c55ea9ed80dc60bd77d54d9f25b369edb029e9a4" -dependencies = [ - "backtrace", - "lazy_static", - "regex", -] - -[[package]] -name = "sp-runtime" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3772a765d076ac548c0c37f6d84dc8873bf64d0cfcf8b7b7322b5374d635ceff" -dependencies = [ - "either", - "hash256-std-hasher", - "impl-trait-for-tuples", - "log", - "parity-scale-codec", - "parity-util-mem", - "paste", - "rand 0.7.3", - "scale-info", - "serde", - "sp-application-crypto", - "sp-arithmetic", - "sp-core", - "sp-io", - "sp-std", -] - -[[package]] -name = "sp-runtime-interface" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab1f6625996742e3e5c0e6a6a2b5c0db363e2c52f4a71ea6cd6d963a10a4bdd6" -dependencies = [ - "impl-trait-for-tuples", - "parity-scale-codec", - "primitive-types 0.10.1", - "sp-externalities", - "sp-runtime-interface-proc-macro", - "sp-std", - "sp-storage", - "sp-tracing", - "sp-wasm-interface", - "static_assertions", -] - -[[package]] -name = "sp-runtime-interface-proc-macro" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b58cc6060b2d2f35061db5b4172f4a47353c3f01a89f281699a6c3f05d1267a" -dependencies = [ - "Inflector", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "sp-state-machine" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e66851fd082cccc6f66dddf6eda458f30766a3febd769f1b5592120aa8072fd" -dependencies = [ - "hash-db", - "log", - "num-traits", - "parity-scale-codec", - "parking_lot", - "rand 0.7.3", - "smallvec", - "sp-core", - "sp-externalities", - "sp-panic-handler", - "sp-std", - "sp-trie", - "thiserror", - "tracing", - "trie-db", - "trie-root", -] - -[[package]] -name = "sp-std" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14804d6069ee7a388240b665f17908d98386ffb0b5d39f89a4099fc7a2a4c03f" - -[[package]] -name = "sp-storage" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "838ec2a757a8e7b903684a71f649dfbd6449d91e3e5d93979fc8d2ee77d56fee" -dependencies = [ - "impl-serde", - "parity-scale-codec", - "ref-cast", - "serde", - "sp-debug-derive", - "sp-std", -] - -[[package]] -name = "sp-tracing" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4688fceac497cee7e9b72c387fef20fa517e2bf6a3bf52a4a45dcc9391d6201" -dependencies = [ - "parity-scale-codec", - "sp-std", - "tracing", - "tracing-core", - "tracing-subscriber", -] - -[[package]] -name = "sp-trie" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7ad44bbb93fb9af94ea9869ec13602884f7d2360c245377aed7c6c92c6834e" -dependencies = [ - "hash-db", - "memory-db", - "parity-scale-codec", - "scale-info", - "sp-core", - "sp-std", - "trie-db", - "trie-root", -] - -[[package]] -name = "sp-wasm-interface" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60951479e2f26018c4c315a6f48956b9e2a3803953517bf8930e69b9a7a159df" -dependencies = [ - "impl-trait-for-tuples", - "log", - "parity-scale-codec", - "sp-std", - "wasmi", -] - -[[package]] -name = "ss58-registry" -version = "1.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a039906277e0d8db996cd9d1ef19278c10209d994ecfc1025ced16342873a17c" -dependencies = [ - "Inflector", - "num-format", - "proc-macro2", - "quote", - "serde", - "serde_json", - "unicode-xid", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "substrate-bip39" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49eee6965196b32f882dd2ee85a92b1dbead41b04e53907f269de3b0dc04733c" -dependencies = [ - "hmac 0.11.0", - "pbkdf2 0.8.0", - "schnorrkel", - "sha2 0.9.9", - "zeroize", -] - -[[package]] -name = "subtle" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" - -[[package]] -name = "subtle-encoding" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dcb1ed7b8330c5eed5441052651dd7a12c75e2ed88f2ec024ae1fa3a5e59945" -dependencies = [ - "zeroize", -] - -[[package]] -name = "syn" -version = "1.0.99" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "synstructure" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "unicode-xid", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "tendermint" -version = "0.23.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "467f82178deeebcd357e1273a0c0b77b9a8a0313ef7c07074baebe99d87851f4" -dependencies = [ - "async-trait", - "bytes", - "ed25519", - "ed25519-dalek", - "flex-error", - "futures", - "num-traits", - "once_cell", - "prost", - "prost-types", - "serde", - "serde_bytes", - "serde_json", - "serde_repr", - "sha2 0.9.9", - "signature", - "subtle", - "subtle-encoding", - "tendermint-proto", - "time", - "zeroize", -] - -[[package]] -name = "tendermint-light-client-verifier" -version = "0.23.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a1ecb58905bc27f977d28d281594c71a8905da1d8cd88f1db31703f1e9e5ad" -dependencies = [ - "derive_more", - "flex-error", - "serde", - "tendermint", - "time", -] - -[[package]] -name = "tendermint-proto" -version = "0.23.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ce80bf536476db81ecc9ebab834dc329c9c1509a694f211a73858814bfe023" -dependencies = [ - "bytes", - "flex-error", - "num-derive", - "num-traits", - "prost", - "prost-types", - "serde", - "serde_bytes", - "subtle-encoding", - "time", -] - -[[package]] -name = "thiserror" -version = "1.0.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5f6586b7f764adc0231f4c79be7b920e766bb2f3e51b3661cdb263828f19994" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "thread_local" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" -dependencies = [ - "once_cell", -] - -[[package]] -name = "time" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c91f41dcb2f096c05f0873d667dceec1087ce5bcf984ec8ffb19acddbb3217" -dependencies = [ - "libc", - "num_threads", - "time-macros", -] - -[[package]] -name = "time-macros" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" - -[[package]] -name = "tiny-bip39" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc59cb9dfc85bb312c3a78fd6aa8a8582e310b0fa885d5bb877f6dcc601839d" -dependencies = [ - "anyhow", - "hmac 0.8.1", - "once_cell", - "pbkdf2 0.4.0", - "rand 0.7.3", - "rustc-hash", - "sha2 0.9.9", - "thiserror", - "unicode-normalization", - "wasm-bindgen", - "zeroize", -] - -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - -[[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.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" - -[[package]] -name = "toml" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" -dependencies = [ - "serde", -] - -[[package]] -name = "tracing" -version = "0.1.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307" -dependencies = [ - "cfg-if", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tracing-core" -version = "0.1.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" -dependencies = [ - "lazy_static", - "log", - "tracing-core", -] - -[[package]] -name = "tracing-serde" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" -dependencies = [ - "serde", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" -dependencies = [ - "ansi_term", - "chrono", - "lazy_static", - "matchers", - "regex", - "serde", - "serde_json", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", - "tracing-serde", -] - -[[package]] -name = "trie-db" -version = "0.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32d034c0d3db64b43c31de38e945f15b40cd4ca6d2dcfc26d4798ce8de4ab83" -dependencies = [ - "hash-db", - "hashbrown 0.12.3", - "log", - "rustc-hex", - "smallvec", -] - -[[package]] -name = "trie-root" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a36c5ca3911ed3c9a5416ee6c679042064b93fc637ded67e25f92e68d783891" -dependencies = [ - "hash-db", -] - -[[package]] -name = "twox-hash" -version = "1.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" -dependencies = [ - "cfg-if", - "rand 0.8.5", - "static_assertions", -] - -[[package]] -name = "typenum" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" - -[[package]] -name = "uint" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f03af7ccf01dd611cc450a0d10dbc9b745770d096473e2faf0ca6e2d66d1e0" -dependencies = [ - "byteorder", - "crunchy", - "hex", - "static_assertions", -] - -[[package]] -name = "unicode-ident" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" - -[[package]] -name = "unicode-normalization" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-xid" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" - -[[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 = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[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.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a" - -[[package]] -name = "wasmi" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca00c5147c319a8ec91ec1a0edbec31e566ce2c9cc93b3f9bb86a9efd0eb795d" -dependencies = [ - "downcast-rs", - "libc", - "memory_units", - "num-rational", - "num-traits", - "parity-wasm", - "wasmi-validation", -] - -[[package]] -name = "wasmi-validation" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "165343ecd6c018fc09ebcae280752702c9a2ef3e6f8d02f1cfcbdb53ef6d7937" -dependencies = [ - "parity-wasm", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "wyz" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" - -[[package]] -name = "zeroize" -version = "1.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] diff --git a/ci/no-std-check/Cargo.toml b/ci/no-std-check/Cargo.toml deleted file mode 100644 index 6f0c6d064d..0000000000 --- a/ci/no-std-check/Cargo.toml +++ /dev/null @@ -1,37 +0,0 @@ -[package] -name = "no-std-check" -version = "0.1.0" -edition = "2021" -resolver = "2" - -[dependencies] -ibc = { path = "../../modules", default-features = false } -ibc-proto = { path = "../../proto", default-features = false } -tendermint = { version = "0.23.9", default-features = false } -tendermint-proto = { version = "0.23.9", default-features = false } -tendermint-light-client-verifier = { version = "0.23.9", default-features = false } - -sp-core = { version = "5.0.0", default-features = false, optional = true } -sp-io = { version = "5.0.0", default-features = false, optional = true } -sp-runtime = { version = "5.0.0", default-features = false, optional = true } -sp-std = { version = "4.0.0", default-features = false, optional = true } - -[features] -panic-handler = [] -use-substrate = [ - "sp-core", - "sp-io", - "sp-runtime", - "sp-std", -] -substrate-std = [ - "sp-core/std", - "sp-io/std", - "sp-runtime/std", - "sp-std/std", -] - -# [patch.crates-io] -# tendermint = { git = "https://github.com/informalsystems/tendermint-rs", branch = "v0.23.x" } -# tendermint-proto = { git = "https://github.com/informalsystems/tendermint-rs", branch = "v0.23.x" } -# tendermint-light-client-verifier = { git = "https://github.com/informalsystems/tendermint-rs", branch = "v0.23.x" } diff --git a/ci/no-std-check/Makefile b/ci/no-std-check/Makefile deleted file mode 100644 index 8d4328dfcd..0000000000 --- a/ci/no-std-check/Makefile +++ /dev/null @@ -1,49 +0,0 @@ -NIGHTLY_VERSION=nightly - -.DEFAULT_GOAL := help - -.PHONY: all setup build-substrate check-panic-conflict check-cargo-build-std check-wasm check-substrate help - -all: ## Run the setup and all checks - $(MAKE) build-substrate - $(MAKE) check-panic-conflict - $(MAKE) check-cargo-build-std - $(MAKE) check-wasm - $(MAKE) check-substrate - -setup: ## Setup the required nightly toolchain and the wasm32 target - rustup install $(NIGHTLY_VERSION) - rustup target add wasm32-unknown-unknown --toolchain $(NIGHTLY_VERSION) - rustup component add rust-src --toolchain $(NIGHTLY_VERSION) - -build-substrate: ## Build with Substrate support - cargo build \ - --no-default-features \ - --features use-substrate,substrate-std - -check-panic-conflict: ## Check for `no_std` compliance by installing a panic handler, and any other crate importing `std` will cause a conflict. Runs on default target. - cargo build \ - --no-default-features \ - --features panic-handler - -check-cargo-build-std: ## Check for `no_std` compliance using Cargo nightly's `build-std` feature. Runs on the target `x86_64-unknown-linux-gnu`. - rustup run $(NIGHTLY_VERSION) -- \ - cargo build -Z build-std=core,alloc \ - --no-default-features \ - --target x86_64-unknown-linux-gnu - -check-wasm: ## Check for WebAssembly and `no_std` compliance by building on the target `wasm32-unknown-unknown` and installing a panic handler. - rustup run $(NIGHTLY_VERSION) -- \ - cargo build \ - --features panic-handler \ - --target wasm32-unknown-unknown - -check-substrate: ## Check for Substrate, WebAssembly, and `no_std` compliance by importing Substrate crates and building on `wasm32-unknown-unknown`. - rustup run $(NIGHTLY_VERSION) -- \ - cargo build \ - --no-default-features \ - --features use-substrate \ - --target wasm32-unknown-unknown - -help: ## Show this help message - @grep -E '^[a-z.A-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' diff --git a/ci/no-std-check/README.md b/ci/no-std-check/README.md deleted file mode 100644 index 16468ae76f..0000000000 --- a/ci/no-std-check/README.md +++ /dev/null @@ -1,191 +0,0 @@ -# `no_std` Compliance Check - -This crate checks the `no_std` compliance of the supported crates in ibc-rs. - -## Make Recipes - -- `check-panic-conflict` - Check for `no_std` compliance by installing a panic handler, and any other crate importing `std` will cause a conflict. Runs on default target. - -- `check-cargo-build-std` - Check for `no_std` compliance using Cargo nightly's `build-std` feature. Runs on the target `x86_64-unknown-linux-gnu`. - -- `check-wasm` - Check for WebAssembly and `no_std` compliance by building on the target `wasm32-unknown-unknown` and installing a panic handler. - -- `check-substrate` - Check for Substrate, WebAssembly, and `no_std` compliance by importing Substrate crates and building on `wasm32-unknown-unknown`. Any crate using `std` will cause a conflict on the panic and out-of-memory (OOM) handlers installed by `sp-io`. - -## Checking Single Unsupported Dependency - -By default, the check scripts try to build all unsupported dependencies and will fail. To test if a particular crate still fails the no_std check, edit the `use-unsupported` list in [Cargo.toml](./Cargo.toml) to uncomment all crates except the crate that we are interested to check. For example, to check for only the `getrandom` crate: - -```toml -use-unsupported = [ - # "tonic", - # "socket2", - "getrandom", - # "serde", - # ..., -] -``` - -## Adding New Dependencies - -For a crate named `my-package-1.2.3`, first try and add the crate in [Cargo.toml](./Cargo.toml) of this project as: - -```toml -my-package = { version = "1.2.3" } -``` - -Then comment out the `use-unsupported` list in the `[features]` section of Cargo.toml and replace it with an empty list temporarily for testing: - -```toml -[features] -... -use-unsupported = [] -# use-unsupported = [ -# "tonic", -# "socket2", -# "getrandom", -# ... -# ] -``` - -Then import the package in [src/lib.rs](./src/lib.rs): - -```rust -use my_package -``` - -Note that you must import the package in `lib.rs`, otherwise Cargo will skip linking the crate and fail to check for the panic handler conflicts. - -Then run all of the check scripts and see if any of them fails. If the check script fails, try and disable the default features and run the checks again: - -```rust -my-package = { version = "1.2.3", default-features = false } -``` - -You may also need other tweaks such as enable custom features to make it run on Wasm. -At this point if the checks pass, we have verified the no_std compliance of `my-package`. Restore the original `use-unsupported` list and commit the code. - -Otherwise if it fails, we have found a dependency that does not support `no_std`. Update Cargo.toml to make the crate optional: - -```rust -my-package = { version = "1.2.3", optional = true, default-features = false } -``` - -Now we have to modify [lib.rs](./src/lib.rs) again and only import the crate if it is enabled: - -```rust -#[cfg(feature = "my-package")] -use my_package; -``` - -Retore the original `use-unsupported` list, and add `my-package` to the end of the list: - -```toml -use-unsupported = [ - "tonic", - "socket2", - "getrandom", - ..., - "my-package", -] -``` - -Commit the changes so that we will track if newer version of the crate would support no_std in the future. - -## Conflict Detection Methods - -There are two methods that we use to detect `std` conflict: - -### Panic Handler Conflict - -This follows the outline of the guide by -[Danilo Bargen](https://blog.dbrgn.ch/2019/12/24/testing-for-no-std-compatibility/) -to register a panic handler in the `no-std-check` crate. -Any crate imported `no-std-check` that uses `std` will cause a compile error that -looks like follows: - -``` -$ cargo build - Updating crates.io index - Compiling no-std-check v0.1.0 (/data/development/informal/ibc-rs/no-std-check) -error[E0152]: found duplicate lang item `panic_impl` - --> src/lib.rs:31:1 - | -31 | fn panic(_info: &PanicInfo) -> ! { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: the lang item is first defined in crate `std` (which `prost` depends on) - = note: first definition in `std` loaded from /home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-b6b48477bfa8c673.rlib - = note: second definition in the local crate (`no_std_check`) - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0152`. -error: could not compile `no-std-check` -``` - -- Pros: - - Can be tested using Rust stable. -- Cons: - - Crates must be listed on both `Cargo.toml` and `lib.rs`. - - Crates that are listed in `Cargo.toml` but not imported inside `lib.rs` are not checked. - -### Overrride std crates using Cargo Nightly - -This uses the unstable `build-std` feature provided by -[Cargo Nightly](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-std). -With this we can explicitly pass the std crates we want to support, `core` and `alloc`, -via command line, and exclude the `std` crate. - -If any of the dependency uses `std`, they will fail to compile at all, albeit with -confusing error messages: - -``` -$ rustup run nightly -- cargo build -j1 -Z build-std=core,alloc --target x86_64-unknown-linux-gnu - ... - Compiling bytes v1.0.1 -error[E0773]: attempted to define built-in macro more than once - --> /home/ubuntu/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/macros/mod.rs:1201:5 - | -1201 | / macro_rules! cfg { -1202 | | ($($cfg:tt)*) => { -1203 | | /* compiler built-in */ -1204 | | }; -1205 | | } - | |_____^ - | -note: previously defined here - --> /home/ubuntu/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/macros/mod.rs:1201:5 - | -1201 | / macro_rules! cfg { -1202 | | ($($cfg:tt)*) => { -1203 | | /* compiler built-in */ -1204 | | }; -1205 | | } - | |_____^ - -error: duplicate lang item in crate `core` (which `std` depends on): `bool`. - | - = note: the lang item is first defined in crate `core` (which `bytes` depends on) - = note: first definition in `core` loaded from /data/development/informal/ibc-rs/no-std-check/target/x86_64-unknown-linux-gnu/debug/deps/libcore-c00d94870d25cd7e.rmeta - = note: second definition in `core` loaded from /home/ubuntu/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcore-9924c22ae1efcf66.rlib - -error: duplicate lang item in crate `core` (which `std` depends on): `char`. - | - = note: the lang item is first defined in crate `core` (which `bytes` depends on) - = note: first definition in `core` loaded from /data/development/informal/ibc-rs/no-std-check/target/x86_64-unknown-linux-gnu/debug/deps/libcore-c00d94870d25cd7e.rmeta - = note: second definition in `core` loaded from /home/ubuntu/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcore-9924c22ae1efcf66.rlib -... -``` - -The above error are shown when building the `bytes` crate. This is caused by `bytes` using imports from `std`, -which causes `std` to be included and produce conflicts with the `core` crate that is explicitly built by Cargo. -This produces very long error messages, so we may want to use tools like `less` to scroll through the errors. - -Pros: - - Directly identify use of `std` in dependencies. - - Error is raised on the first dependency that imports `std`. - -Cons: - - Nightly-only feature that is subject to change. - - Confusing and long error messages. diff --git a/ci/no-std-check/src/lib.rs b/ci/no-std-check/src/lib.rs deleted file mode 100644 index 13eea2c515..0000000000 --- a/ci/no-std-check/src/lib.rs +++ /dev/null @@ -1,52 +0,0 @@ -// ensure_no_std/src/main.rs -#![no_std] -#![allow(unused_imports)] - -extern crate alloc; - -// Import the crates that we want to check if they are fully no-std compliance - -use ibc; -use ibc_proto; -use tendermint; -use tendermint_proto; -use tendermint_light_client_verifier; - -#[cfg(feature = "sp-core")] -use sp_core; - -#[cfg(feature = "sp-io")] -use sp_io; - -#[cfg(feature = "sp-runtime")] -use sp_runtime; - -#[cfg(feature = "sp-std")] -use sp_std; - -use core::panic::PanicInfo; - -/* - -This function definition checks for the compliance of no-std in -dependencies by causing a compile error if this crate is -linked with `std`. When that happens, you should see error messages -such as follows: - -``` -error[E0152]: found duplicate lang item `panic_impl` - --> no-std-check/src/lib.rs - | -12 | fn panic(_info: &PanicInfo) -> ! { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: the lang item is first defined in crate `std` (which `offending-crate` depends on) -``` - - */ -#[cfg(feature = "panic-handler")] -#[panic_handler] -#[no_mangle] -fn panic(_info: &PanicInfo) -> ! { - loop {} -} diff --git a/ibc-chain-registry/Cargo.toml b/crates/ibc-chain-registry/Cargo.toml similarity index 86% rename from ibc-chain-registry/Cargo.toml rename to crates/ibc-chain-registry/Cargo.toml index a1a88863ea..78b3779fb6 100644 --- a/ibc-chain-registry/Cargo.toml +++ b/crates/ibc-chain-registry/Cargo.toml @@ -14,8 +14,8 @@ description = """ [dependencies] -ibc = { version = "0.19.0", path = "../modules", features = ["std"] } -ibc-proto = { version = "0.20.0", path = "../proto" } +ibc = { version = "0.19.0", features = ["std"] } +ibc-proto = "0.20.0" async-trait = "0.1.57" flex-error = { version = "0.4.4", default-features = false } diff --git a/ibc-chain-registry/src/asset_list.rs b/crates/ibc-chain-registry/src/asset_list.rs similarity index 100% rename from ibc-chain-registry/src/asset_list.rs rename to crates/ibc-chain-registry/src/asset_list.rs diff --git a/ibc-chain-registry/src/chain.rs b/crates/ibc-chain-registry/src/chain.rs similarity index 100% rename from ibc-chain-registry/src/chain.rs rename to crates/ibc-chain-registry/src/chain.rs diff --git a/ibc-chain-registry/src/constants.rs b/crates/ibc-chain-registry/src/constants.rs similarity index 100% rename from ibc-chain-registry/src/constants.rs rename to crates/ibc-chain-registry/src/constants.rs diff --git a/ibc-chain-registry/src/error.rs b/crates/ibc-chain-registry/src/error.rs similarity index 100% rename from ibc-chain-registry/src/error.rs rename to crates/ibc-chain-registry/src/error.rs diff --git a/ibc-chain-registry/src/fetchable.rs b/crates/ibc-chain-registry/src/fetchable.rs similarity index 100% rename from ibc-chain-registry/src/fetchable.rs rename to crates/ibc-chain-registry/src/fetchable.rs diff --git a/ibc-chain-registry/src/formatter.rs b/crates/ibc-chain-registry/src/formatter.rs similarity index 100% rename from ibc-chain-registry/src/formatter.rs rename to crates/ibc-chain-registry/src/formatter.rs diff --git a/ibc-chain-registry/src/lib.rs b/crates/ibc-chain-registry/src/lib.rs similarity index 100% rename from ibc-chain-registry/src/lib.rs rename to crates/ibc-chain-registry/src/lib.rs diff --git a/ibc-chain-registry/src/paths.rs b/crates/ibc-chain-registry/src/paths.rs similarity index 100% rename from ibc-chain-registry/src/paths.rs rename to crates/ibc-chain-registry/src/paths.rs diff --git a/ibc-chain-registry/src/querier.rs b/crates/ibc-chain-registry/src/querier.rs similarity index 100% rename from ibc-chain-registry/src/querier.rs rename to crates/ibc-chain-registry/src/querier.rs diff --git a/relayer-cli/.gitignore b/crates/relayer-cli/.gitignore similarity index 100% rename from relayer-cli/.gitignore rename to crates/relayer-cli/.gitignore diff --git a/relayer-cli/Cargo.toml b/crates/relayer-cli/Cargo.toml similarity index 94% rename from relayer-cli/Cargo.toml rename to crates/relayer-cli/Cargo.toml index 7242a2877b..9285c02335 100644 --- a/relayer-cli/Cargo.toml +++ b/crates/relayer-cli/Cargo.toml @@ -26,10 +26,10 @@ telemetry = ["ibc-relayer/telemetry", "ibc-telemetry"] rest-server = ["ibc-relayer-rest"] [dependencies] -ibc = { version = "0.19.0", path = "../modules", features = ["std", "clock"] } -ibc-chain-registry = { version = "0.1.0" , path = "../ibc-chain-registry"} +ibc = { version = "0.19.0", features = ["std", "clock"] } +ibc-chain-registry = { version = "0.1.0" , path = "../ibc-chain-registry" } ibc-relayer = { version = "0.19.0", path = "../relayer" } -ibc-proto = { version = "0.20.1", path = "../proto" } +ibc-proto = "0.20.1" ibc-telemetry = { version = "0.19.0", path = "../telemetry", optional = true } ibc-relayer-rest = { version = "0.19.0", path = "../relayer-rest", optional = true } diff --git a/relayer-cli/README.md b/crates/relayer-cli/README.md similarity index 100% rename from relayer-cli/README.md rename to crates/relayer-cli/README.md diff --git a/relayer-cli/build.rs b/crates/relayer-cli/build.rs similarity index 100% rename from relayer-cli/build.rs rename to crates/relayer-cli/build.rs diff --git a/relayer-cli/example b/crates/relayer-cli/example similarity index 100% rename from relayer-cli/example rename to crates/relayer-cli/example diff --git a/relayer-cli/src/application.rs b/crates/relayer-cli/src/application.rs similarity index 100% rename from relayer-cli/src/application.rs rename to crates/relayer-cli/src/application.rs diff --git a/relayer-cli/src/bin/hermes/main.rs b/crates/relayer-cli/src/bin/hermes/main.rs similarity index 100% rename from relayer-cli/src/bin/hermes/main.rs rename to crates/relayer-cli/src/bin/hermes/main.rs diff --git a/relayer-cli/src/chain_registry.rs b/crates/relayer-cli/src/chain_registry.rs similarity index 100% rename from relayer-cli/src/chain_registry.rs rename to crates/relayer-cli/src/chain_registry.rs diff --git a/relayer-cli/src/cli_utils.rs b/crates/relayer-cli/src/cli_utils.rs similarity index 100% rename from relayer-cli/src/cli_utils.rs rename to crates/relayer-cli/src/cli_utils.rs diff --git a/relayer-cli/src/commands.rs b/crates/relayer-cli/src/commands.rs similarity index 100% rename from relayer-cli/src/commands.rs rename to crates/relayer-cli/src/commands.rs diff --git a/relayer-cli/src/commands/clear.rs b/crates/relayer-cli/src/commands/clear.rs similarity index 100% rename from relayer-cli/src/commands/clear.rs rename to crates/relayer-cli/src/commands/clear.rs diff --git a/relayer-cli/src/commands/completions.rs b/crates/relayer-cli/src/commands/completions.rs similarity index 100% rename from relayer-cli/src/commands/completions.rs rename to crates/relayer-cli/src/commands/completions.rs diff --git a/relayer-cli/src/commands/config.rs b/crates/relayer-cli/src/commands/config.rs similarity index 100% rename from relayer-cli/src/commands/config.rs rename to crates/relayer-cli/src/commands/config.rs diff --git a/relayer-cli/src/commands/config/auto.rs b/crates/relayer-cli/src/commands/config/auto.rs similarity index 100% rename from relayer-cli/src/commands/config/auto.rs rename to crates/relayer-cli/src/commands/config/auto.rs diff --git a/relayer-cli/src/commands/config/validate.rs b/crates/relayer-cli/src/commands/config/validate.rs similarity index 100% rename from relayer-cli/src/commands/config/validate.rs rename to crates/relayer-cli/src/commands/config/validate.rs diff --git a/relayer-cli/src/commands/create.rs b/crates/relayer-cli/src/commands/create.rs similarity index 100% rename from relayer-cli/src/commands/create.rs rename to crates/relayer-cli/src/commands/create.rs diff --git a/relayer-cli/src/commands/create/channel.rs b/crates/relayer-cli/src/commands/create/channel.rs similarity index 100% rename from relayer-cli/src/commands/create/channel.rs rename to crates/relayer-cli/src/commands/create/channel.rs diff --git a/relayer-cli/src/commands/create/connection.rs b/crates/relayer-cli/src/commands/create/connection.rs similarity index 100% rename from relayer-cli/src/commands/create/connection.rs rename to crates/relayer-cli/src/commands/create/connection.rs diff --git a/relayer-cli/src/commands/health.rs b/crates/relayer-cli/src/commands/health.rs similarity index 100% rename from relayer-cli/src/commands/health.rs rename to crates/relayer-cli/src/commands/health.rs diff --git a/relayer-cli/src/commands/keys.rs b/crates/relayer-cli/src/commands/keys.rs similarity index 100% rename from relayer-cli/src/commands/keys.rs rename to crates/relayer-cli/src/commands/keys.rs diff --git a/relayer-cli/src/commands/keys/add.rs b/crates/relayer-cli/src/commands/keys/add.rs similarity index 100% rename from relayer-cli/src/commands/keys/add.rs rename to crates/relayer-cli/src/commands/keys/add.rs diff --git a/relayer-cli/src/commands/keys/balance.rs b/crates/relayer-cli/src/commands/keys/balance.rs similarity index 100% rename from relayer-cli/src/commands/keys/balance.rs rename to crates/relayer-cli/src/commands/keys/balance.rs diff --git a/relayer-cli/src/commands/keys/delete.rs b/crates/relayer-cli/src/commands/keys/delete.rs similarity index 100% rename from relayer-cli/src/commands/keys/delete.rs rename to crates/relayer-cli/src/commands/keys/delete.rs diff --git a/relayer-cli/src/commands/keys/list.rs b/crates/relayer-cli/src/commands/keys/list.rs similarity index 100% rename from relayer-cli/src/commands/keys/list.rs rename to crates/relayer-cli/src/commands/keys/list.rs diff --git a/relayer-cli/src/commands/listen.rs b/crates/relayer-cli/src/commands/listen.rs similarity index 100% rename from relayer-cli/src/commands/listen.rs rename to crates/relayer-cli/src/commands/listen.rs diff --git a/relayer-cli/src/commands/misbehaviour.rs b/crates/relayer-cli/src/commands/misbehaviour.rs similarity index 100% rename from relayer-cli/src/commands/misbehaviour.rs rename to crates/relayer-cli/src/commands/misbehaviour.rs diff --git a/relayer-cli/src/commands/query.rs b/crates/relayer-cli/src/commands/query.rs similarity index 100% rename from relayer-cli/src/commands/query.rs rename to crates/relayer-cli/src/commands/query.rs diff --git a/relayer-cli/src/commands/query/channel.rs b/crates/relayer-cli/src/commands/query/channel.rs similarity index 100% rename from relayer-cli/src/commands/query/channel.rs rename to crates/relayer-cli/src/commands/query/channel.rs diff --git a/relayer-cli/src/commands/query/channel_client.rs b/crates/relayer-cli/src/commands/query/channel_client.rs similarity index 100% rename from relayer-cli/src/commands/query/channel_client.rs rename to crates/relayer-cli/src/commands/query/channel_client.rs diff --git a/relayer-cli/src/commands/query/channel_ends.rs b/crates/relayer-cli/src/commands/query/channel_ends.rs similarity index 100% rename from relayer-cli/src/commands/query/channel_ends.rs rename to crates/relayer-cli/src/commands/query/channel_ends.rs diff --git a/relayer-cli/src/commands/query/channels.rs b/crates/relayer-cli/src/commands/query/channels.rs similarity index 100% rename from relayer-cli/src/commands/query/channels.rs rename to crates/relayer-cli/src/commands/query/channels.rs diff --git a/relayer-cli/src/commands/query/client.rs b/crates/relayer-cli/src/commands/query/client.rs similarity index 100% rename from relayer-cli/src/commands/query/client.rs rename to crates/relayer-cli/src/commands/query/client.rs diff --git a/relayer-cli/src/commands/query/clients.rs b/crates/relayer-cli/src/commands/query/clients.rs similarity index 100% rename from relayer-cli/src/commands/query/clients.rs rename to crates/relayer-cli/src/commands/query/clients.rs diff --git a/relayer-cli/src/commands/query/connection.rs b/crates/relayer-cli/src/commands/query/connection.rs similarity index 100% rename from relayer-cli/src/commands/query/connection.rs rename to crates/relayer-cli/src/commands/query/connection.rs diff --git a/relayer-cli/src/commands/query/connections.rs b/crates/relayer-cli/src/commands/query/connections.rs similarity index 100% rename from relayer-cli/src/commands/query/connections.rs rename to crates/relayer-cli/src/commands/query/connections.rs diff --git a/relayer-cli/src/commands/query/packet.rs b/crates/relayer-cli/src/commands/query/packet.rs similarity index 100% rename from relayer-cli/src/commands/query/packet.rs rename to crates/relayer-cli/src/commands/query/packet.rs diff --git a/relayer-cli/src/commands/query/packet/ack.rs b/crates/relayer-cli/src/commands/query/packet/ack.rs similarity index 100% rename from relayer-cli/src/commands/query/packet/ack.rs rename to crates/relayer-cli/src/commands/query/packet/ack.rs diff --git a/relayer-cli/src/commands/query/packet/acks.rs b/crates/relayer-cli/src/commands/query/packet/acks.rs similarity index 100% rename from relayer-cli/src/commands/query/packet/acks.rs rename to crates/relayer-cli/src/commands/query/packet/acks.rs diff --git a/relayer-cli/src/commands/query/packet/commitment.rs b/crates/relayer-cli/src/commands/query/packet/commitment.rs similarity index 100% rename from relayer-cli/src/commands/query/packet/commitment.rs rename to crates/relayer-cli/src/commands/query/packet/commitment.rs diff --git a/relayer-cli/src/commands/query/packet/commitments.rs b/crates/relayer-cli/src/commands/query/packet/commitments.rs similarity index 100% rename from relayer-cli/src/commands/query/packet/commitments.rs rename to crates/relayer-cli/src/commands/query/packet/commitments.rs diff --git a/relayer-cli/src/commands/query/packet/pending.rs b/crates/relayer-cli/src/commands/query/packet/pending.rs similarity index 100% rename from relayer-cli/src/commands/query/packet/pending.rs rename to crates/relayer-cli/src/commands/query/packet/pending.rs diff --git a/relayer-cli/src/commands/query/packet/pending_acks.rs b/crates/relayer-cli/src/commands/query/packet/pending_acks.rs similarity index 100% rename from relayer-cli/src/commands/query/packet/pending_acks.rs rename to crates/relayer-cli/src/commands/query/packet/pending_acks.rs diff --git a/relayer-cli/src/commands/query/packet/pending_sends.rs b/crates/relayer-cli/src/commands/query/packet/pending_sends.rs similarity index 100% rename from relayer-cli/src/commands/query/packet/pending_sends.rs rename to crates/relayer-cli/src/commands/query/packet/pending_sends.rs diff --git a/relayer-cli/src/commands/query/transfer.rs b/crates/relayer-cli/src/commands/query/transfer.rs similarity index 100% rename from relayer-cli/src/commands/query/transfer.rs rename to crates/relayer-cli/src/commands/query/transfer.rs diff --git a/relayer-cli/src/commands/query/transfer/denom_trace.rs b/crates/relayer-cli/src/commands/query/transfer/denom_trace.rs similarity index 100% rename from relayer-cli/src/commands/query/transfer/denom_trace.rs rename to crates/relayer-cli/src/commands/query/transfer/denom_trace.rs diff --git a/relayer-cli/src/commands/query/tx.rs b/crates/relayer-cli/src/commands/query/tx.rs similarity index 100% rename from relayer-cli/src/commands/query/tx.rs rename to crates/relayer-cli/src/commands/query/tx.rs diff --git a/relayer-cli/src/commands/query/tx/events.rs b/crates/relayer-cli/src/commands/query/tx/events.rs similarity index 100% rename from relayer-cli/src/commands/query/tx/events.rs rename to crates/relayer-cli/src/commands/query/tx/events.rs diff --git a/relayer-cli/src/commands/start.rs b/crates/relayer-cli/src/commands/start.rs similarity index 100% rename from relayer-cli/src/commands/start.rs rename to crates/relayer-cli/src/commands/start.rs diff --git a/relayer-cli/src/commands/tx.rs b/crates/relayer-cli/src/commands/tx.rs similarity index 100% rename from relayer-cli/src/commands/tx.rs rename to crates/relayer-cli/src/commands/tx.rs diff --git a/relayer-cli/src/commands/tx/channel.rs b/crates/relayer-cli/src/commands/tx/channel.rs similarity index 100% rename from relayer-cli/src/commands/tx/channel.rs rename to crates/relayer-cli/src/commands/tx/channel.rs diff --git a/relayer-cli/src/commands/tx/client.rs b/crates/relayer-cli/src/commands/tx/client.rs similarity index 100% rename from relayer-cli/src/commands/tx/client.rs rename to crates/relayer-cli/src/commands/tx/client.rs diff --git a/relayer-cli/src/commands/tx/connection.rs b/crates/relayer-cli/src/commands/tx/connection.rs similarity index 100% rename from relayer-cli/src/commands/tx/connection.rs rename to crates/relayer-cli/src/commands/tx/connection.rs diff --git a/relayer-cli/src/commands/tx/packet.rs b/crates/relayer-cli/src/commands/tx/packet.rs similarity index 100% rename from relayer-cli/src/commands/tx/packet.rs rename to crates/relayer-cli/src/commands/tx/packet.rs diff --git a/relayer-cli/src/commands/tx/transfer.rs b/crates/relayer-cli/src/commands/tx/transfer.rs similarity index 100% rename from relayer-cli/src/commands/tx/transfer.rs rename to crates/relayer-cli/src/commands/tx/transfer.rs diff --git a/relayer-cli/src/commands/tx/upgrade.rs b/crates/relayer-cli/src/commands/tx/upgrade.rs similarity index 100% rename from relayer-cli/src/commands/tx/upgrade.rs rename to crates/relayer-cli/src/commands/tx/upgrade.rs diff --git a/relayer-cli/src/commands/update.rs b/crates/relayer-cli/src/commands/update.rs similarity index 100% rename from relayer-cli/src/commands/update.rs rename to crates/relayer-cli/src/commands/update.rs diff --git a/relayer-cli/src/commands/upgrade.rs b/crates/relayer-cli/src/commands/upgrade.rs similarity index 100% rename from relayer-cli/src/commands/upgrade.rs rename to crates/relayer-cli/src/commands/upgrade.rs diff --git a/relayer-cli/src/commands/version.rs b/crates/relayer-cli/src/commands/version.rs similarity index 100% rename from relayer-cli/src/commands/version.rs rename to crates/relayer-cli/src/commands/version.rs diff --git a/relayer-cli/src/components.rs b/crates/relayer-cli/src/components.rs similarity index 100% rename from relayer-cli/src/components.rs rename to crates/relayer-cli/src/components.rs diff --git a/relayer-cli/src/conclude.rs b/crates/relayer-cli/src/conclude.rs similarity index 100% rename from relayer-cli/src/conclude.rs rename to crates/relayer-cli/src/conclude.rs diff --git a/relayer-cli/src/config.rs b/crates/relayer-cli/src/config.rs similarity index 100% rename from relayer-cli/src/config.rs rename to crates/relayer-cli/src/config.rs diff --git a/relayer-cli/src/entry.rs b/crates/relayer-cli/src/entry.rs similarity index 100% rename from relayer-cli/src/entry.rs rename to crates/relayer-cli/src/entry.rs diff --git a/relayer-cli/src/error.rs b/crates/relayer-cli/src/error.rs similarity index 100% rename from relayer-cli/src/error.rs rename to crates/relayer-cli/src/error.rs diff --git a/relayer-cli/src/lib.rs b/crates/relayer-cli/src/lib.rs similarity index 100% rename from relayer-cli/src/lib.rs rename to crates/relayer-cli/src/lib.rs diff --git a/relayer-cli/src/prelude.rs b/crates/relayer-cli/src/prelude.rs similarity index 100% rename from relayer-cli/src/prelude.rs rename to crates/relayer-cli/src/prelude.rs diff --git a/relayer-cli/tests/acceptance.rs b/crates/relayer-cli/tests/acceptance.rs similarity index 100% rename from relayer-cli/tests/acceptance.rs rename to crates/relayer-cli/tests/acceptance.rs diff --git a/relayer-cli/tests/fixtures/two_chains.toml b/crates/relayer-cli/tests/fixtures/two_chains.toml similarity index 100% rename from relayer-cli/tests/fixtures/two_chains.toml rename to crates/relayer-cli/tests/fixtures/two_chains.toml diff --git a/relayer-rest/Cargo.toml b/crates/relayer-rest/Cargo.toml similarity index 92% rename from relayer-rest/Cargo.toml rename to crates/relayer-rest/Cargo.toml index 5815aab2c7..fd529c924d 100644 --- a/relayer-rest/Cargo.toml +++ b/crates/relayer-rest/Cargo.toml @@ -14,7 +14,7 @@ description = """ """ [dependencies] -ibc = { version = "0.19.0", path = "../modules" } +ibc = "0.19.0" ibc-relayer = { version = "0.19.0", path = "../relayer" } crossbeam-channel = "0.5" diff --git a/relayer-rest/README.md b/crates/relayer-rest/README.md similarity index 100% rename from relayer-rest/README.md rename to crates/relayer-rest/README.md diff --git a/relayer-rest/src/config.rs b/crates/relayer-rest/src/config.rs similarity index 100% rename from relayer-rest/src/config.rs rename to crates/relayer-rest/src/config.rs diff --git a/relayer-rest/src/handle.rs b/crates/relayer-rest/src/handle.rs similarity index 100% rename from relayer-rest/src/handle.rs rename to crates/relayer-rest/src/handle.rs diff --git a/relayer-rest/src/lib.rs b/crates/relayer-rest/src/lib.rs similarity index 100% rename from relayer-rest/src/lib.rs rename to crates/relayer-rest/src/lib.rs diff --git a/relayer-rest/src/server.rs b/crates/relayer-rest/src/server.rs similarity index 100% rename from relayer-rest/src/server.rs rename to crates/relayer-rest/src/server.rs diff --git a/relayer-rest/tests/mock.rs b/crates/relayer-rest/tests/mock.rs similarity index 100% rename from relayer-rest/tests/mock.rs rename to crates/relayer-rest/tests/mock.rs diff --git a/relayer/Cargo.toml b/crates/relayer/Cargo.toml similarity index 92% rename from relayer/Cargo.toml rename to crates/relayer/Cargo.toml index 28c70c0507..2b3f1b379d 100644 --- a/relayer/Cargo.toml +++ b/crates/relayer/Cargo.toml @@ -21,8 +21,8 @@ profiling = [] telemetry = ["ibc-telemetry"] [dependencies] -ibc = { version = "0.19.0", path = "../modules", features = ["mocks"] } -ibc-proto = { version = "0.20.1", path = "../proto" } +ibc = { version = "0.19.0", features = ["mocks"] } +ibc-proto = "0.20.1" ibc-telemetry = { version = "0.19.0", path = "../telemetry", optional = true } subtle-encoding = "0.5" @@ -91,7 +91,7 @@ default-features = false version = "=0.23.9" [dev-dependencies] -ibc = { version = "0.19.0", path = "../modules", features = ["mocks"] } +ibc = { version = "0.19.0", features = ["mocks"] } serial_test = "0.9.0" env_logger = "0.9.0" tracing-subscriber = { version = "0.3.14", features = ["fmt", "env-filter", "json"] } diff --git a/relayer/README.md b/crates/relayer/README.md similarity index 100% rename from relayer/README.md rename to crates/relayer/README.md diff --git a/relayer/src/account.rs b/crates/relayer/src/account.rs similarity index 100% rename from relayer/src/account.rs rename to crates/relayer/src/account.rs diff --git a/relayer/src/cache.rs b/crates/relayer/src/cache.rs similarity index 100% rename from relayer/src/cache.rs rename to crates/relayer/src/cache.rs diff --git a/relayer/src/chain.rs b/crates/relayer/src/chain.rs similarity index 100% rename from relayer/src/chain.rs rename to crates/relayer/src/chain.rs diff --git a/relayer/src/chain/client.rs b/crates/relayer/src/chain/client.rs similarity index 100% rename from relayer/src/chain/client.rs rename to crates/relayer/src/chain/client.rs diff --git a/relayer/src/chain/cosmos.rs b/crates/relayer/src/chain/cosmos.rs similarity index 100% rename from relayer/src/chain/cosmos.rs rename to crates/relayer/src/chain/cosmos.rs diff --git a/relayer/src/chain/cosmos/batch.rs b/crates/relayer/src/chain/cosmos/batch.rs similarity index 100% rename from relayer/src/chain/cosmos/batch.rs rename to crates/relayer/src/chain/cosmos/batch.rs diff --git a/relayer/src/chain/cosmos/client.rs b/crates/relayer/src/chain/cosmos/client.rs similarity index 100% rename from relayer/src/chain/cosmos/client.rs rename to crates/relayer/src/chain/cosmos/client.rs diff --git a/relayer/src/chain/cosmos/compatibility.rs b/crates/relayer/src/chain/cosmos/compatibility.rs similarity index 100% rename from relayer/src/chain/cosmos/compatibility.rs rename to crates/relayer/src/chain/cosmos/compatibility.rs diff --git a/relayer/src/chain/cosmos/encode.rs b/crates/relayer/src/chain/cosmos/encode.rs similarity index 100% rename from relayer/src/chain/cosmos/encode.rs rename to crates/relayer/src/chain/cosmos/encode.rs diff --git a/relayer/src/chain/cosmos/estimate.rs b/crates/relayer/src/chain/cosmos/estimate.rs similarity index 100% rename from relayer/src/chain/cosmos/estimate.rs rename to crates/relayer/src/chain/cosmos/estimate.rs diff --git a/relayer/src/chain/cosmos/gas.rs b/crates/relayer/src/chain/cosmos/gas.rs similarity index 100% rename from relayer/src/chain/cosmos/gas.rs rename to crates/relayer/src/chain/cosmos/gas.rs diff --git a/relayer/src/chain/cosmos/query.rs b/crates/relayer/src/chain/cosmos/query.rs similarity index 100% rename from relayer/src/chain/cosmos/query.rs rename to crates/relayer/src/chain/cosmos/query.rs diff --git a/relayer/src/chain/cosmos/query/account.rs b/crates/relayer/src/chain/cosmos/query/account.rs similarity index 100% rename from relayer/src/chain/cosmos/query/account.rs rename to crates/relayer/src/chain/cosmos/query/account.rs diff --git a/relayer/src/chain/cosmos/query/balance.rs b/crates/relayer/src/chain/cosmos/query/balance.rs similarity index 100% rename from relayer/src/chain/cosmos/query/balance.rs rename to crates/relayer/src/chain/cosmos/query/balance.rs diff --git a/relayer/src/chain/cosmos/query/denom_trace.rs b/crates/relayer/src/chain/cosmos/query/denom_trace.rs similarity index 100% rename from relayer/src/chain/cosmos/query/denom_trace.rs rename to crates/relayer/src/chain/cosmos/query/denom_trace.rs diff --git a/relayer/src/chain/cosmos/query/status.rs b/crates/relayer/src/chain/cosmos/query/status.rs similarity index 100% rename from relayer/src/chain/cosmos/query/status.rs rename to crates/relayer/src/chain/cosmos/query/status.rs diff --git a/relayer/src/chain/cosmos/query/tx.rs b/crates/relayer/src/chain/cosmos/query/tx.rs similarity index 100% rename from relayer/src/chain/cosmos/query/tx.rs rename to crates/relayer/src/chain/cosmos/query/tx.rs diff --git a/relayer/src/chain/cosmos/retry.rs b/crates/relayer/src/chain/cosmos/retry.rs similarity index 100% rename from relayer/src/chain/cosmos/retry.rs rename to crates/relayer/src/chain/cosmos/retry.rs diff --git a/relayer/src/chain/cosmos/simulate.rs b/crates/relayer/src/chain/cosmos/simulate.rs similarity index 100% rename from relayer/src/chain/cosmos/simulate.rs rename to crates/relayer/src/chain/cosmos/simulate.rs diff --git a/relayer/src/chain/cosmos/tx.rs b/crates/relayer/src/chain/cosmos/tx.rs similarity index 100% rename from relayer/src/chain/cosmos/tx.rs rename to crates/relayer/src/chain/cosmos/tx.rs diff --git a/relayer/src/chain/cosmos/types/account.rs b/crates/relayer/src/chain/cosmos/types/account.rs similarity index 100% rename from relayer/src/chain/cosmos/types/account.rs rename to crates/relayer/src/chain/cosmos/types/account.rs diff --git a/relayer/src/chain/cosmos/types/config.rs b/crates/relayer/src/chain/cosmos/types/config.rs similarity index 100% rename from relayer/src/chain/cosmos/types/config.rs rename to crates/relayer/src/chain/cosmos/types/config.rs diff --git a/relayer/src/chain/cosmos/types/events/channel.rs b/crates/relayer/src/chain/cosmos/types/events/channel.rs similarity index 100% rename from relayer/src/chain/cosmos/types/events/channel.rs rename to crates/relayer/src/chain/cosmos/types/events/channel.rs diff --git a/relayer/src/chain/cosmos/types/events/client.rs b/crates/relayer/src/chain/cosmos/types/events/client.rs similarity index 100% rename from relayer/src/chain/cosmos/types/events/client.rs rename to crates/relayer/src/chain/cosmos/types/events/client.rs diff --git a/relayer/src/chain/cosmos/types/events/mod.rs b/crates/relayer/src/chain/cosmos/types/events/mod.rs similarity index 100% rename from relayer/src/chain/cosmos/types/events/mod.rs rename to crates/relayer/src/chain/cosmos/types/events/mod.rs diff --git a/relayer/src/chain/cosmos/types/gas.rs b/crates/relayer/src/chain/cosmos/types/gas.rs similarity index 100% rename from relayer/src/chain/cosmos/types/gas.rs rename to crates/relayer/src/chain/cosmos/types/gas.rs diff --git a/relayer/src/chain/cosmos/types/mod.rs b/crates/relayer/src/chain/cosmos/types/mod.rs similarity index 100% rename from relayer/src/chain/cosmos/types/mod.rs rename to crates/relayer/src/chain/cosmos/types/mod.rs diff --git a/relayer/src/chain/cosmos/types/tx.rs b/crates/relayer/src/chain/cosmos/types/tx.rs similarity index 100% rename from relayer/src/chain/cosmos/types/tx.rs rename to crates/relayer/src/chain/cosmos/types/tx.rs diff --git a/relayer/src/chain/cosmos/version.rs b/crates/relayer/src/chain/cosmos/version.rs similarity index 100% rename from relayer/src/chain/cosmos/version.rs rename to crates/relayer/src/chain/cosmos/version.rs diff --git a/relayer/src/chain/cosmos/wait.rs b/crates/relayer/src/chain/cosmos/wait.rs similarity index 100% rename from relayer/src/chain/cosmos/wait.rs rename to crates/relayer/src/chain/cosmos/wait.rs diff --git a/relayer/src/chain/counterparty.rs b/crates/relayer/src/chain/counterparty.rs similarity index 100% rename from relayer/src/chain/counterparty.rs rename to crates/relayer/src/chain/counterparty.rs diff --git a/relayer/src/chain/endpoint.rs b/crates/relayer/src/chain/endpoint.rs similarity index 100% rename from relayer/src/chain/endpoint.rs rename to crates/relayer/src/chain/endpoint.rs diff --git a/relayer/src/chain/handle.rs b/crates/relayer/src/chain/handle.rs similarity index 100% rename from relayer/src/chain/handle.rs rename to crates/relayer/src/chain/handle.rs diff --git a/relayer/src/chain/handle/base.rs b/crates/relayer/src/chain/handle/base.rs similarity index 100% rename from relayer/src/chain/handle/base.rs rename to crates/relayer/src/chain/handle/base.rs diff --git a/relayer/src/chain/handle/cache.rs b/crates/relayer/src/chain/handle/cache.rs similarity index 100% rename from relayer/src/chain/handle/cache.rs rename to crates/relayer/src/chain/handle/cache.rs diff --git a/relayer/src/chain/handle/counting.rs b/crates/relayer/src/chain/handle/counting.rs similarity index 100% rename from relayer/src/chain/handle/counting.rs rename to crates/relayer/src/chain/handle/counting.rs diff --git a/relayer/src/chain/mock.rs b/crates/relayer/src/chain/mock.rs similarity index 100% rename from relayer/src/chain/mock.rs rename to crates/relayer/src/chain/mock.rs diff --git a/relayer/src/chain/requests.rs b/crates/relayer/src/chain/requests.rs similarity index 100% rename from relayer/src/chain/requests.rs rename to crates/relayer/src/chain/requests.rs diff --git a/relayer/src/chain/runtime.rs b/crates/relayer/src/chain/runtime.rs similarity index 100% rename from relayer/src/chain/runtime.rs rename to crates/relayer/src/chain/runtime.rs diff --git a/relayer/src/chain/tracking.rs b/crates/relayer/src/chain/tracking.rs similarity index 100% rename from relayer/src/chain/tracking.rs rename to crates/relayer/src/chain/tracking.rs diff --git a/relayer/src/channel.rs b/crates/relayer/src/channel.rs similarity index 100% rename from relayer/src/channel.rs rename to crates/relayer/src/channel.rs diff --git a/relayer/src/channel/error.rs b/crates/relayer/src/channel/error.rs similarity index 100% rename from relayer/src/channel/error.rs rename to crates/relayer/src/channel/error.rs diff --git a/relayer/src/channel/version.rs b/crates/relayer/src/channel/version.rs similarity index 100% rename from relayer/src/channel/version.rs rename to crates/relayer/src/channel/version.rs diff --git a/relayer/src/client_state.rs b/crates/relayer/src/client_state.rs similarity index 100% rename from relayer/src/client_state.rs rename to crates/relayer/src/client_state.rs diff --git a/relayer/src/config.rs b/crates/relayer/src/config.rs similarity index 100% rename from relayer/src/config.rs rename to crates/relayer/src/config.rs diff --git a/relayer/src/config/error.rs b/crates/relayer/src/config/error.rs similarity index 100% rename from relayer/src/config/error.rs rename to crates/relayer/src/config/error.rs diff --git a/relayer/src/config/filter.rs b/crates/relayer/src/config/filter.rs similarity index 100% rename from relayer/src/config/filter.rs rename to crates/relayer/src/config/filter.rs diff --git a/relayer/src/config/gas_multiplier.rs b/crates/relayer/src/config/gas_multiplier.rs similarity index 100% rename from relayer/src/config/gas_multiplier.rs rename to crates/relayer/src/config/gas_multiplier.rs diff --git a/relayer/src/config/proof_specs.rs b/crates/relayer/src/config/proof_specs.rs similarity index 100% rename from relayer/src/config/proof_specs.rs rename to crates/relayer/src/config/proof_specs.rs diff --git a/relayer/src/config/types.rs b/crates/relayer/src/config/types.rs similarity index 100% rename from relayer/src/config/types.rs rename to crates/relayer/src/config/types.rs diff --git a/relayer/src/connection.rs b/crates/relayer/src/connection.rs similarity index 100% rename from relayer/src/connection.rs rename to crates/relayer/src/connection.rs diff --git a/relayer/src/connection/error.rs b/crates/relayer/src/connection/error.rs similarity index 100% rename from relayer/src/connection/error.rs rename to crates/relayer/src/connection/error.rs diff --git a/relayer/src/consensus_state.rs b/crates/relayer/src/consensus_state.rs similarity index 100% rename from relayer/src/consensus_state.rs rename to crates/relayer/src/consensus_state.rs diff --git a/relayer/src/denom.rs b/crates/relayer/src/denom.rs similarity index 100% rename from relayer/src/denom.rs rename to crates/relayer/src/denom.rs diff --git a/relayer/src/error.rs b/crates/relayer/src/error.rs similarity index 100% rename from relayer/src/error.rs rename to crates/relayer/src/error.rs diff --git a/relayer/src/event.rs b/crates/relayer/src/event.rs similarity index 100% rename from relayer/src/event.rs rename to crates/relayer/src/event.rs diff --git a/relayer/src/event/bus.rs b/crates/relayer/src/event/bus.rs similarity index 100% rename from relayer/src/event/bus.rs rename to crates/relayer/src/event/bus.rs diff --git a/relayer/src/event/monitor.rs b/crates/relayer/src/event/monitor.rs similarity index 100% rename from relayer/src/event/monitor.rs rename to crates/relayer/src/event/monitor.rs diff --git a/relayer/src/event/monitor/error.rs b/crates/relayer/src/event/monitor/error.rs similarity index 100% rename from relayer/src/event/monitor/error.rs rename to crates/relayer/src/event/monitor/error.rs diff --git a/relayer/src/event/rpc.rs b/crates/relayer/src/event/rpc.rs similarity index 100% rename from relayer/src/event/rpc.rs rename to crates/relayer/src/event/rpc.rs diff --git a/relayer/src/extension_options.rs b/crates/relayer/src/extension_options.rs similarity index 100% rename from relayer/src/extension_options.rs rename to crates/relayer/src/extension_options.rs diff --git a/relayer/src/foreign_client.rs b/crates/relayer/src/foreign_client.rs similarity index 100% rename from relayer/src/foreign_client.rs rename to crates/relayer/src/foreign_client.rs diff --git a/relayer/src/keyring.rs b/crates/relayer/src/keyring.rs similarity index 100% rename from relayer/src/keyring.rs rename to crates/relayer/src/keyring.rs diff --git a/relayer/src/keyring/errors.rs b/crates/relayer/src/keyring/errors.rs similarity index 100% rename from relayer/src/keyring/errors.rs rename to crates/relayer/src/keyring/errors.rs diff --git a/relayer/src/keyring/pub_key.rs b/crates/relayer/src/keyring/pub_key.rs similarity index 100% rename from relayer/src/keyring/pub_key.rs rename to crates/relayer/src/keyring/pub_key.rs diff --git a/relayer/src/lib.rs b/crates/relayer/src/lib.rs similarity index 100% rename from relayer/src/lib.rs rename to crates/relayer/src/lib.rs diff --git a/relayer/src/light_client.rs b/crates/relayer/src/light_client.rs similarity index 100% rename from relayer/src/light_client.rs rename to crates/relayer/src/light_client.rs diff --git a/relayer/src/light_client/mock.rs b/crates/relayer/src/light_client/mock.rs similarity index 100% rename from relayer/src/light_client/mock.rs rename to crates/relayer/src/light_client/mock.rs diff --git a/relayer/src/light_client/tendermint.rs b/crates/relayer/src/light_client/tendermint.rs similarity index 100% rename from relayer/src/light_client/tendermint.rs rename to crates/relayer/src/light_client/tendermint.rs diff --git a/relayer/src/link.rs b/crates/relayer/src/link.rs similarity index 100% rename from relayer/src/link.rs rename to crates/relayer/src/link.rs diff --git a/relayer/src/link/cli.rs b/crates/relayer/src/link/cli.rs similarity index 100% rename from relayer/src/link/cli.rs rename to crates/relayer/src/link/cli.rs diff --git a/relayer/src/link/error.rs b/crates/relayer/src/link/error.rs similarity index 100% rename from relayer/src/link/error.rs rename to crates/relayer/src/link/error.rs diff --git a/relayer/src/link/operational_data.rs b/crates/relayer/src/link/operational_data.rs similarity index 100% rename from relayer/src/link/operational_data.rs rename to crates/relayer/src/link/operational_data.rs diff --git a/relayer/src/link/packet_events.rs b/crates/relayer/src/link/packet_events.rs similarity index 100% rename from relayer/src/link/packet_events.rs rename to crates/relayer/src/link/packet_events.rs diff --git a/relayer/src/link/pending.rs b/crates/relayer/src/link/pending.rs similarity index 100% rename from relayer/src/link/pending.rs rename to crates/relayer/src/link/pending.rs diff --git a/relayer/src/link/relay_path.rs b/crates/relayer/src/link/relay_path.rs similarity index 100% rename from relayer/src/link/relay_path.rs rename to crates/relayer/src/link/relay_path.rs diff --git a/relayer/src/link/relay_sender.rs b/crates/relayer/src/link/relay_sender.rs similarity index 100% rename from relayer/src/link/relay_sender.rs rename to crates/relayer/src/link/relay_sender.rs diff --git a/relayer/src/link/relay_summary.rs b/crates/relayer/src/link/relay_summary.rs similarity index 100% rename from relayer/src/link/relay_summary.rs rename to crates/relayer/src/link/relay_summary.rs diff --git a/relayer/src/link/tx_hashes.rs b/crates/relayer/src/link/tx_hashes.rs similarity index 100% rename from relayer/src/link/tx_hashes.rs rename to crates/relayer/src/link/tx_hashes.rs diff --git a/relayer/src/macros.rs b/crates/relayer/src/macros.rs similarity index 100% rename from relayer/src/macros.rs rename to crates/relayer/src/macros.rs diff --git a/relayer/src/misbehaviour.rs b/crates/relayer/src/misbehaviour.rs similarity index 100% rename from relayer/src/misbehaviour.rs rename to crates/relayer/src/misbehaviour.rs diff --git a/relayer/src/object.rs b/crates/relayer/src/object.rs similarity index 100% rename from relayer/src/object.rs rename to crates/relayer/src/object.rs diff --git a/relayer/src/path.rs b/crates/relayer/src/path.rs similarity index 100% rename from relayer/src/path.rs rename to crates/relayer/src/path.rs diff --git a/relayer/src/registry.rs b/crates/relayer/src/registry.rs similarity index 100% rename from relayer/src/registry.rs rename to crates/relayer/src/registry.rs diff --git a/relayer/src/rest.rs b/crates/relayer/src/rest.rs similarity index 100% rename from relayer/src/rest.rs rename to crates/relayer/src/rest.rs diff --git a/relayer/src/rest/error.rs b/crates/relayer/src/rest/error.rs similarity index 100% rename from relayer/src/rest/error.rs rename to crates/relayer/src/rest/error.rs diff --git a/relayer/src/rest/request.rs b/crates/relayer/src/rest/request.rs similarity index 100% rename from relayer/src/rest/request.rs rename to crates/relayer/src/rest/request.rs diff --git a/relayer/src/sdk_error.rs b/crates/relayer/src/sdk_error.rs similarity index 100% rename from relayer/src/sdk_error.rs rename to crates/relayer/src/sdk_error.rs diff --git a/relayer/src/spawn.rs b/crates/relayer/src/spawn.rs similarity index 100% rename from relayer/src/spawn.rs rename to crates/relayer/src/spawn.rs diff --git a/relayer/src/supervisor.rs b/crates/relayer/src/supervisor.rs similarity index 100% rename from relayer/src/supervisor.rs rename to crates/relayer/src/supervisor.rs diff --git a/relayer/src/supervisor/client_state_filter.rs b/crates/relayer/src/supervisor/client_state_filter.rs similarity index 100% rename from relayer/src/supervisor/client_state_filter.rs rename to crates/relayer/src/supervisor/client_state_filter.rs diff --git a/relayer/src/supervisor/cmd.rs b/crates/relayer/src/supervisor/cmd.rs similarity index 100% rename from relayer/src/supervisor/cmd.rs rename to crates/relayer/src/supervisor/cmd.rs diff --git a/relayer/src/supervisor/dump_state.rs b/crates/relayer/src/supervisor/dump_state.rs similarity index 100% rename from relayer/src/supervisor/dump_state.rs rename to crates/relayer/src/supervisor/dump_state.rs diff --git a/relayer/src/supervisor/error.rs b/crates/relayer/src/supervisor/error.rs similarity index 100% rename from relayer/src/supervisor/error.rs rename to crates/relayer/src/supervisor/error.rs diff --git a/relayer/src/supervisor/scan.rs b/crates/relayer/src/supervisor/scan.rs similarity index 100% rename from relayer/src/supervisor/scan.rs rename to crates/relayer/src/supervisor/scan.rs diff --git a/relayer/src/supervisor/spawn.rs b/crates/relayer/src/supervisor/spawn.rs similarity index 100% rename from relayer/src/supervisor/spawn.rs rename to crates/relayer/src/supervisor/spawn.rs diff --git a/relayer/src/telemetry.rs b/crates/relayer/src/telemetry.rs similarity index 100% rename from relayer/src/telemetry.rs rename to crates/relayer/src/telemetry.rs diff --git a/relayer/src/transfer.rs b/crates/relayer/src/transfer.rs similarity index 100% rename from relayer/src/transfer.rs rename to crates/relayer/src/transfer.rs diff --git a/relayer/src/upgrade_chain.rs b/crates/relayer/src/upgrade_chain.rs similarity index 100% rename from relayer/src/upgrade_chain.rs rename to crates/relayer/src/upgrade_chain.rs diff --git a/relayer/src/util.rs b/crates/relayer/src/util.rs similarity index 100% rename from relayer/src/util.rs rename to crates/relayer/src/util.rs diff --git a/relayer/src/util/block_on.rs b/crates/relayer/src/util/block_on.rs similarity index 100% rename from relayer/src/util/block_on.rs rename to crates/relayer/src/util/block_on.rs diff --git a/relayer/src/util/diff.rs b/crates/relayer/src/util/diff.rs similarity index 100% rename from relayer/src/util/diff.rs rename to crates/relayer/src/util/diff.rs diff --git a/relayer/src/util/iter.rs b/crates/relayer/src/util/iter.rs similarity index 100% rename from relayer/src/util/iter.rs rename to crates/relayer/src/util/iter.rs diff --git a/relayer/src/util/lock.rs b/crates/relayer/src/util/lock.rs similarity index 100% rename from relayer/src/util/lock.rs rename to crates/relayer/src/util/lock.rs diff --git a/relayer/src/util/pretty.rs b/crates/relayer/src/util/pretty.rs similarity index 100% rename from relayer/src/util/pretty.rs rename to crates/relayer/src/util/pretty.rs diff --git a/relayer/src/util/queue.rs b/crates/relayer/src/util/queue.rs similarity index 100% rename from relayer/src/util/queue.rs rename to crates/relayer/src/util/queue.rs diff --git a/relayer/src/util/retry.rs b/crates/relayer/src/util/retry.rs similarity index 100% rename from relayer/src/util/retry.rs rename to crates/relayer/src/util/retry.rs diff --git a/relayer/src/util/stream.rs b/crates/relayer/src/util/stream.rs similarity index 100% rename from relayer/src/util/stream.rs rename to crates/relayer/src/util/stream.rs diff --git a/relayer/src/util/task.rs b/crates/relayer/src/util/task.rs similarity index 100% rename from relayer/src/util/task.rs rename to crates/relayer/src/util/task.rs diff --git a/relayer/src/worker.rs b/crates/relayer/src/worker.rs similarity index 100% rename from relayer/src/worker.rs rename to crates/relayer/src/worker.rs diff --git a/relayer/src/worker/channel.rs b/crates/relayer/src/worker/channel.rs similarity index 100% rename from relayer/src/worker/channel.rs rename to crates/relayer/src/worker/channel.rs diff --git a/relayer/src/worker/client.rs b/crates/relayer/src/worker/client.rs similarity index 100% rename from relayer/src/worker/client.rs rename to crates/relayer/src/worker/client.rs diff --git a/relayer/src/worker/cmd.rs b/crates/relayer/src/worker/cmd.rs similarity index 100% rename from relayer/src/worker/cmd.rs rename to crates/relayer/src/worker/cmd.rs diff --git a/relayer/src/worker/connection.rs b/crates/relayer/src/worker/connection.rs similarity index 100% rename from relayer/src/worker/connection.rs rename to crates/relayer/src/worker/connection.rs diff --git a/relayer/src/worker/error.rs b/crates/relayer/src/worker/error.rs similarity index 100% rename from relayer/src/worker/error.rs rename to crates/relayer/src/worker/error.rs diff --git a/relayer/src/worker/handle.rs b/crates/relayer/src/worker/handle.rs similarity index 100% rename from relayer/src/worker/handle.rs rename to crates/relayer/src/worker/handle.rs diff --git a/relayer/src/worker/map.rs b/crates/relayer/src/worker/map.rs similarity index 100% rename from relayer/src/worker/map.rs rename to crates/relayer/src/worker/map.rs diff --git a/relayer/src/worker/packet.rs b/crates/relayer/src/worker/packet.rs similarity index 100% rename from relayer/src/worker/packet.rs rename to crates/relayer/src/worker/packet.rs diff --git a/relayer/src/worker/retry_strategy.rs b/crates/relayer/src/worker/retry_strategy.rs similarity index 100% rename from relayer/src/worker/retry_strategy.rs rename to crates/relayer/src/worker/retry_strategy.rs diff --git a/relayer/src/worker/wallet.rs b/crates/relayer/src/worker/wallet.rs similarity index 100% rename from relayer/src/worker/wallet.rs rename to crates/relayer/src/worker/wallet.rs diff --git a/relayer/tests/config/fixtures/relayer-seed.json b/crates/relayer/tests/config/fixtures/relayer-seed.json similarity index 100% rename from relayer/tests/config/fixtures/relayer-seed.json rename to crates/relayer/tests/config/fixtures/relayer-seed.json diff --git a/relayer/tests/config/fixtures/relayer_conf_example.toml b/crates/relayer/tests/config/fixtures/relayer_conf_example.toml similarity index 100% rename from relayer/tests/config/fixtures/relayer_conf_example.toml rename to crates/relayer/tests/config/fixtures/relayer_conf_example.toml diff --git a/telemetry/Cargo.toml b/crates/telemetry/Cargo.toml similarity index 94% rename from telemetry/Cargo.toml rename to crates/telemetry/Cargo.toml index 90c3246ab0..df1666e29b 100644 --- a/telemetry/Cargo.toml +++ b/crates/telemetry/Cargo.toml @@ -13,7 +13,7 @@ description = """ """ [dependencies] -ibc = { version = "0.19.0", path = "../modules" } +ibc = "0.19.0" crossbeam-channel = "0.5.5" once_cell = "1.14.0" diff --git a/telemetry/README.md b/crates/telemetry/README.md similarity index 100% rename from telemetry/README.md rename to crates/telemetry/README.md diff --git a/telemetry/src/lib.rs b/crates/telemetry/src/lib.rs similarity index 100% rename from telemetry/src/lib.rs rename to crates/telemetry/src/lib.rs diff --git a/telemetry/src/path_identifier.rs b/crates/telemetry/src/path_identifier.rs similarity index 100% rename from telemetry/src/path_identifier.rs rename to crates/telemetry/src/path_identifier.rs diff --git a/telemetry/src/server.rs b/crates/telemetry/src/server.rs similarity index 100% rename from telemetry/src/server.rs rename to crates/telemetry/src/server.rs diff --git a/telemetry/src/state.rs b/crates/telemetry/src/state.rs similarity index 100% rename from telemetry/src/state.rs rename to crates/telemetry/src/state.rs diff --git a/guide/src/quick-start/installation.md b/guide/src/quick-start/installation.md index faee2fbdf2..37b61ed1bc 100644 --- a/guide/src/quick-start/installation.md +++ b/guide/src/quick-start/installation.md @@ -115,7 +115,7 @@ git checkout {{#template ../templates/version}} ### Building with `cargo build` -This command builds all the crates from the [__`ibc-rs`__](https://github.com/informalsystems/ibc-rs) repository, namely: the [__`ibc`__](https://github.com/informalsystems/ibc-rs/tree/master/modules) modules crate, [__`ibc-relayer`__](https://github.com/informalsystems/ibc-rs/tree/master/relayer) crate, [__`ibc-proto`__](https://github.com/informalsystems/ibc-rs/tree/master/proto) crate, and the [__`ibc-relayer-cli`__](https://github.com/informalsystems/ibc-rs/tree/master/relayer-cli) crate. +This command builds all the crates from the [__`ibc-rs`__](https://github.com/informalsystems/ibc-rs) repository, namely: [__`ibc-relayer`__](https://github.com/informalsystems/ibc-rs/tree/master/relayer) crate and the [__`ibc-relayer-cli`__](https://github.com/informalsystems/ibc-rs/tree/master/relayer-cli) crate. The last of these crates contains the `hermes` binary. ```shell diff --git a/modules/Cargo.toml b/modules/Cargo.toml deleted file mode 100644 index 8c42b99694..0000000000 --- a/modules/Cargo.toml +++ /dev/null @@ -1,79 +0,0 @@ -[package] -name = "ibc" -version = "0.19.0" -edition = "2021" -license = "Apache-2.0" -readme = "README.md" -keywords = ["blockchain", "consensus", "cosmos", "ibc", "tendermint"] -repository = "https://github.com/informalsystems/ibc-rs" -authors = ["Informal Systems "] -rust-version = "1.60" -description = """ - Implementation of the Inter-Blockchain Communication Protocol (IBC). - This crate comprises the main data structures and on-chain logic. -""" - -[package.metadata.docs.rs] -all-features = true - -[features] -default = ["std"] -std = ["flex-error/std", "flex-error/eyre_tracer", "ibc-proto/std", "clock"] -clock = ["tendermint/clock", "time/std"] - -# 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", "std"] - -[dependencies] -# Proto definitions for all IBC-related interfaces, e.g., connections or channels. -ibc-proto = { version = "0.20.1", path = "../proto", default-features = false } -ics23 = { version = "=0.8.1", default-features = false, features = ["host-functions"] } -time = { version = ">=0.3.0, <0.3.12", default-features = false } -serde_derive = { version = "1.0.104", default-features = false } -serde = { version = "1.0", default-features = false } -serde_json = { version = "1", default-features = false } -erased-serde = { version = "0.3", default-features = false, features = ["alloc"] } -tracing = { version = "0.1.36", default-features = false } -prost = { version = "0.11", default-features = false } -bytes = { version = "1.2.1", default-features = false } -safe-regex = { version = "0.2.5", default-features = false } -subtle-encoding = { version = "0.5", default-features = false } -sha2 = { version = "0.10.5", default-features = false } -flex-error = { version = "0.4.4", default-features = false } -num-traits = { version = "0.2.15", default-features = false } -derive_more = { version = "0.99.17", default-features = false, features = ["from", "into", "display"] } -uint = { version = "0.9", default-features = false } -primitive-types = { version = "0.11.1", default-features = false, features = ["serde_no_std"] } -dyn-clone = "1.0.8" - -[dependencies.tendermint] -version = "=0.23.9" -default-features = false - -[dependencies.tendermint-proto] -version = "=0.23.9" -default-features = false - -[dependencies.tendermint-light-client-verifier] -version = "=0.23.9" -default-features = false - -[dependencies.tendermint-testgen] -version = "=0.23.9" -optional = true -default-features = false - -[dev-dependencies] -env_logger = "0.9.0" -tracing-subscriber = { version = "0.3.14", features = ["fmt", "env-filter", "json"]} -test-log = { version = "0.2.10", features = ["trace"] } -modelator = "0.4.2" -sha2 = { version = "0.10.5" } -tendermint-rpc = { version = "=0.23.9", features = ["http-client", "websocket-client"] } -tendermint-testgen = { version = "=0.23.9" } # Needed for generating (synthetic) light blocks. - -[[test]] -name = "mbt" -path = "tests/mbt.rs" -required-features = ["mocks"] diff --git a/modules/README.md b/modules/README.md deleted file mode 100644 index 00a29c55dd..0000000000 --- a/modules/README.md +++ /dev/null @@ -1,76 +0,0 @@ -# IBC module - -[![Crate][crate-image]][crate-link] -[![Docs][docs-image]][docs-link] -[![Build Status][build-image]][build-link] -[![End to End testing][e2e-image]][e2e-link] -[![Apache 2.0 Licensed][license-image]][license-link] -![Rust Stable][rustc-image] -![Rust 1.51+][rustc-version] - - -See the [ibc-rs] repo root for more detailed information on how this crate can be used. - - -Implementation of the Inter-Blockchain Communication Protocol ([IBC]) module. - -## Documentation - -See documentation on [docs.rs][docs-link]. - -## Divergence from the Interchain Standards (ICS) -This crate diverges from the [ICS specification](https://github.com/cosmos/ibc) in a number of ways. See below for more details. - -### Module system: no support for untrusted modules -ICS 24 (Host Requirements) gives the [following requirement](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#module-system) about the module system that the host state machine must support: - -> The host state machine must support a module system, whereby self-contained, potentially mutually distrusted packages of code can safely execute on the same ledger [...]. - -**This crate currently does not support mutually distrusted packages**. That is, modules on the host state machine are assumed to be fully trusted. In practice, this means that every module has either been written by the host state machine developers, or fully vetted by them. - -### Port system: No object capability system -ICS 5 (Port Allocation) requires the host system to support either object-capability reference or source authentication for modules. - -> In the former object-capability case, the IBC handler must have the ability to generate object-capabilities, unique, opaque references which can be passed to a module and will not be duplicable by other modules. [...] -> In the latter source authentication case, the IBC handler must have the ability to securely read the source identifier of the calling module, a unique string for each module in the host state machine, which cannot be altered by the module or faked by another module. - -**This crate currently requires neither of the host system**. Since modules are assumed to be trusted, there is no need for this object capability system that protects resources for potentially malicious modules. - -For more background on this, see [this issue](https://github.com/informalsystems/ibc-rs/issues/2159). - -### Port system: transferring and releasing a port -ICS 5 (Port Allocation) requires the IBC handler to permit [transferring ownership of a port](https://github.com/cosmos/ibc/tree/master/spec/core/ics-005-port-allocation#transferring-ownership-of-a-port) and [releasing a port](https://github.com/cosmos/ibc/tree/master/spec/core/ics-005-port-allocation#releasing-a-port). - -We currently support neither. - -## License - -Copyright © 2021 Informal Systems Inc. and ibc-rs authors. - -Licensed under the Apache License, Version 2.0 (the "License"); you may not use the files in this repository except in compliance with the License. You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. - -[//]: # (badges) - -[crate-image]: https://img.shields.io/crates/v/ibc.svg -[crate-link]: https://crates.io/crates/ibc -[docs-image]: https://docs.rs/ibc/badge.svg -[docs-link]: https://docs.rs/ibc/ - -[build-image]: https://github.com/informalsystems/ibc-rs/workflows/Rust/badge.svg -[build-link]: https://github.com/informalsystems/ibc-rs/actions?query=workflow%3ARust -[e2e-image]: https://github.com/informalsystems/ibc-rs/workflows/End%20to%20End%20testing/badge.svg -[e2e-link]: https://github.com/informalsystems/ibc-rs/actions?query=workflow%3A%22End+to+End+testing%22 - -[license-image]: https://img.shields.io/badge/license-Apache2.0-blue.svg -[license-link]: https://github.com/informalsystems/ibc-rs/blob/master/LICENSE -[rustc-image]: https://img.shields.io/badge/rustc-stable-blue.svg -[rustc-version]: https://img.shields.io/badge/rustc-1.51+-blue.svg - -[//]: # (general links) - -[ibc-rs]: https://github.com/informalsystems/ibc-rs -[IBC]: https://github.com/cosmos/ibc diff --git a/modules/src/applications/mod.rs b/modules/src/applications/mod.rs deleted file mode 100644 index 6de19dfe0d..0000000000 --- a/modules/src/applications/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -//! Various packet encoding semantics which underpin the various types of transactions. - -pub mod transfer; diff --git a/modules/src/applications/transfer/acknowledgement.rs b/modules/src/applications/transfer/acknowledgement.rs deleted file mode 100644 index a7a19b5ed1..0000000000 --- a/modules/src/applications/transfer/acknowledgement.rs +++ /dev/null @@ -1,98 +0,0 @@ -use core::fmt::{Display, Error as FmtError, Formatter}; - -use serde::{Deserialize, Serialize}; - -use super::error::Error; -use crate::core::ics26_routing::context::Acknowledgement as AckTrait; -use crate::prelude::*; - -/// A string constant included in error acknowledgements. -/// NOTE: Changing this const is state machine breaking as acknowledgements are written into state -pub const ACK_ERR_STR: &str = "error handling packet on destination chain: see events for details"; - -/// A successful acknowledgement, equivalent to `base64::encode(0x01)`. -pub const ACK_SUCCESS_B64: &str = "AQ=="; - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub enum ConstAckSuccess { - #[serde(rename = "AQ==")] - Success, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub enum Acknowledgement { - /// Successful Acknowledgement - /// e.g. `{"result":"AQ=="}` - #[serde(rename = "result")] - Success(ConstAckSuccess), - /// Error Acknowledgement - /// e.g. `{"error":"cannot unmarshal ICS-20 transfer packet data"}` - #[serde(rename = "error")] - Error(String), -} - -impl Acknowledgement { - pub fn success() -> Self { - Self::Success(ConstAckSuccess::Success) - } - - pub fn from_error(err: Error) -> Self { - Self::Error(format!("{}: {}", ACK_ERR_STR, err)) - } -} - -impl AsRef<[u8]> for Acknowledgement { - fn as_ref(&self) -> &[u8] { - match self { - Acknowledgement::Success(_) => ACK_SUCCESS_B64.as_bytes(), - Acknowledgement::Error(s) => s.as_bytes(), - } - } -} - -impl Display for Acknowledgement { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - match self { - Acknowledgement::Success(_) => write!(f, "{}", ACK_SUCCESS_B64), - Acknowledgement::Error(err_str) => write!(f, "{}", err_str), - } - } -} - -impl AckTrait for Acknowledgement {} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_ack_ser() { - fn ser_json_assert_eq(ack: Acknowledgement, json_str: &str) { - let ser = serde_json::to_string(&ack).unwrap(); - assert_eq!(ser, json_str) - } - - ser_json_assert_eq(Acknowledgement::success(), r#"{"result":"AQ=="}"#); - ser_json_assert_eq( - Acknowledgement::Error("cannot unmarshal ICS-20 transfer packet data".to_owned()), - r#"{"error":"cannot unmarshal ICS-20 transfer packet data"}"#, - ); - } - - #[test] - fn test_ack_de() { - fn de_json_assert_eq(json_str: &str, ack: Acknowledgement) { - let de = serde_json::from_str::(json_str).unwrap(); - assert_eq!(de, ack) - } - - de_json_assert_eq(r#"{"result":"AQ=="}"#, Acknowledgement::success()); - de_json_assert_eq( - r#"{"error":"cannot unmarshal ICS-20 transfer packet data"}"#, - Acknowledgement::Error("cannot unmarshal ICS-20 transfer packet data".to_owned()), - ); - - assert!(serde_json::from_str::(r#"{"result":"AQ="}"#).is_err()); - assert!(serde_json::from_str::(r#"{"success":"AQ=="}"#).is_err()); - } -} diff --git a/modules/src/applications/transfer/amount.rs b/modules/src/applications/transfer/amount.rs deleted file mode 100644 index c250e91901..0000000000 --- a/modules/src/applications/transfer/amount.rs +++ /dev/null @@ -1,37 +0,0 @@ -use core::str::FromStr; -use derive_more::{Display, From, Into}; -use serde::{Deserialize, Serialize}; - -use super::error::Error; -use crate::bigint::U256; - -/// A type for representing token transfer amounts. -#[derive( - Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize, Display, From, Into, -)] -pub struct Amount(U256); - -impl Amount { - pub fn checked_add(self, rhs: Self) -> Option { - self.0.checked_add(rhs.0).map(Self) - } - - pub fn checked_sub(self, rhs: Self) -> Option { - self.0.checked_sub(rhs.0).map(Self) - } -} - -impl FromStr for Amount { - type Err = Error; - - fn from_str(s: &str) -> Result { - let amount = U256::from_dec_str(s).map_err(Error::invalid_amount)?; - Ok(Self(amount)) - } -} - -impl From for Amount { - fn from(v: u64) -> Self { - Self(v.into()) - } -} diff --git a/modules/src/applications/transfer/coin.rs b/modules/src/applications/transfer/coin.rs deleted file mode 100644 index b6581c6fd3..0000000000 --- a/modules/src/applications/transfer/coin.rs +++ /dev/null @@ -1,157 +0,0 @@ -use core::fmt::{Display, Error as FmtError, Formatter}; -use core::str::{from_utf8, FromStr}; -use ibc_proto::cosmos::base::v1beta1::Coin as ProtoCoin; -use safe_regex::regex; -use serde::{Deserialize, Serialize}; - -use super::amount::Amount; -use super::denom::{BaseDenom, PrefixedDenom}; -use super::error::Error; -use crate::prelude::*; -use crate::serializers::serde_string; - -/// A `Coin` type with fully qualified `PrefixedDenom`. -pub type PrefixedCoin = Coin; - -/// A `Coin` type with an unprefixed denomination. -pub type BaseCoin = Coin; - -pub type RawCoin = Coin; - -/// Coin defines a token with a denomination and an amount. -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct Coin { - /// Denomination - pub denom: D, - /// Amount - #[serde(with = "serde_string")] - pub amount: Amount, -} - -impl Coin -where - D::Err: Into, -{ - pub fn from_string_list(coin_str: &str) -> Result, Error> { - coin_str.split(',').map(FromStr::from_str).collect() - } -} - -impl FromStr for Coin -where - D::Err: Into, -{ - type Err = Error; - - #[allow(clippy::assign_op_pattern)] - fn from_str(coin_str: &str) -> Result { - // Denominations can be 3 ~ 128 characters long and support letters, followed by either - // a letter, a number or a separator ('/', ':', '.', '_' or '-'). - // Loosely copy the regex from here: - // https://github.com/cosmos/cosmos-sdk/blob/v0.45.5/types/coin.go#L760-L762 - let matcher = regex!(br"([0-9]+)([a-zA-Z0-9/:\\._\x2d]+)"); - - let (m1, m2) = matcher - .match_slices(coin_str.as_bytes()) - .ok_or_else(|| Error::invalid_coin(coin_str.to_string()))?; - - let amount = from_utf8(m1).map_err(Error::utf8_decode)?.parse()?; - - let denom = from_utf8(m2) - .map_err(Error::utf8_decode)? - .parse() - .map_err(Into::into)?; - - Ok(Coin { amount, denom }) - } -} - -impl TryFrom for Coin -where - D::Err: Into, -{ - type Error = Error; - - fn try_from(proto: ProtoCoin) -> Result, Self::Error> { - let denom = D::from_str(&proto.denom).map_err(Into::into)?; - let amount = Amount::from_str(&proto.amount)?; - Ok(Self { denom, amount }) - } -} - -impl From> for ProtoCoin { - fn from(coin: Coin) -> ProtoCoin { - ProtoCoin { - denom: coin.denom.to_string(), - amount: coin.amount.to_string(), - } - } -} - -impl From for PrefixedCoin { - fn from(coin: BaseCoin) -> PrefixedCoin { - PrefixedCoin { - denom: coin.denom.into(), - amount: coin.amount, - } - } -} - -impl Display for Coin { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "{}{}", self.amount, self.denom) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_parse_raw_coin() -> Result<(), Error> { - { - let coin = RawCoin::from_str("123stake")?; - assert_eq!(coin.denom, "stake"); - assert_eq!(coin.amount, 123u64.into()); - } - - { - let coin = RawCoin::from_str("1a1")?; - assert_eq!(coin.denom, "a1"); - assert_eq!(coin.amount, 1u64.into()); - } - - { - let coin = RawCoin::from_str("0x1/:.\\_-")?; - assert_eq!(coin.denom, "x1/:.\\_-"); - assert_eq!(coin.amount, 0u64.into()); - } - - { - // `!` is not allowed - let res = RawCoin::from_str("0x!"); - assert!(res.is_err()); - } - - Ok(()) - } - - #[test] - fn test_parse_raw_coin_list() -> Result<(), Error> { - { - let coins = RawCoin::from_string_list("123stake,1a1,999den0m")?; - assert_eq!(coins.len(), 3); - - assert_eq!(coins[0].denom, "stake"); - assert_eq!(coins[0].amount, 123u64.into()); - - assert_eq!(coins[1].denom, "a1"); - assert_eq!(coins[1].amount, 1u64.into()); - - assert_eq!(coins[2].denom, "den0m"); - assert_eq!(coins[2].amount, 999u64.into()); - } - - Ok(()) - } -} diff --git a/modules/src/applications/transfer/context.rs b/modules/src/applications/transfer/context.rs deleted file mode 100644 index 8c9ca03790..0000000000 --- a/modules/src/applications/transfer/context.rs +++ /dev/null @@ -1,334 +0,0 @@ -use sha2::{Digest, Sha256}; - -use super::error::Error as Ics20Error; -use crate::applications::transfer::acknowledgement::Acknowledgement; -use crate::applications::transfer::events::{AckEvent, AckStatusEvent, RecvEvent, TimeoutEvent}; -use crate::applications::transfer::packet::PacketData; -use crate::applications::transfer::relay::on_ack_packet::process_ack_packet; -use crate::applications::transfer::relay::on_recv_packet::process_recv_packet; -use crate::applications::transfer::relay::on_timeout_packet::process_timeout_packet; -use crate::applications::transfer::{PrefixedCoin, PrefixedDenom, VERSION}; -use crate::core::ics04_channel::channel::{Counterparty, Order}; -use crate::core::ics04_channel::context::{ChannelKeeper, ChannelReader}; -use crate::core::ics04_channel::msgs::acknowledgement::Acknowledgement as GenericAcknowledgement; -use crate::core::ics04_channel::packet::Packet; -use crate::core::ics04_channel::Version; -use crate::core::ics24_host::identifier::{ChannelId, ConnectionId, PortId}; -use crate::core::ics26_routing::context::{ModuleOutputBuilder, OnRecvPacketAck}; -use crate::prelude::*; -use crate::signer::Signer; - -pub trait Ics20Keeper: - ChannelKeeper + BankKeeper::AccountId> -{ - type AccountId; -} - -pub trait Ics20Reader: ChannelReader { - type AccountId: TryFrom; - - /// get_port returns the portID for the transfer module. - fn get_port(&self) -> Result; - - /// Returns the escrow account id for a port and channel combination - fn get_channel_escrow_address( - &self, - port_id: &PortId, - channel_id: &ChannelId, - ) -> Result<::AccountId, Ics20Error>; - - /// Returns true iff send is enabled. - fn is_send_enabled(&self) -> bool; - - /// Returns true iff receive is enabled. - fn is_receive_enabled(&self) -> bool; - - /// Returns a hash of the prefixed denom. - /// Implement only if the host chain supports hashed denominations. - fn denom_hash_string(&self, _denom: &PrefixedDenom) -> Option { - None - } -} - -// https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-028-public-key-addresses.md -pub fn cosmos_adr028_escrow_address(port_id: &PortId, channel_id: &ChannelId) -> Vec { - let contents = format!("{}/{}", port_id, channel_id); - - let mut hasher = Sha256::new(); - hasher.update(VERSION.as_bytes()); - hasher.update([0]); - hasher.update(contents.as_bytes()); - - let mut hash = hasher.finalize().to_vec(); - hash.truncate(20); - hash -} - -pub trait BankKeeper { - type AccountId; - - /// This function should enable sending ibc fungible tokens from one account to another - fn send_coins( - &mut self, - from: &Self::AccountId, - to: &Self::AccountId, - amt: &PrefixedCoin, - ) -> Result<(), Ics20Error>; - - /// This function to enable minting ibc tokens to a user account - fn mint_coins( - &mut self, - account: &Self::AccountId, - amt: &PrefixedCoin, - ) -> Result<(), Ics20Error>; - - /// This function should enable burning of minted tokens in a user account - fn burn_coins( - &mut self, - account: &Self::AccountId, - amt: &PrefixedCoin, - ) -> Result<(), Ics20Error>; -} - -/// Captures all the dependencies which the ICS20 module requires to be able to dispatch and -/// process IBC messages. -pub trait Ics20Context: - Ics20Keeper::AccountId> - + Ics20Reader::AccountId> -{ - type AccountId: TryFrom; -} - -fn validate_transfer_channel_params( - ctx: &mut impl Ics20Context, - order: Order, - port_id: &PortId, - _channel_id: &ChannelId, - version: &Version, -) -> Result<(), Ics20Error> { - if order != Order::Unordered { - return Err(Ics20Error::channel_not_unordered(order)); - } - - let bound_port = ctx.get_port()?; - if port_id != &bound_port { - return Err(Ics20Error::invalid_port(port_id.clone(), bound_port)); - } - - if version != &Version::ics20() { - return Err(Ics20Error::invalid_version(version.clone())); - } - - Ok(()) -} - -fn validate_counterparty_version(counterparty_version: &Version) -> Result<(), Ics20Error> { - if counterparty_version == &Version::ics20() { - Ok(()) - } else { - Err(Ics20Error::invalid_counterparty_version( - counterparty_version.clone(), - )) - } -} - -#[allow(clippy::too_many_arguments)] -pub fn on_chan_open_init( - ctx: &mut impl Ics20Context, - _output: &mut ModuleOutputBuilder, - order: Order, - _connection_hops: &[ConnectionId], - port_id: &PortId, - channel_id: &ChannelId, - _counterparty: &Counterparty, - version: &Version, -) -> Result<(), Ics20Error> { - validate_transfer_channel_params(ctx, order, port_id, channel_id, version) -} - -#[allow(clippy::too_many_arguments)] -pub fn on_chan_open_try( - ctx: &mut impl Ics20Context, - _output: &mut ModuleOutputBuilder, - order: Order, - _connection_hops: &[ConnectionId], - port_id: &PortId, - channel_id: &ChannelId, - _counterparty: &Counterparty, - version: &Version, - counterparty_version: &Version, -) -> Result { - validate_transfer_channel_params(ctx, order, port_id, channel_id, version)?; - validate_counterparty_version(counterparty_version)?; - Ok(Version::ics20()) -} - -pub fn on_chan_open_ack( - _ctx: &mut impl Ics20Context, - _output: &mut ModuleOutputBuilder, - _port_id: &PortId, - _channel_id: &ChannelId, - counterparty_version: &Version, -) -> Result<(), Ics20Error> { - validate_counterparty_version(counterparty_version)?; - Ok(()) -} - -pub fn on_chan_open_confirm( - _ctx: &mut impl Ics20Context, - _output: &mut ModuleOutputBuilder, - _port_id: &PortId, - _channel_id: &ChannelId, -) -> Result<(), Ics20Error> { - Ok(()) -} - -pub fn on_chan_close_init( - _ctx: &mut impl Ics20Context, - _output: &mut ModuleOutputBuilder, - _port_id: &PortId, - _channel_id: &ChannelId, -) -> Result<(), Ics20Error> { - Err(Ics20Error::cant_close_channel()) -} - -pub fn on_chan_close_confirm( - _ctx: &mut impl Ics20Context, - _output: &mut ModuleOutputBuilder, - _port_id: &PortId, - _channel_id: &ChannelId, -) -> Result<(), Ics20Error> { - Ok(()) -} - -pub fn on_recv_packet( - ctx: &Ctx, - output: &mut ModuleOutputBuilder, - packet: &Packet, - _relayer: &Signer, -) -> OnRecvPacketAck { - let data = match serde_json::from_slice::(&packet.data) { - Ok(data) => data, - Err(_) => { - return OnRecvPacketAck::Failed(Box::new(Acknowledgement::Error( - Ics20Error::packet_data_deserialization().to_string(), - ))) - } - }; - - let ack = match process_recv_packet(ctx, output, packet, data.clone()) { - Ok(write_fn) => OnRecvPacketAck::Successful(Box::new(Acknowledgement::success()), write_fn), - Err(e) => OnRecvPacketAck::Failed(Box::new(Acknowledgement::from_error(e))), - }; - - let recv_event = RecvEvent { - receiver: data.receiver, - denom: data.token.denom, - amount: data.token.amount, - success: ack.is_successful(), - }; - output.emit(recv_event.into()); - - ack -} - -pub fn on_acknowledgement_packet( - ctx: &mut impl Ics20Context, - output: &mut ModuleOutputBuilder, - packet: &Packet, - acknowledgement: &GenericAcknowledgement, - _relayer: &Signer, -) -> Result<(), Ics20Error> { - let data = serde_json::from_slice::(&packet.data) - .map_err(|_| Ics20Error::packet_data_deserialization())?; - - let acknowledgement = serde_json::from_slice::(acknowledgement.as_ref()) - .map_err(|_| Ics20Error::ack_deserialization())?; - - process_ack_packet(ctx, packet, &data, &acknowledgement)?; - - let ack_event = AckEvent { - receiver: data.receiver, - denom: data.token.denom, - amount: data.token.amount, - acknowledgement: acknowledgement.clone(), - }; - output.emit(ack_event.into()); - output.emit(AckStatusEvent { acknowledgement }.into()); - - Ok(()) -} - -pub fn on_timeout_packet( - ctx: &mut impl Ics20Context, - output: &mut ModuleOutputBuilder, - packet: &Packet, - _relayer: &Signer, -) -> Result<(), Ics20Error> { - let data = serde_json::from_slice::(&packet.data) - .map_err(|_| Ics20Error::packet_data_deserialization())?; - - process_timeout_packet(ctx, packet, &data)?; - - let timeout_event = TimeoutEvent { - refund_receiver: data.sender, - refund_denom: data.token.denom, - refund_amount: data.token.amount, - }; - output.emit(timeout_event.into()); - - Ok(()) -} - -#[cfg(test)] -pub(crate) mod test { - use subtle_encoding::bech32; - - use crate::applications::transfer::context::cosmos_adr028_escrow_address; - use crate::applications::transfer::error::Error as Ics20Error; - use crate::applications::transfer::msgs::transfer::MsgTransfer; - use crate::applications::transfer::relay::send_transfer::send_transfer; - use crate::applications::transfer::PrefixedCoin; - use crate::core::ics04_channel::error::Error; - use crate::handler::HandlerOutputBuilder; - use crate::prelude::*; - use crate::test_utils::DummyTransferModule; - - pub(crate) fn deliver( - ctx: &mut DummyTransferModule, - output: &mut HandlerOutputBuilder<()>, - msg: MsgTransfer, - ) -> Result<(), Error> { - send_transfer(ctx, output, msg).map_err(|e: Ics20Error| Error::app_module(e.to_string())) - } - - #[test] - fn test_cosmos_escrow_address() { - fn assert_eq_escrow_address(port_id: &str, channel_id: &str, address: &str) { - let port_id = port_id.parse().unwrap(); - let channel_id = channel_id.parse().unwrap(); - let gen_address = { - let addr = cosmos_adr028_escrow_address(&port_id, &channel_id); - bech32::encode("cosmos", addr) - }; - assert_eq!(gen_address, address.to_owned()) - } - - // addresses obtained using `gaiad query ibc-transfer escrow-address [port-id] [channel-id]` - assert_eq_escrow_address( - "transfer", - "channel-141", - "cosmos1x54ltnyg88k0ejmk8ytwrhd3ltm84xehrnlslf", - ); - assert_eq_escrow_address( - "transfer", - "channel-207", - "cosmos1ju6tlfclulxumtt2kglvnxduj5d93a64r5czge", - ); - assert_eq_escrow_address( - "transfer", - "channel-187", - "cosmos177x69sver58mcfs74x6dg0tv6ls4s3xmmcaw53", - ); - } -} diff --git a/modules/src/applications/transfer/denom.rs b/modules/src/applications/transfer/denom.rs deleted file mode 100644 index 07ead21047..0000000000 --- a/modules/src/applications/transfer/denom.rs +++ /dev/null @@ -1,389 +0,0 @@ -use core::fmt::{Display, Error as FmtError, Formatter}; -use core::str::FromStr; - -use derive_more::{Display, From}; -use ibc_proto::ibc::applications::transfer::v1::DenomTrace as RawDenomTrace; -use serde::{Deserialize, Serialize}; - -use super::error::Error; -use crate::core::ics24_host::identifier::{ChannelId, PortId}; -use crate::prelude::*; -use crate::serializers::serde_string; - -/// Base denomination type -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize, Display)] -#[serde(transparent)] -pub struct BaseDenom(String); - -impl FromStr for BaseDenom { - type Err = Error; - - fn from_str(s: &str) -> Result { - if s.trim().is_empty() { - Err(Error::empty_base_denom()) - } else { - Ok(BaseDenom(s.to_owned())) - } - } -} - -#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq)] -pub struct TracePrefix { - port_id: PortId, - channel_id: ChannelId, -} - -impl TracePrefix { - pub fn new(port_id: PortId, channel_id: ChannelId) -> Self { - Self { - port_id, - channel_id, - } - } -} - -impl Display for TracePrefix { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "{}/{}", self.port_id, self.channel_id) - } -} - -/// A full trace path modelled as a collection of `TracePrefix`s. -// Internally, the `TracePath` is modelled as a `Vec` but with the order reversed, i.e. -// "transfer/channel-0/transfer/channel-1/uatom" => `["transfer/channel-1", "transfer/channel-0"]` -// This is done for ease of addition/removal of prefixes. -#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord, From)] -pub struct TracePath(Vec); - -impl TracePath { - /// Returns true iff this path starts with the specified prefix - pub fn starts_with(&self, prefix: &TracePrefix) -> bool { - self.0.last().map(|p| p == prefix).unwrap_or(false) - } - - /// Removes the specified prefix from the path if there is a match, otherwise does nothing. - pub fn remove_prefix(&mut self, prefix: &TracePrefix) { - if self.starts_with(prefix) { - self.0.pop(); - } - } - - /// Adds the specified prefix to the path. - pub fn add_prefix(&mut self, prefix: TracePrefix) { - self.0.push(prefix) - } - - /// Returns true if the path is empty and false otherwise. - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } -} - -impl<'a> TryFrom> for TracePath { - type Error = Error; - - fn try_from(v: Vec<&'a str>) -> Result { - if v.len() % 2 != 0 { - return Err(Error::invalid_trace_length(v.len())); - } - - let mut trace = vec![]; - let id_pairs = v.chunks_exact(2).map(|paths| (paths[0], paths[1])); - for (pos, (port_id, channel_id)) in id_pairs.rev().enumerate() { - let port_id = - PortId::from_str(port_id).map_err(|e| Error::invalid_trace_port_id(pos, e))?; - let channel_id = ChannelId::from_str(channel_id) - .map_err(|e| Error::invalid_trace_channel_id(pos, e))?; - trace.push(TracePrefix { - port_id, - channel_id, - }); - } - - Ok(trace.into()) - } -} - -impl FromStr for TracePath { - type Err = Error; - - fn from_str(s: &str) -> Result { - let parts = { - let parts: Vec<&str> = s.split('/').collect(); - if parts.len() == 1 && parts[0].trim().is_empty() { - vec![] - } else { - parts - } - }; - parts.try_into() - } -} - -impl Display for TracePath { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - let path = self - .0 - .iter() - .rev() - .map(|prefix| prefix.to_string()) - .collect::>() - .join("/"); - write!(f, "{}", path) - } -} - -/// A type that contains the base denomination for ICS20 and the source tracing information path. -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct PrefixedDenom { - /// A series of `{port-id}/{channel-id}`s for tracing the source of the token. - #[serde(with = "serde_string")] - trace_path: TracePath, - /// Base denomination of the relayed fungible token. - base_denom: BaseDenom, -} - -impl PrefixedDenom { - /// Removes the specified prefix from the trace path if there is a match, otherwise does nothing. - pub fn remove_trace_prefix(&mut self, prefix: &TracePrefix) { - self.trace_path.remove_prefix(prefix) - } - - /// Adds the specified prefix to the trace path. - pub fn add_trace_prefix(&mut self, prefix: TracePrefix) { - self.trace_path.add_prefix(prefix) - } -} - -/// Returns true if the denomination originally came from the sender chain and -/// false otherwise. -/// -/// Note: It is better to think of the "source" chain as the chain that -/// escrows/unescrows the token, while the other chain mints/burns the tokens, -/// respectively. A chain being the "source" of a token does NOT mean it is the -/// original creator of the token (e.g. "uatom"), as "source" might suggest. -/// -/// This means that in any given transfer, a chain can very well be the source -/// of a token of which it is not the creator. For example, let -/// -/// A: sender chain in this transfer, port "transfer" and channel "c2b" (to B) -/// B: receiver chain in this transfer, port "transfer" and channel "c2a" (to A) -/// token denom: "transfer/someOtherChannel/someDenom" -/// -/// A, initiator of the transfer, needs to figure out if it should escrow the -/// tokens, or burn them. If B had originally sent the token to A in a previous -/// transfer, then A would have stored the token as "transfer/c2b/someDenom". -/// Now, A is sending to B, so to check if B is the source of the token, we need -/// to check if the token starts with "transfer/c2b". In this example, it -/// doesn't, so the token doesn't originate from B. A is considered the source, -/// even though it is not the creator of the token. Specifically, the token was -/// created by the chain at the other end of A's port "transfer" and channel -/// "someOtherChannel". -pub fn is_sender_chain_source( - source_port: PortId, - source_channel: ChannelId, - denom: &PrefixedDenom, -) -> bool { - !is_receiver_chain_source(source_port, source_channel, denom) -} - -/// Returns true if the denomination originally came from the receiving chain and false otherwise. -pub fn is_receiver_chain_source( - source_port: PortId, - source_channel: ChannelId, - denom: &PrefixedDenom, -) -> bool { - // For example, let - // A: sender chain in this transfer, port "transfer" and channel "c2b" (to B) - // B: receiver chain in this transfer, port "transfer" and channel "c2a" (to A) - // - // If B had originally sent the token in a previous tranfer, then A would have stored the token as - // "transfer/c2b/{token_denom}". Now, A is sending to B, so to check if B is the source of the token, - // we need to check if the token starts with "transfer/c2b". - let prefix = TracePrefix::new(source_port, source_channel); - denom.trace_path.starts_with(&prefix) -} - -impl FromStr for PrefixedDenom { - type Err = Error; - - fn from_str(s: &str) -> Result { - let mut parts: Vec<&str> = s.split('/').collect(); - let last_part = parts.pop().expect("split() returned an empty iterator"); - - let (base_denom, trace_path) = { - if last_part == s { - (BaseDenom::from_str(s)?, TracePath::default()) - } else { - let base_denom = BaseDenom::from_str(last_part)?; - let trace_path = TracePath::try_from(parts)?; - (base_denom, trace_path) - } - }; - - Ok(Self { - trace_path, - base_denom, - }) - } -} - -impl TryFrom for PrefixedDenom { - type Error = Error; - - fn try_from(value: RawDenomTrace) -> Result { - let base_denom = BaseDenom::from_str(&value.base_denom)?; - let trace_path = TracePath::from_str(&value.path)?; - Ok(Self { - trace_path, - base_denom, - }) - } -} - -impl From for RawDenomTrace { - fn from(value: PrefixedDenom) -> Self { - Self { - path: value.trace_path.to_string(), - base_denom: value.base_denom.to_string(), - } - } -} - -impl From for PrefixedDenom { - fn from(denom: BaseDenom) -> Self { - Self { - trace_path: Default::default(), - base_denom: denom, - } - } -} - -impl Display for PrefixedDenom { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - if self.trace_path.0.is_empty() { - write!(f, "{}", self.base_denom) - } else { - write!(f, "{}/{}", self.trace_path, self.base_denom) - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_denom_validation() -> Result<(), Error> { - assert!(BaseDenom::from_str("").is_err(), "empty base denom"); - assert!(BaseDenom::from_str("uatom").is_ok(), "valid base denom"); - assert!(PrefixedDenom::from_str("").is_err(), "empty denom trace"); - assert!( - PrefixedDenom::from_str("transfer/channel-0/").is_err(), - "empty base denom with trace" - ); - assert!(PrefixedDenom::from_str("/uatom").is_err(), "empty prefix"); - assert!(PrefixedDenom::from_str("//uatom").is_err(), "empty ids"); - assert!( - PrefixedDenom::from_str("transfer/").is_err(), - "single trace" - ); - assert!( - PrefixedDenom::from_str("transfer/atom").is_err(), - "single trace with base denom" - ); - assert!( - PrefixedDenom::from_str("transfer/channel-0/uatom").is_ok(), - "valid single trace info" - ); - assert!( - PrefixedDenom::from_str("transfer/channel-0/transfer/channel-1/uatom").is_ok(), - "valid multiple trace info" - ); - assert!( - PrefixedDenom::from_str("(transfer)/channel-0/uatom").is_err(), - "invalid port" - ); - assert!( - PrefixedDenom::from_str("transfer/(channel-0)/uatom").is_err(), - "invalid channel" - ); - - Ok(()) - } - - #[test] - fn test_denom_trace() -> Result<(), Error> { - assert_eq!( - PrefixedDenom::from_str("transfer/channel-0/uatom")?, - PrefixedDenom { - trace_path: "transfer/channel-0".parse()?, - base_denom: "uatom".parse()? - }, - "valid single trace info" - ); - assert_eq!( - PrefixedDenom::from_str("transfer/channel-0/transfer/channel-1/uatom")?, - PrefixedDenom { - trace_path: "transfer/channel-0/transfer/channel-1".parse()?, - base_denom: "uatom".parse()? - }, - "valid multiple trace info" - ); - - Ok(()) - } - - #[test] - fn test_denom_serde() -> Result<(), Error> { - let dt_str = "transfer/channel-0/uatom"; - let dt = PrefixedDenom::from_str(dt_str)?; - assert_eq!(dt.to_string(), dt_str, "valid single trace info"); - - let dt_str = "transfer/channel-0/transfer/channel-1/uatom"; - let dt = PrefixedDenom::from_str(dt_str)?; - assert_eq!(dt.to_string(), dt_str, "valid multiple trace info"); - - Ok(()) - } - - #[test] - fn test_trace_path() -> Result<(), Error> { - assert!(TracePath::from_str("").is_ok(), "empty trace path"); - assert!( - TracePath::from_str("transfer/uatom").is_err(), - "invalid trace path: bad ChannelId" - ); - assert!( - TracePath::from_str("transfer//uatom").is_err(), - "malformed trace path: missing ChannelId" - ); - assert!( - TracePath::from_str("transfer/channel-0/").is_err(), - "malformed trace path: trailing delimiter" - ); - - let prefix_1 = TracePrefix::new("transfer".parse().unwrap(), "channel-1".parse().unwrap()); - let prefix_2 = TracePrefix::new("transfer".parse().unwrap(), "channel-0".parse().unwrap()); - let mut trace_path = TracePath(vec![prefix_1.clone()]); - - trace_path.add_prefix(prefix_2.clone()); - assert_eq!( - TracePath::from_str("transfer/channel-0/transfer/channel-1")?, - trace_path - ); - assert_eq!( - TracePath(vec![prefix_1.clone(), prefix_2.clone()]), - trace_path - ); - - trace_path.remove_prefix(&prefix_2); - assert_eq!(TracePath::from_str("transfer/channel-1")?, trace_path); - assert_eq!(TracePath(vec![prefix_1.clone()]), trace_path); - - trace_path.remove_prefix(&prefix_1); - assert!(trace_path.is_empty()); - - Ok(()) - } -} diff --git a/modules/src/applications/transfer/error.rs b/modules/src/applications/transfer/error.rs deleted file mode 100644 index e13cb14fe1..0000000000 --- a/modules/src/applications/transfer/error.rs +++ /dev/null @@ -1,152 +0,0 @@ -use alloc::string::FromUtf8Error; - -use core::convert::Infallible; -use core::str::Utf8Error; -use flex_error::{define_error, DisplayOnly, TraceError}; -use ibc_proto::protobuf::Error as TendermintProtoError; -use subtle_encoding::Error as EncodingError; -use uint::FromDecStrErr; - -use crate::core::ics04_channel::channel::Order; -use crate::core::ics04_channel::error as channel_error; -use crate::core::ics04_channel::Version; -use crate::core::ics24_host::error::ValidationError; -use crate::core::ics24_host::identifier::{ChannelId, PortId}; -use crate::prelude::*; -use crate::signer::SignerError; - -define_error! { - #[derive(Debug, PartialEq, Eq)] - Error { - UnknowMessageTypeUrl - { url: String } - | e | { format_args!("unrecognized ICS-20 transfer message type URL {0}", e.url) }, - - Ics04Channel - [ channel_error::Error ] - |_ | { "Ics04 channel error" }, - - DestinationChannelNotFound - { port_id: PortId, channel_id: ChannelId } - | e | { format_args!("destination channel not found in the counterparty of port_id {0} and channel_id {1} ", e.port_id, e.channel_id) }, - - InvalidPortId - { context: String } - [ ValidationError ] - | _ | { "invalid port identifier" }, - - InvalidChannelId - { context: String } - [ ValidationError ] - | _ | { "invalid channel identifier" }, - - InvalidPacketTimeoutHeight - { context: String } - | _ | { "invalid packet timeout height value" }, - - InvalidPacketTimeoutTimestamp - { timestamp: u64 } - | _ | { "invalid packet timeout timestamp value" }, - - Utf8 - [ DisplayOnly ] - | _ | { "utf8 decoding error" }, - - EmptyBaseDenom - |_| { "base denomination is empty" }, - - InvalidTracePortId - { pos: usize } - [ ValidationError ] - | e | { format_args!("invalid port id in trace at position: {0}", e.pos) }, - - InvalidTraceChannelId - { pos: usize } - [ ValidationError ] - | e | { format_args!("invalid channel id in trace at position: {0}", e.pos) }, - - InvalidTraceLength - { len: usize } - | e | { format_args!("trace length must be even but got: {0}", e.len) }, - - InvalidAmount - [ TraceError ] - | _ | { "invalid amount" }, - - InvalidToken - | _ | { "invalid token" }, - - Signer - [ SignerError ] - | _ | { "failed to parse signer" }, - - MissingDenomIbcPrefix - | _ | { "missing 'ibc/' prefix in denomination" }, - - MalformedHashDenom - | _ | { "hashed denom must be of the form 'ibc/{Hash}'" }, - - ParseHex - [ TraceError ] - | _ | { "invalid hex string" }, - - ChannelNotUnordered - { order: Order } - | e | { format_args!("expected '{0}' channel, got '{1}'", Order::Unordered, e.order) }, - - InvalidVersion - { version: Version } - | e | { format_args!("expected version '{0}', got '{1}'", Version::ics20(), e.version) }, - - InvalidCounterpartyVersion - { version: Version } - | e | { format_args!("expected counterparty version '{0}', got '{1}'", Version::ics20(), e.version) }, - - CantCloseChannel - | _ | { "channel cannot be closed" }, - - PacketDataDeserialization - | _ | { "failed to deserialize packet data" }, - - AckDeserialization - | _ | { "failed to deserialize acknowledgement" }, - - ReceiveDisabled - | _ | { "receive is not enabled" }, - - SendDisabled - | _ | { "send is not enabled" }, - - ParseAccountFailure - | _ | { "failed to parse as AccountId" }, - - InvalidPort - { port_id: PortId, exp_port_id: PortId } - | e | { format_args!("invalid port: '{0}', expected '{1}'", e.port_id, e.exp_port_id) }, - - TraceNotFound - | _ | { "no trace associated with specified hash" }, - - DecodeRawMsg - [ TraceError ] - | _ | { "error decoding raw msg" }, - - UnknownMsgType - { msg_type: String } - | e | { format_args!("unknown msg type: {0}", e.msg_type) }, - - InvalidCoin - { coin: String } - | e | { format_args!("invalid coin string: {}", e.coin) }, - - Utf8Decode - [ TraceError ] - | _ | { "error decoding raw bytes as UTF8 string" }, - } -} - -impl From for Error { - fn from(e: Infallible) -> Self { - match e {} - } -} diff --git a/modules/src/applications/transfer/events.rs b/modules/src/applications/transfer/events.rs deleted file mode 100644 index 590638f448..0000000000 --- a/modules/src/applications/transfer/events.rs +++ /dev/null @@ -1,172 +0,0 @@ -use crate::applications::transfer::acknowledgement::Acknowledgement; -use crate::applications::transfer::{Amount, PrefixedDenom, MODULE_ID_STR}; -use crate::events::ModuleEvent; -use crate::prelude::*; -use crate::signer::Signer; - -const EVENT_TYPE_PACKET: &str = "fungible_token_packet"; -const EVENT_TYPE_TIMEOUT: &str = "timeout"; -const EVENT_TYPE_DENOM_TRACE: &str = "denomination_trace"; -const EVENT_TYPE_TRANSFER: &str = "ibc_transfer"; - -pub enum Event { - Recv(RecvEvent), - Ack(AckEvent), - AckStatus(AckStatusEvent), - Timeout(TimeoutEvent), - DenomTrace(DenomTraceEvent), - Transfer(TransferEvent), -} - -pub struct RecvEvent { - pub receiver: Signer, - pub denom: PrefixedDenom, - pub amount: Amount, - pub success: bool, -} - -impl From for ModuleEvent { - fn from(ev: RecvEvent) -> Self { - let RecvEvent { - receiver, - denom, - amount, - success, - } = ev; - Self { - kind: EVENT_TYPE_PACKET.to_string(), - module_name: MODULE_ID_STR.parse().expect("invalid ModuleId"), - attributes: vec![ - ("receiver", receiver).into(), - ("denom", denom).into(), - ("amount", amount).into(), - ("success", success).into(), - ], - } - } -} - -pub struct AckEvent { - pub receiver: Signer, - pub denom: PrefixedDenom, - pub amount: Amount, - pub acknowledgement: Acknowledgement, -} - -impl From for ModuleEvent { - fn from(ev: AckEvent) -> Self { - let AckEvent { - receiver, - denom, - amount, - acknowledgement, - } = ev; - Self { - kind: EVENT_TYPE_PACKET.to_string(), - module_name: MODULE_ID_STR.parse().expect("invalid ModuleId"), - attributes: vec![ - ("receiver", receiver).into(), - ("denom", denom).into(), - ("amount", amount).into(), - ("acknowledgement", acknowledgement).into(), - ], - } - } -} - -pub struct AckStatusEvent { - pub acknowledgement: Acknowledgement, -} - -impl From for ModuleEvent { - fn from(ev: AckStatusEvent) -> Self { - let AckStatusEvent { acknowledgement } = ev; - let mut event = Self { - kind: EVENT_TYPE_PACKET.to_string(), - module_name: MODULE_ID_STR.parse().expect("invalid ModuleId"), - attributes: vec![], - }; - let attr_label = match acknowledgement { - Acknowledgement::Success(_) => "success", - Acknowledgement::Error(_) => "error", - }; - event - .attributes - .push((attr_label, acknowledgement.to_string()).into()); - event - } -} - -pub struct TimeoutEvent { - pub refund_receiver: Signer, - pub refund_denom: PrefixedDenom, - pub refund_amount: Amount, -} - -impl From for ModuleEvent { - fn from(ev: TimeoutEvent) -> Self { - let TimeoutEvent { - refund_receiver, - refund_denom, - refund_amount, - } = ev; - Self { - kind: EVENT_TYPE_TIMEOUT.to_string(), - module_name: MODULE_ID_STR.parse().expect("invalid ModuleId"), - attributes: vec![ - ("refund_receiver", refund_receiver).into(), - ("refund_denom", refund_denom).into(), - ("refund_amount", refund_amount).into(), - ], - } - } -} - -pub struct DenomTraceEvent { - pub trace_hash: Option, - pub denom: PrefixedDenom, -} - -impl From for ModuleEvent { - fn from(ev: DenomTraceEvent) -> Self { - let DenomTraceEvent { trace_hash, denom } = ev; - let mut ev = Self { - kind: EVENT_TYPE_DENOM_TRACE.to_string(), - module_name: MODULE_ID_STR.parse().expect("invalid ModuleId"), - attributes: vec![("denom", denom).into()], - }; - if let Some(hash) = trace_hash { - ev.attributes.push(("trace_hash", hash).into()); - } - ev - } -} - -pub struct TransferEvent { - pub sender: Signer, - pub receiver: Signer, -} - -impl From for ModuleEvent { - fn from(ev: TransferEvent) -> Self { - let TransferEvent { sender, receiver } = ev; - Self { - kind: EVENT_TYPE_TRANSFER.to_string(), - module_name: MODULE_ID_STR.parse().expect("invalid ModuleId"), - attributes: vec![("sender", sender).into(), ("receiver", receiver).into()], - } - } -} - -impl From for ModuleEvent { - fn from(ev: Event) -> Self { - match ev { - Event::Recv(ev) => ev.into(), - Event::Ack(ev) => ev.into(), - Event::AckStatus(ev) => ev.into(), - Event::Timeout(ev) => ev.into(), - Event::DenomTrace(ev) => ev.into(), - Event::Transfer(ev) => ev.into(), - } - } -} diff --git a/modules/src/applications/transfer/mod.rs b/modules/src/applications/transfer/mod.rs deleted file mode 100644 index 36479d8936..0000000000 --- a/modules/src/applications/transfer/mod.rs +++ /dev/null @@ -1,27 +0,0 @@ -//! ICS 20: Token Transfer implementation allows for multi-chain denomination handling, which -//! constitutes a "fungible token transfer bridge module" between the IBC routing module and an -//! asset tracking module. -pub mod acknowledgement; -pub mod amount; -pub mod coin; -pub mod context; -pub mod denom; -pub mod error; -pub mod events; -pub mod msgs; -pub mod packet; -pub mod relay; - -pub use amount::*; -pub use coin::*; -pub use denom::*; - -/// Module identifier for the ICS20 application. -pub const MODULE_ID_STR: &str = "transfer"; - -/// The port identifier that the ICS20 applications -/// typically bind with. -pub const PORT_ID_STR: &str = "transfer"; - -/// ICS20 application current version. -pub const VERSION: &str = "ics20-1"; diff --git a/modules/src/applications/transfer/msgs.rs b/modules/src/applications/transfer/msgs.rs deleted file mode 100644 index 014e52f277..0000000000 --- a/modules/src/applications/transfer/msgs.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod transfer; diff --git a/modules/src/applications/transfer/msgs/transfer.rs b/modules/src/applications/transfer/msgs/transfer.rs deleted file mode 100644 index 1964d54df3..0000000000 --- a/modules/src/applications/transfer/msgs/transfer.rs +++ /dev/null @@ -1,194 +0,0 @@ -//! This is the definition of a transfer messages that an application submits to a chain. - -use crate::prelude::*; - -use ibc_proto::cosmos::base::v1beta1::Coin; -use ibc_proto::google::protobuf::Any; -use ibc_proto::ibc::applications::transfer::v1::MsgTransfer as RawMsgTransfer; -use ibc_proto::protobuf::Protobuf; - -use crate::applications::transfer::error::Error; -use crate::core::ics04_channel::timeout::TimeoutHeight; -use crate::core::ics24_host::identifier::{ChannelId, PortId}; -use crate::signer::Signer; -use crate::timestamp::Timestamp; -use crate::tx_msg::Msg; - -pub const TYPE_URL: &str = "/ibc.applications.transfer.v1.MsgTransfer"; - -/// Message used to build an ICS20 token transfer packet. -/// -/// Note that this message is not a packet yet, as it lacks the proper sequence -/// number, and destination port/channel. This is by design. The sender of the -/// packet, which might be the user of a command line application, should only -/// have to specify the information related to the transfer of the token, and -/// let the library figure out how to build the packet properly. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct MsgTransfer { - /// the port on which the packet will be sent - pub source_port: PortId, - /// the channel by which the packet will be sent - pub source_channel: ChannelId, - /// the tokens to be transferred - pub token: C, - /// the sender address - pub sender: Signer, - /// the recipient address on the destination chain - pub receiver: Signer, - /// Timeout height relative to the current block height. - /// The timeout is disabled when set to None. - pub timeout_height: TimeoutHeight, - /// Timeout timestamp relative to the current block timestamp. - /// The timeout is disabled when set to 0. - pub timeout_timestamp: Timestamp, -} - -impl Msg for MsgTransfer { - type ValidationError = Error; - type Raw = RawMsgTransfer; - - fn route(&self) -> String { - crate::keys::ROUTER_KEY.to_string() - } - - fn type_url(&self) -> String { - TYPE_URL.to_string() - } -} - -impl TryFrom for MsgTransfer { - type Error = Error; - - fn try_from(raw_msg: RawMsgTransfer) -> Result { - let timeout_timestamp = Timestamp::from_nanoseconds(raw_msg.timeout_timestamp) - .map_err(|_| Error::invalid_packet_timeout_timestamp(raw_msg.timeout_timestamp))?; - - let timeout_height: TimeoutHeight = raw_msg.timeout_height.try_into().map_err(|e| { - Error::invalid_packet_timeout_height(format!("invalid timeout height {}", e)) - })?; - - Ok(MsgTransfer { - source_port: raw_msg - .source_port - .parse() - .map_err(|e| Error::invalid_port_id(raw_msg.source_port.clone(), e))?, - source_channel: raw_msg - .source_channel - .parse() - .map_err(|e| Error::invalid_channel_id(raw_msg.source_channel.clone(), e))?, - token: raw_msg.token.ok_or_else(Error::invalid_token)?, - sender: raw_msg.sender.parse().map_err(Error::signer)?, - receiver: raw_msg.receiver.parse().map_err(Error::signer)?, - timeout_height, - timeout_timestamp, - }) - } -} - -impl From for RawMsgTransfer { - fn from(domain_msg: MsgTransfer) -> Self { - RawMsgTransfer { - source_port: domain_msg.source_port.to_string(), - source_channel: domain_msg.source_channel.to_string(), - token: Some(domain_msg.token), - sender: domain_msg.sender.to_string(), - receiver: domain_msg.receiver.to_string(), - timeout_height: domain_msg.timeout_height.into(), - timeout_timestamp: domain_msg.timeout_timestamp.nanoseconds(), - } - } -} - -impl Protobuf for MsgTransfer {} - -impl TryFrom for MsgTransfer { - type Error = Error; - - fn try_from(raw: Any) -> Result { - match raw.type_url.as_str() { - TYPE_URL => MsgTransfer::decode_vec(&raw.value).map_err(Error::decode_raw_msg), - _ => Err(Error::unknown_msg_type(raw.type_url)), - } - } -} - -impl From for Any { - fn from(msg: MsgTransfer) -> Self { - Self { - type_url: TYPE_URL.to_string(), - value: msg - .encode_vec() - .expect("encoding to `Any` from `MsgTranfer`"), - } - } -} - -#[cfg(test)] -pub mod test_util { - use core::ops::Add; - use core::time::Duration; - - use super::MsgTransfer; - use crate::applications::transfer::packet::PacketData; - use crate::applications::transfer::Coin; - use crate::bigint::U256; - use crate::core::ics04_channel::packet::{Packet, Sequence}; - use crate::core::ics04_channel::timeout::TimeoutHeight; - use crate::signer::Signer; - use crate::{ - applications::transfer::{BaseCoin, PrefixedCoin}, - core::ics24_host::identifier::{ChannelId, PortId}, - test_utils::get_dummy_bech32_account, - timestamp::Timestamp, - }; - - // Returns a dummy ICS20 `MsgTransfer`. If no `timeout_timestamp` is - // specified, a timestamp of 10 seconds in the future is used. - pub fn get_dummy_msg_transfer( - timeout_height: TimeoutHeight, - timeout_timestamp: Option, - ) -> MsgTransfer { - let address: Signer = get_dummy_bech32_account().as_str().parse().unwrap(); - MsgTransfer { - source_port: PortId::default(), - source_channel: ChannelId::default(), - token: BaseCoin { - denom: "uatom".parse().unwrap(), - amount: U256::from(10).into(), - } - .into(), - sender: address.clone(), - receiver: address, - timeout_timestamp: timeout_timestamp - .unwrap_or_else(|| Timestamp::now().add(Duration::from_secs(10)).unwrap()), - timeout_height, - } - } - - pub fn get_dummy_transfer_packet(msg: MsgTransfer, sequence: Sequence) -> Packet { - let coin = Coin { - denom: msg.token.denom.clone(), - amount: msg.token.amount, - }; - - let data = { - let data = PacketData { - token: coin, - sender: msg.sender.clone(), - receiver: msg.receiver.clone(), - }; - serde_json::to_vec(&data).expect("PacketData's infallible Serialize impl failed") - }; - - Packet { - sequence, - source_port: msg.source_port, - source_channel: msg.source_channel, - destination_port: PortId::default(), - destination_channel: ChannelId::default(), - data, - timeout_height: msg.timeout_height, - timeout_timestamp: msg.timeout_timestamp, - } - } -} diff --git a/modules/src/applications/transfer/packet.rs b/modules/src/applications/transfer/packet.rs deleted file mode 100644 index 587f7608b6..0000000000 --- a/modules/src/applications/transfer/packet.rs +++ /dev/null @@ -1,44 +0,0 @@ -use alloc::string::ToString; -use core::convert::TryFrom; -use core::str::FromStr; - -use ibc_proto::ibc::applications::transfer::v2::FungibleTokenPacketData as RawPacketData; -use serde::{Deserialize, Serialize}; - -use super::error::Error; -use super::{Amount, PrefixedCoin, PrefixedDenom}; -use crate::signer::Signer; - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(try_from = "RawPacketData", into = "RawPacketData")] -pub struct PacketData { - pub token: PrefixedCoin, - pub sender: Signer, - pub receiver: Signer, -} - -impl TryFrom for PacketData { - type Error = Error; - - fn try_from(raw_pkt_data: RawPacketData) -> Result { - // This denom may be prefixed or unprefixed. - let denom = PrefixedDenom::from_str(&raw_pkt_data.denom)?; - let amount = Amount::from_str(&raw_pkt_data.amount)?; - Ok(Self { - token: PrefixedCoin { denom, amount }, - sender: raw_pkt_data.sender.parse().map_err(Error::signer)?, - receiver: raw_pkt_data.receiver.parse().map_err(Error::signer)?, - }) - } -} - -impl From for RawPacketData { - fn from(pkt_data: PacketData) -> Self { - Self { - denom: pkt_data.token.denom.to_string(), - amount: pkt_data.token.amount.to_string(), - sender: pkt_data.sender.to_string(), - receiver: pkt_data.receiver.to_string(), - } - } -} diff --git a/modules/src/applications/transfer/relay.rs b/modules/src/applications/transfer/relay.rs deleted file mode 100644 index f5e0e166ce..0000000000 --- a/modules/src/applications/transfer/relay.rs +++ /dev/null @@ -1,40 +0,0 @@ -//! This module implements the processing logic for ICS20 (token transfer) message. -use crate::applications::transfer::context::Ics20Context; -use crate::applications::transfer::error::Error as Ics20Error; -use crate::applications::transfer::is_sender_chain_source; -use crate::applications::transfer::packet::PacketData; -use crate::core::ics04_channel::packet::Packet; -use crate::prelude::*; - -pub mod on_ack_packet; -pub mod on_recv_packet; -pub mod on_timeout_packet; -pub mod send_transfer; - -fn refund_packet_token( - ctx: &mut impl Ics20Context, - packet: &Packet, - data: &PacketData, -) -> Result<(), Ics20Error> { - let sender = data - .sender - .clone() - .try_into() - .map_err(|_| Ics20Error::parse_account_failure())?; - - if is_sender_chain_source( - packet.source_port.clone(), - packet.source_channel.clone(), - &data.token.denom, - ) { - // unescrow tokens back to sender - let escrow_address = - ctx.get_channel_escrow_address(&packet.source_port, &packet.source_channel)?; - - ctx.send_coins(&escrow_address, &sender, &data.token) - } - // mint vouchers back to sender - else { - ctx.mint_coins(&sender, &data.token) - } -} diff --git a/modules/src/applications/transfer/relay/on_ack_packet.rs b/modules/src/applications/transfer/relay/on_ack_packet.rs deleted file mode 100644 index a254de1fc9..0000000000 --- a/modules/src/applications/transfer/relay/on_ack_packet.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::applications::transfer::acknowledgement::Acknowledgement; -use crate::applications::transfer::context::Ics20Context; -use crate::applications::transfer::error::Error as Ics20Error; -use crate::applications::transfer::packet::PacketData; -use crate::applications::transfer::relay::refund_packet_token; -use crate::core::ics04_channel::packet::Packet; - -pub fn process_ack_packet( - ctx: &mut impl Ics20Context, - packet: &Packet, - data: &PacketData, - ack: &Acknowledgement, -) -> Result<(), Ics20Error> { - if matches!(ack, Acknowledgement::Error(_)) { - refund_packet_token(ctx, packet, data)?; - } - - Ok(()) -} diff --git a/modules/src/applications/transfer/relay/on_recv_packet.rs b/modules/src/applications/transfer/relay/on_recv_packet.rs deleted file mode 100644 index 7ebdc4d727..0000000000 --- a/modules/src/applications/transfer/relay/on_recv_packet.rs +++ /dev/null @@ -1,71 +0,0 @@ -use crate::applications::transfer::context::Ics20Context; -use crate::applications::transfer::error::Error as Ics20Error; -use crate::applications::transfer::events::DenomTraceEvent; -use crate::applications::transfer::packet::PacketData; -use crate::applications::transfer::{is_receiver_chain_source, TracePrefix}; -use crate::core::ics04_channel::packet::Packet; -use crate::core::ics26_routing::context::{ModuleOutputBuilder, WriteFn}; -use crate::prelude::*; - -pub fn process_recv_packet( - ctx: &Ctx, - output: &mut ModuleOutputBuilder, - packet: &Packet, - data: PacketData, -) -> Result, Ics20Error> { - if !ctx.is_receive_enabled() { - return Err(Ics20Error::receive_disabled()); - } - - let receiver_account = data - .receiver - .clone() - .try_into() - .map_err(|_| Ics20Error::parse_account_failure())?; - - if is_receiver_chain_source( - packet.source_port.clone(), - packet.source_channel.clone(), - &data.token.denom, - ) { - // sender chain is not the source, unescrow tokens - let prefix = TracePrefix::new(packet.source_port.clone(), packet.source_channel.clone()); - let coin = { - let mut c = data.token; - c.denom.remove_trace_prefix(&prefix); - c - }; - - let escrow_address = - ctx.get_channel_escrow_address(&packet.destination_port, &packet.destination_channel)?; - - Ok(Box::new(move |ctx| { - let ctx = ctx.downcast_mut::().unwrap(); - ctx.send_coins(&escrow_address, &receiver_account, &coin) - .map_err(|e| e.to_string()) - })) - } else { - // sender chain is the source, mint vouchers - let prefix = TracePrefix::new( - packet.destination_port.clone(), - packet.destination_channel.clone(), - ); - let coin = { - let mut c = data.token; - c.denom.add_trace_prefix(prefix); - c - }; - - let denom_trace_event = DenomTraceEvent { - trace_hash: ctx.denom_hash_string(&coin.denom), - denom: coin.denom.clone(), - }; - output.emit(denom_trace_event.into()); - - Ok(Box::new(move |ctx| { - let ctx = ctx.downcast_mut::().unwrap(); - ctx.mint_coins(&receiver_account, &coin) - .map_err(|e| e.to_string()) - })) - } -} diff --git a/modules/src/applications/transfer/relay/on_timeout_packet.rs b/modules/src/applications/transfer/relay/on_timeout_packet.rs deleted file mode 100644 index 192a3dd9b6..0000000000 --- a/modules/src/applications/transfer/relay/on_timeout_packet.rs +++ /dev/null @@ -1,13 +0,0 @@ -use crate::applications::transfer::context::Ics20Context; -use crate::applications::transfer::error::Error as Ics20Error; -use crate::applications::transfer::packet::PacketData; -use crate::applications::transfer::relay::refund_packet_token; -use crate::core::ics04_channel::packet::Packet; - -pub fn process_timeout_packet( - ctx: &mut impl Ics20Context, - packet: &Packet, - data: &PacketData, -) -> Result<(), Ics20Error> { - refund_packet_token(ctx, packet, data) -} diff --git a/modules/src/applications/transfer/relay/send_transfer.rs b/modules/src/applications/transfer/relay/send_transfer.rs deleted file mode 100644 index 36d8e18667..0000000000 --- a/modules/src/applications/transfer/relay/send_transfer.rs +++ /dev/null @@ -1,119 +0,0 @@ -use crate::applications::transfer::context::Ics20Context; -use crate::applications::transfer::error::Error; -use crate::applications::transfer::events::TransferEvent; -use crate::applications::transfer::msgs::transfer::MsgTransfer; -use crate::applications::transfer::packet::PacketData; -use crate::applications::transfer::{is_sender_chain_source, Coin, PrefixedCoin}; -use crate::core::ics04_channel::handler::send_packet::send_packet; -use crate::core::ics04_channel::packet::Packet; -use crate::events::ModuleEvent; -use crate::handler::{HandlerOutput, HandlerOutputBuilder}; -use crate::prelude::*; - -/// This function handles the transfer sending logic. -/// If this method returns an error, the runtime is expected to rollback all state modifications to -/// the `Ctx` caused by all messages from the transaction that this `msg` is a part of. -pub fn send_transfer( - ctx: &mut Ctx, - output: &mut HandlerOutputBuilder<()>, - msg: MsgTransfer, -) -> Result<(), Error> -where - Ctx: Ics20Context, - C: TryInto, -{ - if !ctx.is_send_enabled() { - return Err(Error::send_disabled()); - } - - let source_channel_end = ctx - .channel_end(&msg.source_port, &msg.source_channel) - .map_err(Error::ics04_channel)?; - - let destination_port = source_channel_end.counterparty().port_id().clone(); - let destination_channel = source_channel_end - .counterparty() - .channel_id() - .ok_or_else(|| { - Error::destination_channel_not_found( - msg.source_port.clone(), - msg.source_channel.clone(), - ) - })? - .clone(); - - // get the next sequence - let sequence = ctx - .get_next_sequence_send(&msg.source_port, &msg.source_channel) - .map_err(Error::ics04_channel)?; - - let token = msg.token.try_into().map_err(|_| Error::invalid_token())?; - let denom = token.denom.clone(); - let coin = Coin { - denom: denom.clone(), - amount: token.amount, - }; - - let sender = msg - .sender - .clone() - .try_into() - .map_err(|_| Error::parse_account_failure())?; - - if is_sender_chain_source(msg.source_port.clone(), msg.source_channel.clone(), &denom) { - let escrow_address = - ctx.get_channel_escrow_address(&msg.source_port, &msg.source_channel)?; - ctx.send_coins(&sender, &escrow_address, &coin)?; - } else { - ctx.burn_coins(&sender, &coin)?; - } - - let data = { - let data = PacketData { - token: coin, - sender: msg.sender.clone(), - receiver: msg.receiver.clone(), - }; - serde_json::to_vec(&data).expect("PacketData's infallible Serialize impl failed") - }; - - let packet = Packet { - sequence, - source_port: msg.source_port, - source_channel: msg.source_channel, - destination_port, - destination_channel, - data, - timeout_height: msg.timeout_height, - timeout_timestamp: msg.timeout_timestamp, - }; - - let HandlerOutput { - result, - log, - events, - } = send_packet(ctx, packet).map_err(Error::ics04_channel)?; - - ctx.store_packet_result(result) - .map_err(Error::ics04_channel)?; - - output.merge_output( - HandlerOutput::builder() - .with_log(log) - .with_events(events) - .with_result(()), - ); - - output.log(format!( - "IBC fungible token transfer: {} --({})--> {}", - msg.sender, token, msg.receiver - )); - - let transfer_event = TransferEvent { - sender: msg.sender, - receiver: msg.receiver, - }; - output.emit(ModuleEvent::from(transfer_event).into()); - - Ok(()) -} diff --git a/modules/src/bigint.rs b/modules/src/bigint.rs deleted file mode 100644 index 4b33e02332..0000000000 --- a/modules/src/bigint.rs +++ /dev/null @@ -1 +0,0 @@ -pub use primitive_types::U256; diff --git a/modules/src/clients/ics07_tendermint/client_state.rs b/modules/src/clients/ics07_tendermint/client_state.rs deleted file mode 100644 index c0e8f4d9d3..0000000000 --- a/modules/src/clients/ics07_tendermint/client_state.rs +++ /dev/null @@ -1,1193 +0,0 @@ -use crate::core::ics02_client::context::ClientReader; -use crate::core::ics03_connection::connection::ConnectionEnd; -use crate::core::ics04_channel::commitment::{AcknowledgementCommitment, PacketCommitment}; -use crate::core::ics04_channel::packet::Sequence; -use crate::core::ics23_commitment::commitment::{ - CommitmentPrefix, CommitmentProofBytes, CommitmentRoot, -}; -use crate::core::ics23_commitment::merkle::{apply_prefix, MerkleProof}; -use crate::core::ics24_host::path::{ - AcksPath, ChannelEndsPath, ClientConsensusStatePath, ClientStatePath, CommitmentsPath, - ConnectionsPath, ReceiptsPath, SeqRecvsPath, -}; -use crate::core::ics24_host::Path; -use crate::prelude::*; - -use core::convert::{TryFrom, TryInto}; -use core::time::Duration; - -use ibc_proto::google::protobuf::Any; -use ibc_proto::ibc::core::client::v1::Height as RawHeight; -use ibc_proto::ibc::core::commitment::v1::MerkleProof as RawMerkleProof; -use ibc_proto::ibc::lightclients::tendermint::v1::ClientState as RawTmClientState; -use ibc_proto::protobuf::Protobuf; -use prost::Message; -use serde::{Deserialize, Serialize}; -use tendermint_light_client_verifier::options::Options; -use tendermint_light_client_verifier::types::{TrustedBlockState, UntrustedBlockState}; -use tendermint_light_client_verifier::{ProdVerifier, Verdict, Verifier}; - -use crate::clients::ics07_tendermint::consensus_state::ConsensusState as TmConsensusState; -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, UpdatedState, UpgradeOptions as CoreUpgradeOptions, -}; -use crate::core::ics02_client::client_type::ClientType; -use crate::core::ics02_client::consensus_state::ConsensusState; -use crate::core::ics02_client::error::{Error as Ics02Error, ErrorDetail as Ics02ErrorDetail}; -use crate::core::ics02_client::trust_threshold::TrustThreshold; -use crate::core::ics04_channel::context::ChannelReader; -use crate::core::ics23_commitment::specs::ProofSpecs; -use crate::core::ics24_host::identifier::{ChainId, ChannelId, ClientId, ConnectionId, PortId}; -use crate::timestamp::{Timestamp, ZERO_DURATION}; -use crate::Height; - -pub const TENDERMINT_CLIENT_STATE_TYPE_URL: &str = "/ibc.lightclients.tendermint.v1.ClientState"; - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct ClientState { - pub chain_id: ChainId, - pub trust_level: TrustThreshold, - pub trusting_period: Duration, - pub unbonding_period: Duration, - pub max_clock_drift: Duration, - pub latest_height: Height, - pub proof_specs: ProofSpecs, - pub upgrade_path: Vec, - pub allow_update: AllowUpdate, - pub frozen_height: Option, - #[serde(skip)] - pub verifier: ProdVerifier, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct AllowUpdate { - pub after_expiry: bool, - pub after_misbehaviour: bool, -} - -impl ClientState { - #[allow(clippy::too_many_arguments)] - pub fn new( - chain_id: ChainId, - trust_level: TrustThreshold, - trusting_period: Duration, - unbonding_period: Duration, - max_clock_drift: Duration, - latest_height: Height, - proof_specs: ProofSpecs, - upgrade_path: Vec, - allow_update: AllowUpdate, - ) -> Result { - // Basic validation of trusting period and unbonding period: each should be non-zero. - if trusting_period <= Duration::new(0, 0) { - return Err(Error::invalid_trusting_period(format!( - "ClientState trusting period ({:?}) must be greater than zero", - trusting_period - ))); - } - - if unbonding_period <= Duration::new(0, 0) { - return Err(Error::invalid_unbonding_period(format!( - "ClientState unbonding period ({:?}) must be greater than zero", - unbonding_period - ))); - } - - if trusting_period >= unbonding_period { - return Err(Error::invalid_trusting_period(format!( - "ClientState trusting period ({:?}) must be smaller than unbonding period ({:?})", - trusting_period, unbonding_period, - ))); - } - - // `TrustThreshold` is guaranteed to be in the range `[0, 1)`, but a `TrustThreshold::ZERO` - // value is invalid in this context - if trust_level == TrustThreshold::ZERO { - return Err(Error::validation( - "ClientState trust-level cannot be zero".to_string(), - )); - } - - // Disallow empty proof-specs - if proof_specs.is_empty() { - return Err(Error::validation( - "ClientState proof-specs cannot be empty".to_string(), - )); - } - - Ok(Self { - chain_id, - trust_level, - trusting_period, - unbonding_period, - max_clock_drift, - latest_height, - proof_specs, - upgrade_path, - allow_update, - frozen_height: None, - verifier: ProdVerifier::default(), - }) - } - - pub fn latest_height(&self) -> Height { - self.latest_height - } - - pub fn with_header(self, h: TmHeader) -> Result { - Ok(ClientState { - latest_height: Height::new( - self.latest_height.revision_number(), - h.signed_header.header.height.into(), - ) - .map_err(|_| Error::invalid_header_height(h.signed_header.header.height.value()))?, - ..self - }) - } - - pub fn with_frozen_height(self, h: Height) -> Result { - Ok(Self { - frozen_height: Some(h), - ..self - }) - } - - /// Get the refresh time to ensure the state does not expire - pub fn refresh_time(&self) -> Option { - Some(2 * self.trusting_period / 3) - } - - /// Helper method to produce a [`Options`] struct for use in - /// Tendermint-specific light client verification. - pub fn as_light_client_options(&self) -> Result { - Ok(Options { - trust_threshold: self - .trust_level - .try_into() - .map_err(|e: Ics02Error| Error::invalid_trust_threshold(e.to_string()))?, - trusting_period: self.trusting_period, - clock_drift: self.max_clock_drift, - }) - } - - /// Verify the time and height delays - pub fn verify_delay_passed( - current_time: Timestamp, - current_height: Height, - processed_time: Timestamp, - processed_height: Height, - delay_period_time: Duration, - delay_period_blocks: u64, - ) -> Result<(), Error> { - let earliest_time = - (processed_time + delay_period_time).map_err(Error::timestamp_overflow)?; - if !(current_time == earliest_time || current_time.after(&earliest_time)) { - return Err(Error::not_enough_time_elapsed(current_time, earliest_time)); - } - - let earliest_height = processed_height.add(delay_period_blocks); - if current_height < earliest_height { - return Err(Error::not_enough_blocks_elapsed( - current_height, - earliest_height, - )); - } - - Ok(()) - } - - /// Verify that the client is at a sufficient height and unfrozen at the given height - pub fn verify_height(&self, height: Height) -> Result<(), Error> { - if self.latest_height < height { - return Err(Error::insufficient_height(self.latest_height(), height)); - } - - match self.frozen_height { - Some(frozen_height) if frozen_height <= height => { - Err(Error::client_frozen(frozen_height, height)) - } - _ => Ok(()), - } - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct UpgradeOptions { - pub unbonding_period: Duration, -} - -impl CoreUpgradeOptions for UpgradeOptions {} - -impl Ics2ClientState for ClientState { - fn chain_id(&self) -> ChainId { - self.chain_id.clone() - } - - fn client_type(&self) -> ClientType { - ClientType::Tendermint - } - - fn latest_height(&self) -> Height { - self.latest_height - } - - fn frozen_height(&self) -> Option { - self.frozen_height - } - - fn upgrade( - &mut self, - upgrade_height: Height, - upgrade_options: &dyn CoreUpgradeOptions, - chain_id: ChainId, - ) { - let upgrade_options = upgrade_options - .as_any() - .downcast_ref::() - .expect("UpgradeOptions not of type Tendermint"); - - // Reset custom fields to zero values - self.trusting_period = ZERO_DURATION; - self.trust_level = TrustThreshold::ZERO; - self.allow_update.after_expiry = false; - self.allow_update.after_misbehaviour = false; - self.frozen_height = None; - self.max_clock_drift = ZERO_DURATION; - - // Upgrade the client state - self.latest_height = upgrade_height; - self.unbonding_period = upgrade_options.unbonding_period; - self.chain_id = chain_id; - } - - fn expired(&self, elapsed: Duration) -> bool { - elapsed > self.trusting_period - } - - fn initialise(&self, consensus_state: Any) -> Result, Ics02Error> { - TmConsensusState::try_from(consensus_state).map(TmConsensusState::into_box) - } - - fn check_header_and_update_state( - &self, - ctx: &dyn ClientReader, - client_id: ClientId, - header: Any, - ) -> Result { - fn maybe_consensus_state( - ctx: &dyn ClientReader, - client_id: &ClientId, - height: Height, - ) -> Result>, Ics02Error> { - match ctx.consensus_state(client_id, height) { - Ok(cs) => Ok(Some(cs)), - Err(e) => match e.detail() { - Ics02ErrorDetail::ConsensusStateNotFound(_) => Ok(None), - _ => Err(e), - }, - } - } - - let client_state = downcast_tm_client_state(self)?.clone(); - let header = TmHeader::try_from(header)?; - - if header.height().revision_number() != client_state.chain_id().version() { - return Err(Ics02Error::client_specific( - Error::mismatched_revisions( - client_state.chain_id().version(), - header.height().revision_number(), - ) - .to_string(), - )); - } - - // Check if a consensus state is already installed; if so it should - // match the untrusted header. - let header_consensus_state = TmConsensusState::from(header.clone()); - let existing_consensus_state = - match maybe_consensus_state(ctx, &client_id, header.height())? { - Some(cs) => { - let cs = downcast_tm_consensus_state(cs.as_ref())?; - // If this consensus state matches, skip verification - // (optimization) - if cs == header_consensus_state { - // Header is already installed and matches the incoming - // header (already verified) - return Ok(UpdatedState { - client_state: client_state.into_box(), - consensus_state: cs.into_box(), - }); - } - Some(cs) - } - None => None, - }; - - let trusted_consensus_state = downcast_tm_consensus_state( - ctx.consensus_state(&client_id, header.trusted_height)? - .as_ref(), - )?; - - let trusted_state = TrustedBlockState { - header_time: trusted_consensus_state.timestamp, - height: header - .trusted_height - .revision_height() - .try_into() - .map_err(|_| { - Ics02Error::client_specific( - Error::invalid_header_height(header.trusted_height.revision_height()) - .to_string(), - ) - })?, - next_validators: &header.trusted_validator_set, - next_validators_hash: trusted_consensus_state.next_validators_hash, - }; - - let untrusted_state = UntrustedBlockState { - signed_header: &header.signed_header, - validators: &header.validator_set, - // NB: This will skip the - // VerificationPredicates::next_validators_match check for the - // untrusted state. - next_validators: None, - }; - - let options = client_state.as_light_client_options()?; - - let verdict = self.verifier.verify( - untrusted_state, - trusted_state, - &options, - ctx.host_timestamp().into_tm_time().unwrap(), - ); - - match verdict { - Verdict::Success => {} - Verdict::NotEnoughTrust(voting_power_tally) => { - return Err(Error::not_enough_trusted_vals_signed(format!( - "voting power tally: {}", - voting_power_tally - )) - .into()); - } - Verdict::Invalid(detail) => return Err(Error::verification_error(detail).into()), - } - - // If the header has verified, but its corresponding consensus state - // differs from the existing consensus state for that height, freeze the - // client and return the installed consensus state. - if let Some(cs) = existing_consensus_state { - if cs != header_consensus_state { - return Ok(UpdatedState { - client_state: client_state.with_frozen_height(header.height())?.into_box(), - consensus_state: cs.into_box(), - }); - } - } - - // Monotonicity checks for timestamps for in-the-middle updates - // (cs-new, cs-next, cs-latest) - if header.height() < client_state.latest_height() { - let maybe_next_cs = ctx - .next_consensus_state(&client_id, header.height())? - .as_ref() - .map(|cs| downcast_tm_consensus_state(cs.as_ref())) - .transpose()?; - - if let Some(next_cs) = maybe_next_cs { - // New (untrusted) header timestamp cannot occur after next - // consensus state's height - if header.signed_header.header().time > next_cs.timestamp { - return Err(Ics02Error::client_specific( - Error::header_timestamp_too_high( - header.signed_header.header().time.to_string(), - next_cs.timestamp.to_string(), - ) - .to_string(), - )); - } - } - } - - // (cs-trusted, cs-prev, cs-new) - if header.trusted_height < header.height() { - let maybe_prev_cs = ctx - .prev_consensus_state(&client_id, header.height())? - .as_ref() - .map(|cs| downcast_tm_consensus_state(cs.as_ref())) - .transpose()?; - - if let Some(prev_cs) = maybe_prev_cs { - // New (untrusted) header timestamp cannot occur before the - // previous consensus state's height - if header.signed_header.header().time < prev_cs.timestamp { - return Err(Ics02Error::client_specific( - Error::header_timestamp_too_low( - header.signed_header.header().time.to_string(), - prev_cs.timestamp.to_string(), - ) - .to_string(), - )); - } - } - } - - Ok(UpdatedState { - client_state: client_state.with_header(header.clone())?.into_box(), - consensus_state: TmConsensusState::from(header).into_box(), - }) - } - - fn verify_upgrade_and_update_state( - &self, - _consensus_state: Any, - _proof_upgrade_client: RawMerkleProof, - _proof_upgrade_consensus_state: RawMerkleProof, - ) -> Result { - unimplemented!() - } - - fn verify_client_consensus_state( - &self, - height: Height, - prefix: &CommitmentPrefix, - proof: &CommitmentProofBytes, - root: &CommitmentRoot, - client_id: &ClientId, - consensus_height: Height, - expected_consensus_state: &dyn ConsensusState, - ) -> Result<(), Ics02Error> { - let client_state = downcast_tm_client_state(self)?; - client_state.verify_height(height)?; - - let path = ClientConsensusStatePath { - client_id: client_id.clone(), - epoch: consensus_height.revision_number(), - height: consensus_height.revision_height(), - }; - let value = expected_consensus_state - .encode_vec() - .map_err(Ics02Error::invalid_any_consensus_state)?; - - verify_membership(client_state, prefix, proof, root, path, value) - } - - fn verify_connection_state( - &self, - height: Height, - prefix: &CommitmentPrefix, - proof: &CommitmentProofBytes, - root: &CommitmentRoot, - connection_id: &ConnectionId, - expected_connection_end: &ConnectionEnd, - ) -> Result<(), Ics02Error> { - let client_state = downcast_tm_client_state(self)?; - client_state.verify_height(height)?; - - let path = ConnectionsPath(connection_id.clone()); - let value = expected_connection_end - .encode_vec() - .map_err(Ics02Error::invalid_connection_end)?; - verify_membership(client_state, prefix, proof, root, path, value) - } - - fn verify_channel_state( - &self, - height: Height, - prefix: &CommitmentPrefix, - proof: &CommitmentProofBytes, - root: &CommitmentRoot, - port_id: &PortId, - channel_id: &ChannelId, - expected_channel_end: &crate::core::ics04_channel::channel::ChannelEnd, - ) -> Result<(), Ics02Error> { - let client_state = downcast_tm_client_state(self)?; - client_state.verify_height(height)?; - - let path = ChannelEndsPath(port_id.clone(), channel_id.clone()); - let value = expected_channel_end - .encode_vec() - .map_err(Ics02Error::invalid_channel_end)?; - verify_membership(client_state, prefix, proof, root, path, value) - } - - fn verify_client_full_state( - &self, - height: Height, - prefix: &CommitmentPrefix, - proof: &CommitmentProofBytes, - root: &CommitmentRoot, - client_id: &ClientId, - expected_client_state: Any, - ) -> Result<(), Ics02Error> { - let client_state = downcast_tm_client_state(self)?; - client_state.verify_height(height)?; - - let path = ClientStatePath(client_id.clone()); - let value = expected_client_state.encode_to_vec(); - verify_membership(client_state, prefix, proof, root, path, value) - } - - fn verify_packet_data( - &self, - ctx: &dyn ChannelReader, - height: Height, - connection_end: &ConnectionEnd, - proof: &CommitmentProofBytes, - root: &CommitmentRoot, - port_id: &PortId, - channel_id: &ChannelId, - sequence: Sequence, - commitment: PacketCommitment, - ) -> Result<(), Ics02Error> { - let client_state = downcast_tm_client_state(self)?; - client_state.verify_height(height)?; - verify_delay_passed(ctx, height, connection_end)?; - - let commitment_path = CommitmentsPath { - port_id: port_id.clone(), - channel_id: channel_id.clone(), - sequence, - }; - - verify_membership( - client_state, - connection_end.counterparty().prefix(), - proof, - root, - commitment_path, - commitment.into_vec(), - ) - } - - fn verify_packet_acknowledgement( - &self, - ctx: &dyn ChannelReader, - height: Height, - connection_end: &ConnectionEnd, - proof: &CommitmentProofBytes, - root: &CommitmentRoot, - port_id: &PortId, - channel_id: &ChannelId, - sequence: Sequence, - ack_commitment: AcknowledgementCommitment, - ) -> Result<(), Ics02Error> { - let client_state = downcast_tm_client_state(self)?; - client_state.verify_height(height)?; - verify_delay_passed(ctx, height, connection_end)?; - - let ack_path = AcksPath { - port_id: port_id.clone(), - channel_id: channel_id.clone(), - sequence, - }; - verify_membership( - client_state, - connection_end.counterparty().prefix(), - proof, - root, - ack_path, - ack_commitment.into_vec(), - ) - } - - fn verify_next_sequence_recv( - &self, - ctx: &dyn ChannelReader, - height: Height, - connection_end: &ConnectionEnd, - proof: &CommitmentProofBytes, - root: &CommitmentRoot, - port_id: &PortId, - channel_id: &ChannelId, - sequence: Sequence, - ) -> Result<(), Ics02Error> { - let client_state = downcast_tm_client_state(self)?; - client_state.verify_height(height)?; - verify_delay_passed(ctx, height, connection_end)?; - - let mut seq_bytes = Vec::new(); - u64::from(sequence) - .encode(&mut seq_bytes) - .expect("buffer size too small"); - - let seq_path = SeqRecvsPath(port_id.clone(), channel_id.clone()); - - verify_membership( - client_state, - connection_end.counterparty().prefix(), - proof, - root, - seq_path, - seq_bytes, - ) - } - - fn verify_packet_receipt_absence( - &self, - ctx: &dyn ChannelReader, - height: Height, - connection_end: &ConnectionEnd, - proof: &CommitmentProofBytes, - root: &CommitmentRoot, - port_id: &PortId, - channel_id: &ChannelId, - sequence: Sequence, - ) -> Result<(), Ics02Error> { - let client_state = downcast_tm_client_state(self)?; - client_state.verify_height(height)?; - verify_delay_passed(ctx, height, connection_end)?; - - let receipt_path = ReceiptsPath { - port_id: port_id.clone(), - channel_id: channel_id.clone(), - sequence, - }; - verify_non_membership( - client_state, - connection_end.counterparty().prefix(), - proof, - root, - receipt_path, - ) - } -} - -fn verify_membership( - client_state: &ClientState, - prefix: &CommitmentPrefix, - proof: &CommitmentProofBytes, - root: &CommitmentRoot, - path: impl Into, - value: Vec, -) -> Result<(), Ics02Error> { - let merkle_path = apply_prefix(prefix, vec![path.into().to_string()]); - let merkle_proof: MerkleProof = RawMerkleProof::try_from(proof.clone()) - .map_err(Ics02Error::invalid_commitment_proof)? - .into(); - - merkle_proof - .verify_membership( - &client_state.proof_specs, - root.clone().into(), - merkle_path, - value, - 0, - ) - .map_err(Ics02Error::ics23_verification) -} - -fn verify_non_membership( - client_state: &ClientState, - prefix: &CommitmentPrefix, - proof: &CommitmentProofBytes, - root: &CommitmentRoot, - path: impl Into, -) -> Result<(), Ics02Error> { - let merkle_path = apply_prefix(prefix, vec![path.into().to_string()]); - let merkle_proof: MerkleProof = RawMerkleProof::try_from(proof.clone()) - .map_err(Ics02Error::invalid_commitment_proof)? - .into(); - - merkle_proof - .verify_non_membership(&client_state.proof_specs, root.clone().into(), merkle_path) - .map_err(Ics02Error::ics23_verification) -} - -fn verify_delay_passed( - ctx: &dyn ChannelReader, - height: Height, - connection_end: &ConnectionEnd, -) -> Result<(), Ics02Error> { - let current_timestamp = ctx.host_timestamp(); - let current_height = ctx.host_height(); - - let client_id = connection_end.client_id(); - let processed_time = ctx - .client_update_time(client_id, height) - .map_err(|_| Error::processed_time_not_found(client_id.clone(), height))?; - let processed_height = ctx - .client_update_height(client_id, height) - .map_err(|_| Error::processed_height_not_found(client_id.clone(), height))?; - - let delay_period_time = connection_end.delay_period(); - let delay_period_height = ctx.block_delay(delay_period_time); - - ClientState::verify_delay_passed( - current_timestamp, - current_height, - processed_time, - processed_height, - delay_period_time, - delay_period_height, - ) - .map_err(|e| e.into()) -} -fn downcast_tm_client_state(cs: &dyn Ics2ClientState) -> Result<&ClientState, Ics02Error> { - cs.as_any() - .downcast_ref::() - .ok_or_else(|| Ics02Error::client_args_type_mismatch(ClientType::Tendermint)) -} - -fn downcast_tm_consensus_state(cs: &dyn ConsensusState) -> Result { - cs.as_any() - .downcast_ref::() - .ok_or_else(|| Ics02Error::client_args_type_mismatch(ClientType::Tendermint)) - .map(Clone::clone) -} - -impl Protobuf for ClientState {} - -impl TryFrom for ClientState { - type Error = Error; - - fn try_from(raw: RawTmClientState) -> Result { - let trust_level = raw - .trust_level - .clone() - .ok_or_else(Error::missing_trusting_period)?; - - // In `RawClientState`, a `frozen_height` of `0` means "not frozen". - // See: - // https://github.com/cosmos/ibc-go/blob/8422d0c4c35ef970539466c5bdec1cd27369bab3/modules/light-clients/07-tendermint/types/client_state.go#L74 - let frozen_height = raw - .frozen_height - .and_then(|raw_height| raw_height.try_into().ok()); - - #[allow(deprecated)] - Ok(Self { - chain_id: ChainId::from_string(raw.chain_id.as_str()), - trust_level: trust_level - .try_into() - .map_err(|e| Error::invalid_trust_threshold(format!("{}", e)))?, - trusting_period: raw - .trusting_period - .ok_or_else(Error::missing_trusting_period)? - .try_into() - .map_err(|_| Error::negative_trusting_period())?, - unbonding_period: raw - .unbonding_period - .ok_or_else(Error::missing_unbonding_period)? - .try_into() - .map_err(|_| Error::negative_unbonding_period())?, - max_clock_drift: raw - .max_clock_drift - .ok_or_else(Error::missing_max_clock_drift)? - .try_into() - .map_err(|_| Error::negative_max_clock_drift())?, - latest_height: raw - .latest_height - .ok_or_else(Error::missing_latest_height)? - .try_into() - .map_err(|_| Error::missing_latest_height())?, - frozen_height, - upgrade_path: raw.upgrade_path, - allow_update: AllowUpdate { - after_expiry: raw.allow_update_after_expiry, - after_misbehaviour: raw.allow_update_after_misbehaviour, - }, - proof_specs: raw.proof_specs.into(), - verifier: ProdVerifier::default(), - }) - } -} - -impl From for RawTmClientState { - fn from(value: ClientState) -> Self { - #[allow(deprecated)] - Self { - chain_id: value.chain_id.to_string(), - trust_level: Some(value.trust_level.into()), - trusting_period: Some(value.trusting_period.into()), - unbonding_period: Some(value.unbonding_period.into()), - max_clock_drift: Some(value.max_clock_drift.into()), - frozen_height: Some(value.frozen_height.map(|height| height.into()).unwrap_or( - RawHeight { - revision_number: 0, - revision_height: 0, - }, - )), - latest_height: Some(value.latest_height.into()), - proof_specs: value.proof_specs.into(), - upgrade_path: value.upgrade_path, - allow_update_after_expiry: value.allow_update.after_expiry, - allow_update_after_misbehaviour: value.allow_update.after_misbehaviour, - } - } -} - -impl Protobuf for ClientState {} - -impl TryFrom for ClientState { - type Error = Ics02Error; - - fn try_from(raw: Any) -> Result { - use bytes::Buf; - use core::ops::Deref; - - fn decode_client_state(buf: B) -> Result { - RawTmClientState::decode(buf) - .map_err(Error::decode)? - .try_into() - } - - match raw.type_url.as_str() { - TENDERMINT_CLIENT_STATE_TYPE_URL => { - decode_client_state(raw.value.deref()).map_err(Into::into) - } - _ => Err(Ics02Error::unknown_client_state_type(raw.type_url)), - } - } -} - -impl From for Any { - fn from(client_state: ClientState) -> Self { - Any { - type_url: TENDERMINT_CLIENT_STATE_TYPE_URL.to_string(), - value: Protobuf::::encode_vec(&client_state) - .expect("encoding to `Any` from `TmClientState`"), - } - } -} - -#[cfg(test)] -mod tests { - use crate::prelude::*; - use crate::Height; - use core::time::Duration; - use test_log::test; - - use ibc_proto::ics23::ProofSpec as Ics23ProofSpec; - use tendermint_rpc::endpoint::abci_query::AbciQuery; - - use crate::clients::ics07_tendermint::client_state::{AllowUpdate, ClientState}; - use crate::core::ics02_client::trust_threshold::TrustThreshold; - use crate::core::ics23_commitment::specs::ProofSpecs; - use crate::core::ics24_host::identifier::ChainId; - use crate::test::test_serialization_roundtrip; - use crate::timestamp::{Timestamp, ZERO_DURATION}; - - #[derive(Clone, Debug, PartialEq)] - struct ClientStateParams { - id: ChainId, - trust_level: TrustThreshold, - trusting_period: Duration, - unbonding_period: Duration, - max_clock_drift: Duration, - latest_height: Height, - proof_specs: ProofSpecs, - upgrade_path: Vec, - allow_update: AllowUpdate, - } - - #[test] - fn serialization_roundtrip_no_proof() { - let json_data = - include_str!("../../../tests/support/query/serialization/client_state.json"); - test_serialization_roundtrip::(json_data); - } - - #[test] - fn serialization_roundtrip_with_proof() { - let json_data = - include_str!("../../../tests/support/query/serialization/client_state_proof.json"); - test_serialization_roundtrip::(json_data); - } - - #[test] - fn client_state_new() { - // Define a "default" set of parameters to reuse throughout these tests. - let default_params: ClientStateParams = ClientStateParams { - id: ChainId::default(), - trust_level: TrustThreshold::ONE_THIRD, - trusting_period: Duration::new(64000, 0), - unbonding_period: Duration::new(128000, 0), - max_clock_drift: Duration::new(3, 0), - latest_height: Height::new(0, 10).unwrap(), - proof_specs: ProofSpecs::default(), - upgrade_path: vec!["".to_string()], - allow_update: AllowUpdate { - after_expiry: false, - after_misbehaviour: false, - }, - }; - - struct Test { - name: String, - params: ClientStateParams, - want_pass: bool, - } - - let tests: Vec = vec![ - Test { - name: "Valid parameters".to_string(), - params: default_params.clone(), - want_pass: true, - }, - Test { - name: "Invalid unbonding period".to_string(), - params: ClientStateParams { - unbonding_period: ZERO_DURATION, - ..default_params.clone() - }, - want_pass: false, - }, - Test { - name: "Invalid (too small) trusting period".to_string(), - params: ClientStateParams { - trusting_period: ZERO_DURATION, - ..default_params.clone() - }, - want_pass: false, - }, - Test { - name: "Invalid (too large) trusting period w.r.t. unbonding period".to_string(), - params: ClientStateParams { - trusting_period: Duration::new(11, 0), - unbonding_period: Duration::new(10, 0), - ..default_params.clone() - }, - want_pass: false, - }, - Test { - name: "Invalid (too small) trusting trust threshold".to_string(), - params: ClientStateParams { - trust_level: TrustThreshold::ZERO, - ..default_params.clone() - }, - want_pass: false, - }, - Test { - name: "Invalid (empty) proof specs".to_string(), - params: ClientStateParams { - proof_specs: ProofSpecs::from(Vec::::new()), - ..default_params - }, - want_pass: false, - }, - ] - .into_iter() - .collect(); - - for test in tests { - let p = test.params.clone(); - - let cs_result = ClientState::new( - p.id, - p.trust_level, - p.trusting_period, - p.unbonding_period, - p.max_clock_drift, - p.latest_height, - p.proof_specs, - p.upgrade_path, - p.allow_update, - ); - - assert_eq!( - test.want_pass, - cs_result.is_ok(), - "ClientState::new() failed for test {}, \nmsg{:?} with error {:?}", - test.name, - test.params.clone(), - cs_result.err(), - ); - } - } - - #[test] - fn client_state_verify_delay_passed() { - #[derive(Debug, Clone)] - struct Params { - current_time: Timestamp, - current_height: Height, - processed_time: Timestamp, - processed_height: Height, - delay_period_time: Duration, - delay_period_blocks: u64, - } - struct Test { - name: String, - params: Params, - want_pass: bool, - } - let now = Timestamp::now(); - - let tests: Vec = vec![ - Test { - name: "Successful delay verification".to_string(), - params: Params { - current_time: (now + Duration::from_nanos(2000)).unwrap(), - current_height: Height::new(0, 5).unwrap(), - processed_time: (now + Duration::from_nanos(1000)).unwrap(), - processed_height: Height::new(0, 3).unwrap(), - delay_period_time: Duration::from_nanos(500), - delay_period_blocks: 2, - }, - want_pass: true, - }, - Test { - name: "Delay period(time) has not elapsed".to_string(), - params: Params { - current_time: (now + Duration::from_nanos(1200)).unwrap(), - current_height: Height::new(0, 5).unwrap(), - processed_time: (now + Duration::from_nanos(1000)).unwrap(), - processed_height: Height::new(0, 3).unwrap(), - delay_period_time: Duration::from_nanos(500), - delay_period_blocks: 2, - }, - want_pass: false, - }, - Test { - name: "Delay period(blocks) has not elapsed".to_string(), - params: Params { - current_time: (now + Duration::from_nanos(2000)).unwrap(), - current_height: Height::new(0, 5).unwrap(), - processed_time: (now + Duration::from_nanos(1000)).unwrap(), - processed_height: Height::new(0, 4).unwrap(), - delay_period_time: Duration::from_nanos(500), - delay_period_blocks: 2, - }, - want_pass: false, - }, - ]; - - for test in tests { - let res = ClientState::verify_delay_passed( - test.params.current_time, - test.params.current_height, - test.params.processed_time, - test.params.processed_height, - test.params.delay_period_time, - test.params.delay_period_blocks, - ); - - assert_eq!( - test.want_pass, - res.is_ok(), - "ClientState::verify_delay_passed() failed for test {}, \nmsg{:?} with error {:?}", - test.name, - test.params.clone(), - res.err(), - ); - } - } - - #[test] - fn client_state_verify_height() { - // Define a "default" set of parameters to reuse throughout these tests. - let default_params: ClientStateParams = ClientStateParams { - id: ChainId::default(), - trust_level: TrustThreshold::ONE_THIRD, - trusting_period: Duration::new(64000, 0), - unbonding_period: Duration::new(128000, 0), - max_clock_drift: Duration::new(3, 0), - latest_height: Height::new(1, 10).unwrap(), - proof_specs: ProofSpecs::default(), - upgrade_path: vec!["".to_string()], - allow_update: AllowUpdate { - after_expiry: false, - after_misbehaviour: false, - }, - }; - - struct Test { - name: String, - height: Height, - setup: Option ClientState>>, - want_pass: bool, - } - - let tests = vec![ - Test { - name: "Successful height verification".to_string(), - height: Height::new(1, 8).unwrap(), - setup: None, - want_pass: true, - }, - Test { - name: "Invalid (too large) client height".to_string(), - height: Height::new(1, 12).unwrap(), - setup: None, - want_pass: false, - }, - Test { - name: "Invalid, client is frozen below current height".to_string(), - height: Height::new(1, 6).unwrap(), - setup: Some(Box::new(|client_state| { - client_state - .with_frozen_height(Height::new(1, 5).unwrap()) - .unwrap() - })), - want_pass: false, - }, - ]; - - for test in tests { - let p = default_params.clone(); - let client_state = ClientState::new( - p.id, - p.trust_level, - p.trusting_period, - p.unbonding_period, - p.max_clock_drift, - p.latest_height, - p.proof_specs, - p.upgrade_path, - p.allow_update, - ) - .unwrap(); - let client_state = match test.setup { - Some(setup) => (setup)(client_state), - _ => client_state, - }; - let res = client_state.verify_height(test.height); - - assert_eq!( - test.want_pass, - res.is_ok(), - "ClientState::verify_delay_height() failed for test {}, \nmsg{:?} with error {:?}", - test.name, - test.height, - res.err(), - ); - } - } -} - -#[cfg(any(test, feature = "mocks"))] -pub mod test_util { - use crate::prelude::*; - 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/modules/src/clients/ics07_tendermint/consensus_state.rs b/modules/src/clients/ics07_tendermint/consensus_state.rs deleted file mode 100644 index 2c7a7a9b2a..0000000000 --- a/modules/src/clients/ics07_tendermint/consensus_state.rs +++ /dev/null @@ -1,170 +0,0 @@ -use crate::prelude::*; - -use ibc_proto::google::protobuf::Any; -use ibc_proto::ibc::lightclients::tendermint::v1::ConsensusState as RawConsensusState; -use ibc_proto::protobuf::Protobuf; -use serde::{Deserialize, Serialize}; -use tendermint::{hash::Algorithm, time::Time, Hash}; -use tendermint_proto::google::protobuf as tpb; - -use crate::clients::ics07_tendermint::error::Error; -use crate::clients::ics07_tendermint::header::Header; -use crate::core::ics02_client::client_type::ClientType; -use crate::core::ics02_client::error::Error as Ics02Error; -use crate::core::ics23_commitment::commitment::CommitmentRoot; -use crate::timestamp::Timestamp; - -pub const TENDERMINT_CONSENSUS_STATE_TYPE_URL: &str = - "/ibc.lightclients.tendermint.v1.ConsensusState"; - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct ConsensusState { - pub timestamp: Time, - pub root: CommitmentRoot, - pub next_validators_hash: Hash, -} - -impl ConsensusState { - pub fn new(root: CommitmentRoot, timestamp: Time, next_validators_hash: Hash) -> Self { - Self { - timestamp, - root, - next_validators_hash, - } - } -} - -impl crate::core::ics02_client::consensus_state::ConsensusState for ConsensusState { - fn client_type(&self) -> ClientType { - ClientType::Tendermint - } - - fn root(&self) -> &CommitmentRoot { - &self.root - } - - fn timestamp(&self) -> Timestamp { - self.timestamp.into() - } -} - -impl Protobuf for ConsensusState {} - -impl TryFrom for ConsensusState { - type Error = Error; - - fn try_from(raw: RawConsensusState) -> Result { - let ibc_proto::google::protobuf::Timestamp { seconds, nanos } = raw - .timestamp - .ok_or_else(|| Error::invalid_raw_consensus_state("missing timestamp".into()))?; - // FIXME: shunts like this are necessary due to - // https://github.com/informalsystems/tendermint-rs/issues/1053 - let proto_timestamp = tpb::Timestamp { seconds, nanos }; - let timestamp = proto_timestamp - .try_into() - .map_err(|e| Error::invalid_raw_consensus_state(format!("invalid timestamp: {}", e)))?; - - Ok(Self { - root: raw - .root - .ok_or_else(|| { - Error::invalid_raw_consensus_state("missing commitment root".into()) - })? - .hash - .into(), - timestamp, - next_validators_hash: Hash::from_bytes(Algorithm::Sha256, &raw.next_validators_hash) - .map_err(|e| Error::invalid_raw_consensus_state(e.to_string()))?, - }) - } -} - -impl From for RawConsensusState { - fn from(value: ConsensusState) -> Self { - // FIXME: shunts like this are necessary due to - // https://github.com/informalsystems/tendermint-rs/issues/1053 - let tpb::Timestamp { seconds, nanos } = value.timestamp.into(); - let timestamp = ibc_proto::google::protobuf::Timestamp { seconds, nanos }; - - RawConsensusState { - timestamp: Some(timestamp), - root: Some(ibc_proto::ibc::core::commitment::v1::MerkleRoot { - hash: value.root.into_vec(), - }), - next_validators_hash: value.next_validators_hash.as_bytes().to_vec(), - } - } -} - -impl Protobuf for ConsensusState {} - -impl TryFrom for ConsensusState { - type Error = Ics02Error; - - fn try_from(raw: Any) -> Result { - use bytes::Buf; - use core::ops::Deref; - use prost::Message; - - fn decode_consensus_state(buf: B) -> Result { - RawConsensusState::decode(buf) - .map_err(Error::decode)? - .try_into() - } - - match raw.type_url.as_str() { - TENDERMINT_CONSENSUS_STATE_TYPE_URL => { - decode_consensus_state(raw.value.deref()).map_err(Into::into) - } - _ => Err(Ics02Error::unknown_consensus_state_type(raw.type_url)), - } - } -} - -impl From for Any { - fn from(consensus_state: ConsensusState) -> Self { - Any { - type_url: TENDERMINT_CONSENSUS_STATE_TYPE_URL.to_string(), - value: Protobuf::::encode_vec(&consensus_state) - .expect("encoding to `Any` from `TmConsensusState`"), - } - } -} - -impl From for ConsensusState { - fn from(header: tendermint::block::Header) -> Self { - Self { - root: CommitmentRoot::from_bytes(header.app_hash.as_ref()), - timestamp: header.time, - next_validators_hash: header.next_validators_hash, - } - } -} - -impl From
for ConsensusState { - fn from(header: Header) -> Self { - Self::from(header.signed_header.header) - } -} - -#[cfg(test)] -mod tests { - use tendermint_rpc::endpoint::abci_query::AbciQuery; - use test_log::test; - - use crate::test::test_serialization_roundtrip; - - #[test] - fn serialization_roundtrip_no_proof() { - let json_data = - include_str!("../../../tests/support/query/serialization/consensus_state.json"); - test_serialization_roundtrip::(json_data); - } - - #[test] - fn serialization_roundtrip_with_proof() { - let json_data = - include_str!("../../../tests/support/query/serialization/consensus_state_proof.json"); - test_serialization_roundtrip::(json_data); - } -} diff --git a/modules/src/clients/ics07_tendermint/error.rs b/modules/src/clients/ics07_tendermint/error.rs deleted file mode 100644 index 14637b9e59..0000000000 --- a/modules/src/clients/ics07_tendermint/error.rs +++ /dev/null @@ -1,296 +0,0 @@ -use crate::prelude::*; - -use flex_error::{define_error, TraceError}; - -use crate::core::ics02_client::error::Error as Ics02Error; -use crate::core::ics24_host::error::ValidationError; -use crate::core::ics24_host::identifier::ClientId; -use crate::timestamp::{Timestamp, TimestampOverflowError}; - -use crate::Height; -use tendermint::account::Id; -use tendermint::hash::Hash; -use tendermint::Error as TendermintError; -use tendermint_light_client_verifier::errors::VerificationErrorDetail as LightClientErrorDetail; - -define_error! { - #[derive(Debug, PartialEq, Eq)] - Error { - InvalidTrustingPeriod - { reason: String } - |e| { format_args!("invalid trusting period: {}", e.reason) }, - - InvalidUnbondingPeriod - { reason: String } - |e| { format_args!("invalid unbonding period: {}", e.reason) }, - - InvalidAddress - |_| { "invalid address" }, - - InvalidHeader - { reason: String } - [ TendermintError ] - |e| { format_args!("invalid header, failed basic validation: {}", e.reason) }, - - InvalidTrustThreshold - { reason: String } - |e| { format_args!("invalid client state trust threshold: {}", e.reason) }, - - MissingSignedHeader - |_| { "missing signed header" }, - - Validation - { reason: String } - |e| { format_args!("invalid header, failed basic validation: {}", e.reason) }, - - InvalidRawClientState - { reason: String } - |e| { format_args!("invalid raw client state: {}", e.reason) }, - - MissingValidatorSet - |_| { "missing validator set" }, - - MissingTrustedValidatorSet - |_| { "missing trusted validator set" }, - - MissingTrustedHeight - |_| { "missing trusted height" }, - - MissingTrustingPeriod - |_| { "missing trusting period" }, - - MissingUnbondingPeriod - |_| { "missing unbonding period" }, - - InvalidChainIdentifier - [ ValidationError ] - |_| { "invalid chain identifier" }, - - NegativeTrustingPeriod - |_| { "negative trusting period" }, - - NegativeUnbondingPeriod - |_| { "negative unbonding period" }, - - MissingMaxClockDrift - |_| { "missing max clock drift" }, - - NegativeMaxClockDrift - |_| { "negative max clock drift" }, - - MissingLatestHeight - |_| { "missing latest height" }, - - InvalidFrozenHeight - |_| { "invalid frozen height" }, - - InvalidChainId - { raw_value: String } - [ ValidationError ] - |e| { format_args!("invalid chain identifier: {}", e.raw_value) }, - - InvalidRawHeight - { raw_height: u64 } - |e| { format_args!("invalid raw height: {}", e.raw_height) }, - - InvalidRawConsensusState - { reason: String } - | e | { format_args!("invalid raw client consensus state: {}", e.reason) }, - - InvalidRawHeader - [ TendermintError ] - | _ | { "invalid raw header" }, - - InvalidRawMisbehaviour - { reason: String } - | e | { format_args!("invalid raw misbehaviour: {}", e.reason) }, - - Decode - [ TraceError ] - | _ | { "decode error" }, - - InsufficientVotingPower - { reason: String } - | e | { - format_args!("insufficient overlap: {}", e.reason) - }, - - LowUpdateTimestamp - { - low: String, - high: String - } - | e | { - format_args!("header timestamp {0} must be greater than current client consensus state timestamp {1}", e.low, e.high) - }, - - HeaderTimestampOutsideTrustingTime - { - low: String, - high: String - } - | e | { - format_args!("header timestamp {0} is outside the trusting period w.r.t. consensus state timestamp {1}", e.low, e.high) - }, - - HeaderTimestampTooHigh - { - actual: String, - max: String, - } - | e | { - format_args!("given other previous updates, header timestamp should be at most {0}, but was {1}", e.max, e.actual) - }, - - HeaderTimestampTooLow - { - actual: String, - min: String, - } - | e | { - format_args!("given other previous updates, header timestamp should be at least {0}, but was {1}", e.min, e.actual) - }, - - TimestampOverflow - [ TimestampOverflowError ] - |_| { "timestamp overflowed" }, - - NotEnoughTimeElapsed - { - current_time: Timestamp, - earliest_time: Timestamp, - } - | e | { - format_args!("not enough time elapsed, current timestamp {0} is still less than earliest acceptable timestamp {1}", e.current_time, e.earliest_time) - }, - - NotEnoughBlocksElapsed - { - current_height: Height, - earliest_height: Height, - } - | e | { - format_args!("not enough blocks elapsed, current height {0} is still less than earliest acceptable height {1}", e.current_height, e.earliest_height) - }, - - InvalidHeaderHeight - { height: u64 } - | e | { - format_args!("header revision height = {0} is invalid", e.height) - }, - - InvalidTrustedHeaderHeight - { - trusted_header_height: Height, - height_header: Height - } - | e | { - format_args!("header height is {0} and is lower than the trusted header height, which is {1} ", e.height_header, e.trusted_header_height) - }, - - LowUpdateHeight - { - low: Height, - high: Height - } - | e | { - format_args!("header height is {0} but it must be greater than the current client height which is {1}", e.low, e.high) - }, - - MismatchedRevisions - { - current_revision: u64, - update_revision: u64, - } - | e | { - format_args!("the header's current/trusted revision number ({0}) and the update's revision number ({1}) should be the same", e.current_revision, e.update_revision) - }, - - InvalidValidatorSet - { - hash1: Hash, - hash2: Hash, - } - | e | { - format_args!("invalid validator set: header_validators_hash={} and validators_hash={}", e.hash1, e.hash2) - }, - - NotEnoughTrustedValsSigned - { reason: String } - | e | { - format_args!("not enough trust because insufficient validators overlap: {}", e.reason) - }, - - VerificationError - { detail: LightClientErrorDetail } - | e | { - format_args!("verification failed: {}", e.detail) - }, - - ProcessedTimeNotFound - { - client_id: ClientId, - height: Height, - } - | e | { - format_args!( - "Processed time for the client {0} at height {1} not found", - e.client_id, e.height) - }, - - ProcessedHeightNotFound - { - client_id: ClientId, - height: Height, - } - | e | { - format_args!( - "Processed height for the client {0} at height {1} not found", - e.client_id, e.height) - }, - - InsufficientHeight - { - latest_height: Height, - target_height: Height, - } - | e | { - format_args!("the height is insufficient: latest_height={0} target_height={1}", e.latest_height, e.target_height) - }, - - ClientFrozen - { - frozen_height: Height, - target_height: Height, - } - | e | { - format_args!("the client is frozen: frozen_height={0} target_height={1}", e.frozen_height, e.target_height) - }, - } -} - -define_error! { - #[derive(Debug, PartialEq, Eq)] - VerificationError { - InvalidSignature - | _ | { "couldn't verify validator signature" }, - - DuplicateValidator - { id: Id } - | e | { - format_args!("duplicate validator in commit signatures with address {}", e.id) - }, - - InsufficientOverlap - { q1: u64, q2: u64 } - | e | { - format_args!("insufficient signers overlap between {0} and {1}", e.q1, e.q2) - }, - } -} - -impl From for Ics02Error { - fn from(e: Error) -> Self { - Self::client_specific(e.to_string()) - } -} diff --git a/modules/src/clients/ics07_tendermint/header.rs b/modules/src/clients/ics07_tendermint/header.rs deleted file mode 100644 index e3ceb3b2c5..0000000000 --- a/modules/src/clients/ics07_tendermint/header.rs +++ /dev/null @@ -1,241 +0,0 @@ -use alloc::string::ToString; -use core::cmp::Ordering; -use core::fmt::{Display, Error as FmtError, Formatter}; - -use bytes::Buf; -use ibc_proto::google::protobuf::Any; -use ibc_proto::ibc::lightclients::tendermint::v1::Header as RawHeader; -use ibc_proto::protobuf::Protobuf; -use prost::Message; -use serde_derive::{Deserialize, Serialize}; -use tendermint::block::signed_header::SignedHeader; -use tendermint::validator::Set as ValidatorSet; - -use crate::clients::ics07_tendermint::error::Error; -use crate::core::ics02_client::client_type::ClientType; -use crate::core::ics02_client::error::Error as Ics02Error; -use crate::core::ics24_host::identifier::ChainId; -use crate::timestamp::Timestamp; -use crate::utils::pretty::{PrettySignedHeader, PrettyValidatorSet}; -use crate::Height; - -pub const TENDERMINT_HEADER_TYPE_URL: &str = "/ibc.lightclients.tendermint.v1.Header"; - -/// Tendermint consensus header -#[derive(Clone, PartialEq, Eq, Deserialize, Serialize)] -pub struct Header { - pub signed_header: SignedHeader, // contains the commitment root - pub validator_set: ValidatorSet, // the validator set that signed Header - pub trusted_height: Height, // the height of a trusted header seen by client less than or equal to Header - // TODO(thane): Rename this to trusted_next_validator_set? - pub trusted_validator_set: ValidatorSet, // the last trusted validator set at trusted height -} - -impl core::fmt::Debug for Header { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, " Header {{...}}") - } -} - -impl Display for Header { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "Header {{ signed_header: {}, validator_set: {}, trusted_height: {}, trusted_validator_set: {} }}", PrettySignedHeader(&self.signed_header), PrettyValidatorSet(&self.validator_set), self.trusted_height, PrettyValidatorSet(&self.trusted_validator_set)) - } -} - -impl Header { - pub fn height(&self) -> Height { - Height::new( - ChainId::chain_version(self.signed_header.header.chain_id.as_str()), - u64::from(self.signed_header.header.height), - ) - .expect("malformed tendermint header domain type has an illegal height of 0") - } - - pub fn compatible_with(&self, other_header: &Header) -> bool { - headers_compatible(&self.signed_header, &other_header.signed_header) - } -} - -pub fn headers_compatible(header: &SignedHeader, other: &SignedHeader) -> bool { - let ibc_client_height = other.header.height; - let self_header_height = header.header.height; - - match self_header_height.cmp(&ibc_client_height) { - Ordering::Equal => { - // 1 - fork - header.commit.block_id == other.commit.block_id - } - Ordering::Greater => { - // 2 - BFT time violation - header.header.time > other.header.time - } - Ordering::Less => { - // 3 - BFT time violation - header.header.time < other.header.time - } - } -} - -impl crate::core::ics02_client::header::Header for Header { - fn client_type(&self) -> ClientType { - ClientType::Tendermint - } - - fn height(&self) -> Height { - self.height() - } - - fn timestamp(&self) -> Timestamp { - self.signed_header.header.time.into() - } -} - -impl Protobuf for Header {} - -impl TryFrom for Header { - type Error = Error; - - fn try_from(raw: RawHeader) -> Result { - let header = Self { - signed_header: raw - .signed_header - .ok_or_else(Error::missing_signed_header)? - .try_into() - .map_err(|e| Error::invalid_header("signed header conversion".to_string(), e))?, - validator_set: raw - .validator_set - .ok_or_else(Error::missing_validator_set)? - .try_into() - .map_err(Error::invalid_raw_header)?, - trusted_height: raw - .trusted_height - .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or_else(Error::missing_trusted_height)?, - trusted_validator_set: raw - .trusted_validators - .ok_or_else(Error::missing_trusted_validator_set)? - .try_into() - .map_err(Error::invalid_raw_header)?, - }; - - if header.height().revision_number() != header.trusted_height.revision_number() { - return Err(Error::mismatched_revisions( - header.trusted_height.revision_number(), - header.height().revision_number(), - )); - } - - Ok(header) - } -} - -impl Protobuf for Header {} - -impl TryFrom for Header { - type Error = Ics02Error; - - fn try_from(raw: Any) -> Result { - use core::ops::Deref; - - fn decode_header(buf: B) -> Result { - RawHeader::decode(buf).map_err(Error::decode)?.try_into() - } - - match raw.type_url.as_str() { - TENDERMINT_HEADER_TYPE_URL => decode_header(raw.value.deref()).map_err(Into::into), - _ => Err(Ics02Error::unknown_header_type(raw.type_url)), - } - } -} - -impl From
for Any { - fn from(header: Header) -> Self { - Any { - type_url: TENDERMINT_HEADER_TYPE_URL.to_string(), - value: Protobuf::::encode_vec(&header) - .expect("encoding to `Any` from `TmHeader`"), - } - } -} - -pub fn decode_header(buf: B) -> Result { - RawHeader::decode(buf).map_err(Error::decode)?.try_into() -} - -impl From
for RawHeader { - fn from(value: Header) -> Self { - RawHeader { - signed_header: Some(value.signed_header.into()), - validator_set: Some(value.validator_set.into()), - trusted_height: Some(value.trusted_height.into()), - trusted_validators: Some(value.trusted_validator_set.into()), - } - } -} - -#[cfg(any(test, feature = "mocks"))] -pub mod test_util { - use alloc::vec; - - 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/modules/src/clients/ics07_tendermint/misbehaviour.rs b/modules/src/clients/ics07_tendermint/misbehaviour.rs deleted file mode 100644 index afe161cfd2..0000000000 --- a/modules/src/clients/ics07_tendermint/misbehaviour.rs +++ /dev/null @@ -1,73 +0,0 @@ -use crate::prelude::*; - -use ibc_proto::ibc::lightclients::tendermint::v1::Misbehaviour as RawMisbehaviour; -use ibc_proto::protobuf::Protobuf; -use serde::{Deserialize, Serialize}; - -use crate::clients::ics07_tendermint::error::Error; -use crate::clients::ics07_tendermint::header::Header; -use crate::core::ics24_host::identifier::ClientId; -use crate::Height; - -pub const TENDERMINT_MISBEHAVIOR_TYPE_URL: &str = "/ibc.lightclients.tendermint.v1.Misbehaviour"; - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct Misbehaviour { - pub client_id: ClientId, - pub header1: Header, - pub header2: Header, -} - -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 - .header_1 - .ok_or_else(|| Error::invalid_raw_misbehaviour("missing header1".into()))? - .try_into()?, - header2: raw - .header_2 - .ok_or_else(|| Error::invalid_raw_misbehaviour("missing header2".into()))? - .try_into()?, - }) - } -} - -impl From for RawMisbehaviour { - fn from(value: Misbehaviour) -> Self { - RawMisbehaviour { - client_id: value.client_id.to_string(), - header_1: Some(value.header1.into()), - header_2: Some(value.header2.into()), - } - } -} - -impl core::fmt::Display for Misbehaviour { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - write!( - f, - "{} h1: {}-{} h2: {}-{}", - self.client_id, - self.header1.height(), - self.header1.trusted_height, - self.header2.height(), - self.header2.trusted_height, - ) - } -} diff --git a/modules/src/clients/ics07_tendermint/mod.rs b/modules/src/clients/ics07_tendermint/mod.rs deleted file mode 100644 index b0920cb07f..0000000000 --- a/modules/src/clients/ics07_tendermint/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -//! ICS 07: Tendermint Client implements a client verification algorithm for blockchains which use -//! the Tendermint consensus algorithm. - -pub mod client_state; -pub mod consensus_state; -pub mod error; -pub mod header; -pub mod misbehaviour; diff --git a/modules/src/clients/mod.rs b/modules/src/clients/mod.rs deleted file mode 100644 index 65ea910b18..0000000000 --- a/modules/src/clients/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -//! Implementations of client verification algorithms for specific types of chains. - -pub mod ics07_tendermint; diff --git a/modules/src/core/ics02_client/client_state.rs b/modules/src/core/ics02_client/client_state.rs deleted file mode 100644 index 1128c22210..0000000000 --- a/modules/src/core/ics02_client/client_state.rs +++ /dev/null @@ -1,257 +0,0 @@ -use core::marker::{Send, Sync}; -use core::time::Duration; - -use dyn_clone::DynClone; -use erased_serde::Serialize as ErasedSerialize; -use ibc_proto::google::protobuf::Any; -use ibc_proto::ibc::core::commitment::v1::MerkleProof; -use ibc_proto::protobuf::Protobuf as ErasedProtobuf; - -use crate::core::ics02_client::client_type::ClientType; -use crate::core::ics02_client::error::Error; -use crate::core::ics03_connection::connection::ConnectionEnd; -use crate::core::ics04_channel::channel::ChannelEnd; -use crate::core::ics04_channel::commitment::{AcknowledgementCommitment, PacketCommitment}; -use crate::core::ics04_channel::context::ChannelReader; -use crate::core::ics04_channel::packet::Sequence; -use crate::core::ics23_commitment::commitment::{ - CommitmentPrefix, CommitmentProofBytes, CommitmentRoot, -}; -use crate::core::ics24_host::identifier::{ChainId, ChannelId, ClientId, ConnectionId, PortId}; -use crate::dynamic_typing::AsAny; -use crate::prelude::*; -use crate::Height; - -use super::consensus_state::ConsensusState; -use super::context::ClientReader; - -pub trait ClientState: - AsAny - + sealed::ErasedPartialEqClientState - + DynClone - + ErasedSerialize - + ErasedProtobuf - + core::fmt::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; - - /// Type of client associated with this state (eg. Tendermint) - fn client_type(&self) -> ClientType; - - /// Latest height the client was updated to - fn latest_height(&self) -> Height; - - /// Freeze status of the client - fn is_frozen(&self) -> bool { - self.frozen_height().is_some() - } - - /// Frozen height of the client - fn frozen_height(&self) -> Option; - - /// Check if the state is expired when `elapsed` time has passed since the latest consensus - /// state timestamp - fn expired(&self, elapsed: Duration) -> bool; - - /// Helper function to verify the upgrade client procedure. - /// Resets all fields except the blockchain-specific ones, - /// and updates the given fields. - fn upgrade( - &mut self, - upgrade_height: Height, - upgrade_options: &dyn UpgradeOptions, - chain_id: ChainId, - ); - - /// Convert into a boxed trait object - fn into_box(self) -> Box - where - Self: Sized, - { - Box::new(self) - } - - fn initialise(&self, consensus_state: Any) -> Result, Error>; - - fn check_header_and_update_state( - &self, - ctx: &dyn ClientReader, - client_id: ClientId, - header: Any, - ) -> Result; - - fn verify_upgrade_and_update_state( - &self, - consensus_state: Any, - proof_upgrade_client: MerkleProof, - proof_upgrade_consensus_state: MerkleProof, - ) -> Result; - - /// Verification functions as specified in: - /// - /// - /// Verify a `proof` that the consensus state of a given client (at height `consensus_height`) - /// matches the input `consensus_state`. The parameter `counterparty_height` represent the - /// height of the counterparty chain that this proof assumes (i.e., the height at which this - /// proof was computed). - #[allow(clippy::too_many_arguments)] - fn verify_client_consensus_state( - &self, - height: Height, - prefix: &CommitmentPrefix, - proof: &CommitmentProofBytes, - root: &CommitmentRoot, - client_id: &ClientId, - consensus_height: Height, - expected_consensus_state: &dyn ConsensusState, - ) -> Result<(), Error>; - - /// Verify a `proof` that a connection state matches that of the input `connection_end`. - #[allow(clippy::too_many_arguments)] - fn verify_connection_state( - &self, - height: Height, - prefix: &CommitmentPrefix, - proof: &CommitmentProofBytes, - root: &CommitmentRoot, - connection_id: &ConnectionId, - expected_connection_end: &ConnectionEnd, - ) -> Result<(), Error>; - - /// Verify a `proof` that a channel state matches that of the input `channel_end`. - #[allow(clippy::too_many_arguments)] - fn verify_channel_state( - &self, - height: Height, - prefix: &CommitmentPrefix, - proof: &CommitmentProofBytes, - root: &CommitmentRoot, - port_id: &PortId, - channel_id: &ChannelId, - expected_channel_end: &ChannelEnd, - ) -> Result<(), Error>; - - /// Verify the client state for this chain that it is stored on the counterparty chain. - #[allow(clippy::too_many_arguments)] - fn verify_client_full_state( - &self, - height: Height, - prefix: &CommitmentPrefix, - proof: &CommitmentProofBytes, - root: &CommitmentRoot, - client_id: &ClientId, - expected_client_state: Any, - ) -> Result<(), Error>; - - /// Verify a `proof` that a packet has been commited. - #[allow(clippy::too_many_arguments)] - fn verify_packet_data( - &self, - ctx: &dyn ChannelReader, - height: Height, - connection_end: &ConnectionEnd, - proof: &CommitmentProofBytes, - root: &CommitmentRoot, - port_id: &PortId, - channel_id: &ChannelId, - sequence: Sequence, - commitment: PacketCommitment, - ) -> Result<(), Error>; - - /// Verify a `proof` that a packet has been commited. - #[allow(clippy::too_many_arguments)] - fn verify_packet_acknowledgement( - &self, - ctx: &dyn ChannelReader, - height: Height, - connection_end: &ConnectionEnd, - proof: &CommitmentProofBytes, - root: &CommitmentRoot, - port_id: &PortId, - channel_id: &ChannelId, - sequence: Sequence, - ack: AcknowledgementCommitment, - ) -> Result<(), Error>; - - /// Verify a `proof` that of the next_seq_received. - #[allow(clippy::too_many_arguments)] - fn verify_next_sequence_recv( - &self, - ctx: &dyn ChannelReader, - height: Height, - connection_end: &ConnectionEnd, - proof: &CommitmentProofBytes, - root: &CommitmentRoot, - port_id: &PortId, - channel_id: &ChannelId, - sequence: Sequence, - ) -> Result<(), Error>; - - /// Verify a `proof` that a packet has not been received. - #[allow(clippy::too_many_arguments)] - fn verify_packet_receipt_absence( - &self, - ctx: &dyn ChannelReader, - height: Height, - connection_end: &ConnectionEnd, - proof: &CommitmentProofBytes, - root: &CommitmentRoot, - port_id: &PortId, - channel_id: &ChannelId, - sequence: Sequence, - ) -> Result<(), Error>; -} - -// Implements `Clone` for `Box` -dyn_clone::clone_trait_object!(ClientState); - -// Implements `serde::Serialize` for all types that have ClientState as supertrait -erased_serde::serialize_trait_object!(ClientState); - -impl PartialEq for dyn ClientState { - fn eq(&self, other: &Self) -> bool { - self.eq_client_state(other) - } -} - -// see https://github.com/rust-lang/rust/issues/31740 -impl PartialEq<&Self> for Box { - fn eq(&self, other: &&Self) -> bool { - self.eq_client_state(other.as_ref()) - } -} - -pub fn downcast_client_state(h: &dyn ClientState) -> Option<&CS> { - h.as_any().downcast_ref::() -} - -pub trait UpgradeOptions: AsAny {} - -pub struct UpdatedState { - pub client_state: Box, - pub consensus_state: Box, -} - -mod sealed { - use super::*; - - pub trait ErasedPartialEqClientState { - fn eq_client_state(&self, other: &dyn ClientState) -> bool; - } - - impl ErasedPartialEqClientState for CS - where - CS: ClientState + PartialEq, - { - fn eq_client_state(&self, other: &dyn ClientState) -> bool { - other - .as_any() - .downcast_ref::() - .map_or(false, |h| self == h) - } - } -} diff --git a/modules/src/core/ics02_client/client_type.rs b/modules/src/core/ics02_client/client_type.rs deleted file mode 100644 index 22b6657f13..0000000000 --- a/modules/src/core/ics02_client/client_type.rs +++ /dev/null @@ -1,112 +0,0 @@ -use crate::prelude::*; -use core::fmt::{Display, Error as FmtError, Formatter}; -use serde_derive::{Deserialize, Serialize}; - -use super::error::Error; - -/// Type of the client, depending on the specific consensus algorithm. -#[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, - } - } -} - -impl Display for ClientType { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "ClientType({})", self.as_str()) - } -} - -impl core::str::FromStr for ClientType { - type Err = Error; - - fn from_str(s: &str) -> Result { - 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())), - } - } -} - -#[cfg(test)] -mod tests { - use core::str::FromStr; - use test_log::test; - - use super::ClientType; - use crate::core::ics02_client::error::{Error, ErrorDetail}; - - #[test] - fn parse_tendermint_client_type() { - let client_type = ClientType::from_str("07-tendermint"); - - match client_type { - Ok(ClientType::Tendermint) => (), - _ => panic!("parse failed"), - } - } - - #[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"; - let result = ClientType::from_str(client_type_str); - - match result { - Err(Error(ErrorDetail::UnknownClientType(e), _)) => { - assert_eq!(&e.client_type, client_type_str) - } - _ => { - panic!("Expected ClientType::from_str to fail with UnknownClientType, instead got",) - } - } - } - - #[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; - 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); - } -} diff --git a/modules/src/core/ics02_client/consensus_state.rs b/modules/src/core/ics02_client/consensus_state.rs deleted file mode 100644 index 4d7c0adac3..0000000000 --- a/modules/src/core/ics02_client/consensus_state.rs +++ /dev/null @@ -1,92 +0,0 @@ -use crate::prelude::*; - -use core::marker::{Send, Sync}; - -use dyn_clone::DynClone; -use erased_serde::Serialize as ErasedSerialize; -use ibc_proto::google::protobuf::Any; -use ibc_proto::protobuf::Protobuf as ErasedProtobuf; - -use crate::core::ics02_client::client_type::ClientType; -use crate::core::ics02_client::error::Error; -use crate::core::ics23_commitment::commitment::CommitmentRoot; -use crate::dynamic_typing::AsAny; -use crate::timestamp::Timestamp; - -/// Abstract of consensus state information used by the validity predicate -/// to verify new commits & state roots. -/// -/// Users are not expected to implement sealed::ErasedPartialEqConsensusState. -/// Effectively, that trait bound mandates implementors to derive PartialEq, -/// after which our blanket implementation will implement -/// `ErasedPartialEqConsensusState` for their type. -pub trait ConsensusState: - AsAny - + sealed::ErasedPartialEqConsensusState - + DynClone - + ErasedSerialize - + ErasedProtobuf - + core::fmt::Debug - + Send - + Sync -{ - /// Type of client associated with this consensus state (eg. Tendermint) - fn client_type(&self) -> ClientType; - - /// Commitment root of the consensus state, which is used for key-value pair verification. - fn root(&self) -> &CommitmentRoot; - - /// The timestamp of the consensus state - fn timestamp(&self) -> Timestamp; - - /// Convert into a boxed trait object - fn into_box(self) -> Box - where - Self: Sized, - { - Box::new(self) - } -} - -// Implements `Clone` for `Box` -dyn_clone::clone_trait_object!(ConsensusState); - -// Implements `serde::Serialize` for all types that have ConsensusState as supertrait -erased_serde::serialize_trait_object!(ConsensusState); - -pub fn downcast_consensus_state(h: &dyn ConsensusState) -> Option<&CS> { - h.as_any().downcast_ref::() -} - -impl PartialEq for dyn ConsensusState { - fn eq(&self, other: &Self) -> bool { - self.eq_consensus_state(other) - } -} - -// see https://github.com/rust-lang/rust/issues/31740 -impl PartialEq<&Self> for Box { - fn eq(&self, other: &&Self) -> bool { - self.eq_consensus_state(other.as_ref()) - } -} - -mod sealed { - use super::*; - - pub trait ErasedPartialEqConsensusState { - fn eq_consensus_state(&self, other: &dyn ConsensusState) -> bool; - } - - impl ErasedPartialEqConsensusState for CS - where - CS: ConsensusState + PartialEq, - { - fn eq_consensus_state(&self, other: &dyn ConsensusState) -> bool { - other - .as_any() - .downcast_ref::() - .map_or(false, |h| self == h) - } - } -} diff --git a/modules/src/core/ics02_client/context.rs b/modules/src/core/ics02_client/context.rs deleted file mode 100644 index 4ad9e9b7e2..0000000000 --- a/modules/src/core/ics02_client/context.rs +++ /dev/null @@ -1,177 +0,0 @@ -//! ICS2 (client) context. The two traits `ClientReader` and `ClientKeeper` define the interface -//! that any host chain must implement to be able to process any `ClientMsg`. See -//! "ADR 003: IBC protocol implementation" for more details. - -use alloc::boxed::Box; - -use ibc_proto::google::protobuf::Any; - -use crate::core::ics02_client::client_state::ClientState; -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::ics02_client::handler::ClientResult::{self, Create, Update, Upgrade}; -use crate::core::ics24_host::identifier::ClientId; -use crate::timestamp::Timestamp; -use crate::Height; - -/// Defines the read-only part of ICS2 (client functions) context. -pub trait ClientReader { - /// Returns the ClientType for the given identifier `client_id`. - fn client_type(&self, client_id: &ClientId) -> Result; - - /// Returns the ClientState for the given identifier `client_id`. - fn client_state(&self, client_id: &ClientId) -> Result, Error>; - - /// Tries to decode the given `client_state` into a concrete light client state. - fn decode_client_state(&self, client_state: Any) -> Result, Error>; - - /// Retrieve the consensus state for the given client ID at the specified - /// height. - /// - /// Returns an error if no such state exists. - fn consensus_state( - &self, - client_id: &ClientId, - height: Height, - ) -> Result, Error>; - - /// Search for the lowest consensus state higher than `height`. - fn next_consensus_state( - &self, - client_id: &ClientId, - height: Height, - ) -> Result>, Error>; - - /// Search for the highest consensus state lower than `height`. - fn prev_consensus_state( - &self, - client_id: &ClientId, - height: Height, - ) -> Result>, Error>; - - /// Returns the current height of the local chain. - fn host_height(&self) -> Height; - - /// Returns the current timestamp of the local chain. - fn host_timestamp(&self) -> Timestamp { - let pending_consensus_state = self - .pending_host_consensus_state() - .expect("host must have pending consensus state"); - pending_consensus_state.timestamp() - } - - /// Returns the `ConsensusState` of the host (local) chain at a specific height. - fn host_consensus_state(&self, height: Height) -> Result, Error>; - - /// Returns the pending `ConsensusState` of the host (local) chain. - fn pending_host_consensus_state(&self) -> Result, Error>; - - /// Returns a natural number, counting how many clients have been created thus far. - /// The value of this counter should increase only via method `ClientKeeper::increase_client_counter`. - fn client_counter(&self) -> Result; -} - -/// Defines the write-only part of ICS2 (client functions) context. -pub trait ClientKeeper { - fn store_client_result(&mut self, handler_res: ClientResult) -> Result<(), Error> { - match handler_res { - Create(res) => { - self.store_client_type(res.client_id.clone(), res.client_type)?; - self.store_client_state(res.client_id.clone(), res.client_state.clone())?; - self.store_consensus_state( - res.client_id.clone(), - res.client_state.latest_height(), - res.consensus_state, - )?; - self.increase_client_counter(); - self.store_update_time( - res.client_id.clone(), - res.client_state.latest_height(), - res.processed_time, - )?; - self.store_update_height( - res.client_id, - res.client_state.latest_height(), - res.processed_height, - )?; - Ok(()) - } - Update(res) => { - self.store_client_state(res.client_id.clone(), res.client_state.clone())?; - self.store_consensus_state( - res.client_id.clone(), - res.client_state.latest_height(), - res.consensus_state, - )?; - self.store_update_time( - res.client_id.clone(), - res.client_state.latest_height(), - res.processed_time, - )?; - self.store_update_height( - res.client_id, - res.client_state.latest_height(), - res.processed_height, - )?; - Ok(()) - } - Upgrade(res) => { - self.store_client_state(res.client_id.clone(), res.client_state.clone())?; - self.store_consensus_state( - res.client_id.clone(), - res.client_state.latest_height(), - res.consensus_state, - )?; - Ok(()) - } - } - } - - /// Called upon successful client creation - fn store_client_type( - &mut self, - client_id: ClientId, - client_type: ClientType, - ) -> Result<(), Error>; - - /// Called upon successful client creation and update - fn store_client_state( - &mut self, - client_id: ClientId, - client_state: Box, - ) -> Result<(), Error>; - - /// Called upon successful client creation and update - fn store_consensus_state( - &mut self, - client_id: ClientId, - height: Height, - consensus_state: Box, - ) -> Result<(), Error>; - - /// Called upon client creation. - /// Increases the counter which keeps track of how many clients have been created. - /// Should never fail. - fn increase_client_counter(&mut self); - - /// Called upon successful client update. - /// Implementations are expected to use this to record the specified time as the time at which - /// this update (or header) was processed. - fn store_update_time( - &mut self, - client_id: ClientId, - height: Height, - timestamp: Timestamp, - ) -> Result<(), Error>; - - /// Called upon successful client update. - /// Implementations are expected to use this to record the specified height as the height at - /// at which this update (or header) was processed. - fn store_update_height( - &mut self, - client_id: ClientId, - height: Height, - host_height: Height, - ) -> Result<(), Error>; -} diff --git a/modules/src/core/ics02_client/error.rs b/modules/src/core/ics02_client/error.rs deleted file mode 100644 index efa610f11b..0000000000 --- a/modules/src/core/ics02_client/error.rs +++ /dev/null @@ -1,276 +0,0 @@ -use crate::prelude::*; - -use flex_error::{define_error, TraceError}; -use ibc_proto::protobuf::Error as TendermintProtoError; - -use crate::core::ics02_client::client_type::ClientType; -use crate::core::ics02_client::height::HeightError; -use crate::core::ics23_commitment::error::Error as Ics23Error; -use crate::core::ics24_host::error::ValidationError; -use crate::core::ics24_host::identifier::ClientId; -use crate::signer::SignerError; -use crate::timestamp::Timestamp; -use crate::Height; - -define_error! { - #[derive(Debug, PartialEq, Eq)] - Error { - UnknownClientType - { client_type: String } - | e | { format_args!("unknown client type: {0}", e.client_type) }, - - ClientIdentifierConstructor - { client_type: ClientType, counter: u64 } - [ ValidationError ] - | e | { - format_args!("Client identifier constructor failed for type {0} with counter {1}", - e.client_type, e.counter) - }, - - ClientAlreadyExists - { client_id: ClientId } - | e | { format_args!("client already exists: {0}", e.client_id) }, - - ClientNotFound - { client_id: ClientId } - | e | { format_args!("client not found: {0}", e.client_id) }, - - ClientFrozen - { client_id: ClientId } - | e | { format_args!("client is frozen: {0}", e.client_id) }, - - ConsensusStateNotFound - { client_id: ClientId, height: Height } - | e | { - format_args!("consensus state not found at: {0} at height {1}", - e.client_id, e.height) - }, - - ImplementationSpecific - | _ | { "implementation specific error" }, - - HeaderVerificationFailure - { reason: String } - | e | { format_args!("header verification failed with reason: {}", e.reason) }, - - InvalidTrustThreshold - { numerator: u64, denominator: u64 } - | e | { format_args!("failed to build trust threshold from fraction: {}/{}", e.numerator, e.denominator) }, - - FailedTrustThresholdConversion - { numerator: u64, denominator: u64 } - | e | { format_args!("failed to build Tendermint domain type trust threshold from fraction: {}/{}", e.numerator, e.denominator) }, - - UnknownClientStateType - { client_state_type: String } - | e | { format_args!("unknown client state type: {0}", e.client_state_type) }, - - EmptyClientStateResponse - | _ | { "the client state was not found" }, - - EmptyPrefix - | _ | { "empty prefix" }, - - UnknownConsensusStateType - { consensus_state_type: String } - | e | { - format_args!("unknown client consensus state type: {0}", - e.consensus_state_type) - }, - - EmptyConsensusStateResponse - | _ | { "the client consensus state was not found" }, - - UnknownHeaderType - { header_type: String } - | e | { - format_args!("unknown header type: {0}", - e.header_type) - }, - - UnknownMisbehaviourType - { misbehavior_type: String } - | e | { - format_args!("unknown misbehaviour type: {0}", - e.misbehavior_type) - }, - - InvalidRawClientId - { client_id: String } - [ ValidationError ] - | e | { - format_args!("invalid raw client identifier {0}", - e.client_id) - }, - - DecodeRawClientState - [ TraceError ] - | _ | { "error decoding raw client state" }, - - MissingRawClientState - | _ | { "missing raw client state" }, - - InvalidRawConsensusState - [ TraceError ] - | _ | { "invalid raw client consensus state" }, - - MissingRawConsensusState - | _ | { "missing raw client consensus state" }, - - InvalidMsgUpdateClientId - [ ValidationError ] - | _ | { "invalid client id in the update client message" }, - - Decode - [ TraceError ] - | _ | { "decode error" }, - - MissingHeight - | _ | { "invalid raw client consensus state: the height field is missing" }, - - InvalidClientIdentifier - [ ValidationError ] - | _ | { "invalid client identifier" }, - - InvalidRawHeader - [ TraceError ] - | _ | { "invalid raw header" }, - - MissingRawHeader - | _ | { "missing raw header" }, - - DecodeRawMisbehaviour - [ TraceError ] - | _ | { "invalid raw misbehaviour" }, - - InvalidRawMisbehaviour - [ ValidationError ] - | _ | { "invalid raw misbehaviour" }, - - MissingRawMisbehaviour - | _ | { "missing raw misbehaviour" }, - - InvalidStringAsHeight - { value: String } - [ HeightError ] - | e | { format_args!("String {0} cannnot be converted to height", e.value) }, - - InvalidHeight - | _ | { "revision height cannot be zero" }, - - InvalidHeightResult - | _ | { "height cannot end up zero or negative" }, - - InvalidAddress - | _ | { "invalid address" }, - - InvalidUpgradeClientProof - [ Ics23Error ] - | _ | { "invalid proof for the upgraded client state" }, - - InvalidUpgradeConsensusStateProof - [ Ics23Error ] - | _ | { "invalid proof for the upgraded consensus state" }, - - InvalidCommitmentProof - [ Ics23Error ] - | _ | { "invalid commitment proof bytes" }, - - InvalidPacketTimestamp - [ crate::timestamp::ParseTimestampError ] - | _ | { "invalid packet timeout timestamp value" }, - - ClientArgsTypeMismatch - { client_type: ClientType } - | e | { - format_args!("mismatch between client and arguments types, expected: {0:?}", - e.client_type) - }, - - InsufficientVotingPower - { reason: String } - | e | { - format_args!("Insufficient overlap {}", e.reason) - }, - - RawClientAndConsensusStateTypesMismatch - { - state_type: ClientType, - consensus_type: ClientType, - } - | e | { - format_args!("mismatch in raw client consensus state {} with expected state {}", - e.state_type, e.consensus_type) - }, - - LowHeaderHeight - { - header_height: Height, - latest_height: Height - } - | e | { - format!("received header height ({}) is lower than (or equal to) client latest height ({})", - e.header_height, e.latest_height) - }, - - LowUpgradeHeight - { - upgraded_height: Height, - client_height: Height, - } - | e | { - format_args!("upgraded client height {} must be at greater than current client height {}", - e.upgraded_height, e.client_height) - }, - - InvalidConsensusStateTimestamp - { - time1: Timestamp, - time2: Timestamp, - } - | e | { - format_args!("timestamp is invalid or missing, timestamp={0}, now={1}", e.time1, e.time2) - }, - - HeaderNotWithinTrustPeriod - { - latest_time:Timestamp, - update_time: Timestamp, - } - | e | { - format_args!("header not withing trusting period: expires_at={0} now={1}", e.latest_time, e.update_time) - }, - - MissingLocalConsensusState - { height: Height } - | e | { format_args!("the local consensus state could not be retrieved for height {}", e.height) }, - - InvalidConnectionEnd - [ TraceError] - | _ | { "invalid connection end" }, - - InvalidChannelEnd - [ TraceError] - | _ | { "invalid channel end" }, - - InvalidAnyClientState - [ TraceError] - | _ | { "invalid any client state" }, - - InvalidAnyConsensusState - [ TraceError ] - | _ | { "invalid any client consensus state" }, - - Signer - [ SignerError ] - | _ | { "failed to parse signer" }, - - Ics23Verification - [ Ics23Error ] - | _ | { "ics23 verification failure" }, - - ClientSpecific - { description: String } - | e | { format_args!("client specific error: {0}", e.description) }, - } -} diff --git a/modules/src/core/ics02_client/events.rs b/modules/src/core/ics02_client/events.rs deleted file mode 100644 index dd5e035312..0000000000 --- a/modules/src/core/ics02_client/events.rs +++ /dev/null @@ -1,282 +0,0 @@ -//! Types for the IBC events emitted from Tendermint Websocket by the client module. - -use core::fmt::{Display, Error as FmtError, Formatter}; -use serde_derive::{Deserialize, Serialize}; -use tendermint::abci::tag::Tag; -use tendermint::abci::Event as AbciEvent; - -use super::header::Header; -use crate::core::ics02_client::client_type::ClientType; -use crate::core::ics02_client::height::Height; -use crate::core::ics24_host::identifier::ClientId; -use crate::events::{IbcEvent, IbcEventType}; -use crate::prelude::*; - -/// The content of the `key` field for the attribute containing the client identifier. -pub const CLIENT_ID_ATTRIBUTE_KEY: &str = "client_id"; - -/// The content of the `key` field for the attribute containing the client type. -pub const CLIENT_TYPE_ATTRIBUTE_KEY: &str = "client_type"; - -/// The content of the `key` field for the attribute containing the height. -pub const CONSENSUS_HEIGHT_ATTRIBUTE_KEY: &str = "consensus_height"; - -/// The content of the `key` field for the header in update client event. -pub const HEADER_ATTRIBUTE_KEY: &str = "header"; - -/// NewBlock event signals the committing & execution of a new block. -// TODO - find a better place for NewBlock -#[derive(Debug, Serialize, Clone, Copy, PartialEq, Eq)] -pub struct NewBlock { - pub height: Height, -} - -impl NewBlock { - pub fn new(h: Height) -> NewBlock { - NewBlock { height: h } - } - pub fn set_height(&mut self, height: Height) { - self.height = height; - } - pub fn height(&self) -> Height { - self.height - } -} - -impl Display for NewBlock { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "NewBlock {{ height: {} }}", self.height) - } -} - -impl From for IbcEvent { - fn from(v: NewBlock) -> Self { - IbcEvent::NewBlock(v) - } -} - -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Attributes { - pub client_id: ClientId, - pub client_type: ClientType, - pub consensus_height: Height, -} - -impl Default for Attributes { - fn default() -> Self { - Attributes { - client_id: Default::default(), - client_type: ClientType::Tendermint, - consensus_height: Height::new(0, 1).unwrap(), - } - } -} - -impl Display for Attributes { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!( - f, - "Attributes {{ client_id: {}, client_type: {}, consensus_height: {} }}", - self.client_id, self.client_type, self.consensus_height - ) - } -} - -/// Convert attributes to Tendermint ABCI tags -/// -/// # Note -/// The parsing of `Key`s and `Value`s never fails, because the -/// `FromStr` instance of `tendermint::abci::tag::{Key, Value}` -/// is infallible, even if it is not represented in the error type. -/// Once tendermint-rs improves the API of the `Key` and `Value` types, -/// we will be able to remove the `.parse().unwrap()` calls. -impl From for Vec { - fn from(attrs: Attributes) -> Self { - let client_id = Tag { - key: CLIENT_ID_ATTRIBUTE_KEY.parse().unwrap(), - value: attrs.client_id.to_string().parse().unwrap(), - }; - let client_type = Tag { - key: CLIENT_TYPE_ATTRIBUTE_KEY.parse().unwrap(), - value: attrs.client_type.as_str().parse().unwrap(), - }; - let consensus_height = Tag { - key: CONSENSUS_HEIGHT_ATTRIBUTE_KEY.parse().unwrap(), - value: attrs.consensus_height.to_string().parse().unwrap(), - }; - vec![client_id, client_type, consensus_height] - } -} - -/// CreateClient event signals the creation of a new on-chain client (IBC client). -#[derive(Debug, Serialize, Clone, PartialEq, Eq)] -pub struct CreateClient(pub Attributes); - -impl CreateClient { - pub fn client_id(&self) -> &ClientId { - &self.0.client_id - } -} - -impl Display for CreateClient { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "CreateClient {{ {} }}", self.0) - } -} - -impl From for CreateClient { - fn from(attrs: Attributes) -> Self { - CreateClient(attrs) - } -} - -impl From for IbcEvent { - fn from(v: CreateClient) -> Self { - IbcEvent::CreateClient(v) - } -} - -impl From for AbciEvent { - fn from(v: CreateClient) -> Self { - let attributes = Vec::::from(v.0); - AbciEvent { - type_str: IbcEventType::CreateClient.as_str().to_string(), - attributes, - } - } -} - -/// UpdateClient event signals a recent update of an on-chain client (IBC Client). -#[derive(Clone, Debug, PartialEq, Serialize)] -pub struct UpdateClient { - pub common: Attributes, - pub header: Option>, -} - -impl UpdateClient { - pub fn client_id(&self) -> &ClientId { - &self.common.client_id - } - - pub fn client_type(&self) -> ClientType { - self.common.client_type - } - - pub fn consensus_height(&self) -> Height { - self.common.consensus_height - } -} - -impl Display for UpdateClient { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - // TODO Display: Check for a solution for Box - write!( - f, - "UpdateClient {{ common: {}, header: None }}", - self.common - ) - } -} - -impl From for UpdateClient { - fn from(attrs: Attributes) -> Self { - UpdateClient { - common: attrs, - header: None, - } - } -} - -impl From for IbcEvent { - fn from(v: UpdateClient) -> Self { - IbcEvent::UpdateClient(v) - } -} - -impl From for AbciEvent { - fn from(v: UpdateClient) -> Self { - let mut attributes = Vec::::from(v.common); - if let Some(h) = v.header { - let header = Tag { - key: HEADER_ATTRIBUTE_KEY.parse().unwrap(), - value: h.encode_to_hex_string().parse().unwrap(), - }; - attributes.push(header); - } - AbciEvent { - type_str: IbcEventType::UpdateClient.as_str().to_string(), - attributes, - } - } -} - -/// ClientMisbehaviour event signals the update of an on-chain client (IBC Client) with evidence of -/// misbehaviour. -#[derive(Debug, Serialize, Clone, PartialEq, Eq)] -pub struct ClientMisbehaviour(pub Attributes); - -impl ClientMisbehaviour { - pub fn client_id(&self) -> &ClientId { - &self.0.client_id - } -} - -impl Display for ClientMisbehaviour { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "ClientMisbehaviour {{ {} }}", self.0) - } -} - -impl From for ClientMisbehaviour { - fn from(attrs: Attributes) -> Self { - ClientMisbehaviour(attrs) - } -} - -impl From for IbcEvent { - fn from(v: ClientMisbehaviour) -> Self { - IbcEvent::ClientMisbehaviour(v) - } -} - -impl From for AbciEvent { - fn from(v: ClientMisbehaviour) -> Self { - let attributes = Vec::::from(v.0); - AbciEvent { - type_str: IbcEventType::ClientMisbehaviour.as_str().to_string(), - attributes, - } - } -} - -/// Signals a recent upgrade of an on-chain client (IBC Client). -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)] -pub struct UpgradeClient(pub Attributes); - -impl UpgradeClient { - pub fn client_id(&self) -> &ClientId { - &self.0.client_id - } -} - -impl Display for UpgradeClient { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "UpgradeClient {{ {} }}", self.0) - } -} - -impl From for UpgradeClient { - fn from(attrs: Attributes) -> Self { - UpgradeClient(attrs) - } -} - -impl From for AbciEvent { - fn from(v: UpgradeClient) -> Self { - let attributes = Vec::::from(v.0); - AbciEvent { - type_str: IbcEventType::UpgradeClient.as_str().to_string(), - attributes, - } - } -} diff --git a/modules/src/core/ics02_client/handler.rs b/modules/src/core/ics02_client/handler.rs deleted file mode 100644 index 638ab2654e..0000000000 --- a/modules/src/core/ics02_client/handler.rs +++ /dev/null @@ -1,32 +0,0 @@ -//! This module implements the processing logic for ICS2 (client abstractions and functions) msgs. - -use crate::core::ics02_client::context::ClientReader; -use crate::core::ics02_client::error::Error; -use crate::core::ics02_client::msgs::ClientMsg; -use crate::handler::HandlerOutput; - -pub mod create_client; -pub mod update_client; -pub mod upgrade_client; - -#[derive(Clone, Debug, PartialEq)] -pub enum ClientResult { - Create(create_client::Result), - Update(update_client::Result), - Upgrade(upgrade_client::Result), -} - -/// General entry point for processing any message related to ICS2 (client functions) protocols. -pub fn dispatch(ctx: &Ctx, msg: ClientMsg) -> Result, Error> -where - Ctx: ClientReader, -{ - match msg { - ClientMsg::CreateClient(msg) => create_client::process(ctx, msg), - ClientMsg::UpdateClient(msg) => update_client::process(ctx, msg), - ClientMsg::UpgradeClient(msg) => upgrade_client::process(ctx, msg), - _ => { - unimplemented!() - } - } -} diff --git a/modules/src/core/ics02_client/handler/create_client.rs b/modules/src/core/ics02_client/handler/create_client.rs deleted file mode 100644 index 6c7c73b96f..0000000000 --- a/modules/src/core/ics02_client/handler/create_client.rs +++ /dev/null @@ -1,298 +0,0 @@ -//! Protocol logic specific to processing ICS2 messages of type `MsgCreateClient`. - -use crate::prelude::*; - -use crate::core::ics02_client::client_state::ClientState; -use crate::core::ics02_client::client_type::ClientType; -use crate::core::ics02_client::consensus_state::ConsensusState; -use crate::core::ics02_client::context::ClientReader; -use crate::core::ics02_client::error::Error; -use crate::core::ics02_client::events::Attributes; -use crate::core::ics02_client::handler::ClientResult; -use crate::core::ics02_client::height::Height; -use crate::core::ics02_client::msgs::create_client::MsgCreateClient; -use crate::core::ics24_host::identifier::ClientId; -use crate::events::IbcEvent; -use crate::handler::{HandlerOutput, HandlerResult}; -use crate::timestamp::Timestamp; - -/// The result following the successful processing of a `MsgCreateClient` message. Preferably -/// this data type should be used with a qualified name `create_client::Result` to avoid ambiguity. -#[derive(Clone, Debug, PartialEq)] -pub struct Result { - pub client_id: ClientId, - pub client_type: ClientType, - pub client_state: Box, - pub consensus_state: Box, - pub processed_time: Timestamp, - pub processed_height: Height, -} - -pub fn process(ctx: &dyn ClientReader, msg: MsgCreateClient) -> HandlerResult { - let mut output = HandlerOutput::builder(); - - let MsgCreateClient { - client_state, - consensus_state, - signer: _, - } = msg; - - // Construct this client's identifier - let id_counter = ctx.client_counter()?; - - let client_state = ctx.decode_client_state(client_state)?; - - let client_type = client_state.client_type(); - - let client_id = ClientId::new(client_type, id_counter).map_err(|e| { - Error::client_identifier_constructor(client_state.client_type(), id_counter, e) - })?; - - let consensus_state = client_state.initialise(consensus_state)?; - - output.log(format!( - "success: generated new client identifier: {}", - client_id - )); - - let result = ClientResult::Create(Result { - client_id: client_id.clone(), - client_type, - client_state, - consensus_state, - processed_time: ctx.host_timestamp(), - processed_height: ctx.host_height(), - }); - - let event_attributes = Attributes { - client_id, - ..Default::default() - }; - output.emit(IbcEvent::CreateClient(event_attributes.into())); - - Ok(output.with_result(result)) -} - -#[cfg(test)] -mod tests { - use crate::prelude::*; - - use core::time::Duration; - use test_log::test; - - use crate::clients::ics07_tendermint::client_state::{ - AllowUpdate, ClientState as TmClientState, - }; - 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::client_type::ClientType; - use crate::core::ics02_client::handler::{dispatch, ClientResult}; - use crate::core::ics02_client::msgs::create_client::MsgCreateClient; - use crate::core::ics02_client::msgs::ClientMsg; - use crate::core::ics02_client::trust_threshold::TrustThreshold; - use crate::core::ics23_commitment::specs::ProofSpecs; - use crate::core::ics24_host::identifier::ClientId; - use crate::events::IbcEvent; - use crate::handler::HandlerOutput; - use crate::mock::client_state::MockClientState; - use crate::mock::consensus_state::MockConsensusState; - use crate::mock::context::MockContext; - use crate::mock::header::MockHeader; - use crate::test_utils::get_dummy_account_id; - use crate::Height; - - #[test] - fn test_create_client_ok() { - let ctx = MockContext::default(); - let signer = get_dummy_account_id(); - let height = Height::new(0, 42).unwrap(); - - let msg = MsgCreateClient::new( - MockClientState::new(MockHeader::new(height)).into(), - MockConsensusState::new(MockHeader::new(height)).into(), - signer, - ) - .unwrap(); - - let output = dispatch(&ctx, ClientMsg::CreateClient(msg.clone())); - - match output { - Ok(HandlerOutput { - result, mut events, .. - }) => { - assert_eq!(events.len(), 1); - let event = events.pop().unwrap(); - let expected_client_id = ClientId::new(ClientType::Mock, 0).unwrap(); - assert!( - matches!(event, IbcEvent::CreateClient(ref e) if e.client_id() == &expected_client_id) - ); - match result { - ClientResult::Create(create_result) => { - assert_eq!(create_result.client_type, ClientType::Mock); - assert_eq!(create_result.client_id, expected_client_id); - assert_eq!( - create_result.client_state.as_ref().clone_into(), - msg.client_state - ); - assert_eq!( - create_result.consensus_state.as_ref().clone_into(), - msg.consensus_state - ); - } - _ => { - panic!("unexpected result type: expected ClientResult::CreateResult!"); - } - } - } - Err(err) => { - panic!("unexpected error: {}", err); - } - } - } - - #[test] - fn test_create_client_ok_multiple() { - let existing_client_id = ClientId::default(); - let signer = get_dummy_account_id(); - let height_1 = Height::new(0, 80).unwrap(); - let height_2 = Height::new(0, 42).unwrap(); - let height_3 = Height::new(0, 50).unwrap(); - - let ctx = MockContext::default().with_client(&existing_client_id, height_1); - - let create_client_msgs: Vec = vec![ - MsgCreateClient::new( - MockClientState::new(MockHeader::new(height_2)).into(), - MockConsensusState::new(MockHeader::new(height_2)).into(), - signer.clone(), - ) - .unwrap(), - MsgCreateClient::new( - MockClientState::new(MockHeader::new(height_2)).into(), - MockConsensusState::new(MockHeader::new(height_2)).into(), - signer.clone(), - ) - .unwrap(), - MsgCreateClient::new( - MockClientState::new(MockHeader::new(height_3)).into(), - MockConsensusState::new(MockHeader::new(height_3)).into(), - signer, - ) - .unwrap(), - ] - .into_iter() - .collect(); - - // The expected client id that will be generated will be identical to "9999-mock-0" for all - // tests. This is because we're not persisting any client results (which is done via the - // tests for `ics26_routing::dispatch`. - let expected_client_id = ClientId::new(ClientType::Mock, 0).unwrap(); - - for msg in create_client_msgs { - let output = dispatch(&ctx, ClientMsg::CreateClient(msg.clone())); - - match output { - Ok(HandlerOutput { - result, mut events, .. - }) => { - assert_eq!(events.len(), 1); - let event = events.pop().unwrap(); - assert!( - matches!(event, IbcEvent::CreateClient(ref e) if e.client_id() == &expected_client_id) - ); - match result { - ClientResult::Create(create_res) => { - assert_eq!( - create_res.client_type, - create_res.client_state.client_type() - ); - assert_eq!(create_res.client_id, expected_client_id); - assert_eq!( - create_res.client_state.as_ref().clone_into(), - msg.client_state - ); - assert_eq!( - create_res.consensus_state.as_ref().clone_into(), - msg.consensus_state - ); - } - _ => { - panic!("expected result of type ClientResult::CreateResult"); - } - } - } - Err(err) => { - panic!("unexpected error: {}", err); - } - } - } - } - - #[test] - fn test_tm_create_client_ok() { - let signer = get_dummy_account_id(); - - let ctx = MockContext::default(); - - let tm_header = get_dummy_tendermint_header(); - - let tm_client_state = TmClientState::new( - tm_header.chain_id.clone().into(), - TrustThreshold::ONE_THIRD, - Duration::from_secs(64000), - Duration::from_secs(128000), - Duration::from_millis(3000), - Height::new(0, u64::from(tm_header.height)).unwrap(), - ProofSpecs::default(), - vec!["".to_string()], - AllowUpdate { - after_expiry: false, - after_misbehaviour: false, - }, - ) - .unwrap() - .into(); - - let msg = MsgCreateClient::new( - tm_client_state, - TmConsensusState::try_from(tm_header).unwrap().into(), - signer, - ) - .unwrap(); - - let output = dispatch(&ctx, ClientMsg::CreateClient(msg.clone())); - - match output { - Ok(HandlerOutput { - result, mut events, .. - }) => { - assert_eq!(events.len(), 1); - let event = events.pop().unwrap(); - let expected_client_id = ClientId::new(ClientType::Tendermint, 0).unwrap(); - assert!( - matches!(event, IbcEvent::CreateClient(ref e) if e.client_id() == &expected_client_id) - ); - match result { - ClientResult::Create(create_res) => { - assert_eq!(create_res.client_type, ClientType::Tendermint); - assert_eq!(create_res.client_id, expected_client_id); - assert_eq!( - create_res.client_state.as_ref().clone_into(), - msg.client_state - ); - assert_eq!( - create_res.consensus_state.as_ref().clone_into(), - msg.consensus_state - ); - } - _ => { - panic!("expected result of type ClientResult::CreateResult"); - } - } - } - Err(err) => { - panic!("unexpected error: {}", err); - } - } - } -} diff --git a/modules/src/core/ics02_client/handler/update_client.rs b/modules/src/core/ics02_client/handler/update_client.rs deleted file mode 100644 index 7184b5202a..0000000000 --- a/modules/src/core/ics02_client/handler/update_client.rs +++ /dev/null @@ -1,513 +0,0 @@ -//! Protocol logic specific to processing ICS2 messages of type `MsgUpdateAnyClient`. - -use tracing::debug; - -use crate::core::ics02_client::client_state::{ClientState, UpdatedState}; -use crate::core::ics02_client::consensus_state::ConsensusState; -use crate::core::ics02_client::context::ClientReader; -use crate::core::ics02_client::error::Error; -use crate::core::ics02_client::events::Attributes; -use crate::core::ics02_client::handler::ClientResult; -use crate::core::ics02_client::height::Height; -use crate::core::ics02_client::msgs::update_client::MsgUpdateClient; -use crate::core::ics24_host::identifier::ClientId; -use crate::events::IbcEvent; -use crate::handler::{HandlerOutput, HandlerResult}; -use crate::prelude::*; -use crate::timestamp::Timestamp; - -/// The result following the successful processing of a `MsgUpdateAnyClient` message. Preferably -/// this data type should be used with a qualified name `update_client::Result` to avoid ambiguity. -#[derive(Clone, Debug, PartialEq)] -pub struct Result { - pub client_id: ClientId, - pub client_state: Box, - pub consensus_state: Box, - pub processed_time: Timestamp, - pub processed_height: Height, -} - -pub fn process( - ctx: &Ctx, - msg: MsgUpdateClient, -) -> HandlerResult { - let mut output = HandlerOutput::builder(); - - let MsgUpdateClient { - client_id, - header, - signer: _, - } = msg; - - // Read client type from the host chain store. The client should already exist. - // Read client state from the host chain store. - let client_state = ctx.client_state(&client_id)?; - - if client_state.is_frozen() { - return Err(Error::client_frozen(client_id)); - } - - // Read consensus state from the host chain store. - let latest_consensus_state = - ClientReader::consensus_state(ctx, &client_id, client_state.latest_height()).map_err( - |_| Error::consensus_state_not_found(client_id.clone(), client_state.latest_height()), - )?; - - debug!("latest consensus state: {:?}", latest_consensus_state); - - let now = ClientReader::host_timestamp(ctx); - let duration = now - .duration_since(&latest_consensus_state.timestamp()) - .ok_or_else(|| { - Error::invalid_consensus_state_timestamp(latest_consensus_state.timestamp(), now) - })?; - - if client_state.expired(duration) { - return Err(Error::header_not_within_trust_period( - latest_consensus_state.timestamp(), - now, - )); - } - - // Use client_state to validate the new header against the latest consensus_state. - // This function will return the new client_state (its latest_height changed) and a - // consensus_state obtained from header. These will be later persisted by the keeper. - let UpdatedState { - client_state, - consensus_state, - } = client_state - .check_header_and_update_state(ctx, client_id.clone(), header) - .map_err(|e| Error::header_verification_failure(e.to_string()))?; - - let result = ClientResult::Update(Result { - client_id: client_id.clone(), - client_state, - consensus_state, - processed_time: ClientReader::host_timestamp(ctx), - processed_height: ctx.host_height(), - }); - - let event_attributes = Attributes { - client_id, - ..Default::default() - }; - output.emit(IbcEvent::UpdateClient(event_attributes.into())); - - Ok(output.with_result(result)) -} - -#[cfg(test)] -mod tests { - use core::str::FromStr; - use test_log::test; - - use crate::clients::ics07_tendermint::consensus_state::ConsensusState as TmConsensusState; - use crate::core::ics02_client::client_state::ClientState; - use crate::core::ics02_client::client_type::ClientType; - use crate::core::ics02_client::consensus_state::downcast_consensus_state; - use crate::core::ics02_client::error::{Error, ErrorDetail}; - use crate::core::ics02_client::handler::dispatch; - use crate::core::ics02_client::handler::ClientResult::Update; - use crate::core::ics02_client::msgs::update_client::MsgUpdateClient; - use crate::core::ics02_client::msgs::ClientMsg; - use crate::core::ics24_host::identifier::{ChainId, ClientId}; - use crate::events::IbcEvent; - use crate::handler::HandlerOutput; - use crate::mock::client_state::MockClientState; - use crate::mock::context::MockContext; - use crate::mock::header::MockHeader; - use crate::mock::host::{HostBlock, HostType}; - use crate::prelude::*; - use crate::test_utils::get_dummy_account_id; - use crate::timestamp::Timestamp; - use crate::Height; - - #[test] - fn test_update_client_ok() { - let client_id = ClientId::default(); - let signer = get_dummy_account_id(); - - let timestamp = Timestamp::now(); - - let ctx = MockContext::default().with_client(&client_id, Height::new(0, 42).unwrap()); - let height = Height::new(0, 46).unwrap(); - let msg = MsgUpdateClient { - client_id: client_id.clone(), - header: MockHeader::new(height).with_timestamp(timestamp).into(), - signer, - }; - - let output = dispatch(&ctx, ClientMsg::UpdateClient(msg.clone())); - - match output { - Ok(HandlerOutput { - result, - mut events, - log, - }) => { - assert_eq!(events.len(), 1); - let event = events.pop().unwrap(); - assert!( - matches!(event, IbcEvent::UpdateClient(ref e) if e.client_id() == &msg.client_id) - ); - assert!(log.is_empty()); - // Check the result - match result { - Update(upd_res) => { - assert_eq!(upd_res.client_id, client_id); - assert_eq!( - upd_res.client_state, - MockClientState::new(MockHeader::new(height).with_timestamp(timestamp)) - .into_box() - ) - } - _ => panic!("update handler result has incorrect type"), - } - } - Err(err) => { - panic!("unexpected error: {}", err); - } - } - } - - #[test] - fn test_update_nonexisting_client() { - let client_id = ClientId::from_str("mockclient1").unwrap(); - let signer = get_dummy_account_id(); - - let ctx = MockContext::default().with_client(&client_id, Height::new(0, 42).unwrap()); - - let msg = MsgUpdateClient { - client_id: ClientId::from_str("nonexistingclient").unwrap(), - header: MockHeader::new(Height::new(0, 46).unwrap()).into(), - signer, - }; - - let output = dispatch(&ctx, ClientMsg::UpdateClient(msg.clone())); - - match output { - Err(Error(ErrorDetail::ClientNotFound(e), _)) => { - assert_eq!(e.client_id, msg.client_id); - } - _ => { - panic!("expected ClientNotFound error, instead got {:?}", output) - } - } - } - - #[test] - fn test_update_client_ok_multiple() { - let client_ids = vec![ - ClientId::from_str("mockclient1").unwrap(), - ClientId::from_str("mockclient2").unwrap(), - ClientId::from_str("mockclient3").unwrap(), - ]; - let signer = get_dummy_account_id(); - let initial_height = Height::new(0, 45).unwrap(); - let update_height = Height::new(0, 49).unwrap(); - - let mut ctx = MockContext::default(); - - for cid in &client_ids { - ctx = ctx.with_client(cid, initial_height); - } - - for cid in &client_ids { - let msg = MsgUpdateClient { - client_id: cid.clone(), - header: MockHeader::new(update_height).into(), - signer: signer.clone(), - }; - - let output = dispatch(&ctx, ClientMsg::UpdateClient(msg.clone())); - - match output { - Ok(HandlerOutput { - result: _, - mut events, - log, - }) => { - assert_eq!(events.len(), 1); - let event = events.pop().unwrap(); - assert!( - matches!(event, IbcEvent::UpdateClient(ref e) if e.client_id() == &msg.client_id) - ); - assert!(log.is_empty()); - } - Err(err) => { - panic!("unexpected error: {}", err); - } - } - } - } - - #[test] - fn test_update_synthetic_tendermint_client_adjacent_ok() { - let client_id = ClientId::new(ClientType::Tendermint, 0).unwrap(); - let client_height = Height::new(1, 20).unwrap(); - let update_height = Height::new(1, 21).unwrap(); - - let ctx = MockContext::new( - ChainId::new("mockgaiaA".to_string(), 1), - HostType::Mock, - 5, - Height::new(1, 1).unwrap(), - ) - .with_client_parametrized( - &client_id, - client_height, - Some(ClientType::Tendermint), // The target host chain (B) is synthetic TM. - Some(client_height), - ); - - let ctx_b = MockContext::new( - ChainId::new("mockgaiaB".to_string(), 1), - HostType::SyntheticTendermint, - 5, - update_height, - ); - - let signer = get_dummy_account_id(); - - let mut block = ctx_b.host_block(update_height).unwrap().clone(); - block.set_trusted_height(client_height); - - let latest_header_height = block.height(); - let msg = MsgUpdateClient { - client_id: client_id.clone(), - header: block.into(), - signer, - }; - - let output = dispatch(&ctx, ClientMsg::UpdateClient(msg.clone())); - - match output { - Ok(HandlerOutput { - result, - mut events, - log, - }) => { - assert_eq!(events.len(), 1); - let event = events.pop().unwrap(); - assert!( - matches!(event, IbcEvent::UpdateClient(ref e) if e.client_id() == &msg.client_id) - ); - assert!(log.is_empty()); - // Check the result - match result { - Update(upd_res) => { - assert_eq!(upd_res.client_id, client_id); - assert!(!upd_res.client_state.is_frozen()); - assert_eq!(upd_res.client_state.latest_height(), latest_header_height,) - } - _ => panic!("update handler result has incorrect type"), - } - } - Err(err) => { - panic!("unexpected error: {}", err); - } - } - } - - #[test] - fn test_update_synthetic_tendermint_client_non_adjacent_ok() { - let client_id = ClientId::new(ClientType::Tendermint, 0).unwrap(); - let client_height = Height::new(1, 20).unwrap(); - let update_height = Height::new(1, 21).unwrap(); - - let ctx = MockContext::new( - ChainId::new("mockgaiaA".to_string(), 1), - HostType::Mock, - 5, - Height::new(1, 1).unwrap(), - ) - .with_client_parametrized_history( - &client_id, - client_height, - Some(ClientType::Tendermint), // The target host chain (B) is synthetic TM. - Some(client_height), - ); - - let ctx_b = MockContext::new( - ChainId::new("mockgaiaB".to_string(), 1), - HostType::SyntheticTendermint, - 5, - update_height, - ); - - let signer = get_dummy_account_id(); - - let mut block = ctx_b.host_block(update_height).unwrap().clone(); - let trusted_height = client_height.clone().sub(1).unwrap(); - block.set_trusted_height(trusted_height); - - let latest_header_height = block.height(); - let msg = MsgUpdateClient { - client_id: client_id.clone(), - header: block.into(), - signer, - }; - - let output = dispatch(&ctx, ClientMsg::UpdateClient(msg.clone())); - - match output { - Ok(HandlerOutput { - result, - mut events, - log, - }) => { - assert_eq!(events.len(), 1); - let event = events.pop().unwrap(); - assert!( - matches!(event, IbcEvent::UpdateClient(ref e) if e.client_id() == &msg.client_id) - ); - assert!(log.is_empty()); - // Check the result - match result { - Update(upd_res) => { - assert_eq!(upd_res.client_id, client_id); - assert!(!upd_res.client_state.is_frozen()); - assert_eq!(upd_res.client_state.latest_height(), latest_header_height,) - } - _ => panic!("update handler result has incorrect type"), - } - } - Err(err) => { - panic!("unexpected error: {}", err); - } - } - } - - #[test] - fn test_update_synthetic_tendermint_client_duplicate_ok() { - let client_id = ClientId::new(ClientType::Tendermint, 0).unwrap(); - let client_height = Height::new(1, 20).unwrap(); - - let chain_start_height = Height::new(1, 11).unwrap(); - - let ctx = MockContext::new( - ChainId::new("mockgaiaA".to_string(), 1), - HostType::Mock, - 5, - chain_start_height, - ) - .with_client_parametrized( - &client_id, - client_height, - Some(ClientType::Tendermint), // The target host chain (B) is synthetic TM. - Some(client_height), - ); - - let ctx_b = MockContext::new( - ChainId::new("mockgaiaB".to_string(), 1), - HostType::SyntheticTendermint, - 5, - client_height, - ); - - let signer = get_dummy_account_id(); - - let block = ctx_b.host_block(client_height).unwrap().clone(); - let block = match block { - HostBlock::SyntheticTendermint(mut theader) => { - let cons_state = ctx.latest_consensus_states(&client_id, &client_height); - if let Some(tcs) = downcast_consensus_state::(cons_state.as_ref()) - { - theader.light_block.signed_header.header.time = tcs.timestamp; - theader.trusted_height = Height::new(1, 11).unwrap(); - } - HostBlock::SyntheticTendermint(theader) - } - _ => block, - }; - - let latest_header_height = block.height(); - let msg = MsgUpdateClient { - client_id: client_id.clone(), - header: block.into(), - signer, - }; - - let output = dispatch(&ctx, ClientMsg::UpdateClient(msg.clone())); - - match output { - Ok(HandlerOutput { - result, - mut events, - log, - }) => { - assert_eq!(events.len(), 1); - let event = events.pop().unwrap(); - assert!( - matches!(event, IbcEvent::UpdateClient(ref e) if e.client_id() == &msg.client_id) - ); - assert!(log.is_empty()); - // Check the result - match result { - Update(upd_res) => { - assert_eq!(upd_res.client_id, client_id); - assert!(!upd_res.client_state.is_frozen()); - assert_eq!(upd_res.client_state, ctx.latest_client_states(&client_id)); - assert_eq!(upd_res.client_state.latest_height(), latest_header_height,) - } - _ => panic!("update handler result has incorrect type"), - } - } - Err(err) => { - panic!("unexpected error: {:?}", err); - } - } - } - - #[test] - fn test_update_synthetic_tendermint_client_lower_height() { - let client_id = ClientId::new(ClientType::Tendermint, 0).unwrap(); - let client_height = Height::new(1, 20).unwrap(); - - let client_update_height = Height::new(1, 19).unwrap(); - - let chain_start_height = Height::new(1, 11).unwrap(); - - let ctx = MockContext::new( - ChainId::new("mockgaiaA".to_string(), 1), - HostType::Mock, - 5, - chain_start_height, - ) - .with_client_parametrized( - &client_id, - client_height, - Some(ClientType::Tendermint), // The target host chain (B) is synthetic TM. - Some(client_height), - ); - - let ctx_b = MockContext::new( - ChainId::new("mockgaiaB".to_string(), 1), - HostType::SyntheticTendermint, - 5, - client_height, - ); - - let signer = get_dummy_account_id(); - - let block_ref = ctx_b.host_block(client_update_height).unwrap(); - - let msg = MsgUpdateClient { - client_id, - header: block_ref.clone().into(), - signer, - }; - - let output = dispatch(&ctx, ClientMsg::UpdateClient(msg)); - - match output { - Ok(_) => { - panic!("update handler result has incorrect type"); - } - Err(err) => match err.detail() { - ErrorDetail::HeaderVerificationFailure(_) => {} - _ => panic!("unexpected error: {:?}", err), - }, - } - } -} diff --git a/modules/src/core/ics02_client/handler/upgrade_client.rs b/modules/src/core/ics02_client/handler/upgrade_client.rs deleted file mode 100644 index c6c0ab9edf..0000000000 --- a/modules/src/core/ics02_client/handler/upgrade_client.rs +++ /dev/null @@ -1,203 +0,0 @@ -//! Protocol logic specific to processing ICS2 messages of type `MsgUpgradeAnyClient`. -//! -use crate::core::ics02_client::client_state::{ClientState, UpdatedState}; -use crate::core::ics02_client::consensus_state::ConsensusState; -use crate::core::ics02_client::context::ClientReader; -use crate::core::ics02_client::error::Error; -use crate::core::ics02_client::events::Attributes; -use crate::core::ics02_client::handler::ClientResult; -use crate::core::ics02_client::msgs::upgrade_client::MsgUpgradeClient; -use crate::core::ics24_host::identifier::ClientId; -use crate::events::IbcEvent; -use crate::handler::{HandlerOutput, HandlerResult}; -use crate::prelude::*; - -/// The result following the successful processing of a `MsgUpgradeAnyClient` message. -/// This data type should be used with a qualified name `upgrade_client::Result` to avoid ambiguity. -#[derive(Clone, Debug, PartialEq)] -pub struct Result { - pub client_id: ClientId, - pub client_state: Box, - pub consensus_state: Box, -} - -pub fn process( - ctx: &dyn ClientReader, - msg: MsgUpgradeClient, -) -> HandlerResult { - let mut output = HandlerOutput::builder(); - let MsgUpgradeClient { client_id, .. } = msg; - - // Read client state from the host chain store. - let old_client_state = ctx.client_state(&client_id)?; - - if old_client_state.is_frozen() { - return Err(Error::client_frozen(client_id)); - } - - let upgrade_client_state = ctx.decode_client_state(msg.client_state)?; - - if old_client_state.latest_height() >= upgrade_client_state.latest_height() { - return Err(Error::low_upgrade_height( - old_client_state.latest_height(), - upgrade_client_state.latest_height(), - )); - } - - let UpdatedState { - client_state, - consensus_state, - } = upgrade_client_state.verify_upgrade_and_update_state( - msg.consensus_state.clone(), - msg.proof_upgrade_client.clone(), - msg.proof_upgrade_consensus_state, - )?; - - // Not implemented yet: https://github.com/informalsystems/ibc-rs/issues/722 - // todo!() - - let result = ClientResult::Upgrade(Result { - client_id: client_id.clone(), - client_state, - consensus_state, - }); - let event_attributes = Attributes { - client_id, - ..Default::default() - }; - - output.emit(IbcEvent::UpgradeClient(event_attributes.into())); - Ok(output.with_result(result)) -} - -#[cfg(test)] -mod tests { - use crate::prelude::*; - - use core::str::FromStr; - - use crate::core::ics02_client::error::{Error, ErrorDetail}; - use crate::core::ics02_client::handler::dispatch; - use crate::core::ics02_client::handler::ClientResult::Upgrade; - use crate::core::ics02_client::msgs::upgrade_client::MsgUpgradeClient; - use crate::core::ics02_client::msgs::ClientMsg; - use crate::core::ics24_host::identifier::ClientId; - use crate::events::IbcEvent; - use crate::handler::HandlerOutput; - use crate::mock::client_state::MockClientState; - use crate::mock::consensus_state::MockConsensusState; - use crate::mock::context::MockContext; - use crate::mock::header::MockHeader; - use crate::test_utils::get_dummy_account_id; - use crate::Height; - - #[test] - fn test_upgrade_client_ok() { - let client_id = ClientId::default(); - let signer = get_dummy_account_id(); - - let ctx = MockContext::default().with_client(&client_id, Height::new(0, 42).unwrap()); - - let msg = MsgUpgradeClient { - client_id: client_id.clone(), - client_state: MockClientState::new(MockHeader::new(Height::new(1, 26).unwrap())).into(), - consensus_state: MockConsensusState::new(MockHeader::new(Height::new(1, 26).unwrap())) - .into(), - proof_upgrade_client: Default::default(), - proof_upgrade_consensus_state: Default::default(), - signer, - }; - - let output = dispatch(&ctx, ClientMsg::UpgradeClient(msg.clone())); - - match output { - Ok(HandlerOutput { - result, - mut events, - log, - }) => { - assert_eq!(events.len(), 1); - let event = events.pop().unwrap(); - assert!( - matches!(event, IbcEvent::UpgradeClient(ref e) if e.client_id() == &msg.client_id) - ); - assert!(log.is_empty()); - // Check the result - match result { - Upgrade(upg_res) => { - assert_eq!(upg_res.client_id, client_id); - assert_eq!(upg_res.client_state.as_ref().clone_into(), msg.client_state) - } - _ => panic!("upgrade handler result has incorrect type"), - } - } - Err(err) => { - panic!("unexpected error: {}", err); - } - } - } - - #[test] - fn test_upgrade_nonexisting_client() { - let client_id = ClientId::from_str("mockclient1").unwrap(); - let signer = get_dummy_account_id(); - - let ctx = MockContext::default().with_client(&client_id, Height::new(0, 42).unwrap()); - - let msg = MsgUpgradeClient { - client_id: ClientId::from_str("nonexistingclient").unwrap(), - client_state: MockClientState::new(MockHeader::new(Height::new(1, 26).unwrap())).into(), - consensus_state: MockConsensusState::new(MockHeader::new(Height::new(1, 26).unwrap())) - .into(), - proof_upgrade_client: Default::default(), - proof_upgrade_consensus_state: Default::default(), - signer, - }; - - let output = dispatch(&ctx, ClientMsg::UpgradeClient(msg.clone())); - - match output { - Err(Error(ErrorDetail::ClientNotFound(e), _)) => { - assert_eq!(e.client_id, msg.client_id); - } - _ => { - panic!("expected ClientNotFound error, instead got {:?}", output); - } - } - } - - #[test] - fn test_upgrade_client_low_height() { - let client_id = ClientId::default(); - let signer = get_dummy_account_id(); - - let ctx = MockContext::default().with_client(&client_id, Height::new(0, 42).unwrap()); - - let msg = MsgUpgradeClient { - client_id, - client_state: MockClientState::new(MockHeader::new(Height::new(0, 26).unwrap())).into(), - consensus_state: MockConsensusState::new(MockHeader::new(Height::new(0, 26).unwrap())) - .into(), - proof_upgrade_client: Default::default(), - proof_upgrade_consensus_state: Default::default(), - signer, - }; - - let output = dispatch(&ctx, ClientMsg::UpgradeClient(msg.clone())); - - match output { - Err(Error(ErrorDetail::LowUpgradeHeight(e), _)) => { - assert_eq!(e.upgraded_height, Height::new(0, 42).unwrap()); - assert_eq!( - e.client_height, - MockClientState::try_from(msg.client_state) - .unwrap() - .latest_height() - ); - } - _ => { - panic!("expected LowUpgradeHeight error, instead got {:?}", output); - } - } - } -} diff --git a/modules/src/core/ics02_client/header.rs b/modules/src/core/ics02_client/header.rs deleted file mode 100644 index 99f05c886b..0000000000 --- a/modules/src/core/ics02_client/header.rs +++ /dev/null @@ -1,82 +0,0 @@ -use crate::prelude::*; - -use dyn_clone::DynClone; -use erased_serde::Serialize as ErasedSerialize; -use ibc_proto::google::protobuf::Any; -use ibc_proto::protobuf::Protobuf as ErasedProtobuf; - -use crate::core::ics02_client::client_type::ClientType; -use crate::core::ics02_client::error::Error; -use crate::dynamic_typing::AsAny; -use crate::timestamp::Timestamp; -use crate::Height; - -/// Abstract of consensus state update information -/// -/// Users are not expected to implement sealed::ErasedPartialEqHeader. -/// Effectively, that trait bound mandates implementors to derive PartialEq, -/// after which our blanket implementation will implement -/// `ErasedPartialEqHeader` for their type. -pub trait Header: - AsAny - + sealed::ErasedPartialEqHeader - + DynClone - + ErasedSerialize - + ErasedProtobuf - + core::fmt::Debug - + Send - + Sync -{ - /// The type of client (eg. Tendermint) - fn client_type(&self) -> ClientType; - - /// The height of the consensus state - fn height(&self) -> Height; - - /// The timestamp of the consensus state - fn timestamp(&self) -> Timestamp; - - /// Convert into a boxed trait object - fn into_box(self) -> Box - where - Self: Sized, - { - Box::new(self) - } -} - -// Implements `Clone` for `Box` -dyn_clone::clone_trait_object!(Header); - -// Implements `serde::Serialize` for all types that have Header as supertrait -erased_serde::serialize_trait_object!(Header); - -pub fn downcast_header(h: &dyn Header) -> Option<&H> { - h.as_any().downcast_ref::() -} - -impl PartialEq for dyn Header { - fn eq(&self, other: &Self) -> bool { - self.eq_header(other) - } -} - -mod sealed { - use super::*; - - pub trait ErasedPartialEqHeader { - fn eq_header(&self, other: &dyn Header) -> bool; - } - - impl ErasedPartialEqHeader for H - where - H: Header + PartialEq, - { - fn eq_header(&self, other: &dyn Header) -> bool { - other - .as_any() - .downcast_ref::() - .map_or(false, |h| self == h) - } - } -} diff --git a/modules/src/core/ics02_client/height.rs b/modules/src/core/ics02_client/height.rs deleted file mode 100644 index 9dee17454c..0000000000 --- a/modules/src/core/ics02_client/height.rs +++ /dev/null @@ -1,172 +0,0 @@ -use crate::prelude::*; -use core::cmp::Ordering; - -use core::num::ParseIntError; -use core::str::FromStr; - -use flex_error::{define_error, TraceError}; -use ibc_proto::protobuf::Protobuf; -use serde_derive::{Deserialize, Serialize}; - -use ibc_proto::ibc::core::client::v1::Height as RawHeight; - -use crate::core::ics02_client::error::Error; - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct Height { - /// Previously known as "epoch" - revision_number: u64, - - /// The height of a block - revision_height: u64, -} - -impl Height { - pub fn new(revision_number: u64, revision_height: u64) -> Result { - if revision_height == 0 { - return Err(Error::invalid_height()); - } - - Ok(Self { - revision_number, - revision_height, - }) - } - - pub fn revision_number(&self) -> u64 { - self.revision_number - } - - pub fn revision_height(&self) -> u64 { - self.revision_height - } - - pub fn add(&self, delta: u64) -> Height { - Height { - revision_number: self.revision_number, - revision_height: self.revision_height + delta, - } - } - - pub fn increment(&self) -> Height { - self.add(1) - } - - pub fn sub(&self, delta: u64) -> Result { - if self.revision_height <= delta { - return Err(Error::invalid_height_result()); - } - - Ok(Height { - revision_number: self.revision_number, - revision_height: self.revision_height - delta, - }) - } - - pub fn decrement(&self) -> Result { - self.sub(1) - } -} - -impl PartialOrd for Height { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Height { - fn cmp(&self, other: &Self) -> Ordering { - if self.revision_number < other.revision_number { - Ordering::Less - } else if self.revision_number > other.revision_number { - Ordering::Greater - } else if self.revision_height < other.revision_height { - Ordering::Less - } else if self.revision_height > other.revision_height { - Ordering::Greater - } else { - Ordering::Equal - } - } -} - -impl Protobuf for Height {} - -impl TryFrom for Height { - type Error = Error; - - fn try_from(raw_height: RawHeight) -> Result { - Height::new(raw_height.revision_number, raw_height.revision_height) - } -} - -impl From for RawHeight { - fn from(ics_height: Height) -> Self { - RawHeight { - revision_number: ics_height.revision_number, - revision_height: ics_height.revision_height, - } - } -} - -impl core::fmt::Debug for Height { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - f.debug_struct("Height") - .field("revision", &self.revision_number) - .field("height", &self.revision_height) - .finish() - } -} - -/// Custom debug output to omit the packet data -impl core::fmt::Display for Height { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - write!(f, "{}-{}", self.revision_number, self.revision_height) - } -} - -define_error! { - #[derive(Debug, PartialEq, Eq)] - HeightError { - HeightConversion - { height: String } - [ TraceError ] - | e | { - format_args!("cannot convert into a `Height` type from string {0}", - e.height) - }, - ZeroHeight - |_| { "attempted to parse an invalid zero height" } - } -} - -impl TryFrom<&str> for Height { - type Error = HeightError; - - fn try_from(value: &str) -> Result { - let split: Vec<&str> = value.split('-').collect(); - - let revision_number = split[0] - .parse::() - .map_err(|e| HeightError::height_conversion(value.to_owned(), e))?; - let revision_height = split[1] - .parse::() - .map_err(|e| HeightError::height_conversion(value.to_owned(), e))?; - - Height::new(revision_number, revision_height).map_err(|_| HeightError::zero_height()) - } -} - -impl From for String { - fn from(height: Height) -> Self { - format!("{}-{}", height.revision_number, height.revision_height) - } -} - -impl FromStr for Height { - type Err = HeightError; - - fn from_str(s: &str) -> Result { - Height::try_from(s) - } -} diff --git a/modules/src/core/ics02_client/misbehaviour.rs b/modules/src/core/ics02_client/misbehaviour.rs deleted file mode 100644 index be2acfc424..0000000000 --- a/modules/src/core/ics02_client/misbehaviour.rs +++ /dev/null @@ -1,45 +0,0 @@ -use dyn_clone::DynClone; - -use crate::dynamic_typing::AsAny; -use crate::prelude::*; - -use crate::core::ics24_host::identifier::ClientId; -use crate::Height; - -pub trait Misbehaviour: - AsAny + sealed::ErasedPartialEqMisbehaviour + DynClone + core::fmt::Debug + Send + Sync -{ - /// The type of client (eg. Tendermint) - fn client_id(&self) -> &ClientId; - - /// The height of the consensus state - fn height(&self) -> Height; -} - -// Implements `Clone` for `Box` -dyn_clone::clone_trait_object!(Misbehaviour); - -impl PartialEq for dyn Misbehaviour { - fn eq(&self, other: &Self) -> bool { - self.eq_misbehaviour(other) - } -} -mod sealed { - use super::*; - - pub trait ErasedPartialEqMisbehaviour { - fn eq_misbehaviour(&self, other: &dyn Misbehaviour) -> bool; - } - - impl ErasedPartialEqMisbehaviour for H - where - H: Misbehaviour + PartialEq, - { - fn eq_misbehaviour(&self, other: &dyn Misbehaviour) -> bool { - other - .as_any() - .downcast_ref::() - .map_or(false, |h| self == h) - } - } -} diff --git a/modules/src/core/ics02_client/mod.rs b/modules/src/core/ics02_client/mod.rs deleted file mode 100644 index 3e9dec5836..0000000000 --- a/modules/src/core/ics02_client/mod.rs +++ /dev/null @@ -1,14 +0,0 @@ -//! ICS 02: Client implementation for verifying remote IBC-enabled chains. - -pub mod client_state; -pub mod client_type; -pub mod consensus_state; -pub mod context; -pub mod error; -pub mod events; -pub mod handler; -pub mod header; -pub mod height; -pub mod misbehaviour; -pub mod msgs; -pub mod trust_threshold; diff --git a/modules/src/core/ics02_client/msgs.rs b/modules/src/core/ics02_client/msgs.rs deleted file mode 100644 index ac28763ee5..0000000000 --- a/modules/src/core/ics02_client/msgs.rs +++ /dev/null @@ -1,24 +0,0 @@ -//! These are definitions of messages that a relayer submits to a chain. Specific implementations of -//! these messages can be found, for instance, in ICS 07 for Tendermint-specific chains. A chain -//! handles these messages in two layers: first with the general ICS 02 client handler, which -//! subsequently calls into the chain-specific (e.g., ICS 07) client handler. See: -//! . - -use crate::core::ics02_client::msgs::create_client::MsgCreateClient; -use crate::core::ics02_client::msgs::misbehaviour::MsgSubmitMisbehaviour; -use crate::core::ics02_client::msgs::update_client::MsgUpdateClient; -use crate::core::ics02_client::msgs::upgrade_client::MsgUpgradeClient; - -pub mod create_client; -pub mod misbehaviour; -pub mod update_client; -pub mod upgrade_client; - -#[allow(clippy::large_enum_variant)] -#[derive(Clone, Debug)] -pub enum ClientMsg { - CreateClient(MsgCreateClient), - UpdateClient(MsgUpdateClient), - Misbehaviour(MsgSubmitMisbehaviour), - UpgradeClient(MsgUpgradeClient), -} diff --git a/modules/src/core/ics02_client/msgs/create_client.rs b/modules/src/core/ics02_client/msgs/create_client.rs deleted file mode 100644 index 496e28638d..0000000000 --- a/modules/src/core/ics02_client/msgs/create_client.rs +++ /dev/null @@ -1,111 +0,0 @@ -//! Definition of domain type message `MsgCreateClient`. - -use crate::prelude::*; - -use ibc_proto::google::protobuf::Any; -use ibc_proto::ibc::core::client::v1::MsgCreateClient as RawMsgCreateClient; -use ibc_proto::protobuf::Protobuf; - -use crate::core::ics02_client::error::Error; -use crate::signer::Signer; -use crate::tx_msg::Msg; - -pub const TYPE_URL: &str = "/ibc.core.client.v1.MsgCreateClient"; - -/// A type of message that triggers the creation of a new on-chain (IBC) client. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct MsgCreateClient { - pub client_state: Any, - pub consensus_state: Any, - pub signer: Signer, -} - -impl MsgCreateClient { - pub fn new(client_state: Any, consensus_state: Any, signer: Signer) -> Result { - Ok(MsgCreateClient { - client_state, - consensus_state, - signer, - }) - } -} - -impl Msg for MsgCreateClient { - type ValidationError = crate::core::ics24_host::error::ValidationError; - type Raw = RawMsgCreateClient; - - fn route(&self) -> String { - crate::keys::ROUTER_KEY.to_string() - } - - fn type_url(&self) -> String { - TYPE_URL.to_string() - } -} - -impl Protobuf for MsgCreateClient {} - -impl TryFrom for MsgCreateClient { - type Error = Error; - - fn try_from(raw: RawMsgCreateClient) -> Result { - let raw_client_state = raw - .client_state - .ok_or_else(Error::missing_raw_client_state)?; - - let raw_consensus_state = raw - .consensus_state - .ok_or_else(Error::missing_raw_client_state)?; - - MsgCreateClient::new( - raw_client_state, - raw_consensus_state, - raw.signer.parse().map_err(Error::signer)?, - ) - } -} - -impl From for RawMsgCreateClient { - fn from(ics_msg: MsgCreateClient) -> Self { - RawMsgCreateClient { - client_state: Some(ics_msg.client_state), - consensus_state: Some(ics_msg.consensus_state), - signer: ics_msg.signer.to_string(), - } - } -} - -#[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::try_from(tm_header).unwrap().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/modules/src/core/ics02_client/msgs/misbehaviour.rs b/modules/src/core/ics02_client/msgs/misbehaviour.rs deleted file mode 100644 index 07923bae8f..0000000000 --- a/modules/src/core/ics02_client/msgs/misbehaviour.rs +++ /dev/null @@ -1,67 +0,0 @@ -use crate::prelude::*; - -use ibc_proto::google::protobuf::Any as ProtoAny; -use ibc_proto::ibc::core::client::v1::MsgSubmitMisbehaviour as RawMsgSubmitMisbehaviour; -use ibc_proto::protobuf::Protobuf; - -use crate::core::ics02_client::error::Error; -use crate::core::ics24_host::identifier::ClientId; -use crate::signer::Signer; -use crate::tx_msg::Msg; - -pub const TYPE_URL: &str = "/ibc.core.client.v1.MsgSubmitMisbehaviour"; - -/// A type of message that submits client misbehaviour proof. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct MsgSubmitMisbehaviour { - /// client unique identifier - pub client_id: ClientId, - /// misbehaviour used for freezing the light client - pub misbehaviour: ProtoAny, - /// signer address - pub signer: Signer, -} - -impl Msg for MsgSubmitMisbehaviour { - type ValidationError = crate::core::ics24_host::error::ValidationError; - type Raw = RawMsgSubmitMisbehaviour; - - fn route(&self) -> String { - crate::keys::ROUTER_KEY.to_string() - } - - fn type_url(&self) -> String { - TYPE_URL.to_string() - } -} - -impl Protobuf for MsgSubmitMisbehaviour {} - -impl TryFrom for MsgSubmitMisbehaviour { - type Error = Error; - - fn try_from(raw: RawMsgSubmitMisbehaviour) -> Result { - let raw_misbehaviour = raw - .misbehaviour - .ok_or_else(Error::missing_raw_misbehaviour)?; - - Ok(MsgSubmitMisbehaviour { - client_id: raw - .client_id - .parse() - .map_err(Error::invalid_raw_misbehaviour)?, - misbehaviour: raw_misbehaviour, - signer: raw.signer.parse().map_err(Error::signer)?, - }) - } -} - -impl From for RawMsgSubmitMisbehaviour { - fn from(ics_msg: MsgSubmitMisbehaviour) -> Self { - RawMsgSubmitMisbehaviour { - client_id: ics_msg.client_id.to_string(), - misbehaviour: Some(ics_msg.misbehaviour), - signer: ics_msg.signer.to_string(), - } - } -} diff --git a/modules/src/core/ics02_client/msgs/update_client.rs b/modules/src/core/ics02_client/msgs/update_client.rs deleted file mode 100644 index dcc3dc9753..0000000000 --- a/modules/src/core/ics02_client/msgs/update_client.rs +++ /dev/null @@ -1,101 +0,0 @@ -//! Definition of domain type message `MsgUpdateAnyClient`. - -use crate::prelude::*; - -use ibc_proto::google::protobuf::Any; -use ibc_proto::ibc::core::client::v1::MsgUpdateClient as RawMsgUpdateClient; -use ibc_proto::protobuf::Protobuf; - -use crate::core::ics02_client::error::Error; -use crate::core::ics24_host::error::ValidationError; -use crate::core::ics24_host::identifier::ClientId; -use crate::signer::Signer; -use crate::tx_msg::Msg; - -pub const TYPE_URL: &str = "/ibc.core.client.v1.MsgUpdateClient"; - -/// A type of message that triggers the update of an on-chain (IBC) client with new headers. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct MsgUpdateClient { - pub client_id: ClientId, - pub header: Any, - pub signer: Signer, -} - -impl MsgUpdateClient { - pub fn new(client_id: ClientId, header: Any, signer: Signer) -> Self { - MsgUpdateClient { - client_id, - header, - signer, - } - } -} - -impl Msg for MsgUpdateClient { - type ValidationError = ValidationError; - type Raw = RawMsgUpdateClient; - - fn route(&self) -> String { - crate::keys::ROUTER_KEY.to_string() - } - - fn type_url(&self) -> String { - TYPE_URL.to_string() - } -} - -impl Protobuf for MsgUpdateClient {} - -impl TryFrom for MsgUpdateClient { - type Error = Error; - - fn try_from(raw: RawMsgUpdateClient) -> Result { - Ok(MsgUpdateClient { - client_id: raw - .client_id - .parse() - .map_err(Error::invalid_msg_update_client_id)?, - header: raw.header.ok_or_else(Error::missing_raw_header)?, - signer: raw.signer.parse().map_err(Error::signer)?, - }) - } -} - -impl From for RawMsgUpdateClient { - fn from(ics_msg: MsgUpdateClient) -> Self { - RawMsgUpdateClient { - client_id: ics_msg.client_id.to_string(), - header: Some(ics_msg.header), - signer: ics_msg.signer.to_string(), - } - } -} - -#[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/modules/src/core/ics02_client/msgs/upgrade_client.rs b/modules/src/core/ics02_client/msgs/upgrade_client.rs deleted file mode 100644 index f8d1b9fa17..0000000000 --- a/modules/src/core/ics02_client/msgs/upgrade_client.rs +++ /dev/null @@ -1,196 +0,0 @@ -//! Definition of domain type msg `MsgUpgradeAnyClient`. - -use crate::prelude::*; - -use core::str::FromStr; - -use ibc_proto::google::protobuf::Any; -use ibc_proto::ibc::core::client::v1::MsgUpgradeClient as RawMsgUpgradeClient; -use ibc_proto::ibc::core::commitment::v1::MerkleProof as RawMerkleProof; -use ibc_proto::protobuf::Protobuf; - -use crate::core::ics02_client::error::Error; -use crate::core::ics23_commitment::commitment::CommitmentProofBytes; -use crate::core::ics23_commitment::error::Error as Ics23Error; -use crate::core::ics24_host::identifier::ClientId; -use crate::signer::Signer; -use crate::tx_msg::Msg; - -pub(crate) const TYPE_URL: &str = "/ibc.core.client.v1.MsgUpgradeClient"; - -/// A type of message that triggers the upgrade of an on-chain (IBC) client. -#[derive(Clone, Debug, PartialEq)] -pub struct MsgUpgradeClient { - pub client_id: ClientId, - pub client_state: Any, - pub consensus_state: Any, - pub proof_upgrade_client: RawMerkleProof, - pub proof_upgrade_consensus_state: RawMerkleProof, - pub signer: Signer, -} - -impl MsgUpgradeClient { - pub fn new( - client_id: ClientId, - client_state: Any, - consensus_state: Any, - proof_upgrade_client: RawMerkleProof, - proof_upgrade_consensus_state: RawMerkleProof, - signer: Signer, - ) -> Self { - MsgUpgradeClient { - client_id, - client_state, - consensus_state, - proof_upgrade_client, - proof_upgrade_consensus_state, - signer, - } - } -} - -impl Msg for MsgUpgradeClient { - type ValidationError = crate::core::ics24_host::error::ValidationError; - type Raw = RawMsgUpgradeClient; - - fn route(&self) -> String { - crate::keys::ROUTER_KEY.to_string() - } - - fn type_url(&self) -> String { - TYPE_URL.to_string() - } -} - -impl Protobuf for MsgUpgradeClient {} - -impl From for RawMsgUpgradeClient { - fn from(dm_msg: MsgUpgradeClient) -> RawMsgUpgradeClient { - let c_bytes = CommitmentProofBytes::try_from(dm_msg.proof_upgrade_client) - .map_or(vec![], |c| c.into()); - let cs_bytes = CommitmentProofBytes::try_from(dm_msg.proof_upgrade_consensus_state) - .map_or(vec![], |c| c.into()); - - RawMsgUpgradeClient { - client_id: dm_msg.client_id.to_string(), - client_state: Some(dm_msg.client_state), - consensus_state: Some(dm_msg.consensus_state), - proof_upgrade_client: c_bytes, - proof_upgrade_consensus_state: cs_bytes, - signer: dm_msg.signer.to_string(), - } - } -} - -impl TryFrom for MsgUpgradeClient { - type Error = Error; - - fn try_from(proto_msg: RawMsgUpgradeClient) -> Result { - let raw_client_state = proto_msg - .client_state - .ok_or_else(Error::missing_raw_client_state)?; - - let raw_consensus_state = proto_msg - .consensus_state - .ok_or_else(Error::missing_raw_client_state)?; - - let c_bytes = CommitmentProofBytes::try_from(proto_msg.proof_upgrade_client) - .map_err(|_| Error::invalid_upgrade_client_proof(Ics23Error::empty_merkle_proof()))?; - let cs_bytes = CommitmentProofBytes::try_from(proto_msg.proof_upgrade_consensus_state) - .map_err(|_| { - Error::invalid_upgrade_consensus_state_proof(Ics23Error::empty_merkle_proof()) - })?; - - Ok(MsgUpgradeClient { - client_id: ClientId::from_str(&proto_msg.client_id) - .map_err(Error::invalid_client_identifier)?, - client_state: raw_client_state, - consensus_state: raw_consensus_state, - proof_upgrade_client: RawMerkleProof::try_from(c_bytes) - .map_err(Error::invalid_upgrade_client_proof)?, - proof_upgrade_consensus_state: RawMerkleProof::try_from(cs_bytes) - .map_err(Error::invalid_upgrade_consensus_state_proof)?, - signer: proto_msg.signer.parse().map_err(Error::signer)?, - }) - } -} - -#[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/modules/src/core/ics02_client/trust_threshold.rs b/modules/src/core/ics02_client/trust_threshold.rs deleted file mode 100644 index 4202b66118..0000000000 --- a/modules/src/core/ics02_client/trust_threshold.rs +++ /dev/null @@ -1,133 +0,0 @@ -//! IBC Domain type definition for [`TrustThreshold`] -//! represented as a fraction with valid values in the -//! range `[0, 1)`. - -use core::{ - convert::TryFrom, - fmt::{Display, Error as FmtError, Formatter}, -}; - -use ibc_proto::protobuf::Protobuf; -use serde::{Deserialize, Serialize}; - -use ibc_proto::ibc::lightclients::tendermint::v1::Fraction; -use tendermint::trust_threshold::TrustThresholdFraction; - -use crate::core::ics02_client::error::Error; - -/// [`TrustThreshold`] defines the level of trust that a client has -/// towards a set of validators of a chain. -/// -/// A trust threshold is represented as a fraction, i.e., a numerator and -/// and a denominator. -/// A typical trust threshold is 1/3 in practice. -/// This type accepts even a value of 0, (numerator = 0, denominator = 0), -/// which is used in the client state of an upgrading client. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct TrustThreshold { - numerator: u64, - denominator: u64, -} - -impl TrustThreshold { - /// Constant for a trust threshold of 1/3. - pub const ONE_THIRD: Self = Self { - numerator: 1, - denominator: 3, - }; - - /// Constant for a trust threshold of 2/3. - pub const TWO_THIRDS: Self = Self { - numerator: 2, - denominator: 3, - }; - - /// Constant for a trust threshold of 0/0. - pub const ZERO: Self = Self { - numerator: 0, - denominator: 0, - }; - - /// Instantiate a TrustThreshold with the given denominator and - /// numerator. - /// - /// The constructor succeeds if long as the resulting fraction - /// is in the range`[0, 1)`. - pub fn new(numerator: u64, denominator: u64) -> Result { - // The two parameters cannot yield a fraction that is bigger or equal to 1 - if (numerator > denominator) - || (denominator == 0 && numerator != 0) - || (numerator == denominator && numerator != 0) - { - return Err(Error::invalid_trust_threshold(numerator, denominator)); - } - - Ok(Self { - numerator, - denominator, - }) - } - - /// The numerator of the fraction underlying this trust threshold. - pub fn numerator(&self) -> u64 { - self.numerator - } - - /// The denominator of the fraction underlying this trust threshold. - pub fn denominator(&self) -> u64 { - self.denominator - } -} - -/// Conversion from Tendermint domain type into -/// IBC domain type. -impl From for TrustThreshold { - fn from(t: TrustThresholdFraction) -> Self { - Self { - numerator: t.numerator(), - denominator: t.denominator(), - } - } -} - -/// Conversion from IBC domain type into -/// Tendermint domain type. -impl TryFrom for TrustThresholdFraction { - type Error = Error; - - fn try_from(t: TrustThreshold) -> Result { - Self::new(t.numerator, t.denominator) - .map_err(|_| Error::failed_trust_threshold_conversion(t.numerator, t.denominator)) - } -} - -impl Protobuf for TrustThreshold {} - -impl From for Fraction { - fn from(t: TrustThreshold) -> Self { - Self { - numerator: t.numerator, - denominator: t.denominator, - } - } -} - -impl TryFrom for TrustThreshold { - type Error = Error; - - fn try_from(value: Fraction) -> Result { - Self::new(value.numerator, value.denominator) - } -} - -impl Default for TrustThreshold { - fn default() -> Self { - Self::ONE_THIRD - } -} - -impl Display for TrustThreshold { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "{}/{}", self.numerator, self.denominator) - } -} diff --git a/modules/src/core/ics03_connection/connection.rs b/modules/src/core/ics03_connection/connection.rs deleted file mode 100644 index 7b0a84afaf..0000000000 --- a/modules/src/core/ics03_connection/connection.rs +++ /dev/null @@ -1,395 +0,0 @@ -use crate::prelude::*; - -use core::str::FromStr; -use core::time::Duration; -use core::{ - fmt::{Display, Error as FmtError, Formatter}, - u64, -}; - -use ibc_proto::protobuf::Protobuf; -use serde::{Deserialize, Serialize}; - -use ibc_proto::ibc::core::connection::v1::{ - ConnectionEnd as RawConnectionEnd, Counterparty as RawCounterparty, - IdentifiedConnection as RawIdentifiedConnection, -}; - -use crate::core::ics02_client::error::Error as ClientError; -use crate::core::ics03_connection::error::Error; -use crate::core::ics03_connection::version::Version; -use crate::core::ics23_commitment::commitment::CommitmentPrefix; -use crate::core::ics24_host::error::ValidationError; -use crate::core::ics24_host::identifier::{ClientId, ConnectionId}; -use crate::timestamp::ZERO_DURATION; - -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct IdentifiedConnectionEnd { - pub connection_id: ConnectionId, - pub connection_end: ConnectionEnd, -} - -impl IdentifiedConnectionEnd { - pub fn new(connection_id: ConnectionId, connection_end: ConnectionEnd) -> Self { - IdentifiedConnectionEnd { - connection_id, - connection_end, - } - } - - pub fn id(&self) -> &ConnectionId { - &self.connection_id - } - - pub fn end(&self) -> &ConnectionEnd { - &self.connection_end - } -} - -impl Protobuf for IdentifiedConnectionEnd {} - -impl TryFrom for IdentifiedConnectionEnd { - type Error = Error; - - fn try_from(value: RawIdentifiedConnection) -> Result { - let raw_connection_end = RawConnectionEnd { - client_id: value.client_id.to_string(), - versions: value.versions, - state: value.state, - counterparty: value.counterparty, - delay_period: value.delay_period, - }; - - Ok(IdentifiedConnectionEnd { - connection_id: value.id.parse().map_err(Error::invalid_identifier)?, - connection_end: raw_connection_end.try_into()?, - }) - } -} - -impl From for RawIdentifiedConnection { - fn from(value: IdentifiedConnectionEnd) -> Self { - RawIdentifiedConnection { - id: value.connection_id.to_string(), - client_id: value.connection_end.client_id.to_string(), - versions: value - .connection_end - .versions - .iter() - .map(|v| From::from(v.clone())) - .collect(), - state: value.connection_end.state as i32, - delay_period: value.connection_end.delay_period.as_nanos() as u64, - counterparty: Some(value.connection_end.counterparty().clone().into()), - } - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct ConnectionEnd { - pub state: State, - client_id: ClientId, - counterparty: Counterparty, - versions: Vec, - delay_period: Duration, -} - -impl Default for ConnectionEnd { - fn default() -> Self { - Self { - state: State::Uninitialized, - client_id: Default::default(), - counterparty: Default::default(), - versions: Vec::new(), - delay_period: ZERO_DURATION, - } - } -} - -impl Protobuf for ConnectionEnd {} - -impl TryFrom for ConnectionEnd { - type Error = Error; - fn try_from(value: RawConnectionEnd) -> Result { - let state = value.state.try_into()?; - if state == State::Uninitialized { - return Ok(ConnectionEnd::default()); - } - if value.client_id.is_empty() { - return Err(Error::empty_proto_connection_end()); - } - - Ok(Self::new( - state, - value.client_id.parse().map_err(Error::invalid_identifier)?, - value - .counterparty - .ok_or_else(Error::missing_counterparty)? - .try_into()?, - value - .versions - .into_iter() - .map(Version::try_from) - .collect::, _>>()?, - Duration::from_nanos(value.delay_period), - )) - } -} - -impl From for RawConnectionEnd { - fn from(value: ConnectionEnd) -> Self { - RawConnectionEnd { - client_id: value.client_id.to_string(), - versions: value - .versions - .iter() - .map(|v| From::from(v.clone())) - .collect(), - state: value.state as i32, - counterparty: Some(value.counterparty.into()), - delay_period: value.delay_period.as_nanos() as u64, - } - } -} - -impl ConnectionEnd { - pub fn new( - state: State, - client_id: ClientId, - counterparty: Counterparty, - versions: Vec, - delay_period: Duration, - ) -> Self { - Self { - state, - client_id, - counterparty, - versions, - delay_period, - } - } - - /// Getter for the state of this connection end. - pub fn state(&self) -> &State { - &self.state - } - - /// Setter for the `state` field. - pub fn set_state(&mut self, new_state: State) { - self.state = new_state; - } - - /// Setter for the `counterparty` field. - pub fn set_counterparty(&mut self, new_cparty: Counterparty) { - self.counterparty = new_cparty; - } - - /// Setter for the `version` field. - pub fn set_version(&mut self, new_version: Version) { - self.versions = vec![new_version]; - } - - /// Helper function to compare the counterparty of this end with another counterparty. - pub fn counterparty_matches(&self, other: &Counterparty) -> bool { - self.counterparty.eq(other) - } - - /// Helper function to compare the client id of this end with another client identifier. - pub fn client_id_matches(&self, other: &ClientId) -> bool { - self.client_id.eq(other) - } - - /// Helper function to determine whether the connection is open. - pub fn is_open(&self) -> bool { - self.state_matches(&State::Open) - } - - /// Helper function to determine whether the connection is uninitialized. - pub fn is_uninitialized(&self) -> bool { - self.state_matches(&State::Uninitialized) - } - - /// Helper function to compare the state of this end with another state. - pub fn state_matches(&self, other: &State) -> bool { - self.state.eq(other) - } - - /// Getter for the client id on the local party of this connection end. - pub fn client_id(&self) -> &ClientId { - &self.client_id - } - - /// Getter for the list of versions in this connection end. - pub fn versions(&self) -> &[Version] { - &self.versions - } - - /// Getter for the counterparty. - pub fn counterparty(&self) -> &Counterparty { - &self.counterparty - } - - /// Getter for the delay_period field. This represents the duration, at minimum, - /// to delay the sending of a packet after the client update for that packet has been submitted. - pub fn delay_period(&self) -> Duration { - self.delay_period - } - - /// TODO: Clean this up, probably not necessary. - pub fn validate_basic(&self) -> Result<(), ValidationError> { - self.counterparty.validate_basic() - } -} - -#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct Counterparty { - client_id: ClientId, - pub connection_id: Option, - prefix: CommitmentPrefix, -} - -impl Protobuf for Counterparty {} - -// Converts from the wire format RawCounterparty. Typically used from the relayer side -// during queries for response validation and to extract the Counterparty structure. -impl TryFrom for Counterparty { - type Error = Error; - - fn try_from(value: RawCounterparty) -> Result { - let connection_id = Some(value.connection_id) - .filter(|x| !x.is_empty()) - .map(|v| FromStr::from_str(v.as_str())) - .transpose() - .map_err(Error::invalid_identifier)?; - Ok(Counterparty::new( - value.client_id.parse().map_err(Error::invalid_identifier)?, - connection_id, - value - .prefix - .ok_or_else(Error::missing_counterparty)? - .key_prefix - .try_into() - .map_err(|_| Error::ics02_client(ClientError::empty_prefix()))?, - )) - } -} - -impl From for RawCounterparty { - fn from(value: Counterparty) -> Self { - RawCounterparty { - client_id: value.client_id.as_str().to_string(), - connection_id: value - .connection_id - .map_or_else(|| "".to_string(), |v| v.as_str().to_string()), - prefix: Some(ibc_proto::ibc::core::commitment::v1::MerklePrefix { - key_prefix: value.prefix.into_vec(), - }), - } - } -} - -impl Counterparty { - pub fn new( - client_id: ClientId, - connection_id: Option, - prefix: CommitmentPrefix, - ) -> Self { - Self { - client_id, - connection_id, - prefix, - } - } - - /// Getter for the client id. - pub fn client_id(&self) -> &ClientId { - &self.client_id - } - - /// Getter for connection id. - pub fn connection_id(&self) -> Option<&ConnectionId> { - self.connection_id.as_ref() - } - - pub fn prefix(&self) -> &CommitmentPrefix { - &self.prefix - } - - pub fn validate_basic(&self) -> Result<(), ValidationError> { - Ok(()) - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub enum State { - Uninitialized = 0, - Init = 1, - TryOpen = 2, - Open = 3, -} - -impl State { - /// Yields the State as a string. - pub fn as_str(&self) -> &'static str { - match self { - Self::Uninitialized => "UNINITIALIZED", - Self::Init => "INIT", - Self::TryOpen => "TRYOPEN", - Self::Open => "OPEN", - } - } - - /// Parses the State out from a i32. - pub fn from_i32(s: i32) -> Result { - match s { - 0 => Ok(Self::Uninitialized), - 1 => Ok(Self::Init), - 2 => Ok(Self::TryOpen), - 3 => Ok(Self::Open), - _ => Err(Error::invalid_state(s)), - } - } - - /// Returns whether or not this connection state is `Open`. - pub fn is_open(self) -> bool { - self == State::Open - } - - /// Returns whether or not this connection with this state - /// has progressed less or the same than the argument. - /// - /// # Example - /// ```rust,ignore - /// assert!(State::Init.less_or_equal_progress(State::Open)); - /// assert!(State::TryOpen.less_or_equal_progress(State::TryOpen)); - /// assert!(!State::Open.less_or_equal_progress(State::Uninitialized)); - /// ``` - pub fn less_or_equal_progress(self, other: Self) -> bool { - self as u32 <= other as u32 - } -} - -impl Display for State { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "{}", self.as_str()) - } -} - -impl TryFrom for State { - type Error = Error; - fn try_from(value: i32) -> Result { - match value { - 0 => Ok(Self::Uninitialized), - 1 => Ok(Self::Init), - 2 => Ok(Self::TryOpen), - 3 => Ok(Self::Open), - _ => Err(Error::invalid_state(value)), - } - } -} - -impl From for i32 { - fn from(value: State) -> Self { - value.into() - } -} diff --git a/modules/src/core/ics03_connection/context.rs b/modules/src/core/ics03_connection/context.rs deleted file mode 100644 index d4a49a0954..0000000000 --- a/modules/src/core/ics03_connection/context.rs +++ /dev/null @@ -1,108 +0,0 @@ -//! ICS3 (connection) context. The two traits `ConnectionReader` and `ConnectionKeeper` define -//! the interface that any host chain must implement to be able to process any `ConnectionMsg`. -//! See "ADR 003: IBC protocol implementation" for more details. - -use crate::core::ics02_client::client_state::ClientState; -use crate::core::ics02_client::consensus_state::ConsensusState; -use crate::core::ics03_connection::connection::ConnectionEnd; -use crate::core::ics03_connection::error::Error; -use crate::core::ics03_connection::handler::{ConnectionIdState, ConnectionResult}; -use crate::core::ics03_connection::version::{get_compatible_versions, pick_version, Version}; -use crate::core::ics23_commitment::commitment::CommitmentPrefix; -use crate::core::ics24_host::identifier::{ClientId, ConnectionId}; -use crate::prelude::*; -use crate::Height; -use ibc_proto::google::protobuf::Any; - -/// A context supplying all the necessary read-only dependencies for processing any `ConnectionMsg`. -pub trait ConnectionReader { - /// Returns the ConnectionEnd for the given identifier `conn_id`. - fn connection_end(&self, conn_id: &ConnectionId) -> Result; - - /// Returns the ClientState for the given identifier `client_id`. - fn client_state(&self, client_id: &ClientId) -> Result, Error>; - - /// Tries to decode the given `client_state` into a concrete light client state. - fn decode_client_state(&self, client_state: Any) -> Result, Error>; - - /// Returns the current height of the local chain. - fn host_current_height(&self) -> Height; - - /// Returns the oldest height available on the local chain. - fn host_oldest_height(&self) -> Height; - - /// Returns the prefix that the local chain uses in the KV store. - fn commitment_prefix(&self) -> CommitmentPrefix; - - /// Returns the ConsensusState that the given client stores at a specific height. - fn client_consensus_state( - &self, - client_id: &ClientId, - height: Height, - ) -> Result, Error>; - - /// Returns the ConsensusState of the host (local) chain at a specific height. - fn host_consensus_state(&self, height: Height) -> Result, Error>; - - /// Function required by ICS 03. Returns the list of all possible versions that the connection - /// handshake protocol supports. - fn get_compatible_versions(&self) -> Vec { - get_compatible_versions() - } - - /// Function required by ICS 03. Returns one version out of the supplied list of versions, which the - /// connection handshake protocol prefers. - fn pick_version( - &self, - supported_versions: Vec, - counterparty_candidate_versions: Vec, - ) -> Result { - pick_version(supported_versions, counterparty_candidate_versions) - } - - /// Returns a counter on how many connections have been created thus far. - /// The value of this counter should increase only via method - /// `ConnectionKeeper::increase_connection_counter`. - fn connection_counter(&self) -> Result; -} - -/// A context supplying all the necessary write-only dependencies (i.e., storage writing facility) -/// for processing any `ConnectionMsg`. -pub trait ConnectionKeeper { - fn store_connection_result(&mut self, result: ConnectionResult) -> Result<(), Error> { - self.store_connection(result.connection_id.clone(), &result.connection_end)?; - - // If we generated an identifier, increase the counter & associate this new identifier - // with the client id. - if matches!(result.connection_id_state, ConnectionIdState::Generated) { - self.increase_connection_counter(); - - // Also associate the connection end to its client identifier. - self.store_connection_to_client( - result.connection_id.clone(), - result.connection_end.client_id(), - )?; - } - - Ok(()) - } - - /// Stores the given connection_end at a path associated with the connection_id. - fn store_connection( - &mut self, - connection_id: ConnectionId, - connection_end: &ConnectionEnd, - ) -> Result<(), Error>; - - /// Stores the given connection_id at a path associated with the client_id. - fn store_connection_to_client( - &mut self, - connection_id: ConnectionId, - client_id: &ClientId, - ) -> Result<(), Error>; - - /// Called upon connection identifier creation (Init or Try process). - /// Increases the counter which keeps track of how many connections have been created. - /// Should never fail. - fn increase_connection_counter(&mut self); -} diff --git a/modules/src/core/ics03_connection/error.rs b/modules/src/core/ics03_connection/error.rs deleted file mode 100644 index 619f14b2e1..0000000000 --- a/modules/src/core/ics03_connection/error.rs +++ /dev/null @@ -1,161 +0,0 @@ -use crate::core::ics02_client::error as client_error; -use crate::core::ics03_connection::version::Version; -use crate::core::ics24_host::error::ValidationError; -use crate::core::ics24_host::identifier::{ClientId, ConnectionId}; -use crate::proofs::ProofError; -use crate::signer::SignerError; -use crate::Height; - -use flex_error::define_error; - -define_error! { - #[derive(Debug, PartialEq, Eq)] - Error { - Ics02Client - [ client_error::Error ] - | _ | { "ics02 client error" }, - - InvalidState - { state: i32 } - | e | { format_args!("connection state is unknown: {}", e.state) }, - - ConnectionExistsAlready - { connection_id: ConnectionId } - | e | { - format_args!("connection exists (was initialized) already: {0}", - e.connection_id) - }, - - ConnectionMismatch - { connection_id: ConnectionId } - | e | { - format_args!("connection end for identifier {0} was never initialized", - e.connection_id) - }, - - InvalidConsensusHeight - { - target_height: Height, - currrent_height: Height - } - | e | { - format_args!("consensus height claimed by the client on the other party is too advanced: {0} (host chain current height: {1})", - e.target_height, e.currrent_height) - }, - - StaleConsensusHeight - { - target_height: Height, - oldest_height: Height - } - | e | { - format_args!("consensus height claimed by the client on the other party has been pruned: {0} (host chain oldest height: {1})", - e.target_height, e.oldest_height) - }, - - InvalidIdentifier - [ ValidationError ] - | _ | { "identifier error" }, - - EmptyProtoConnectionEnd - | _ | { "ConnectionEnd domain object could not be constructed out of empty proto object" }, - - EmptyVersions - | _ | { "empty supported versions" }, - - EmptyFeatures - | _ | { "empty supported features" }, - - NoCommonVersion - | _ | { "no common version" }, - - VersionNotSupported - { - version: Version, - } - | e | { format_args!("version \"{}\" not supported", e.version) }, - - InvalidAddress - | _ | { "invalid address" }, - - MissingProofHeight - | _ | { "missing proof height" }, - - MissingConsensusHeight - | _ | { "missing consensus height" }, - - InvalidProof - [ ProofError ] - | _ | { "invalid connection proof" }, - - VerifyConnectionState - [ client_error::Error ] - | _ | { "error verifying connnection state" }, - - Signer - [ SignerError ] - | _ | { "invalid signer" }, - - ConnectionNotFound - { connection_id: ConnectionId } - | e | { - format_args!("no connection was found for the previous connection id provided {0}", - e.connection_id) - }, - - InvalidCounterparty - | _ | { "invalid signer" }, - - ConnectionIdMismatch - { - connection_id: ConnectionId, - counterparty_connection_id: ConnectionId, - } - | e | { - format_args!("counterparty chosen connection id {0} is different than the connection id {1}", - e.connection_id, e.counterparty_connection_id) - }, - - MissingCounterparty - | _ | { "missing counterparty" }, - - - MissingCounterpartyPrefix - | _ | { "missing counterparty prefix" }, - - NullClientProof - | _ | { "client proof must be present" }, - - FrozenClient - { client_id: ClientId } - | e | { - format_args!("the client id does not match any client state: {0}", - e.client_id) - }, - - ConnectionVerificationFailure - | _ | { "the connection proof verification failed" }, - - ConsensusStateVerificationFailure - { height: Height } - [ client_error::Error ] - | e | { - format_args!("the consensus proof verification failed (height: {0})", - e.height) - }, - - // TODO: use more specific error source - ClientStateVerificationFailure - { - client_id: ClientId, - } - [ client_error::Error ] - | e | { - format_args!("the client state proof verification failed for client id {0}", - e.client_id) - }, - - ImplementationSpecific - | _ | { "implementation specific error" }, - } -} diff --git a/modules/src/core/ics03_connection/events.rs b/modules/src/core/ics03_connection/events.rs deleted file mode 100644 index d8ddede11d..0000000000 --- a/modules/src/core/ics03_connection/events.rs +++ /dev/null @@ -1,234 +0,0 @@ -//! Types for the IBC events emitted from Tendermint Websocket by the connection module. - -use core::fmt::{Display, Error as FmtError, Formatter}; -use serde_derive::{Deserialize, Serialize}; -use tendermint::abci::tag::Tag; -use tendermint::abci::Event as AbciEvent; - -use crate::core::ics24_host::identifier::{ClientId, ConnectionId}; -use crate::events::{IbcEvent, IbcEventType}; -use crate::prelude::*; - -/// The content of the `key` field for the attribute containing the connection identifier. -pub const CONN_ID_ATTRIBUTE_KEY: &str = "connection_id"; -pub const CLIENT_ID_ATTRIBUTE_KEY: &str = "client_id"; -pub const COUNTERPARTY_CONN_ID_ATTRIBUTE_KEY: &str = "counterparty_connection_id"; -pub const COUNTERPARTY_CLIENT_ID_ATTRIBUTE_KEY: &str = "counterparty_client_id"; - -#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)] -pub struct Attributes { - pub connection_id: Option, - pub client_id: ClientId, - pub counterparty_connection_id: Option, - pub counterparty_client_id: ClientId, -} - -impl Display for Attributes { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - match (&self.connection_id, &self.counterparty_connection_id) { - (Some(connection_id), Some(counterparty_connection_id)) => write!(f, "Attributes {{ connection_id: {}, client_id: {}, counterparty_connection_id: {}, counterparty_client_id: {} }}", connection_id, self.client_id, counterparty_connection_id, self.counterparty_client_id), - (Some(connection_id), None) => write!(f, "Attributes {{ connection_id: {}, client_id: {}, counterparty_connection_id: None, counterparty_client_id: {} }}", connection_id, self.client_id, self.counterparty_client_id), - (None, Some(counterparty_connection_id)) => write!(f, "Attributes {{ connection_id: None, client_id: {}, counterparty_connection_id: {}, counterparty_client_id: {} }}", self.client_id, counterparty_connection_id, self.counterparty_client_id), - (None, None) => write!(f, "Attributes {{ connection_id: None, client_id: {}, counterparty_connection_id: None, counterparty_client_id: {} }}", self.client_id, self.counterparty_client_id), - } - } -} - -/// Convert attributes to Tendermint ABCI tags -/// -/// # Note -/// The parsing of `Key`s and `Value`s never fails, because the -/// `FromStr` instance of `tendermint::abci::tag::{Key, Value}` -/// is infallible, even if it is not represented in the error type. -/// Once tendermint-rs improves the API of the `Key` and `Value` types, -/// we will be able to remove the `.parse().unwrap()` calls. -impl From for Vec { - fn from(a: Attributes) -> Self { - let mut attributes = vec![]; - if let Some(conn_id) = a.connection_id { - let conn_id = Tag { - key: CONN_ID_ATTRIBUTE_KEY.parse().unwrap(), - value: conn_id.to_string().parse().unwrap(), - }; - attributes.push(conn_id); - } - let client_id = Tag { - key: CLIENT_ID_ATTRIBUTE_KEY.parse().unwrap(), - value: a.client_id.to_string().parse().unwrap(), - }; - attributes.push(client_id); - if let Some(conn_id) = a.counterparty_connection_id { - let conn_id = Tag { - key: COUNTERPARTY_CONN_ID_ATTRIBUTE_KEY.parse().unwrap(), - value: conn_id.to_string().parse().unwrap(), - }; - attributes.push(conn_id); - } - let counterparty_client_id = Tag { - key: COUNTERPARTY_CLIENT_ID_ATTRIBUTE_KEY.parse().unwrap(), - value: a.counterparty_client_id.to_string().parse().unwrap(), - }; - attributes.push(counterparty_client_id); - attributes - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize)] -pub struct OpenInit(pub Attributes); - -impl OpenInit { - pub fn attributes(&self) -> &Attributes { - &self.0 - } - pub fn connection_id(&self) -> Option<&ConnectionId> { - self.0.connection_id.as_ref() - } -} - -impl Display for OpenInit { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "OpenInit {{ {} }}", self.0) - } -} - -impl From for OpenInit { - fn from(attrs: Attributes) -> Self { - OpenInit(attrs) - } -} - -impl From for IbcEvent { - fn from(v: OpenInit) -> Self { - IbcEvent::OpenInitConnection(v) - } -} - -impl From for AbciEvent { - fn from(v: OpenInit) -> Self { - let attributes = Vec::::from(v.0); - AbciEvent { - type_str: IbcEventType::OpenInitConnection.as_str().to_string(), - attributes, - } - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize)] -pub struct OpenTry(pub Attributes); - -impl OpenTry { - pub fn attributes(&self) -> &Attributes { - &self.0 - } - pub fn connection_id(&self) -> Option<&ConnectionId> { - self.0.connection_id.as_ref() - } -} - -impl Display for OpenTry { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "OpenTry {{ {} }}", self.0) - } -} - -impl From for OpenTry { - fn from(attrs: Attributes) -> Self { - OpenTry(attrs) - } -} - -impl From for IbcEvent { - fn from(v: OpenTry) -> Self { - IbcEvent::OpenTryConnection(v) - } -} - -impl From for AbciEvent { - fn from(v: OpenTry) -> Self { - let attributes = Vec::::from(v.0); - AbciEvent { - type_str: IbcEventType::OpenTryConnection.as_str().to_string(), - attributes, - } - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize)] -pub struct OpenAck(pub Attributes); - -impl OpenAck { - pub fn attributes(&self) -> &Attributes { - &self.0 - } - pub fn connection_id(&self) -> Option<&ConnectionId> { - self.0.connection_id.as_ref() - } -} - -impl Display for OpenAck { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "OpenAck {{ {} }}", self.0) - } -} - -impl From for OpenAck { - fn from(attrs: Attributes) -> Self { - OpenAck(attrs) - } -} - -impl From for IbcEvent { - fn from(v: OpenAck) -> Self { - IbcEvent::OpenAckConnection(v) - } -} - -impl From for AbciEvent { - fn from(v: OpenAck) -> Self { - let attributes = Vec::::from(v.0); - AbciEvent { - type_str: IbcEventType::OpenAckConnection.as_str().to_string(), - attributes, - } - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize)] -pub struct OpenConfirm(pub Attributes); - -impl OpenConfirm { - pub fn attributes(&self) -> &Attributes { - &self.0 - } - pub fn connection_id(&self) -> Option<&ConnectionId> { - self.0.connection_id.as_ref() - } -} - -impl Display for OpenConfirm { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "OpenConfirm {{ {} }}", self.0) - } -} - -impl From for OpenConfirm { - fn from(attrs: Attributes) -> Self { - OpenConfirm(attrs) - } -} - -impl From for IbcEvent { - fn from(v: OpenConfirm) -> Self { - IbcEvent::OpenConfirmConnection(v) - } -} - -impl From for AbciEvent { - fn from(v: OpenConfirm) -> Self { - let attributes = Vec::::from(v.0); - AbciEvent { - type_str: IbcEventType::OpenConfirmConnection.as_str().to_string(), - attributes, - } - } -} diff --git a/modules/src/core/ics03_connection/handler.rs b/modules/src/core/ics03_connection/handler.rs deleted file mode 100644 index b096c32e1d..0000000000 --- a/modules/src/core/ics03_connection/handler.rs +++ /dev/null @@ -1,57 +0,0 @@ -//! This module implements the processing logic for ICS3 (connection open handshake) messages. - -use crate::core::ics03_connection::connection::ConnectionEnd; -use crate::core::ics03_connection::context::ConnectionReader; -use crate::core::ics03_connection::error::Error; -use crate::core::ics03_connection::msgs::ConnectionMsg; -use crate::core::ics24_host::identifier::ConnectionId; -use crate::handler::HandlerOutput; - -pub mod conn_open_ack; -pub mod conn_open_confirm; -pub mod conn_open_init; -pub mod conn_open_try; - -pub mod verify; - -/// Defines the possible states of a connection identifier in a `ConnectionResult`. -#[derive(Clone, Debug)] -pub enum ConnectionIdState { - /// Specifies that the handler allocated a new connection identifier. This happens during the - /// processing of either the `MsgConnectionOpenInit` or `MsgConnectionOpenTry` message. - Generated, - - /// Specifies that the handler reused a previously-allocated connection identifier. - Reused, -} - -#[derive(Clone, Debug)] -pub struct ConnectionResult { - /// The identifier for the connection which the handler processed. Typically this represents the - /// newly-generated connection id (e.g., when processing `MsgConnectionOpenInit`) or - /// an existing connection id (e.g., for `MsgConnectionOpenAck`). - pub connection_id: ConnectionId, - - /// The state of the connection identifier (whether it was newly-generated or not). - pub connection_id_state: ConnectionIdState, - - /// The connection end, which the handler produced as a result of processing the message. - pub connection_end: ConnectionEnd, -} - -/// General entry point for processing any type of message related to the ICS3 connection open -/// handshake protocol. -pub fn dispatch( - ctx: &Ctx, - msg: ConnectionMsg, -) -> Result, Error> -where - Ctx: ConnectionReader, -{ - match msg { - ConnectionMsg::ConnectionOpenInit(msg) => conn_open_init::process(ctx, msg), - ConnectionMsg::ConnectionOpenTry(msg) => conn_open_try::process(ctx, *msg), - ConnectionMsg::ConnectionOpenAck(msg) => conn_open_ack::process(ctx, *msg), - ConnectionMsg::ConnectionOpenConfirm(msg) => conn_open_confirm::process(ctx, msg), - } -} diff --git a/modules/src/core/ics03_connection/handler/conn_open_ack.rs b/modules/src/core/ics03_connection/handler/conn_open_ack.rs deleted file mode 100644 index 40d2f26608..0000000000 --- a/modules/src/core/ics03_connection/handler/conn_open_ack.rs +++ /dev/null @@ -1,271 +0,0 @@ -//! Protocol logic specific to processing ICS3 messages of type `MsgConnectionOpenAck`. - -use crate::core::ics03_connection::connection::{ConnectionEnd, Counterparty, State}; -use crate::core::ics03_connection::context::ConnectionReader; -use crate::core::ics03_connection::error::Error; -use crate::core::ics03_connection::events::Attributes; -use crate::core::ics03_connection::handler::verify::{ - check_client_consensus_height, verify_proofs, -}; -use crate::core::ics03_connection::handler::{ConnectionIdState, ConnectionResult}; -use crate::core::ics03_connection::msgs::conn_open_ack::MsgConnectionOpenAck; -use crate::events::IbcEvent; -use crate::handler::{HandlerOutput, HandlerResult}; -use crate::prelude::*; - -pub(crate) fn process( - ctx: &dyn ConnectionReader, - msg: MsgConnectionOpenAck, -) -> HandlerResult { - let mut output = HandlerOutput::builder(); - - // If a consensus proof is present, check that the consensus height (for - // client proof) in the message is not too advanced nor too old. - if let Some(consensus_height) = msg.consensus_height() { - check_client_consensus_height(ctx, consensus_height)?; - } - - // Validate the connection end. - let mut conn_end = ctx.connection_end(&msg.connection_id)?; - // A connection end must be Init or TryOpen; otherwise we return an error. - let state_is_consistent = conn_end.state_matches(&State::Init) - && conn_end.versions().contains(&msg.version) - || conn_end.state_matches(&State::TryOpen) - && conn_end.versions().get(0).eq(&Some(&msg.version)); - - if !state_is_consistent { - // Old connection end is in incorrect state, propagate the error. - return Err(Error::connection_mismatch(msg.connection_id)); - } - - // Set the connection ID of the counterparty - let prev_counterparty = conn_end.counterparty(); - let counterparty = Counterparty::new( - prev_counterparty.client_id().clone(), - Some(msg.counterparty_connection_id.clone()), - prev_counterparty.prefix().clone(), - ); - conn_end.set_state(State::Open); - conn_end.set_version(msg.version.clone()); - conn_end.set_counterparty(counterparty); - - // Proof verification. - let expected_conn = { - // The counterparty is the local chain. - let counterparty = Counterparty::new( - conn_end.client_id().clone(), // The local client identifier. - Some(msg.connection_id.clone()), // This chain's connection id as known on counterparty. - ctx.commitment_prefix(), // Local commitment prefix. - ); - - ConnectionEnd::new( - State::TryOpen, - conn_end.counterparty().client_id().clone(), - counterparty, - vec![msg.version.clone()], - conn_end.delay_period(), - ) - }; - - // 2. Pass the details to the verification function. - verify_proofs( - ctx, - msg.client_state, - msg.proofs.height(), - &conn_end, - &expected_conn, - &msg.proofs, - )?; - - output.log("success: connection verification passed"); - - let result = ConnectionResult { - connection_id: msg.connection_id, - connection_id_state: ConnectionIdState::Reused, - connection_end: conn_end, - }; - - let event_attributes = Attributes { - connection_id: Some(result.connection_id.clone()), - ..Default::default() - }; - output.emit(IbcEvent::OpenAckConnection(event_attributes.into())); - - Ok(output.with_result(result)) -} - -#[cfg(test)] -mod tests { - use crate::prelude::*; - - use core::str::FromStr; - use test_log::test; - - use crate::core::ics03_connection::connection::{ConnectionEnd, Counterparty, State}; - use crate::core::ics03_connection::error; - use crate::core::ics03_connection::handler::{dispatch, ConnectionResult}; - use crate::core::ics03_connection::msgs::conn_open_ack::test_util::get_dummy_raw_msg_conn_open_ack; - use crate::core::ics03_connection::msgs::conn_open_ack::MsgConnectionOpenAck; - use crate::core::ics03_connection::msgs::ConnectionMsg; - use crate::core::ics23_commitment::commitment::CommitmentPrefix; - use crate::core::ics24_host::identifier::{ChainId, ClientId}; - use crate::events::IbcEvent; - use crate::mock::context::MockContext; - use crate::mock::host::HostType; - use crate::timestamp::ZERO_DURATION; - - #[test] - fn conn_open_ack_msg_processing() { - struct Test { - name: String, - ctx: MockContext, - msg: ConnectionMsg, - want_pass: bool, - match_error: Box, - } - - let msg_ack = - MsgConnectionOpenAck::try_from(get_dummy_raw_msg_conn_open_ack(10, 10)).unwrap(); - let conn_id = msg_ack.connection_id.clone(); - let counterparty_conn_id = msg_ack.counterparty_connection_id.clone(); - - // Client parameters -- identifier and correct height (matching the proof height) - let client_id = ClientId::from_str("mock_clientid").unwrap(); - let proof_height = msg_ack.proofs.height(); - - // Parametrize the host chain to have a height at least as recent as the - // the height of the proofs in the Ack msg. - let latest_height = proof_height.increment(); - let max_history_size = 5; - let default_context = MockContext::new( - ChainId::new("mockgaia".to_string(), latest_height.revision_number()), - HostType::Mock, - max_history_size, - latest_height, - ); - - // A connection end that will exercise the successful path. - let default_conn_end = ConnectionEnd::new( - State::Init, - client_id.clone(), - Counterparty::new( - client_id.clone(), - Some(msg_ack.counterparty_connection_id.clone()), - CommitmentPrefix::try_from(b"ibc".to_vec()).unwrap(), - ), - vec![msg_ack.version.clone()], - ZERO_DURATION, - ); - - // A connection end with incorrect state `Open`; will be part of the context. - let mut conn_end_open = default_conn_end.clone(); - conn_end_open.set_state(State::Open); // incorrect field - - let tests: Vec = vec![ - Test { - name: "Successful processing of an Ack message".to_string(), - ctx: default_context - .clone() - .with_client(&client_id, proof_height) - .with_connection(conn_id.clone(), default_conn_end), - msg: ConnectionMsg::ConnectionOpenAck(Box::new(msg_ack.clone())), - want_pass: true, - match_error: Box::new(|_| panic!("should not have error")), - }, - Test { - name: "Processing fails because the connection does not exist in the context" - .to_string(), - ctx: default_context.clone(), - msg: ConnectionMsg::ConnectionOpenAck(Box::new(msg_ack.clone())), - want_pass: false, - match_error: { - let connection_id = conn_id.clone(); - Box::new(move |e| match e.detail() { - error::ErrorDetail::ConnectionNotFound(e) => { - assert_eq!(e.connection_id, connection_id) - } - _ => { - panic!("Expected ConnectionNotFound error"); - } - }) - }, - }, - Test { - name: "Processing fails due to connections mismatch (incorrect 'open' state)" - .to_string(), - ctx: default_context - .with_client(&client_id, proof_height) - .with_connection(conn_id.clone(), conn_end_open), - msg: ConnectionMsg::ConnectionOpenAck(Box::new(msg_ack)), - want_pass: false, - match_error: { - let connection_id = conn_id; - Box::new(move |e| match e.detail() { - error::ErrorDetail::ConnectionMismatch(e) => { - assert_eq!(e.connection_id, connection_id); - } - _ => { - panic!("Expected ConnectionMismatch error"); - } - }) - }, - }, - /* - Test { - name: "Processing fails due to MissingLocalConsensusState".to_string(), - ctx: MockContext::default() - .with_client(&client_id, proof_height) - .with_connection(conn_id, default_conn_end), - msg: ConnectionMsg::ConnectionOpenAck(Box::new(msg_ack)), - want_pass: false, - error_kind: Some(Kind::MissingLocalConsensusState) - }, - */ - ]; - - for test in tests { - let res = dispatch(&test.ctx, test.msg.clone()); - // Additionally check the events and the output objects in the result. - match res { - Ok(proto_output) => { - assert!( - test.want_pass, - "conn_open_ack: test passed but was supposed to fail for test: {}, \nparams {:?} {:?}", - test.name, - test.msg.clone(), - test.ctx.clone() - ); - - assert!(!proto_output.events.is_empty()); // Some events must exist. - - // The object in the output is a ConnectionEnd, should have OPEN state. - let res: ConnectionResult = proto_output.result; - assert_eq!(res.connection_end.state().clone(), State::Open); - - // assert that counterparty connection id is correct - assert_eq!( - res.connection_end.counterparty().connection_id, - Some(counterparty_conn_id.clone()) - ); - - for e in proto_output.events.iter() { - assert!(matches!(e, &IbcEvent::OpenAckConnection(_))); - } - } - Err(e) => { - assert!( - !test.want_pass, - "conn_open_ack: failed for test: {}, \nparams {:?} {:?} error: {:?}", - test.name, - test.msg, - test.ctx.clone(), - e, - ); - - // Verify that the error kind matches - (test.match_error)(e); - } - } - } - } -} diff --git a/modules/src/core/ics03_connection/handler/conn_open_confirm.rs b/modules/src/core/ics03_connection/handler/conn_open_confirm.rs deleted file mode 100644 index c28358cf3c..0000000000 --- a/modules/src/core/ics03_connection/handler/conn_open_confirm.rs +++ /dev/null @@ -1,187 +0,0 @@ -//! Protocol logic specific to processing ICS3 messages of type `MsgConnectionOpenConfirm`. - -use crate::core::ics03_connection::connection::{ConnectionEnd, Counterparty, State}; -use crate::core::ics03_connection::context::ConnectionReader; -use crate::core::ics03_connection::error::Error; -use crate::core::ics03_connection::events::Attributes; -use crate::core::ics03_connection::handler::verify::verify_proofs; -use crate::core::ics03_connection::handler::{ConnectionIdState, ConnectionResult}; -use crate::core::ics03_connection::msgs::conn_open_confirm::MsgConnectionOpenConfirm; -use crate::events::IbcEvent; -use crate::handler::{HandlerOutput, HandlerResult}; -use crate::prelude::*; - -pub(crate) fn process( - ctx: &dyn ConnectionReader, - msg: MsgConnectionOpenConfirm, -) -> HandlerResult { - let mut output = HandlerOutput::builder(); - - // Validate the connection end. - let mut conn_end = ctx.connection_end(&msg.connection_id)?; - // A connection end must be in TryOpen state; otherwise return error. - if !conn_end.state_matches(&State::TryOpen) { - // Old connection end is in incorrect state, propagate the error. - return Err(Error::connection_mismatch(msg.connection_id)); - } - - // Verify proofs. Assemble the connection end as we expect to find it on the counterparty. - let expected_conn = ConnectionEnd::new( - State::Open, - conn_end.counterparty().client_id().clone(), - Counterparty::new( - // The counterparty is the local chain. - conn_end.client_id().clone(), // The local client identifier. - Some(msg.connection_id.clone()), // Local connection id. - ctx.commitment_prefix(), // Local commitment prefix. - ), - conn_end.versions().to_vec(), - conn_end.delay_period(), - ); - - // 2. Pass the details to the verification function. - verify_proofs( - ctx, - None, - msg.proofs.height(), - &conn_end, - &expected_conn, - &msg.proofs, - )?; - - output.log("success: connection verification passed"); - - // Transition our own end of the connection to state OPEN. - conn_end.set_state(State::Open); - - let result = ConnectionResult { - connection_id: msg.connection_id, - connection_id_state: ConnectionIdState::Reused, - connection_end: conn_end, - }; - - let event_attributes = Attributes { - connection_id: Some(result.connection_id.clone()), - ..Default::default() - }; - output.emit(IbcEvent::OpenConfirmConnection(event_attributes.into())); - - Ok(output.with_result(result)) -} - -#[cfg(test)] -mod tests { - use crate::prelude::*; - - use core::str::FromStr; - use test_log::test; - - use crate::core::ics03_connection::connection::{ConnectionEnd, Counterparty, State}; - use crate::core::ics03_connection::context::ConnectionReader; - use crate::core::ics03_connection::handler::{dispatch, ConnectionResult}; - use crate::core::ics03_connection::msgs::conn_open_confirm::test_util::get_dummy_raw_msg_conn_open_confirm; - use crate::core::ics03_connection::msgs::conn_open_confirm::MsgConnectionOpenConfirm; - use crate::core::ics03_connection::msgs::ConnectionMsg; - use crate::core::ics23_commitment::commitment::CommitmentPrefix; - use crate::core::ics24_host::identifier::ClientId; - use crate::events::IbcEvent; - use crate::mock::context::MockContext; - use crate::timestamp::ZERO_DURATION; - use crate::Height; - - #[test] - fn conn_open_confirm_msg_processing() { - struct Test { - name: String, - ctx: MockContext, - msg: ConnectionMsg, - want_pass: bool, - } - - let client_id = ClientId::from_str("mock_clientid").unwrap(); - let msg_confirm = - MsgConnectionOpenConfirm::try_from(get_dummy_raw_msg_conn_open_confirm()).unwrap(); - let counterparty = Counterparty::new( - client_id.clone(), - Some(msg_confirm.connection_id.clone()), - CommitmentPrefix::try_from(b"ibc".to_vec()).unwrap(), - ); - - let context = MockContext::default(); - - let incorrect_conn_end_state = ConnectionEnd::new( - State::Init, - client_id.clone(), - counterparty, - context.get_compatible_versions(), - ZERO_DURATION, - ); - - let mut correct_conn_end = incorrect_conn_end_state.clone(); - correct_conn_end.set_state(State::TryOpen); - - let tests: Vec = vec![ - Test { - name: "Processing fails due to missing connection in context".to_string(), - ctx: context.clone(), - msg: ConnectionMsg::ConnectionOpenConfirm(msg_confirm.clone()), - want_pass: false, - }, - Test { - name: "Processing fails due to connections mismatch (incorrect state)".to_string(), - ctx: context - .clone() - .with_client(&client_id, Height::new(0, 10).unwrap()) - .with_connection(msg_confirm.connection_id.clone(), incorrect_conn_end_state), - msg: ConnectionMsg::ConnectionOpenConfirm(msg_confirm.clone()), - want_pass: false, - }, - Test { - name: "Processing successful".to_string(), - ctx: context - .with_client(&client_id, Height::new(0, 10).unwrap()) - .with_connection(msg_confirm.connection_id.clone(), correct_conn_end), - msg: ConnectionMsg::ConnectionOpenConfirm(msg_confirm), - want_pass: true, - }, - ] - .into_iter() - .collect(); - - for test in tests { - let res = dispatch(&test.ctx, test.msg.clone()); - // Additionally check the events and the output objects in the result. - match res { - Ok(proto_output) => { - assert!( - test.want_pass, - "conn_open_confirm: test passed but was supposed to fail for: {}, \nparams {:?} {:?}", - test.name, - test.msg.clone(), - test.ctx.clone() - ); - - assert!(!proto_output.events.is_empty()); // Some events must exist. - - // The object in the output is a ConnectionEnd, should have OPEN state. - let res: ConnectionResult = proto_output.result; - assert_eq!(res.connection_end.state().clone(), State::Open); - - for e in proto_output.events.iter() { - assert!(matches!(e, &IbcEvent::OpenConfirmConnection(_))); - } - } - Err(e) => { - assert!( - !test.want_pass, - "conn_open_confirm: failed for test: {}, \nparams {:?} {:?} error: {:?}", - test.name, - test.msg, - test.ctx.clone(), - e, - ); - } - } - } - } -} diff --git a/modules/src/core/ics03_connection/handler/conn_open_init.rs b/modules/src/core/ics03_connection/handler/conn_open_init.rs deleted file mode 100644 index 12e934246a..0000000000 --- a/modules/src/core/ics03_connection/handler/conn_open_init.rs +++ /dev/null @@ -1,187 +0,0 @@ -//! Protocol logic specific to ICS3 messages of type `MsgConnectionOpenInit`. - -use crate::core::ics03_connection::connection::{ConnectionEnd, State}; -use crate::core::ics03_connection::context::ConnectionReader; -use crate::core::ics03_connection::error::Error; -use crate::core::ics03_connection::events::Attributes; -use crate::core::ics03_connection::handler::{ConnectionIdState, ConnectionResult}; -use crate::core::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; -use crate::core::ics24_host::identifier::ConnectionId; -use crate::events::IbcEvent; -use crate::handler::{HandlerOutput, HandlerResult}; -use crate::prelude::*; - -pub(crate) fn process( - ctx: &dyn ConnectionReader, - msg: MsgConnectionOpenInit, -) -> HandlerResult { - let mut output = HandlerOutput::builder(); - - // An IBC client running on the local (host) chain should exist. - ctx.client_state(&msg.client_id)?; - - let versions = match msg.version { - Some(version) => { - if ctx.get_compatible_versions().contains(&version) { - Ok(vec![version]) - } else { - Err(Error::version_not_supported(version)) - } - } - None => Ok(ctx.get_compatible_versions()), - }?; - - let new_connection_end = ConnectionEnd::new( - State::Init, - msg.client_id.clone(), - msg.counterparty.clone(), - versions, - msg.delay_period, - ); - - // Construct the identifier for the new connection. - let id_counter = ctx.connection_counter()?; - let conn_id = ConnectionId::new(id_counter); - - output.log(format!( - "success: generated new connection identifier: {}", - conn_id - )); - - let result = ConnectionResult { - connection_id: conn_id.clone(), - connection_id_state: ConnectionIdState::Generated, - connection_end: new_connection_end, - }; - - let event_attributes = Attributes { - connection_id: Some(conn_id), - ..Default::default() - }; - output.emit(IbcEvent::OpenInitConnection(event_attributes.into())); - - Ok(output.with_result(result)) -} - -#[cfg(test)] -mod tests { - use test_log::test; - - use crate::core::ics03_connection::connection::State; - use crate::core::ics03_connection::context::ConnectionReader; - use crate::core::ics03_connection::handler::{dispatch, ConnectionResult}; - use crate::core::ics03_connection::msgs::conn_open_init::test_util::get_dummy_raw_msg_conn_open_init; - use crate::core::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; - use crate::core::ics03_connection::msgs::ConnectionMsg; - use crate::core::ics03_connection::version::Version; - use crate::events::IbcEvent; - use crate::mock::context::MockContext; - use crate::prelude::*; - use crate::Height; - - use ibc_proto::ibc::core::connection::v1::Version as RawVersion; - - #[test] - fn conn_open_init_msg_processing() { - struct Test { - name: String, - ctx: MockContext, - msg: ConnectionMsg, - expected_versions: Vec, - want_pass: bool, - } - - let msg_conn_init_default = - MsgConnectionOpenInit::try_from(get_dummy_raw_msg_conn_open_init()).unwrap(); - let msg_conn_init_no_version = MsgConnectionOpenInit { - version: None, - ..msg_conn_init_default.clone() - }; - let msg_conn_init_bad_version = MsgConnectionOpenInit { - version: Version::try_from(RawVersion { - identifier: "random identifier 424242".to_string(), - features: vec![], - }) - .unwrap() - .into(), - ..msg_conn_init_default.clone() - }; - let default_context = MockContext::default(); - let good_context = default_context.clone().with_client( - &msg_conn_init_default.client_id, - Height::new(0, 10).unwrap(), - ); - - let tests: Vec = vec![ - Test { - name: "Processing fails because no client exists in the context".to_string(), - ctx: default_context, - msg: ConnectionMsg::ConnectionOpenInit(msg_conn_init_default.clone()), - expected_versions: vec![msg_conn_init_default.version.clone().unwrap()], - want_pass: false, - }, - Test { - name: "Incompatible version in MsgConnectionOpenInit msg".to_string(), - ctx: good_context.clone(), - msg: ConnectionMsg::ConnectionOpenInit(msg_conn_init_bad_version), - expected_versions: vec![], - want_pass: false, - }, - Test { - name: "No version in MsgConnectionOpenInit msg".to_string(), - ctx: good_context.clone(), - msg: ConnectionMsg::ConnectionOpenInit(msg_conn_init_no_version), - expected_versions: good_context.get_compatible_versions(), - want_pass: true, - }, - Test { - name: "Good parameters".to_string(), - ctx: good_context, - msg: ConnectionMsg::ConnectionOpenInit(msg_conn_init_default.clone()), - expected_versions: vec![msg_conn_init_default.version.unwrap()], - want_pass: true, - }, - ] - .into_iter() - .collect(); - - for test in tests { - let res = dispatch(&test.ctx, test.msg.clone()); - // Additionally check the events and the output objects in the result. - match res { - Ok(proto_output) => { - assert!(!proto_output.events.is_empty()); // Some events must exist. - - // The object in the output is a ConnectionEnd, should have init state. - let res: ConnectionResult = proto_output.result; - assert_eq!(res.connection_end.state().clone(), State::Init); - - for e in proto_output.events.iter() { - assert!(matches!(e, &IbcEvent::OpenInitConnection(_))); - } - - assert_eq!(res.connection_end.versions(), test.expected_versions); - - // This needs to be last - assert!( - test.want_pass, - "conn_open_init: test passed but was supposed to fail for test: {}, \nparams {:?} {:?}", - test.name, - test.msg.clone(), - test.ctx.clone() - ); - } - Err(e) => { - assert!( - !test.want_pass, - "conn_open_init: did not pass test: {}, \nparams {:?} {:?} error: {:?}", - test.name, - test.msg, - test.ctx.clone(), - e, - ); - } - } - } - } -} diff --git a/modules/src/core/ics03_connection/handler/conn_open_try.rs b/modules/src/core/ics03_connection/handler/conn_open_try.rs deleted file mode 100644 index 954d8e1153..0000000000 --- a/modules/src/core/ics03_connection/handler/conn_open_try.rs +++ /dev/null @@ -1,269 +0,0 @@ -//! Protocol logic specific to processing ICS3 messages of type `MsgConnectionOpenTry`. - -use crate::core::ics03_connection::connection::{ConnectionEnd, Counterparty, State}; -use crate::core::ics03_connection::context::ConnectionReader; -use crate::core::ics03_connection::error::Error; -use crate::core::ics03_connection::events::Attributes; -use crate::core::ics03_connection::handler::verify::{ - check_client_consensus_height, verify_proofs, -}; -use crate::core::ics03_connection::handler::{ConnectionIdState, ConnectionResult}; -use crate::core::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; -use crate::core::ics24_host::identifier::ConnectionId; -use crate::events::IbcEvent; -use crate::handler::{HandlerOutput, HandlerResult}; -use crate::prelude::*; - -pub(crate) fn process( - ctx: &dyn ConnectionReader, - msg: MsgConnectionOpenTry, -) -> HandlerResult { - let mut output = HandlerOutput::builder(); - - // If a consensus proof is present, check that the consensus height (for - // client proof) in the message is not too advanced nor too old. - if let Some(consensus_height) = msg.consensus_height() { - check_client_consensus_height(ctx, consensus_height)?; - } - - // Unwrap the old connection end (if any) and its identifier. - let (mut new_connection_end, conn_id) = match &msg.previous_connection_id { - // A connection with this id should already exist. Search & validate. - Some(prev_id) => { - let old_connection_end = ctx.connection_end(prev_id)?; - - // Validate that existing connection end matches with the one we're trying to establish. - if old_connection_end.state_matches(&State::Init) - && old_connection_end.counterparty_matches(&msg.counterparty) - && old_connection_end.client_id_matches(&msg.client_id) - && old_connection_end.delay_period() == msg.delay_period - { - // A ConnectionEnd already exists and all validation passed. - output.log(format!( - "success: `previous_connection_id` {} validation passed", - prev_id - )); - Ok((old_connection_end, prev_id.clone())) - } else { - // A ConnectionEnd already exists and validation failed. - Err(Error::connection_mismatch(prev_id.clone())) - } - } - // No prev. connection id was supplied, create a new connection end and conn id. - None => { - // Build a new connection end as well as an identifier. - let conn_end = ConnectionEnd::new( - State::Init, - msg.client_id.clone(), - msg.counterparty.clone(), - msg.counterparty_versions.clone(), - msg.delay_period, - ); - let id_counter = ctx.connection_counter()?; - let conn_id = ConnectionId::new(id_counter); - - output.log(format!( - "success: new connection end and identifier {} generated", - conn_id - )); - Ok((conn_end, conn_id)) - } - }?; - - // Proof verification in two steps: - // 1. Setup: build the ConnectionEnd as we expect to find it on the other party. - let expected_conn = ConnectionEnd::new( - State::Init, - msg.counterparty.client_id().clone(), - Counterparty::new(msg.client_id.clone(), None, ctx.commitment_prefix()), - msg.counterparty_versions.clone(), - msg.delay_period, - ); - - // 2. Pass the details to the verification function. - verify_proofs( - ctx, - msg.client_state, - msg.proofs.height(), - &new_connection_end, - &expected_conn, - &msg.proofs, - )?; - - // Transition the connection end to the new state & pick a version. - new_connection_end.set_state(State::TryOpen); - - // Pick the version. - new_connection_end.set_version(ctx.pick_version( - ctx.get_compatible_versions(), - msg.counterparty_versions.clone(), - )?); - - assert_eq!(new_connection_end.versions().len(), 1); - - output.log("success: connection verification passed"); - - let result = ConnectionResult { - connection_id: conn_id.clone(), - connection_id_state: if matches!(msg.previous_connection_id, None) { - ConnectionIdState::Generated - } else { - ConnectionIdState::Reused - }, - connection_end: new_connection_end, - }; - - let event_attributes = Attributes { - connection_id: Some(conn_id), - ..Default::default() - }; - output.emit(IbcEvent::OpenTryConnection(event_attributes.into())); - - Ok(output.with_result(result)) -} - -#[cfg(test)] -mod tests { - use crate::prelude::*; - - use test_log::test; - - use crate::core::ics03_connection::connection::State; - use crate::core::ics03_connection::handler::{dispatch, ConnectionResult}; - use crate::core::ics03_connection::msgs::conn_open_try::test_util::get_dummy_raw_msg_conn_open_try; - use crate::core::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; - use crate::core::ics03_connection::msgs::ConnectionMsg; - use crate::core::ics24_host::identifier::ChainId; - use crate::events::IbcEvent; - use crate::mock::context::MockContext; - use crate::mock::host::HostType; - use crate::Height; - - #[test] - fn conn_open_try_msg_processing() { - struct Test { - name: String, - ctx: MockContext, - msg: ConnectionMsg, - want_pass: bool, - } - - let host_chain_height = Height::new(0, 35).unwrap(); - let max_history_size = 5; - let context = MockContext::new( - ChainId::new("mockgaia".to_string(), 0), - HostType::Mock, - max_history_size, - host_chain_height, - ); - let client_consensus_state_height = 10; - - let msg_conn_try = MsgConnectionOpenTry::try_from(get_dummy_raw_msg_conn_open_try( - client_consensus_state_height, - host_chain_height.revision_height(), - )) - .unwrap(); - - // The proof targets a height that does not exist (i.e., too advanced) on destination chain. - let msg_height_advanced = MsgConnectionOpenTry::try_from(get_dummy_raw_msg_conn_open_try( - client_consensus_state_height, - host_chain_height.increment().revision_height(), - )) - .unwrap(); - let pruned_height = host_chain_height - .sub(max_history_size as u64 + 1) - .unwrap() - .revision_height(); - // The consensus proof targets a missing height (pruned) on destination chain. - let msg_height_old = MsgConnectionOpenTry::try_from(get_dummy_raw_msg_conn_open_try( - client_consensus_state_height, - pruned_height, - )) - .unwrap(); - - // The proofs in this message are created at a height which the client on destination chain does not have. - let msg_proof_height_missing = - MsgConnectionOpenTry::try_from(get_dummy_raw_msg_conn_open_try( - client_consensus_state_height - 1, - host_chain_height.revision_height(), - )) - .unwrap(); - - let tests: Vec = vec![ - Test { - name: "Processing fails because the height is too advanced".to_string(), - ctx: context.clone(), - msg: ConnectionMsg::ConnectionOpenTry(Box::new(msg_height_advanced)), - want_pass: false, - }, - Test { - name: "Processing fails because the height is too old".to_string(), - ctx: context.clone(), - msg: ConnectionMsg::ConnectionOpenTry(Box::new(msg_height_old)), - want_pass: false, - }, - Test { - name: "Processing fails because no client exists".to_string(), - ctx: context.clone(), - msg: ConnectionMsg::ConnectionOpenTry(Box::new(msg_conn_try.clone())), - want_pass: false, - }, - Test { - name: "Processing fails because the client misses the consensus state targeted by the proof".to_string(), - ctx: context.clone().with_client(&msg_proof_height_missing.client_id, Height::new(0, client_consensus_state_height).unwrap()), - msg: ConnectionMsg::ConnectionOpenTry(Box::new(msg_proof_height_missing)), - want_pass: false, - }, - Test { - name: "Good parameters but has previous_connection_id".to_string(), - ctx: context.clone().with_client(&msg_conn_try.client_id, Height::new(0, client_consensus_state_height).unwrap()), - msg: ConnectionMsg::ConnectionOpenTry(Box::new(msg_conn_try.clone())), - want_pass: false, - }, - Test { - name: "Good parameters".to_string(), - ctx: context.with_client(&msg_conn_try.client_id, Height::new(0, client_consensus_state_height).unwrap()), - msg: ConnectionMsg::ConnectionOpenTry(Box::new(msg_conn_try.with_previous_connection_id(None))), - want_pass: true, - }, - ] - .into_iter() - .collect(); - - for test in tests { - let res = dispatch(&test.ctx, test.msg.clone()); - // Additionally check the events and the output objects in the result. - match res { - Ok(proto_output) => { - assert!( - test.want_pass, - "conn_open_try: test passed but was supposed to fail for test: {}, \nparams {:?} {:?}", - test.name, - test.msg.clone(), - test.ctx.clone() - ); - - assert!(!proto_output.events.is_empty()); // Some events must exist. - - // The object in the output is a ConnectionEnd, should have TryOpen state. - let res: ConnectionResult = proto_output.result; - assert_eq!(res.connection_end.state().clone(), State::TryOpen); - - for e in proto_output.events.iter() { - assert!(matches!(e, &IbcEvent::OpenTryConnection(_))); - } - } - Err(e) => { - assert!( - !test.want_pass, - "conn_open_try: failed for test: {}, \nparams {:?} {:?} error: {:?}", - test.name, - test.msg, - test.ctx.clone(), - e, - ); - } - } - } - } -} diff --git a/modules/src/core/ics03_connection/handler/verify.rs b/modules/src/core/ics03_connection/handler/verify.rs deleted file mode 100644 index 3c2bc7b2a8..0000000000 --- a/modules/src/core/ics03_connection/handler/verify.rs +++ /dev/null @@ -1,188 +0,0 @@ -//! ICS3 verification functions, common across all four handlers of ICS3. - -use ibc_proto::google::protobuf::Any; - -use crate::core::ics03_connection::connection::ConnectionEnd; -use crate::core::ics03_connection::context::ConnectionReader; -use crate::core::ics03_connection::error::Error; -use crate::core::ics23_commitment::commitment::CommitmentProofBytes; -use crate::proofs::{ConsensusProof, Proofs}; -use crate::Height; - -/// Entry point for verifying all proofs bundled in any ICS3 message. -pub fn verify_proofs( - ctx: &dyn ConnectionReader, - client_state: Option, - height: Height, - connection_end: &ConnectionEnd, - expected_conn: &ConnectionEnd, - proofs: &Proofs, -) -> Result<(), Error> { - verify_connection_proof( - ctx, - height, - connection_end, - expected_conn, - proofs.height(), - proofs.object_proof(), - )?; - - // If the message includes a client state, then verify the proof for that state. - if let Some(expected_client_state) = client_state { - verify_client_proof( - ctx, - height, - connection_end, - expected_client_state, - proofs.height(), - proofs - .client_proof() - .as_ref() - .ok_or_else(Error::null_client_proof)?, - )?; - } - - // If a consensus proof is attached to the message, then verify it. - if let Some(proof) = proofs.consensus_proof() { - Ok(verify_consensus_proof(ctx, height, connection_end, &proof)?) - } else { - Ok(()) - } -} - -/// Verifies the authenticity and semantic correctness of a commitment `proof`. The commitment -/// claims to prove that an object of type connection exists on the source chain (i.e., the chain -/// which created this proof). This object must match the state of `expected_conn`. -pub fn verify_connection_proof( - ctx: &dyn ConnectionReader, - height: Height, - connection_end: &ConnectionEnd, - expected_conn: &ConnectionEnd, - proof_height: Height, - proof: &CommitmentProofBytes, -) -> Result<(), Error> { - // Fetch the client state (IBC client on the local/host chain). - let client_state = ctx.client_state(connection_end.client_id())?; - - // The client must not be frozen. - if client_state.is_frozen() { - return Err(Error::frozen_client(connection_end.client_id().clone())); - } - - // The client must have the consensus state for the height where this proof was created. - let consensus_state = ctx.client_consensus_state(connection_end.client_id(), proof_height)?; - - // A counterparty connection id of None causes `unwrap()` below and indicates an internal - // error as this is the connection id on the counterparty chain that must always be present. - let connection_id = connection_end - .counterparty() - .connection_id() - .ok_or_else(Error::invalid_counterparty)?; - - // Verify the proof for the connection state against the expected connection end. - client_state - .verify_connection_state( - height, - connection_end.counterparty().prefix(), - proof, - consensus_state.root(), - connection_id, - expected_conn, - ) - .map_err(Error::verify_connection_state) -} - -/// Verifies the client `proof` from a connection handshake message, typically from a -/// `MsgConnectionOpenTry` or a `MsgConnectionOpenAck`. The `expected_client_state` argument is a -/// representation for a client of the current chain (the chain handling the current message), which -/// is running on the counterparty chain (the chain which sent this message). This method does a -/// complete verification: that the client state the counterparty stores is valid (i.e., not frozen, -/// at the same revision as the current chain, with matching chain identifiers, etc) and that the -/// `proof` is correct. -pub fn verify_client_proof( - ctx: &dyn ConnectionReader, - height: Height, - connection_end: &ConnectionEnd, - expected_client_state: Any, - proof_height: Height, - proof: &CommitmentProofBytes, -) -> Result<(), Error> { - // Fetch the local client state (IBC client running on the host chain). - let client_state = ctx.client_state(connection_end.client_id())?; - - if client_state.is_frozen() { - return Err(Error::frozen_client(connection_end.client_id().clone())); - } - - let consensus_state = ctx.client_consensus_state(connection_end.client_id(), proof_height)?; - - client_state - .verify_client_full_state( - height, - connection_end.counterparty().prefix(), - proof, - consensus_state.root(), - connection_end.counterparty().client_id(), - expected_client_state, - ) - .map_err(|e| { - Error::client_state_verification_failure(connection_end.client_id().clone(), e) - }) -} - -pub fn verify_consensus_proof( - ctx: &dyn ConnectionReader, - height: Height, - connection_end: &ConnectionEnd, - proof: &ConsensusProof, -) -> Result<(), Error> { - // Fetch the client state (IBC client on the local chain). - let client_state = ctx.client_state(connection_end.client_id())?; - - if client_state.is_frozen() { - return Err(Error::frozen_client(connection_end.client_id().clone())); - } - - // Fetch the expected consensus state from the historical (local) header data. - let expected_consensus = ctx.host_consensus_state(proof.height())?; - - let consensus_state = ctx.client_consensus_state(connection_end.client_id(), height)?; - - client_state - .verify_client_consensus_state( - height, - connection_end.counterparty().prefix(), - proof.proof(), - consensus_state.root(), - connection_end.counterparty().client_id(), - proof.height(), - expected_consensus.as_ref(), - ) - .map_err(|e| Error::consensus_state_verification_failure(proof.height(), e)) -} - -/// Checks that `claimed_height` is within normal bounds, i.e., fresh enough so that the chain has -/// not pruned it yet, but not newer than the current (actual) height of the local chain. -pub fn check_client_consensus_height( - ctx: &dyn ConnectionReader, - claimed_height: Height, -) -> Result<(), Error> { - if claimed_height > ctx.host_current_height() { - // Fail if the consensus height is too advanced. - return Err(Error::invalid_consensus_height( - claimed_height, - ctx.host_current_height(), - )); - } - - if claimed_height < ctx.host_oldest_height() { - // Fail if the consensus height is too old (has been pruned). - return Err(Error::stale_consensus_height( - claimed_height, - ctx.host_oldest_height(), - )); - } - - // Height check is within normal bounds, check passes. - Ok(()) -} diff --git a/modules/src/core/ics03_connection/mod.rs b/modules/src/core/ics03_connection/mod.rs deleted file mode 100644 index b3e9cf77c0..0000000000 --- a/modules/src/core/ics03_connection/mod.rs +++ /dev/null @@ -1,12 +0,0 @@ -//! ICS 03: Connection implementation for connecting a client -//! on the local chain with a client on a remote chain. - -pub mod connection; -/// Context definitions (dependencies for the protocol). -pub mod context; -pub mod error; -pub mod events; -/// Message processing logic (protocol) for ICS 03. -pub mod handler; -pub mod msgs; -pub mod version; diff --git a/modules/src/core/ics03_connection/msgs.rs b/modules/src/core/ics03_connection/msgs.rs deleted file mode 100644 index ab2cbec661..0000000000 --- a/modules/src/core/ics03_connection/msgs.rs +++ /dev/null @@ -1,52 +0,0 @@ -//! Message definitions for the connection handshake datagrams. -//! -//! We define each of the four messages in the connection handshake protocol as a `struct`. -//! Each such message comprises the same fields as the datagrams defined in ICS3 English spec: -//! . -//! -//! One departure from ICS3 is that we abstract the three counterparty fields (connection id, -//! prefix, and client id) into a single field of type `Counterparty`; this applies to messages -//! `MsgConnectionOpenInit` and `MsgConnectionOpenTry`. One other difference with regards to -//! abstraction is that all proof-related attributes in a message are encapsulated in `Proofs` type. -//! -//! Another difference to ICS3 specs is that each message comprises an additional field called -//! `signer` which is specific to Cosmos-SDK. - -use crate::core::ics03_connection::msgs::conn_open_ack::MsgConnectionOpenAck; -use crate::core::ics03_connection::msgs::conn_open_confirm::MsgConnectionOpenConfirm; -use crate::core::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; -use crate::core::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; -use alloc::boxed::Box; - -pub mod conn_open_ack; -pub mod conn_open_confirm; -pub mod conn_open_init; -pub mod conn_open_try; - -/// Enumeration of all possible messages that the ICS3 protocol processes. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum ConnectionMsg { - ConnectionOpenInit(MsgConnectionOpenInit), - ConnectionOpenTry(Box), - ConnectionOpenAck(Box), - ConnectionOpenConfirm(MsgConnectionOpenConfirm), -} - -#[cfg(test)] -pub mod test_util { - - use crate::core::ics24_host::identifier::{ClientId, ConnectionId}; - use crate::prelude::*; - use ibc_proto::ibc::core::commitment::v1::MerklePrefix; - use ibc_proto::ibc::core::connection::v1::Counterparty as RawCounterparty; - - pub fn get_dummy_raw_counterparty() -> RawCounterparty { - RawCounterparty { - client_id: ClientId::default().to_string(), - connection_id: ConnectionId::default().to_string(), - prefix: Some(MerklePrefix { - key_prefix: b"ibc".to_vec(), - }), - } - } -} diff --git a/modules/src/core/ics03_connection/msgs/conn_open_ack.rs b/modules/src/core/ics03_connection/msgs/conn_open_ack.rs deleted file mode 100644 index 060914b442..0000000000 --- a/modules/src/core/ics03_connection/msgs/conn_open_ack.rs +++ /dev/null @@ -1,256 +0,0 @@ -use crate::prelude::*; - -use ibc_proto::google::protobuf::Any; -use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenAck as RawMsgConnectionOpenAck; -use ibc_proto::protobuf::Protobuf; - -use crate::core::ics03_connection::error::Error; -use crate::core::ics03_connection::version::Version; -use crate::core::ics23_commitment::commitment::CommitmentProofBytes; -use crate::core::ics24_host::identifier::ConnectionId; -use crate::proofs::{ConsensusProof, Proofs}; -use crate::signer::Signer; -use crate::tx_msg::Msg; -use crate::Height; - -pub const TYPE_URL: &str = "/ibc.core.connection.v1.MsgConnectionOpenAck"; - -/// Message definition `MsgConnectionOpenAck` (i.e., `ConnOpenAck` datagram). -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct MsgConnectionOpenAck { - pub connection_id: ConnectionId, - pub counterparty_connection_id: ConnectionId, - pub client_state: Option, - pub proofs: Proofs, - pub version: Version, - pub signer: Signer, -} - -impl MsgConnectionOpenAck { - /// Getter for accessing the `consensus_height` field from this message. - /// Returns `None` if this field is not set. - pub fn consensus_height(&self) -> Option { - self.proofs.consensus_proof().map(|proof| proof.height()) - } -} - -impl Msg for MsgConnectionOpenAck { - type ValidationError = Error; - type Raw = RawMsgConnectionOpenAck; - - fn route(&self) -> String { - crate::keys::ROUTER_KEY.to_string() - } - - fn type_url(&self) -> String { - TYPE_URL.to_string() - } -} - -impl Protobuf for MsgConnectionOpenAck {} - -impl TryFrom for MsgConnectionOpenAck { - type Error = Error; - - fn try_from(msg: RawMsgConnectionOpenAck) -> Result { - let consensus_height = msg - .consensus_height - .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or_else(Error::missing_consensus_height)?; - let consensus_proof_obj = ConsensusProof::new( - msg.proof_consensus - .try_into() - .map_err(Error::invalid_proof)?, - consensus_height, - ) - .map_err(Error::invalid_proof)?; - - let proof_height = msg - .proof_height - .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or_else(Error::missing_proof_height)?; - - let client_proof = - CommitmentProofBytes::try_from(msg.proof_client).map_err(Error::invalid_proof)?; - - Ok(Self { - connection_id: msg - .connection_id - .parse() - .map_err(Error::invalid_identifier)?, - counterparty_connection_id: msg - .counterparty_connection_id - .parse() - .map_err(Error::invalid_identifier)?, - client_state: msg.client_state, - version: msg.version.ok_or_else(Error::empty_versions)?.try_into()?, - proofs: Proofs::new( - msg.proof_try.try_into().map_err(Error::invalid_proof)?, - Some(client_proof), - Option::from(consensus_proof_obj), - None, - proof_height, - ) - .map_err(Error::invalid_proof)?, - signer: msg.signer.parse().map_err(Error::signer)?, - }) - } -} - -impl From for RawMsgConnectionOpenAck { - fn from(ics_msg: MsgConnectionOpenAck) -> Self { - RawMsgConnectionOpenAck { - connection_id: ics_msg.connection_id.as_str().to_string(), - counterparty_connection_id: ics_msg.counterparty_connection_id.as_str().to_string(), - client_state: ics_msg.client_state, - proof_height: Some(ics_msg.proofs.height().into()), - proof_try: ics_msg.proofs.object_proof().clone().into(), - proof_client: ics_msg - .proofs - .client_proof() - .clone() - .map_or_else(Vec::new, |v| v.into()), - proof_consensus: ics_msg - .proofs - .consensus_proof() - .map_or_else(Vec::new, |v| v.proof().clone().into()), - consensus_height: ics_msg - .proofs - .consensus_proof() - .map_or_else(|| None, |h| Some(h.height().into())), - version: Some(ics_msg.version.into()), - signer: ics_msg.signer.to_string(), - } - } -} - -#[cfg(test)] -pub mod test_util { - use crate::prelude::*; - use ibc_proto::ibc::core::client::v1::Height; - use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenAck as RawMsgConnectionOpenAck; - - use crate::core::ics03_connection::version::Version; - use crate::core::ics24_host::identifier::ConnectionId; - use crate::test_utils::{get_dummy_bech32_account, get_dummy_proof}; - - pub fn get_dummy_raw_msg_conn_open_ack( - proof_height: u64, - consensus_height: u64, - ) -> RawMsgConnectionOpenAck { - RawMsgConnectionOpenAck { - connection_id: ConnectionId::new(0).to_string(), - counterparty_connection_id: ConnectionId::new(1).to_string(), - proof_try: get_dummy_proof(), - proof_height: Some(Height { - revision_number: 0, - revision_height: proof_height, - }), - proof_consensus: get_dummy_proof(), - consensus_height: Some(Height { - revision_number: 0, - revision_height: consensus_height, - }), - client_state: None, - proof_client: get_dummy_proof(), - version: Some(Version::default().into()), - signer: get_dummy_bech32_account(), - } - } -} - -#[cfg(test)] -mod tests { - use crate::prelude::*; - - use test_log::test; - - use ibc_proto::ibc::core::client::v1::Height; - use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenAck as RawMsgConnectionOpenAck; - - use crate::core::ics03_connection::msgs::conn_open_ack::test_util::get_dummy_raw_msg_conn_open_ack; - use crate::core::ics03_connection::msgs::conn_open_ack::MsgConnectionOpenAck; - - #[test] - fn parse_connection_open_ack_msg() { - #[derive(Clone, Debug, PartialEq)] - struct Test { - name: String, - raw: RawMsgConnectionOpenAck, - want_pass: bool, - } - - let default_ack_msg = get_dummy_raw_msg_conn_open_ack(5, 5); - - let tests: Vec = vec![ - Test { - name: "Good parameters".to_string(), - raw: default_ack_msg.clone(), - want_pass: true, - }, - Test { - name: "Bad connection id, non-alpha".to_string(), - raw: RawMsgConnectionOpenAck { - connection_id: "con007".to_string(), - ..default_ack_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Bad version, missing version".to_string(), - raw: RawMsgConnectionOpenAck { - version: None, - ..default_ack_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Bad proof height, height is 0".to_string(), - raw: RawMsgConnectionOpenAck { - proof_height: Some(Height { - revision_number: 1, - revision_height: 0, - }), - ..default_ack_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Bad consensus height, height is 0".to_string(), - raw: RawMsgConnectionOpenAck { - consensus_height: Some(Height { - revision_number: 1, - revision_height: 0, - }), - ..default_ack_msg - }, - want_pass: false, - }, - ] - .into_iter() - .collect(); - - for test in tests { - let msg = MsgConnectionOpenAck::try_from(test.raw.clone()); - - assert_eq!( - test.want_pass, - msg.is_ok(), - "MsgConnOpenAck::new failed for test {}, \nmsg {:?} with error {:?}", - test.name, - test.raw, - msg.err(), - ); - } - } - - #[test] - fn to_and_from() { - let raw = get_dummy_raw_msg_conn_open_ack(5, 6); - let msg = MsgConnectionOpenAck::try_from(raw.clone()).unwrap(); - let raw_back = RawMsgConnectionOpenAck::from(msg.clone()); - let msg_back = MsgConnectionOpenAck::try_from(raw_back.clone()).unwrap(); - assert_eq!(raw, raw_back); - assert_eq!(msg, msg_back); - } -} diff --git a/modules/src/core/ics03_connection/msgs/conn_open_confirm.rs b/modules/src/core/ics03_connection/msgs/conn_open_confirm.rs deleted file mode 100644 index 750b8ec168..0000000000 --- a/modules/src/core/ics03_connection/msgs/conn_open_confirm.rs +++ /dev/null @@ -1,173 +0,0 @@ -use crate::prelude::*; - -use ibc_proto::protobuf::Protobuf; - -use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenConfirm as RawMsgConnectionOpenConfirm; - -use crate::core::ics03_connection::error::Error; -use crate::core::ics24_host::identifier::ConnectionId; -use crate::proofs::Proofs; -use crate::signer::Signer; -use crate::tx_msg::Msg; - -pub const TYPE_URL: &str = "/ibc.core.connection.v1.MsgConnectionOpenConfirm"; - -/// -/// Message definition for `MsgConnectionOpenConfirm` (i.e., `ConnOpenConfirm` datagram). -/// -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct MsgConnectionOpenConfirm { - pub connection_id: ConnectionId, - pub proofs: Proofs, - pub signer: Signer, -} - -impl Msg for MsgConnectionOpenConfirm { - type ValidationError = Error; - type Raw = RawMsgConnectionOpenConfirm; - - fn route(&self) -> String { - crate::keys::ROUTER_KEY.to_string() - } - - fn type_url(&self) -> String { - TYPE_URL.to_string() - } -} - -impl Protobuf for MsgConnectionOpenConfirm {} - -impl TryFrom for MsgConnectionOpenConfirm { - type Error = Error; - - fn try_from(msg: RawMsgConnectionOpenConfirm) -> Result { - let proof_height = msg - .proof_height - .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or_else(Error::missing_proof_height)?; - - Ok(Self { - connection_id: msg - .connection_id - .parse() - .map_err(Error::invalid_identifier)?, - proofs: Proofs::new( - msg.proof_ack.try_into().map_err(Error::invalid_proof)?, - None, - None, - None, - proof_height, - ) - .map_err(Error::invalid_proof)?, - signer: msg.signer.parse().map_err(Error::signer)?, - }) - } -} - -impl From for RawMsgConnectionOpenConfirm { - fn from(ics_msg: MsgConnectionOpenConfirm) -> Self { - RawMsgConnectionOpenConfirm { - connection_id: ics_msg.connection_id.as_str().to_string(), - proof_ack: ics_msg.proofs.object_proof().clone().into(), - proof_height: Some(ics_msg.proofs.height().into()), - signer: ics_msg.signer.to_string(), - } - } -} - -#[cfg(test)] -pub mod test_util { - use crate::prelude::*; - use ibc_proto::ibc::core::client::v1::Height; - use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenConfirm as RawMsgConnectionOpenConfirm; - - use crate::test_utils::{get_dummy_bech32_account, get_dummy_proof}; - - pub fn get_dummy_raw_msg_conn_open_confirm() -> RawMsgConnectionOpenConfirm { - RawMsgConnectionOpenConfirm { - connection_id: "srcconnection".to_string(), - proof_ack: get_dummy_proof(), - proof_height: Some(Height { - revision_number: 0, - revision_height: 10, - }), - signer: get_dummy_bech32_account(), - } - } -} - -#[cfg(test)] -mod tests { - use crate::prelude::*; - - use test_log::test; - - use ibc_proto::ibc::core::client::v1::Height; - use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenConfirm as RawMsgConnectionOpenConfirm; - - use crate::core::ics03_connection::msgs::conn_open_confirm::test_util::get_dummy_raw_msg_conn_open_confirm; - use crate::core::ics03_connection::msgs::conn_open_confirm::MsgConnectionOpenConfirm; - - #[test] - fn parse_connection_open_confirm_msg() { - #[derive(Clone, Debug, PartialEq)] - struct Test { - name: String, - raw: RawMsgConnectionOpenConfirm, - want_pass: bool, - } - - let default_ack_msg = get_dummy_raw_msg_conn_open_confirm(); - let tests: Vec = vec![ - Test { - name: "Good parameters".to_string(), - raw: default_ack_msg.clone(), - want_pass: true, - }, - Test { - name: "Bad connection id, non-alpha".to_string(), - raw: RawMsgConnectionOpenConfirm { - connection_id: "con007".to_string(), - ..default_ack_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Bad proof height, height is 0".to_string(), - raw: RawMsgConnectionOpenConfirm { - proof_height: Some(Height { - revision_number: 1, - revision_height: 0, - }), - ..default_ack_msg - }, - want_pass: false, - }, - ] - .into_iter() - .collect(); - - for test in tests { - let msg = MsgConnectionOpenConfirm::try_from(test.raw.clone()); - - assert_eq!( - test.want_pass, - msg.is_ok(), - "MsgConnOpenTry::new failed for test {}, \nmsg {:?} with error {:?}", - test.name, - test.raw, - msg.err(), - ); - } - } - - #[test] - fn to_and_from() { - let raw = get_dummy_raw_msg_conn_open_confirm(); - let msg = MsgConnectionOpenConfirm::try_from(raw.clone()).unwrap(); - let raw_back = RawMsgConnectionOpenConfirm::from(msg.clone()); - let msg_back = MsgConnectionOpenConfirm::try_from(raw_back.clone()).unwrap(); - assert_eq!(raw, raw_back); - assert_eq!(msg, msg_back); - } -} diff --git a/modules/src/core/ics03_connection/msgs/conn_open_init.rs b/modules/src/core/ics03_connection/msgs/conn_open_init.rs deleted file mode 100644 index b48bf3f2ce..0000000000 --- a/modules/src/core/ics03_connection/msgs/conn_open_init.rs +++ /dev/null @@ -1,183 +0,0 @@ -use crate::prelude::*; - -use core::time::Duration; - -use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenInit as RawMsgConnectionOpenInit; -use ibc_proto::protobuf::Protobuf; - -use crate::core::ics03_connection::connection::Counterparty; -use crate::core::ics03_connection::error::Error; -use crate::core::ics03_connection::version::Version; -use crate::core::ics24_host::identifier::ClientId; -use crate::signer::Signer; -use crate::tx_msg::Msg; - -pub const TYPE_URL: &str = "/ibc.core.connection.v1.MsgConnectionOpenInit"; - -/// -/// Message definition `MsgConnectionOpenInit` (i.e., the `ConnOpenInit` datagram). -/// -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct MsgConnectionOpenInit { - pub client_id: ClientId, - pub counterparty: Counterparty, - pub version: Option, - pub delay_period: Duration, - pub signer: Signer, -} - -impl Msg for MsgConnectionOpenInit { - type ValidationError = Error; - type Raw = RawMsgConnectionOpenInit; - - fn route(&self) -> String { - crate::keys::ROUTER_KEY.to_string() - } - - fn type_url(&self) -> String { - TYPE_URL.to_string() - } -} - -impl Protobuf for MsgConnectionOpenInit {} - -impl TryFrom for MsgConnectionOpenInit { - type Error = Error; - - fn try_from(msg: RawMsgConnectionOpenInit) -> Result { - Ok(Self { - client_id: msg.client_id.parse().map_err(Error::invalid_identifier)?, - counterparty: msg - .counterparty - .ok_or_else(Error::missing_counterparty)? - .try_into()?, - version: msg.version.map(|version| version.try_into()).transpose()?, - delay_period: Duration::from_nanos(msg.delay_period), - signer: msg.signer.parse().map_err(Error::signer)?, - }) - } -} - -impl From for RawMsgConnectionOpenInit { - fn from(ics_msg: MsgConnectionOpenInit) -> Self { - RawMsgConnectionOpenInit { - client_id: ics_msg.client_id.as_str().to_string(), - counterparty: Some(ics_msg.counterparty.into()), - version: ics_msg.version.map(|version| version.into()), - delay_period: ics_msg.delay_period.as_nanos() as u64, - signer: ics_msg.signer.to_string(), - } - } -} - -#[cfg(test)] -pub mod test_util { - use crate::prelude::*; - use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenInit as RawMsgConnectionOpenInit; - - use crate::core::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; - use crate::core::ics03_connection::msgs::test_util::get_dummy_raw_counterparty; - use crate::core::ics03_connection::version::Version; - use crate::core::ics24_host::identifier::ClientId; - use crate::test_utils::get_dummy_bech32_account; - - /// Extends the implementation with additional helper methods. - impl MsgConnectionOpenInit { - /// Setter for `client_id`. Amenable to chaining, since it consumes the input message. - pub fn with_client_id(self, client_id: ClientId) -> Self { - MsgConnectionOpenInit { client_id, ..self } - } - } - - /// Returns a dummy message, for testing only. - /// Other unit tests may import this if they depend on a MsgConnectionOpenInit. - pub fn get_dummy_raw_msg_conn_open_init() -> RawMsgConnectionOpenInit { - RawMsgConnectionOpenInit { - client_id: ClientId::default().to_string(), - counterparty: Some(get_dummy_raw_counterparty()), - version: Some(Version::default().into()), - delay_period: 0, - signer: get_dummy_bech32_account(), - } - } -} - -#[cfg(test)] -mod tests { - use crate::prelude::*; - - use test_log::test; - - use ibc_proto::ibc::core::connection::v1::Counterparty as RawCounterparty; - use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenInit as RawMsgConnectionOpenInit; - - use super::MsgConnectionOpenInit; - use crate::core::ics03_connection::msgs::conn_open_init::test_util::get_dummy_raw_msg_conn_open_init; - use crate::core::ics03_connection::msgs::test_util::get_dummy_raw_counterparty; - - #[test] - fn parse_connection_open_init_msg() { - #[derive(Clone, Debug, PartialEq)] - struct Test { - name: String, - raw: RawMsgConnectionOpenInit, - want_pass: bool, - } - - let default_init_msg = get_dummy_raw_msg_conn_open_init(); - - let tests: Vec = vec![ - Test { - name: "Good parameters".to_string(), - raw: default_init_msg.clone(), - want_pass: true, - }, - Test { - name: "Bad client id, name too short".to_string(), - raw: RawMsgConnectionOpenInit { - client_id: "client".to_string(), - ..default_init_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Bad destination connection id, name too long".to_string(), - raw: RawMsgConnectionOpenInit { - counterparty: Some(RawCounterparty { - connection_id: - "abcdefghijksdffjssdkflweldflsfladfsfwjkrekcmmsdfsdfjflddmnopqrstu" - .to_string(), - ..get_dummy_raw_counterparty() - }), - ..default_init_msg - }, - want_pass: false, - }, - ] - .into_iter() - .collect(); - - for test in tests { - let msg = MsgConnectionOpenInit::try_from(test.raw.clone()); - - assert_eq!( - test.want_pass, - msg.is_ok(), - "MsgConnOpenInit::new failed for test {}, \nmsg {:?} with error {:?}", - test.name, - test.raw, - msg.err(), - ); - } - } - - #[test] - fn to_and_from() { - let raw = get_dummy_raw_msg_conn_open_init(); - let msg = MsgConnectionOpenInit::try_from(raw.clone()).unwrap(); - let raw_back = RawMsgConnectionOpenInit::from(msg.clone()); - let msg_back = MsgConnectionOpenInit::try_from(raw_back.clone()).unwrap(); - assert_eq!(raw, raw_back); - assert_eq!(msg, msg_back); - } -} diff --git a/modules/src/core/ics03_connection/msgs/conn_open_try.rs b/modules/src/core/ics03_connection/msgs/conn_open_try.rs deleted file mode 100644 index 4e60217c89..0000000000 --- a/modules/src/core/ics03_connection/msgs/conn_open_try.rs +++ /dev/null @@ -1,359 +0,0 @@ -use crate::prelude::*; - -use core::{ - convert::{TryFrom, TryInto}, - str::FromStr, - time::Duration, -}; - -use ibc_proto::google::protobuf::Any; -use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenTry as RawMsgConnectionOpenTry; -use ibc_proto::protobuf::Protobuf; - -use crate::core::ics03_connection::connection::Counterparty; -use crate::core::ics03_connection::error::Error; -use crate::core::ics03_connection::version::Version; -use crate::core::ics23_commitment::commitment::CommitmentProofBytes; -use crate::core::ics24_host::identifier::{ClientId, ConnectionId}; -use crate::proofs::{ConsensusProof, Proofs}; -use crate::signer::Signer; -use crate::tx_msg::Msg; -use crate::Height; - -pub const TYPE_URL: &str = "/ibc.core.connection.v1.MsgConnectionOpenTry"; - -/// -/// Message definition `MsgConnectionOpenTry` (i.e., `ConnOpenTry` datagram). -/// -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct MsgConnectionOpenTry { - pub previous_connection_id: Option, - pub client_id: ClientId, - pub client_state: Option, - pub counterparty: Counterparty, - pub counterparty_versions: Vec, - pub proofs: Proofs, - pub delay_period: Duration, - pub signer: Signer, -} - -impl MsgConnectionOpenTry { - /// Getter for accessing the `consensus_height` field from this message. - /// Returns `None` if this field is not set. - pub fn consensus_height(&self) -> Option { - self.proofs.consensus_proof().map(|proof| proof.height()) - } -} - -impl Msg for MsgConnectionOpenTry { - type ValidationError = Error; - type Raw = RawMsgConnectionOpenTry; - - fn route(&self) -> String { - crate::keys::ROUTER_KEY.to_string() - } - - fn type_url(&self) -> String { - TYPE_URL.to_string() - } -} - -impl Protobuf for MsgConnectionOpenTry {} - -impl TryFrom for MsgConnectionOpenTry { - type Error = Error; - - fn try_from(msg: RawMsgConnectionOpenTry) -> Result { - let previous_connection_id = Some(msg.previous_connection_id) - .filter(|x| !x.is_empty()) - .map(|v| FromStr::from_str(v.as_str())) - .transpose() - .map_err(Error::invalid_identifier)?; - - let consensus_height = msg - .consensus_height - .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or_else(Error::missing_consensus_height)?; - - let consensus_proof_obj = ConsensusProof::new( - msg.proof_consensus - .try_into() - .map_err(Error::invalid_proof)?, - consensus_height, - ) - .map_err(Error::invalid_proof)?; - - let proof_height = msg - .proof_height - .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or_else(Error::missing_proof_height)?; - - let client_proof = - CommitmentProofBytes::try_from(msg.proof_client).map_err(Error::invalid_proof)?; - - let counterparty_versions = msg - .counterparty_versions - .into_iter() - .map(Version::try_from) - .collect::, _>>()?; - - if counterparty_versions.is_empty() { - return Err(Error::empty_versions()); - } - - Ok(Self { - previous_connection_id, - client_id: msg.client_id.parse().map_err(Error::invalid_identifier)?, - client_state: msg.client_state, - counterparty: msg - .counterparty - .ok_or_else(Error::missing_counterparty)? - .try_into()?, - counterparty_versions, - proofs: Proofs::new( - msg.proof_init.try_into().map_err(Error::invalid_proof)?, - Some(client_proof), - Some(consensus_proof_obj), - None, - proof_height, - ) - .map_err(Error::invalid_proof)?, - delay_period: Duration::from_nanos(msg.delay_period), - signer: msg.signer.parse().map_err(Error::signer)?, - }) - } -} - -impl From for RawMsgConnectionOpenTry { - fn from(ics_msg: MsgConnectionOpenTry) -> Self { - RawMsgConnectionOpenTry { - client_id: ics_msg.client_id.as_str().to_string(), - previous_connection_id: ics_msg - .previous_connection_id - .map_or_else(|| "".to_string(), |v| v.as_str().to_string()), - client_state: ics_msg.client_state, - counterparty: Some(ics_msg.counterparty.into()), - delay_period: ics_msg.delay_period.as_nanos() as u64, - counterparty_versions: ics_msg - .counterparty_versions - .iter() - .map(|v| v.clone().into()) - .collect(), - proof_height: Some(ics_msg.proofs.height().into()), - proof_init: ics_msg.proofs.object_proof().clone().into(), - proof_client: ics_msg - .proofs - .client_proof() - .clone() - .map_or_else(Vec::new, |v| v.into()), - proof_consensus: ics_msg - .proofs - .consensus_proof() - .map_or_else(Vec::new, |v| v.proof().clone().into()), - consensus_height: ics_msg - .proofs - .consensus_proof() - .map_or_else(|| None, |h| Some(h.height().into())), - signer: ics_msg.signer.to_string(), - } - } -} - -#[cfg(test)] -pub mod test_util { - use crate::prelude::*; - use ibc_proto::ibc::core::client::v1::Height; - use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenTry as RawMsgConnectionOpenTry; - - use crate::core::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; - use crate::core::ics03_connection::msgs::test_util::get_dummy_raw_counterparty; - use crate::core::ics03_connection::version::get_compatible_versions; - use crate::core::ics24_host::identifier::{ClientId, ConnectionId}; - use crate::test_utils::{get_dummy_bech32_account, get_dummy_proof}; - - /// Testing-specific helper methods. - impl MsgConnectionOpenTry { - /// Moves the given message into another one, and updates the `previous_connection_id` field. - pub fn with_previous_connection_id( - self, - previous_connection_id: Option, - ) -> MsgConnectionOpenTry { - MsgConnectionOpenTry { - previous_connection_id, - ..self - } - } - - /// Setter for `client_id`. - pub fn with_client_id(self, client_id: ClientId) -> MsgConnectionOpenTry { - MsgConnectionOpenTry { client_id, ..self } - } - } - - /// Returns a dummy `RawMsgConnectionOpenTry` with parametrized heights. The parameter - /// `proof_height` represents the height, on the source chain, at which this chain produced the - /// proof. Parameter `consensus_height` represents the height of destination chain which a - /// client on the source chain stores. - pub fn get_dummy_raw_msg_conn_open_try( - proof_height: u64, - consensus_height: u64, - ) -> RawMsgConnectionOpenTry { - RawMsgConnectionOpenTry { - client_id: ClientId::default().to_string(), - previous_connection_id: ConnectionId::default().to_string(), - client_state: None, - counterparty: Some(get_dummy_raw_counterparty()), - delay_period: 0, - counterparty_versions: get_compatible_versions() - .iter() - .map(|v| v.clone().into()) - .collect(), - proof_init: get_dummy_proof(), - proof_height: Some(Height { - revision_number: 0, - revision_height: proof_height, - }), - proof_consensus: get_dummy_proof(), - consensus_height: Some(Height { - revision_number: 0, - revision_height: consensus_height, - }), - proof_client: get_dummy_proof(), - signer: get_dummy_bech32_account(), - } - } -} - -#[cfg(test)] -mod tests { - use crate::prelude::*; - - use test_log::test; - - use ibc_proto::ibc::core::client::v1::Height; - use ibc_proto::ibc::core::connection::v1::Counterparty as RawCounterparty; - use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenTry as RawMsgConnectionOpenTry; - - use crate::core::ics03_connection::msgs::conn_open_try::test_util::get_dummy_raw_msg_conn_open_try; - use crate::core::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; - use crate::core::ics03_connection::msgs::test_util::get_dummy_raw_counterparty; - - #[test] - fn parse_connection_open_try_msg() { - #[derive(Clone, Debug, PartialEq)] - struct Test { - name: String, - raw: RawMsgConnectionOpenTry, - want_pass: bool, - } - - let default_try_msg = get_dummy_raw_msg_conn_open_try(10, 34); - - let tests: Vec = - vec![ - Test { - name: "Good parameters".to_string(), - raw: default_try_msg.clone(), - want_pass: true, - }, - Test { - name: "Bad client id, name too short".to_string(), - raw: RawMsgConnectionOpenTry { - client_id: "client".to_string(), - ..default_try_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Bad destination connection id, name too long".to_string(), - raw: RawMsgConnectionOpenTry { - counterparty: Some(RawCounterparty { - connection_id: - "abcdasdfasdfsdfasfdwefwfsdfsfsfasfwewvxcvdvwgadvaadsefghijklmnopqrstu" - .to_string(), - ..get_dummy_raw_counterparty() - }), - ..default_try_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Correct destination client id with lower/upper case and special chars" - .to_string(), - raw: RawMsgConnectionOpenTry { - counterparty: Some(RawCounterparty { - client_id: "ClientId_".to_string(), - ..get_dummy_raw_counterparty() - }), - ..default_try_msg.clone() - }, - want_pass: true, - }, - Test { - name: "Bad counterparty versions, empty versions vec".to_string(), - raw: RawMsgConnectionOpenTry { - counterparty_versions: Vec::new(), - ..default_try_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Bad counterparty versions, empty version string".to_string(), - raw: RawMsgConnectionOpenTry { - counterparty_versions: Vec::new(), - ..default_try_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Bad proof height, height is 0".to_string(), - raw: RawMsgConnectionOpenTry { - proof_height: Some(Height { revision_number: 1, revision_height: 0 }), - ..default_try_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Bad consensus height, height is 0".to_string(), - raw: RawMsgConnectionOpenTry { - proof_height: Some(Height { revision_number: 1, revision_height: 0 }), - ..default_try_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Empty proof".to_string(), - raw: RawMsgConnectionOpenTry { - proof_init: b"".to_vec(), - ..default_try_msg - }, - want_pass: false, - } - ] - .into_iter() - .collect(); - - for test in tests { - let msg = MsgConnectionOpenTry::try_from(test.raw.clone()); - - assert_eq!( - test.want_pass, - msg.is_ok(), - "MsgConnOpenTry::new failed for test {}, \nmsg {:?} with error {:?}", - test.name, - test.raw, - msg.err(), - ); - } - } - - #[test] - fn to_and_from() { - let raw = get_dummy_raw_msg_conn_open_try(10, 34); - let msg = MsgConnectionOpenTry::try_from(raw.clone()).unwrap(); - let raw_back = RawMsgConnectionOpenTry::from(msg.clone()); - let msg_back = MsgConnectionOpenTry::try_from(raw_back.clone()).unwrap(); - assert_eq!(raw, raw_back); - assert_eq!(msg, msg_back); - } -} diff --git a/modules/src/core/ics03_connection/version.rs b/modules/src/core/ics03_connection/version.rs deleted file mode 100644 index 983d2198ff..0000000000 --- a/modules/src/core/ics03_connection/version.rs +++ /dev/null @@ -1,315 +0,0 @@ -use core::fmt::Display; - -use crate::prelude::*; -use crate::utils::pretty::PrettyVec; - -use ibc_proto::ibc::core::connection::v1::Version as RawVersion; -use ibc_proto::protobuf::Protobuf; -use serde::{Deserialize, Serialize}; - -use crate::core::ics03_connection::error::Error; -use crate::core::ics04_channel::channel::Order; - -/// Stores the identifier and the features supported by a version -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct Version { - /// unique version identifier - identifier: String, - /// list of features compatible with the specified identifier - features: Vec, -} - -impl Version { - /// Checks whether or not the given feature is supported in this versin - pub fn is_supported_feature(&self, feature: String) -> bool { - self.features.contains(&feature) - } -} - -impl Protobuf for Version {} - -impl TryFrom for Version { - type Error = Error; - fn try_from(value: RawVersion) -> Result { - if value.identifier.trim().is_empty() { - return Err(Error::empty_versions()); - } - for feature in value.features.iter() { - if feature.trim().is_empty() { - return Err(Error::empty_features()); - } - } - Ok(Version { - identifier: value.identifier, - features: value.features, - }) - } -} - -impl From for RawVersion { - fn from(value: Version) -> Self { - Self { - identifier: value.identifier, - features: value.features, - } - } -} - -impl Default for Version { - fn default() -> Self { - Version { - identifier: "1".to_string(), - features: vec![ - Order::Ordered.as_str().to_owned(), - Order::Unordered.as_str().to_owned(), - ], - } - } -} - -impl Display for Version { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!( - f, - "Version {{ identifier: {}, features: {} }}", - self.identifier, - PrettyVec(&self.features) - ) - } -} - -/// Returns the lists of supported versions -pub fn get_compatible_versions() -> Vec { - vec![Version::default()] -} - -/// Selects a version from the intersection of locally supported and counterparty versions. -pub fn pick_version( - supported_versions: Vec, - counterparty_versions: Vec, -) -> Result { - let mut intersection: Vec = Vec::new(); - for s in supported_versions.iter() { - for c in counterparty_versions.iter() { - if c.identifier != s.identifier { - continue; - } - for feature in c.features.iter() { - if feature.trim().is_empty() { - return Err(Error::empty_features()); - } - } - intersection.append(&mut vec![s.clone()]); - } - } - intersection.sort_by(|a, b| a.identifier.cmp(&b.identifier)); - if intersection.is_empty() { - return Err(Error::no_common_version()); - } - Ok(intersection[0].clone()) -} - -#[cfg(test)] -mod tests { - use crate::prelude::*; - - use test_log::test; - - use ibc_proto::ibc::core::connection::v1::Version as RawVersion; - - use crate::core::ics03_connection::error::Error; - use crate::core::ics03_connection::version::{get_compatible_versions, pick_version, Version}; - - fn good_versions() -> Vec { - vec![ - Version::default().into(), - RawVersion { - identifier: "2".to_string(), - features: vec!["ORDER_RANDOM".to_string(), "ORDER_UNORDERED".to_string()], - }, - ] - .into_iter() - .collect() - } - - fn bad_versions_identifier() -> Vec { - vec![RawVersion { - identifier: "".to_string(), - features: vec!["ORDER_RANDOM".to_string(), "ORDER_UNORDERED".to_string()], - }] - .into_iter() - .collect() - } - - fn bad_versions_features() -> Vec { - vec![RawVersion { - identifier: "2".to_string(), - features: vec!["".to_string()], - }] - .into_iter() - .collect() - } - - fn overlapping() -> (Vec, Vec, Version) { - ( - vec![ - Version::default(), - Version { - identifier: "3".to_string(), - features: Vec::new(), - }, - Version { - identifier: "4".to_string(), - features: Vec::new(), - }, - ] - .into_iter() - .collect(), - vec![ - Version { - identifier: "2".to_string(), - features: Vec::new(), - }, - Version { - identifier: "4".to_string(), - features: Vec::new(), - }, - Version { - identifier: "3".to_string(), - features: Vec::new(), - }, - ] - .into_iter() - .collect(), - // Should pick version 3 as it's the lowest of the intersection {3, 4} - Version { - identifier: "3".to_string(), - features: Vec::new(), - }, - ) - } - - fn disjoint() -> (Vec, Vec) { - ( - vec![Version { - identifier: "1".to_string(), - features: Vec::new(), - }] - .into_iter() - .collect(), - vec![Version { - identifier: "2".to_string(), - features: Vec::new(), - }] - .into_iter() - .collect(), - ) - } - - #[test] - fn verify() { - struct Test { - name: String, - versions: Vec, - want_pass: bool, - } - let tests: Vec = vec![ - Test { - name: "Compatible versions".to_string(), - versions: vec![Version::default().into()], - want_pass: true, - }, - Test { - name: "Multiple versions".to_string(), - versions: good_versions(), - want_pass: true, - }, - Test { - name: "Bad version identifier".to_string(), - versions: bad_versions_identifier(), - want_pass: false, - }, - Test { - name: "Bad version feature".to_string(), - versions: bad_versions_features(), - want_pass: false, - }, - Test { - name: "Bad versions empty".to_string(), - versions: Vec::new(), - want_pass: true, - }, - ]; - - for test in tests { - let versions = test - .versions - .into_iter() - .map(Version::try_from) - .collect::, _>>(); - - assert_eq!( - test.want_pass, - versions.is_ok(), - "Validate versions failed for test {} with error {:?}", - test.name, - versions.err(), - ); - } - } - #[test] - fn pick() { - struct Test { - name: String, - supported: Vec, - counterparty: Vec, - picked: Result, - want_pass: bool, - } - let tests: Vec = vec![ - Test { - name: "Compatible versions".to_string(), - supported: get_compatible_versions(), - counterparty: get_compatible_versions(), - picked: Ok(Version::default()), - want_pass: true, - }, - Test { - name: "Overlapping versions".to_string(), - supported: overlapping().0, - counterparty: overlapping().1, - picked: Ok(overlapping().2), - want_pass: true, - }, - Test { - name: "Disjoint versions".to_string(), - supported: disjoint().0, - counterparty: disjoint().1, - picked: Err(Error::no_common_version()), - want_pass: false, - }, - ]; - - for test in tests { - let version = pick_version(test.supported, test.counterparty); - - assert_eq!( - test.want_pass, - version.is_ok(), - "Validate versions failed for test {}", - test.name, - ); - - if test.want_pass { - assert_eq!(version.unwrap(), test.picked.unwrap()); - } - } - } - #[test] - fn serialize() { - let def = Version::default(); - let def_raw: RawVersion = def.clone().into(); - let def_back = def_raw.try_into().unwrap(); - assert_eq!(def, def_back); - } -} diff --git a/modules/src/core/ics04_channel/channel.rs b/modules/src/core/ics04_channel/channel.rs deleted file mode 100644 index eb331a03a0..0000000000 --- a/modules/src/core/ics04_channel/channel.rs +++ /dev/null @@ -1,611 +0,0 @@ -use crate::prelude::*; -use crate::utils::pretty::PrettyVec; - -use core::fmt::{Display, Error as FmtError, Formatter}; -use core::str::FromStr; - -use ibc_proto::protobuf::Protobuf; -use serde::{Deserialize, Serialize}; - -use ibc_proto::ibc::core::channel::v1::{ - Channel as RawChannel, Counterparty as RawCounterparty, - IdentifiedChannel as RawIdentifiedChannel, -}; - -use crate::core::ics04_channel::{error::Error, Version}; -use crate::core::ics24_host::identifier::{ChannelId, ConnectionId, PortId}; - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct IdentifiedChannelEnd { - pub port_id: PortId, - pub channel_id: ChannelId, - pub channel_end: ChannelEnd, -} - -impl IdentifiedChannelEnd { - pub fn new(port_id: PortId, channel_id: ChannelId, channel_end: ChannelEnd) -> Self { - IdentifiedChannelEnd { - port_id, - channel_id, - channel_end, - } - } -} - -impl Protobuf for IdentifiedChannelEnd {} - -impl TryFrom for IdentifiedChannelEnd { - type Error = Error; - - fn try_from(value: RawIdentifiedChannel) -> Result { - let raw_channel_end = RawChannel { - state: value.state, - ordering: value.ordering, - counterparty: value.counterparty, - connection_hops: value.connection_hops, - version: value.version, - }; - - Ok(IdentifiedChannelEnd { - port_id: value.port_id.parse().map_err(Error::identifier)?, - channel_id: value.channel_id.parse().map_err(Error::identifier)?, - channel_end: raw_channel_end.try_into()?, - }) - } -} - -impl From for RawIdentifiedChannel { - fn from(value: IdentifiedChannelEnd) -> Self { - RawIdentifiedChannel { - 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 - .channel_end - .connection_hops - .iter() - .map(|v| v.as_str().to_string()) - .collect(), - version: value.channel_end.version.to_string(), - port_id: value.port_id.to_string(), - channel_id: value.channel_id.to_string(), - } - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct ChannelEnd { - pub state: State, - pub ordering: Order, - pub remote: Counterparty, - pub connection_hops: Vec, - pub version: Version, -} - -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, PrettyVec(&self.connection_hops), self.version - ) - } -} - -impl Default for ChannelEnd { - fn default() -> Self { - ChannelEnd { - state: State::Uninitialized, - ordering: Default::default(), - remote: Counterparty::default(), - connection_hops: Vec::new(), - version: Version::default(), - } - } -} - -impl Protobuf for ChannelEnd {} - -impl TryFrom for ChannelEnd { - type Error = Error; - - fn try_from(value: RawChannel) -> Result { - let chan_state: State = State::from_i32(value.state)?; - - if chan_state == State::Uninitialized { - return Ok(ChannelEnd::default()); - } - - let chan_ordering = Order::from_i32(value.ordering)?; - - // Assemble the 'remote' attribute of the Channel, which represents the Counterparty. - let remote = value - .counterparty - .ok_or_else(Error::missing_counterparty)? - .try_into()?; - - // Parse each item in connection_hops into a ConnectionId. - let connection_hops = value - .connection_hops - .into_iter() - .map(|conn_id| ConnectionId::from_str(conn_id.as_str())) - .collect::, _>>() - .map_err(Error::identifier)?; - - let version = value.version.into(); - - Ok(ChannelEnd::new( - chan_state, - chan_ordering, - remote, - connection_hops, - version, - )) - } -} - -impl From for RawChannel { - fn from(value: ChannelEnd) -> Self { - RawChannel { - state: value.state as i32, - ordering: value.ordering as i32, - counterparty: Some(value.counterparty().clone().into()), - connection_hops: value - .connection_hops - .iter() - .map(|v| v.as_str().to_string()) - .collect(), - version: value.version.to_string(), - } - } -} - -impl ChannelEnd { - /// Creates a new ChannelEnd in state Uninitialized and other fields parametrized. - pub fn new( - state: State, - ordering: Order, - remote: Counterparty, - connection_hops: Vec, - version: Version, - ) -> Self { - Self { - state, - ordering, - remote, - connection_hops, - version, - } - } - - /// Updates the ChannelEnd to assume a new State 's'. - pub fn set_state(&mut self, s: State) { - self.state = s; - } - - pub fn set_version(&mut self, v: Version) { - self.version = v; - } - - pub fn set_counterparty_channel_id(&mut self, c: ChannelId) { - self.remote.channel_id = Some(c); - } - - /// Returns `true` if this `ChannelEnd` is in state [`State::Open`]. - pub fn is_open(&self) -> bool { - self.state_matches(&State::Open) - } - - pub fn state(&self) -> &State { - &self.state - } - - pub fn ordering(&self) -> &Order { - &self.ordering - } - - pub fn counterparty(&self) -> &Counterparty { - &self.remote - } - - pub fn connection_hops(&self) -> &Vec { - &self.connection_hops - } - - pub fn version(&self) -> &Version { - &self.version - } - - pub fn validate_basic(&self) -> Result<(), Error> { - if self.connection_hops.len() != 1 { - return Err(Error::invalid_connection_hops_length( - 1, - self.connection_hops.len(), - )); - } - self.counterparty().validate_basic() - } - - /// Helper function to compare the state of this end with another state. - pub fn state_matches(&self, other: &State) -> bool { - self.state.eq(other) - } - - /// Helper function to compare the order of this end with another order. - pub fn order_matches(&self, other: &Order) -> bool { - self.ordering.eq(other) - } - - #[allow(clippy::ptr_arg)] - pub fn connection_hops_matches(&self, other: &Vec) -> bool { - self.connection_hops.eq(other) - } - - pub fn counterparty_matches(&self, other: &Counterparty) -> bool { - self.counterparty().eq(other) - } - - pub fn version_matches(&self, other: &Version) -> bool { - self.version().eq(other) - } -} - -#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] -pub struct Counterparty { - pub port_id: PortId, - pub channel_id: Option, -} - -impl Counterparty { - pub fn new(port_id: PortId, channel_id: Option) -> Self { - Self { - port_id, - channel_id, - } - } - - pub fn port_id(&self) -> &PortId { - &self.port_id - } - - pub fn channel_id(&self) -> Option<&ChannelId> { - self.channel_id.as_ref() - } - - pub fn validate_basic(&self) -> Result<(), Error> { - Ok(()) - } -} - -impl Display for Counterparty { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - match &self.channel_id { - Some(channel_id) => write!( - f, - "Counterparty(port_id: {}, channel_id: {})", - self.port_id, channel_id - ), - None => write!( - f, - "Counterparty(port_id: {}, channel_id: None)", - self.port_id - ), - } - } -} - -impl Protobuf for Counterparty {} - -impl TryFrom for Counterparty { - type Error = Error; - - fn try_from(value: RawCounterparty) -> Result { - let channel_id = Some(value.channel_id) - .filter(|x| !x.is_empty()) - .map(|v| FromStr::from_str(v.as_str())) - .transpose() - .map_err(Error::identifier)?; - Ok(Counterparty::new( - value.port_id.parse().map_err(Error::identifier)?, - channel_id, - )) - } -} - -impl From for RawCounterparty { - fn from(value: Counterparty) -> Self { - RawCounterparty { - port_id: value.port_id.as_str().to_string(), - channel_id: value - .channel_id - .map_or_else(|| "".to_string(), |v| v.to_string()), - } - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)] -pub enum Order { - None = 0, - Unordered = 1, - Ordered = 2, -} - -impl Default for Order { - fn default() -> Self { - Order::Unordered - } -} - -impl Display for Order { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "{}", self.as_str()) - } -} - -impl Order { - /// Yields the Order as a string - pub fn as_str(&self) -> &'static str { - match self { - Self::None => "UNINITIALIZED", - Self::Unordered => "ORDER_UNORDERED", - Self::Ordered => "ORDER_ORDERED", - } - } - - // Parses the Order out from a i32. - pub fn from_i32(nr: i32) -> Result { - match nr { - 0 => Ok(Self::None), - 1 => Ok(Self::Unordered), - 2 => Ok(Self::Ordered), - _ => Err(Error::unknown_order_type(nr.to_string())), - } - } -} - -impl FromStr for Order { - type Err = Error; - - fn from_str(s: &str) -> Result { - match s.to_lowercase().trim_start_matches("order_") { - "uninitialized" => Ok(Self::None), - "unordered" => Ok(Self::Unordered), - "ordered" => Ok(Self::Ordered), - _ => Err(Error::unknown_order_type(s.to_string())), - } - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub enum State { - Uninitialized = 0, - Init = 1, - TryOpen = 2, - Open = 3, - Closed = 4, -} - -impl State { - /// Yields the state as a string - pub fn as_string(&self) -> &'static str { - match self { - Self::Uninitialized => "UNINITIALIZED", - Self::Init => "INIT", - Self::TryOpen => "TRYOPEN", - Self::Open => "OPEN", - Self::Closed => "CLOSED", - } - } - - // Parses the State out from a i32. - pub fn from_i32(s: i32) -> Result { - match s { - 0 => Ok(Self::Uninitialized), - 1 => Ok(Self::Init), - 2 => Ok(Self::TryOpen), - 3 => Ok(Self::Open), - 4 => Ok(Self::Closed), - _ => Err(Error::unknown_state(s)), - } - } - - /// Returns whether or not this channel state is `Open`. - pub fn is_open(self) -> bool { - self == State::Open - } - - /// Returns whether or not the channel with this state - /// has progressed less or the same than the argument. - /// - /// # Example - /// ```rust,ignore - /// assert!(State::Init.less_or_equal_progress(State::Open)); - /// assert!(State::TryOpen.less_or_equal_progress(State::TryOpen)); - /// 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 - } -} - -/// Provides a `to_string` method. -impl Display for State { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "{}", self.as_string()) - } -} - -#[cfg(test)] -pub mod test_util { - use crate::core::ics24_host::identifier::{ChannelId, ConnectionId, PortId}; - use crate::prelude::*; - use ibc_proto::ibc::core::channel::v1::Channel as RawChannel; - use ibc_proto::ibc::core::channel::v1::Counterparty as RawCounterparty; - - /// Returns a dummy `RawCounterparty`, for testing only! - /// Can be optionally parametrized with a specific channel identifier. - pub fn get_dummy_raw_counterparty() -> RawCounterparty { - RawCounterparty { - port_id: PortId::default().to_string(), - channel_id: ChannelId::default().to_string(), - } - } - - /// Returns a dummy `RawChannel`, for testing only! - pub fn get_dummy_raw_channel_end() -> RawChannel { - RawChannel { - state: 1, - ordering: 2, - counterparty: Some(get_dummy_raw_counterparty()), - connection_hops: vec![ConnectionId::default().to_string()], - version: "ics20".to_string(), // The version is not validated. - } - } -} - -#[cfg(test)] -mod tests { - use crate::prelude::*; - - use core::str::FromStr; - use test_log::test; - - use ibc_proto::ibc::core::channel::v1::Channel as RawChannel; - - use crate::core::ics04_channel::channel::test_util::get_dummy_raw_channel_end; - use crate::core::ics04_channel::channel::ChannelEnd; - - #[test] - fn channel_end_try_from_raw() { - let raw_channel_end = get_dummy_raw_channel_end(); - - let empty_raw_channel_end = RawChannel { - counterparty: None, - ..raw_channel_end.clone() - }; - - struct Test { - name: String, - params: RawChannel, - want_pass: bool, - } - - let tests: Vec = vec![ - Test { - name: "Raw channel end with missing counterparty".to_string(), - params: empty_raw_channel_end, - want_pass: false, - }, - Test { - name: "Raw channel end with incorrect state".to_string(), - params: RawChannel { - state: -1, - ..raw_channel_end.clone() - }, - want_pass: false, - }, - Test { - name: "Raw channel end with incorrect ordering".to_string(), - params: RawChannel { - ordering: -1, - ..raw_channel_end.clone() - }, - want_pass: false, - }, - Test { - name: "Raw channel end with incorrect connection id in connection hops".to_string(), - params: RawChannel { - connection_hops: vec!["connection*".to_string()].into_iter().collect(), - ..raw_channel_end.clone() - }, - want_pass: false, - }, - Test { - name: "Raw channel end with incorrect connection id (has blank space)".to_string(), - params: RawChannel { - connection_hops: vec!["con nection".to_string()].into_iter().collect(), - ..raw_channel_end.clone() - }, - want_pass: false, - }, - Test { - name: "Raw channel end with two correct connection ids in connection hops" - .to_string(), - params: RawChannel { - connection_hops: vec!["connection1".to_string(), "connection2".to_string()] - .into_iter() - .collect(), - ..raw_channel_end.clone() - }, - want_pass: true, - }, - Test { - name: "Raw channel end with correct params".to_string(), - params: raw_channel_end, - want_pass: true, - }, - ] - .into_iter() - .collect(); - - for test in tests { - let p = test.params.clone(); - - let ce_result = ChannelEnd::try_from(p); - - assert_eq!( - test.want_pass, - ce_result.is_ok(), - "ChannelEnd::try_from() failed for test {}, \nmsg{:?} with error {:?}", - test.name, - test.params.clone(), - ce_result.err(), - ); - } - } - - #[test] - fn parse_channel_ordering_type() { - use super::Order; - - struct Test { - ordering: &'static str, - want_res: Order, - want_err: bool, - } - let tests: Vec = vec![ - Test { - ordering: "UNINITIALIZED", - want_res: Order::None, - want_err: false, - }, - Test { - ordering: "UNORDERED", - want_res: Order::Unordered, - want_err: false, - }, - Test { - ordering: "ORDERED", - want_res: Order::Ordered, - want_err: false, - }, - Test { - ordering: "UNKNOWN_ORDER", - want_res: Order::None, - want_err: true, - }, - ] - .into_iter() - .collect(); - - for test in tests { - match Order::from_str(test.ordering) { - Ok(res) => { - assert!(!test.want_err); - assert_eq!(test.want_res, res); - } - Err(_) => assert!(test.want_err, "parse failed"), - } - } - } -} diff --git a/modules/src/core/ics04_channel/commitment.rs b/modules/src/core/ics04_channel/commitment.rs deleted file mode 100644 index 62f13bc4ea..0000000000 --- a/modules/src/core/ics04_channel/commitment.rs +++ /dev/null @@ -1,47 +0,0 @@ -use crate::prelude::*; - -use serde_derive::{Deserialize, Serialize}; - -/// Packet commitment -#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] -pub struct PacketCommitment(Vec); - -impl PacketCommitment { - pub fn into_vec(self) -> Vec { - self.0 - } -} - -impl AsRef<[u8]> for PacketCommitment { - fn as_ref(&self) -> &[u8] { - &self.0 - } -} - -impl From> for PacketCommitment { - fn from(bytes: Vec) -> Self { - Self(bytes) - } -} - -/// Acknowledgement commitment to be stored -#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] -pub struct AcknowledgementCommitment(Vec); - -impl AcknowledgementCommitment { - pub fn into_vec(self) -> Vec { - self.0 - } -} - -impl AsRef<[u8]> for AcknowledgementCommitment { - fn as_ref(&self) -> &[u8] { - &self.0 - } -} - -impl From> for AcknowledgementCommitment { - fn from(bytes: Vec) -> Self { - Self(bytes) - } -} diff --git a/modules/src/core/ics04_channel/context.rs b/modules/src/core/ics04_channel/context.rs deleted file mode 100644 index be771b6c93..0000000000 --- a/modules/src/core/ics04_channel/context.rs +++ /dev/null @@ -1,336 +0,0 @@ -//! ICS4 (channel) context. The two traits `ChannelReader ` and `ChannelKeeper` define -//! the interface that any host chain must implement to be able to process any `ChannelMsg`. -//! -use crate::core::ics02_client::client_state::ClientState; -use core::time::Duration; -use num_traits::float::FloatCore; - -use crate::core::ics02_client::consensus_state::ConsensusState; -use crate::core::ics03_connection::connection::ConnectionEnd; -use crate::core::ics04_channel::channel::ChannelEnd; -use crate::core::ics04_channel::commitment::{AcknowledgementCommitment, PacketCommitment}; -use crate::core::ics04_channel::handler::recv_packet::RecvPacketResult; -use crate::core::ics04_channel::handler::{ChannelIdState, ChannelResult}; -use crate::core::ics04_channel::msgs::acknowledgement::Acknowledgement; -use crate::core::ics04_channel::{error::Error, packet::Receipt}; -use crate::core::ics24_host::identifier::{ChannelId, ClientId, ConnectionId, PortId}; -use crate::prelude::*; -use crate::timestamp::Timestamp; -use crate::Height; - -use super::packet::{PacketResult, Sequence}; -use super::timeout::TimeoutHeight; - -/// A context supplying all the necessary read-only dependencies for processing any `ChannelMsg`. -pub trait ChannelReader { - /// Returns the ChannelEnd for the given `port_id` and `chan_id`. - fn channel_end(&self, port_id: &PortId, channel_id: &ChannelId) -> Result; - - /// Returns the ConnectionState for the given identifier `connection_id`. - fn connection_end(&self, connection_id: &ConnectionId) -> Result; - - fn connection_channels(&self, cid: &ConnectionId) -> Result, Error>; - - /// Returns the ClientState for the given identifier `client_id`. Necessary dependency towards - /// proof verification. - fn client_state(&self, client_id: &ClientId) -> Result, Error>; - - fn client_consensus_state( - &self, - client_id: &ClientId, - height: Height, - ) -> Result, Error>; - - fn get_next_sequence_send( - &self, - port_id: &PortId, - channel_id: &ChannelId, - ) -> Result; - - fn get_next_sequence_recv( - &self, - port_id: &PortId, - channel_id: &ChannelId, - ) -> Result; - - fn get_next_sequence_ack( - &self, - port_id: &PortId, - channel_id: &ChannelId, - ) -> Result; - - fn get_packet_commitment( - &self, - port_id: &PortId, - channel_id: &ChannelId, - sequence: Sequence, - ) -> Result; - - fn get_packet_receipt( - &self, - port_id: &PortId, - channel_id: &ChannelId, - sequence: Sequence, - ) -> Result; - - fn get_packet_acknowledgement( - &self, - port_id: &PortId, - channel_id: &ChannelId, - sequence: Sequence, - ) -> Result; - - /// Compute the commitment for a packet. - /// Note that the absence of `timeout_height` is treated as - /// `{revision_number: 0, revision_height: 0}` to be consistent with ibc-go, - /// where this value is used to mean "no timeout height": - /// - fn packet_commitment( - &self, - packet_data: Vec, - timeout_height: TimeoutHeight, - timeout_timestamp: Timestamp, - ) -> PacketCommitment { - let mut hash_input = timeout_timestamp.nanoseconds().to_be_bytes().to_vec(); - - let revision_number = timeout_height.commitment_revision_number().to_be_bytes(); - hash_input.append(&mut revision_number.to_vec()); - - let revision_height = timeout_height.commitment_revision_height().to_be_bytes(); - hash_input.append(&mut revision_height.to_vec()); - - let packet_data_hash = self.hash(packet_data); - hash_input.append(&mut packet_data_hash.to_vec()); - - self.hash(hash_input).into() - } - - fn ack_commitment(&self, ack: Acknowledgement) -> AcknowledgementCommitment { - self.hash(ack.into()).into() - } - - /// A hashing function for packet commitments - fn hash(&self, value: Vec) -> Vec; - - /// Returns the current height of the local chain. - fn host_height(&self) -> Height; - - /// Returns the current timestamp of the local chain. - fn host_timestamp(&self) -> Timestamp { - let pending_consensus_state = self - .pending_host_consensus_state() - .expect("host must have pending consensus state"); - pending_consensus_state.timestamp() - } - - /// Returns the `ConsensusState` of the host (local) chain at a specific height. - fn host_consensus_state(&self, height: Height) -> Result, Error>; - - /// Returns the pending `ConsensusState` of the host (local) chain. - fn pending_host_consensus_state(&self) -> Result, Error>; - - /// Returns the time when the client state for the given [`ClientId`] was updated with a header for the given [`Height`] - fn client_update_time(&self, client_id: &ClientId, height: Height) -> Result; - - /// Returns the height when the client state for the given [`ClientId`] was updated with a header for the given [`Height`] - fn client_update_height(&self, client_id: &ClientId, height: Height) -> Result; - - /// Returns a counter on the number of channel ids have been created thus far. - /// The value of this counter should increase only via method - /// `ChannelKeeper::increase_channel_counter`. - fn channel_counter(&self) -> Result; - - /// Returns the maximum expected time per block - fn max_expected_time_per_block(&self) -> Duration; - - /// Calculates the block delay period using the connection's delay period and the maximum - /// expected time per block. - fn block_delay(&self, delay_period_time: Duration) -> u64 { - calculate_block_delay(delay_period_time, self.max_expected_time_per_block()) - } -} - -/// A context supplying all the necessary write-only dependencies (i.e., storage writing facility) -/// for processing any `ChannelMsg`. -pub trait ChannelKeeper { - fn store_channel_result(&mut self, result: ChannelResult) -> Result<(), Error> { - let connection_id = result.channel_end.connection_hops()[0].clone(); - - // The handler processed this channel & some modifications occurred, store the new end. - self.store_channel( - result.port_id.clone(), - result.channel_id.clone(), - result.channel_end, - )?; - - // The channel identifier was freshly brewed. - // Increase counter & initialize seq. nrs. - if matches!(result.channel_id_state, ChannelIdState::Generated) { - self.increase_channel_counter(); - - // Associate also the channel end to its connection. - self.store_connection_channels( - connection_id, - result.port_id.clone(), - result.channel_id.clone(), - )?; - - // Initialize send, recv, and ack sequence numbers. - self.store_next_sequence_send( - result.port_id.clone(), - result.channel_id.clone(), - 1.into(), - )?; - self.store_next_sequence_recv( - result.port_id.clone(), - result.channel_id.clone(), - 1.into(), - )?; - self.store_next_sequence_ack(result.port_id, result.channel_id, 1.into())?; - } - - Ok(()) - } - - fn store_packet_result(&mut self, general_result: PacketResult) -> Result<(), Error> { - match general_result { - PacketResult::Send(res) => { - self.store_next_sequence_send( - res.port_id.clone(), - res.channel_id.clone(), - res.seq_number, - )?; - - self.store_packet_commitment(res.port_id, res.channel_id, res.seq, res.commitment)?; - } - PacketResult::Recv(res) => match res { - RecvPacketResult::Ordered { - port_id, - channel_id, - next_seq_recv, - } => self.store_next_sequence_recv(port_id, channel_id, next_seq_recv)?, - RecvPacketResult::Unordered { - port_id, - channel_id, - sequence, - receipt, - } => self.store_packet_receipt(port_id, channel_id, sequence, receipt)?, - RecvPacketResult::NoOp => unreachable!(), - }, - PacketResult::WriteAck(res) => { - self.store_packet_acknowledgement( - res.port_id, - res.channel_id, - res.seq, - res.ack_commitment, - )?; - } - PacketResult::Ack(res) => { - self.delete_packet_commitment(&res.port_id, &res.channel_id, res.seq)?; - if let Some(s) = res.seq_number { - //Ordered Channel - self.store_next_sequence_ack(res.port_id, res.channel_id, s)?; - } - } - PacketResult::Timeout(res) => { - self.delete_packet_commitment(&res.port_id, &res.channel_id, res.seq)?; - if let Some(c) = res.channel { - //Ordered Channel - self.store_channel(res.port_id, res.channel_id, c)?; - } - } - } - Ok(()) - } - - fn store_packet_commitment( - &mut self, - port_id: PortId, - channel_id: ChannelId, - sequence: Sequence, - commitment: PacketCommitment, - ) -> Result<(), Error>; - - fn delete_packet_commitment( - &mut self, - port_id: &PortId, - channel_id: &ChannelId, - seq: Sequence, - ) -> Result<(), Error>; - - fn store_packet_receipt( - &mut self, - port_id: PortId, - channel_id: ChannelId, - sequence: Sequence, - receipt: Receipt, - ) -> Result<(), Error>; - - fn store_packet_acknowledgement( - &mut self, - port_id: PortId, - channel_id: ChannelId, - sequence: Sequence, - ack_commitment: AcknowledgementCommitment, - ) -> Result<(), Error>; - - fn delete_packet_acknowledgement( - &mut self, - port_id: &PortId, - channel_id: &ChannelId, - sequence: Sequence, - ) -> Result<(), Error>; - - fn store_connection_channels( - &mut self, - conn_id: ConnectionId, - port_id: PortId, - channel_id: ChannelId, - ) -> Result<(), Error>; - - /// Stores the given channel_end at a path associated with the port_id and channel_id. - fn store_channel( - &mut self, - port_id: PortId, - channel_id: ChannelId, - channel_end: ChannelEnd, - ) -> Result<(), Error>; - - fn store_next_sequence_send( - &mut self, - port_id: PortId, - channel_id: ChannelId, - seq: Sequence, - ) -> Result<(), Error>; - - fn store_next_sequence_recv( - &mut self, - port_id: PortId, - channel_id: ChannelId, - seq: Sequence, - ) -> Result<(), Error>; - - fn store_next_sequence_ack( - &mut self, - port_id: PortId, - channel_id: ChannelId, - seq: Sequence, - ) -> Result<(), Error>; - - /// Called upon channel identifier creation (Init or Try message processing). - /// Increases the counter which keeps track of how many channels have been created. - /// Should never fail. - fn increase_channel_counter(&mut self); -} - -pub fn calculate_block_delay( - delay_period_time: Duration, - max_expected_time_per_block: Duration, -) -> u64 { - if max_expected_time_per_block.is_zero() { - return 0; - } - - FloatCore::ceil(delay_period_time.as_secs_f64() / max_expected_time_per_block.as_secs_f64()) - as u64 -} diff --git a/modules/src/core/ics04_channel/error.rs b/modules/src/core/ics04_channel/error.rs deleted file mode 100644 index 18dd3dc90f..0000000000 --- a/modules/src/core/ics04_channel/error.rs +++ /dev/null @@ -1,359 +0,0 @@ -use super::packet::Sequence; -use super::timeout::TimeoutHeight; -use crate::core::ics02_client::error as client_error; -use crate::core::ics03_connection::error as connection_error; -use crate::core::ics04_channel::channel::State; -use crate::core::ics05_port::error as port_error; -use crate::core::ics24_host::error::ValidationError; -use crate::core::ics24_host::identifier::{ChannelId, ClientId, ConnectionId, PortId}; -use crate::prelude::*; -use crate::proofs::ProofError; -use crate::signer::SignerError; -use crate::timestamp::Timestamp; -use crate::Height; - -use flex_error::{define_error, TraceError}; -use ibc_proto::protobuf::Error as TendermintError; - -define_error! { - #[derive(Debug, PartialEq, Eq)] - Error { - Ics03Connection - [ connection_error::Error ] - | _ | { "ics03 connection error" }, - - Ics05Port - [ port_error::Error ] - | _ | { "ics05 port error" }, - - UnknownState - { state: i32 } - | e | { format_args!("channel state unknown: {}", e.state) }, - - Identifier - [ ValidationError ] - | _ | { "identifier error" }, - - UnknownOrderType - { type_id: String } - | e | { format_args!("channel order type unknown: {}", e.type_id) }, - - InvalidConnectionHopsLength - { expected: usize, actual: usize } - | e | { - format_args!( - "invalid connection hops length: expected {0}; actual {1}", - e.expected, e.actual) - }, - - InvalidPacketCounterparty - { port_id: PortId, channel_id: ChannelId } - | e | { - format_args!( - "packet destination port {} and channel {} doesn't match the counterparty's port/channel", - e.port_id, e.channel_id) - }, - - InvalidVersion - [ TraceError ] - | _ | { "invalid version" }, - - Signer - [ SignerError ] - | _ | { "invalid signer address" }, - - InvalidProof - [ ProofError ] - | _ | { "invalid proof" }, - - MissingHeight - | _ | { "invalid proof: missing height" }, - - MissingNextRecvSeq - { port_id: PortId, channel_id: ChannelId } - | e | { - format_args!("Missing sequence number for receiving packets on port {0} and channel {1}", - e.port_id, - e.channel_id) - }, - - ZeroPacketSequence - | _ | { "packet sequence cannot be 0" }, - - ZeroPacketData - | _ | { "packet data bytes cannot be empty" }, - - InvalidTimeoutHeight - | _ | { "invalid timeout height for the packet" }, - - InvalidPacket - | _ | { "invalid packet" }, - - MissingPacket - | _ | { "there is no packet in this message" }, - - MissingChannelId - | _ | { "missing channel id" }, - - MissingCounterparty - | _ | { "missing counterparty" }, - - NoCommonVersion - | _ | { "no commong version" }, - - MissingChannel - | _ | { "missing channel end" }, - - InvalidVersionLengthConnection - | _ | { "single version must be negociated on connection before opening channel" }, - - ChannelFeatureNotSuportedByConnection - | _ | { "the channel ordering is not supported by connection" }, - - ChannelNotFound - { port_id: PortId, channel_id: ChannelId } - | e | { - format_args!( - "the channel end ({0}, {1}) does not exist", - e.port_id, e.channel_id) - }, - - ChannelMismatch - { channel_id: ChannelId } - | e | { - format_args!( - "a different channel exists (was initialized) already for the same channel identifier {0}", - e.channel_id) - }, - - ConnectionNotOpen - { connection_id: ConnectionId } - | e | { - format_args!( - "the associated connection {0} is not OPEN", - e.connection_id) - }, - - UndefinedConnectionCounterparty - { connection_id: ConnectionId } - | e | { - format_args!( - "Undefined counterparty connection for {0}", - e.connection_id) - }, - - PacketVerificationFailed - { sequence: Sequence } - [ client_error::Error ] - | e | { - format_args!( - "Verification fails for the packet with the sequence number {0}", - e.sequence) - }, - - VerifyChannelFailed - [ client_error::Error ] - | _ | { - "Error verifying channel state" - }, - - InvalidAcknowledgement - | _ | { "Acknowledgment cannot be empty" }, - - AcknowledgementExists - { sequence: Sequence } - | e | { - format_args!( - "Packet acknowledgement exists for the packet with the sequence {0}", - e.sequence) - }, - - MissingNextSendSeq - { port_id: PortId, channel_id: ChannelId } - | e | { - format_args!("Missing sequence number for sending packets on port {0} and channel {1}", - e.port_id, - e.channel_id) - }, - - InvalidStringAsSequence - { value: String } - [ TraceError ] - | e | { - format_args!( - "String {0} cannot be converted to packet sequence", - e.value) - }, - - InvalidPacketSequence - { - given_sequence: Sequence, - next_sequence: Sequence - } - | e | { - format_args!( - "Invalid packet sequence {0} ≠ next send sequence {1}", - e.given_sequence, e.next_sequence) - }, - - LowPacketHeight - { - chain_height: Height, - timeout_height: TimeoutHeight - } - | e | { - format_args!( - "Receiving chain block height {0} >= packet timeout height {1}", - e.chain_height, e.timeout_height) - }, - - PacketTimeoutHeightNotReached - { - timeout_height: TimeoutHeight, - chain_height: Height, - } - | e | { - format_args!( - "Packet timeout height {0} > chain height {1}", - e.timeout_height, e.chain_height) - }, - - PacketTimeoutTimestampNotReached - { - timeout_timestamp: Timestamp, - chain_timestamp: Timestamp, - } - | e | { - format_args!( - "Packet timeout timestamp {0} > chain timestamp {1}", - e.timeout_timestamp, e.chain_timestamp) - }, - - LowPacketTimestamp - | _ | { "Receiving chain block timestamp >= packet timeout timestamp" }, - - InvalidPacketTimestamp - [ crate::timestamp::ParseTimestampError ] - | _ | { "Invalid packet timeout timestamp value" }, - - ErrorInvalidConsensusState - | _ | { "Invalid timestamp in consensus state; timestamp must be a positive value" }, - - FrozenClient - { client_id: ClientId } - | e | { - format_args!( - "Client with id {0} is frozen", - e.client_id) - }, - - InvalidCounterpartyChannelId - [ ValidationError ] - | _ | { "Invalid channel id in counterparty" }, - - InvalidChannelState - { channel_id: ChannelId, state: State } - | e | { - format_args!( - "Channel {0} should not be state {1}", - e.channel_id, e.state) - }, - - ChannelClosed - { channel_id: ChannelId } - | e | { - format_args!( - "Channel {0} is Closed", - e.channel_id) - }, - - ChanOpenAckProofVerification - | _ | { "Handshake proof verification fails at ChannelOpenAck" }, - - PacketCommitmentNotFound - { sequence: Sequence } - | e | { - format_args!( - "Commitment for the packet {0} not found", - e.sequence) - }, - - IncorrectPacketCommitment - { sequence: Sequence } - | e | { - format_args!( - "The stored commitment of the packet {0} is incorrect", - e.sequence) - }, - - PacketReceiptNotFound - { sequence: Sequence } - | e | { - format_args!( - "Receipt for the packet {0} not found", - e.sequence) - }, - - PacketAcknowledgementNotFound - { sequence: Sequence } - | e | { - format_args!( - "Acknowledgment for the packet {0} not found", - e.sequence) - }, - - MissingNextAckSeq - { port_id: PortId, channel_id: ChannelId } - | e | { - format_args!("Missing sequence number for ack packets on port {0} and channel {1}", - e.port_id, - e.channel_id) - }, - - ProcessedTimeNotFound - { - client_id: ClientId, - height: Height, - } - | e | { - format_args!( - "Processed time for the client {0} at height {1} not found", - e.client_id, e.height) - }, - - ProcessedHeightNotFound - { - client_id: ClientId, - height: Height, - } - | e | { - format_args!( - "Processed height for the client {0} at height {1} not found", - e.client_id, e.height) - }, - - RouteNotFound - | _ | { "route not found" }, - - ImplementationSpecific - | _ | { "implementation specific error" }, - - AppModule - { description: String } - | e | { - format_args!( - "application module error: {0}", - e.description) - }, - - AbciConversionFailed - { abci_event: String } - | e | { format_args!("Failed to convert abci event to IbcEvent: {}", e.abci_event)} - } -} - -impl Error { - pub fn chan_open_confirm_proof_verification(e: Error) -> Error { - e.add_trace(&"Handshake proof verification fails at ChannelOpenConfirm") - } -} diff --git a/modules/src/core/ics04_channel/events.rs b/modules/src/core/ics04_channel/events.rs deleted file mode 100644 index b6eb47877f..0000000000 --- a/modules/src/core/ics04_channel/events.rs +++ /dev/null @@ -1,835 +0,0 @@ -//! Types for the IBC events emitted from Tendermint Websocket by the channels module. - -use core::fmt::{Display, Error as FmtError, Formatter}; -use serde_derive::{Deserialize, Serialize}; -use tendermint::abci::tag::Tag; -use tendermint::abci::Event as AbciEvent; - -use crate::core::ics04_channel::error::Error; -use crate::core::ics04_channel::packet::Packet; -use crate::core::ics24_host::identifier::{ChannelId, ConnectionId, PortId}; -use crate::events::{Error as EventError, IbcEvent, IbcEventType}; -use crate::prelude::*; -use crate::utils::pretty::PrettyVec; - -/// Channel event attribute keys -pub const CONNECTION_ID_ATTRIBUTE_KEY: &str = "connection_id"; -pub const CHANNEL_ID_ATTRIBUTE_KEY: &str = "channel_id"; -pub const PORT_ID_ATTRIBUTE_KEY: &str = "port_id"; -pub const COUNTERPARTY_CHANNEL_ID_ATTRIBUTE_KEY: &str = "counterparty_channel_id"; -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_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"; - -#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)] -pub struct Attributes { - pub port_id: PortId, - pub channel_id: Option, - pub connection_id: ConnectionId, - pub counterparty_port_id: PortId, - pub counterparty_channel_id: Option, -} - -impl Attributes { - pub fn port_id(&self) -> &PortId { - &self.port_id - } - pub fn channel_id(&self) -> Option<&ChannelId> { - self.channel_id.as_ref() - } -} - -impl Display for Attributes { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - match (&self.channel_id, &self.counterparty_channel_id) { - (Some(channel_id), Some(counterparty_channel_id)) => write!(f, "Attributes {{ port_id: {}, channel_id: {}, connection_id: {}, counterparty_port_id: {}, counterparty_channel_id: {} }}", self.port_id, channel_id, self.connection_id, self.counterparty_port_id, counterparty_channel_id), - (Some(channel_id), None) => write!(f, "Attributes {{ port_id: {}, channel_id: {}, connection_id: None, counterparty_port_id: {}, counterparty_channel_id: None }}", self.port_id, channel_id, self.counterparty_port_id), - (None, Some(counterparty_channel_id)) => write!(f, "Attributes {{ port_id: {}, channel_id: None, connection_id: {}, counterparty_port_id: {}, counterparty_channel_id: {} }}", self.port_id, self.connection_id, self.counterparty_port_id, counterparty_channel_id), - (None, None) => write!(f, "Attributes {{ port_id: {}, client_id: None, connection_id: {}, counterparty_port_id: {}, counterparty_channel_id: None }}", self.port_id, self.connection_id, self.counterparty_port_id), - } - } -} - -/// Convert attributes to Tendermint ABCI tags -/// -/// # Note -/// The parsing of `Key`s and `Value`s never fails, because the -/// `FromStr` instance of `tendermint::abci::tag::{Key, Value}` -/// is infallible, even if it is not represented in the error type. -/// Once tendermint-rs improves the API of the `Key` and `Value` types, -/// we will be able to remove the `.parse().unwrap()` calls. -impl From for Vec { - fn from(a: Attributes) -> Self { - let mut attributes = vec![]; - let port_id = Tag { - key: PORT_ID_ATTRIBUTE_KEY.parse().unwrap(), - value: a.port_id.to_string().parse().unwrap(), - }; - attributes.push(port_id); - if let Some(channel_id) = a.channel_id { - let channel_id = Tag { - key: CHANNEL_ID_ATTRIBUTE_KEY.parse().unwrap(), - value: channel_id.to_string().parse().unwrap(), - }; - attributes.push(channel_id); - } - let connection_id = Tag { - key: CONNECTION_ID_ATTRIBUTE_KEY.parse().unwrap(), - value: a.connection_id.to_string().parse().unwrap(), - }; - attributes.push(connection_id); - let counterparty_port_id = Tag { - key: COUNTERPARTY_PORT_ID_ATTRIBUTE_KEY.parse().unwrap(), - value: a.counterparty_port_id.to_string().parse().unwrap(), - }; - attributes.push(counterparty_port_id); - if let Some(channel_id) = a.counterparty_channel_id { - let channel_id = Tag { - key: COUNTERPARTY_CHANNEL_ID_ATTRIBUTE_KEY.parse().unwrap(), - value: channel_id.to_string().parse().unwrap(), - }; - attributes.push(channel_id); - } - attributes - } -} - -/// Convert attributes to Tendermint ABCI tags -/// -/// # Note -/// The parsing of `Key`s and `Value`s never fails, because the -/// `FromStr` instance of `tendermint::abci::tag::{Key, Value}` -/// is infallible, even if it is not represented in the error type. -/// Once tendermint-rs improves the API of the `Key` and `Value` types, -/// we will be able to remove the `.parse().unwrap()` calls. -impl TryFrom for Vec { - type Error = Error; - fn try_from(p: Packet) -> Result { - let mut attributes = vec![]; - let src_port = Tag { - key: PKT_SRC_PORT_ATTRIBUTE_KEY.parse().unwrap(), - value: p.source_port.to_string().parse().unwrap(), - }; - attributes.push(src_port); - let src_channel = Tag { - key: PKT_SRC_CHANNEL_ATTRIBUTE_KEY.parse().unwrap(), - value: p.source_channel.to_string().parse().unwrap(), - }; - attributes.push(src_channel); - let dst_port = Tag { - key: PKT_DST_PORT_ATTRIBUTE_KEY.parse().unwrap(), - value: p.destination_port.to_string().parse().unwrap(), - }; - attributes.push(dst_port); - let dst_channel = Tag { - key: PKT_DST_CHANNEL_ATTRIBUTE_KEY.parse().unwrap(), - value: p.destination_channel.to_string().parse().unwrap(), - }; - attributes.push(dst_channel); - let sequence = Tag { - key: PKT_SEQ_ATTRIBUTE_KEY.parse().unwrap(), - value: p.sequence.to_string().parse().unwrap(), - }; - attributes.push(sequence); - let timeout_height = Tag { - key: PKT_TIMEOUT_HEIGHT_ATTRIBUTE_KEY.parse().unwrap(), - value: p.timeout_height.into(), - }; - attributes.push(timeout_height); - let timeout_timestamp = Tag { - key: PKT_TIMEOUT_TIMESTAMP_ATTRIBUTE_KEY.parse().unwrap(), - value: p - .timeout_timestamp - .nanoseconds() - .to_string() - .parse() - .unwrap(), - }; - attributes.push(timeout_timestamp); - let val = - String::from_utf8(p.data).expect("hex-encoded string should always be valid UTF-8"); - let packet_data = Tag { - key: PKT_DATA_ATTRIBUTE_KEY.parse().unwrap(), - value: val.parse().unwrap(), - }; - attributes.push(packet_data); - let ack = Tag { - key: PKT_ACK_ATTRIBUTE_KEY.parse().unwrap(), - value: "".parse().unwrap(), - }; - attributes.push(ack); - Ok(attributes) - } -} - -pub trait EventType { - fn event_type() -> IbcEventType; -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize)] -pub struct OpenInit { - pub port_id: PortId, - pub channel_id: Option, - pub connection_id: ConnectionId, - pub counterparty_port_id: PortId, - pub counterparty_channel_id: Option, -} - -impl OpenInit { - pub fn channel_id(&self) -> Option<&ChannelId> { - self.channel_id.as_ref() - } - pub fn port_id(&self) -> &PortId { - &self.port_id - } -} - -impl Display for OpenInit { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - match (&self.channel_id, &self.counterparty_channel_id) { - (Some(channel_id), Some(counterparty_channel_id)) => write!(f, "OpenInit {{ port_id: {}, channel_id: {}, connection_id: {}, counterparty_port_id: {}, counterparty_channel_id: {} }}", self.port_id, channel_id, self.connection_id, self.counterparty_port_id, counterparty_channel_id), - (Some(channel_id), None) => write!(f, "OpenInit {{ port_id: {}, channel_id: {}, connection_id: None, counterparty_port_id: {}, counterparty_channel_id: None }}", self.port_id, channel_id, self.counterparty_port_id), - (None, Some(counterparty_channel_id)) => write!(f, "OpenInit {{ port_id: {}, channel_id: None, connection_id: {}, counterparty_port_id: {}, counterparty_channel_id: {} }}", self.port_id, self.connection_id, self.counterparty_port_id, counterparty_channel_id), - (None, None) => write!(f, "OpenInit {{ port_id: {}, client_id: None, connection_id: {}, counterparty_port_id: {}, counterparty_channel_id: None }}", self.port_id, self.connection_id, self.counterparty_port_id), - } - } -} - -impl From for Attributes { - fn from(ev: OpenInit) -> Self { - Self { - port_id: ev.port_id, - channel_id: ev.channel_id, - connection_id: ev.connection_id, - counterparty_port_id: ev.counterparty_port_id, - counterparty_channel_id: ev.counterparty_channel_id, - } - } -} - -impl From for IbcEvent { - fn from(v: OpenInit) -> Self { - IbcEvent::OpenInitChannel(v) - } -} - -impl EventType for OpenInit { - fn event_type() -> IbcEventType { - IbcEventType::OpenInitChannel - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize)] -pub struct OpenTry { - pub port_id: PortId, - pub channel_id: Option, - pub connection_id: ConnectionId, - pub counterparty_port_id: PortId, - pub counterparty_channel_id: Option, -} - -impl Display for OpenTry { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - match (&self.channel_id, &self.counterparty_channel_id) { - (Some(channel_id), Some(counterparty_channel_id)) => write!(f, "OpenTry {{ port_id: {}, channel_id: {}, connection_id: {}, counterparty_port_id: {}, counterparty_channel_id: {} }}", self.port_id, channel_id, self.connection_id, self.counterparty_port_id, counterparty_channel_id), - (Some(channel_id), None) => write!(f, "OpenTry {{ port_id: {}, channel_id: {}, connection_id: None, counterparty_port_id: {}, counterparty_channel_id: None }}", self.port_id, channel_id, self.counterparty_port_id), - (None, Some(counterparty_channel_id)) => write!(f, "OpenTry {{ port_id: {}, channel_id: None, connection_id: {}, counterparty_port_id: {}, counterparty_channel_id: {} }}", self.port_id, self.connection_id, self.counterparty_port_id, counterparty_channel_id), - (None, None) => write!(f, "OpenTry {{ port_id: {}, client_id: None, connection_id: {}, counterparty_port_id: {}, counterparty_channel_id: None }}", self.port_id, self.connection_id, self.counterparty_port_id), - } - } -} - -impl From for Attributes { - fn from(ev: OpenTry) -> Self { - Self { - port_id: ev.port_id, - channel_id: ev.channel_id, - connection_id: ev.connection_id, - counterparty_port_id: ev.counterparty_port_id, - counterparty_channel_id: ev.counterparty_channel_id, - } - } -} -impl OpenTry { - pub fn channel_id(&self) -> Option<&ChannelId> { - self.channel_id.as_ref() - } - pub fn port_id(&self) -> &PortId { - &self.port_id - } -} - -impl From for IbcEvent { - fn from(v: OpenTry) -> Self { - IbcEvent::OpenTryChannel(v) - } -} - -impl EventType for OpenTry { - fn event_type() -> IbcEventType { - IbcEventType::OpenTryChannel - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize)] -pub struct OpenAck { - pub port_id: PortId, - pub channel_id: Option, - pub counterparty_channel_id: Option, - pub connection_id: ConnectionId, - pub counterparty_port_id: PortId, -} - -impl Display for OpenAck { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - match (&self.channel_id, &self.counterparty_channel_id) { - (Some(channel_id), Some(counterparty_channel_id)) => write!(f, "OpenAck {{ port_id: {}, channel_id: {}, connection_id: {}, counterparty_port_id: {}, counterparty_channel_id: {} }}", self.port_id, channel_id, self.connection_id, self.counterparty_port_id, counterparty_channel_id), - (Some(channel_id), None) => write!(f, "OpenAck {{ port_id: {}, channel_id: {}, connection_id: None, counterparty_port_id: {}, counterparty_channel_id: None }}", self.port_id, channel_id, self.counterparty_port_id), - (None, Some(counterparty_channel_id)) => write!(f, "OpenAck {{ port_id: {}, channel_id: None, connection_id: {}, counterparty_port_id: {}, counterparty_channel_id: {} }}", self.port_id, self.connection_id, self.counterparty_port_id, counterparty_channel_id), - (None, None) => write!(f, "OpenAck {{ port_id: {}, client_id: None, connection_id: {}, counterparty_port_id: {}, counterparty_channel_id: None }}", self.port_id, self.connection_id, self.counterparty_port_id), - } - } -} - -impl From for Attributes { - fn from(ev: OpenAck) -> Self { - Self { - port_id: ev.port_id, - channel_id: ev.channel_id, - connection_id: ev.connection_id, - counterparty_port_id: ev.counterparty_port_id, - counterparty_channel_id: ev.counterparty_channel_id, - } - } -} - -impl OpenAck { - pub fn channel_id(&self) -> Option<&ChannelId> { - self.channel_id.as_ref() - } - pub fn port_id(&self) -> &PortId { - &self.port_id - } - - pub fn counterparty_channel_id(&self) -> Option<&ChannelId> { - self.counterparty_channel_id.as_ref() - } -} - -impl From for IbcEvent { - fn from(v: OpenAck) -> Self { - IbcEvent::OpenAckChannel(v) - } -} - -impl EventType for OpenAck { - fn event_type() -> IbcEventType { - IbcEventType::OpenAckChannel - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize)] -pub struct OpenConfirm { - pub port_id: PortId, - pub channel_id: Option, - pub connection_id: ConnectionId, - pub counterparty_port_id: PortId, - pub counterparty_channel_id: Option, -} - -impl Display for OpenConfirm { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - match (&self.channel_id, &self.counterparty_channel_id) { - (Some(channel_id), Some(counterparty_channel_id)) => write!(f, "OpenConfirm {{ port_id: {}, channel_id: {}, connection_id: {}, counterparty_port_id: {}, counterparty_channel_id: {} }}", self.port_id, channel_id, self.connection_id, self.counterparty_port_id, counterparty_channel_id), - (Some(channel_id), None) => write!(f, "OpenConfirm {{ port_id: {}, channel_id: {}, connection_id: None, counterparty_port_id: {}, counterparty_channel_id: None }}", self.port_id, channel_id, self.counterparty_port_id), - (None, Some(counterparty_channel_id)) => write!(f, "OpenConfirm {{ port_id: {}, channel_id: None, connection_id: {}, counterparty_port_id: {}, counterparty_channel_id: {} }}", self.port_id, self.connection_id, self.counterparty_port_id, counterparty_channel_id), - (None, None) => write!(f, "OpenConfirm {{ port_id: {}, client_id: None, connection_id: {}, counterparty_port_id: {}, counterparty_channel_id: None }}", self.port_id, self.connection_id, self.counterparty_port_id), - } - } -} - -impl From for Attributes { - fn from(ev: OpenConfirm) -> Self { - Self { - port_id: ev.port_id, - channel_id: ev.channel_id, - connection_id: ev.connection_id, - counterparty_port_id: ev.counterparty_port_id, - counterparty_channel_id: ev.counterparty_channel_id, - } - } -} - -impl OpenConfirm { - pub fn channel_id(&self) -> Option<&ChannelId> { - self.channel_id.as_ref() - } - pub fn port_id(&self) -> &PortId { - &self.port_id - } -} - -impl From for IbcEvent { - fn from(v: OpenConfirm) -> Self { - IbcEvent::OpenConfirmChannel(v) - } -} - -impl EventType for OpenConfirm { - fn event_type() -> IbcEventType { - IbcEventType::OpenConfirmChannel - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize)] -pub struct CloseInit { - pub port_id: PortId, - pub channel_id: ChannelId, - pub connection_id: ConnectionId, - pub counterparty_port_id: PortId, - pub counterparty_channel_id: Option, -} - -impl Display for CloseInit { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - match &self.counterparty_channel_id { - Some(counterparty_channel_id) => write!(f, "CloseInit {{ port_id: {}, channel_id: {}, connection_id: {}, counterparty_port_id: {}, counterparty_channel_id: {} }}", self.port_id, self.channel_id, self.connection_id, self.counterparty_port_id, counterparty_channel_id), - None => write!(f, "CloseInit {{ port_id: {}, client_id: None, connection_id: {}, counterparty_port_id: {}, counterparty_channel_id: None }}", self.port_id, self.connection_id, self.counterparty_port_id), - } - } -} - -impl From for Attributes { - fn from(ev: CloseInit) -> Self { - Self { - port_id: ev.port_id, - channel_id: Some(ev.channel_id), - connection_id: ev.connection_id, - counterparty_port_id: ev.counterparty_port_id, - counterparty_channel_id: ev.counterparty_channel_id, - } - } -} - -impl CloseInit { - pub fn port_id(&self) -> &PortId { - &self.port_id - } - - pub fn channel_id(&self) -> &ChannelId { - &self.channel_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 CloseInit { - type Error = EventError; - fn try_from(attrs: Attributes) -> Result { - if let Some(channel_id) = attrs.channel_id() { - Ok(CloseInit { - port_id: attrs.port_id.clone(), - channel_id: channel_id.clone(), - connection_id: attrs.connection_id.clone(), - counterparty_port_id: attrs.counterparty_port_id.clone(), - counterparty_channel_id: attrs.counterparty_channel_id, - }) - } else { - Err(EventError::channel(Error::missing_channel_id())) - } - } -} - -impl From for IbcEvent { - fn from(v: CloseInit) -> Self { - IbcEvent::CloseInitChannel(v) - } -} - -impl EventType for CloseInit { - fn event_type() -> IbcEventType { - IbcEventType::CloseInitChannel - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize)] -pub struct CloseConfirm { - pub channel_id: Option, - pub port_id: PortId, - pub connection_id: ConnectionId, - pub counterparty_port_id: PortId, - pub counterparty_channel_id: Option, -} - -impl Display for CloseConfirm { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - match (&self.channel_id, &self.counterparty_channel_id) { - (Some(channel_id), Some(counterparty_channel_id)) => write!(f, "CloseConfirm {{ port_id: {}, channel_id: {}, connection_id: {}, counterparty_port_id: {}, counterparty_channel_id: {} }}", self.port_id, channel_id, self.connection_id, self.counterparty_port_id, counterparty_channel_id), - (Some(channel_id), None) => write!(f, "CloseConfirm {{ port_id: {}, channel_id: {}, connection_id: None, counterparty_port_id: {}, counterparty_channel_id: None }}", self.port_id, channel_id, self.counterparty_port_id), - (None, Some(counterparty_channel_id)) => write!(f, "CloseConfirm {{ port_id: {}, channel_id: None, connection_id: {}, counterparty_port_id: {}, counterparty_channel_id: {} }}", self.port_id, self.connection_id, self.counterparty_port_id, counterparty_channel_id), - (None, None) => write!(f, "CloseConfirm {{ port_id: {}, client_id: None, connection_id: {}, counterparty_port_id: {}, counterparty_channel_id: None }}", self.port_id, self.connection_id, self.counterparty_port_id), - } - } -} - -impl From for Attributes { - fn from(ev: CloseConfirm) -> Self { - Self { - port_id: ev.port_id, - channel_id: ev.channel_id, - connection_id: ev.connection_id, - counterparty_port_id: ev.counterparty_port_id, - counterparty_channel_id: ev.counterparty_channel_id, - } - } -} - -impl CloseConfirm { - pub fn channel_id(&self) -> Option<&ChannelId> { - self.channel_id.as_ref() - } -} - -impl From for IbcEvent { - fn from(v: CloseConfirm) -> Self { - IbcEvent::CloseConfirmChannel(v) - } -} - -impl EventType for CloseConfirm { - fn event_type() -> IbcEventType { - IbcEventType::CloseConfirmChannel - } -} - -macro_rules! impl_try_from_attribute_for_event { - ($($event:ty),+) => { - $(impl TryFrom for $event { - type Error = EventError; - - fn try_from(attrs: Attributes) -> Result { - Ok(Self { - port_id: attrs.port_id, - channel_id: attrs.channel_id, - connection_id: attrs.connection_id, - counterparty_port_id: attrs.counterparty_port_id, - counterparty_channel_id: attrs.counterparty_channel_id, - }) - } - })+ - }; -} - -impl_try_from_attribute_for_event!(OpenInit, OpenTry, OpenAck, OpenConfirm, CloseConfirm); - -macro_rules! impl_from_ibc_to_abci_event { - ($($event:ty),+) => { - $(impl From<$event> for AbciEvent { - fn from(v: $event) -> Self { - let attributes = Vec::::from(Attributes::from(v)); - let type_str = <$event>::event_type().as_str().to_string(); - AbciEvent { - type_str, - attributes, - } - } - })+ - }; -} - -impl_from_ibc_to_abci_event!( - OpenInit, - OpenTry, - OpenAck, - OpenConfirm, - CloseInit, - CloseConfirm -); - -#[derive(Clone, Debug, PartialEq, Eq, Serialize)] -pub struct SendPacket { - pub packet: Packet, -} - -impl SendPacket { - pub fn src_port_id(&self) -> &PortId { - &self.packet.source_port - } - pub fn src_channel_id(&self) -> &ChannelId { - &self.packet.source_channel - } - pub fn dst_port_id(&self) -> &PortId { - &self.packet.destination_port - } - pub fn dst_channel_id(&self) -> &ChannelId { - &self.packet.destination_channel - } -} - -impl Display for SendPacket { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "SendPacket {{ packet: {} }}", self.packet) - } -} - -impl From for IbcEvent { - fn from(v: SendPacket) -> Self { - IbcEvent::SendPacket(v) - } -} - -impl TryFrom for AbciEvent { - type Error = Error; - - fn try_from(v: SendPacket) -> Result { - let attributes = Vec::::try_from(v.packet)?; - Ok(AbciEvent { - type_str: IbcEventType::SendPacket.as_str().to_string(), - attributes, - }) - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize)] -pub struct ReceivePacket { - pub packet: Packet, -} - -impl ReceivePacket { - pub fn src_port_id(&self) -> &PortId { - &self.packet.source_port - } - pub fn src_channel_id(&self) -> &ChannelId { - &self.packet.source_channel - } - pub fn dst_port_id(&self) -> &PortId { - &self.packet.destination_port - } - pub fn dst_channel_id(&self) -> &ChannelId { - &self.packet.destination_channel - } -} - -impl Display for ReceivePacket { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "ReceivePacket {{ packet: {} }}", self.packet) - } -} - -impl From for IbcEvent { - fn from(v: ReceivePacket) -> Self { - IbcEvent::ReceivePacket(v) - } -} - -impl TryFrom for AbciEvent { - type Error = Error; - - fn try_from(v: ReceivePacket) -> Result { - let attributes = Vec::::try_from(v.packet)?; - Ok(AbciEvent { - type_str: IbcEventType::ReceivePacket.as_str().to_string(), - attributes, - }) - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize)] -pub struct WriteAcknowledgement { - pub packet: Packet, - #[serde(serialize_with = "crate::serializers::ser_hex_upper")] - pub ack: Vec, -} - -impl WriteAcknowledgement { - pub fn src_port_id(&self) -> &PortId { - &self.packet.source_port - } - pub fn src_channel_id(&self) -> &ChannelId { - &self.packet.source_channel - } - pub fn dst_port_id(&self) -> &PortId { - &self.packet.destination_port - } - pub fn dst_channel_id(&self) -> &ChannelId { - &self.packet.destination_channel - } -} - -impl Display for WriteAcknowledgement { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!( - f, - "WriteAcknowledgement {{ packet: {}, ack: {} }}", - self.packet, - PrettyVec(&self.ack) - ) - } -} - -impl From for IbcEvent { - fn from(v: WriteAcknowledgement) -> Self { - IbcEvent::WriteAcknowledgement(v) - } -} - -impl TryFrom for AbciEvent { - type Error = Error; - - fn try_from(v: WriteAcknowledgement) -> Result { - let mut attributes = Vec::::try_from(v.packet)?; - let val = - String::from_utf8(v.ack).expect("hex-encoded string should always be valid UTF-8"); - // No actual conversion from string to `Tag::Key` or `Tag::Value` - let ack = Tag { - key: PKT_ACK_ATTRIBUTE_KEY.parse().unwrap(), - value: val.parse().unwrap(), - }; - attributes.push(ack); - Ok(AbciEvent { - type_str: IbcEventType::WriteAck.as_str().to_string(), - attributes, - }) - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize)] -pub struct AcknowledgePacket { - pub packet: Packet, -} - -impl AcknowledgePacket { - pub fn src_port_id(&self) -> &PortId { - &self.packet.source_port - } - pub fn src_channel_id(&self) -> &ChannelId { - &self.packet.source_channel - } -} - -impl Display for AcknowledgePacket { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "AcknowledgePacket {{ packet: {}}}", self.packet) - } -} - -impl From for IbcEvent { - fn from(v: AcknowledgePacket) -> Self { - IbcEvent::AcknowledgePacket(v) - } -} - -impl TryFrom for AbciEvent { - type Error = Error; - - fn try_from(v: AcknowledgePacket) -> Result { - let attributes = Vec::::try_from(v.packet)?; - Ok(AbciEvent { - type_str: IbcEventType::AckPacket.as_str().to_string(), - attributes, - }) - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize)] -pub struct TimeoutPacket { - pub packet: Packet, -} - -impl TimeoutPacket { - pub fn src_port_id(&self) -> &PortId { - &self.packet.source_port - } - pub fn src_channel_id(&self) -> &ChannelId { - &self.packet.source_channel - } - pub fn dst_port_id(&self) -> &PortId { - &self.packet.destination_port - } - pub fn dst_channel_id(&self) -> &ChannelId { - &self.packet.destination_channel - } -} - -impl Display for TimeoutPacket { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "TimeoutPacket {{ packet: {}}}", self.packet) - } -} - -impl From for IbcEvent { - fn from(v: TimeoutPacket) -> Self { - IbcEvent::TimeoutPacket(v) - } -} - -impl TryFrom for AbciEvent { - type Error = Error; - - fn try_from(v: TimeoutPacket) -> Result { - let attributes = Vec::::try_from(v.packet)?; - Ok(AbciEvent { - type_str: IbcEventType::Timeout.as_str().to_string(), - attributes, - }) - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize)] -pub struct TimeoutOnClosePacket { - pub packet: Packet, -} - -impl TimeoutOnClosePacket { - pub fn src_port_id(&self) -> &PortId { - &self.packet.source_port - } - pub fn src_channel_id(&self) -> &ChannelId { - &self.packet.source_channel - } - pub fn dst_port_id(&self) -> &PortId { - &self.packet.destination_port - } - pub fn dst_channel_id(&self) -> &ChannelId { - &self.packet.destination_channel - } -} - -impl Display for TimeoutOnClosePacket { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "TimeoutOnClosePacket {{ packet: {}}}", self.packet) - } -} - -impl From for IbcEvent { - fn from(v: TimeoutOnClosePacket) -> Self { - IbcEvent::TimeoutOnClosePacket(v) - } -} - -impl TryFrom for AbciEvent { - type Error = Error; - - fn try_from(v: TimeoutOnClosePacket) -> Result { - let attributes = Vec::::try_from(v.packet)?; - Ok(AbciEvent { - type_str: IbcEventType::TimeoutOnClose.as_str().to_string(), - attributes, - }) - } -} diff --git a/modules/src/core/ics04_channel/handler.rs b/modules/src/core/ics04_channel/handler.rs deleted file mode 100644 index ff90a6f557..0000000000 --- a/modules/src/core/ics04_channel/handler.rs +++ /dev/null @@ -1,277 +0,0 @@ -//! This module implements the processing logic for ICS4 (channel) messages. -use crate::prelude::*; - -use crate::core::ics04_channel::channel::ChannelEnd; -use crate::core::ics04_channel::context::ChannelReader; -use crate::core::ics04_channel::error::Error; -use crate::core::ics04_channel::msgs::ChannelMsg; -use crate::core::ics04_channel::packet::Packet; -use crate::core::ics04_channel::{msgs::PacketMsg, packet::PacketResult}; -use crate::core::ics24_host::identifier::{ChannelId, PortId}; -use crate::core::ics26_routing::context::{ - Acknowledgement, Ics26Context, ModuleId, ModuleOutputBuilder, OnRecvPacketAck, Router, -}; -use crate::handler::{HandlerOutput, HandlerOutputBuilder}; - -pub mod acknowledgement; -pub mod chan_close_confirm; -pub mod chan_close_init; -pub mod chan_open_ack; -pub mod chan_open_confirm; -pub mod chan_open_init; -pub mod chan_open_try; -pub mod recv_packet; -pub mod send_packet; -pub mod timeout; -pub mod timeout_on_close; -pub mod verify; -pub mod write_acknowledgement; - -/// Defines the possible states of a channel identifier in a `ChannelResult`. -#[derive(Clone, Debug)] -pub enum ChannelIdState { - /// Specifies that the channel handshake handler allocated a new channel identifier. This - /// happens during the processing of either the `MsgChannelOpenInit` or `MsgChannelOpenTry`. - Generated, - - /// Specifies that the handler reused a previously-allocated channel identifier. - Reused, -} - -#[derive(Clone, Debug)] -pub struct ChannelResult { - pub port_id: PortId, - pub channel_id: ChannelId, - pub channel_id_state: ChannelIdState, - pub channel_end: ChannelEnd, -} - -pub fn channel_validate(ctx: &Ctx, msg: &ChannelMsg) -> Result -where - Ctx: Ics26Context, -{ - let module_id = msg.lookup_module(ctx)?; - if ctx.router().has_route(&module_id) { - Ok(module_id) - } else { - Err(Error::route_not_found()) - } -} - -/// General entry point for processing any type of message related to the ICS4 channel open and -/// channel close handshake protocols. -pub fn channel_dispatch( - ctx: &Ctx, - msg: &ChannelMsg, -) -> Result<(HandlerOutputBuilder<()>, ChannelResult), Error> -where - Ctx: ChannelReader, -{ - let output = match msg { - ChannelMsg::ChannelOpenInit(msg) => chan_open_init::process(ctx, msg), - ChannelMsg::ChannelOpenTry(msg) => chan_open_try::process(ctx, msg), - ChannelMsg::ChannelOpenAck(msg) => chan_open_ack::process(ctx, msg), - ChannelMsg::ChannelOpenConfirm(msg) => chan_open_confirm::process(ctx, msg), - ChannelMsg::ChannelCloseInit(msg) => chan_close_init::process(ctx, msg), - ChannelMsg::ChannelCloseConfirm(msg) => chan_close_confirm::process(ctx, msg), - }?; - let HandlerOutput { - result, - log, - events, - } = output; - let builder = HandlerOutput::builder().with_log(log).with_events(events); - Ok((builder, result)) -} - -pub fn channel_callback( - ctx: &mut Ctx, - module_id: &ModuleId, - msg: &ChannelMsg, - mut result: ChannelResult, - module_output: &mut ModuleOutputBuilder, -) -> Result -where - Ctx: Ics26Context, -{ - let cb = ctx - .router_mut() - .get_route_mut(module_id) - .ok_or_else(Error::route_not_found)?; - - match msg { - ChannelMsg::ChannelOpenInit(msg) => cb.on_chan_open_init( - module_output, - msg.channel.ordering, - &msg.channel.connection_hops, - &msg.port_id, - &result.channel_id, - msg.channel.counterparty(), - &msg.channel.version, - )?, - ChannelMsg::ChannelOpenTry(msg) => { - let version = cb.on_chan_open_try( - module_output, - msg.channel.ordering, - &msg.channel.connection_hops, - &msg.port_id, - &result.channel_id, - msg.channel.counterparty(), - msg.channel.version(), - &msg.counterparty_version, - )?; - result.channel_end.version = version; - } - ChannelMsg::ChannelOpenAck(msg) => cb.on_chan_open_ack( - module_output, - &msg.port_id, - &result.channel_id, - &msg.counterparty_version, - )?, - ChannelMsg::ChannelOpenConfirm(msg) => { - cb.on_chan_open_confirm(module_output, &msg.port_id, &result.channel_id)? - } - ChannelMsg::ChannelCloseInit(msg) => { - cb.on_chan_close_init(module_output, &msg.port_id, &result.channel_id)? - } - ChannelMsg::ChannelCloseConfirm(msg) => { - cb.on_chan_close_confirm(module_output, &msg.port_id, &result.channel_id)? - } - } - Ok(result) -} - -pub fn get_module_for_packet_msg(ctx: &Ctx, msg: &PacketMsg) -> Result -where - Ctx: Ics26Context, -{ - let module_id = match msg { - PacketMsg::RecvPacket(msg) => ctx - .lookup_module_by_port(&msg.packet.destination_port) - .map_err(Error::ics05_port)?, - PacketMsg::AckPacket(msg) => ctx - .lookup_module_by_port(&msg.packet.source_port) - .map_err(Error::ics05_port)?, - PacketMsg::ToPacket(msg) => ctx - .lookup_module_by_port(&msg.packet.source_port) - .map_err(Error::ics05_port)?, - PacketMsg::ToClosePacket(msg) => ctx - .lookup_module_by_port(&msg.packet.source_port) - .map_err(Error::ics05_port)?, - }; - - if ctx.router().has_route(&module_id) { - Ok(module_id) - } else { - Err(Error::route_not_found()) - } -} - -/// Dispatcher for processing any type of message related to the ICS4 packet protocols. -pub fn packet_dispatch( - ctx: &Ctx, - msg: &PacketMsg, -) -> Result<(HandlerOutputBuilder<()>, PacketResult), Error> -where - Ctx: ChannelReader, -{ - let output = match msg { - PacketMsg::RecvPacket(msg) => recv_packet::process(ctx, msg), - PacketMsg::AckPacket(msg) => acknowledgement::process(ctx, msg), - PacketMsg::ToPacket(msg) => timeout::process(ctx, msg), - PacketMsg::ToClosePacket(msg) => timeout_on_close::process(ctx, msg), - }?; - let HandlerOutput { - result, - log, - events, - } = output; - let builder = HandlerOutput::builder().with_log(log).with_events(events); - Ok((builder, result)) -} - -pub fn packet_callback( - ctx: &mut Ctx, - module_id: &ModuleId, - msg: &PacketMsg, - output: &mut HandlerOutputBuilder<()>, -) -> Result<(), Error> -where - Ctx: Ics26Context, -{ - let mut module_output = ModuleOutputBuilder::new(); - let mut core_output = HandlerOutputBuilder::new(); - - let result = do_packet_callback(ctx, module_id, msg, &mut module_output, &mut core_output); - output.merge(module_output); - output.merge(core_output); - - result -} - -fn do_packet_callback( - ctx: &mut impl Ics26Context, - module_id: &ModuleId, - msg: &PacketMsg, - module_output: &mut ModuleOutputBuilder, - core_output: &mut HandlerOutputBuilder<()>, -) -> Result<(), Error> { - let cb = ctx - .router_mut() - .get_route_mut(module_id) - .ok_or_else(Error::route_not_found)?; - - match msg { - PacketMsg::RecvPacket(msg) => { - let result = cb.on_recv_packet(module_output, &msg.packet, &msg.signer); - match result { - OnRecvPacketAck::Nil(write_fn) => { - write_fn(cb.as_any_mut()).map_err(Error::app_module) - } - OnRecvPacketAck::Successful(ack, write_fn) => { - write_fn(cb.as_any_mut()).map_err(Error::app_module)?; - - process_write_ack(ctx, msg.packet.clone(), ack.as_ref(), core_output) - } - OnRecvPacketAck::Failed(ack) => { - process_write_ack(ctx, msg.packet.clone(), ack.as_ref(), core_output) - } - } - } - PacketMsg::AckPacket(msg) => cb.on_acknowledgement_packet( - module_output, - &msg.packet, - &msg.acknowledgement, - &msg.signer, - ), - PacketMsg::ToPacket(msg) => cb.on_timeout_packet(module_output, &msg.packet, &msg.signer), - PacketMsg::ToClosePacket(msg) => { - cb.on_timeout_packet(module_output, &msg.packet, &msg.signer) - } - } -} - -fn process_write_ack( - ctx: &mut impl Ics26Context, - packet: Packet, - acknowledgement: &dyn Acknowledgement, - core_output: &mut HandlerOutputBuilder<()>, -) -> Result<(), Error> { - let HandlerOutput { - result, - log, - events, - } = write_acknowledgement::process(ctx, packet, acknowledgement.as_ref().to_vec().into())?; - - // store write ack result - ctx.store_packet_result(result)?; - - core_output.merge_output( - HandlerOutput::builder() - .with_log(log) - .with_events(events) - .with_result(()), - ); - - Ok(()) -} diff --git a/modules/src/core/ics04_channel/handler/acknowledgement.rs b/modules/src/core/ics04_channel/handler/acknowledgement.rs deleted file mode 100644 index d9573ad234..0000000000 --- a/modules/src/core/ics04_channel/handler/acknowledgement.rs +++ /dev/null @@ -1,251 +0,0 @@ -use crate::core::ics03_connection::connection::State as ConnectionState; -use crate::core::ics04_channel::channel::State; -use crate::core::ics04_channel::channel::{Counterparty, Order}; -use crate::core::ics04_channel::events::AcknowledgePacket; -use crate::core::ics04_channel::handler::verify::verify_packet_acknowledgement_proofs; -use crate::core::ics04_channel::msgs::acknowledgement::MsgAcknowledgement; -use crate::core::ics04_channel::packet::{PacketResult, Sequence}; -use crate::core::ics04_channel::{context::ChannelReader, error::Error}; -use crate::core::ics24_host::identifier::{ChannelId, PortId}; -use crate::events::IbcEvent; -use crate::handler::{HandlerOutput, HandlerResult}; -use crate::prelude::*; - -#[derive(Clone, Debug)] -pub struct AckPacketResult { - pub port_id: PortId, - pub channel_id: ChannelId, - pub seq: Sequence, - pub seq_number: Option, -} - -pub fn process( - ctx: &Ctx, - msg: &MsgAcknowledgement, -) -> HandlerResult { - let mut output = HandlerOutput::builder(); - - let packet = &msg.packet; - - let source_channel_end = ctx.channel_end(&packet.source_port, &packet.source_channel)?; - - if !source_channel_end.state_matches(&State::Open) { - return Err(Error::channel_closed(packet.source_channel.clone())); - } - - let counterparty = Counterparty::new( - packet.destination_port.clone(), - Some(packet.destination_channel.clone()), - ); - - if !source_channel_end.counterparty_matches(&counterparty) { - return Err(Error::invalid_packet_counterparty( - packet.destination_port.clone(), - packet.destination_channel.clone(), - )); - } - - let connection_end = ctx.connection_end(&source_channel_end.connection_hops()[0])?; - - if !connection_end.state_matches(&ConnectionState::Open) { - return Err(Error::connection_not_open( - source_channel_end.connection_hops()[0].clone(), - )); - } - - // Verify packet commitment - let packet_commitment = - ctx.get_packet_commitment(&packet.source_port, &packet.source_channel, packet.sequence)?; - - if packet_commitment - != ctx.packet_commitment( - packet.data.clone(), - packet.timeout_height, - packet.timeout_timestamp, - ) - { - return Err(Error::incorrect_packet_commitment(packet.sequence)); - } - - // Verify the acknowledgement proof - verify_packet_acknowledgement_proofs( - ctx, - msg.proofs.height(), - packet, - msg.acknowledgement.clone(), - &connection_end, - &msg.proofs, - )?; - - let result = if source_channel_end.order_matches(&Order::Ordered) { - let next_seq_ack = - ctx.get_next_sequence_ack(&packet.source_port, &packet.source_channel)?; - - if packet.sequence != next_seq_ack { - return Err(Error::invalid_packet_sequence( - packet.sequence, - next_seq_ack, - )); - } - - PacketResult::Ack(AckPacketResult { - port_id: packet.source_port.clone(), - channel_id: packet.source_channel.clone(), - seq: packet.sequence, - seq_number: Some(next_seq_ack.increment()), - }) - } else { - PacketResult::Ack(AckPacketResult { - port_id: packet.source_port.clone(), - channel_id: packet.source_channel.clone(), - seq: packet.sequence, - seq_number: None, - }) - }; - - output.log("success: packet ack"); - - output.emit(IbcEvent::AcknowledgePacket(AcknowledgePacket { - packet: packet.clone(), - })); - - Ok(output.with_result(result)) -} - -#[cfg(test)] -mod tests { - use test_log::test; - - use crate::core::ics02_client::height::Height; - use crate::core::ics03_connection::connection::ConnectionEnd; - use crate::core::ics03_connection::connection::Counterparty as ConnectionCounterparty; - use crate::core::ics03_connection::connection::State as ConnectionState; - use crate::core::ics03_connection::version::get_compatible_versions; - use crate::core::ics04_channel::channel::{ChannelEnd, Counterparty, Order, State}; - use crate::core::ics04_channel::context::ChannelReader; - use crate::core::ics04_channel::handler::acknowledgement::process; - use crate::core::ics04_channel::msgs::acknowledgement::test_util::get_dummy_raw_msg_acknowledgement; - use crate::core::ics04_channel::msgs::acknowledgement::MsgAcknowledgement; - use crate::core::ics04_channel::Version; - use crate::core::ics24_host::identifier::{ClientId, ConnectionId}; - use crate::events::IbcEvent; - use crate::mock::context::MockContext; - use crate::prelude::*; - use crate::timestamp::ZERO_DURATION; - - #[test] - fn ack_packet_processing() { - struct Test { - name: String, - ctx: MockContext, - msg: MsgAcknowledgement, - want_pass: bool, - } - - let context = MockContext::default(); - - let client_height = Height::new(0, 2).unwrap(); - - let msg = MsgAcknowledgement::try_from(get_dummy_raw_msg_acknowledgement( - client_height.revision_height(), - )) - .unwrap(); - let packet = msg.packet.clone(); - - let data = context.packet_commitment( - packet.data.clone(), - packet.timeout_height, - packet.timeout_timestamp, - ); - - let source_channel_end = ChannelEnd::new( - State::Open, - Order::default(), - Counterparty::new( - packet.destination_port.clone(), - Some(packet.destination_channel.clone()), - ), - vec![ConnectionId::default()], - Version::ics20(), - ); - - let connection_end = ConnectionEnd::new( - ConnectionState::Open, - ClientId::default(), - ConnectionCounterparty::new( - ClientId::default(), - Some(ConnectionId::default()), - Default::default(), - ), - get_compatible_versions(), - ZERO_DURATION, - ); - - let tests: Vec = vec![ - Test { - name: "Processing fails because no channel exists in the context".to_string(), - ctx: context.clone(), - msg: msg.clone(), - want_pass: false, - }, - Test { - name: "Good parameters".to_string(), - ctx: context - .with_client(&ClientId::default(), client_height) - .with_connection(ConnectionId::default(), connection_end) - .with_channel( - packet.source_port.clone(), - packet.source_channel.clone(), - source_channel_end, - ) - .with_packet_commitment( - packet.source_port, - packet.source_channel, - packet.sequence, - data, - ) //with_ack_sequence required for ordered channels - .with_ack_sequence( - packet.destination_port, - packet.destination_channel, - 1.into(), - ), - msg, - want_pass: true, - }, - ] - .into_iter() - .collect(); - - for test in tests { - let res = process(&test.ctx, &test.msg); - // Additionally check the events and the output objects in the result. - match res { - Ok(proto_output) => { - assert!( - test.want_pass, - "ack_packet: test passed but was supposed to fail for test: {}, \nparams {:?} {:?}", - test.name, - test.msg.clone(), - test.ctx.clone() - ); - - assert!(!proto_output.events.is_empty()); // Some events must exist. - - for e in proto_output.events.iter() { - assert!(matches!(e, &IbcEvent::AcknowledgePacket(_))); - } - } - Err(e) => { - assert!( - !test.want_pass, - "ack_packet: did not pass test: {}, \nparams {:?} {:?} error: {:?}", - test.name, - test.msg.clone(), - test.ctx.clone(), - e, - ); - } - } - } - } -} diff --git a/modules/src/core/ics04_channel/handler/chan_close_confirm.rs b/modules/src/core/ics04_channel/handler/chan_close_confirm.rs deleted file mode 100644 index 3d1b03029c..0000000000 --- a/modules/src/core/ics04_channel/handler/chan_close_confirm.rs +++ /dev/null @@ -1,178 +0,0 @@ -//! Protocol logic specific to ICS4 messages of type `MsgChannelCloseConfirm`. -use crate::core::ics03_connection::connection::State as ConnectionState; -use crate::core::ics04_channel::channel::{ChannelEnd, Counterparty, State}; -use crate::core::ics04_channel::context::ChannelReader; -use crate::core::ics04_channel::error::Error; -use crate::core::ics04_channel::events::Attributes; -use crate::core::ics04_channel::handler::verify::verify_channel_proofs; -use crate::core::ics04_channel::handler::{ChannelIdState, ChannelResult}; -use crate::core::ics04_channel::msgs::chan_close_confirm::MsgChannelCloseConfirm; -use crate::events::IbcEvent; -use crate::handler::{HandlerOutput, HandlerResult}; -use crate::prelude::*; - -pub(crate) fn process( - ctx: &Ctx, - msg: &MsgChannelCloseConfirm, -) -> HandlerResult { - let mut output = HandlerOutput::builder(); - - // Retrieve the old channel end and validate it against the message. - let mut channel_end = ctx.channel_end(&msg.port_id, &msg.channel_id)?; - - // Validate that the channel end is in a state where it can be closed. - if channel_end.state_matches(&State::Closed) { - return Err(Error::channel_closed(msg.channel_id.clone())); - } - - // An OPEN IBC connection running on the local (host) chain should exist. - if channel_end.connection_hops().len() != 1 { - return Err(Error::invalid_connection_hops_length( - 1, - channel_end.connection_hops().len(), - )); - } - - let conn = ctx.connection_end(&channel_end.connection_hops()[0])?; - - if !conn.state_matches(&ConnectionState::Open) { - return Err(Error::connection_not_open( - channel_end.connection_hops()[0].clone(), - )); - } - - // Proof verification in two steps: - // 1. Setup: build the Channel as we expect to find it on the other party. - - let expected_counterparty = - Counterparty::new(msg.port_id.clone(), Some(msg.channel_id.clone())); - - let counterparty = conn.counterparty(); - let ccid = counterparty.connection_id().ok_or_else(|| { - Error::undefined_connection_counterparty(channel_end.connection_hops()[0].clone()) - })?; - - let expected_connection_hops = vec![ccid.clone()]; - - let expected_channel_end = ChannelEnd::new( - State::Closed, - *channel_end.ordering(), - expected_counterparty, - expected_connection_hops, - channel_end.version().clone(), - ); - - verify_channel_proofs( - ctx, - msg.proofs.height(), - &channel_end, - &conn, - &expected_channel_end, - &msg.proofs, - )?; - - output.log("success: channel close confirm "); - - // Transition the channel end to the new state & pick a version. - channel_end.set_state(State::Closed); - - let result = ChannelResult { - port_id: msg.port_id.clone(), - channel_id: msg.channel_id.clone(), - channel_id_state: ChannelIdState::Reused, - channel_end, - }; - - let event_attributes = Attributes { - channel_id: Some(msg.channel_id.clone()), - ..Default::default() - }; - output.emit(IbcEvent::CloseConfirmChannel( - event_attributes - .try_into() - .map_err(|_| Error::missing_channel_id())?, - )); - - Ok(output.with_result(result)) -} - -#[cfg(test)] -mod tests { - use crate::core::ics04_channel::context::ChannelReader; - use crate::core::ics04_channel::msgs::chan_close_confirm::test_util::get_dummy_raw_msg_chan_close_confirm; - use crate::core::ics04_channel::msgs::chan_close_confirm::MsgChannelCloseConfirm; - use crate::core::ics04_channel::msgs::ChannelMsg; - use crate::events::IbcEvent; - use crate::prelude::*; - - use crate::core::ics02_client::client_type::ClientType; - use crate::core::ics03_connection::connection::ConnectionEnd; - use crate::core::ics03_connection::connection::Counterparty as ConnectionCounterparty; - use crate::core::ics03_connection::connection::State as ConnectionState; - use crate::core::ics03_connection::msgs::test_util::get_dummy_raw_counterparty; - use crate::core::ics03_connection::version::get_compatible_versions; - use crate::core::ics04_channel::channel::{ - ChannelEnd, Counterparty, Order, State as ChannelState, - }; - use crate::core::ics04_channel::handler::channel_dispatch; - use crate::core::ics04_channel::Version; - use crate::core::ics24_host::identifier::{ClientId, ConnectionId}; - - use crate::mock::context::MockContext; - use crate::timestamp::ZERO_DURATION; - - #[test] - fn chan_close_confirm_event_height() { - let client_id = ClientId::new(ClientType::Mock, 24).unwrap(); - let conn_id = ConnectionId::new(2); - let default_context = MockContext::default(); - let client_consensus_state_height = default_context.host_height(); - - let conn_end = ConnectionEnd::new( - ConnectionState::Open, - client_id.clone(), - ConnectionCounterparty::try_from(get_dummy_raw_counterparty()).unwrap(), - get_compatible_versions(), - ZERO_DURATION, - ); - - let msg_chan_close_confirm = MsgChannelCloseConfirm::try_from( - get_dummy_raw_msg_chan_close_confirm(client_consensus_state_height.revision_height()), - ) - .unwrap(); - - let chan_end = ChannelEnd::new( - ChannelState::Open, - Order::default(), - Counterparty::new( - msg_chan_close_confirm.port_id.clone(), - Some(msg_chan_close_confirm.channel_id.clone()), - ), - vec![conn_id.clone()], - Version::default(), - ); - - let context = default_context - .with_client(&client_id, client_consensus_state_height) - .with_connection(conn_id, conn_end) - .with_channel( - msg_chan_close_confirm.port_id.clone(), - msg_chan_close_confirm.channel_id.clone(), - chan_end, - ); - - let (handler_output_builder, _) = channel_dispatch( - &context, - &ChannelMsg::ChannelCloseConfirm(msg_chan_close_confirm), - ) - .unwrap(); - - let handler_output = handler_output_builder.with_result(()); - - assert!(!handler_output.events.is_empty()); // Some events must exist. - - for event in handler_output.events.iter() { - assert!(matches!(event, &IbcEvent::CloseConfirmChannel(_))); - } - } -} diff --git a/modules/src/core/ics04_channel/handler/chan_close_init.rs b/modules/src/core/ics04_channel/handler/chan_close_init.rs deleted file mode 100644 index db716ca815..0000000000 --- a/modules/src/core/ics04_channel/handler/chan_close_init.rs +++ /dev/null @@ -1,146 +0,0 @@ -//! Protocol logic specific to ICS4 messages of type `MsgChannelCloseInit`. -use crate::core::ics03_connection::connection::State as ConnectionState; -use crate::core::ics04_channel::channel::State; -use crate::core::ics04_channel::context::ChannelReader; -use crate::core::ics04_channel::error::Error; -use crate::core::ics04_channel::events::Attributes; -use crate::core::ics04_channel::handler::{ChannelIdState, ChannelResult}; -use crate::core::ics04_channel::msgs::chan_close_init::MsgChannelCloseInit; -use crate::events::IbcEvent; -use crate::handler::{HandlerOutput, HandlerResult}; - -pub(crate) fn process( - ctx: &Ctx, - msg: &MsgChannelCloseInit, -) -> HandlerResult { - let mut output = HandlerOutput::builder(); - - // Unwrap the old channel end and validate it against the message. - let mut channel_end = ctx.channel_end(&msg.port_id, &msg.channel_id)?; - - // Validate that the channel end is in a state where it can be closed. - if channel_end.state_matches(&State::Closed) { - return Err(Error::invalid_channel_state( - msg.channel_id.clone(), - channel_end.state, - )); - } - - // An OPEN IBC connection running on the local (host) chain should exist. - if channel_end.connection_hops().len() != 1 { - return Err(Error::invalid_connection_hops_length( - 1, - channel_end.connection_hops().len(), - )); - } - - let conn = ctx.connection_end(&channel_end.connection_hops()[0])?; - - if !conn.state_matches(&ConnectionState::Open) { - return Err(Error::connection_not_open( - channel_end.connection_hops()[0].clone(), - )); - } - - output.log("success: channel close init "); - - // Transition the channel end to the new state & pick a version. - channel_end.set_state(State::Closed); - - let result = ChannelResult { - port_id: msg.port_id.clone(), - channel_id: msg.channel_id.clone(), - channel_id_state: ChannelIdState::Reused, - channel_end, - }; - - let event_attributes = Attributes { - channel_id: Some(msg.channel_id.clone()), - ..Default::default() - }; - output.emit(IbcEvent::CloseInitChannel( - event_attributes - .try_into() - .map_err(|_| Error::missing_channel_id())?, - )); - - Ok(output.with_result(result)) -} - -#[cfg(test)] -mod tests { - use crate::core::ics04_channel::context::ChannelReader; - use crate::core::ics04_channel::msgs::chan_close_init::test_util::get_dummy_raw_msg_chan_close_init; - use crate::core::ics04_channel::msgs::chan_close_init::MsgChannelCloseInit; - use crate::core::ics04_channel::msgs::ChannelMsg; - use crate::events::IbcEvent; - use crate::prelude::*; - - use crate::core::ics02_client::client_type::ClientType; - use crate::core::ics03_connection::connection::ConnectionEnd; - use crate::core::ics03_connection::connection::Counterparty as ConnectionCounterparty; - use crate::core::ics03_connection::connection::State as ConnectionState; - use crate::core::ics03_connection::msgs::test_util::get_dummy_raw_counterparty; - use crate::core::ics03_connection::version::get_compatible_versions; - use crate::core::ics04_channel::channel::{ - ChannelEnd, Counterparty, Order, State as ChannelState, - }; - use crate::core::ics04_channel::handler::channel_dispatch; - use crate::core::ics04_channel::Version; - use crate::core::ics24_host::identifier::{ClientId, ConnectionId}; - - use crate::mock::context::MockContext; - use crate::timestamp::ZERO_DURATION; - - #[test] - fn chan_close_init_event_height() { - let client_id = ClientId::new(ClientType::Mock, 24).unwrap(); - let conn_id = ConnectionId::new(2); - - let conn_end = ConnectionEnd::new( - ConnectionState::Open, - client_id.clone(), - ConnectionCounterparty::try_from(get_dummy_raw_counterparty()).unwrap(), - get_compatible_versions(), - ZERO_DURATION, - ); - - let msg_chan_close_init = - MsgChannelCloseInit::try_from(get_dummy_raw_msg_chan_close_init()).unwrap(); - - let chan_end = ChannelEnd::new( - ChannelState::Open, - Order::default(), - Counterparty::new( - msg_chan_close_init.port_id.clone(), - Some(msg_chan_close_init.channel_id.clone()), - ), - vec![conn_id.clone()], - Version::default(), - ); - - let context = { - let default_context = MockContext::default(); - let client_consensus_state_height = default_context.host_height(); - - default_context - .with_client(&client_id, client_consensus_state_height) - .with_connection(conn_id, conn_end) - .with_channel( - msg_chan_close_init.port_id.clone(), - msg_chan_close_init.channel_id.clone(), - chan_end, - ) - }; - - let (handler_output_builder, _) = - channel_dispatch(&context, &ChannelMsg::ChannelCloseInit(msg_chan_close_init)).unwrap(); - let handler_output = handler_output_builder.with_result(()); - - assert!(!handler_output.events.is_empty()); // Some events must exist. - - for event in handler_output.events.iter() { - assert!(matches!(event, &IbcEvent::CloseInitChannel(_))); - } - } -} diff --git a/modules/src/core/ics04_channel/handler/chan_open_ack.rs b/modules/src/core/ics04_channel/handler/chan_open_ack.rs deleted file mode 100644 index 788831a642..0000000000 --- a/modules/src/core/ics04_channel/handler/chan_open_ack.rs +++ /dev/null @@ -1,324 +0,0 @@ -//! Protocol logic specific to ICS4 messages of type `MsgChannelOpenAck`. -use crate::core::ics03_connection::connection::State as ConnectionState; -use crate::core::ics04_channel::channel::{ChannelEnd, Counterparty, State}; -use crate::core::ics04_channel::context::ChannelReader; -use crate::core::ics04_channel::error::Error; -use crate::core::ics04_channel::events::Attributes; -use crate::core::ics04_channel::handler::verify::verify_channel_proofs; -use crate::core::ics04_channel::handler::{ChannelIdState, ChannelResult}; -use crate::core::ics04_channel::msgs::chan_open_ack::MsgChannelOpenAck; -use crate::events::IbcEvent; -use crate::handler::{HandlerOutput, HandlerResult}; -use crate::prelude::*; - -pub(crate) fn process( - ctx: &Ctx, - msg: &MsgChannelOpenAck, -) -> HandlerResult { - let mut output = HandlerOutput::builder(); - - // Unwrap the old channel end and validate it against the message. - let mut channel_end = ctx.channel_end(&msg.port_id, &msg.channel_id)?; - - // Validate that the channel end is in a state where it can be ack. - if !channel_end.state_matches(&State::Init) && !channel_end.state_matches(&State::TryOpen) { - return Err(Error::invalid_channel_state( - msg.channel_id.clone(), - channel_end.state, - )); - } - - // An OPEN IBC connection running on the local (host) chain should exist. - - if channel_end.connection_hops().len() != 1 { - return Err(Error::invalid_connection_hops_length( - 1, - channel_end.connection_hops().len(), - )); - } - - let conn = ctx.connection_end(&channel_end.connection_hops()[0])?; - - if !conn.state_matches(&ConnectionState::Open) { - return Err(Error::connection_not_open( - channel_end.connection_hops()[0].clone(), - )); - } - - // Proof verification in two steps: - // 1. Setup: build the Channel as we expect to find it on the other party. - - let expected_counterparty = - Counterparty::new(msg.port_id.clone(), Some(msg.channel_id.clone())); - - let counterparty = conn.counterparty(); - let ccid = counterparty.connection_id().ok_or_else(|| { - Error::undefined_connection_counterparty(channel_end.connection_hops()[0].clone()) - })?; - - let expected_connection_hops = vec![ccid.clone()]; - - let expected_channel_end = ChannelEnd::new( - State::TryOpen, - *channel_end.ordering(), - expected_counterparty, - expected_connection_hops, - msg.counterparty_version.clone(), - ); - - // set the counterparty channel id to verify against it - channel_end.set_counterparty_channel_id(msg.counterparty_channel_id.clone()); - - //2. Verify proofs - verify_channel_proofs( - ctx, - msg.proofs.height(), - &channel_end, - &conn, - &expected_channel_end, - &msg.proofs, - )?; - - output.log("success: channel open ack "); - - // Transition the channel end to the new state & pick a version. - channel_end.set_state(State::Open); - channel_end.set_version(msg.counterparty_version.clone()); - - let result = ChannelResult { - port_id: msg.port_id.clone(), - channel_id: msg.channel_id.clone(), - channel_id_state: ChannelIdState::Reused, - channel_end, - }; - - let event_attributes = Attributes { - channel_id: Some(msg.channel_id.clone()), - ..Default::default() - }; - output.emit(IbcEvent::OpenAckChannel( - event_attributes - .try_into() - .map_err(|_| Error::missing_channel_id())?, - )); - - Ok(output.with_result(result)) -} - -#[cfg(test)] -mod tests { - use core::str::FromStr; - - use test_log::test; - - use crate::core::ics03_connection::connection::ConnectionEnd; - use crate::core::ics03_connection::connection::Counterparty as ConnectionCounterparty; - use crate::core::ics03_connection::connection::State as ConnectionState; - use crate::core::ics03_connection::msgs::conn_open_init::test_util::get_dummy_raw_msg_conn_open_init; - use crate::core::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; - use crate::core::ics03_connection::msgs::conn_open_try::test_util::get_dummy_raw_msg_conn_open_try; - use crate::core::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; - use crate::core::ics03_connection::version::get_compatible_versions; - use crate::core::ics04_channel::channel::{ChannelEnd, Counterparty, State}; - use crate::core::ics04_channel::handler::channel_dispatch; - use crate::core::ics04_channel::msgs::chan_open_ack::test_util::get_dummy_raw_msg_chan_open_ack; - use crate::core::ics04_channel::msgs::chan_open_ack::MsgChannelOpenAck; - use crate::core::ics04_channel::msgs::chan_open_try::test_util::get_dummy_raw_msg_chan_open_try; - use crate::core::ics04_channel::msgs::chan_open_try::MsgChannelOpenTry; - use crate::core::ics04_channel::msgs::ChannelMsg; - use crate::core::ics24_host::identifier::ConnectionId; - use crate::events::IbcEvent; - use crate::mock::context::MockContext; - use crate::prelude::*; - use crate::Height; - - // TODO: The tests here are very fragile and complex. - // Should be adapted to use the same structure as `handler::chan_open_try::tests`. - #[test] - fn chan_open_ack_msg_processing() { - struct Test { - name: String, - ctx: MockContext, - msg: ChannelMsg, - want_pass: bool, - } - let proof_height = 10; - let client_consensus_state_height = 10; - let host_chain_height = Height::new(0, 35).unwrap(); - - let context = MockContext::default(); - - let msg_conn_init = - MsgConnectionOpenInit::try_from(get_dummy_raw_msg_conn_open_init()).unwrap(); - - let conn_end = ConnectionEnd::new( - ConnectionState::Open, - msg_conn_init.client_id.clone(), - ConnectionCounterparty::new( - msg_conn_init.counterparty.client_id().clone(), - Some(ConnectionId::from_str("defaultConnection-1").unwrap()), - msg_conn_init.counterparty.prefix().clone(), - ), - get_compatible_versions(), - msg_conn_init.delay_period, - ); - - let ccid = ::from_str("defaultConnection-0"); - let cid = match ccid { - Ok(v) => v, - Err(_e) => ConnectionId::default(), - }; - - let mut connection_vec0 = Vec::new(); - connection_vec0.insert( - 0, - match ::from_str("defaultConnection-0") { - Ok(a) => a, - _ => unreachable!(), - }, - ); - - let msg_conn_try = MsgConnectionOpenTry::try_from(get_dummy_raw_msg_conn_open_try( - client_consensus_state_height, - host_chain_height.revision_height(), - )) - .unwrap(); - - let msg_chan_ack = - MsgChannelOpenAck::try_from(get_dummy_raw_msg_chan_open_ack(proof_height)).unwrap(); - - let msg_chan_try = - MsgChannelOpenTry::try_from(get_dummy_raw_msg_chan_open_try(proof_height)).unwrap(); - - let chan_end = ChannelEnd::new( - State::Init, - *msg_chan_try.channel.ordering(), - Counterparty::new( - msg_chan_ack.port_id.clone(), - Some(msg_chan_ack.channel_id.clone()), - ), - connection_vec0.clone(), - msg_chan_try.channel.version().clone(), - ); - - let failed_chan_end = ChannelEnd::new( - State::Open, - *msg_chan_try.channel.ordering(), - Counterparty::new( - msg_chan_ack.port_id.clone(), - Some(msg_chan_ack.channel_id.clone()), - ), - connection_vec0, - msg_chan_try.channel.version().clone(), - ); - - let tests: Vec = vec![ - Test { - name: "Processing fails because no channel exists in the context".to_string(), - ctx: context.clone(), - msg: ChannelMsg::ChannelOpenAck(msg_chan_ack.clone()), - want_pass: false, - }, - Test { - name: "Processing fails because the channel is in the wrong state".to_string(), - ctx: context - .clone() - .with_client( - &msg_conn_try.client_id, - Height::new(0, client_consensus_state_height).unwrap(), - ) - .with_channel( - msg_chan_ack.port_id.clone(), - msg_chan_ack.channel_id.clone(), - failed_chan_end, - ), - msg: ChannelMsg::ChannelOpenAck(msg_chan_ack.clone()), - want_pass: false, - }, - Test { - name: "Processing fails because a connection does exist".to_string(), - ctx: context - .clone() - .with_client( - &msg_conn_try.client_id, - Height::new(0, client_consensus_state_height).unwrap(), - ) - .with_channel( - msg_chan_ack.port_id.clone(), - msg_chan_ack.channel_id.clone(), - chan_end.clone(), - ), - msg: ChannelMsg::ChannelOpenAck(msg_chan_ack.clone()), - want_pass: false, - }, - Test { - name: "Processing fails due to missing client state ".to_string(), - ctx: context - .clone() - .with_connection(cid.clone(), conn_end.clone()) - .with_channel( - msg_chan_ack.port_id.clone(), - msg_chan_ack.channel_id.clone(), - chan_end.clone(), - ), - msg: ChannelMsg::ChannelOpenAck(msg_chan_ack.clone()), - want_pass: false, - }, - Test { - name: "Good parameters".to_string(), - ctx: context // .clone() - .with_client( - &msg_conn_try.client_id, - Height::new(0, client_consensus_state_height).unwrap(), - ) - .with_connection(cid, conn_end) - .with_channel( - msg_chan_ack.port_id.clone(), - msg_chan_ack.channel_id.clone(), - chan_end, - ), - msg: ChannelMsg::ChannelOpenAck(msg_chan_ack), - want_pass: true, - }, - ] - .into_iter() - .collect(); - - for test in tests { - let res = channel_dispatch(&test.ctx, &test.msg); - // Additionally check the events and the output objects in the result. - match res { - Ok((proto_output, res)) => { - assert!( - test.want_pass, - "chan_open_ack: test passed but was supposed to fail for test: {}, \nparams {:?} {:?}", - test.name, - test.msg, - test.ctx.clone() - ); - - let proto_output = proto_output.with_result(()); - assert!(!proto_output.events.is_empty()); // Some events must exist. - - // The object in the output is a ConnectionEnd, should have init state. - //assert_eq!(res.channel_id, msg_chan_init.channel_id().clone()); - assert_eq!(res.channel_end.state().clone(), State::Open); - - for e in proto_output.events.iter() { - assert!(matches!(e, &IbcEvent::OpenAckChannel(_))); - } - } - Err(e) => { - assert!( - !test.want_pass, - "chan_open_ack: did not pass test: {}, \nparams {:?} {:?} error: {:?}", - test.name, - test.msg, - test.ctx.clone(), - e, - ); - } - } - } - } -} diff --git a/modules/src/core/ics04_channel/handler/chan_open_confirm.rs b/modules/src/core/ics04_channel/handler/chan_open_confirm.rs deleted file mode 100644 index 0884102a9f..0000000000 --- a/modules/src/core/ics04_channel/handler/chan_open_confirm.rs +++ /dev/null @@ -1,223 +0,0 @@ -//! Protocol logic specific to ICS4 messages of type `MsgChannelOpenConfirm`. -use crate::core::ics03_connection::connection::State as ConnectionState; -use crate::core::ics04_channel::channel::{ChannelEnd, Counterparty, State}; -use crate::core::ics04_channel::context::ChannelReader; -use crate::core::ics04_channel::error::Error; -use crate::core::ics04_channel::events::Attributes; -use crate::core::ics04_channel::handler::verify::verify_channel_proofs; -use crate::core::ics04_channel::handler::{ChannelIdState, ChannelResult}; -use crate::core::ics04_channel::msgs::chan_open_confirm::MsgChannelOpenConfirm; -use crate::events::IbcEvent; -use crate::handler::{HandlerOutput, HandlerResult}; -use crate::prelude::*; - -pub(crate) fn process( - ctx: &Ctx, - msg: &MsgChannelOpenConfirm, -) -> HandlerResult { - let mut output = HandlerOutput::builder(); - - // Unwrap the old channel end and validate it against the message. - let mut channel_end = ctx.channel_end(&msg.port_id, &msg.channel_id)?; - - // Validate that the channel end is in a state where it can be confirmed. - if !channel_end.state_matches(&State::TryOpen) { - return Err(Error::invalid_channel_state( - msg.channel_id.clone(), - channel_end.state, - )); - } - - // An OPEN IBC connection running on the local (host) chain should exist. - if channel_end.connection_hops().len() != 1 { - return Err(Error::invalid_connection_hops_length( - 1, - channel_end.connection_hops().len(), - )); - } - - let conn = ctx.connection_end(&channel_end.connection_hops()[0])?; - - if !conn.state_matches(&ConnectionState::Open) { - return Err(Error::connection_not_open( - channel_end.connection_hops()[0].clone(), - )); - } - - // Proof verification in two steps: - // 1. Setup: build the Channel as we expect to find it on the other party. - - let expected_counterparty = - Counterparty::new(msg.port_id.clone(), Some(msg.channel_id.clone())); - - let connection_counterparty = conn.counterparty(); - let ccid = connection_counterparty.connection_id().ok_or_else(|| { - Error::undefined_connection_counterparty(channel_end.connection_hops()[0].clone()) - })?; - - let expected_connection_hops = vec![ccid.clone()]; - - let expected_channel_end = ChannelEnd::new( - State::Open, - *channel_end.ordering(), - expected_counterparty, - expected_connection_hops, - channel_end.version().clone(), - ); - //2. Verify proofs - verify_channel_proofs( - ctx, - msg.proofs.height(), - &channel_end, - &conn, - &expected_channel_end, - &msg.proofs, - ) - .map_err(Error::chan_open_confirm_proof_verification)?; - - output.log("success: channel open confirm "); - - // Transition the channel end to the new state. - channel_end.set_state(State::Open); - - let result = ChannelResult { - port_id: msg.port_id.clone(), - channel_id: msg.channel_id.clone(), - channel_id_state: ChannelIdState::Reused, - channel_end, - }; - - let event_attributes = Attributes { - channel_id: Some(msg.channel_id.clone()), - ..Default::default() - }; - output.emit(IbcEvent::OpenConfirmChannel( - event_attributes - .try_into() - .map_err(|_| Error::missing_channel_id())?, - )); - - Ok(output.with_result(result)) -} - -#[cfg(test)] -mod tests { - use crate::prelude::*; - - use test_log::test; - - use crate::core::ics02_client::client_type::ClientType; - use crate::core::ics03_connection::connection::ConnectionEnd; - use crate::core::ics03_connection::connection::Counterparty as ConnectionCounterparty; - use crate::core::ics03_connection::connection::State as ConnectionState; - use crate::core::ics03_connection::context::ConnectionReader; - use crate::core::ics03_connection::msgs::test_util::get_dummy_raw_counterparty; - use crate::core::ics03_connection::version::get_compatible_versions; - use crate::core::ics04_channel::channel::{ChannelEnd, Counterparty, Order, State}; - use crate::core::ics04_channel::handler::channel_dispatch; - use crate::core::ics04_channel::msgs::chan_open_confirm::test_util::get_dummy_raw_msg_chan_open_confirm; - use crate::core::ics04_channel::msgs::chan_open_confirm::MsgChannelOpenConfirm; - use crate::core::ics04_channel::msgs::ChannelMsg; - use crate::core::ics04_channel::Version; - use crate::core::ics24_host::identifier::{ClientId, ConnectionId}; - use crate::events::IbcEvent; - use crate::mock::context::MockContext; - use crate::timestamp::ZERO_DURATION; - use crate::Height; - - // TODO: The tests here should use the same structure as `handler::chan_open_try::tests`. - #[test] - fn chan_open_confirm_msg_processing() { - struct Test { - name: String, - ctx: MockContext, - msg: ChannelMsg, - want_pass: bool, - } - let client_id = ClientId::new(ClientType::Mock, 24).unwrap(); - let conn_id = ConnectionId::new(2); - let context = MockContext::default(); - let client_consensus_state_height = context.host_current_height().revision_height(); - - // The connection underlying the channel we're trying to open. - let conn_end = ConnectionEnd::new( - ConnectionState::Open, - client_id.clone(), - ConnectionCounterparty::try_from(get_dummy_raw_counterparty()).unwrap(), - get_compatible_versions(), - ZERO_DURATION, - ); - - let msg_chan_confirm = MsgChannelOpenConfirm::try_from( - get_dummy_raw_msg_chan_open_confirm(client_consensus_state_height), - ) - .unwrap(); - - let chan_end = ChannelEnd::new( - State::TryOpen, - Order::default(), - Counterparty::new( - msg_chan_confirm.port_id.clone(), - Some(msg_chan_confirm.channel_id.clone()), - ), - vec![conn_id.clone()], - Version::default(), - ); - - let tests: Vec = vec![Test { - name: "Good parameters".to_string(), - ctx: context - .with_client( - &client_id, - Height::new(0, client_consensus_state_height).unwrap(), - ) - .with_connection(conn_id, conn_end) - .with_channel( - msg_chan_confirm.port_id.clone(), - msg_chan_confirm.channel_id.clone(), - chan_end, - ), - msg: ChannelMsg::ChannelOpenConfirm(msg_chan_confirm), - want_pass: true, - }] - .into_iter() - .collect(); - - for test in tests { - let res = channel_dispatch(&test.ctx, &test.msg); - // Additionally check the events and the output objects in the result. - match res { - Ok((proto_output, res)) => { - assert!( - test.want_pass, - "chan_open_confirm: test passed but was supposed to fail for test: {}, \nparams {:?} {:?}", - test.name, - test.msg, - test.ctx.clone() - ); - - let proto_output = proto_output.with_result(()); - assert!(!proto_output.events.is_empty()); // Some events must exist. - - // The object in the output is a ConnectionEnd, should have init state. - //assert_eq!(res.channel_id, msg_chan_init.channel_id().clone()); - assert_eq!(res.channel_end.state().clone(), State::Open); - - for e in proto_output.events.iter() { - assert!(matches!(e, &IbcEvent::OpenConfirmChannel(_))); - } - } - Err(e) => { - assert!( - !test.want_pass, - "chan_open_ack: did not pass test: {}, \nparams {:?} {:?}\nerror: {:?}", - test.name, - test.msg, - test.ctx.clone(), - e, - ); - } - } - } - } -} diff --git a/modules/src/core/ics04_channel/handler/chan_open_init.rs b/modules/src/core/ics04_channel/handler/chan_open_init.rs deleted file mode 100644 index 228a9ca510..0000000000 --- a/modules/src/core/ics04_channel/handler/chan_open_init.rs +++ /dev/null @@ -1,184 +0,0 @@ -//! Protocol logic specific to ICS4 messages of type `MsgChannelOpenInit`. - -use crate::core::ics04_channel::channel::{ChannelEnd, State}; -use crate::core::ics04_channel::context::ChannelReader; -use crate::core::ics04_channel::error::Error; -use crate::core::ics04_channel::events::Attributes; -use crate::core::ics04_channel::handler::{ChannelIdState, ChannelResult}; -use crate::core::ics04_channel::msgs::chan_open_init::MsgChannelOpenInit; -use crate::core::ics24_host::identifier::ChannelId; -use crate::events::IbcEvent; -use crate::handler::{HandlerOutput, HandlerResult}; -use crate::prelude::*; - -pub(crate) fn process( - ctx: &Ctx, - msg: &MsgChannelOpenInit, -) -> HandlerResult { - let mut output = HandlerOutput::builder(); - - if msg.channel.connection_hops().len() != 1 { - return Err(Error::invalid_connection_hops_length( - 1, - msg.channel.connection_hops().len(), - )); - } - - // An IBC connection running on the local (host) chain should exist. - let conn = ctx.connection_end(&msg.channel.connection_hops()[0])?; - let get_versions = conn.versions(); - let version = match get_versions { - [version] => version, - _ => return Err(Error::invalid_version_length_connection()), - }; - - let channel_feature = msg.channel.ordering().to_string(); - if !version.is_supported_feature(channel_feature) { - return Err(Error::channel_feature_not_suported_by_connection()); - } - - // Channel identifier construction. - let id_counter = ctx.channel_counter()?; - let chan_id = ChannelId::new(id_counter); - - output.log(format!( - "success: generated new channel identifier: {}", - chan_id - )); - - let new_channel_end = ChannelEnd::new( - State::Init, - *msg.channel.ordering(), - msg.channel.counterparty().clone(), - msg.channel.connection_hops().clone(), - msg.channel.version().clone(), - ); - - output.log("success: no channel found"); - - let result = ChannelResult { - port_id: msg.port_id.clone(), - channel_id: chan_id.clone(), - channel_end: new_channel_end, - channel_id_state: ChannelIdState::Generated, - }; - - let event_attributes = Attributes { - channel_id: Some(chan_id), - ..Default::default() - }; - output.emit(IbcEvent::OpenInitChannel( - event_attributes - .try_into() - .map_err(|_| Error::missing_channel_id())?, - )); - - Ok(output.with_result(result)) -} - -#[cfg(test)] -mod tests { - use crate::prelude::*; - - use test_log::test; - - use crate::core::ics03_connection::connection::ConnectionEnd; - use crate::core::ics03_connection::connection::State as ConnectionState; - use crate::core::ics03_connection::msgs::conn_open_init::test_util::get_dummy_raw_msg_conn_open_init; - use crate::core::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; - use crate::core::ics03_connection::version::get_compatible_versions; - use crate::core::ics04_channel::channel::State; - use crate::core::ics04_channel::handler::channel_dispatch; - use crate::core::ics04_channel::msgs::chan_open_init::test_util::get_dummy_raw_msg_chan_open_init; - use crate::core::ics04_channel::msgs::chan_open_init::MsgChannelOpenInit; - use crate::core::ics04_channel::msgs::ChannelMsg; - use crate::core::ics24_host::identifier::ConnectionId; - use crate::events::IbcEvent; - use crate::mock::context::MockContext; - - #[test] - fn chan_open_init_msg_processing() { - struct Test { - name: String, - ctx: MockContext, - msg: ChannelMsg, - want_pass: bool, - } - - let msg_chan_init = - MsgChannelOpenInit::try_from(get_dummy_raw_msg_chan_open_init()).unwrap(); - - let context = MockContext::default(); - - let msg_conn_init = - MsgConnectionOpenInit::try_from(get_dummy_raw_msg_conn_open_init()).unwrap(); - - let init_conn_end = ConnectionEnd::new( - ConnectionState::Init, - msg_conn_init.client_id.clone(), - msg_conn_init.counterparty.clone(), - get_compatible_versions(), - msg_conn_init.delay_period, - ); - - let cid = ConnectionId::default(); - - let tests: Vec = vec![ - Test { - name: "Processing fails because no connection exists in the context".to_string(), - ctx: context.clone(), - msg: ChannelMsg::ChannelOpenInit(msg_chan_init.clone()), - want_pass: false, - }, - Test { - name: "Good parameters".to_string(), - ctx: context.with_connection(cid, init_conn_end), - msg: ChannelMsg::ChannelOpenInit(msg_chan_init), - want_pass: true, - }, - ] - .into_iter() - .collect(); - - for test in tests { - let res = channel_dispatch(&test.ctx, &test.msg); - // Additionally check the events and the output objects in the result. - match res { - Ok((proto_output, res)) => { - assert!( - test.want_pass, - "chan_open_init: test passed but was supposed to fail for test: {}, \nparams {:?} {:?}", - test.name, - test.msg, - test.ctx.clone() - ); - - let proto_output = proto_output.with_result(()); - assert!(!proto_output.events.is_empty()); // Some events must exist. - - // The object in the output is a ChannelEnd, should have init state. - assert_eq!(res.channel_end.state().clone(), State::Init); - let msg_init = test.msg; - - if let ChannelMsg::ChannelOpenInit(msg_init) = msg_init { - assert_eq!(res.port_id.clone(), msg_init.port_id.clone()); - } - - for e in proto_output.events.iter() { - assert!(matches!(e, &IbcEvent::OpenInitChannel(_))); - } - } - Err(e) => { - assert!( - !test.want_pass, - "chan_open_init: did not pass test: {}, \nparams {:?} {:?} error: {:?}", - test.name, - test.msg, - test.ctx.clone(), - e, - ); - } - } - } - } -} diff --git a/modules/src/core/ics04_channel/handler/chan_open_try.rs b/modules/src/core/ics04_channel/handler/chan_open_try.rs deleted file mode 100644 index 9efc219e28..0000000000 --- a/modules/src/core/ics04_channel/handler/chan_open_try.rs +++ /dev/null @@ -1,431 +0,0 @@ -//! Protocol logic specific to ICS4 messages of type `MsgChannelOpenTry`. - -use crate::core::ics03_connection::connection::State as ConnectionState; -use crate::core::ics04_channel::channel::{ChannelEnd, Counterparty, State}; -use crate::core::ics04_channel::context::ChannelReader; -use crate::core::ics04_channel::error::Error; -use crate::core::ics04_channel::events::Attributes; -use crate::core::ics04_channel::handler::verify::verify_channel_proofs; -use crate::core::ics04_channel::handler::{ChannelIdState, ChannelResult}; -use crate::core::ics04_channel::msgs::chan_open_try::MsgChannelOpenTry; -use crate::core::ics24_host::identifier::ChannelId; -use crate::events::IbcEvent; -use crate::handler::{HandlerOutput, HandlerResult}; -use crate::prelude::*; - -pub(crate) fn process( - ctx: &Ctx, - msg: &MsgChannelOpenTry, -) -> HandlerResult { - let mut output = HandlerOutput::builder(); - - // Unwrap the old channel end (if any) and validate it against the message. - let (mut new_channel_end, channel_id) = match &msg.previous_channel_id { - Some(prev_id) => { - let old_channel_end = ctx.channel_end(&msg.port_id, prev_id)?; - - // Validate that existing channel end matches with the one we're trying to establish. - if old_channel_end.state_matches(&State::Init) - && old_channel_end.order_matches(msg.channel.ordering()) - && old_channel_end.connection_hops_matches(msg.channel.connection_hops()) - && old_channel_end.counterparty_matches(msg.channel.counterparty()) - && old_channel_end.version_matches(msg.channel.version()) - { - // A ChannelEnd already exists and all validation passed. - Ok((old_channel_end, prev_id.clone())) - } else { - // A ConnectionEnd already exists and validation failed. - Err(Error::channel_mismatch(prev_id.clone())) - } - } - // No previous channel id was supplied. Create a new channel end & an identifier. - None => { - let channel_end = ChannelEnd::new( - State::Init, - *msg.channel.ordering(), - msg.channel.counterparty().clone(), - msg.channel.connection_hops().clone(), - msg.counterparty_version.clone(), - ); - - // Channel identifier construction. - let id_counter = ctx.channel_counter()?; - let chan_id = ChannelId::new(id_counter); - - output.log(format!( - "success: generated new channel identifier: {}", - chan_id - )); - - Ok((channel_end, chan_id)) - } - }?; - - // An IBC connection running on the local (host) chain should exist. - if msg.channel.connection_hops().len() != 1 { - return Err(Error::invalid_connection_hops_length( - 1, - msg.channel.connection_hops().len(), - )); - } - - let conn = ctx.connection_end(&msg.channel.connection_hops()[0])?; - if !conn.state_matches(&ConnectionState::Open) { - return Err(Error::connection_not_open( - msg.channel.connection_hops()[0].clone(), - )); - } - - let get_versions = conn.versions(); - let version = match get_versions { - [version] => version, - _ => return Err(Error::invalid_version_length_connection()), - }; - - let channel_feature = msg.channel.ordering().to_string(); - if !version.is_supported_feature(channel_feature) { - return Err(Error::channel_feature_not_suported_by_connection()); - } - - // Proof verification in two steps: - // 1. Setup: build the Channel as we expect to find it on the other party. - // the port should be identical with the port we're using; the channel id should not be set - // since the counterparty cannot know yet which ID did we choose. - let expected_counterparty = Counterparty::new(msg.port_id.clone(), None); - let counterparty = conn.counterparty(); - let ccid = counterparty.connection_id().ok_or_else(|| { - Error::undefined_connection_counterparty(msg.channel.connection_hops()[0].clone()) - })?; - let expected_connection_hops = vec![ccid.clone()]; - - // The other party should be storing a channel end in this configuration. - let expected_channel_end = ChannelEnd::new( - State::Init, - *msg.channel.ordering(), - expected_counterparty, - expected_connection_hops, - msg.counterparty_version.clone(), - ); - - // 2. Actual proofs are verified now. - verify_channel_proofs( - ctx, - msg.proofs.height(), - &new_channel_end, - &conn, - &expected_channel_end, - &msg.proofs, - )?; - - output.log("success: channel open try "); - - // Transition the channel end to the new state & pick a version. - new_channel_end.set_state(State::TryOpen); - - let result = ChannelResult { - port_id: msg.port_id.clone(), - channel_id_state: if matches!(msg.previous_channel_id, None) { - ChannelIdState::Generated - } else { - ChannelIdState::Reused - }, - channel_id: channel_id.clone(), - channel_end: new_channel_end, - }; - - let event_attributes = Attributes { - channel_id: Some(channel_id), - ..Default::default() - }; - output.emit(IbcEvent::OpenTryChannel( - event_attributes - .try_into() - .map_err(|_| Error::missing_channel_id())?, - )); - - Ok(output.with_result(result)) -} - -#[cfg(test)] -mod tests { - use crate::prelude::*; - - use test_log::test; - - use crate::core::ics02_client::client_type::ClientType; - use crate::core::ics02_client::error as ics02_error; - use crate::core::ics03_connection::connection::ConnectionEnd; - use crate::core::ics03_connection::connection::Counterparty as ConnectionCounterparty; - use crate::core::ics03_connection::connection::State as ConnectionState; - use crate::core::ics03_connection::error as ics03_error; - use crate::core::ics03_connection::msgs::test_util::get_dummy_raw_counterparty; - use crate::core::ics03_connection::version::get_compatible_versions; - use crate::core::ics04_channel::channel::{ChannelEnd, State}; - use crate::core::ics04_channel::handler::channel_dispatch; - use crate::core::ics04_channel::msgs::chan_open_try::test_util::get_dummy_raw_msg_chan_open_try; - use crate::core::ics04_channel::msgs::chan_open_try::MsgChannelOpenTry; - use crate::core::ics04_channel::msgs::ChannelMsg; - use crate::core::ics04_channel::{error, Version}; - use crate::core::ics24_host::identifier::{ChannelId, ClientId, ConnectionId}; - use crate::events::IbcEvent; - use crate::mock::context::MockContext; - use crate::timestamp::ZERO_DURATION; - use crate::Height; - - #[test] - fn chan_open_try_msg_processing() { - struct Test { - name: String, - ctx: MockContext, - msg: ChannelMsg, - want_pass: bool, - match_error: Box, - } - - // Some general-purpose variable to parametrize the messages and the context. - let proof_height = 10; - let conn_id = ConnectionId::new(2); - let client_id = ClientId::new(ClientType::Mock, 45).unwrap(); - - // The context. We'll reuse this same one across all tests. - let context = MockContext::default(); - - // This is the connection underlying the channel we're trying to open. - let conn_end = ConnectionEnd::new( - ConnectionState::Open, - client_id.clone(), - ConnectionCounterparty::try_from(get_dummy_raw_counterparty()).unwrap(), - get_compatible_versions(), - ZERO_DURATION, - ); - - // We're going to test message processing against this message. - let mut msg = - MsgChannelOpenTry::try_from(get_dummy_raw_msg_chan_open_try(proof_height)).unwrap(); - - // Assumption: an already existing `Init` channel should exist in the context for `msg`, and - // this channel should depend on connection `conn_id`. - let chan_id = ChannelId::new(24); - let hops = vec![conn_id.clone()]; - msg.previous_channel_id = Some(chan_id.clone()); - msg.channel.connection_hops = hops; - - // This message does not assume a channel should already be initialized. - let mut msg_vanilla = msg.clone(); - msg_vanilla.previous_channel_id = None; - - // A preloaded channel end that resides in the context. This is constructed so as to be - // consistent with the incoming ChanOpenTry message `msg`. - let correct_chan_end = ChannelEnd::new( - State::Init, - *msg.channel.ordering(), - msg.channel.counterparty().clone(), - msg.channel.connection_hops().clone(), - msg.channel.version().clone(), - ); - - // A preloaded channel end that resides in the context. This is constructed so as to be - // __inconsistent__ with the incoming ChanOpenTry message `msg` due to its version field. - let version = Version::from(format!("{}-", msg.channel.version())); - let incorrect_chan_end_ver = ChannelEnd::new( - State::Init, - *msg.channel.ordering(), - msg.channel.counterparty().clone(), - msg.channel.connection_hops().clone(), - version, - ); - - // A preloaded channel end residing in the context, which will be __inconsistent__ with - // the incoming ChanOpenTry message `msg` due to its connection hops field. - let hops = vec![ConnectionId::new(9890)]; - let incorrect_chan_end_hops = ChannelEnd::new( - State::Init, - *msg.channel.ordering(), - msg.channel.counterparty().clone(), - hops, - msg.channel.version().clone(), - ); - - let tests: Vec = vec![ - Test { - name: "Processing fails because no channel is preloaded in the context".to_string(), - ctx: context.clone(), - msg: ChannelMsg::ChannelOpenTry(msg.clone()), - want_pass: false, - match_error: { - let port_id = msg.port_id.clone(); - let channel_id = chan_id.clone(); - Box::new(move |e| match e { - error::ErrorDetail::ChannelNotFound(e) => { - assert_eq!(e.port_id, port_id); - assert_eq!(e.channel_id, channel_id); - } - _ => { - panic!("Expected ChannelNotFound, instead got {}", e) - } - }) - }, - }, - Test { - name: "Processing fails because no connection exists in the context".to_string(), - ctx: context.clone(), - msg: ChannelMsg::ChannelOpenTry(msg_vanilla.clone()), - want_pass: false, - match_error: { - let connection_id = msg.channel.connection_hops()[0].clone(); - Box::new(move |e| match e { - error::ErrorDetail::Ics03Connection(e) => { - assert_eq!( - e.source, - ics03_error::ErrorDetail::ConnectionNotFound( - ics03_error::ConnectionNotFoundSubdetail { connection_id } - ) - ); - } - _ => { - panic!("Expected MissingConnection, instead got {}", e) - } - }) - }, - }, - Test { - name: "Processing fails because of inconsistent version with preexisting channel" - .to_string(), - ctx: context - .clone() - .with_connection(conn_id.clone(), conn_end.clone()) - .with_channel(msg.port_id.clone(), chan_id.clone(), incorrect_chan_end_ver), - msg: ChannelMsg::ChannelOpenTry(msg.clone()), - want_pass: false, - match_error: { - let channel_id = chan_id.clone(); - Box::new(move |e| match e { - error::ErrorDetail::ChannelMismatch(e) => { - assert_eq!(e.channel_id, channel_id); - } - _ => { - panic!("Expected ChannelMismatch, instead got {}", e) - } - }) - }, - }, - Test { - name: "Processing fails because of inconsistent connection hops".to_string(), - ctx: context - .clone() - .with_connection(conn_id.clone(), conn_end.clone()) - .with_channel( - msg.port_id.clone(), - chan_id.clone(), - incorrect_chan_end_hops, - ), - msg: ChannelMsg::ChannelOpenTry(msg.clone()), - want_pass: false, - match_error: { - let channel_id = chan_id.clone(); - Box::new(move |e| match e { - error::ErrorDetail::ChannelMismatch(e) => { - assert_eq!(e.channel_id, channel_id); - } - _ => { - panic!("Expected ChannelMismatch, instead got {}", e) - } - }) - }, - }, - Test { - name: "Processing fails b/c the context has no client state".to_string(), - ctx: context - .clone() - .with_connection(conn_id.clone(), conn_end.clone()) - .with_channel( - msg.port_id.clone(), - chan_id.clone(), - correct_chan_end.clone(), - ), - msg: ChannelMsg::ChannelOpenTry(msg.clone()), - want_pass: false, - match_error: Box::new(|e| match e { - error::ErrorDetail::Ics03Connection(e) => { - assert_eq!( - e.source, - ics03_error::ErrorDetail::Ics02Client( - ics03_error::Ics02ClientSubdetail { - source: ics02_error::ErrorDetail::ClientNotFound( - ics02_error::ClientNotFoundSubdetail { - client_id: ClientId::new(ClientType::Mock, 45).unwrap() - } - ) - } - ) - ); - } - _ => { - panic!("Expected MissingClientState, instead got {}", e) - } - }), - }, - Test { - name: "Processing is successful".to_string(), - ctx: context - .clone() - .with_client(&client_id, Height::new(0, proof_height).unwrap()) - .with_connection(conn_id.clone(), conn_end.clone()) - .with_channel(msg.port_id.clone(), chan_id, correct_chan_end), - msg: ChannelMsg::ChannelOpenTry(msg), - want_pass: true, - match_error: Box::new(|_| {}), - }, - Test { - name: "Processing is successful against an empty context (no preexisting channel)" - .to_string(), - ctx: context - .with_client(&client_id, Height::new(0, proof_height).unwrap()) - .with_connection(conn_id, conn_end), - msg: ChannelMsg::ChannelOpenTry(msg_vanilla), - want_pass: true, - match_error: Box::new(|_| {}), - }, - ] - .into_iter() - .collect(); - - for test in tests { - let res = channel_dispatch(&test.ctx, &test.msg); - // Additionally check the events and the output objects in the result. - match res { - Ok((proto_output, res)) => { - assert!( - test.want_pass, - "chan_open_ack: test passed but was supposed to fail for test: {}, \nparams {:?} {:?}", - test.name, - test.msg, - test.ctx.clone() - ); - - let proto_output = proto_output.with_result(()); - assert!(!proto_output.events.is_empty()); // Some events must exist. - - // The object in the output is a channel end, should have TryOpen state. - assert_eq!(res.channel_end.state().clone(), State::TryOpen); - - for e in proto_output.events.iter() { - assert!(matches!(e, &IbcEvent::OpenTryChannel(_))); - } - } - Err(e) => { - assert!( - !test.want_pass, - "chan_open_try: did not pass test: {}, \nparams:\n\tmsg={:?}\n\tcontext={:?}\nerror: {:?}", - test.name, - test.msg, - test.ctx.clone(), - e, - ); - - (test.match_error)(e.0); - } - } - } - } -} diff --git a/modules/src/core/ics04_channel/handler/recv_packet.rs b/modules/src/core/ics04_channel/handler/recv_packet.rs deleted file mode 100644 index 7c5ee58db1..0000000000 --- a/modules/src/core/ics04_channel/handler/recv_packet.rs +++ /dev/null @@ -1,305 +0,0 @@ -use crate::core::ics03_connection::connection::State as ConnectionState; -use crate::core::ics04_channel::channel::{Counterparty, Order, State}; -use crate::core::ics04_channel::context::ChannelReader; -use crate::core::ics04_channel::error::Error; -use crate::core::ics04_channel::events::ReceivePacket; -use crate::core::ics04_channel::handler::verify::verify_packet_recv_proofs; -use crate::core::ics04_channel::msgs::recv_packet::MsgRecvPacket; -use crate::core::ics04_channel::packet::{PacketResult, Receipt, Sequence}; -use crate::core::ics24_host::identifier::{ChannelId, PortId}; -use crate::events::IbcEvent; -use crate::handler::{HandlerOutput, HandlerResult}; -use crate::timestamp::Expiry; - -#[derive(Clone, Debug)] -pub enum RecvPacketResult { - NoOp, - Unordered { - port_id: PortId, - channel_id: ChannelId, - sequence: Sequence, - receipt: Receipt, - }, - Ordered { - port_id: PortId, - channel_id: ChannelId, - next_seq_recv: Sequence, - }, -} - -pub fn process( - ctx: &Ctx, - msg: &MsgRecvPacket, -) -> HandlerResult { - let mut output = HandlerOutput::builder(); - - let packet = &msg.packet; - - let dest_channel_end = - ctx.channel_end(&packet.destination_port, &packet.destination_channel)?; - - if !dest_channel_end.state_matches(&State::Open) { - return Err(Error::invalid_channel_state( - packet.source_channel.clone(), - dest_channel_end.state, - )); - } - - let counterparty = Counterparty::new( - packet.source_port.clone(), - Some(packet.source_channel.clone()), - ); - - if !dest_channel_end.counterparty_matches(&counterparty) { - return Err(Error::invalid_packet_counterparty( - packet.source_port.clone(), - packet.source_channel.clone(), - )); - } - - let connection_end = ctx.connection_end(&dest_channel_end.connection_hops()[0])?; - - if !connection_end.state_matches(&ConnectionState::Open) { - return Err(Error::connection_not_open( - dest_channel_end.connection_hops()[0].clone(), - )); - } - - let latest_height = ChannelReader::host_height(ctx); - if packet.timeout_height.has_expired(latest_height) { - return Err(Error::low_packet_height( - latest_height, - packet.timeout_height, - )); - } - - let latest_timestamp = ChannelReader::host_timestamp(ctx); - if let Expiry::Expired = latest_timestamp.check_expiry(&packet.timeout_timestamp) { - return Err(Error::low_packet_timestamp()); - } - - verify_packet_recv_proofs( - ctx, - msg.proofs.height(), - packet, - &connection_end, - &msg.proofs, - )?; - - let result = if dest_channel_end.order_matches(&Order::Ordered) { - let next_seq_recv = - ctx.get_next_sequence_recv(&packet.destination_port, &packet.destination_channel)?; - - if packet.sequence < next_seq_recv { - output.emit(IbcEvent::ReceivePacket(ReceivePacket { - packet: msg.packet.clone(), - })); - return Ok(output.with_result(PacketResult::Recv(RecvPacketResult::NoOp))); - } else if packet.sequence != next_seq_recv { - return Err(Error::invalid_packet_sequence( - packet.sequence, - next_seq_recv, - )); - } - - PacketResult::Recv(RecvPacketResult::Ordered { - port_id: packet.destination_port.clone(), - channel_id: packet.destination_channel.clone(), - next_seq_recv: next_seq_recv.increment(), - }) - } else { - let packet_rec = ctx.get_packet_receipt( - &packet.destination_port, - &packet.destination_channel, - packet.sequence, - ); - - match packet_rec { - Ok(_receipt) => { - output.emit(IbcEvent::ReceivePacket(ReceivePacket { - packet: msg.packet.clone(), - })); - return Ok(output.with_result(PacketResult::Recv(RecvPacketResult::NoOp))); - } - Err(e) if e.detail() == Error::packet_receipt_not_found(packet.sequence).detail() => { - // store a receipt that does not contain any data - PacketResult::Recv(RecvPacketResult::Unordered { - port_id: packet.destination_port.clone(), - channel_id: packet.destination_channel.clone(), - sequence: packet.sequence, - receipt: Receipt::Ok, - }) - } - Err(_) => return Err(Error::implementation_specific()), - } - }; - - output.log("success: packet receive"); - - output.emit(IbcEvent::ReceivePacket(ReceivePacket { - packet: msg.packet.clone(), - })); - - Ok(output.with_result(result)) -} - -#[cfg(test)] -mod tests { - use crate::prelude::*; - - use test_log::test; - - use crate::core::ics03_connection::connection::ConnectionEnd; - use crate::core::ics03_connection::connection::Counterparty as ConnectionCounterparty; - use crate::core::ics03_connection::connection::State as ConnectionState; - use crate::core::ics03_connection::version::get_compatible_versions; - use crate::core::ics04_channel::channel::{ChannelEnd, Counterparty, Order, State}; - use crate::core::ics04_channel::handler::recv_packet::process; - use crate::core::ics04_channel::msgs::recv_packet::test_util::get_dummy_raw_msg_recv_packet; - use crate::core::ics04_channel::msgs::recv_packet::MsgRecvPacket; - use crate::core::ics04_channel::Version; - use crate::core::ics24_host::identifier::{ChannelId, ClientId, ConnectionId, PortId}; - use crate::mock::context::MockContext; - use crate::relayer::ics18_relayer::context::Ics18Context; - use crate::test_utils::get_dummy_account_id; - use crate::timestamp::Timestamp; - use crate::timestamp::ZERO_DURATION; - use crate::{core::ics04_channel::packet::Packet, events::IbcEvent}; - - #[test] - fn recv_packet_processing() { - struct Test { - name: String, - ctx: MockContext, - msg: MsgRecvPacket, - want_pass: bool, - } - - let context = MockContext::default(); - - let host_height = context.query_latest_height().increment(); - - let client_height = host_height.increment(); - - let msg = MsgRecvPacket::try_from(get_dummy_raw_msg_recv_packet( - client_height.revision_height(), - )) - .unwrap(); - - let packet = msg.packet.clone(); - - let packet_old = Packet { - sequence: 1.into(), - source_port: PortId::default(), - source_channel: ChannelId::default(), - destination_port: PortId::default(), - destination_channel: ChannelId::default(), - data: Vec::new(), - timeout_height: client_height.into(), - timeout_timestamp: Timestamp::from_nanoseconds(1).unwrap(), - }; - - let msg_packet_old = - MsgRecvPacket::new(packet_old, msg.proofs.clone(), get_dummy_account_id()); - - let dest_channel_end = ChannelEnd::new( - State::Open, - Order::default(), - Counterparty::new(packet.source_port.clone(), Some(packet.source_channel)), - vec![ConnectionId::default()], - Version::ics20(), - ); - - let connection_end = ConnectionEnd::new( - ConnectionState::Open, - ClientId::default(), - ConnectionCounterparty::new( - ClientId::default(), - Some(ConnectionId::default()), - Default::default(), - ), - get_compatible_versions(), - ZERO_DURATION, - ); - - let tests: Vec = vec![ - Test { - name: "Processing fails because no channel exists in the context".to_string(), - ctx: context.clone(), - msg: msg.clone(), - want_pass: false, - }, - Test { - name: "Good parameters".to_string(), - ctx: context - .clone() - .with_client(&ClientId::default(), client_height) - .with_connection(ConnectionId::default(), connection_end.clone()) - .with_channel( - packet.destination_port.clone(), - packet.destination_channel.clone(), - dest_channel_end.clone(), - ) - .with_send_sequence( - packet.destination_port.clone(), - packet.destination_channel.clone(), - 1.into(), - ) - .with_height(host_height) - // This `with_recv_sequence` is required for ordered channels - .with_recv_sequence( - packet.destination_port.clone(), - packet.destination_channel.clone(), - packet.sequence, - ), - msg, - want_pass: true, - }, - Test { - name: "Packet timeout expired".to_string(), - ctx: context - .with_client(&ClientId::default(), client_height) - .with_connection(ConnectionId::default(), connection_end) - .with_channel(PortId::default(), ChannelId::default(), dest_channel_end) - .with_send_sequence(PortId::default(), ChannelId::default(), 1.into()) - .with_height(host_height), - msg: msg_packet_old, - want_pass: false, - }, - ] - .into_iter() - .collect(); - - for test in tests { - let res = process(&test.ctx, &test.msg); - // Additionally check the events and the output objects in the result. - match res { - Ok(proto_output) => { - assert!( - test.want_pass, - "recv_packet: test passed but was supposed to fail for test: {}, \nparams \n msg={:?}\nctx:{:?}", - test.name, - test.msg.clone(), - test.ctx.clone() - ); - - assert!(!proto_output.events.is_empty()); // Some events must exist. - - for e in proto_output.events.iter() { - assert!(matches!(e, &IbcEvent::ReceivePacket(_))); - } - } - Err(e) => { - assert!( - !test.want_pass, - "recv_packet: did not pass test: {}, \nparams \nmsg={:?}\nctx={:?}\nerror={:?}", - test.name, - test.msg.clone(), - test.ctx.clone(), - e, - ); - } - } - } - } -} diff --git a/modules/src/core/ics04_channel/handler/send_packet.rs b/modules/src/core/ics04_channel/handler/send_packet.rs deleted file mode 100644 index a2266a62c4..0000000000 --- a/modules/src/core/ics04_channel/handler/send_packet.rs +++ /dev/null @@ -1,271 +0,0 @@ -use crate::core::ics04_channel::channel::Counterparty; -use crate::core::ics04_channel::channel::State; -use crate::core::ics04_channel::commitment::PacketCommitment; -use crate::core::ics04_channel::events::SendPacket; -use crate::core::ics04_channel::packet::{PacketResult, Sequence}; -use crate::core::ics04_channel::{context::ChannelReader, error::Error, packet::Packet}; -use crate::core::ics24_host::identifier::{ChannelId, PortId}; -use crate::events::IbcEvent; -use crate::handler::{HandlerOutput, HandlerResult}; -use crate::prelude::*; -use crate::timestamp::Expiry; - -#[derive(Clone, Debug)] -pub struct SendPacketResult { - pub port_id: PortId, - pub channel_id: ChannelId, - pub seq: Sequence, - pub seq_number: Sequence, - pub commitment: PacketCommitment, -} - -pub fn send_packet(ctx: &dyn ChannelReader, packet: Packet) -> HandlerResult { - let mut output = HandlerOutput::builder(); - - let source_channel_end = ctx.channel_end(&packet.source_port, &packet.source_channel)?; - - if source_channel_end.state_matches(&State::Closed) { - return Err(Error::channel_closed(packet.source_channel)); - } - - let counterparty = Counterparty::new( - packet.destination_port.clone(), - Some(packet.destination_channel.clone()), - ); - - if !source_channel_end.counterparty_matches(&counterparty) { - return Err(Error::invalid_packet_counterparty( - packet.destination_port.clone(), - packet.destination_channel, - )); - } - - let connection_end = ctx.connection_end(&source_channel_end.connection_hops()[0])?; - - let client_id = connection_end.client_id().clone(); - - let client_state = ctx.client_state(&client_id)?; - - // prevent accidental sends with clients that cannot be updated - if client_state.is_frozen() { - return Err(Error::frozen_client(connection_end.client_id().clone())); - } - - let latest_height = client_state.latest_height(); - - if packet.timeout_height.has_expired(latest_height) { - return Err(Error::low_packet_height( - latest_height, - packet.timeout_height, - )); - } - - let consensus_state = ctx.client_consensus_state(&client_id, latest_height)?; - let latest_timestamp = consensus_state.timestamp(); - let packet_timestamp = packet.timeout_timestamp; - if let Expiry::Expired = latest_timestamp.check_expiry(&packet_timestamp) { - return Err(Error::low_packet_timestamp()); - } - - let next_seq_send = ctx.get_next_sequence_send(&packet.source_port, &packet.source_channel)?; - - if packet.sequence != next_seq_send { - return Err(Error::invalid_packet_sequence( - packet.sequence, - next_seq_send, - )); - } - - output.log("success: packet send "); - - let result = PacketResult::Send(SendPacketResult { - port_id: packet.source_port.clone(), - channel_id: packet.source_channel.clone(), - seq: packet.sequence, - seq_number: next_seq_send.increment(), - commitment: ctx.packet_commitment( - packet.data.clone(), - packet.timeout_height, - packet.timeout_timestamp, - ), - }); - - output.emit(IbcEvent::SendPacket(SendPacket { packet })); - - Ok(output.with_result(result)) -} - -#[cfg(test)] -mod tests { - use core::ops::Add; - use core::time::Duration; - - use test_log::test; - - use crate::core::ics02_client::height::Height; - use crate::core::ics03_connection::connection::ConnectionEnd; - use crate::core::ics03_connection::connection::Counterparty as ConnectionCounterparty; - use crate::core::ics03_connection::connection::State as ConnectionState; - use crate::core::ics03_connection::version::get_compatible_versions; - use crate::core::ics04_channel::channel::{ChannelEnd, Counterparty, Order, State}; - use crate::core::ics04_channel::handler::send_packet::send_packet; - use crate::core::ics04_channel::packet::test_utils::get_dummy_raw_packet; - use crate::core::ics04_channel::packet::Packet; - use crate::core::ics04_channel::Version; - use crate::core::ics24_host::identifier::{ChannelId, ClientId, ConnectionId, PortId}; - use crate::events::IbcEvent; - use crate::mock::context::MockContext; - use crate::prelude::*; - use crate::timestamp::Timestamp; - use crate::timestamp::ZERO_DURATION; - - #[test] - fn send_packet_processing() { - struct Test { - name: String, - ctx: MockContext, - packet: Packet, - want_pass: bool, - } - - let context = MockContext::default(); - - let channel_end = ChannelEnd::new( - State::TryOpen, - Order::default(), - Counterparty::new(PortId::default(), Some(ChannelId::default())), - vec![ConnectionId::default()], - Version::ics20(), - ); - - let connection_end = ConnectionEnd::new( - ConnectionState::Open, - ClientId::default(), - ConnectionCounterparty::new( - ClientId::default(), - Some(ConnectionId::default()), - Default::default(), - ), - get_compatible_versions(), - ZERO_DURATION, - ); - - let timestamp_future = Timestamp::now().add(Duration::from_secs(10)).unwrap(); - let timestamp_ns_past = 1; - - let timeout_height_future = 10; - - let mut packet: Packet = - get_dummy_raw_packet(timeout_height_future, timestamp_future.nanoseconds()) - .try_into() - .unwrap(); - packet.sequence = 1.into(); - packet.data = vec![0]; - - let mut packet_with_timestamp_old: Packet = - get_dummy_raw_packet(timeout_height_future, timestamp_ns_past) - .try_into() - .unwrap(); - packet_with_timestamp_old.sequence = 1.into(); - packet_with_timestamp_old.data = vec![0]; - - let client_raw_height = 5; - let packet_timeout_equal_client_height: Packet = - get_dummy_raw_packet(client_raw_height, timestamp_future.nanoseconds()) - .try_into() - .unwrap(); - let packet_timeout_one_before_client_height: Packet = - get_dummy_raw_packet(client_raw_height - 1, timestamp_future.nanoseconds()) - .try_into() - .unwrap(); - - let client_height = Height::new(0, client_raw_height).unwrap(); - - let tests: Vec = vec![ - Test { - name: "Processing fails because no channel exists in the context".to_string(), - ctx: context.clone(), - packet: packet.clone(), - want_pass: false, - }, - Test { - name: "Good parameters".to_string(), - ctx: context - .clone() - .with_client(&ClientId::default(), client_height) - .with_connection(ConnectionId::default(), connection_end.clone()) - .with_channel(PortId::default(), ChannelId::default(), channel_end.clone()) - .with_send_sequence(PortId::default(), ChannelId::default(), 1.into()), - packet, - want_pass: true, - }, - Test { - name: "Packet timeout height same as destination chain height".to_string(), - ctx: context - .clone() - .with_client(&ClientId::default(), client_height) - .with_connection(ConnectionId::default(), connection_end.clone()) - .with_channel(PortId::default(), ChannelId::default(), channel_end.clone()) - .with_send_sequence(PortId::default(), ChannelId::default(), 1.into()), - packet: packet_timeout_equal_client_height, - want_pass: true, - }, - Test { - name: "Packet timeout height one more than destination chain height".to_string(), - ctx: context - .clone() - .with_client(&ClientId::default(), client_height) - .with_connection(ConnectionId::default(), connection_end.clone()) - .with_channel(PortId::default(), ChannelId::default(), channel_end.clone()) - .with_send_sequence(PortId::default(), ChannelId::default(), 1.into()), - packet: packet_timeout_one_before_client_height, - want_pass: false, - }, - Test { - name: "Packet timeout due to timestamp".to_string(), - ctx: context - .with_client(&ClientId::default(), client_height) - .with_connection(ConnectionId::default(), connection_end) - .with_channel(PortId::default(), ChannelId::default(), channel_end) - .with_send_sequence(PortId::default(), ChannelId::default(), 1.into()), - packet: packet_with_timestamp_old, - want_pass: false, - }, - ] - .into_iter() - .collect(); - - for test in tests { - let res = send_packet(&test.ctx, test.packet.clone()); - // Additionally check the events and the output objects in the result. - match res { - Ok(proto_output) => { - assert!( - test.want_pass, - "send_packet: test passed but was supposed to fail for test: {}, \nparams {:?} {:?}", - test.name, - test.packet.clone(), - test.ctx.clone() - ); - - assert!(!proto_output.events.is_empty()); // Some events must exist. - - // TODO: The object in the output is a PacketResult what can we check on it? - for e in proto_output.events.iter() { - assert!(matches!(e, &IbcEvent::SendPacket(_))); - } - } - Err(e) => { - assert!( - !test.want_pass, - "send_packet: did not pass test: {}, \nparams {:?} {:?} error: {:?}", - test.name, - test.packet.clone(), - test.ctx.clone(), - e, - ); - } - } - } - } -} diff --git a/modules/src/core/ics04_channel/handler/timeout.rs b/modules/src/core/ics04_channel/handler/timeout.rs deleted file mode 100644 index 5f1badfd59..0000000000 --- a/modules/src/core/ics04_channel/handler/timeout.rs +++ /dev/null @@ -1,335 +0,0 @@ -use crate::core::ics04_channel::channel::State; -use crate::core::ics04_channel::channel::{ChannelEnd, Counterparty, Order}; -use crate::core::ics04_channel::events::TimeoutPacket; -use crate::core::ics04_channel::handler::verify::{ - verify_next_sequence_recv, verify_packet_receipt_absence, -}; -use crate::core::ics04_channel::msgs::timeout::MsgTimeout; -use crate::core::ics04_channel::packet::{PacketResult, Sequence}; -use crate::core::ics04_channel::{context::ChannelReader, error::Error}; -use crate::core::ics24_host::identifier::{ChannelId, PortId}; -use crate::events::IbcEvent; -use crate::handler::{HandlerOutput, HandlerResult}; -use crate::prelude::*; -use crate::timestamp::Expiry; - -#[derive(Clone, Debug)] -pub struct TimeoutPacketResult { - pub port_id: PortId, - pub channel_id: ChannelId, - pub seq: Sequence, - pub channel: Option, -} - -/// TimeoutPacket is called by a module which originally attempted to send a -/// packet to a counterparty module, where the timeout height has passed on the -/// counterparty chain without the packet being committed, to prove that the -/// packet can no longer be executed and to allow the calling module to safely -/// perform appropriate state transitions. -pub fn process( - ctx: &Ctx, - msg: &MsgTimeout, -) -> HandlerResult { - let mut output = HandlerOutput::builder(); - - let packet = &msg.packet; - - let mut source_channel_end = ctx.channel_end(&packet.source_port, &packet.source_channel)?; - - if !source_channel_end.state_matches(&State::Open) { - return Err(Error::channel_closed(packet.source_channel.clone())); - } - - let counterparty = Counterparty::new( - packet.destination_port.clone(), - Some(packet.destination_channel.clone()), - ); - - if !source_channel_end.counterparty_matches(&counterparty) { - return Err(Error::invalid_packet_counterparty( - packet.destination_port.clone(), - packet.destination_channel.clone(), - )); - } - - let connection_end = ctx.connection_end(&source_channel_end.connection_hops()[0])?; - - let client_id = connection_end.client_id().clone(); - - // check that timeout height or timeout timestamp has passed on the other end - let proof_height = msg.proofs.height(); - - if packet.timeout_height.has_expired(proof_height) { - return Err(Error::packet_timeout_height_not_reached( - packet.timeout_height, - proof_height, - )); - } - - let consensus_state = ctx.client_consensus_state(&client_id, proof_height)?; - - let proof_timestamp = consensus_state.timestamp(); - - let packet_timestamp = packet.timeout_timestamp; - if let Expiry::Expired = packet_timestamp.check_expiry(&proof_timestamp) { - return Err(Error::packet_timeout_timestamp_not_reached( - packet_timestamp, - proof_timestamp, - )); - } - - //verify packet commitment - let packet_commitment = - ctx.get_packet_commitment(&packet.source_port, &packet.source_channel, packet.sequence)?; - - let expected_commitment = ctx.packet_commitment( - packet.data.clone(), - packet.timeout_height, - packet.timeout_timestamp, - ); - if packet_commitment != expected_commitment { - return Err(Error::incorrect_packet_commitment(packet.sequence)); - } - - let result = if source_channel_end.order_matches(&Order::Ordered) { - if packet.sequence < msg.next_sequence_recv { - return Err(Error::invalid_packet_sequence( - packet.sequence, - msg.next_sequence_recv, - )); - } - verify_next_sequence_recv( - ctx, - msg.proofs.height(), - &connection_end, - packet.clone(), - msg.next_sequence_recv, - &msg.proofs, - )?; - - source_channel_end.state = State::Closed; - PacketResult::Timeout(TimeoutPacketResult { - port_id: packet.source_port.clone(), - channel_id: packet.source_channel.clone(), - seq: packet.sequence, - channel: Some(source_channel_end), - }) - } else { - verify_packet_receipt_absence( - ctx, - msg.proofs.height(), - &connection_end, - packet.clone(), - &msg.proofs, - )?; - - PacketResult::Timeout(TimeoutPacketResult { - port_id: packet.source_port.clone(), - channel_id: packet.source_channel.clone(), - seq: packet.sequence, - channel: None, - }) - }; - - output.log("success: packet timeout "); - - output.emit(IbcEvent::TimeoutPacket(TimeoutPacket { - packet: packet.clone(), - })); - - Ok(output.with_result(result)) -} - -#[cfg(test)] -mod tests { - use test_log::test; - - use crate::core::ics02_client::height::Height; - use crate::core::ics03_connection::connection::ConnectionEnd; - use crate::core::ics03_connection::connection::Counterparty as ConnectionCounterparty; - use crate::core::ics03_connection::connection::State as ConnectionState; - use crate::core::ics03_connection::version::get_compatible_versions; - use crate::core::ics04_channel::channel::{ChannelEnd, Counterparty, Order, State}; - use crate::core::ics04_channel::context::ChannelReader; - use crate::core::ics04_channel::handler::timeout::process; - use crate::core::ics04_channel::msgs::timeout::test_util::get_dummy_raw_msg_timeout; - use crate::core::ics04_channel::msgs::timeout::MsgTimeout; - use crate::core::ics04_channel::Version; - use crate::core::ics24_host::identifier::{ChannelId, ClientId, ConnectionId, PortId}; - use crate::events::IbcEvent; - use crate::mock::context::MockContext; - use crate::prelude::*; - use crate::timestamp::ZERO_DURATION; - - #[test] - fn timeout_packet_processing() { - struct Test { - name: String, - ctx: MockContext, - msg: MsgTimeout, - want_pass: bool, - } - - let context = MockContext::default(); - - let msg_proof_height = 2; - let msg_timeout_height = 5; - let timeout_timestamp = 5; - - let client_height = Height::new(0, 2).unwrap(); - - let msg = MsgTimeout::try_from(get_dummy_raw_msg_timeout( - msg_proof_height, - msg_timeout_height, - timeout_timestamp, - )) - .unwrap(); - let packet = msg.packet.clone(); - - let mut msg_ok = msg.clone(); - msg_ok.packet.timeout_timestamp = Default::default(); - - let data = context.packet_commitment( - msg_ok.packet.data.clone(), - msg_ok.packet.timeout_height, - msg_ok.packet.timeout_timestamp, - ); - - let source_channel_end = ChannelEnd::new( - State::Open, - Order::default(), - Counterparty::new( - packet.destination_port.clone(), - Some(packet.destination_channel.clone()), - ), - vec![ConnectionId::default()], - Version::ics20(), - ); - - let mut source_ordered_channel_end = source_channel_end.clone(); - source_ordered_channel_end.ordering = Order::Ordered; - - let connection_end = ConnectionEnd::new( - ConnectionState::Open, - ClientId::default(), - ConnectionCounterparty::new( - ClientId::default(), - Some(ConnectionId::default()), - Default::default(), - ), - get_compatible_versions(), - ZERO_DURATION, - ); - - let tests: Vec = vec![ - Test { - name: "Processing fails because no channel exists in the context".to_string(), - ctx: context.clone(), - msg: msg.clone(), - want_pass: false, - }, - Test { - name: "Processing fails because the client does not have a consensus state for the required height" - .to_string(), - ctx: context.clone().with_channel( - PortId::default(), - ChannelId::default(), - source_channel_end.clone(), - ) - .with_connection(ConnectionId::default(), connection_end.clone()), - msg: msg.clone(), - want_pass: false, - }, - Test { - name: "Processing fails because the proof's timeout has not been reached " - .to_string(), - ctx: context.clone().with_channel( - PortId::default(), - ChannelId::default(), - source_channel_end.clone(), - ) - .with_client(&ClientId::default(), client_height) - .with_connection(ConnectionId::default(), connection_end.clone()), - msg, - want_pass: false, - }, - Test { - name: "Good parameters Unordered channel".to_string(), - ctx: context.clone() - .with_client(&ClientId::default(), client_height) - .with_connection(ConnectionId::default(), connection_end.clone()) - .with_channel( - packet.source_port.clone(), - packet.source_channel.clone(), - source_channel_end, - ) - .with_packet_commitment( - msg_ok.packet.source_port.clone(), - msg_ok.packet.source_channel.clone(), - msg_ok.packet.sequence, - data.clone(), - ), - msg: msg_ok.clone(), - want_pass: true, - }, - Test { - name: "Good parameters Ordered Channel".to_string(), - ctx: context - .with_client(&ClientId::default(), client_height) - .with_connection(ConnectionId::default(), connection_end) - .with_channel( - packet.source_port.clone(), - packet.source_channel, - source_ordered_channel_end, - ) - .with_packet_commitment( - msg_ok.packet.source_port.clone(), - msg_ok.packet.source_channel.clone(), - msg_ok.packet.sequence, - data, - ) - .with_ack_sequence( - packet.destination_port, - packet.destination_channel, - 1.into(), - ), - msg: msg_ok, - want_pass: true, - }, - ] - .into_iter() - .collect(); - - for test in tests { - let res = process(&test.ctx, &test.msg); - // Additionally check the events and the output objects in the result. - match res { - Ok(proto_output) => { - assert!( - test.want_pass, - "TO_packet: test passed but was supposed to fail for test: {}, \nparams {:?} {:?}", - test.name, - test.msg.clone(), - test.ctx.clone() - ); - - assert!(!proto_output.events.is_empty()); // Some events must exist. - - for e in proto_output.events.iter() { - assert!(matches!(e, &IbcEvent::TimeoutPacket(_))); - } - } - Err(e) => { - assert!( - !test.want_pass, - "timeout_packet: did not pass test: {}, \nparams {:?} {:?} error: {:?}", - test.name, - test.msg.clone(), - test.ctx.clone(), - e, - ); - } - } - } - } -} diff --git a/modules/src/core/ics04_channel/handler/timeout_on_close.rs b/modules/src/core/ics04_channel/handler/timeout_on_close.rs deleted file mode 100644 index f00d8bf7c6..0000000000 --- a/modules/src/core/ics04_channel/handler/timeout_on_close.rs +++ /dev/null @@ -1,286 +0,0 @@ -use crate::core::ics04_channel::channel::State; -use crate::core::ics04_channel::channel::{ChannelEnd, Counterparty, Order}; -use crate::core::ics04_channel::events::TimeoutOnClosePacket; -use crate::core::ics04_channel::handler::verify::verify_channel_proofs; -use crate::core::ics04_channel::handler::verify::{ - verify_next_sequence_recv, verify_packet_receipt_absence, -}; -use crate::core::ics04_channel::msgs::timeout_on_close::MsgTimeoutOnClose; -use crate::core::ics04_channel::packet::PacketResult; -use crate::core::ics04_channel::{ - context::ChannelReader, error::Error, handler::timeout::TimeoutPacketResult, -}; -use crate::events::IbcEvent; -use crate::handler::{HandlerOutput, HandlerResult}; -use crate::prelude::*; -use crate::proofs::{ProofError, Proofs}; - -pub fn process( - ctx: &Ctx, - msg: &MsgTimeoutOnClose, -) -> HandlerResult { - let mut output = HandlerOutput::builder(); - - let packet = &msg.packet; - - let source_channel_end = ctx.channel_end(&packet.source_port, &packet.source_channel)?; - - let counterparty = Counterparty::new( - packet.destination_port.clone(), - Some(packet.destination_channel.clone()), - ); - - if !source_channel_end.counterparty_matches(&counterparty) { - return Err(Error::invalid_packet_counterparty( - packet.destination_port.clone(), - packet.destination_channel.clone(), - )); - } - - let connection_end = ctx.connection_end(&source_channel_end.connection_hops()[0])?; - - //verify the packet was sent, check the store - let packet_commitment = - ctx.get_packet_commitment(&packet.source_port, &packet.source_channel, packet.sequence)?; - - let expected_commitment = ctx.packet_commitment( - packet.data.clone(), - packet.timeout_height, - packet.timeout_timestamp, - ); - if packet_commitment != expected_commitment { - return Err(Error::incorrect_packet_commitment(packet.sequence)); - } - - let expected_counterparty = Counterparty::new( - packet.source_port.clone(), - Some(packet.source_channel.clone()), - ); - - let counterparty = connection_end.counterparty(); - let ccid = counterparty.connection_id().ok_or_else(|| { - Error::undefined_connection_counterparty(source_channel_end.connection_hops()[0].clone()) - })?; - - let expected_connection_hops = vec![ccid.clone()]; - - let expected_channel_end = ChannelEnd::new( - State::Closed, - *source_channel_end.ordering(), - expected_counterparty, - expected_connection_hops, - source_channel_end.version().clone(), - ); - - // The message's proofs have the channel proof as `other_proof` - let proof_close = match msg.proofs.other_proof() { - Some(p) => p.clone(), - None => return Err(Error::invalid_proof(ProofError::empty_proof())), - }; - let proofs = Proofs::new(proof_close, None, None, None, msg.proofs.height()) - .map_err(Error::invalid_proof)?; - verify_channel_proofs( - ctx, - msg.proofs.height(), - &source_channel_end, - &connection_end, - &expected_channel_end, - &proofs, - )?; - - let result = if source_channel_end.order_matches(&Order::Ordered) { - if packet.sequence < msg.next_sequence_recv { - return Err(Error::invalid_packet_sequence( - packet.sequence, - msg.next_sequence_recv, - )); - } - verify_next_sequence_recv( - ctx, - msg.proofs.height(), - &connection_end, - packet.clone(), - msg.next_sequence_recv, - &msg.proofs, - )?; - - PacketResult::Timeout(TimeoutPacketResult { - port_id: packet.source_port.clone(), - channel_id: packet.source_channel.clone(), - seq: packet.sequence, - channel: Some(source_channel_end), - }) - } else { - verify_packet_receipt_absence( - ctx, - msg.proofs.height(), - &connection_end, - packet.clone(), - &msg.proofs, - )?; - - PacketResult::Timeout(TimeoutPacketResult { - port_id: packet.source_port.clone(), - channel_id: packet.source_channel.clone(), - seq: packet.sequence, - channel: None, - }) - }; - - output.log("success: packet timeout "); - - output.emit(IbcEvent::TimeoutOnClosePacket(TimeoutOnClosePacket { - packet: packet.clone(), - })); - - Ok(output.with_result(result)) -} - -#[cfg(test)] -mod tests { - use test_log::test; - - use crate::core::ics02_client::height::Height; - use crate::core::ics03_connection::connection::ConnectionEnd; - use crate::core::ics03_connection::connection::Counterparty as ConnectionCounterparty; - use crate::core::ics03_connection::connection::State as ConnectionState; - use crate::core::ics03_connection::version::get_compatible_versions; - use crate::core::ics04_channel::channel::{ChannelEnd, Counterparty, Order, State}; - use crate::core::ics04_channel::context::ChannelReader; - use crate::core::ics04_channel::handler::timeout_on_close::process; - use crate::core::ics04_channel::msgs::timeout_on_close::test_util::get_dummy_raw_msg_timeout_on_close; - use crate::core::ics04_channel::msgs::timeout_on_close::MsgTimeoutOnClose; - use crate::core::ics04_channel::Version; - use crate::core::ics24_host::identifier::{ChannelId, ClientId, ConnectionId, PortId}; - use crate::events::IbcEvent; - use crate::mock::context::MockContext; - use crate::prelude::*; - use crate::timestamp::ZERO_DURATION; - - #[test] - fn timeout_on_close_packet_processing() { - struct Test { - name: String, - ctx: MockContext, - msg: MsgTimeoutOnClose, - want_pass: bool, - } - - let context = MockContext::default(); - - let height = 2; - let timeout_timestamp = 5; - - let client_height = Height::new(0, 2).unwrap(); - - let msg = MsgTimeoutOnClose::try_from(get_dummy_raw_msg_timeout_on_close( - height, - timeout_timestamp, - )) - .unwrap(); - let packet = msg.packet.clone(); - - let data = context.packet_commitment( - msg.packet.data.clone(), - msg.packet.timeout_height, - msg.packet.timeout_timestamp, - ); - - let source_channel_end = ChannelEnd::new( - State::Open, - Order::Ordered, - Counterparty::new( - packet.destination_port.clone(), - Some(packet.destination_channel), - ), - vec![ConnectionId::default()], - Version::ics20(), - ); - - let connection_end = ConnectionEnd::new( - ConnectionState::Open, - ClientId::default(), - ConnectionCounterparty::new( - ClientId::default(), - Some(ConnectionId::default()), - Default::default(), - ), - get_compatible_versions(), - ZERO_DURATION, - ); - - let tests: Vec = vec![ - Test { - name: "Processing fails because no channel exists in the context".to_string(), - ctx: context.clone(), - msg: msg.clone(), - want_pass: false, - }, - Test { - name: "Processing fails no packet commitment is found".to_string(), - ctx: context - .clone() - .with_channel( - PortId::default(), - ChannelId::default(), - source_channel_end.clone(), - ) - .with_connection(ConnectionId::default(), connection_end.clone()), - msg: msg.clone(), - want_pass: false, - }, - Test { - name: "Good parameters".to_string(), - ctx: context - .with_client(&ClientId::default(), client_height) - .with_connection(ConnectionId::default(), connection_end) - .with_channel( - packet.source_port, - packet.source_channel, - source_channel_end, - ) - .with_packet_commitment( - msg.packet.source_port.clone(), - msg.packet.source_channel.clone(), - msg.packet.sequence, - data, - ), - msg, - want_pass: true, - }, - ] - .into_iter() - .collect(); - - for test in tests { - let res = process(&test.ctx, &test.msg); - // Additionally check the events and the output objects in the result. - match res { - Ok(proto_output) => { - assert!( - test.want_pass, - "TO_on_close_packet: test passed but was supposed to fail for test: {}, \nparams {:?} {:?}", - test.name, - test.msg.clone(), - test.ctx.clone() - ); - - assert!(!proto_output.events.is_empty()); // Some events must exist. - for e in proto_output.events.iter() { - assert!(matches!(e, &IbcEvent::TimeoutOnClosePacket(_))); - } - } - Err(e) => { - assert!( - !test.want_pass, - "timeout_packet: did not pass test: {}, \nparams {:?} {:?} error: {:?}", - test.name, - test.msg.clone(), - test.ctx.clone(), - e, - ); - } - } - } - } -} diff --git a/modules/src/core/ics04_channel/handler/verify.rs b/modules/src/core/ics04_channel/handler/verify.rs deleted file mode 100644 index 7ae31dc1f9..0000000000 --- a/modules/src/core/ics04_channel/handler/verify.rs +++ /dev/null @@ -1,196 +0,0 @@ -use crate::core::ics03_connection::connection::ConnectionEnd; -use crate::core::ics04_channel::channel::ChannelEnd; -use crate::core::ics04_channel::context::ChannelReader; -use crate::core::ics04_channel::error::Error; -use crate::core::ics04_channel::msgs::acknowledgement::Acknowledgement; -use crate::core::ics04_channel::packet::{Packet, Sequence}; -use crate::prelude::*; -use crate::proofs::Proofs; -use crate::Height; - -/// Entry point for verifying all proofs bundled in any ICS4 message for channel protocols. -pub fn verify_channel_proofs( - ctx: &Ctx, - height: Height, - channel_end: &ChannelEnd, - connection_end: &ConnectionEnd, - expected_chan: &ChannelEnd, - proofs: &Proofs, -) -> Result<(), Error> { - // This is the client which will perform proof verification. - let client_id = connection_end.client_id().clone(); - - let client_state = ctx.client_state(&client_id)?; - - // The client must not be frozen. - if client_state.is_frozen() { - return Err(Error::frozen_client(client_id)); - } - - let consensus_state = ctx.client_consensus_state(&client_id, proofs.height())?; - - // Verify the proof for the channel state against the expected channel end. - // A counterparty channel id of None in not possible, and is checked by validate_basic in msg. - client_state - .verify_channel_state( - height, - connection_end.counterparty().prefix(), - proofs.object_proof(), - consensus_state.root(), - channel_end.counterparty().port_id(), - channel_end.counterparty().channel_id().unwrap(), - expected_chan, - ) - .map_err(Error::verify_channel_failed) -} - -/// Entry point for verifying all proofs bundled in a ICS4 packet recv. message. -pub fn verify_packet_recv_proofs( - ctx: &Ctx, - height: Height, - packet: &Packet, - connection_end: &ConnectionEnd, - proofs: &Proofs, -) -> Result<(), Error> { - let client_id = connection_end.client_id(); - let client_state = ctx.client_state(client_id)?; - - // The client must not be frozen. - if client_state.is_frozen() { - return Err(Error::frozen_client(client_id.clone())); - } - - let consensus_state = ctx.client_consensus_state(client_id, proofs.height())?; - - let commitment = ctx.packet_commitment( - packet.data.clone(), - packet.timeout_height, - packet.timeout_timestamp, - ); - - // Verify the proof for the packet against the chain store. - client_state - .verify_packet_data( - ctx, - height, - connection_end, - proofs.object_proof(), - consensus_state.root(), - &packet.source_port, - &packet.source_channel, - packet.sequence, - commitment, - ) - .map_err(|e| Error::packet_verification_failed(packet.sequence, e))?; - - Ok(()) -} - -/// Entry point for verifying all proofs bundled in an ICS4 packet ack message. -pub fn verify_packet_acknowledgement_proofs( - ctx: &Ctx, - height: Height, - packet: &Packet, - acknowledgement: Acknowledgement, - connection_end: &ConnectionEnd, - proofs: &Proofs, -) -> Result<(), Error> { - let client_id = connection_end.client_id(); - let client_state = ctx.client_state(client_id)?; - - // The client must not be frozen. - if client_state.is_frozen() { - return Err(Error::frozen_client(client_id.clone())); - } - - let consensus_state = ctx.client_consensus_state(client_id, proofs.height())?; - - let ack_commitment = ctx.ack_commitment(acknowledgement); - - // Verify the proof for the packet against the chain store. - client_state - .verify_packet_acknowledgement( - ctx, - height, - connection_end, - proofs.object_proof(), - consensus_state.root(), - &packet.destination_port, - &packet.destination_channel, - packet.sequence, - ack_commitment, - ) - .map_err(|e| Error::packet_verification_failed(packet.sequence, e))?; - - Ok(()) -} - -/// Entry point for verifying all timeout proofs. -pub fn verify_next_sequence_recv( - ctx: &Ctx, - height: Height, - connection_end: &ConnectionEnd, - packet: Packet, - seq: Sequence, - proofs: &Proofs, -) -> Result<(), Error> { - let client_id = connection_end.client_id(); - let client_state = ctx.client_state(client_id)?; - - // The client must not be frozen. - if client_state.is_frozen() { - return Err(Error::frozen_client(client_id.clone())); - } - - let consensus_state = ctx.client_consensus_state(client_id, proofs.height())?; - - // Verify the proof for the packet against the chain store. - client_state - .verify_next_sequence_recv( - ctx, - height, - connection_end, - proofs.object_proof(), - consensus_state.root(), - &packet.destination_port, - &packet.destination_channel, - packet.sequence, - ) - .map_err(|e| Error::packet_verification_failed(seq, e))?; - - Ok(()) -} - -pub fn verify_packet_receipt_absence( - ctx: &Ctx, - height: Height, - connection_end: &ConnectionEnd, - packet: Packet, - proofs: &Proofs, -) -> Result<(), Error> { - let client_id = connection_end.client_id(); - let client_state = ctx.client_state(client_id)?; - - // The client must not be frozen. - if client_state.is_frozen() { - return Err(Error::frozen_client(client_id.clone())); - } - - let consensus_state = ctx.client_consensus_state(client_id, proofs.height())?; - - // Verify the proof for the packet against the chain store. - client_state - .verify_packet_receipt_absence( - ctx, - height, - connection_end, - proofs.object_proof(), - consensus_state.root(), - &packet.destination_port, - &packet.destination_channel, - packet.sequence, - ) - .map_err(|e| Error::packet_verification_failed(packet.sequence, e))?; - - Ok(()) -} diff --git a/modules/src/core/ics04_channel/handler/write_acknowledgement.rs b/modules/src/core/ics04_channel/handler/write_acknowledgement.rs deleted file mode 100644 index 60c24f39af..0000000000 --- a/modules/src/core/ics04_channel/handler/write_acknowledgement.rs +++ /dev/null @@ -1,207 +0,0 @@ -use crate::core::ics04_channel::channel::State; -use crate::core::ics04_channel::commitment::AcknowledgementCommitment; -use crate::core::ics04_channel::events::WriteAcknowledgement; -use crate::core::ics04_channel::msgs::acknowledgement::Acknowledgement; -use crate::core::ics04_channel::packet::{Packet, PacketResult, Sequence}; -use crate::core::ics04_channel::{context::ChannelReader, error::Error}; -use crate::core::ics24_host::identifier::{ChannelId, PortId}; -use crate::prelude::*; -use crate::{ - events::IbcEvent, - handler::{HandlerOutput, HandlerResult}, -}; - -#[derive(Clone, Debug)] -pub struct WriteAckPacketResult { - pub port_id: PortId, - pub channel_id: ChannelId, - pub seq: Sequence, - pub ack_commitment: AcknowledgementCommitment, -} - -pub fn process( - ctx: &Ctx, - packet: Packet, - ack: Acknowledgement, -) -> HandlerResult { - let mut output = HandlerOutput::builder(); - - let dest_channel_end = - ctx.channel_end(&packet.destination_port, &packet.destination_channel)?; - - if !dest_channel_end.state_matches(&State::Open) { - return Err(Error::invalid_channel_state( - packet.source_channel, - dest_channel_end.state, - )); - } - - // NOTE: IBC app modules might have written the acknowledgement synchronously on - // the OnRecvPacket callback so we need to check if the acknowledgement is already - // set on the store and return an error if so. - match ctx.get_packet_acknowledgement( - &packet.destination_port, - &packet.destination_channel, - packet.sequence, - ) { - Ok(_) => return Err(Error::acknowledgement_exists(packet.sequence)), - Err(e) - if e.detail() == Error::packet_acknowledgement_not_found(packet.sequence).detail() => {} - Err(e) => return Err(e), - } - - if ack.is_empty() { - return Err(Error::invalid_acknowledgement()); - } - - let result = PacketResult::WriteAck(WriteAckPacketResult { - port_id: packet.destination_port.clone(), - channel_id: packet.destination_channel.clone(), - seq: packet.sequence, - ack_commitment: ctx.ack_commitment(ack.clone()), - }); - - output.log("success: packet write acknowledgement"); - - output.emit(IbcEvent::WriteAcknowledgement(WriteAcknowledgement { - packet, - ack: ack.into(), - })); - - Ok(output.with_result(result)) -} - -#[cfg(test)] -mod tests { - use crate::prelude::*; - - use test_log::test; - - use crate::core::ics02_client::height::Height; - use crate::core::ics03_connection::connection::ConnectionEnd; - use crate::core::ics03_connection::connection::Counterparty as ConnectionCounterparty; - use crate::core::ics03_connection::connection::State as ConnectionState; - use crate::core::ics03_connection::version::get_compatible_versions; - use crate::core::ics04_channel::channel::{ChannelEnd, Counterparty, Order, State}; - use crate::core::ics04_channel::handler::write_acknowledgement::process; - use crate::core::ics04_channel::packet::test_utils::get_dummy_raw_packet; - use crate::core::ics04_channel::Version; - use crate::core::ics24_host::identifier::{ChannelId, ClientId, ConnectionId, PortId}; - use crate::mock::context::MockContext; - use crate::timestamp::ZERO_DURATION; - use crate::{core::ics04_channel::packet::Packet, events::IbcEvent}; - - #[test] - fn write_ack_packet_processing() { - struct Test { - name: String, - ctx: MockContext, - packet: Packet, - ack: Vec, - want_pass: bool, - } - - let context = MockContext::default(); - - let client_height = Height::new(0, 1).unwrap(); - - let mut packet: Packet = get_dummy_raw_packet(1, 6).try_into().unwrap(); - packet.sequence = 1.into(); - packet.data = vec![0]; - - let ack = vec![0]; - let ack_null = Vec::new(); - - let dest_channel_end = ChannelEnd::new( - State::Open, - Order::default(), - Counterparty::new( - packet.source_port.clone(), - Some(packet.source_channel.clone()), - ), - vec![ConnectionId::default()], - Version::ics20(), - ); - - let connection_end = ConnectionEnd::new( - ConnectionState::Open, - ClientId::default(), - ConnectionCounterparty::new( - ClientId::default(), - Some(ConnectionId::default()), - Default::default(), - ), - get_compatible_versions(), - ZERO_DURATION, - ); - - let tests: Vec = vec![ - Test { - name: "Processing fails because no channel exists in the context".to_string(), - ctx: context.clone(), - packet: packet.clone(), - ack: ack.clone(), - want_pass: false, - }, - Test { - name: "Good parameters".to_string(), - ctx: context - .clone() - .with_client(&ClientId::default(), client_height) - .with_connection(ConnectionId::default(), connection_end.clone()) - .with_channel( - packet.destination_port.clone(), - packet.destination_channel.clone(), - dest_channel_end.clone(), - ), - packet: packet.clone(), - ack, - want_pass: true, - }, - Test { - name: "Zero ack".to_string(), - ctx: context - .with_client(&ClientId::default(), Height::new(0, 1).unwrap()) - .with_connection(ConnectionId::default(), connection_end) - .with_channel(PortId::default(), ChannelId::default(), dest_channel_end), - packet, - ack: ack_null, - want_pass: false, - }, - ] - .into_iter() - .collect(); - - for test in tests { - let res = process(&test.ctx, test.packet.clone(), test.ack.into()); - // Additionally check the events and the output objects in the result. - match res { - Ok(proto_output) => { - assert!( - test.want_pass, - "write_ack: test passed but was supposed to fail for test: {}, \nparams {:?} {:?}", - test.name, - test.packet.clone(), - test.ctx.clone() - ); - - assert!(!proto_output.events.is_empty()); // Some events must exist. - - for e in proto_output.events.iter() { - assert!(matches!(e, &IbcEvent::WriteAcknowledgement(_))); - } - } - Err(e) => { - assert!( - !test.want_pass, - "write_ack: did not pass test: {}, \nparams {:?} {:?} error: {:?}", - test.name, - test.packet.clone(), - test.ctx.clone(), - e, - ); - } - } - } - } -} diff --git a/modules/src/core/ics04_channel/mod.rs b/modules/src/core/ics04_channel/mod.rs deleted file mode 100644 index d6b23e13bc..0000000000 --- a/modules/src/core/ics04_channel/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -//! ICS 04: Channel implementation that facilitates communication between -//! applications and the chains those applications are built upon. - -pub mod channel; -pub mod context; -pub mod error; -pub mod events; - -pub mod handler; -pub mod msgs; -pub mod packet; -pub mod timeout; - -pub mod commitment; -mod version; -pub use version::Version; diff --git a/modules/src/core/ics04_channel/msgs.rs b/modules/src/core/ics04_channel/msgs.rs deleted file mode 100644 index 804821e294..0000000000 --- a/modules/src/core/ics04_channel/msgs.rs +++ /dev/null @@ -1,76 +0,0 @@ -//! Message definitions for all ICS4 domain types: channel open & close handshake datagrams, as well -//! as packets. - -use crate::core::ics04_channel::error::Error; -use crate::core::ics04_channel::msgs::acknowledgement::MsgAcknowledgement; -use crate::core::ics04_channel::msgs::chan_close_confirm::MsgChannelCloseConfirm; -use crate::core::ics04_channel::msgs::chan_close_init::MsgChannelCloseInit; -use crate::core::ics04_channel::msgs::chan_open_ack::MsgChannelOpenAck; -use crate::core::ics04_channel::msgs::chan_open_confirm::MsgChannelOpenConfirm; -use crate::core::ics04_channel::msgs::chan_open_init::MsgChannelOpenInit; -use crate::core::ics04_channel::msgs::chan_open_try::MsgChannelOpenTry; -use crate::core::ics04_channel::msgs::recv_packet::MsgRecvPacket; -use crate::core::ics04_channel::msgs::timeout::MsgTimeout; -use crate::core::ics04_channel::msgs::timeout_on_close::MsgTimeoutOnClose; -use crate::core::ics26_routing::context::{Ics26Context, ModuleId}; - -// Opening handshake messages. -pub mod chan_open_ack; -pub mod chan_open_confirm; -pub mod chan_open_init; -pub mod chan_open_try; - -// Closing handshake messages. -pub mod chan_close_confirm; -pub mod chan_close_init; - -// Packet specific messages. -pub mod acknowledgement; -pub mod recv_packet; -pub mod timeout; -pub mod timeout_on_close; - -/// Enumeration of all possible messages that the ICS4 protocol processes. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum ChannelMsg { - ChannelOpenInit(MsgChannelOpenInit), - ChannelOpenTry(MsgChannelOpenTry), - ChannelOpenAck(MsgChannelOpenAck), - ChannelOpenConfirm(MsgChannelOpenConfirm), - ChannelCloseInit(MsgChannelCloseInit), - ChannelCloseConfirm(MsgChannelCloseConfirm), -} - -impl ChannelMsg { - pub(super) fn lookup_module(&self, ctx: &impl Ics26Context) -> Result { - let module_id = match self { - ChannelMsg::ChannelOpenInit(msg) => ctx - .lookup_module_by_port(&msg.port_id) - .map_err(Error::ics05_port)?, - ChannelMsg::ChannelOpenTry(msg) => ctx - .lookup_module_by_port(&msg.port_id) - .map_err(Error::ics05_port)?, - ChannelMsg::ChannelOpenAck(msg) => ctx - .lookup_module_by_port(&msg.port_id) - .map_err(Error::ics05_port)?, - ChannelMsg::ChannelOpenConfirm(msg) => ctx - .lookup_module_by_port(&msg.port_id) - .map_err(Error::ics05_port)?, - ChannelMsg::ChannelCloseInit(msg) => ctx - .lookup_module_by_port(&msg.port_id) - .map_err(Error::ics05_port)?, - ChannelMsg::ChannelCloseConfirm(msg) => ctx - .lookup_module_by_port(&msg.port_id) - .map_err(Error::ics05_port)?, - }; - Ok(module_id) - } -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum PacketMsg { - RecvPacket(MsgRecvPacket), - AckPacket(MsgAcknowledgement), - ToPacket(MsgTimeout), - ToClosePacket(MsgTimeoutOnClose), -} diff --git a/modules/src/core/ics04_channel/msgs/acknowledgement.rs b/modules/src/core/ics04_channel/msgs/acknowledgement.rs deleted file mode 100644 index 14129cd67b..0000000000 --- a/modules/src/core/ics04_channel/msgs/acknowledgement.rs +++ /dev/null @@ -1,233 +0,0 @@ -use crate::prelude::*; - -use derive_more::{From, Into}; -use ibc_proto::ibc::core::channel::v1::MsgAcknowledgement as RawMsgAcknowledgement; -use ibc_proto::protobuf::Protobuf; - -use crate::core::ics04_channel::error::Error; -use crate::core::ics04_channel::packet::Packet; -use crate::proofs::Proofs; -use crate::signer::Signer; -use crate::tx_msg::Msg; - -pub const TYPE_URL: &str = "/ibc.core.channel.v1.MsgAcknowledgement"; - -/// A generic Acknowledgement type that modules may interpret as they like. -#[derive(Clone, Debug, PartialEq, Eq, From, Into)] -pub struct Acknowledgement(Vec); - -impl Acknowledgement { - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } -} - -impl AsRef<[u8]> for Acknowledgement { - fn as_ref(&self) -> &[u8] { - self.0.as_slice() - } -} - -/// -/// Message definition for packet acknowledgements. -/// -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct MsgAcknowledgement { - pub packet: Packet, - pub acknowledgement: Acknowledgement, - pub proofs: Proofs, - pub signer: Signer, -} - -impl MsgAcknowledgement { - pub fn new( - packet: Packet, - acknowledgement: Acknowledgement, - proofs: Proofs, - signer: Signer, - ) -> MsgAcknowledgement { - Self { - packet, - acknowledgement, - proofs, - signer, - } - } - - pub fn acknowledgement(&self) -> &Acknowledgement { - &self.acknowledgement - } - - pub fn proofs(&self) -> &Proofs { - &self.proofs - } -} - -impl Msg for MsgAcknowledgement { - type ValidationError = Error; - type Raw = RawMsgAcknowledgement; - - fn route(&self) -> String { - crate::keys::ROUTER_KEY.to_string() - } - - fn type_url(&self) -> String { - TYPE_URL.to_string() - } -} - -impl Protobuf for MsgAcknowledgement {} - -impl TryFrom for MsgAcknowledgement { - type Error = Error; - - fn try_from(raw_msg: RawMsgAcknowledgement) -> Result { - let proofs = Proofs::new( - raw_msg - .proof_acked - .try_into() - .map_err(Error::invalid_proof)?, - None, - None, - None, - raw_msg - .proof_height - .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or_else(Error::missing_height)?, - ) - .map_err(Error::invalid_proof)?; - - Ok(MsgAcknowledgement { - packet: raw_msg - .packet - .ok_or_else(Error::missing_packet)? - .try_into()?, - acknowledgement: raw_msg.acknowledgement.into(), - signer: raw_msg.signer.parse().map_err(Error::signer)?, - proofs, - }) - } -} - -impl From for RawMsgAcknowledgement { - fn from(domain_msg: MsgAcknowledgement) -> Self { - RawMsgAcknowledgement { - packet: Some(domain_msg.packet.into()), - acknowledgement: domain_msg.acknowledgement.into(), - signer: domain_msg.signer.to_string(), - proof_height: Some(domain_msg.proofs.height().into()), - proof_acked: domain_msg.proofs.object_proof().clone().into(), - } - } -} - -#[cfg(test)] -pub mod test_util { - use ibc_proto::ibc::core::channel::v1::MsgAcknowledgement as RawMsgAcknowledgement; - use ibc_proto::ibc::core::channel::v1::Packet as RawPacket; - use ibc_proto::ibc::core::client::v1::Height as RawHeight; - - use crate::core::ics04_channel::packet::test_utils::get_dummy_raw_packet; - use crate::test_utils::{get_dummy_bech32_account, get_dummy_proof}; - - /// Returns a dummy `RawMsgAcknowledgement`, for testing only! - /// The `height` parametrizes both the proof height as well as the timeout height. - pub fn get_dummy_raw_msg_acknowledgement(height: u64) -> RawMsgAcknowledgement { - get_dummy_raw_msg_ack_with_packet(get_dummy_raw_packet(height, 1), height) - } - - pub fn get_dummy_raw_msg_ack_with_packet( - packet: RawPacket, - height: u64, - ) -> RawMsgAcknowledgement { - RawMsgAcknowledgement { - packet: Some(packet), - acknowledgement: get_dummy_proof(), - proof_acked: get_dummy_proof(), - proof_height: Some(RawHeight { - revision_number: 0, - revision_height: height, - }), - signer: get_dummy_bech32_account(), - } - } -} - -#[cfg(test)] -mod test { - use crate::prelude::*; - - use test_log::test; - - use ibc_proto::ibc::core::channel::v1::MsgAcknowledgement as RawMsgAcknowledgement; - - use crate::core::ics04_channel::error::Error; - use crate::core::ics04_channel::msgs::acknowledgement::test_util::get_dummy_raw_msg_acknowledgement; - use crate::core::ics04_channel::msgs::acknowledgement::MsgAcknowledgement; - use crate::test_utils::get_dummy_bech32_account; - - #[test] - fn msg_acknowledgment_try_from_raw() { - struct Test { - name: String, - raw: RawMsgAcknowledgement, - want_pass: bool, - } - - let height = 50; - let default_raw_msg = get_dummy_raw_msg_acknowledgement(height); - - let tests: Vec = vec![ - Test { - name: "Good parameters".to_string(), - raw: default_raw_msg.clone(), - want_pass: true, - }, - Test { - name: "Missing packet".to_string(), - raw: RawMsgAcknowledgement { - packet: None, - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Missing proof height".to_string(), - raw: RawMsgAcknowledgement { - proof_height: None, - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Empty signer".to_string(), - raw: RawMsgAcknowledgement { - signer: get_dummy_bech32_account(), - ..default_raw_msg.clone() - }, - want_pass: true, - }, - Test { - name: "Empty proof acked".to_string(), - raw: RawMsgAcknowledgement { - proof_acked: Vec::new(), - ..default_raw_msg - }, - want_pass: false, - }, - ]; - - for test in tests { - let res_msg: Result = test.raw.clone().try_into(); - - assert_eq!( - res_msg.is_ok(), - test.want_pass, - "MsgAcknowledgement::try_from failed for test {} \nraw message: {:?} with error: {:?}", - test.name, - test.raw, - res_msg.err() - ); - } - } -} diff --git a/modules/src/core/ics04_channel/msgs/chan_close_confirm.rs b/modules/src/core/ics04_channel/msgs/chan_close_confirm.rs deleted file mode 100644 index ce53866ab1..0000000000 --- a/modules/src/core/ics04_channel/msgs/chan_close_confirm.rs +++ /dev/null @@ -1,234 +0,0 @@ -use crate::prelude::*; - -use ibc_proto::protobuf::Protobuf; - -use ibc_proto::ibc::core::channel::v1::MsgChannelCloseConfirm as RawMsgChannelCloseConfirm; - -use crate::core::ics04_channel::error::Error; -use crate::core::ics24_host::identifier::{ChannelId, PortId}; -use crate::proofs::Proofs; -use crate::signer::Signer; -use crate::tx_msg::Msg; - -pub const TYPE_URL: &str = "/ibc.core.channel.v1.MsgChannelCloseConfirm"; - -/// -/// Message definition for the second step in the channel close handshake (the `ChanCloseConfirm` -/// datagram). -/// -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct MsgChannelCloseConfirm { - pub port_id: PortId, - pub channel_id: ChannelId, - pub proofs: Proofs, - pub signer: Signer, -} - -impl MsgChannelCloseConfirm { - pub fn new(port_id: PortId, channel_id: ChannelId, proofs: Proofs, signer: Signer) -> Self { - Self { - port_id, - channel_id, - proofs, - signer, - } - } -} - -impl Msg for MsgChannelCloseConfirm { - type ValidationError = Error; - type Raw = RawMsgChannelCloseConfirm; - - fn route(&self) -> String { - crate::keys::ROUTER_KEY.to_string() - } - - fn type_url(&self) -> String { - TYPE_URL.to_string() - } -} - -impl Protobuf for MsgChannelCloseConfirm {} - -impl TryFrom for MsgChannelCloseConfirm { - type Error = Error; - - fn try_from(raw_msg: RawMsgChannelCloseConfirm) -> Result { - let proofs = Proofs::new( - raw_msg - .proof_init - .try_into() - .map_err(Error::invalid_proof)?, - None, - None, - None, - raw_msg - .proof_height - .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or_else(Error::missing_height)?, - ) - .map_err(Error::invalid_proof)?; - - Ok(MsgChannelCloseConfirm { - port_id: raw_msg.port_id.parse().map_err(Error::identifier)?, - channel_id: raw_msg.channel_id.parse().map_err(Error::identifier)?, - proofs, - signer: raw_msg.signer.parse().map_err(Error::signer)?, - }) - } -} - -impl From for RawMsgChannelCloseConfirm { - fn from(domain_msg: MsgChannelCloseConfirm) -> Self { - RawMsgChannelCloseConfirm { - port_id: domain_msg.port_id.to_string(), - channel_id: domain_msg.channel_id.to_string(), - proof_init: domain_msg.proofs.object_proof().clone().into(), - proof_height: Some(domain_msg.proofs.height().into()), - signer: domain_msg.signer.to_string(), - } - } -} - -#[cfg(test)] -pub mod test_util { - use crate::prelude::*; - use ibc_proto::ibc::core::channel::v1::MsgChannelCloseConfirm as RawMsgChannelCloseConfirm; - use ibc_proto::ibc::core::client::v1::Height; - - use crate::core::ics24_host::identifier::{ChannelId, PortId}; - use crate::test_utils::{get_dummy_bech32_account, get_dummy_proof}; - - /// Returns a dummy `RawMsgChannelCloseConfirm`, for testing only! - pub fn get_dummy_raw_msg_chan_close_confirm(proof_height: u64) -> RawMsgChannelCloseConfirm { - RawMsgChannelCloseConfirm { - port_id: PortId::default().to_string(), - channel_id: ChannelId::default().to_string(), - proof_init: get_dummy_proof(), - proof_height: Some(Height { - revision_number: 0, - revision_height: proof_height, - }), - signer: get_dummy_bech32_account(), - } - } -} - -#[cfg(test)] -mod tests { - use crate::prelude::*; - - use ibc_proto::ibc::core::channel::v1::MsgChannelCloseConfirm as RawMsgChannelCloseConfirm; - use ibc_proto::ibc::core::client::v1::Height; - - use crate::core::ics04_channel::msgs::chan_close_confirm::test_util::get_dummy_raw_msg_chan_close_confirm; - use crate::core::ics04_channel::msgs::chan_close_confirm::MsgChannelCloseConfirm; - - #[test] - fn parse_channel_close_confirm_msg() { - struct Test { - name: String, - raw: RawMsgChannelCloseConfirm, - want_pass: bool, - } - - let proof_height = 10; - let default_raw_msg = get_dummy_raw_msg_chan_close_confirm(proof_height); - - let tests: Vec = vec![ - Test { - name: "Good parameters".to_string(), - raw: default_raw_msg.clone(), - want_pass: true, - }, - Test { - name: "Correct port".to_string(), - raw: RawMsgChannelCloseConfirm { - port_id: "p34".to_string(), - ..default_raw_msg.clone() - }, - want_pass: true, - }, - Test { - name: "Bad port, name too short".to_string(), - raw: RawMsgChannelCloseConfirm { - port_id: "p".to_string(), - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Bad port, name too long".to_string(), - raw: RawMsgChannelCloseConfirm { - port_id: - "abcdefghijklmnsdfasdfasdfasdfasdgafgadsfasdfasdfasdasfdasdfsadfopqrstuabcdefghijklmnsdfasdfasdfasdfasdgafgadsfasdfasdfasdasfdasdfsadfopqrstu" - .to_string(), - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Correct channel identifier".to_string(), - raw: RawMsgChannelCloseConfirm { - channel_id: "channel-34".to_string(), - ..default_raw_msg.clone() - }, - want_pass: true, - }, - Test { - name: "Bad channel, name too short".to_string(), - raw: RawMsgChannelCloseConfirm { - channel_id: "chshort".to_string(), - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Bad channel, name too long".to_string(), - raw: RawMsgChannelCloseConfirm { - channel_id: - "channel-128391283791827398127398791283912837918273981273987912839" - .to_string(), - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Bad proof height, height = 0".to_string(), - raw: RawMsgChannelCloseConfirm { - proof_height: Some(Height { - revision_number: 0, - revision_height: 0, - }), - ..default_raw_msg - }, - want_pass: false, - }, - ] - .into_iter() - .collect(); - - for test in tests { - let msg = MsgChannelCloseConfirm::try_from(test.raw.clone()); - - assert_eq!( - test.want_pass, - msg.is_ok(), - "MsgChanCloseConfirm::try_from raw failed for test {}, \nraw msg {:?} with error {:?}", - test.name, - test.raw, - msg.err(), - ); - } - } - - #[test] - fn to_and_from() { - let raw = get_dummy_raw_msg_chan_close_confirm(19); - let msg = MsgChannelCloseConfirm::try_from(raw.clone()).unwrap(); - let raw_back = RawMsgChannelCloseConfirm::from(msg.clone()); - let msg_back = MsgChannelCloseConfirm::try_from(raw_back.clone()).unwrap(); - assert_eq!(raw, raw_back); - assert_eq!(msg, msg_back); - } -} diff --git a/modules/src/core/ics04_channel/msgs/chan_close_init.rs b/modules/src/core/ics04_channel/msgs/chan_close_init.rs deleted file mode 100644 index 20e3f25043..0000000000 --- a/modules/src/core/ics04_channel/msgs/chan_close_init.rs +++ /dev/null @@ -1,191 +0,0 @@ -use crate::prelude::*; - -use ibc_proto::protobuf::Protobuf; - -use ibc_proto::ibc::core::channel::v1::MsgChannelCloseInit as RawMsgChannelCloseInit; - -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.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, - pub channel_id: ChannelId, - pub signer: Signer, -} - -impl MsgChannelCloseInit { - pub fn new(port_id: PortId, channel_id: ChannelId, signer: Signer) -> Self { - Self { - port_id, - channel_id, - signer, - } - } -} - -impl Msg for MsgChannelCloseInit { - type ValidationError = Error; - type Raw = RawMsgChannelCloseInit; - - fn route(&self) -> String { - crate::keys::ROUTER_KEY.to_string() - } - - fn type_url(&self) -> String { - TYPE_URL.to_string() - } -} - -impl Protobuf for MsgChannelCloseInit {} - -impl TryFrom for MsgChannelCloseInit { - type Error = Error; - - fn try_from(raw_msg: RawMsgChannelCloseInit) -> Result { - Ok(MsgChannelCloseInit { - 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)?, - }) - } -} - -impl From for RawMsgChannelCloseInit { - fn from(domain_msg: MsgChannelCloseInit) -> Self { - RawMsgChannelCloseInit { - port_id: domain_msg.port_id.to_string(), - channel_id: domain_msg.channel_id.to_string(), - signer: domain_msg.signer.to_string(), - } - } -} - -#[cfg(test)] -pub mod test_util { - use crate::prelude::*; - use ibc_proto::ibc::core::channel::v1::MsgChannelCloseInit as RawMsgChannelCloseInit; - - use crate::core::ics24_host::identifier::{ChannelId, PortId}; - use crate::test_utils::get_dummy_bech32_account; - - /// Returns a dummy `RawMsgChannelCloseInit`, for testing only! - pub fn get_dummy_raw_msg_chan_close_init() -> RawMsgChannelCloseInit { - RawMsgChannelCloseInit { - port_id: PortId::default().to_string(), - channel_id: ChannelId::default().to_string(), - signer: get_dummy_bech32_account(), - } - } -} - -#[cfg(test)] -mod tests { - use crate::prelude::*; - - use test_log::test; - - use ibc_proto::ibc::core::channel::v1::MsgChannelCloseInit as RawMsgChannelCloseInit; - - use crate::core::ics04_channel::msgs::chan_close_init::test_util::get_dummy_raw_msg_chan_close_init; - use crate::core::ics04_channel::msgs::chan_close_init::MsgChannelCloseInit; - - #[test] - fn parse_channel_close_init_msg() { - struct Test { - name: String, - raw: RawMsgChannelCloseInit, - want_pass: bool, - } - - let default_raw_msg = get_dummy_raw_msg_chan_close_init(); - - let tests: Vec = vec![ - Test { - name: "Good parameters".to_string(), - raw: default_raw_msg.clone(), - want_pass: true, - }, - Test { - name: "Correct port".to_string(), - raw: RawMsgChannelCloseInit { - port_id: "p34".to_string(), - ..default_raw_msg.clone() - }, - want_pass: true, - }, - Test { - name: "Bad port, name too short".to_string(), - raw: RawMsgChannelCloseInit { - port_id: "p".to_string(), - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Bad port, name too long".to_string(), - raw: RawMsgChannelCloseInit { - port_id: "abcdefsdfasdfasdfasdfasdfasdfadsfasdgafsgadfasdfasdfasdfsdfasdfaghijklmnopqrstuabcdefsdfasdfasdfasdfasdfasdfadsfasdgafsgadfasdfasdfasdfsdfasdfaghijklmnopqrstu".to_string(), - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Correct channel identifier".to_string(), - raw: RawMsgChannelCloseInit { - channel_id: "channel-34".to_string(), - ..default_raw_msg.clone() - }, - want_pass: true, - }, - Test { - name: "Bad channel, name too short".to_string(), - raw: RawMsgChannelCloseInit { - channel_id: "chshort".to_string(), - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Bad channel, name too long".to_string(), - raw: RawMsgChannelCloseInit { - channel_id: "channel-128391283791827398127398791283912837918273981273987912839".to_string(), - ..default_raw_msg - }, - want_pass: false, - }, - ] - .into_iter() - .collect(); - - for test in tests { - let msg = MsgChannelCloseInit::try_from(test.raw.clone()); - - assert_eq!( - test.want_pass, - msg.is_ok(), - "MsgChanCloseInit::try_from failed for test {}, \nmsg {:?} with error {:?}", - test.name, - test.raw, - msg.err(), - ); - } - } - - #[test] - fn to_and_from() { - let raw = get_dummy_raw_msg_chan_close_init(); - let msg = MsgChannelCloseInit::try_from(raw.clone()).unwrap(); - let raw_back = RawMsgChannelCloseInit::from(msg.clone()); - let msg_back = MsgChannelCloseInit::try_from(raw_back.clone()).unwrap(); - assert_eq!(raw, raw_back); - assert_eq!(msg, msg_back); - } -} diff --git a/modules/src/core/ics04_channel/msgs/chan_open_ack.rs b/modules/src/core/ics04_channel/msgs/chan_open_ack.rs deleted file mode 100644 index a438aa792e..0000000000 --- a/modules/src/core/ics04_channel/msgs/chan_open_ack.rs +++ /dev/null @@ -1,302 +0,0 @@ -use crate::core::ics04_channel::error::Error; -use crate::core::ics04_channel::Version; -use crate::core::ics24_host::identifier::{ChannelId, PortId}; -use crate::prelude::*; -use crate::proofs::Proofs; -use crate::signer::Signer; -use crate::tx_msg::Msg; - -use ibc_proto::ibc::core::channel::v1::MsgChannelOpenAck as RawMsgChannelOpenAck; -use ibc_proto::protobuf::Protobuf; - -pub const TYPE_URL: &str = "/ibc.core.channel.v1.MsgChannelOpenAck"; - -/// -/// Message definition for the third step in the channel open handshake (`ChanOpenAck` datagram). -/// -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct MsgChannelOpenAck { - pub port_id: PortId, - pub channel_id: ChannelId, - pub counterparty_channel_id: ChannelId, - pub counterparty_version: Version, - pub proofs: Proofs, - pub signer: Signer, -} - -impl MsgChannelOpenAck { - pub fn new( - port_id: PortId, - channel_id: ChannelId, - counterparty_channel_id: ChannelId, - counterparty_version: Version, - proofs: Proofs, - signer: Signer, - ) -> Self { - Self { - port_id, - channel_id, - counterparty_channel_id, - counterparty_version, - proofs, - signer, - } - } -} - -impl Msg for MsgChannelOpenAck { - type ValidationError = Error; - type Raw = RawMsgChannelOpenAck; - - fn route(&self) -> String { - crate::keys::ROUTER_KEY.to_string() - } - - fn type_url(&self) -> String { - TYPE_URL.to_string() - } -} - -impl Protobuf for MsgChannelOpenAck {} - -impl TryFrom for MsgChannelOpenAck { - type Error = Error; - - fn try_from(raw_msg: RawMsgChannelOpenAck) -> Result { - let proofs = Proofs::new( - raw_msg.proof_try.try_into().map_err(Error::invalid_proof)?, - None, - None, - None, - raw_msg - .proof_height - .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or_else(Error::missing_height)?, - ) - .map_err(Error::invalid_proof)?; - - Ok(MsgChannelOpenAck { - port_id: raw_msg.port_id.parse().map_err(Error::identifier)?, - channel_id: raw_msg.channel_id.parse().map_err(Error::identifier)?, - counterparty_channel_id: raw_msg - .counterparty_channel_id - .parse() - .map_err(Error::identifier)?, - counterparty_version: raw_msg.counterparty_version.into(), - proofs, - signer: raw_msg.signer.parse().map_err(Error::signer)?, - }) - } -} - -impl From for RawMsgChannelOpenAck { - fn from(domain_msg: MsgChannelOpenAck) -> Self { - RawMsgChannelOpenAck { - port_id: domain_msg.port_id.to_string(), - channel_id: domain_msg.channel_id.to_string(), - counterparty_channel_id: domain_msg.counterparty_channel_id.to_string(), - counterparty_version: domain_msg.counterparty_version.to_string(), - proof_try: domain_msg.proofs.object_proof().clone().into(), - proof_height: Some(domain_msg.proofs.height().into()), - signer: domain_msg.signer.to_string(), - } - } -} - -#[cfg(test)] -pub mod test_util { - use crate::prelude::*; - use ibc_proto::ibc::core::channel::v1::MsgChannelOpenAck as RawMsgChannelOpenAck; - - use crate::core::ics24_host::identifier::{ChannelId, PortId}; - use crate::test_utils::{get_dummy_bech32_account, get_dummy_proof}; - use ibc_proto::ibc::core::client::v1::Height; - - /// Returns a dummy `RawMsgChannelOpenAck`, for testing only! - pub fn get_dummy_raw_msg_chan_open_ack(proof_height: u64) -> RawMsgChannelOpenAck { - RawMsgChannelOpenAck { - port_id: PortId::default().to_string(), - channel_id: ChannelId::default().to_string(), - counterparty_channel_id: ChannelId::default().to_string(), - counterparty_version: "".to_string(), - proof_try: get_dummy_proof(), - proof_height: Some(Height { - revision_number: 0, - revision_height: proof_height, - }), - signer: get_dummy_bech32_account(), - } - } -} - -#[cfg(test)] -mod tests { - use crate::prelude::*; - use ibc_proto::ibc::core::channel::v1::MsgChannelOpenAck as RawMsgChannelOpenAck; - use test_log::test; - - use crate::core::ics04_channel::msgs::chan_open_ack::test_util::get_dummy_raw_msg_chan_open_ack; - use crate::core::ics04_channel::msgs::chan_open_ack::MsgChannelOpenAck; - - use ibc_proto::ibc::core::client::v1::Height; - - #[test] - fn parse_channel_open_ack_msg() { - struct Test { - name: String, - raw: RawMsgChannelOpenAck, - want_pass: bool, - } - - let proof_height = 20; - let default_raw_msg = get_dummy_raw_msg_chan_open_ack(proof_height); - - let tests: Vec = vec![ - Test { - name: "Good parameters".to_string(), - raw: default_raw_msg.clone(), - want_pass: true, - }, - Test { - name: "Correct port identifier".to_string(), - raw: RawMsgChannelOpenAck { - port_id: "p34".to_string(), - ..default_raw_msg.clone() - }, - want_pass: true, - }, - Test { - name: "Bad port, name too short".to_string(), - raw: RawMsgChannelOpenAck { - port_id: "p".to_string(), - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Bad port, name too long".to_string(), - raw: RawMsgChannelOpenAck { - port_id: "abcdezdfDfsdfgfddsfsfdsdfdfvxcvzxcvsgdfsdfwefwvsdfdsfdasgagadgsadgsdffghijklmnopqrstuabcdezdfDfsdfgfddsfsfdsdfdfvxcvzxcvsgdfsdfwefwvsdfdsfdasgagadgsadgsdffghijklmnopqrstu".to_string(), - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Correct channel identifier".to_string(), - raw: RawMsgChannelOpenAck { - channel_id: "channel-34".to_string(), - ..default_raw_msg.clone() - }, - want_pass: true, - }, - Test { - name: "Bad channel, name too short".to_string(), - raw: RawMsgChannelOpenAck { - channel_id: "chshort".to_string(), - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Bad channel, name too long".to_string(), - raw: RawMsgChannelOpenAck { - channel_id: "channel-128391283791827398127398791283912837918273981273987912839".to_string(), - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "[Counterparty] Correct channel identifier".to_string(), - raw: RawMsgChannelOpenAck { - counterparty_channel_id: "channel-34".to_string(), - ..default_raw_msg.clone() - }, - want_pass: true, - }, - Test { - name: "[Counterparty] Bad channel, name too short".to_string(), - raw: RawMsgChannelOpenAck { - counterparty_channel_id: "chshort".to_string(), - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "[Counterparty] Bad channel, name too long".to_string(), - raw: RawMsgChannelOpenAck { - counterparty_channel_id: "channel-128391283791827398127398791283912837918273981273987912839".to_string(), - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Empty counterparty version (allowed)".to_string(), - raw: RawMsgChannelOpenAck { - counterparty_version: " ".to_string(), - ..default_raw_msg.clone() - }, - want_pass: true, - }, - Test { - name: "Arbitrary counterparty version (allowed)".to_string(), - raw: RawMsgChannelOpenAck { - counterparty_version: "v1.1.23-alpha".to_string(), - ..default_raw_msg.clone() - }, - want_pass: true, - }, - Test { - name: "Bad proof height, height = 0".to_string(), - raw: RawMsgChannelOpenAck { - 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: RawMsgChannelOpenAck { - proof_height: None, - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Missing proof try (object proof)".to_string(), - raw: RawMsgChannelOpenAck { - proof_try: Vec::new(), - ..default_raw_msg - }, - want_pass: false, - }, - ] - .into_iter() - .collect(); - - for test in tests { - let res_msg = MsgChannelOpenAck::try_from(test.raw.clone()); - - assert_eq!( - test.want_pass, - res_msg.is_ok(), - "MsgChanOpenAck::try_from raw failed for test {}, \nraw msg {:?} with error {:?}", - test.name, - test.raw, - res_msg.err(), - ); - } - } - - #[test] - fn to_and_from() { - let raw = get_dummy_raw_msg_chan_open_ack(100); - let msg = MsgChannelOpenAck::try_from(raw.clone()).unwrap(); - let raw_back = RawMsgChannelOpenAck::from(msg.clone()); - let msg_back = MsgChannelOpenAck::try_from(raw_back.clone()).unwrap(); - assert_eq!(raw, raw_back); - assert_eq!(msg, msg_back); - } -} diff --git a/modules/src/core/ics04_channel/msgs/chan_open_confirm.rs b/modules/src/core/ics04_channel/msgs/chan_open_confirm.rs deleted file mode 100644 index fcbc1ffb1f..0000000000 --- a/modules/src/core/ics04_channel/msgs/chan_open_confirm.rs +++ /dev/null @@ -1,234 +0,0 @@ -use crate::core::ics04_channel::error::Error; -use crate::core::ics24_host::identifier::{ChannelId, PortId}; -use crate::prelude::*; -use crate::proofs::Proofs; -use crate::signer::Signer; -use crate::tx_msg::Msg; - -use ibc_proto::ibc::core::channel::v1::MsgChannelOpenConfirm as RawMsgChannelOpenConfirm; -use ibc_proto::protobuf::Protobuf; - -pub const TYPE_URL: &str = "/ibc.core.channel.v1.MsgChannelOpenConfirm"; - -/// -/// Message definition for the fourth step in the channel open handshake (`ChanOpenConfirm` -/// datagram). -/// -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct MsgChannelOpenConfirm { - pub port_id: PortId, - pub channel_id: ChannelId, - pub proofs: Proofs, - pub signer: Signer, -} - -impl MsgChannelOpenConfirm { - pub fn new(port_id: PortId, channel_id: ChannelId, proofs: Proofs, signer: Signer) -> Self { - Self { - port_id, - channel_id, - proofs, - signer, - } - } -} - -impl Msg for MsgChannelOpenConfirm { - type ValidationError = Error; - type Raw = RawMsgChannelOpenConfirm; - - fn route(&self) -> String { - crate::keys::ROUTER_KEY.to_string() - } - - fn type_url(&self) -> String { - TYPE_URL.to_string() - } -} - -impl Protobuf for MsgChannelOpenConfirm {} - -impl TryFrom for MsgChannelOpenConfirm { - type Error = Error; - - fn try_from(raw_msg: RawMsgChannelOpenConfirm) -> Result { - let proofs = Proofs::new( - raw_msg.proof_ack.try_into().map_err(Error::invalid_proof)?, - None, - None, - None, - raw_msg - .proof_height - .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or_else(Error::missing_height)?, - ) - .map_err(Error::invalid_proof)?; - - Ok(MsgChannelOpenConfirm { - port_id: raw_msg.port_id.parse().map_err(Error::identifier)?, - channel_id: raw_msg.channel_id.parse().map_err(Error::identifier)?, - proofs, - signer: raw_msg.signer.parse().map_err(Error::signer)?, - }) - } -} - -impl From for RawMsgChannelOpenConfirm { - fn from(domain_msg: MsgChannelOpenConfirm) -> Self { - RawMsgChannelOpenConfirm { - port_id: domain_msg.port_id.to_string(), - channel_id: domain_msg.channel_id.to_string(), - proof_ack: domain_msg.proofs.object_proof().clone().into(), - proof_height: Some(domain_msg.proofs.height().into()), - signer: domain_msg.signer.to_string(), - } - } -} - -#[cfg(test)] -pub mod test_util { - use crate::prelude::*; - use ibc_proto::ibc::core::channel::v1::MsgChannelOpenConfirm as RawMsgChannelOpenConfirm; - - use crate::core::ics24_host::identifier::{ChannelId, PortId}; - use crate::test_utils::{get_dummy_bech32_account, get_dummy_proof}; - use ibc_proto::ibc::core::client::v1::Height; - - /// Returns a dummy `RawMsgChannelOpenConfirm`, for testing only! - pub fn get_dummy_raw_msg_chan_open_confirm(proof_height: u64) -> RawMsgChannelOpenConfirm { - RawMsgChannelOpenConfirm { - port_id: PortId::default().to_string(), - channel_id: ChannelId::default().to_string(), - proof_ack: get_dummy_proof(), - proof_height: Some(Height { - revision_number: 0, - revision_height: proof_height, - }), - signer: get_dummy_bech32_account(), - } - } -} - -#[cfg(test)] -mod tests { - use crate::prelude::*; - use ibc_proto::ibc::core::channel::v1::MsgChannelOpenConfirm as RawMsgChannelOpenConfirm; - use test_log::test; - - use crate::core::ics04_channel::msgs::chan_open_confirm::test_util::get_dummy_raw_msg_chan_open_confirm; - use crate::core::ics04_channel::msgs::chan_open_confirm::MsgChannelOpenConfirm; - - use ibc_proto::ibc::core::client::v1::Height; - - #[test] - fn parse_channel_open_confirm_msg() { - struct Test { - name: String, - raw: RawMsgChannelOpenConfirm, - want_pass: bool, - } - - let proof_height = 78; - let default_raw_msg = get_dummy_raw_msg_chan_open_confirm(proof_height); - - let tests: Vec = vec![ - Test { - name: "Good parameters".to_string(), - raw: default_raw_msg.clone(), - want_pass: true, - }, - Test { - name: "Correct port".to_string(), - raw: RawMsgChannelOpenConfirm { - port_id: "p34".to_string(), - ..default_raw_msg.clone() - }, - want_pass: true, - }, - Test { - name: "Bad port, name too short".to_string(), - raw: RawMsgChannelOpenConfirm { - port_id: "p".to_string(), - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Bad port, name too long".to_string(), - raw: RawMsgChannelOpenConfirm { - port_id: "abcdesdfasdsdffasdfasdfasfasdgasdfgasdfasdfasdfasdfasdfasdffghijklmnopqrstuabcdesdfasdsdffasdfasdfasfasdgasdfgasdfasdfasdfasdfasdfasdffghijklmnopqrstu".to_string(), - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Correct channel identifier".to_string(), - raw: RawMsgChannelOpenConfirm { - channel_id: "channel-34".to_string(), - ..default_raw_msg.clone() - }, - want_pass: true, - }, - Test { - name: "Bad channel, name too short".to_string(), - raw: RawMsgChannelOpenConfirm { - channel_id: "chshort".to_string(), - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Bad channel, name too long".to_string(), - raw: RawMsgChannelOpenConfirm { - channel_id: "channel-128391283791827398127398791283912837918273981273987912839".to_string(), - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Bad proof height, height = 0".to_string(), - raw: RawMsgChannelOpenConfirm { - proof_height: Some(Height { - revision_number: 0, - revision_height: 0, - }), - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Missing object proof".to_string(), - raw: RawMsgChannelOpenConfirm { - proof_ack: Vec::new(), - ..default_raw_msg - }, - want_pass: false, - }, - ] - .into_iter() - .collect(); - - for test in tests { - let res_msg = MsgChannelOpenConfirm::try_from(test.raw.clone()); - - assert_eq!( - test.want_pass, - res_msg.is_ok(), - "MsgChanOpenConfirm::try_from failed for test {}, \nraw msg {:?} with error {:?}", - test.name, - test.raw, - res_msg.err(), - ); - } - } - - #[test] - fn to_and_from() { - let raw = get_dummy_raw_msg_chan_open_confirm(19); - let msg = MsgChannelOpenConfirm::try_from(raw.clone()).unwrap(); - let raw_back = RawMsgChannelOpenConfirm::from(msg.clone()); - let msg_back = MsgChannelOpenConfirm::try_from(raw_back.clone()).unwrap(); - assert_eq!(raw, raw_back); - assert_eq!(msg, msg_back); - } -} diff --git a/modules/src/core/ics04_channel/msgs/chan_open_init.rs b/modules/src/core/ics04_channel/msgs/chan_open_init.rs deleted file mode 100644 index f9ade01ac8..0000000000 --- a/modules/src/core/ics04_channel/msgs/chan_open_init.rs +++ /dev/null @@ -1,160 +0,0 @@ -use crate::core::ics04_channel::channel::ChannelEnd; -use crate::core::ics04_channel::error::Error; -use crate::core::ics24_host::identifier::PortId; -use crate::prelude::*; -use crate::signer::Signer; -use crate::tx_msg::Msg; - -use ibc_proto::ibc::core::channel::v1::MsgChannelOpenInit as RawMsgChannelOpenInit; -use ibc_proto::protobuf::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, - pub channel: ChannelEnd, - pub signer: Signer, -} - -impl MsgChannelOpenInit { - pub fn new(port_id: PortId, channel: ChannelEnd, signer: Signer) -> Self { - Self { - port_id, - channel, - signer, - } - } -} - -impl Msg for MsgChannelOpenInit { - type ValidationError = Error; - type Raw = RawMsgChannelOpenInit; - - fn route(&self) -> String { - crate::keys::ROUTER_KEY.to_string() - } - - fn type_url(&self) -> String { - TYPE_URL.to_string() - } -} - -impl Protobuf for MsgChannelOpenInit {} - -impl TryFrom for MsgChannelOpenInit { - type Error = Error; - - fn try_from(raw_msg: RawMsgChannelOpenInit) -> Result { - Ok(MsgChannelOpenInit { - port_id: raw_msg.port_id.parse().map_err(Error::identifier)?, - channel: raw_msg - .channel - .ok_or_else(Error::missing_channel)? - .try_into()?, - signer: raw_msg.signer.parse().map_err(Error::signer)?, - }) - } -} - -impl From for RawMsgChannelOpenInit { - fn from(domain_msg: MsgChannelOpenInit) -> Self { - RawMsgChannelOpenInit { - port_id: domain_msg.port_id.to_string(), - channel: Some(domain_msg.channel.into()), - signer: domain_msg.signer.to_string(), - } - } -} - -#[cfg(test)] -pub mod test_util { - use crate::prelude::*; - use ibc_proto::ibc::core::channel::v1::MsgChannelOpenInit as RawMsgChannelOpenInit; - - use crate::core::ics04_channel::channel::test_util::get_dummy_raw_channel_end; - use crate::core::ics24_host::identifier::PortId; - use crate::test_utils::get_dummy_bech32_account; - - /// Returns a dummy `RawMsgChannelOpenInit`, for testing only! - pub fn get_dummy_raw_msg_chan_open_init() -> RawMsgChannelOpenInit { - RawMsgChannelOpenInit { - port_id: PortId::default().to_string(), - channel: Some(get_dummy_raw_channel_end()), - signer: get_dummy_bech32_account(), - } - } -} - -#[cfg(test)] -mod tests { - use crate::core::ics04_channel::msgs::chan_open_init::test_util::get_dummy_raw_msg_chan_open_init; - use crate::core::ics04_channel::msgs::chan_open_init::MsgChannelOpenInit; - use crate::prelude::*; - - use ibc_proto::ibc::core::channel::v1::MsgChannelOpenInit as RawMsgChannelOpenInit; - use test_log::test; - - #[test] - fn channel_open_init_from_raw() { - struct Test { - name: String, - raw: RawMsgChannelOpenInit, - want_pass: bool, - } - - let default_raw_msg = get_dummy_raw_msg_chan_open_init(); - - let tests: Vec = vec![ - Test { - name: "Good parameters".to_string(), - raw: default_raw_msg.clone(), - want_pass: true, - }, - Test { - name: "Incorrect port identifier, slash (separator) prohibited".to_string(), - raw: RawMsgChannelOpenInit { - port_id: "p34/".to_string(), - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Missing channel".to_string(), - raw: RawMsgChannelOpenInit { - channel: None, - ..default_raw_msg - }, - want_pass: false, - }, - ] - .into_iter() - .collect(); - - for test in tests { - let res_msg = MsgChannelOpenInit::try_from(test.raw.clone()); - - assert_eq!( - test.want_pass, - res_msg.is_ok(), - "MsgChanOpenInit::try_from failed for test {}, \nraw msg {:?} with error {:?}", - test.name, - test.raw, - res_msg.err(), - ); - } - } - - #[test] - fn to_and_from() { - let raw = get_dummy_raw_msg_chan_open_init(); - let msg = MsgChannelOpenInit::try_from(raw.clone()).unwrap(); - let raw_back = RawMsgChannelOpenInit::from(msg.clone()); - let msg_back = MsgChannelOpenInit::try_from(raw_back.clone()).unwrap(); - assert_eq!(raw, raw_back); - assert_eq!(msg, msg_back); - } -} diff --git a/modules/src/core/ics04_channel/msgs/chan_open_try.rs b/modules/src/core/ics04_channel/msgs/chan_open_try.rs deleted file mode 100644 index 6de1bb6286..0000000000 --- a/modules/src/core/ics04_channel/msgs/chan_open_try.rs +++ /dev/null @@ -1,305 +0,0 @@ -use crate::core::ics04_channel::channel::ChannelEnd; -use crate::core::ics04_channel::error::Error as ChannelError; -use crate::core::ics04_channel::Version; -use crate::core::ics24_host::error::ValidationError; -use crate::core::ics24_host::identifier::{ChannelId, PortId}; -use crate::prelude::*; -use crate::proofs::Proofs; -use crate::signer::Signer; -use crate::tx_msg::Msg; - -use ibc_proto::ibc::core::channel::v1::MsgChannelOpenTry as RawMsgChannelOpenTry; -use ibc_proto::protobuf::Protobuf; - -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, - pub previous_channel_id: Option, - pub channel: ChannelEnd, - pub counterparty_version: Version, - pub proofs: Proofs, - pub signer: Signer, -} - -impl MsgChannelOpenTry { - pub fn new( - port_id: PortId, - previous_channel_id: Option, - channel: ChannelEnd, - counterparty_version: Version, - proofs: Proofs, - signer: Signer, - ) -> Self { - Self { - port_id, - previous_channel_id, - channel, - counterparty_version, - proofs, - signer, - } - } -} - -impl Msg for MsgChannelOpenTry { - type ValidationError = ChannelError; - type Raw = RawMsgChannelOpenTry; - - fn route(&self) -> String { - crate::keys::ROUTER_KEY.to_string() - } - - 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 {} - -impl TryFrom for MsgChannelOpenTry { - type Error = ChannelError; - - fn try_from(raw_msg: RawMsgChannelOpenTry) -> Result { - let proofs = Proofs::new( - raw_msg - .proof_init - .try_into() - .map_err(ChannelError::invalid_proof)?, - None, - None, - None, - raw_msg - .proof_height - .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or_else(ChannelError::missing_height)?, - ) - .map_err(ChannelError::invalid_proof)?; - - let previous_channel_id = Some(raw_msg.previous_channel_id) - .filter(|x| !x.is_empty()) - .map(|v| FromStr::from_str(v.as_str())) - .transpose() - .map_err(ChannelError::identifier)?; - - 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()?, - 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) - } -} - -impl From for RawMsgChannelOpenTry { - fn from(domain_msg: MsgChannelOpenTry) -> Self { - RawMsgChannelOpenTry { - port_id: domain_msg.port_id.to_string(), - previous_channel_id: domain_msg - .previous_channel_id - .map_or_else(|| "".to_string(), |v| v.to_string()), - channel: Some(domain_msg.channel.into()), - counterparty_version: domain_msg.counterparty_version.to_string(), - proof_init: domain_msg.proofs.object_proof().clone().into(), - proof_height: Some(domain_msg.proofs.height().into()), - signer: domain_msg.signer.to_string(), - } - } -} - -#[cfg(test)] -pub mod test_util { - use crate::prelude::*; - use ibc_proto::ibc::core::channel::v1::MsgChannelOpenTry as RawMsgChannelOpenTry; - - use crate::core::ics04_channel::channel::test_util::get_dummy_raw_channel_end; - use crate::core::ics24_host::identifier::{ChannelId, PortId}; - use crate::test_utils::{get_dummy_bech32_account, get_dummy_proof}; - use ibc_proto::ibc::core::client::v1::Height; - - /// Returns a dummy `RawMsgChannelOpenTry`, for testing only! - pub fn get_dummy_raw_msg_chan_open_try(proof_height: u64) -> RawMsgChannelOpenTry { - RawMsgChannelOpenTry { - port_id: PortId::default().to_string(), - previous_channel_id: ChannelId::default().to_string(), - channel: Some(get_dummy_raw_channel_end()), - counterparty_version: "".to_string(), - proof_init: get_dummy_proof(), - proof_height: Some(Height { - revision_number: 0, - revision_height: proof_height, - }), - signer: get_dummy_bech32_account(), - } - } -} - -#[cfg(test)] -mod tests { - use crate::core::ics04_channel::msgs::chan_open_try::test_util::get_dummy_raw_msg_chan_open_try; - use crate::core::ics04_channel::msgs::chan_open_try::MsgChannelOpenTry; - use crate::prelude::*; - - use ibc_proto::ibc::core::channel::v1::MsgChannelOpenTry as RawMsgChannelOpenTry; - use ibc_proto::ibc::core::client::v1::Height; - use test_log::test; - - #[test] - fn channel_open_try_from_raw() { - struct Test { - name: String, - raw: RawMsgChannelOpenTry, - want_pass: bool, - } - - let proof_height = 10; - let default_raw_msg = get_dummy_raw_msg_chan_open_try(proof_height); - - let tests: Vec = vec![ - Test { - name: "Good parameters".to_string(), - raw: default_raw_msg.clone(), - want_pass: true, - }, - Test { - name: "Correct port".to_string(), - raw: RawMsgChannelOpenTry { - port_id: "p34".to_string(), - ..default_raw_msg.clone() - }, - want_pass: true, - }, - Test { - name: "Bad port, name too short".to_string(), - raw: RawMsgChannelOpenTry { - port_id: "p".to_string(), - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Bad port, name too long".to_string(), - raw: RawMsgChannelOpenTry { - port_id: "abcdefghijasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfadgasgasdfasdfaabcdefghijasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfadgasgasdfasdfa".to_string(), - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Correct channel identifier".to_string(), - raw: RawMsgChannelOpenTry { - previous_channel_id: "channel-34".to_string(), - ..default_raw_msg.clone() - }, - want_pass: true, - }, - Test { - name: "Bad channel, name too short".to_string(), - raw: RawMsgChannelOpenTry { - previous_channel_id: "chshort".to_string(), - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Bad channel, name too long".to_string(), - raw: RawMsgChannelOpenTry { - previous_channel_id: "channel-128391283791827398127398791283912837918273981273987912839".to_string(), - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Empty counterparty version (valid choice)".to_string(), - raw: RawMsgChannelOpenTry { - counterparty_version: " ".to_string(), - ..default_raw_msg.clone() - }, - want_pass: true, - }, - Test { - name: "Arbitrary counterparty version (valid choice)".to_string(), - raw: RawMsgChannelOpenTry { - counterparty_version: "anyversion".to_string(), - ..default_raw_msg.clone() - }, - want_pass: true, - }, - Test { - name: "Bad proof height, height = 0".to_string(), - raw: RawMsgChannelOpenTry { - 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: RawMsgChannelOpenTry { - proof_height: None, - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Missing proof init (object proof)".to_string(), - raw: RawMsgChannelOpenTry { - proof_init: Vec::new(), - ..default_raw_msg - }, - want_pass: false, - }, - ] - .into_iter() - .collect(); - - for test in tests { - let res_msg = MsgChannelOpenTry::try_from(test.raw.clone()); - - assert_eq!( - test.want_pass, - res_msg.is_ok(), - "MsgChanOpenTry::try_from failed for test {}, \nraw msg {:?} with error {:?}", - test.name, - test.raw, - res_msg.err(), - ); - } - } - - #[test] - fn to_and_from() { - let raw = get_dummy_raw_msg_chan_open_try(10); - let msg = MsgChannelOpenTry::try_from(raw.clone()).unwrap(); - let raw_back = RawMsgChannelOpenTry::from(msg.clone()); - let msg_back = MsgChannelOpenTry::try_from(raw_back.clone()).unwrap(); - assert_eq!(raw, raw_back); - assert_eq!(msg, msg_back); - } -} diff --git a/modules/src/core/ics04_channel/msgs/recv_packet.rs b/modules/src/core/ics04_channel/msgs/recv_packet.rs deleted file mode 100644 index 274ffa3bb2..0000000000 --- a/modules/src/core/ics04_channel/msgs/recv_packet.rs +++ /dev/null @@ -1,199 +0,0 @@ -use crate::prelude::*; - -use ibc_proto::protobuf::Protobuf; - -use ibc_proto::ibc::core::channel::v1::MsgRecvPacket as RawMsgRecvPacket; - -use crate::core::ics04_channel::error::Error; -use crate::core::ics04_channel::packet::Packet; -use crate::proofs::Proofs; -use crate::signer::Signer; -use crate::tx_msg::Msg; - -pub const TYPE_URL: &str = "/ibc.core.channel.v1.MsgRecvPacket"; - -/// -/// Message definition for the "packet receiving" datagram. -/// -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct MsgRecvPacket { - pub packet: Packet, - pub proofs: Proofs, - pub signer: Signer, -} - -impl MsgRecvPacket { - pub fn new(packet: Packet, proofs: Proofs, signer: Signer) -> MsgRecvPacket { - Self { - packet, - proofs, - signer, - } - } -} - -impl Msg for MsgRecvPacket { - type ValidationError = Error; - type Raw = RawMsgRecvPacket; - - fn route(&self) -> String { - crate::keys::ROUTER_KEY.to_string() - } - - fn type_url(&self) -> String { - TYPE_URL.to_string() - } -} - -impl Protobuf for MsgRecvPacket {} - -impl TryFrom for MsgRecvPacket { - type Error = Error; - - fn try_from(raw_msg: RawMsgRecvPacket) -> Result { - let proofs = Proofs::new( - raw_msg - .proof_commitment - .try_into() - .map_err(Error::invalid_proof)?, - None, - None, - None, - raw_msg - .proof_height - .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or_else(Error::missing_height)?, - ) - .map_err(Error::invalid_proof)?; - - Ok(MsgRecvPacket { - packet: raw_msg - .packet - .ok_or_else(Error::missing_packet)? - .try_into()?, - proofs, - signer: raw_msg.signer.parse().map_err(Error::signer)?, - }) - } -} - -impl From for RawMsgRecvPacket { - fn from(domain_msg: MsgRecvPacket) -> Self { - RawMsgRecvPacket { - packet: Some(domain_msg.packet.into()), - proof_commitment: domain_msg.proofs.object_proof().clone().into(), - proof_height: Some(domain_msg.proofs.height().into()), - signer: domain_msg.signer.to_string(), - } - } -} - -#[cfg(test)] -pub mod test_util { - use ibc_proto::ibc::core::channel::v1::MsgRecvPacket as RawMsgRecvPacket; - use ibc_proto::ibc::core::client::v1::Height as RawHeight; - - use crate::core::ics04_channel::packet::test_utils::get_dummy_raw_packet; - use crate::test_utils::{get_dummy_bech32_account, get_dummy_proof}; - use crate::timestamp::Timestamp; - use core::ops::Add; - use core::time::Duration; - - /// Returns a dummy `RawMsgRecvPacket`, for testing only! The `height` parametrizes both the - /// proof height as well as the timeout height. - pub fn get_dummy_raw_msg_recv_packet(height: u64) -> RawMsgRecvPacket { - let timestamp = Timestamp::now().add(Duration::from_secs(9)); - RawMsgRecvPacket { - packet: Some(get_dummy_raw_packet( - height, - timestamp.unwrap().nanoseconds(), - )), - proof_commitment: get_dummy_proof(), - proof_height: Some(RawHeight { - revision_number: 0, - revision_height: height, - }), - signer: get_dummy_bech32_account(), - } - } -} - -#[cfg(test)] -mod test { - use crate::prelude::*; - - use test_log::test; - - use ibc_proto::ibc::core::channel::v1::MsgRecvPacket as RawMsgRecvPacket; - - use crate::core::ics04_channel::error::Error; - use crate::core::ics04_channel::msgs::recv_packet::test_util::get_dummy_raw_msg_recv_packet; - use crate::core::ics04_channel::msgs::recv_packet::MsgRecvPacket; - use crate::test_utils::get_dummy_bech32_account; - - #[test] - fn msg_recv_packet_try_from_raw() { - struct Test { - name: String, - raw: RawMsgRecvPacket, - want_pass: bool, - } - - let height = 20; - let default_raw_msg = get_dummy_raw_msg_recv_packet(height); - let tests: Vec = vec![ - Test { - name: "Good parameters".to_string(), - raw: default_raw_msg.clone(), - want_pass: true, - }, - Test { - name: "Missing proof".to_string(), - raw: RawMsgRecvPacket { - proof_commitment: Vec::new(), - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Missing proof height".to_string(), - raw: RawMsgRecvPacket { - proof_height: None, - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Empty signer".to_string(), - raw: RawMsgRecvPacket { - signer: get_dummy_bech32_account(), - ..default_raw_msg - }, - want_pass: true, - }, - ]; - - for test in tests { - let res_msg: Result = test.raw.clone().try_into(); - - assert_eq!( - res_msg.is_ok(), - test.want_pass, - "MsgRecvPacket::try_from failed for test {} \nraw message: {:?} with error: {:?}", - test.name, - test.raw, - res_msg.err() - ); - } - } - - #[test] - fn to_and_from() { - let raw = get_dummy_raw_msg_recv_packet(15); - let msg = MsgRecvPacket::try_from(raw.clone()).unwrap(); - let raw_back = RawMsgRecvPacket::from(msg.clone()); - let msg_back = MsgRecvPacket::try_from(raw_back.clone()).unwrap(); - assert_eq!(raw, raw_back); - assert_eq!(msg, msg_back); - } -} diff --git a/modules/src/core/ics04_channel/msgs/timeout.rs b/modules/src/core/ics04_channel/msgs/timeout.rs deleted file mode 100644 index 58d5761e9f..0000000000 --- a/modules/src/core/ics04_channel/msgs/timeout.rs +++ /dev/null @@ -1,220 +0,0 @@ -use crate::prelude::*; - -use ibc_proto::protobuf::Protobuf; - -use ibc_proto::ibc::core::channel::v1::MsgTimeout as RawMsgTimeout; - -use crate::core::ics04_channel::error::Error; -use crate::core::ics04_channel::packet::{Packet, Sequence}; -use crate::proofs::Proofs; -use crate::signer::Signer; -use crate::tx_msg::Msg; - -pub const TYPE_URL: &str = "/ibc.core.channel.v1.MsgTimeout"; - -/// -/// Message definition for packet timeout domain type. -/// -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct MsgTimeout { - pub packet: Packet, - pub next_sequence_recv: Sequence, - pub proofs: Proofs, - pub signer: Signer, -} - -impl MsgTimeout { - pub fn new( - packet: Packet, - next_sequence_recv: Sequence, - proofs: Proofs, - signer: Signer, - ) -> MsgTimeout { - Self { - packet, - next_sequence_recv, - proofs, - signer, - } - } -} - -impl Msg for MsgTimeout { - type ValidationError = Error; - type Raw = RawMsgTimeout; - - fn route(&self) -> String { - crate::keys::ROUTER_KEY.to_string() - } - - fn type_url(&self) -> String { - TYPE_URL.to_string() - } -} - -impl Protobuf for MsgTimeout {} - -impl TryFrom for MsgTimeout { - type Error = Error; - - fn try_from(raw_msg: RawMsgTimeout) -> Result { - let proofs = Proofs::new( - raw_msg - .proof_unreceived - .try_into() - .map_err(Error::invalid_proof)?, - None, - None, - None, - raw_msg - .proof_height - .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or_else(Error::missing_height)?, - ) - .map_err(Error::invalid_proof)?; - - // TODO: Domain type verification for the next sequence: this should probably be > 0. - - Ok(MsgTimeout { - packet: raw_msg - .packet - .ok_or_else(Error::missing_packet)? - .try_into()?, - next_sequence_recv: Sequence::from(raw_msg.next_sequence_recv), - signer: raw_msg.signer.parse().map_err(Error::signer)?, - proofs, - }) - } -} - -impl From for RawMsgTimeout { - fn from(domain_msg: MsgTimeout) -> Self { - RawMsgTimeout { - packet: Some(domain_msg.packet.into()), - proof_unreceived: domain_msg.proofs.object_proof().clone().into(), - proof_height: Some(domain_msg.proofs.height().into()), - next_sequence_recv: domain_msg.next_sequence_recv.into(), - signer: domain_msg.signer.to_string(), - } - } -} - -#[cfg(test)] -pub mod test_util { - use ibc_proto::ibc::core::channel::v1::MsgTimeout as RawMsgTimeout; - use ibc_proto::ibc::core::client::v1::Height as RawHeight; - - use crate::core::ics04_channel::packet::test_utils::get_dummy_raw_packet; - use crate::test_utils::{get_dummy_bech32_account, get_dummy_proof}; - - /// Returns a dummy `RawMsgTimeout`, for testing only! - /// The `height` parametrizes both the proof height as well as the timeout height. - pub fn get_dummy_raw_msg_timeout( - proof_height: u64, - timeout_height: u64, - timeout_timestamp: u64, - ) -> RawMsgTimeout { - RawMsgTimeout { - packet: Some(get_dummy_raw_packet(timeout_height, timeout_timestamp)), - proof_unreceived: get_dummy_proof(), - proof_height: Some(RawHeight { - revision_number: 0, - revision_height: proof_height, - }), - next_sequence_recv: 1, - signer: get_dummy_bech32_account(), - } - } -} - -#[cfg(test)] -mod test { - use crate::prelude::*; - - use test_log::test; - - use ibc_proto::ibc::core::channel::v1::MsgTimeout as RawMsgTimeout; - - use crate::core::ics04_channel::error::Error; - use crate::core::ics04_channel::msgs::timeout::test_util::get_dummy_raw_msg_timeout; - use crate::core::ics04_channel::msgs::timeout::MsgTimeout; - use crate::test_utils::get_dummy_bech32_account; - - #[test] - fn msg_timeout_try_from_raw() { - struct Test { - name: String, - raw: RawMsgTimeout, - want_pass: bool, - } - - let proof_height = 50; - let timeout_height = proof_height; - let timeout_timestamp = 0; - let default_raw_msg = - get_dummy_raw_msg_timeout(proof_height, timeout_height, timeout_timestamp); - - let tests: Vec = vec![ - Test { - name: "Good parameters".to_string(), - raw: default_raw_msg.clone(), - want_pass: true, - }, - Test { - name: "Missing packet".to_string(), - raw: RawMsgTimeout { - packet: None, - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Missing proof".to_string(), - raw: RawMsgTimeout { - proof_unreceived: Vec::new(), - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Missing proof height".to_string(), - raw: RawMsgTimeout { - proof_height: None, - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Empty signer".to_string(), - raw: RawMsgTimeout { - signer: get_dummy_bech32_account(), - ..default_raw_msg - }, - want_pass: true, - }, - ]; - - for test in tests { - let res_msg: Result = test.raw.clone().try_into(); - - assert_eq!( - res_msg.is_ok(), - test.want_pass, - "MsgTimeout::try_from failed for test {} \nraw message: {:?} with error: {:?}", - test.name, - test.raw, - res_msg.err() - ); - } - } - - #[test] - fn to_and_from() { - let raw = get_dummy_raw_msg_timeout(15, 20, 0); - let msg = MsgTimeout::try_from(raw.clone()).unwrap(); - let raw_back = RawMsgTimeout::from(msg.clone()); - let msg_back = MsgTimeout::try_from(raw_back.clone()).unwrap(); - assert_eq!(raw, raw_back); - assert_eq!(msg, msg_back); - } -} diff --git a/modules/src/core/ics04_channel/msgs/timeout_on_close.rs b/modules/src/core/ics04_channel/msgs/timeout_on_close.rs deleted file mode 100644 index 82b10928b1..0000000000 --- a/modules/src/core/ics04_channel/msgs/timeout_on_close.rs +++ /dev/null @@ -1,224 +0,0 @@ -use crate::prelude::*; - -use ibc_proto::ibc::core::channel::v1::MsgTimeoutOnClose as RawMsgTimeoutOnClose; -use ibc_proto::protobuf::Protobuf; - -use crate::core::ics04_channel::error::Error; -use crate::core::ics04_channel::packet::{Packet, Sequence}; -use crate::proofs::Proofs; -use crate::signer::Signer; -use crate::tx_msg::Msg; - -pub const TYPE_URL: &str = "/ibc.core.channel.v1.MsgTimeoutOnClose"; - -/// -/// Message definition for packet timeout domain type. -/// -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct MsgTimeoutOnClose { - pub packet: Packet, - pub next_sequence_recv: Sequence, - pub proofs: Proofs, - pub signer: Signer, -} - -impl MsgTimeoutOnClose { - pub fn new( - packet: Packet, - next_sequence_recv: Sequence, - proofs: Proofs, - signer: Signer, - ) -> MsgTimeoutOnClose { - Self { - packet, - next_sequence_recv, - proofs, - signer, - } - } -} - -impl Msg for MsgTimeoutOnClose { - type ValidationError = Error; - type Raw = RawMsgTimeoutOnClose; - - fn route(&self) -> String { - crate::keys::ROUTER_KEY.to_string() - } - - fn type_url(&self) -> String { - TYPE_URL.to_string() - } -} - -impl Protobuf for MsgTimeoutOnClose {} - -impl TryFrom for MsgTimeoutOnClose { - type Error = Error; - - fn try_from(raw_msg: RawMsgTimeoutOnClose) -> Result { - let proofs = Proofs::new( - raw_msg - .proof_unreceived - .try_into() - .map_err(Error::invalid_proof)?, - None, - None, - Some( - raw_msg - .proof_close - .try_into() - .map_err(Error::invalid_proof)?, - ), - raw_msg - .proof_height - .and_then(|raw_height| raw_height.try_into().ok()) - .ok_or_else(Error::missing_height)?, - ) - .map_err(Error::invalid_proof)?; - - // TODO: Domain type verification for the next sequence: this should probably be > 0. - - Ok(MsgTimeoutOnClose { - packet: raw_msg - .packet - .ok_or_else(Error::missing_packet)? - .try_into()?, - next_sequence_recv: Sequence::from(raw_msg.next_sequence_recv), - signer: raw_msg.signer.parse().map_err(Error::signer)?, - proofs, - }) - } -} - -impl From for RawMsgTimeoutOnClose { - fn from(domain_msg: MsgTimeoutOnClose) -> Self { - RawMsgTimeoutOnClose { - packet: Some(domain_msg.packet.into()), - proof_unreceived: domain_msg.proofs.object_proof().clone().into(), - proof_close: domain_msg - .proofs - .other_proof() - .clone() - .map_or_else(Vec::new, |v| v.into()), - proof_height: Some(domain_msg.proofs.height().into()), - next_sequence_recv: domain_msg.next_sequence_recv.into(), - signer: domain_msg.signer.to_string(), - } - } -} - -#[cfg(test)] -mod tests { - use crate::prelude::*; - use ibc_proto::ibc::core::channel::v1::MsgTimeoutOnClose as RawMsgTimeoutOnClose; - use test_log::test; - - use crate::core::ics04_channel::msgs::timeout_on_close::test_util::get_dummy_raw_msg_timeout_on_close; - use crate::core::ics04_channel::msgs::timeout_on_close::MsgTimeoutOnClose; - - #[test] - fn msg_timeout_on_close_try_from_raw() { - let height = 50; - let timeout_timestamp = 5; - let raw = get_dummy_raw_msg_timeout_on_close(height, timeout_timestamp); - - let msg = MsgTimeoutOnClose::try_from(raw.clone()).unwrap(); - let raw_back = RawMsgTimeoutOnClose::from(msg); - assert_eq!(raw, raw_back); - } - - #[test] - fn parse_timeout_on_close_msg() { - struct Test { - name: String, - raw: RawMsgTimeoutOnClose, - want_pass: bool, - } - - let height = 50; - let timeout_timestamp = 5; - let default_raw_msg = get_dummy_raw_msg_timeout_on_close(height, timeout_timestamp); - - let tests: Vec = vec![ - Test { - name: "Good parameters".to_string(), - raw: default_raw_msg.clone(), - want_pass: true, - }, - Test { - name: "Missing packet".to_string(), - raw: RawMsgTimeoutOnClose { - packet: None, - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Missing proof of unreceived packet".to_string(), - raw: RawMsgTimeoutOnClose { - proof_unreceived: Vec::new(), - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Missing proof of channel".to_string(), - raw: RawMsgTimeoutOnClose { - proof_close: Vec::new(), - ..default_raw_msg.clone() - }, - want_pass: false, - }, - Test { - name: "Missing proof height".to_string(), - raw: RawMsgTimeoutOnClose { - proof_height: None, - ..default_raw_msg - }, - want_pass: false, - }, - ]; - - for test in tests { - let res_msg = MsgTimeoutOnClose::try_from(test.raw.clone()); - - assert_eq!( - test.want_pass, - res_msg.is_ok(), - "MsgTimeoutOnClose::try_from raw failed for test {}, \nraw msg {:?} with error {:?}", - test.name, - test.raw, - res_msg.err(), - ); - } - } -} - -#[cfg(test)] -pub mod test_util { - use ibc_proto::ibc::core::channel::v1::MsgTimeoutOnClose as RawMsgTimeoutOnClose; - use ibc_proto::ibc::core::client::v1::Height as RawHeight; - - use crate::core::ics04_channel::packet::test_utils::get_dummy_raw_packet; - use crate::test_utils::{get_dummy_bech32_account, get_dummy_proof}; - - /// Returns a dummy `RawMsgTimeoutOnClose`, for testing only! - /// The `height` parametrizes both the proof height as well as the timeout height. - pub fn get_dummy_raw_msg_timeout_on_close( - height: u64, - timeout_timestamp: u64, - ) -> RawMsgTimeoutOnClose { - RawMsgTimeoutOnClose { - packet: Some(get_dummy_raw_packet(height, timeout_timestamp)), - proof_unreceived: get_dummy_proof(), - proof_close: get_dummy_proof(), - proof_height: Some(RawHeight { - revision_number: 0, - revision_height: height, - }), - next_sequence_recv: 1, - signer: get_dummy_bech32_account(), - } - } -} diff --git a/modules/src/core/ics04_channel/packet.rs b/modules/src/core/ics04_channel/packet.rs deleted file mode 100644 index 585564caad..0000000000 --- a/modules/src/core/ics04_channel/packet.rs +++ /dev/null @@ -1,465 +0,0 @@ -use crate::prelude::*; - -use core::str::FromStr; - -use serde_derive::{Deserialize, Serialize}; - -use ibc_proto::ibc::core::channel::v1::Packet as RawPacket; - -use super::handler::{ - acknowledgement::AckPacketResult, recv_packet::RecvPacketResult, send_packet::SendPacketResult, - timeout::TimeoutPacketResult, write_acknowledgement::WriteAckPacketResult, -}; -use super::timeout::TimeoutHeight; -use crate::core::ics04_channel::error::Error; -use crate::core::ics24_host::identifier::{ChannelId, PortId}; -use crate::timestamp::{Expiry::Expired, Timestamp}; -use crate::Height; - -/// Enumeration of proof carrying ICS4 message, helper for relayer. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum PacketMsgType { - Recv, - Ack, - TimeoutUnordered, - TimeoutOrdered, - TimeoutOnClose, -} - -#[derive(Clone, Debug)] -pub enum PacketResult { - Send(SendPacketResult), - Recv(RecvPacketResult), - WriteAck(WriteAckPacketResult), - Ack(AckPacketResult), - Timeout(TimeoutPacketResult), -} - -#[derive(Clone, Debug)] -pub enum Receipt { - Ok, -} - -impl core::fmt::Display for PacketMsgType { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - PacketMsgType::Recv => write!(f, "(PacketMsgType::Recv)"), - PacketMsgType::Ack => write!(f, "(PacketMsgType::Ack)"), - PacketMsgType::TimeoutUnordered => write!(f, "(PacketMsgType::TimeoutUnordered)"), - PacketMsgType::TimeoutOrdered => write!(f, "(PacketMsgType::TimeoutOrdered)"), - PacketMsgType::TimeoutOnClose => write!(f, "(PacketMsgType::TimeoutOnClose)"), - } - } -} - -/// The sequence number of a packet enforces ordering among packets from the same source. -#[derive( - Copy, Clone, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord, Deserialize, Serialize, -)] -pub struct Sequence(u64); - -impl FromStr for Sequence { - type Err = Error; - - fn from_str(s: &str) -> Result { - Ok(Self::from(s.parse::().map_err(|e| { - Error::invalid_string_as_sequence(s.to_string(), e) - })?)) - } -} - -impl Sequence { - pub fn is_zero(&self) -> bool { - self.0 == 0 - } - - pub fn increment(&self) -> Sequence { - Sequence(self.0 + 1) - } -} - -impl From for Sequence { - fn from(seq: u64) -> Self { - Sequence(seq) - } -} - -impl From for u64 { - fn from(s: Sequence) -> u64 { - s.0 - } -} - -impl core::fmt::Display for Sequence { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - write!(f, "{}", self.0) - } -} - -#[derive(Clone, Default, Hash, PartialEq, Eq, Deserialize, Serialize)] -pub struct Packet { - pub sequence: Sequence, - pub source_port: PortId, - pub source_channel: ChannelId, - pub destination_port: PortId, - pub destination_channel: ChannelId, - #[serde(serialize_with = "crate::serializers::ser_hex_upper")] - pub data: Vec, - pub timeout_height: TimeoutHeight, - pub timeout_timestamp: Timestamp, -} - -struct PacketData<'a>(&'a [u8]); - -impl<'a> core::fmt::Debug for PacketData<'a> { - fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - write!(formatter, "{:?}", self.0) - } -} - -impl core::fmt::Debug for Packet { - fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - // Remember: if you alter the definition of `Packet`, - // 1. update the formatter debug struct builder calls (return object of - // this function) - // 2. update this destructuring assignment accordingly - let Packet { - sequence: _, - source_port: _, - source_channel: _, - destination_port: _, - destination_channel: _, - data, - timeout_height: _, - timeout_timestamp: _, - } = self; - let data_wrapper = PacketData(data); - - formatter - .debug_struct("Packet") - .field("sequence", &self.sequence) - .field("source_port", &self.source_port) - .field("source_channel", &self.source_channel) - .field("destination_port", &self.destination_port) - .field("destination_channel", &self.destination_channel) - .field("data", &data_wrapper) - .field("timeout_height", &self.timeout_height) - .field("timeout_timestamp", &self.timeout_timestamp) - .finish() - } -} - -impl Packet { - /// Checks whether a packet from a - /// [`SendPacket`](crate::core::ics04_channel::events::SendPacket) - /// event is timed-out relative to the current state of the - /// destination chain. - /// - /// Checks both for time-out relative to the destination chain's - /// current timestamp `dst_chain_ts` as well as relative to - /// the height `dst_chain_height`. - /// - /// Note: a timed-out packet should result in a - /// [`MsgTimeout`](crate::core::ics04_channel::msgs::timeout::MsgTimeout), - /// instead of the common-case where it results in - /// [`MsgRecvPacket`](crate::core::ics04_channel::msgs::recv_packet::MsgRecvPacket). - pub fn timed_out(&self, dst_chain_ts: &Timestamp, dst_chain_height: Height) -> bool { - let height_timed_out = self.timeout_height.has_expired(dst_chain_height); - - let timestamp_timed_out = self.timeout_timestamp != Timestamp::none() - && dst_chain_ts.check_expiry(&self.timeout_timestamp) == Expired; - - height_timed_out || timestamp_timed_out - } -} - -/// Custom debug output to omit the packet data -impl core::fmt::Display for Packet { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - write!( - f, - "seq:{}, path:{}/{}->{}/{}, toh:{}, tos:{})", - self.sequence, - self.source_channel, - self.source_port, - self.destination_channel, - self.destination_port, - self.timeout_height, - self.timeout_timestamp - ) - } -} - -impl TryFrom for Packet { - type Error = Error; - - fn try_from(raw_pkt: RawPacket) -> Result { - if Sequence::from(raw_pkt.sequence).is_zero() { - return Err(Error::zero_packet_sequence()); - } - - // Note: ibc-go currently (July 2022) incorrectly treats the timeout - // heights `{revision_number : >0, revision_height: 0}` as valid - // timeouts. However, heights with `revision_height == 0` are invalid in - // Tendermint. We explicitly reject these values because they go against - // the Tendermint spec, and shouldn't be used. To timeout on the next - // revision_number as soon as the chain starts, - // `{revision_number: old_rev + 1, revision_height: 1}` - // should be used. - let packet_timeout_height: TimeoutHeight = raw_pkt - .timeout_height - .try_into() - .map_err(|_| Error::invalid_timeout_height())?; - - if raw_pkt.data.is_empty() { - return Err(Error::zero_packet_data()); - } - - let timeout_timestamp = Timestamp::from_nanoseconds(raw_pkt.timeout_timestamp) - .map_err(Error::invalid_packet_timestamp)?; - - Ok(Packet { - sequence: Sequence::from(raw_pkt.sequence), - source_port: raw_pkt.source_port.parse().map_err(Error::identifier)?, - source_channel: raw_pkt.source_channel.parse().map_err(Error::identifier)?, - destination_port: raw_pkt - .destination_port - .parse() - .map_err(Error::identifier)?, - destination_channel: raw_pkt - .destination_channel - .parse() - .map_err(Error::identifier)?, - data: raw_pkt.data, - timeout_height: packet_timeout_height, - timeout_timestamp, - }) - } -} - -impl From for RawPacket { - fn from(packet: Packet) -> Self { - RawPacket { - sequence: packet.sequence.0, - source_port: packet.source_port.to_string(), - source_channel: packet.source_channel.to_string(), - destination_port: packet.destination_port.to_string(), - destination_channel: packet.destination_channel.to_string(), - data: packet.data, - timeout_height: packet.timeout_height.into(), - timeout_timestamp: packet.timeout_timestamp.nanoseconds(), - } - } -} - -#[cfg(test)] -pub mod test_utils { - use crate::prelude::*; - use ibc_proto::ibc::core::channel::v1::Packet as RawPacket; - use ibc_proto::ibc::core::client::v1::Height as RawHeight; - - use crate::core::ics24_host::identifier::{ChannelId, PortId}; - - /// Returns a dummy `RawPacket`, for testing only! - pub fn get_dummy_raw_packet(timeout_height: u64, timeout_timestamp: u64) -> RawPacket { - RawPacket { - sequence: 1, - source_port: PortId::default().to_string(), - source_channel: ChannelId::default().to_string(), - destination_port: PortId::default().to_string(), - destination_channel: ChannelId::default().to_string(), - data: vec![0], - timeout_height: Some(RawHeight { - revision_number: 0, - revision_height: timeout_height, - }), - timeout_timestamp, - } - } -} - -#[cfg(test)] -mod tests { - use crate::prelude::*; - - use test_log::test; - - use ibc_proto::ibc::core::channel::v1::Packet as RawPacket; - use ibc_proto::ibc::core::client::v1::Height as RawHeight; - - use crate::core::ics04_channel::packet::test_utils::get_dummy_raw_packet; - use crate::core::ics04_channel::packet::Packet; - - #[test] - fn packet_try_from_raw() { - struct Test { - name: String, - raw: RawPacket, - want_pass: bool, - } - - let proof_height = 10; - let default_raw_packet = get_dummy_raw_packet(proof_height, 0); - let raw_packet_no_timeout_or_timestamp = get_dummy_raw_packet(0, 0); - - let mut raw_packet_invalid_timeout_height = get_dummy_raw_packet(0, 0); - raw_packet_invalid_timeout_height.timeout_height = Some(RawHeight { - revision_number: 1, - revision_height: 0, - }); - - let tests: Vec = vec![ - Test { - name: "Good parameters".to_string(), - raw: default_raw_packet.clone(), - want_pass: true, - }, - Test { - // Note: ibc-go currently (July 2022) incorrectly rejects this - // case, even though it is allowed in ICS-4. - name: "Packet with no timeout of timestamp".to_string(), - raw: raw_packet_no_timeout_or_timestamp, - want_pass: true, - }, - Test { - name: "Packet with invalid timeout height".to_string(), - raw: raw_packet_invalid_timeout_height, - want_pass: false, - }, - Test { - name: "Src port validation: correct".to_string(), - raw: RawPacket { - source_port: "srcportp34".to_string(), - ..default_raw_packet.clone() - }, - want_pass: true, - }, - Test { - name: "Bad src port, name too short".to_string(), - raw: RawPacket { - source_port: "p".to_string(), - ..default_raw_packet.clone() - }, - want_pass: false, - }, - Test { - name: "Bad src port, name too long".to_string(), - raw: RawPacket { - source_port: "abcdefghijasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfadgasgasdfasdfasdfasdfaklmnopqrstuabcdefghijasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfadgasgasdfasdfasdfasdfaklmnopqrstu".to_string(), - ..default_raw_packet.clone() - }, - want_pass: false, - }, - Test { - name: "Dst port validation: correct".to_string(), - raw: RawPacket { - destination_port: "destportsrcp34".to_string(), - ..default_raw_packet.clone() - }, - want_pass: true, - }, - Test { - name: "Bad dst port, name too short".to_string(), - raw: RawPacket { - destination_port: "p".to_string(), - ..default_raw_packet.clone() - }, - want_pass: false, - }, - Test { - name: "Bad dst port, name too long".to_string(), - raw: RawPacket { - destination_port: "abcdefghijasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfadgasgasdfasdfasdfasdfaklmnopqrstuabcdefghijasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfadgasgasdfas".to_string(), - ..default_raw_packet.clone() - }, - want_pass: false, - }, - Test { - name: "Src channel validation: correct".to_string(), - raw: RawPacket { - source_channel: "channel-1".to_string(), - ..default_raw_packet.clone() - }, - want_pass: true, - }, - Test { - name: "Bad src channel, name too short".to_string(), - raw: RawPacket { - source_channel: "p".to_string(), - ..default_raw_packet.clone() - }, - want_pass: false, - }, - Test { - name: "Bad src channel, name too long".to_string(), - raw: RawPacket { - source_channel: "channel-128391283791827398127398791283912837918273981273987912839".to_string(), - ..default_raw_packet.clone() - }, - want_pass: false, - }, - Test { - name: "Dst channel validation: correct".to_string(), - raw: RawPacket { - destination_channel: "channel-34".to_string(), - ..default_raw_packet.clone() - }, - want_pass: true, - }, - Test { - name: "Bad dst channel, name too short".to_string(), - raw: RawPacket { - destination_channel: "p".to_string(), - ..default_raw_packet.clone() - }, - want_pass: false, - }, - Test { - name: "Bad dst channel, name too long".to_string(), - raw: RawPacket { - destination_channel: "channel-128391283791827398127398791283912837918273981273987912839".to_string(), - ..default_raw_packet.clone() - }, - want_pass: false, - }, - // Note: `timeout_height == None` is a quirk of protobuf. In - // `proto3` syntax, all structs are "nullable" by default and are - // represented as `Option`. `ibc-go` defines the protobuf file - // with the extension option `gogoproto.nullable = false`, which - // means that they will always generate a field. It is left - // unspecified what a `None` value means. In this case, I believe it - // is best to assume the obvious semantic of "no timeout". - Test { - name: "Missing timeout height".to_string(), - raw: RawPacket { - timeout_height: None, - ..default_raw_packet - }, - want_pass: true, - }, - ]; - - for test in tests { - let res_msg = Packet::try_from(test.raw.clone()); - - assert_eq!( - test.want_pass, - res_msg.is_ok(), - "Packet::try_from failed for test {}, \nraw packet {:?} with error {:?}", - test.name, - test.raw, - res_msg.err(), - ); - } - } - - #[test] - fn to_and_from() { - let raw = get_dummy_raw_packet(15, 0); - let msg = Packet::try_from(raw.clone()).unwrap(); - let raw_back = RawPacket::from(msg.clone()); - let msg_back = Packet::try_from(raw_back.clone()).unwrap(); - assert_eq!(raw, raw_back); - assert_eq!(msg, msg_back); - } -} diff --git a/modules/src/core/ics04_channel/timeout.rs b/modules/src/core/ics04_channel/timeout.rs deleted file mode 100644 index 7e91d47b2c..0000000000 --- a/modules/src/core/ics04_channel/timeout.rs +++ /dev/null @@ -1,185 +0,0 @@ -use core::fmt::{Display, Error as FmtError, Formatter}; - -use serde::{Deserialize, Serialize}; - -use ibc_proto::ibc::core::client::v1::Height as RawHeight; -use tendermint::abci::tag::Value as TagValue; - -use crate::core::ics02_client::{error::Error as ICS2Error, height::Height}; -use crate::prelude::*; - -/// 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. -/// -/// `TimeoutHeight` is treated differently from other heights because -/// -/// `RawHeight.timeout_height == {revision_number: 0, revision_height = 0}` -/// -/// is legal and meaningful, even though the Tendermint spec rejects this height -/// as invalid. Thus, it must be parsed specially, where this special case means -/// "no timeout". -#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)] -pub enum TimeoutHeight { - Never, - At(Height), -} - -impl TimeoutHeight { - pub fn no_timeout() -> Self { - Self::Never - } - - /// Revision number to be used in packet commitment computation - pub fn commitment_revision_number(&self) -> u64 { - match self { - Self::At(height) => height.revision_number(), - Self::Never => 0, - } - } - - /// Revision height to be used in packet commitment computation - pub fn commitment_revision_height(&self) -> u64 { - match self { - Self::At(height) => height.revision_height(), - Self::Never => 0, - } - } - - /// Check if a height is *stricly past* the timeout height, and thus is - /// deemed expired. - pub fn has_expired(&self, height: Height) -> bool { - match self { - Self::At(timeout_height) => height > *timeout_height, - // When there's no timeout, heights are never expired - Self::Never => false, - } - } -} - -impl Default for TimeoutHeight { - fn default() -> Self { - Self::Never - } -} - -impl TryFrom for TimeoutHeight { - type Error = ICS2Error; - - // Note: it is important for `revision_number` to also be `0`, otherwise - // packet commitment proofs will be incorrect (proof construction in - // `ChannelReader::packet_commitment()` uses both `revision_number` and - // `revision_height`). Note also that ibc-go conforms to this convention. - fn try_from(raw_height: RawHeight) -> Result { - if raw_height.revision_number == 0 && raw_height.revision_height == 0 { - Ok(TimeoutHeight::Never) - } else { - let height: Height = raw_height.try_into()?; - Ok(TimeoutHeight::At(height)) - } - } -} - -impl TryFrom> for TimeoutHeight { - type Error = ICS2Error; - - fn try_from(maybe_raw_height: Option) -> Result { - match maybe_raw_height { - Some(raw_height) => Self::try_from(raw_height), - None => Ok(TimeoutHeight::Never), - } - } -} -/// We map "no timeout height" to `Some(RawHeight::zero)` due to a quirk -/// in ICS-4. See . -impl From for Option { - fn from(timeout_height: TimeoutHeight) -> Self { - let raw_height = match timeout_height { - TimeoutHeight::At(height) => height.into(), - TimeoutHeight::Never => RawHeight { - revision_number: 0, - revision_height: 0, - }, - }; - - Some(raw_height) - } -} - -impl From for TimeoutHeight { - fn from(height: Height) -> Self { - Self::At(height) - } -} - -impl From for TagValue { - fn from(timeout_height: TimeoutHeight) -> Self { - match timeout_height { - TimeoutHeight::At(height) => height.to_string().parse().unwrap(), - TimeoutHeight::Never => "0-0".parse().unwrap(), - } - } -} - -impl Display for TimeoutHeight { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - match self { - TimeoutHeight::At(timeout_height) => write!(f, "{}", timeout_height), - TimeoutHeight::Never => write!(f, "no timeout"), - } - } -} - -impl Serialize for TimeoutHeight { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - // When there is no timeout, we cannot construct an ICS02 Height with - // revision number and height at zero, so we have to define an - // isomorphic struct to serialize it as if it were an ICS02 height. - #[derive(Serialize)] - struct Height { - revision_number: u64, - revision_height: u64, - } - - match self { - // If there is no timeout, we use our ad-hoc struct above - TimeoutHeight::Never => { - let zero = Height { - revision_number: 0, - revision_height: 0, - }; - - zero.serialize(serializer) - } - // Otherwise we can directly serialize the underlying height - TimeoutHeight::At(height) => height.serialize(serializer), - } - } -} - -impl<'de> Deserialize<'de> for TimeoutHeight { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - use crate::core::ics02_client::height::Height as Ics02Height; - - // Here we have to use a bespoke struct as well in order to deserialize - // a height which may have a revision height equal to zero. - #[derive(Deserialize)] - struct Height { - revision_number: u64, - revision_height: u64, - } - - Height::deserialize(deserializer).map(|height| { - Ics02Height::new(height.revision_number, height.revision_height) - // If it's a valid height with a non-zero revision height, then we have a timeout - .map(TimeoutHeight::At) - // Otherwise, no timeout - .unwrap_or(TimeoutHeight::Never) - }) - } -} diff --git a/modules/src/core/ics04_channel/version.rs b/modules/src/core/ics04_channel/version.rs deleted file mode 100644 index 3ca28976b4..0000000000 --- a/modules/src/core/ics04_channel/version.rs +++ /dev/null @@ -1,60 +0,0 @@ -//! Data type definition and utilities for the -//! version field of a channel end. -//! - -use core::convert::Infallible; -use core::fmt::{Display, Error as FmtError, Formatter}; -use core::str::FromStr; -use serde_derive::{Deserialize, Serialize}; - -use crate::applications::transfer; -use crate::prelude::*; - -/// The version field for a `ChannelEnd`. -/// -/// This field is opaque to the core IBC protocol. -/// No explicit validation is necessary, and the -/// spec (v1) currently allows empty strings. -#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] -pub struct Version(String); - -impl Version { - pub fn new(v: String) -> Self { - Self(v) - } - - pub fn ics20() -> Self { - Self::new(transfer::VERSION.to_string()) - } - - pub fn empty() -> Self { - Self::new("".to_string()) - } -} - -impl From for Version { - fn from(s: String) -> Self { - Self::new(s) - } -} - -impl FromStr for Version { - type Err = Infallible; - - fn from_str(s: &str) -> Result { - Ok(Self::new(s.to_string())) - } -} - -/// The default version is empty (unspecified). -impl Default for Version { - fn default() -> Self { - Version::empty() - } -} - -impl Display for Version { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "{}", self.0) - } -} diff --git a/modules/src/core/ics05_port/context.rs b/modules/src/core/ics05_port/context.rs deleted file mode 100644 index 2c59d4a592..0000000000 --- a/modules/src/core/ics05_port/context.rs +++ /dev/null @@ -1,10 +0,0 @@ -use crate::core::ics05_port::error::Error; -use crate::core::ics24_host::identifier::PortId; -use crate::core::ics26_routing::context::ModuleId; -use crate::prelude::*; - -/// A context supplying all the necessary read-only dependencies for processing any information regarding a port. -pub trait PortReader { - /// Return the module_id associated with a given port_id - fn lookup_module_by_port(&self, port_id: &PortId) -> Result; -} diff --git a/modules/src/core/ics05_port/error.rs b/modules/src/core/ics05_port/error.rs deleted file mode 100644 index 4c49d3d800..0000000000 --- a/modules/src/core/ics05_port/error.rs +++ /dev/null @@ -1,22 +0,0 @@ -use crate::core::ics24_host::identifier::PortId; -use flex_error::define_error; - -define_error! { - #[derive(Debug, PartialEq, Eq)] - Error { - UnknownPort - { port_id: PortId } - | e | { format_args!("port '{0}' is unknown", e.port_id) }, - - PortAlreadyBound - { port_id: PortId } - | e | { format_args!("port '{0}' is already bound", e.port_id) }, - - ModuleNotFound - { port_id: PortId } - | e | { format_args!("could not retrieve module from port '{0}'", e.port_id) }, - - ImplementationSpecific - | _ | { "implementation specific error" }, - } -} diff --git a/modules/src/core/ics05_port/mod.rs b/modules/src/core/ics05_port/mod.rs deleted file mode 100644 index 103464b7f6..0000000000 --- a/modules/src/core/ics05_port/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -//! ICS 05: Port implementation specifies the allocation scheme used by modules to -//! bind to uniquely named ports. - -pub mod context; -pub mod error; diff --git a/modules/src/core/ics23_commitment/commitment.rs b/modules/src/core/ics23_commitment/commitment.rs deleted file mode 100644 index 59a9df743b..0000000000 --- a/modules/src/core/ics23_commitment/commitment.rs +++ /dev/null @@ -1,170 +0,0 @@ -use crate::core::ics23_commitment::error::Error; -use crate::prelude::*; -use crate::proofs::ProofError; - -use core::{convert::TryFrom, fmt}; -use ibc_proto::ibc::core::commitment::v1::MerkleProof as RawMerkleProof; -use serde::{Deserialize, Serialize}; -use subtle_encoding::{Encoding, Hex}; - -use super::merkle::MerkleProof; - -#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(transparent)] -pub struct CommitmentRoot { - #[serde(serialize_with = "crate::serializers::ser_hex_upper")] - bytes: Vec, -} - -impl fmt::Debug for CommitmentRoot { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let hex = Hex::upper_case().encode_to_string(&self.bytes).unwrap(); - f.debug_tuple("CommitmentRoot").field(&hex).finish() - } -} - -impl CommitmentRoot { - pub fn from_bytes(bytes: &[u8]) -> Self { - Self { - bytes: Vec::from(bytes), - } - } - - pub fn as_bytes(&self) -> &[u8] { - &self.bytes - } - - pub fn into_vec(self) -> Vec { - self.bytes - } -} - -impl From> for CommitmentRoot { - fn from(bytes: Vec) -> Self { - Self { bytes } - } -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct CommitmentPath; - -#[derive(Clone, PartialEq, Eq, Serialize)] -#[serde(transparent)] -pub struct CommitmentProofBytes { - #[serde(serialize_with = "crate::serializers::ser_hex_upper")] - bytes: Vec, -} - -impl fmt::Debug for CommitmentProofBytes { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let hex = Hex::upper_case().encode_to_string(&self.bytes).unwrap(); - f.debug_tuple("CommitmentProof").field(&hex).finish() - } -} - -impl TryFrom> for CommitmentProofBytes { - type Error = ProofError; - - fn try_from(bytes: Vec) -> Result { - if bytes.is_empty() { - Err(Self::Error::empty_proof()) - } else { - Ok(Self { bytes }) - } - } -} - -impl From for Vec { - fn from(p: CommitmentProofBytes) -> Vec { - p.bytes - } -} - -impl TryFrom for CommitmentProofBytes { - type Error = ProofError; - - fn try_from(proof: RawMerkleProof) -> Result { - let mut buf = Vec::new(); - prost::Message::encode(&proof, &mut buf).unwrap(); - buf.try_into() - } -} - -impl TryFrom for CommitmentProofBytes { - type Error = ProofError; - - fn try_from(value: MerkleProof) -> Result { - Self::try_from(RawMerkleProof::from(value)) - } -} - -impl TryFrom for RawMerkleProof { - type Error = Error; - - fn try_from(value: CommitmentProofBytes) -> Result { - let value: Vec = value.into(); - let res: RawMerkleProof = - prost::Message::decode(value.as_ref()).map_err(Error::invalid_raw_merkle_proof)?; - Ok(res) - } -} - -#[derive(Clone, PartialEq, Eq, Hash, Deserialize, Default)] -pub struct CommitmentPrefix { - bytes: Vec, -} - -impl CommitmentPrefix { - pub fn as_bytes(&self) -> &[u8] { - &self.bytes - } - - pub fn into_vec(self) -> Vec { - self.bytes - } -} - -impl TryFrom> for CommitmentPrefix { - type Error = Error; - - fn try_from(bytes: Vec) -> Result { - if bytes.is_empty() { - Err(Self::Error::empty_commitment_prefix()) - } else { - Ok(Self { bytes }) - } - } -} - -impl fmt::Debug for CommitmentPrefix { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let converted = core::str::from_utf8(self.as_bytes()); - match converted { - Ok(s) => write!(f, "{}", s), - Err(_e) => write!(f, "", self.as_bytes()), - } - } -} - -impl Serialize for CommitmentPrefix { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - format!("{:?}", self).serialize(serializer) - } -} - -#[cfg(test)] -pub mod test_util { - use crate::prelude::*; - use ibc_proto::ibc::core::commitment::v1::MerkleProof as RawMerkleProof; - use ibc_proto::ics23::CommitmentProof; - - /// Returns a dummy `RawMerkleProof`, for testing only! - pub fn get_dummy_merkle_proof() -> RawMerkleProof { - let parsed = CommitmentProof { proof: None }; - let mproofs: Vec = vec![parsed]; - RawMerkleProof { proofs: mproofs } - } -} diff --git a/modules/src/core/ics23_commitment/error.rs b/modules/src/core/ics23_commitment/error.rs deleted file mode 100644 index 260c9557b4..0000000000 --- a/modules/src/core/ics23_commitment/error.rs +++ /dev/null @@ -1,39 +0,0 @@ -use flex_error::{define_error, TraceError}; -use prost::DecodeError; - -define_error! { - #[derive(Debug, PartialEq, Eq)] - Error { - InvalidRawMerkleProof - [ TraceError ] - |_| { "invalid raw merkle proof" }, - - CommitmentProofDecodingFailed - [ TraceError ] - |_| { "failed to decode commitment proof" }, - - EmptyCommitmentPrefix - |_| { "empty commitment prefix" }, - - EmptyMerkleProof - |_| { "empty merkle proof" }, - - EmptyMerkleRoot - |_| { "empty merkle root" }, - - EmptyVerifiedValue - |_| { "empty verified value" }, - - NumberOfSpecsMismatch - |_| { "mismatch between the number of proofs with that of specs" }, - - NumberOfKeysMismatch - |_| { "mismatch between the number of proofs with that of keys" }, - - InvalidMerkleProof - |_| { "invalid merkle proof" }, - - VerificationFailure - |_| { "proof verification failed" } - } -} diff --git a/modules/src/core/ics23_commitment/merkle.rs b/modules/src/core/ics23_commitment/merkle.rs deleted file mode 100644 index 74e990d76c..0000000000 --- a/modules/src/core/ics23_commitment/merkle.rs +++ /dev/null @@ -1,264 +0,0 @@ -use crate::prelude::*; -use tendermint::merkle::proof::Proof as TendermintProof; - -use ibc_proto::ibc::core::commitment::v1::MerklePath; -use ibc_proto::ibc::core::commitment::v1::MerkleProof as RawMerkleProof; -use ibc_proto::ibc::core::commitment::v1::MerkleRoot; -use ics23::commitment_proof::Proof; -use ics23::{ - calculate_existence_root, verify_membership, verify_non_membership, CommitmentProof, - NonExistenceProof, -}; - -use crate::core::ics23_commitment::commitment::{CommitmentPrefix, CommitmentRoot}; -use crate::core::ics23_commitment::error::Error; -use crate::core::ics23_commitment::specs::ProofSpecs; - -pub fn apply_prefix(prefix: &CommitmentPrefix, mut path: Vec) -> MerklePath { - let mut key_path: Vec = vec![format!("{:?}", prefix)]; - key_path.append(&mut path); - MerklePath { key_path } -} - -impl From for MerkleRoot { - fn from(root: CommitmentRoot) -> Self { - Self { - hash: root.into_vec(), - } - } -} - -#[derive(Clone, Debug, PartialEq)] -pub struct MerkleProof { - pub proofs: Vec, -} - -/// Convert to ics23::CommitmentProof -/// The encoding and decoding shouldn't fail since ics23::CommitmentProof and ibc_proto::ics23::CommitmentProof should be the same -/// Ref. -impl From for MerkleProof { - fn from(proof: RawMerkleProof) -> Self { - let proofs: Vec = proof - .proofs - .into_iter() - .map(|p| { - let mut encoded = Vec::new(); - prost::Message::encode(&p, &mut encoded).unwrap(); - prost::Message::decode(&*encoded).unwrap() - }) - .collect(); - Self { proofs } - } -} - -impl From for RawMerkleProof { - fn from(proof: MerkleProof) -> Self { - Self { - proofs: proof - .proofs - .into_iter() - .map(|p| { - let mut encoded = Vec::new(); - prost::Message::encode(&p, &mut encoded).unwrap(); - prost::Message::decode(&*encoded).unwrap() - }) - .collect(), - } - } -} - -impl MerkleProof { - pub fn verify_membership( - &self, - specs: &ProofSpecs, - root: MerkleRoot, - keys: MerklePath, - value: Vec, - start_index: usize, - ) -> Result<(), Error> { - // validate arguments - if self.proofs.is_empty() { - return Err(Error::empty_merkle_proof()); - } - if root.hash.is_empty() { - return Err(Error::empty_merkle_root()); - } - let num = self.proofs.len(); - let ics23_specs = Vec::::from(specs.clone()); - if ics23_specs.len() != num { - return Err(Error::number_of_specs_mismatch()); - } - if keys.key_path.len() != num { - return Err(Error::number_of_keys_mismatch()); - } - if value.is_empty() { - return Err(Error::empty_verified_value()); - } - - let mut subroot = value.clone(); - let mut value = value; - // keys are represented from root-to-leaf - for ((proof, spec), key) in self - .proofs - .iter() - .zip(ics23_specs.iter()) - .zip(keys.key_path.iter().rev()) - .skip(start_index) - { - match &proof.proof { - Some(Proof::Exist(existence_proof)) => { - subroot = - calculate_existence_root::(existence_proof) - .map_err(|_| Error::invalid_merkle_proof())?; - - if !verify_membership::( - proof, - spec, - &subroot, - key.as_bytes(), - &value, - ) { - return Err(Error::verification_failure()); - } - value = subroot.clone(); - } - _ => return Err(Error::invalid_merkle_proof()), - } - } - - if root.hash != subroot { - return Err(Error::verification_failure()); - } - - Ok(()) - } - - pub fn verify_non_membership( - &self, - specs: &ProofSpecs, - root: MerkleRoot, - keys: MerklePath, - ) -> Result<(), Error> { - // validate arguments - if self.proofs.is_empty() { - return Err(Error::empty_merkle_proof()); - } - if root.hash.is_empty() { - return Err(Error::empty_merkle_root()); - } - let num = self.proofs.len(); - let ics23_specs = Vec::::from(specs.clone()); - if ics23_specs.len() != num { - return Err(Error::number_of_specs_mismatch()); - } - if keys.key_path.len() != num { - return Err(Error::number_of_keys_mismatch()); - } - - // verify the absence of key in lowest subtree - let proof = self.proofs.get(0).ok_or_else(Error::invalid_merkle_proof)?; - let spec = ics23_specs.get(0).ok_or_else(Error::invalid_merkle_proof)?; - // keys are represented from root-to-leaf - let key = keys - .key_path - .get(num - 1) - .ok_or_else(Error::invalid_merkle_proof)?; - match &proof.proof { - Some(Proof::Nonexist(non_existence_proof)) => { - let subroot = calculate_non_existence_root(non_existence_proof)?; - - if !verify_non_membership::( - proof, - spec, - &subroot, - key.as_bytes(), - ) { - return Err(Error::verification_failure()); - } - - // verify membership proofs starting from index 1 with value = subroot - self.verify_membership(specs, root, keys, subroot, 1) - } - _ => Err(Error::invalid_merkle_proof()), - } - } -} - -// TODO move to ics23 -fn calculate_non_existence_root(proof: &NonExistenceProof) -> Result, Error> { - if let Some(left) = &proof.left { - calculate_existence_root::(left) - .map_err(|_| Error::invalid_merkle_proof()) - } else if let Some(right) = &proof.right { - calculate_existence_root::(right) - .map_err(|_| Error::invalid_merkle_proof()) - } else { - Err(Error::invalid_merkle_proof()) - } -} - -// Merkle Proof serialization notes: -// "Proof" id currently defined in a number of forms and included in a number of places -// - TmProof: in tendermint-rs/src/merkle/proof.rs:Proof -// - RawProofOps: in tendermint-proto/tendermint.cyrpto.rs:ProofOps -// - RawMerkleProof: in ibc-proto/ibc.core.commitment.v1.rs:MerkleProof -// - structure that includes a RawProofOps in its only `proof` field. -// #[derive(Clone, PartialEq, ::prost::Message)] -// pub struct MerkleProof { -// #[prost(message, optional, tag="1")] -// pub proof: ::core::option::Option<::tendermint_proto::crypto::ProofOps>, -// } -// - Vec: RawMerkleProof is not explicitly used but, serialized as Vec, it is -// included in all handshake messages that require proofs (i.e. all except the two `OpenInit`), -// and also in all queries that require proofs -// - MerkleProof: Domain type for RawMerkleProof, currently not used and identical to RawMerkleProof. -// This will change with verification implementation. -// - CommitmentProof: Defined in ibc-rs as Vec and currently used in all its messages -// -// Here are a couple of flows that illustrate the different conversions: -// IBC Messages and Handlers: sink happens in the handle verification -// Vec -> CommitmentProof -> RawMerkleProof -> MerkleProof -// -// Relayer: from the proof in the query response to the proof being included in a message -// TmProof -> RawProofOps => RawMerkleProof -> MerkleProof -> verify() -// -> MerkleProof -> RawMerkleProof -> CommitmentProof -> Vec -// Note: current implementation for ^ is simplified since verification is not yet implemented: -// TmProof -> RawProofOps => RawMerkleProof -> CommitmentProof -> Vec -// -// Implementations of (de)serializers and conversions: -// - commitment.rs: -// Vec <-> CommitmentProof -// CommitmentProof <-> RawMerkleProof -// - merkle.rs: -// RawMerkleProof <-> MerkleProof -// - tendermint-rs/src/merkle/proof.rs: -// TmProof <-> RawProofOps -// - cosmos.rs:abci_query() converts from query proof to Merkle proof: -// RawProofOps => RawMerkleProof -// -// impl TryFrom for MerkleProof { -// type Error = Error; -// fn try_from(value: RawMerkleProof) -> Result { -// Ok(MerkleProof { proof: value.proofs.into_iter().map(|v| v.into()).collect() }) -// } -// } -// -// impl From for RawMerkleProof { -// fn from(value: MerkleProof) -> Self { -// RawMerkleProof { proof: value.proof } -// } -// } - -pub fn convert_tm_to_ics_merkle_proof(tm_proof: &TendermintProof) -> Result { - let mut proofs = Vec::new(); - - for op in &tm_proof.ops { - let mut parsed = ibc_proto::ics23::CommitmentProof { proof: None }; - prost::Message::merge(&mut parsed, op.data.as_slice()) - .map_err(Error::commitment_proof_decoding_failed)?; - - proofs.push(parsed); - } - - Ok(MerkleProof::from(RawMerkleProof { proofs })) -} diff --git a/modules/src/core/ics23_commitment/mock.rs b/modules/src/core/ics23_commitment/mock.rs deleted file mode 100644 index 8b13789179..0000000000 --- a/modules/src/core/ics23_commitment/mock.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/modules/src/core/ics23_commitment/mod.rs b/modules/src/core/ics23_commitment/mod.rs deleted file mode 100644 index e3806ad771..0000000000 --- a/modules/src/core/ics23_commitment/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -//! ICS 23: Commitment implementation of a cryptographic scheme that verifies -//! state transitions between chains. - -pub mod commitment; -pub mod error; -pub mod merkle; -pub mod mock; -pub mod specs; diff --git a/modules/src/core/ics23_commitment/specs.rs b/modules/src/core/ics23_commitment/specs.rs deleted file mode 100644 index 53e45a5912..0000000000 --- a/modules/src/core/ics23_commitment/specs.rs +++ /dev/null @@ -1,148 +0,0 @@ -use crate::prelude::*; -use ibc_proto::ics23::{InnerSpec as IbcInnerSpec, LeafOp as IbcLeafOp, ProofSpec as IbcProofSpec}; -use ics23::{InnerSpec as Ics23InnerSpec, LeafOp as Ics23LeafOp, ProofSpec as Ics23ProofSpec}; -use serde::{Deserialize, Serialize}; - -/// An array of proof specifications. -/// -/// This type encapsulates different types of proof specifications, mostly predefined, e.g., for -/// Cosmos-SDK. -/// Additionally, this type also aids in the conversion from `ProofSpec` types from crate `ics23` -/// into proof specifications as represented in the `ibc_proto` type; see the -/// `From` trait(s) below. -#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] -pub struct ProofSpecs(Vec); - -impl ProofSpecs { - /// Returns the specification for Cosmos-SDK proofs - pub fn cosmos() -> Self { - vec![ - ics23::iavl_spec(), // Format of proofs-iavl (iavl merkle proofs) - ics23::tendermint_spec(), // Format of proofs-tendermint (crypto/ merkle SimpleProof) - ] - .into() - } - - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } -} - -impl Default for ProofSpecs { - fn default() -> Self { - Self::cosmos() - } -} - -impl From> for ProofSpecs { - fn from(ibc_specs: Vec) -> Self { - Self(ibc_specs.into_iter().map(ProofSpec).collect()) - } -} - -impl From> for ProofSpecs { - fn from(ics23_specs: Vec) -> Self { - Self( - ics23_specs - .into_iter() - .map(|ics23_spec| ics23_spec.into()) - .collect(), - ) - } -} - -impl From for Vec { - fn from(specs: ProofSpecs) -> Self { - specs.0.into_iter().map(|spec| spec.into()).collect() - } -} - -impl From for Vec { - fn from(specs: ProofSpecs) -> Self { - specs.0.into_iter().map(|spec| spec.0).collect() - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] -struct ProofSpec(IbcProofSpec); - -impl From for ProofSpec { - fn from(spec: Ics23ProofSpec) -> Self { - Self(IbcProofSpec { - leaf_spec: spec.leaf_spec.map(|lop| LeafOp::from(lop).0), - inner_spec: spec.inner_spec.map(|ispec| InnerSpec::from(ispec).0), - max_depth: spec.max_depth, - min_depth: spec.min_depth, - }) - } -} - -impl From for Ics23ProofSpec { - fn from(spec: ProofSpec) -> Self { - let spec = spec.0; - Ics23ProofSpec { - leaf_spec: spec.leaf_spec.map(|lop| LeafOp(lop).into()), - inner_spec: spec.inner_spec.map(|ispec| InnerSpec(ispec).into()), - max_depth: spec.max_depth, - min_depth: spec.min_depth, - } - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] -struct LeafOp(IbcLeafOp); - -impl From for LeafOp { - fn from(leaf_op: Ics23LeafOp) -> Self { - Self(IbcLeafOp { - hash: leaf_op.hash, - prehash_key: leaf_op.prehash_key, - prehash_value: leaf_op.prehash_value, - length: leaf_op.length, - prefix: leaf_op.prefix, - }) - } -} - -impl From for Ics23LeafOp { - fn from(leaf_op: LeafOp) -> Self { - let leaf_op = leaf_op.0; - Ics23LeafOp { - hash: leaf_op.hash, - prehash_key: leaf_op.prehash_key, - prehash_value: leaf_op.prehash_value, - length: leaf_op.length, - prefix: leaf_op.prefix, - } - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] -struct InnerSpec(IbcInnerSpec); - -impl From for InnerSpec { - fn from(inner_spec: Ics23InnerSpec) -> Self { - Self(IbcInnerSpec { - child_order: inner_spec.child_order, - child_size: inner_spec.child_size, - min_prefix_length: inner_spec.min_prefix_length, - max_prefix_length: inner_spec.max_prefix_length, - empty_child: inner_spec.empty_child, - hash: inner_spec.hash, - }) - } -} - -impl From for Ics23InnerSpec { - fn from(inner_spec: InnerSpec) -> Self { - let inner_spec = inner_spec.0; - Ics23InnerSpec { - child_order: inner_spec.child_order, - child_size: inner_spec.child_size, - min_prefix_length: inner_spec.min_prefix_length, - max_prefix_length: inner_spec.max_prefix_length, - empty_child: inner_spec.empty_child, - hash: inner_spec.hash, - } - } -} diff --git a/modules/src/core/ics24_host/error.rs b/modules/src/core/ics24_host/error.rs deleted file mode 100644 index 0221414211..0000000000 --- a/modules/src/core/ics24_host/error.rs +++ /dev/null @@ -1,36 +0,0 @@ -use flex_error::define_error; -use serde::Serialize; - -use crate::prelude::*; - -define_error! { - #[derive(Debug, PartialEq, Eq, Serialize)] - ValidationError { - ContainSeparator - { id : String } - | e | { format_args!("identifier {0} cannot contain separator '/'", e.id) }, - - InvalidLength - { - id: String, - length: usize, - 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) }, - - InvalidCharacter - { id: String } - | e | { format_args!("identifier {0} must only contain alphanumeric characters or `.`, `_`, `+`, `-`, `#`, - `[`, `]`, `<`, `>`", e.id) }, - - Empty - | _ | { "identifier cannot be empty" }, - - ChainIdInvalidFormat - { id: String } - | e | { format_args!("chain identifiers are expected to be in epoch format {0}", e.id) }, - - InvalidCounterpartyChannelId - |_| { "Invalid channel id in counterparty" } - } -} diff --git a/modules/src/core/ics24_host/identifier.rs b/modules/src/core/ics24_host/identifier.rs deleted file mode 100644 index 3ef0a56687..0000000000 --- a/modules/src/core/ics24_host/identifier.rs +++ /dev/null @@ -1,432 +0,0 @@ -use core::convert::{From, Infallible}; -use core::fmt::{Debug, Display, Error as FmtError, Formatter}; -use core::str::FromStr; - -use serde::{Deserialize, Serialize}; - -use super::validate::*; -use crate::core::ics02_client::client_type::ClientType; -use crate::core::ics24_host::error::ValidationError; -use crate::prelude::*; - -/// This type is subject to future changes. -/// -/// TODO: ChainId validation is not standardized yet. -/// `is_epoch_format` will most likely be replaced by validate_chain_id()-style function. -/// See: . -/// -/// Also, contrast with tendermint-rs `ChainId` type. -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] -#[serde(from = "tendermint::chain::Id", into = "tendermint::chain::Id")] -pub struct ChainId { - id: String, - version: u64, -} - -impl ChainId { - /// Creates a new `ChainId` given a chain name and an epoch number. - /// - /// The returned `ChainId` will have the format: `{chain name}-{epoch number}`. - /// ``` - /// use ibc::core::ics24_host::identifier::ChainId; - /// - /// let epoch_number = 10; - /// let id = ChainId::new("chainA".to_string(), epoch_number); - /// assert_eq!(id.version(), epoch_number); - /// ``` - pub fn new(name: String, version: u64) -> Self { - Self { - id: format!("{}-{}", name, version), - version, - } - } - - pub fn from_string(id: &str) -> Self { - let version = if Self::is_epoch_format(id) { - Self::chain_version(id) - } else { - 0 - }; - - Self { - id: id.to_string(), - version, - } - } - - /// Get a reference to the underlying string. - pub fn as_str(&self) -> &str { - &self.id - } - - // TODO: this should probably be named epoch_number. - /// Extract the version from this chain identifier. - pub fn version(&self) -> u64 { - self.version - } - - /// Extract the version from the given chain identifier. - /// ``` - /// use ibc::core::ics24_host::identifier::ChainId; - /// - /// assert_eq!(ChainId::chain_version("chain--a-0"), 0); - /// assert_eq!(ChainId::chain_version("ibc-10"), 10); - /// assert_eq!(ChainId::chain_version("cosmos-hub-97"), 97); - /// assert_eq!(ChainId::chain_version("testnet-helloworld-2"), 2); - /// ``` - pub fn chain_version(chain_id: &str) -> u64 { - if !ChainId::is_epoch_format(chain_id) { - return 0; - } - - let split: Vec<_> = chain_id.split('-').collect(); - split - .last() - .expect("get revision number from chain_id") - .parse() - .unwrap_or(0) - } - - /// is_epoch_format() checks if a chain_id is in the format required for parsing epochs - /// The chainID must be in the form: `{chainID}-{version}` - /// ``` - /// use ibc::core::ics24_host::identifier::ChainId; - /// assert_eq!(ChainId::is_epoch_format("chainA-0"), false); - /// assert_eq!(ChainId::is_epoch_format("chainA"), false); - /// assert_eq!(ChainId::is_epoch_format("chainA-1"), true); - /// ``` - pub fn is_epoch_format(chain_id: &str) -> bool { - let re = safe_regex::regex!(br".+[^-]-{1}[1-9][0-9]*"); - re.is_match(chain_id.as_bytes()) - } -} - -impl FromStr for ChainId { - type Err = Infallible; - - fn from_str(id: &str) -> Result { - Ok(Self::from_string(id)) - } -} - -impl Display for ChainId { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "{}", self.id) - } -} - -impl From for tendermint::chain::Id { - fn from(id: ChainId) -> Self { - tendermint::chain::Id::from_str(id.as_str()).unwrap() - } -} - -impl From for ChainId { - fn from(id: tendermint::chain::Id) -> Self { - ChainId::from_str(id.as_str()).unwrap() - } -} - -impl Default for ChainId { - fn default() -> Self { - "defaultChainId".to_string().parse().unwrap() - } -} - -impl From for ChainId { - fn from(value: String) -> Self { - Self::from_string(&value) - } -} - -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] -pub struct ClientId(String); - -impl ClientId { - /// Builds a new client identifier. Client identifiers are deterministically formed from two - /// elements: a prefix derived from the client type `ctype`, and a monotonically increasing - /// `counter`; these are separated by a dash "-". - /// - /// ``` - /// # use ibc::core::ics24_host::identifier::ClientId; - /// # use ibc::core::ics02_client::client_type::ClientType; - /// let tm_client_id = ClientId::new(ClientType::Tendermint, 0); - /// assert!(tm_client_id.is_ok()); - /// tm_client_id.map(|id| { assert_eq!(&id, "07-tendermint-0") }); - /// ``` - pub fn new(ctype: ClientType, counter: u64) -> Result { - let prefix = Self::prefix(ctype); - let id = format!("{}-{}", prefix, counter); - Self::from_str(id.as_str()) - } - - /// Get this identifier as a borrowed `&str` - pub fn as_str(&self) -> &str { - &self.0 - } - - /// Returns one of the prefixes that should be present in any client identifiers. - /// The prefix is deterministic for a given chain type, hence all clients for a Tendermint-type - /// chain, for example, will have the prefix '07-tendermint'. - 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(), - } - } - - /// Get this identifier as a borrowed byte slice - pub fn as_bytes(&self) -> &[u8] { - self.0.as_bytes() - } -} - -/// This implementation provides a `to_string` method. -impl Display for ClientId { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "{}", self.0) - } -} - -impl FromStr for ClientId { - type Err = ValidationError; - - fn from_str(s: &str) -> Result { - validate_client_identifier(s).map(|_| Self(s.to_string())) - } -} - -impl Default for ClientId { - fn default() -> Self { - Self::new(ClientType::Tendermint, 0).unwrap() - } -} - -/// Equality check against string literal (satisfies &ClientId == &str). -/// ``` -/// use core::str::FromStr; -/// use ibc::core::ics24_host::identifier::ClientId; -/// let client_id = ClientId::from_str("clientidtwo"); -/// assert!(client_id.is_ok()); -/// client_id.map(|id| {assert_eq!(&id, "clientidtwo")}); -/// ``` -impl PartialEq for ClientId { - fn eq(&self, other: &str) -> bool { - self.as_str().eq(other) - } -} - -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] -pub struct ConnectionId(String); - -impl ConnectionId { - /// Builds a new connection identifier. Connection identifiers are deterministically formed from - /// two elements: a prefix `prefix`, and a monotonically increasing `counter`; these are - /// separated by a dash "-". The prefix is currently determined statically (see - /// `ConnectionId::prefix()`) so this method accepts a single argument, the `counter`. - /// - /// ``` - /// # use ibc::core::ics24_host::identifier::ConnectionId; - /// let conn_id = ConnectionId::new(11); - /// assert_eq!(&conn_id, "connection-11"); - /// ``` - pub fn new(counter: u64) -> Self { - let id = format!("{}-{}", Self::prefix(), counter); - Self::from_str(id.as_str()).unwrap() - } - - /// Returns the static prefix to be used across all connection identifiers. - pub fn prefix() -> &'static str { - "connection" - } - - /// Get this identifier as a borrowed `&str` - pub fn as_str(&self) -> &str { - &self.0 - } - - /// Get this identifier as a borrowed byte slice - pub fn as_bytes(&self) -> &[u8] { - self.0.as_bytes() - } -} - -/// This implementation provides a `to_string` method. -impl Display for ConnectionId { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "{}", self.0) - } -} - -impl FromStr for ConnectionId { - type Err = ValidationError; - - fn from_str(s: &str) -> Result { - validate_connection_identifier(s).map(|_| Self(s.to_string())) - } -} - -impl Default for ConnectionId { - fn default() -> Self { - Self::new(0) - } -} - -/// Equality check against string literal (satisfies &ConnectionId == &str). -/// ``` -/// use core::str::FromStr; -/// use ibc::core::ics24_host::identifier::ConnectionId; -/// let conn_id = ConnectionId::from_str("connectionId-0"); -/// assert!(conn_id.is_ok()); -/// conn_id.map(|id| {assert_eq!(&id, "connectionId-0")}); -/// ``` -impl PartialEq for ConnectionId { - fn eq(&self, other: &str) -> bool { - self.as_str().eq(other) - } -} - -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] -pub struct PortId(String); - -impl PortId { - /// Infallible creation of the well-known transfer port - pub fn transfer() -> Self { - Self("transfer".to_string()) - } - - /// Get this identifier as a borrowed `&str` - pub fn as_str(&self) -> &str { - &self.0 - } - - /// Get this identifier as a borrowed byte slice - pub fn as_bytes(&self) -> &[u8] { - self.0.as_bytes() - } -} - -/// This implementation provides a `to_string` method. -impl Display for PortId { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "{}", self.0) - } -} - -impl FromStr for PortId { - type Err = ValidationError; - - fn from_str(s: &str) -> Result { - validate_port_identifier(s).map(|_| Self(s.to_string())) - } -} - -impl AsRef for PortId { - fn as_ref(&self) -> &str { - self.0.as_str() - } -} - -impl Default for PortId { - fn default() -> Self { - "defaultPort".to_string().parse().unwrap() - } -} - -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] -pub struct ChannelId(String); - -impl ChannelId { - const PREFIX: &'static str = "channel-"; - - /// Builds a new channel identifier. Like client and connection identifiers, channel ids are - /// deterministically formed from two elements: a prefix `prefix`, and a monotonically - /// increasing `counter`, separated by a dash "-". - /// The prefix is currently determined statically (see `ChannelId::prefix()`) so this method - /// accepts a single argument, the `counter`. - /// - /// ``` - /// # use ibc::core::ics24_host::identifier::ChannelId; - /// let chan_id = ChannelId::new(27); - /// assert_eq!(chan_id.to_string(), "channel-27"); - /// ``` - pub fn new(counter: u64) -> Self { - let id = format!("{}{}", Self::PREFIX, counter); - Self(id) - } - - /// Get this identifier as a borrowed `&str` - pub fn as_str(&self) -> &str { - &self.0 - } - - /// Get this identifier as a borrowed byte slice - pub fn as_bytes(&self) -> &[u8] { - self.0.as_bytes() - } -} - -/// This implementation provides a `to_string` method. -impl Display for ChannelId { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "{}", self.0) - } -} - -impl FromStr for ChannelId { - type Err = ValidationError; - - fn from_str(s: &str) -> Result { - validate_channel_identifier(s).map(|_| Self(s.to_string())) - } -} - -impl AsRef for ChannelId { - fn as_ref(&self) -> &str { - &self.0 - } -} - -impl Default for ChannelId { - fn default() -> Self { - Self::new(0) - } -} - -/// Equality check against string literal (satisfies &ChannelId == &str). -/// ``` -/// use core::str::FromStr; -/// use ibc::core::ics24_host::identifier::ChannelId; -/// let channel_id = ChannelId::from_str("channelId-0"); -/// assert!(channel_id.is_ok()); -/// channel_id.map(|id| {assert_eq!(&id, "channelId-0")}); -/// ``` -impl PartialEq for ChannelId { - fn eq(&self, other: &str) -> bool { - self.as_str().eq(other) - } -} - -/// A pair of [`PortId`] and [`ChannelId`] are used together for sending IBC packets. -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] -pub struct PortChannelId { - pub channel_id: ChannelId, - pub port_id: PortId, -} - -impl PortChannelId { - pub fn new(channel_id: ChannelId, port_id: PortId) -> Self { - Self { - channel_id, - port_id, - } - } -} - -impl Display for PortChannelId { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "{}/{}", self.port_id, self.channel_id) - } -} diff --git a/modules/src/core/ics24_host/mod.rs b/modules/src/core/ics24_host/mod.rs deleted file mode 100644 index 23be43fb73..0000000000 --- a/modules/src/core/ics24_host/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -//! ICS 24: Host defines the minimal set of interfaces that a -//! state machine hosting an IBC-enabled chain must implement. - -pub use path::{ClientUpgradePath, Path, IBC_QUERY_PATH, SDK_UPGRADE_QUERY_PATH}; - -pub mod error; -pub mod identifier; -pub mod path; -pub mod validate; diff --git a/modules/src/core/ics24_host/path.rs b/modules/src/core/ics24_host/path.rs deleted file mode 100644 index 56542e1d26..0000000000 --- a/modules/src/core/ics24_host/path.rs +++ /dev/null @@ -1,1017 +0,0 @@ -use crate::prelude::*; - -/// Path-space as listed in ICS-024 -/// https://github.com/cosmos/ibc/tree/master/spec/core/ics-024-host-requirements#path-space -/// Some of these are implemented in other ICSs, but ICS-024 has a nice summary table. -/// -use core::str::FromStr; - -use crate::core::ics04_channel::packet::Sequence; -use crate::core::ics24_host::identifier::{ChannelId, ClientId, ConnectionId, PortId}; - -use derive_more::{Display, From}; -use flex_error::define_error; - -/// ABCI Query path for the IBC sub-store -pub const IBC_QUERY_PATH: &str = "store/ibc/key"; - -/// ABCI Query path for the upgrade sub-store -/// ## Note: This is SDK/Tendermint specific! -pub const SDK_UPGRADE_QUERY_PATH: &str = "store/upgrade/key"; - -/// ABCI client upgrade keys -/// - The key identifying the upgraded IBC state within the upgrade sub-store -const UPGRADED_IBC_STATE: &str = "upgradedIBCState"; -///- The key identifying the upgraded client state -const UPGRADED_CLIENT_STATE: &str = "upgradedClient"; -/// - The key identifying the upgraded consensus state -const UPGRADED_CLIENT_CONSENSUS_STATE: &str = "upgradedConsState"; - -/// The Path enum abstracts out the different sub-paths. -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, From, Display)] -pub enum Path { - ClientType(ClientTypePath), - ClientState(ClientStatePath), - ClientConsensusState(ClientConsensusStatePath), - ClientConnections(ClientConnectionsPath), - Connections(ConnectionsPath), - Ports(PortsPath), - ChannelEnds(ChannelEndsPath), - SeqSends(SeqSendsPath), - SeqRecvs(SeqRecvsPath), - SeqAcks(SeqAcksPath), - Commitments(CommitmentsPath), - Acks(AcksPath), - Receipts(ReceiptsPath), - Upgrade(ClientUpgradePath), -} - -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] -#[display(fmt = "clients/{}/clientType", _0)] -pub struct ClientTypePath(pub ClientId); - -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] -#[display(fmt = "clients/{}/clientState", _0)] -pub struct ClientStatePath(pub ClientId); - -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] -#[display( - fmt = "clients/{}/consensusStates/{}-{}", - "client_id", - "epoch", - "height" -)] -pub struct ClientConsensusStatePath { - pub client_id: ClientId, - pub epoch: u64, - pub height: u64, -} - -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] -#[display(fmt = "clients/{}/connections", _0)] -pub struct ClientConnectionsPath(pub ClientId); - -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] -#[display(fmt = "connections/{}", _0)] -pub struct ConnectionsPath(pub ConnectionId); - -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] -#[display(fmt = "ports/{}", _0)] -pub struct PortsPath(pub PortId); - -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] -#[display(fmt = "channelEnds/ports/{}/channels/{}", _0, _1)] -pub struct ChannelEndsPath(pub PortId, pub ChannelId); - -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] -#[display(fmt = "nextSequenceSend/ports/{}/channels/{}", _0, _1)] -pub struct SeqSendsPath(pub PortId, pub ChannelId); - -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] -#[display(fmt = "nextSequenceRecv/ports/{}/channels/{}", _0, _1)] -pub struct SeqRecvsPath(pub PortId, pub ChannelId); - -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] -#[display(fmt = "nextSequenceAck/ports/{}/channels/{}", _0, _1)] -pub struct SeqAcksPath(pub PortId, pub ChannelId); - -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] -#[display( - fmt = "commitments/ports/{}/channels/{}/sequences/{}", - "port_id", - "channel_id", - "sequence" -)] -pub struct CommitmentsPath { - pub port_id: PortId, - pub channel_id: ChannelId, - pub sequence: Sequence, -} - -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] -#[display( - fmt = "acks/ports/{}/channels/{}/sequences/{}", - "port_id", - "channel_id", - "sequence" -)] -pub struct AcksPath { - pub port_id: PortId, - pub channel_id: ChannelId, - pub sequence: Sequence, -} - -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] -#[display( - fmt = "receipts/ports/{}/channels/{}/sequences/{}", - "port_id", - "channel_id", - "sequence" -)] -pub struct ReceiptsPath { - pub port_id: PortId, - pub channel_id: ChannelId, - pub sequence: Sequence, -} - -/// Paths that are specific for client upgrades. -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] -pub enum ClientUpgradePath { - #[display(fmt = "{}/{}/{}", UPGRADED_IBC_STATE, _0, UPGRADED_CLIENT_STATE)] - UpgradedClientState(u64), - #[display( - fmt = "{}/{}/{}", - UPGRADED_IBC_STATE, - _0, - UPGRADED_CLIENT_CONSENSUS_STATE - )] - UpgradedClientConsensusState(u64), -} - -/// Sub-paths which are not part of the specification, but are still -/// useful to represent for parsing purposes. -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -enum SubPath { - Channels(ChannelId), - Sequences(Sequence), -} - -impl Path { - /// Indication if the path is provable. - pub fn is_provable(&self) -> bool { - !matches!(&self, Path::ClientConnections(_) | Path::Ports(_)) - } - - /// into_bytes implementation - pub fn into_bytes(self) -> Vec { - self.to_string().into_bytes() - } -} - -define_error! { - #[derive(Eq, PartialEq)] - PathError { - ParseFailure - { path: String } - | e | { format!("'{}' could not be parsed into a Path", e.path) }, - } -} - -/// The FromStr trait allows paths encoded as strings to be parsed into Paths. -impl FromStr for Path { - type Err = PathError; - - fn from_str(s: &str) -> Result { - let components: Vec<&str> = s.split('/').collect(); - - parse_client_paths(&components) - .or_else(|| parse_connections(&components)) - .or_else(|| parse_ports(&components)) - .or_else(|| parse_channel_ends(&components)) - .or_else(|| parse_seqs(&components)) - .or_else(|| parse_commitments(&components)) - .or_else(|| parse_acks(&components)) - .or_else(|| parse_receipts(&components)) - .or_else(|| parse_upgrades(&components)) - .ok_or_else(|| PathError::parse_failure(s.to_string())) - } -} - -fn parse_client_paths(components: &[&str]) -> Option { - let first = match components.first() { - Some(f) => *f, - None => return None, - }; - - if first != "clients" { - return None; - } - - let client_id = match ClientId::from_str(components[1]) { - Ok(s) => s, - Err(_) => return None, - }; - - if components.len() == 3 { - match components[2] { - "clientType" => Some(ClientTypePath(client_id).into()), - "clientState" => Some(ClientStatePath(client_id).into()), - "connections" => Some(ClientConnectionsPath(client_id).into()), - _ => None, - } - } else if components.len() == 4 { - if "consensusStates" != components[2] { - return None; - } - - let epoch_height = match components.last() { - Some(eh) => *eh, - None => return None, - }; - - let epoch_height: Vec<&str> = epoch_height.split('-').collect(); - - if epoch_height.len() != 2 { - return None; - } - - let epoch = epoch_height[0]; - let height = epoch_height[1]; - - let epoch = match epoch.parse::() { - Ok(ep) => ep, - Err(_) => return None, - }; - - let height = match height.parse::() { - Ok(h) => h, - Err(_) => return None, - }; - - Some( - ClientConsensusStatePath { - client_id, - epoch, - height, - } - .into(), - ) - } else { - None - } -} - -fn parse_connections(components: &[&str]) -> Option { - if components.len() != 2 { - return None; - } - - let first = match components.first() { - Some(f) => *f, - None => return None, - }; - - if first != "connections" { - return None; - } - - let connection_id = match components.last() { - Some(c) => *c, - None => return None, - }; - - let connection_id = match ConnectionId::from_str(connection_id) { - Ok(c) => c, - Err(_) => return None, - }; - - Some(ConnectionsPath(connection_id).into()) -} - -fn parse_ports(components: &[&str]) -> Option { - if components.len() != 2 { - return None; - } - - let first = match components.first() { - Some(f) => *f, - None => return None, - }; - - if first != "ports" { - return None; - } - - let port_id = match components.last() { - Some(p) => *p, - None => return None, - }; - - let port_id = match PortId::from_str(port_id) { - Ok(p) => p, - Err(_) => return None, - }; - - Some(PortsPath(port_id).into()) -} - -fn parse_channels(components: &[&str]) -> Option { - if components.len() != 2 { - return None; - } - - let first = match components.first() { - Some(f) => *f, - None => return None, - }; - - if first != "channels" { - return None; - } - - let channel_id = match components.last() { - Some(c) => *c, - None => return None, - }; - - let channel_id = match ChannelId::from_str(channel_id) { - Ok(c) => c, - Err(_) => return None, - }; - - Some(SubPath::Channels(channel_id)) -} - -fn parse_sequences(components: &[&str]) -> Option { - if components.len() != 2 { - return None; - } - - let first = match components.first() { - Some(f) => *f, - None => return None, - }; - - if first != "sequences" { - return None; - } - - let sequence_number = match components.last() { - Some(s) => *s, - None => return None, - }; - - match Sequence::from_str(sequence_number) { - Ok(seq) => Some(SubPath::Sequences(seq)), - Err(_) => None, - } -} - -fn parse_channel_ends(components: &[&str]) -> Option { - if components.len() != 5 { - return None; - } - - let first = match components.first() { - Some(f) => *f, - None => return None, - }; - - if first != "channelEnds" { - return None; - } - - let port = parse_ports(&components[1..=2]); - let channel = parse_channels(&components[3..=4]); - - let port_id = if let Some(Path::Ports(PortsPath(port_id))) = port { - port_id - } else { - return None; - }; - - let channel_id = if let Some(SubPath::Channels(channel_id)) = channel { - channel_id - } else { - return None; - }; - - Some(ChannelEndsPath(port_id, channel_id).into()) -} - -fn parse_seqs(components: &[&str]) -> Option { - if components.len() != 5 { - return None; - } - - let first = match components.first() { - Some(f) => *f, - None => return None, - }; - - let port = parse_ports(&components[1..=2]); - let channel = parse_channels(&components[3..=4]); - - let port_id = if let Some(Path::Ports(PortsPath(port_id))) = port { - port_id - } else { - return None; - }; - - let channel_id = if let Some(SubPath::Channels(channel_id)) = channel { - channel_id - } else { - return None; - }; - - match first { - "nextSequenceSend" => Some(SeqSendsPath(port_id, channel_id).into()), - "nextSequenceRecv" => Some(SeqRecvsPath(port_id, channel_id).into()), - "nextSequenceAck" => Some(SeqAcksPath(port_id, channel_id).into()), - _ => None, - } -} - -fn parse_commitments(components: &[&str]) -> Option { - if components.len() != 7 { - return None; - } - - let first = match components.first() { - Some(f) => *f, - None => return None, - }; - - if first != "commitments" { - return None; - } - - let port = parse_ports(&components[1..=2]); - let channel = parse_channels(&components[3..=4]); - let sequence = parse_sequences(&components[5..]); - - let port_id = if let Some(Path::Ports(PortsPath(port_id))) = port { - port_id - } else { - return None; - }; - - let channel_id = if let Some(SubPath::Channels(channel_id)) = channel { - channel_id - } else { - return None; - }; - - let sequence = if let Some(SubPath::Sequences(seq)) = sequence { - seq - } else { - return None; - }; - - Some( - CommitmentsPath { - port_id, - channel_id, - sequence, - } - .into(), - ) -} - -fn parse_acks(components: &[&str]) -> Option { - if components.len() != 7 { - return None; - } - - let first = match components.first() { - Some(f) => *f, - None => return None, - }; - - if first != "acks" { - return None; - } - - let port = parse_ports(&components[1..=2]); - let channel = parse_channels(&components[3..=4]); - let sequence = parse_sequences(&components[5..]); - - let port_id = if let Some(Path::Ports(PortsPath(port_id))) = port { - port_id - } else { - return None; - }; - - let channel_id = if let Some(SubPath::Channels(channel_id)) = channel { - channel_id - } else { - return None; - }; - - let sequence = if let Some(SubPath::Sequences(seq)) = sequence { - seq - } else { - return None; - }; - - Some( - AcksPath { - port_id, - channel_id, - sequence, - } - .into(), - ) -} - -fn parse_receipts(components: &[&str]) -> Option { - if components.len() != 7 { - return None; - } - - let first = match components.first() { - Some(f) => *f, - None => return None, - }; - - if first != "receipts" { - return None; - } - - let port = parse_ports(&components[1..=2]); - let channel = parse_channels(&components[3..=4]); - let sequence = parse_sequences(&components[5..]); - - let port_id = if let Some(Path::Ports(PortsPath(port_id))) = port { - port_id - } else { - return None; - }; - - let channel_id = if let Some(SubPath::Channels(channel_id)) = channel { - channel_id - } else { - return None; - }; - - let sequence = if let Some(SubPath::Sequences(seq)) = sequence { - seq - } else { - return None; - }; - - Some( - ReceiptsPath { - port_id, - channel_id, - sequence, - } - .into(), - ) -} - -fn parse_upgrades(components: &[&str]) -> Option { - if components.len() != 3 { - return None; - } - - let first = match components.first() { - Some(f) => *f, - None => return None, - }; - - if first != UPGRADED_IBC_STATE { - return None; - } - - let last = match components.last() { - Some(l) => *l, - None => return None, - }; - - let height = match components[1].parse::() { - Ok(h) => h, - Err(_) => return None, - }; - - match last { - UPGRADED_CLIENT_STATE => Some(ClientUpgradePath::UpgradedClientState(height).into()), - UPGRADED_CLIENT_CONSENSUS_STATE => { - Some(ClientUpgradePath::UpgradedClientConsensusState(height).into()) - } - _ => None, - } -} - -#[cfg(test)] -mod tests { - use super::*; - use core::str::FromStr; - - #[test] - fn invalid_path_doesnt_parse() { - let invalid_path = Path::from_str("clients/clientType"); - - assert!(invalid_path.is_err()); - } - - #[test] - fn test_parse_client_paths_fn() { - let path = "clients/07-tendermint-0/clientType"; - let components: Vec<&str> = path.split('/').collect(); - - assert_eq!( - parse_client_paths(&components), - Some(Path::ClientType(ClientTypePath(ClientId::default()))) - ); - - let path = "clients/07-tendermint-0/clientState"; - let components: Vec<&str> = path.split('/').collect(); - - assert_eq!( - parse_client_paths(&components), - Some(Path::ClientState(ClientStatePath(ClientId::default()))) - ); - - let path = "clients/07-tendermint-0/consensusStates/15-31"; - let components: Vec<&str> = path.split('/').collect(); - - assert_eq!( - parse_client_paths(&components), - Some(Path::ClientConsensusState(ClientConsensusStatePath { - client_id: ClientId::default(), - epoch: 15, - height: 31, - })) - ); - } - - #[test] - fn client_type_path_parses() { - let path = "clients/07-tendermint-0/clientType"; - let path = Path::from_str(path); - - assert!(path.is_ok()); - assert_eq!( - path.unwrap(), - Path::ClientType(ClientTypePath(ClientId::default())) - ); - } - - #[test] - fn client_state_path_parses() { - let path = "clients/07-tendermint-0/clientState"; - let path = Path::from_str(path); - - assert!(path.is_ok()); - assert_eq!( - path.unwrap(), - Path::ClientState(ClientStatePath(ClientId::default())) - ); - } - - #[test] - fn client_consensus_state_path_parses() { - let path = "clients/07-tendermint-0/consensusStates/15-31"; - let path = Path::from_str(path); - - assert!(path.is_ok()); - assert_eq!( - path.unwrap(), - Path::ClientConsensusState(ClientConsensusStatePath { - client_id: ClientId::default(), - epoch: 15, - height: 31, - }) - ); - } - - #[test] - fn client_connections_path_parses() { - let path = "clients/07-tendermint-0/connections"; - let path = Path::from_str(path); - - assert!(path.is_ok()); - assert_eq!( - path.unwrap(), - Path::ClientConnections(ClientConnectionsPath(ClientId::default())) - ); - } - - #[test] - fn test_parse_connections_fn() { - let path = "connections/connection-0"; - let components: Vec<&str> = path.split('/').collect(); - - assert_eq!( - parse_connections(&components), - Some(Path::Connections(ConnectionsPath(ConnectionId::new(0)))), - ); - } - - #[test] - fn connections_path_parses() { - let path = "connections/connection-0"; - let path = Path::from_str(path); - - assert!(path.is_ok()); - assert_eq!( - path.unwrap(), - Path::Connections(ConnectionsPath(ConnectionId::new(0))) - ); - } - - #[test] - fn test_parse_ports_fn() { - let path = "ports/defaultPort"; - let components: Vec<&str> = path.split('/').collect(); - - assert_eq!( - parse_ports(&components), - Some(Path::Ports(PortsPath(PortId::default()))), - ); - } - - #[test] - fn ports_path_parses() { - let path = "ports/defaultPort"; - let path = Path::from_str(path); - - assert!(path.is_ok()); - assert_eq!(path.unwrap(), Path::Ports(PortsPath(PortId::default()))); - } - - #[test] - fn test_parse_channels_fn() { - let path = "channels/channel-0"; - let components: Vec<&str> = path.split('/').collect(); - - assert_eq!( - parse_channels(&components), - Some(SubPath::Channels(ChannelId::default())), - ); - } - - #[test] - fn channels_path_doesnt_parse() { - let path = "channels/channel-0"; - let path = Path::from_str(path); - - assert!(path.is_err()); - } - - #[test] - fn test_parse_sequences_fn() { - let path = "sequences/0"; - let components: Vec<&str> = path.split('/').collect(); - - assert_eq!( - parse_sequences(&components), - Some(SubPath::Sequences(Sequence::default())) - ); - } - - #[test] - fn sequences_path_doesnt_parse() { - let path = "sequences/0"; - let path = Path::from_str(path); - - assert!(path.is_err()); - } - - #[test] - fn test_parse_channel_ends_fn() { - let path = "channelEnds/ports/defaultPort/channels/channel-0"; - let components: Vec<&str> = path.split('/').collect(); - - assert_eq!( - parse_channel_ends(&components), - Some(Path::ChannelEnds(ChannelEndsPath( - PortId::default(), - ChannelId::default() - ))), - ); - } - - #[test] - fn channel_ends_path_parses() { - let path = "channelEnds/ports/defaultPort/channels/channel-0"; - let path = Path::from_str(path); - - assert!(path.is_ok()); - assert_eq!( - path.unwrap(), - Path::ChannelEnds(ChannelEndsPath(PortId::default(), ChannelId::default())), - ); - } - - #[test] - fn test_parse_seqs_fn() { - let path = "nextSequenceSend/ports/defaultPort/channels/channel-0"; - let components: Vec<&str> = path.split('/').collect(); - - assert_eq!( - parse_seqs(&components), - Some(Path::SeqSends(SeqSendsPath( - PortId::default(), - ChannelId::default() - ))), - ); - - let path = "nextSequenceRecv/ports/defaultPort/channels/channel-0"; - let components: Vec<&str> = path.split('/').collect(); - - assert_eq!( - parse_seqs(&components), - Some(Path::SeqRecvs(SeqRecvsPath( - PortId::default(), - ChannelId::default() - ))), - ); - - let path = "nextSequenceAck/ports/defaultPort/channels/channel-0"; - let components: Vec<&str> = path.split('/').collect(); - - assert_eq!( - parse_seqs(&components), - Some(Path::SeqAcks(SeqAcksPath( - PortId::default(), - ChannelId::default() - ))), - ); - } - - #[test] - fn sequence_send_path_parses() { - let path = "nextSequenceSend/ports/defaultPort/channels/channel-0"; - let path = Path::from_str(path); - - assert!(path.is_ok()); - assert_eq!( - path.unwrap(), - Path::SeqSends(SeqSendsPath(PortId::default(), ChannelId::default())), - ); - } - - #[test] - fn sequence_recv_path_parses() { - let path = "nextSequenceRecv/ports/defaultPort/channels/channel-0"; - let path = Path::from_str(path); - - assert!(path.is_ok()); - assert_eq!( - path.unwrap(), - Path::SeqRecvs(SeqRecvsPath(PortId::default(), ChannelId::default())), - ); - } - - #[test] - fn sequence_ack_path_parses() { - let path = "nextSequenceAck/ports/defaultPort/channels/channel-0"; - let path = Path::from_str(path); - - assert!(path.is_ok()); - assert_eq!( - path.unwrap(), - Path::SeqAcks(SeqAcksPath(PortId::default(), ChannelId::default())), - ); - } - - #[test] - fn test_parse_commitments_fn() { - let path = "commitments/ports/defaultPort/channels/channel-0/sequences/0"; - let components: Vec<&str> = path.split('/').collect(); - - assert_eq!( - parse_commitments(&components), - Some(Path::Commitments(CommitmentsPath { - port_id: PortId::default(), - channel_id: ChannelId::default(), - sequence: Sequence::default(), - })), - ); - } - - #[test] - fn commitments_path_parses() { - let path = "commitments/ports/defaultPort/channels/channel-0/sequences/0"; - let path = Path::from_str(path); - - assert!(path.is_ok()); - assert_eq!( - path.unwrap(), - Path::Commitments(CommitmentsPath { - port_id: PortId::default(), - channel_id: ChannelId::default(), - sequence: Sequence::default(), - }), - ); - } - - #[test] - fn test_parse_acks_fn() { - let path = "acks/ports/defaultPort/channels/channel-0/sequences/0"; - let components: Vec<&str> = path.split('/').collect(); - - assert_eq!( - parse_acks(&components), - Some(Path::Acks(AcksPath { - port_id: PortId::default(), - channel_id: ChannelId::default(), - sequence: Sequence::default(), - })), - ); - } - - #[test] - fn acks_path_parses() { - let path = "acks/ports/defaultPort/channels/channel-0/sequences/0"; - let path = Path::from_str(path); - - assert!(path.is_ok()); - assert_eq!( - path.unwrap(), - Path::Acks(AcksPath { - port_id: PortId::default(), - channel_id: ChannelId::default(), - sequence: Sequence::default(), - }), - ); - } - - #[test] - fn test_parse_receipts_fn() { - let path = "receipts/ports/defaultPort/channels/channel-0/sequences/0"; - let components: Vec<&str> = path.split('/').collect(); - - assert_eq!( - parse_receipts(&components), - Some(Path::Receipts(ReceiptsPath { - port_id: PortId::default(), - channel_id: ChannelId::default(), - sequence: Sequence::default(), - })), - ); - } - - #[test] - fn receipts_path_parses() { - let path = "receipts/ports/defaultPort/channels/channel-0/sequences/0"; - let path = Path::from_str(path); - - assert!(path.is_ok()); - assert_eq!( - path.unwrap(), - Path::Receipts(ReceiptsPath { - port_id: PortId::default(), - channel_id: ChannelId::default(), - sequence: Sequence::default(), - }), - ); - } - - #[test] - fn test_parse_upgrades_fn() { - let path = "upgradedIBCState/0/upgradedClient"; - let components: Vec<&str> = path.split('/').collect(); - - assert_eq!( - parse_upgrades(&components), - Some(Path::Upgrade(ClientUpgradePath::UpgradedClientState(0))), - ); - - let path = "upgradedIBCState/0/upgradedConsState"; - let components: Vec<&str> = path.split('/').collect(); - - assert_eq!( - parse_upgrades(&components), - Some(Path::Upgrade( - ClientUpgradePath::UpgradedClientConsensusState(0) - )), - ) - } - - #[test] - fn upgrade_client_state_path_parses() { - let path = "upgradedIBCState/0/upgradedClient"; - let path = Path::from_str(path); - - assert!(path.is_ok()); - assert_eq!( - path.unwrap(), - Path::Upgrade(ClientUpgradePath::UpgradedClientState(0)), - ); - } - - #[test] - fn upgrade_client_consensus_state_path_parses() { - let path = "upgradedIBCState/0/upgradedConsState"; - let path = Path::from_str(path); - - assert!(path.is_ok()); - assert_eq!( - path.unwrap(), - Path::Upgrade(ClientUpgradePath::UpgradedClientConsensusState(0)), - ); - } -} diff --git a/modules/src/core/ics24_host/validate.rs b/modules/src/core/ics24_host/validate.rs deleted file mode 100644 index 0bc4163bb2..0000000000 --- a/modules/src/core/ics24_host/validate.rs +++ /dev/null @@ -1,170 +0,0 @@ -use crate::prelude::*; - -use super::error::ValidationError as Error; - -/// Path separator (ie. forward slash '/') -const PATH_SEPARATOR: char = '/'; -const VALID_SPECIAL_CHARS: &str = "._+-#[]<>"; - -/// Default validator function for identifiers. -/// -/// A valid identifier only contain lowercase alphabetic characters, and be of a given min and max -/// length. -pub fn validate_identifier(id: &str, min: usize, max: usize) -> Result<(), Error> { - assert!(max >= min); - - // Check identifier is not empty - if id.is_empty() { - return Err(Error::empty()); - } - - // Check identifier does not contain path separators - if id.contains(PATH_SEPARATOR) { - return Err(Error::contain_separator(id.to_string())); - } - - // Check identifier length is between given min/max - if id.len() < min || id.len() > max { - return Err(Error::invalid_length(id.to_string(), id.len(), min, max)); - } - - // Check that the identifier comprises only valid characters: - // - Alphanumeric - // - `.`, `_`, `+`, `-`, `#` - // - `[`, `]`, `<`, `>` - if !id - .chars() - .all(|c| c.is_alphanumeric() || VALID_SPECIAL_CHARS.contains(c)) - { - return Err(Error::invalid_character(id.to_string())); - } - - // All good! - Ok(()) -} - -/// Default validator function for Client identifiers. -/// -/// A valid identifier must be between 9-64 characters and only contain lowercase -/// alphabetic characters, -pub fn validate_client_identifier(id: &str) -> Result<(), Error> { - validate_identifier(id, 9, 64) -} - -/// Default validator function for Connection identifiers. -/// -/// A valid Identifier must be between 10-64 characters and only contain lowercase -/// alphabetic characters, -pub fn validate_connection_identifier(id: &str) -> Result<(), Error> { - validate_identifier(id, 10, 64) -} - -/// Default validator function for Port identifiers. -/// -/// A valid Identifier must be between 2-128 characters and only contain lowercase -/// alphabetic characters, -pub fn validate_port_identifier(id: &str) -> Result<(), Error> { - validate_identifier(id, 2, 128) -} - -/// Default validator function for Channel identifiers. -/// -/// A valid identifier must be between 8-64 characters and only contain -/// alphabetic characters, -pub fn validate_channel_identifier(id: &str) -> Result<(), Error> { - validate_identifier(id, 8, 64) -} - -#[cfg(test)] -mod tests { - use crate::core::ics24_host::validate::{ - validate_channel_identifier, validate_client_identifier, validate_connection_identifier, - validate_identifier, validate_port_identifier, - }; - use test_log::test; - - #[test] - fn parse_invalid_port_id_min() { - // invalid min port id - let id = validate_port_identifier("p"); - assert!(id.is_err()) - } - - #[test] - fn parse_invalid_port_id_max() { - // invalid max port id (test string length is 130 chars) - let id = validate_port_identifier( - "9anxkcme6je544d5lnj46zqiiiygfqzf8w4bjecbnyj4lj6s7zlpst67yln64tixp9anxkcme6je544d5lnj46zqiiiygfqzf8w4bjecbnyj4lj6s7zlpst67yln64tixp", - ); - assert!(id.is_err()) - } - - #[test] - fn parse_invalid_connection_id_min() { - // invalid min connection id - let id = validate_connection_identifier("connect01"); - assert!(id.is_err()) - } - - #[test] - fn parse_connection_id_max() { - // invalid max connection id (test string length is 65) - let id = validate_connection_identifier( - "ihhankr30iy4nna65hjl2wjod7182io1t2s7u3ip3wqtbbn1sl0rgcntqc540r36r", - ); - assert!(id.is_err()) - } - - #[test] - fn parse_invalid_channel_id_min() { - // invalid channel id, must be at least 8 characters - let id = validate_channel_identifier("channel"); - assert!(id.is_err()) - } - - #[test] - fn parse_channel_id_max() { - // invalid channel id (test string length is 65) - let id = validate_channel_identifier( - "ihhankr30iy4nna65hjl2wjod7182io1t2s7u3ip3wqtbbn1sl0rgcntqc540r36r", - ); - assert!(id.is_err()) - } - - #[test] - fn parse_invalid_client_id_min() { - // invalid min client id - let id = validate_client_identifier("client"); - assert!(id.is_err()) - } - - #[test] - fn parse_client_id_max() { - // invalid max client id (test string length is 65) - let id = validate_client_identifier( - "f0isrs5enif9e4td3r2jcbxoevhz6u1fthn4aforq7ams52jn5m48eiesfht9ckpn", - ); - assert!(id.is_err()) - } - - #[test] - fn parse_invalid_id_chars() { - // invalid id chars - let id = validate_identifier("channel@01", 1, 10); - assert!(id.is_err()) - } - - #[test] - fn parse_invalid_id_empty() { - // invalid id empty - let id = validate_identifier("", 1, 10); - assert!(id.is_err()) - } - - #[test] - fn parse_invalid_id_path_separator() { - // invalid id with path separator - let id = validate_identifier("id/1", 1, 10); - assert!(id.is_err()) - } -} diff --git a/modules/src/core/ics26_routing/context.rs b/modules/src/core/ics26_routing/context.rs deleted file mode 100644 index 6203338c1d..0000000000 --- a/modules/src/core/ics26_routing/context.rs +++ /dev/null @@ -1,226 +0,0 @@ -use crate::prelude::*; - -use alloc::borrow::{Borrow, Cow}; -use core::any::Any; -use core::{ - fmt::{Debug, Display, Error as FmtError, Formatter}, - str::FromStr, -}; - -use serde::{Deserialize, Serialize}; - -use crate::core::ics02_client::context::{ClientKeeper, ClientReader}; -use crate::core::ics03_connection::context::{ConnectionKeeper, ConnectionReader}; -use crate::core::ics04_channel::channel::{Counterparty, Order}; -use crate::core::ics04_channel::context::{ChannelKeeper, ChannelReader}; -use crate::core::ics04_channel::error::Error; -use crate::core::ics04_channel::msgs::acknowledgement::Acknowledgement as GenericAcknowledgement; -use crate::core::ics04_channel::packet::Packet; -use crate::core::ics04_channel::Version; -use crate::core::ics05_port::context::PortReader; -use crate::core::ics24_host::identifier::{ChannelId, ConnectionId, PortId}; -use crate::events::ModuleEvent; -use crate::handler::HandlerOutputBuilder; -use crate::signer::Signer; - -/// This trait captures all the functional dependencies (i.e., context) which the ICS26 module -/// requires to be able to dispatch and process IBC messages. In other words, this is the -/// representation of a chain from the perspective of the IBC module of that chain. -pub trait Ics26Context: - ClientReader - + ClientKeeper - + ConnectionReader - + ConnectionKeeper - + ChannelKeeper - + ChannelReader - + PortReader -{ - type Router: Router; - - fn router(&self) -> &Self::Router; - - fn router_mut(&mut self) -> &mut Self::Router; -} - -#[derive(Debug, PartialEq, Eq)] -pub struct InvalidModuleId; - -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)] -pub struct ModuleId(String); - -impl ModuleId { - pub fn new(s: Cow<'_, str>) -> Result { - if !s.trim().is_empty() && s.chars().all(char::is_alphanumeric) { - Ok(Self(s.into_owned())) - } else { - Err(InvalidModuleId) - } - } -} - -impl Display for ModuleId { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "{}", self.0) - } -} - -impl FromStr for ModuleId { - type Err = InvalidModuleId; - - fn from_str(s: &str) -> Result { - Self::new(Cow::Borrowed(s)) - } -} - -impl Borrow for ModuleId { - fn borrow(&self) -> &str { - self.0.as_str() - } -} - -/// Types implementing this trait are expected to implement `From` -pub trait Acknowledgement: AsRef<[u8]> {} - -pub type WriteFn = dyn FnOnce(&mut dyn Any) -> Result<(), String>; - -pub enum OnRecvPacketAck { - Nil(Box), - Successful(Box, Box), - Failed(Box), -} - -impl OnRecvPacketAck { - pub fn is_successful(&self) -> bool { - matches!(self, OnRecvPacketAck::Successful(_, _)) - } -} - -pub type ModuleOutputBuilder = HandlerOutputBuilder<(), ModuleEvent>; - -pub trait Module: Send + Sync + AsAnyMut { - #[allow(clippy::too_many_arguments)] - fn on_chan_open_init( - &mut self, - _output: &mut ModuleOutputBuilder, - _order: Order, - _connection_hops: &[ConnectionId], - _port_id: &PortId, - _channel_id: &ChannelId, - _counterparty: &Counterparty, - _version: &Version, - ) -> Result<(), Error> { - Ok(()) - } - - #[allow(clippy::too_many_arguments)] - fn on_chan_open_try( - &mut self, - _output: &mut ModuleOutputBuilder, - _order: Order, - _connection_hops: &[ConnectionId], - _port_id: &PortId, - _channel_id: &ChannelId, - _counterparty: &Counterparty, - _version: &Version, - _counterparty_version: &Version, - ) -> Result; - - fn on_chan_open_ack( - &mut self, - _output: &mut ModuleOutputBuilder, - _port_id: &PortId, - _channel_id: &ChannelId, - _counterparty_version: &Version, - ) -> Result<(), Error> { - Ok(()) - } - - fn on_chan_open_confirm( - &mut self, - _output: &mut ModuleOutputBuilder, - _port_id: &PortId, - _channel_id: &ChannelId, - ) -> Result<(), Error> { - Ok(()) - } - - fn on_chan_close_init( - &mut self, - _output: &mut ModuleOutputBuilder, - _port_id: &PortId, - _channel_id: &ChannelId, - ) -> Result<(), Error> { - Ok(()) - } - - fn on_chan_close_confirm( - &mut self, - _output: &mut ModuleOutputBuilder, - _port_id: &PortId, - _channel_id: &ChannelId, - ) -> Result<(), Error> { - Ok(()) - } - - fn on_recv_packet( - &self, - _output: &mut ModuleOutputBuilder, - _packet: &Packet, - _relayer: &Signer, - ) -> OnRecvPacketAck { - OnRecvPacketAck::Nil(Box::new(|_| Ok(()))) - } - - fn on_acknowledgement_packet( - &mut self, - _output: &mut ModuleOutputBuilder, - _packet: &Packet, - _acknowledgement: &GenericAcknowledgement, - _relayer: &Signer, - ) -> Result<(), Error> { - Ok(()) - } - - fn on_timeout_packet( - &mut self, - _output: &mut ModuleOutputBuilder, - _packet: &Packet, - _relayer: &Signer, - ) -> Result<(), Error> { - Ok(()) - } -} - -pub trait RouterBuilder: Sized { - /// The `Router` type that the builder must build - type Router: Router; - - /// Registers `Module` against the specified `ModuleId` in the `Router`'s internal map - /// - /// Returns an error if a `Module` has already been registered against the specified `ModuleId` - fn add_route(self, module_id: ModuleId, module: impl Module) -> Result; - - /// Consumes the `RouterBuilder` and returns a `Router` as configured - fn build(self) -> Self::Router; -} - -pub trait AsAnyMut: Any { - fn as_any_mut(&mut self) -> &mut dyn Any; -} - -impl AsAnyMut for M { - fn as_any_mut(&mut self) -> &mut dyn Any { - self - } -} - -/// A router maintains a mapping of `ModuleId`s against `Modules`. Implementations must not publicly -/// expose APIs to add new routes once constructed. Routes may only be added at the time of -/// instantiation using the `RouterBuilder`. -pub trait Router { - /// Returns a mutable reference to a `Module` registered against the specified `ModuleId` - fn get_route_mut(&mut self, module_id: &impl Borrow) -> Option<&mut dyn Module>; - - /// Returns true if the `Router` has a `Module` registered against the specified `ModuleId` - fn has_route(&self, module_id: &impl Borrow) -> bool; -} diff --git a/modules/src/core/ics26_routing/error.rs b/modules/src/core/ics26_routing/error.rs deleted file mode 100644 index c0d3c69c6d..0000000000 --- a/modules/src/core/ics26_routing/error.rs +++ /dev/null @@ -1,36 +0,0 @@ -use crate::prelude::*; -use flex_error::{define_error, TraceError}; - -use crate::applications::transfer; -use crate::core::ics02_client; -use crate::core::ics03_connection; -use crate::core::ics04_channel; - -define_error! { - #[derive(Debug, PartialEq, Eq)] - Error { - Ics02Client - [ ics02_client::error::Error ] - | _ | { "ICS02 client error" }, - - Ics03Connection - [ ics03_connection::error::Error ] - | _ | { "ICS03 connection error" }, - - Ics04Channel - [ ics04_channel::error::Error ] - | _ | { "ICS04 channel error" }, - - Ics20FungibleTokenTransfer - [ transfer::error::Error ] - | _ | { "ICS20 fungible token transfer error" }, - - UnknownMessageTypeUrl - { url: String } - | e | { format_args!("unknown type URL {0}", e.url) }, - - MalformedMessageBytes - [ TraceError ] - | _ | { "the message is malformed and cannot be decoded" }, - } -} diff --git a/modules/src/core/ics26_routing/handler.rs b/modules/src/core/ics26_routing/handler.rs deleted file mode 100644 index 24c9668364..0000000000 --- a/modules/src/core/ics26_routing/handler.rs +++ /dev/null @@ -1,625 +0,0 @@ -use crate::prelude::*; - -use ibc_proto::google::protobuf::Any; - -use crate::core::ics02_client::handler::dispatch as ics2_msg_dispatcher; -use crate::core::ics03_connection::handler::dispatch as ics3_msg_dispatcher; -use crate::core::ics04_channel::handler::{ - channel_callback as ics4_callback, channel_dispatch as ics4_msg_dispatcher, - channel_validate as ics4_validate, recv_packet::RecvPacketResult, -}; -use crate::core::ics04_channel::handler::{ - get_module_for_packet_msg, packet_callback as ics4_packet_callback, - packet_dispatch as ics4_packet_msg_dispatcher, -}; -use crate::core::ics04_channel::packet::PacketResult; -use crate::core::ics26_routing::context::{Ics26Context, ModuleOutputBuilder}; -use crate::core::ics26_routing::error::Error; -use crate::core::ics26_routing::msgs::Ics26Envelope::{ - self, Ics2Msg, Ics3Msg, Ics4ChannelMsg, Ics4PacketMsg, -}; -use crate::{events::IbcEvent, handler::HandlerOutput}; - -/// Result of message execution - comprises of events emitted and logs entries created during the -/// execution of a transaction message. -pub struct MsgReceipt { - pub events: Vec, - pub log: Vec, -} - -/// Mimics the DeliverTx ABCI interface, but for a single message and at a slightly lower level. -/// No need for authentication info or signature checks here. -/// Returns a vector of all events that got generated as a byproduct of processing `message`. -pub fn deliver(ctx: &mut Ctx, message: Any) -> Result -where - Ctx: Ics26Context, -{ - // Decode the proto message into a domain message, creating an ICS26 envelope. - let envelope = decode(message)?; - - // Process the envelope, and accumulate any events that were generated. - let HandlerOutput { log, events, .. } = dispatch(ctx, envelope)?; - - Ok(MsgReceipt { events, log }) -} - -/// Attempts to convert a message into a [Ics26Envelope] message -pub fn decode(message: Any) -> Result { - message.try_into() -} - -/// Top-level ICS dispatch function. Routes incoming IBC messages to their corresponding module. -/// Returns a handler output with empty result of type `HandlerOutput<()>` which contains the log -/// and events produced after processing the input `msg`. -/// If this method returns an error, the runtime is expected to rollback all state modifications to -/// the `Ctx` caused by all messages from the transaction that this `msg` is a part of. -pub fn dispatch(ctx: &mut Ctx, msg: Ics26Envelope) -> Result, Error> -where - Ctx: Ics26Context, -{ - let output = match msg { - Ics2Msg(msg) => { - let handler_output = ics2_msg_dispatcher(ctx, msg).map_err(Error::ics02_client)?; - - // Apply the result to the context (host chain store). - ctx.store_client_result(handler_output.result) - .map_err(Error::ics02_client)?; - - HandlerOutput::builder() - .with_log(handler_output.log) - .with_events(handler_output.events) - .with_result(()) - } - - Ics3Msg(msg) => { - let handler_output = ics3_msg_dispatcher(ctx, msg).map_err(Error::ics03_connection)?; - - // Apply any results to the host chain store. - ctx.store_connection_result(handler_output.result) - .map_err(Error::ics03_connection)?; - - HandlerOutput::builder() - .with_log(handler_output.log) - .with_events(handler_output.events) - .with_result(()) - } - - Ics4ChannelMsg(msg) => { - let module_id = ics4_validate(ctx, &msg).map_err(Error::ics04_channel)?; - let (mut handler_builder, channel_result) = - ics4_msg_dispatcher(ctx, &msg).map_err(Error::ics04_channel)?; - - let mut module_output = ModuleOutputBuilder::new(); - let cb_result = - ics4_callback(ctx, &module_id, &msg, channel_result, &mut module_output); - handler_builder.merge(module_output); - let channel_result = cb_result.map_err(Error::ics04_channel)?; - - // Apply any results to the host chain store. - ctx.store_channel_result(channel_result) - .map_err(Error::ics04_channel)?; - - handler_builder.with_result(()) - } - - Ics4PacketMsg(msg) => { - let module_id = get_module_for_packet_msg(ctx, &msg).map_err(Error::ics04_channel)?; - let (mut handler_builder, packet_result) = - ics4_packet_msg_dispatcher(ctx, &msg).map_err(Error::ics04_channel)?; - - if matches!(packet_result, PacketResult::Recv(RecvPacketResult::NoOp)) { - return Ok(handler_builder.with_result(())); - } - - let cb_result = ics4_packet_callback(ctx, &module_id, &msg, &mut handler_builder); - cb_result.map_err(Error::ics04_channel)?; - - // Apply any results to the host chain store. - ctx.store_packet_result(packet_result) - .map_err(Error::ics04_channel)?; - - handler_builder.with_result(()) - } - }; - - Ok(output) -} - -#[cfg(test)] -mod tests { - use core::default::Default; - - use test_log::test; - - use crate::applications::transfer::msgs::transfer::test_util::get_dummy_transfer_packet; - use crate::applications::transfer::{ - context::test::deliver as ics20_deliver, msgs::transfer::test_util::get_dummy_msg_transfer, - msgs::transfer::MsgTransfer, packet::PacketData, PrefixedCoin, MODULE_ID_STR, - }; - use crate::core::ics02_client::msgs::{ - create_client::MsgCreateClient, update_client::MsgUpdateClient, - upgrade_client::MsgUpgradeClient, ClientMsg, - }; - use crate::core::ics03_connection::msgs::{ - conn_open_ack::{test_util::get_dummy_raw_msg_conn_open_ack, MsgConnectionOpenAck}, - conn_open_init::{test_util::get_dummy_raw_msg_conn_open_init, MsgConnectionOpenInit}, - conn_open_try::{test_util::get_dummy_raw_msg_conn_open_try, MsgConnectionOpenTry}, - ConnectionMsg, - }; - use crate::core::ics04_channel::context::ChannelReader; - use crate::core::ics04_channel::msgs::acknowledgement::test_util::get_dummy_raw_msg_ack_with_packet; - use crate::core::ics04_channel::msgs::acknowledgement::MsgAcknowledgement; - use crate::core::ics04_channel::msgs::{ - chan_close_confirm::{ - test_util::get_dummy_raw_msg_chan_close_confirm, MsgChannelCloseConfirm, - }, - chan_close_init::{test_util::get_dummy_raw_msg_chan_close_init, MsgChannelCloseInit}, - chan_open_ack::{test_util::get_dummy_raw_msg_chan_open_ack, MsgChannelOpenAck}, - chan_open_init::{test_util::get_dummy_raw_msg_chan_open_init, MsgChannelOpenInit}, - chan_open_try::{test_util::get_dummy_raw_msg_chan_open_try, MsgChannelOpenTry}, - recv_packet::{test_util::get_dummy_raw_msg_recv_packet, MsgRecvPacket}, - timeout_on_close::{test_util::get_dummy_raw_msg_timeout_on_close, MsgTimeoutOnClose}, - ChannelMsg, PacketMsg, - }; - use crate::core::ics04_channel::timeout::TimeoutHeight; - use crate::core::ics23_commitment::commitment::test_util::get_dummy_merkle_proof; - use crate::core::ics24_host::identifier::ConnectionId; - use crate::core::ics26_routing::context::{Ics26Context, ModuleId, Router, RouterBuilder}; - use crate::core::ics26_routing::error::Error; - use crate::core::ics26_routing::handler::dispatch; - use crate::core::ics26_routing::msgs::Ics26Envelope; - use crate::events::IbcEvent; - use crate::handler::HandlerOutputBuilder; - use crate::mock::client_state::MockClientState; - use crate::mock::consensus_state::MockConsensusState; - use crate::mock::context::{MockContext, MockRouterBuilder}; - use crate::mock::header::MockHeader; - use crate::prelude::*; - use crate::test_utils::{get_dummy_account_id, DummyTransferModule}; - use crate::timestamp::Timestamp; - use crate::Height; - - #[test] - /// These tests exercise two main paths: (1) the ability of the ICS26 routing module to dispatch - /// messages to the correct module handler, and more importantly: (2) the ability of ICS handlers - /// to work with the context and correctly store results (i.e., the `ClientKeeper`, - /// `ConnectionKeeper`, and `ChannelKeeper` traits). - fn routing_module_and_keepers() { - #[derive(Clone, Debug)] - enum TestMsg { - Ics26(Ics26Envelope), - Ics20(MsgTransfer), - } - - impl From for TestMsg { - fn from(msg: Ics26Envelope) -> Self { - Self::Ics26(msg) - } - } - - impl From> for TestMsg { - fn from(msg: MsgTransfer) -> Self { - Self::Ics20(msg) - } - } - - type StateCheckFn = dyn FnOnce(&MockContext) -> bool; - - // Test parameters - struct Test { - name: String, - msg: TestMsg, - want_pass: bool, - state_check: Option>, - } - let default_signer = get_dummy_account_id(); - let client_height = 5; - let start_client_height = Height::new(0, client_height).unwrap(); - let update_client_height = Height::new(0, 34).unwrap(); - let update_client_height_after_send = Height::new(0, 35).unwrap(); - - let update_client_height_after_second_send = Height::new(0, 36).unwrap(); - - let upgrade_client_height = Height::new(1, 2).unwrap(); - - let upgrade_client_height_second = Height::new(1, 1).unwrap(); - - let transfer_module_id: ModuleId = MODULE_ID_STR.parse().unwrap(); - - // We reuse this same context across all tests. Nothing in particular needs parametrizing. - let mut ctx = { - let ctx = MockContext::default(); - let module = DummyTransferModule::new(ctx.ibc_store_share()); - let router = MockRouterBuilder::default() - .add_route(transfer_module_id.clone(), module) - .unwrap() - .build(); - ctx.with_router(router) - }; - - let create_client_msg = MsgCreateClient::new( - MockClientState::new(MockHeader::new(start_client_height)).into(), - MockConsensusState::new(MockHeader::new(start_client_height)).into(), - default_signer.clone(), - ) - .unwrap(); - - // - // Connection handshake messages. - // - let msg_conn_init = - MsgConnectionOpenInit::try_from(get_dummy_raw_msg_conn_open_init()).unwrap(); - - let correct_msg_conn_try = MsgConnectionOpenTry::try_from(get_dummy_raw_msg_conn_open_try( - client_height, - client_height, - )) - .unwrap(); - - // The handler will fail to process this msg because the client height is too advanced. - let incorrect_msg_conn_try = MsgConnectionOpenTry::try_from( - get_dummy_raw_msg_conn_open_try(client_height + 1, client_height + 1), - ) - .unwrap(); - - let msg_conn_ack = MsgConnectionOpenAck::try_from(get_dummy_raw_msg_conn_open_ack( - client_height, - client_height, - )) - .unwrap(); - - // - // Channel handshake messages. - // - let msg_chan_init = - MsgChannelOpenInit::try_from(get_dummy_raw_msg_chan_open_init()).unwrap(); - - // The handler will fail to process this b/c the associated connection does not exist - let mut incorrect_msg_chan_init = msg_chan_init.clone(); - incorrect_msg_chan_init.channel.connection_hops = vec![ConnectionId::new(590)]; - - let msg_chan_try = - MsgChannelOpenTry::try_from(get_dummy_raw_msg_chan_open_try(client_height)).unwrap(); - - let msg_chan_ack = - MsgChannelOpenAck::try_from(get_dummy_raw_msg_chan_open_ack(client_height)).unwrap(); - - let msg_chan_close_init = - MsgChannelCloseInit::try_from(get_dummy_raw_msg_chan_close_init()).unwrap(); - - let msg_chan_close_confirm = - MsgChannelCloseConfirm::try_from(get_dummy_raw_msg_chan_close_confirm(client_height)) - .unwrap(); - - let msg_transfer = get_dummy_msg_transfer(Height::new(0, 35).unwrap().into(), None); - let msg_transfer_two = get_dummy_msg_transfer(Height::new(0, 36).unwrap().into(), None); - let msg_transfer_no_timeout = get_dummy_msg_transfer(TimeoutHeight::no_timeout(), None); - let msg_transfer_no_timeout_or_timestamp = get_dummy_msg_transfer( - TimeoutHeight::no_timeout(), - Some(Timestamp::from_nanoseconds(0).unwrap()), - ); - - let mut msg_to_on_close = - MsgTimeoutOnClose::try_from(get_dummy_raw_msg_timeout_on_close(36, 5)).unwrap(); - msg_to_on_close.packet.sequence = 2.into(); - msg_to_on_close.packet.timeout_height = msg_transfer_two.timeout_height; - msg_to_on_close.packet.timeout_timestamp = msg_transfer_two.timeout_timestamp; - - let denom = msg_transfer_two.token.denom.clone(); - let packet_data = { - let data = PacketData { - token: PrefixedCoin { - denom, - amount: msg_transfer_two.token.amount, - }, - sender: msg_transfer_two.sender.clone(), - receiver: msg_transfer_two.receiver.clone(), - }; - serde_json::to_vec(&data).expect("PacketData's infallible Serialize impl failed") - }; - msg_to_on_close.packet.data = packet_data; - - let msg_recv_packet = MsgRecvPacket::try_from(get_dummy_raw_msg_recv_packet(35)).unwrap(); - let msg_ack_packet = MsgAcknowledgement::try_from(get_dummy_raw_msg_ack_with_packet( - get_dummy_transfer_packet(msg_transfer.clone(), 1u64.into()).into(), - 35, - )) - .unwrap(); - - // First, create a client.. - let res = dispatch( - &mut ctx, - Ics26Envelope::Ics2Msg(ClientMsg::CreateClient(create_client_msg.clone())), - ); - - assert!( - res.is_ok(), - "ICS26 routing dispatch test 'client creation' failed for message {:?} with result: {:?}", - create_client_msg, - res - ); - - ctx.scope_port_to_module(msg_chan_init.port_id.clone(), transfer_module_id.clone()); - - // Figure out the ID of the client that was just created. - let mut events = res.unwrap().events; - let client_id_event = events.pop(); - assert!( - client_id_event.is_some(), - "There was no event generated for client creation!" - ); - let client_id = match client_id_event.unwrap() { - IbcEvent::CreateClient(create_client) => create_client.client_id().clone(), - event => panic!("unexpected IBC event: {:?}", event), - }; - - let tests: Vec = vec![ - // Test some ICS2 client functionality. - Test { - name: "Client update successful".to_string(), - msg: Ics26Envelope::Ics2Msg(ClientMsg::UpdateClient(MsgUpdateClient { - client_id: client_id.clone(), - header: MockHeader::new(update_client_height) - .with_timestamp(Timestamp::now()) - .into(), - signer: default_signer.clone(), - })) - .into(), - want_pass: true, - state_check: None, - }, - Test { - name: "Client update fails due to stale header".to_string(), - msg: Ics26Envelope::Ics2Msg(ClientMsg::UpdateClient(MsgUpdateClient { - client_id: client_id.clone(), - header: MockHeader::new(update_client_height).into(), - signer: default_signer.clone(), - })) - .into(), - want_pass: false, - state_check: None, - }, - Test { - name: "Connection open init succeeds".to_string(), - msg: Ics26Envelope::Ics3Msg(ConnectionMsg::ConnectionOpenInit( - msg_conn_init.with_client_id(client_id.clone()), - )) - .into(), - want_pass: true, - state_check: None, - }, - Test { - name: "Connection open try fails due to InvalidConsensusHeight (too high)" - .to_string(), - msg: Ics26Envelope::Ics3Msg(ConnectionMsg::ConnectionOpenTry(Box::new( - incorrect_msg_conn_try, - ))) - .into(), - want_pass: false, - state_check: None, - }, - Test { - name: "Connection open try succeeds".to_string(), - msg: Ics26Envelope::Ics3Msg(ConnectionMsg::ConnectionOpenTry(Box::new( - correct_msg_conn_try.with_client_id(client_id.clone()), - ))) - .into(), - want_pass: true, - state_check: None, - }, - Test { - name: "Connection open ack succeeds".to_string(), - msg: Ics26Envelope::Ics3Msg(ConnectionMsg::ConnectionOpenAck(Box::new( - msg_conn_ack, - ))) - .into(), - want_pass: true, - state_check: None, - }, - // ICS04 - Test { - name: "Channel open init succeeds".to_string(), - msg: Ics26Envelope::Ics4ChannelMsg(ChannelMsg::ChannelOpenInit(msg_chan_init)) - .into(), - want_pass: true, - state_check: None, - }, - Test { - name: "Channel open init fail due to missing connection".to_string(), - msg: Ics26Envelope::Ics4ChannelMsg(ChannelMsg::ChannelOpenInit( - incorrect_msg_chan_init, - )) - .into(), - want_pass: false, - state_check: None, - }, - Test { - name: "Channel open try succeeds".to_string(), - msg: Ics26Envelope::Ics4ChannelMsg(ChannelMsg::ChannelOpenTry(msg_chan_try)).into(), - want_pass: true, - state_check: None, - }, - Test { - name: "Channel open ack succeeds".to_string(), - msg: Ics26Envelope::Ics4ChannelMsg(ChannelMsg::ChannelOpenAck(msg_chan_ack)).into(), - want_pass: true, - state_check: None, - }, - Test { - name: "Packet send".to_string(), - msg: msg_transfer.into(), - want_pass: true, - state_check: None, - }, - // The client update is required in this test, because the proof associated with - // msg_recv_packet has the same height as the packet TO height (see get_dummy_raw_msg_recv_packet) - Test { - name: "Client update successful #2".to_string(), - msg: Ics26Envelope::Ics2Msg(ClientMsg::UpdateClient(MsgUpdateClient { - client_id: client_id.clone(), - header: MockHeader::new(update_client_height_after_send) - .with_timestamp(Timestamp::now()) - .into(), - signer: default_signer.clone(), - })) - .into(), - want_pass: true, - state_check: None, - }, - Test { - name: "Receive packet".to_string(), - msg: Ics26Envelope::Ics4PacketMsg(PacketMsg::RecvPacket(msg_recv_packet.clone())) - .into(), - want_pass: true, - state_check: None, - }, - Test { - name: "Re-Receive packet".to_string(), - msg: Ics26Envelope::Ics4PacketMsg(PacketMsg::RecvPacket(msg_recv_packet)).into(), - want_pass: true, - state_check: None, - }, - // Ack packet - Test { - name: "Ack packet".to_string(), - msg: Ics26Envelope::Ics4PacketMsg(PacketMsg::AckPacket(msg_ack_packet.clone())) - .into(), - want_pass: true, - state_check: Some(Box::new(move |ctx| { - ctx.get_packet_commitment( - &msg_ack_packet.packet.source_port, - &msg_ack_packet.packet.source_channel, - msg_ack_packet.packet.sequence, - ) - .is_err() - })), - }, - Test { - name: "Packet send".to_string(), - msg: msg_transfer_two.into(), - want_pass: true, - state_check: None, - }, - Test { - name: "Client update successful".to_string(), - msg: Ics26Envelope::Ics2Msg(ClientMsg::UpdateClient(MsgUpdateClient { - client_id: client_id.clone(), - header: MockHeader::new(update_client_height_after_second_send).into(), - signer: default_signer.clone(), - })) - .into(), - want_pass: true, - state_check: None, - }, - // Timeout packets - Test { - name: "Transfer message no timeout".to_string(), - msg: msg_transfer_no_timeout.into(), - want_pass: true, - state_check: None, - }, - Test { - name: "Transfer message no timeout nor timestamp".to_string(), - msg: msg_transfer_no_timeout_or_timestamp.into(), - want_pass: true, - state_check: None, - }, - //ICS04-close channel - Test { - name: "Channel close init succeeds".to_string(), - msg: Ics26Envelope::Ics4ChannelMsg(ChannelMsg::ChannelCloseInit( - msg_chan_close_init, - )) - .into(), - want_pass: true, - state_check: None, - }, - Test { - name: "Channel close confirm fails cause channel is already closed".to_string(), - msg: Ics26Envelope::Ics4ChannelMsg(ChannelMsg::ChannelCloseConfirm( - msg_chan_close_confirm, - )) - .into(), - want_pass: false, - state_check: None, - }, - //ICS04-to_on_close - Test { - name: "Timeout on close".to_string(), - msg: Ics26Envelope::Ics4PacketMsg(PacketMsg::ToClosePacket(msg_to_on_close)).into(), - want_pass: true, - state_check: None, - }, - Test { - name: "Client upgrade successful".to_string(), - msg: Ics26Envelope::Ics2Msg(ClientMsg::UpgradeClient(MsgUpgradeClient::new( - client_id.clone(), - MockClientState::new(MockHeader::new(upgrade_client_height)).into(), - MockConsensusState::new(MockHeader::new(upgrade_client_height)).into(), - get_dummy_merkle_proof(), - get_dummy_merkle_proof(), - default_signer.clone(), - ))) - .into(), - want_pass: true, - state_check: None, - }, - Test { - name: "Client upgrade un-successful".to_string(), - msg: Ics26Envelope::Ics2Msg(ClientMsg::UpgradeClient(MsgUpgradeClient::new( - client_id, - MockClientState::new(MockHeader::new(upgrade_client_height_second)).into(), - MockConsensusState::new(MockHeader::new(upgrade_client_height_second)).into(), - get_dummy_merkle_proof(), - get_dummy_merkle_proof(), - default_signer, - ))) - .into(), - want_pass: false, - state_check: None, - }, - ] - .into_iter() - .collect(); - - for test in tests { - let res = match test.msg.clone() { - TestMsg::Ics26(msg) => dispatch(&mut ctx, msg).map(|_| ()), - TestMsg::Ics20(msg) => { - let transfer_module = - ctx.router_mut().get_route_mut(&transfer_module_id).unwrap(); - ics20_deliver( - transfer_module - .as_any_mut() - .downcast_mut::() - .unwrap(), - &mut HandlerOutputBuilder::new(), - msg, - ) - .map(|_| ()) - .map_err(Error::ics04_channel) - } - }; - - assert_eq!( - test.want_pass, - res.is_ok(), - "ICS26 routing dispatch test '{}' failed for message {:?}\nwith result: {:?}", - test.name, - test.msg, - res - ); - - if let Some(state_check) = test.state_check { - assert_eq!( - test.want_pass, - state_check(&ctx), - "ICS26 routing state check '{}' failed for message {:?}\nwith result: {:?}", - test.name, - test.msg, - res - ); - } - } - } -} diff --git a/modules/src/core/ics26_routing/mod.rs b/modules/src/core/ics26_routing/mod.rs deleted file mode 100644 index 79e5a5ff29..0000000000 --- a/modules/src/core/ics26_routing/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -//! ICS 26: Routing module keeps a lookup table of modules for looking -//! the appropriate module to relay to when a packet is received. - -pub mod context; -pub mod error; -pub mod handler; -pub mod msgs; diff --git a/modules/src/core/ics26_routing/msgs.rs b/modules/src/core/ics26_routing/msgs.rs deleted file mode 100644 index 5f3d581408..0000000000 --- a/modules/src/core/ics26_routing/msgs.rs +++ /dev/null @@ -1,156 +0,0 @@ -use crate::prelude::*; - -use ibc_proto::google::protobuf::Any; - -use crate::core::ics02_client::msgs::{create_client, update_client, upgrade_client, ClientMsg}; -use crate::core::ics03_connection::msgs::{ - conn_open_ack, conn_open_confirm, conn_open_init, conn_open_try, ConnectionMsg, -}; -use crate::core::ics04_channel::msgs::{ - acknowledgement, chan_close_confirm, chan_close_init, chan_open_ack, chan_open_confirm, - chan_open_init, chan_open_try, recv_packet, timeout, timeout_on_close, ChannelMsg, PacketMsg, -}; -use crate::core::ics26_routing::error::Error; -use ibc_proto::protobuf::Protobuf; - -/// Enumeration of all messages that the local ICS26 module is capable of routing. -#[derive(Clone, Debug)] -pub enum Ics26Envelope { - Ics2Msg(ClientMsg), - Ics3Msg(ConnectionMsg), - Ics4ChannelMsg(ChannelMsg), - Ics4PacketMsg(PacketMsg), -} - -impl TryFrom for Ics26Envelope { - type Error = Error; - - fn try_from(any_msg: Any) -> Result { - match any_msg.type_url.as_str() { - // ICS2 messages - create_client::TYPE_URL => { - // Pop out the message and then wrap it in the corresponding type. - let domain_msg = create_client::MsgCreateClient::decode_vec(&any_msg.value) - .map_err(Error::malformed_message_bytes)?; - Ok(Ics26Envelope::Ics2Msg(ClientMsg::CreateClient(domain_msg))) - } - update_client::TYPE_URL => { - let domain_msg = update_client::MsgUpdateClient::decode_vec(&any_msg.value) - .map_err(Error::malformed_message_bytes)?; - Ok(Ics26Envelope::Ics2Msg(ClientMsg::UpdateClient(domain_msg))) - } - upgrade_client::TYPE_URL => { - let domain_msg = upgrade_client::MsgUpgradeClient::decode_vec(&any_msg.value) - .map_err(Error::malformed_message_bytes)?; - Ok(Ics26Envelope::Ics2Msg(ClientMsg::UpgradeClient(domain_msg))) - } - - // ICS03 - conn_open_init::TYPE_URL => { - let domain_msg = conn_open_init::MsgConnectionOpenInit::decode_vec(&any_msg.value) - .map_err(Error::malformed_message_bytes)?; - Ok(Ics26Envelope::Ics3Msg(ConnectionMsg::ConnectionOpenInit( - domain_msg, - ))) - } - conn_open_try::TYPE_URL => { - let domain_msg = conn_open_try::MsgConnectionOpenTry::decode_vec(&any_msg.value) - .map_err(Error::malformed_message_bytes)?; - Ok(Ics26Envelope::Ics3Msg(ConnectionMsg::ConnectionOpenTry( - Box::new(domain_msg), - ))) - } - conn_open_ack::TYPE_URL => { - let domain_msg = conn_open_ack::MsgConnectionOpenAck::decode_vec(&any_msg.value) - .map_err(Error::malformed_message_bytes)?; - Ok(Ics26Envelope::Ics3Msg(ConnectionMsg::ConnectionOpenAck( - Box::new(domain_msg), - ))) - } - conn_open_confirm::TYPE_URL => { - let domain_msg = - conn_open_confirm::MsgConnectionOpenConfirm::decode_vec(&any_msg.value) - .map_err(Error::malformed_message_bytes)?; - Ok(Ics26Envelope::Ics3Msg( - ConnectionMsg::ConnectionOpenConfirm(domain_msg), - )) - } - - // ICS04 channel messages - chan_open_init::TYPE_URL => { - let domain_msg = chan_open_init::MsgChannelOpenInit::decode_vec(&any_msg.value) - .map_err(Error::malformed_message_bytes)?; - Ok(Ics26Envelope::Ics4ChannelMsg(ChannelMsg::ChannelOpenInit( - domain_msg, - ))) - } - chan_open_try::TYPE_URL => { - let domain_msg = chan_open_try::MsgChannelOpenTry::decode_vec(&any_msg.value) - .map_err(Error::malformed_message_bytes)?; - Ok(Ics26Envelope::Ics4ChannelMsg(ChannelMsg::ChannelOpenTry( - domain_msg, - ))) - } - chan_open_ack::TYPE_URL => { - let domain_msg = chan_open_ack::MsgChannelOpenAck::decode_vec(&any_msg.value) - .map_err(Error::malformed_message_bytes)?; - Ok(Ics26Envelope::Ics4ChannelMsg(ChannelMsg::ChannelOpenAck( - domain_msg, - ))) - } - chan_open_confirm::TYPE_URL => { - let domain_msg = - chan_open_confirm::MsgChannelOpenConfirm::decode_vec(&any_msg.value) - .map_err(Error::malformed_message_bytes)?; - Ok(Ics26Envelope::Ics4ChannelMsg( - ChannelMsg::ChannelOpenConfirm(domain_msg), - )) - } - chan_close_init::TYPE_URL => { - let domain_msg = chan_close_init::MsgChannelCloseInit::decode_vec(&any_msg.value) - .map_err(Error::malformed_message_bytes)?; - Ok(Ics26Envelope::Ics4ChannelMsg(ChannelMsg::ChannelCloseInit( - domain_msg, - ))) - } - chan_close_confirm::TYPE_URL => { - let domain_msg = - chan_close_confirm::MsgChannelCloseConfirm::decode_vec(&any_msg.value) - .map_err(Error::malformed_message_bytes)?; - Ok(Ics26Envelope::Ics4ChannelMsg( - ChannelMsg::ChannelCloseConfirm(domain_msg), - )) - } - // ICS04 packet messages - recv_packet::TYPE_URL => { - let domain_msg = recv_packet::MsgRecvPacket::decode_vec(&any_msg.value) - .map_err(Error::malformed_message_bytes)?; - Ok(Ics26Envelope::Ics4PacketMsg(PacketMsg::RecvPacket( - domain_msg, - ))) - } - acknowledgement::TYPE_URL => { - let domain_msg = acknowledgement::MsgAcknowledgement::decode_vec(&any_msg.value) - .map_err(Error::malformed_message_bytes)?; - Ok(Ics26Envelope::Ics4PacketMsg(PacketMsg::AckPacket( - domain_msg, - ))) - } - timeout::TYPE_URL => { - let domain_msg = timeout::MsgTimeout::decode_vec(&any_msg.value) - .map_err(Error::malformed_message_bytes)?; - Ok(Ics26Envelope::Ics4PacketMsg(PacketMsg::ToPacket( - domain_msg, - ))) - } - timeout_on_close::TYPE_URL => { - let domain_msg = timeout_on_close::MsgTimeoutOnClose::decode_vec(&any_msg.value) - .map_err(Error::malformed_message_bytes)?; - Ok(Ics26Envelope::Ics4PacketMsg(PacketMsg::ToClosePacket( - domain_msg, - ))) - } - _ => Err(Error::unknown_message_type_url(any_msg.type_url)), - } - } -} diff --git a/modules/src/core/mod.rs b/modules/src/core/mod.rs deleted file mode 100644 index ef9cc94681..0000000000 --- a/modules/src/core/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -//! The designs and logic pertaining to the transport, authentication, and -//! ordering layers of the IBC protocol. - -pub mod ics02_client; -pub mod ics03_connection; -pub mod ics04_channel; -pub mod ics05_port; -pub mod ics23_commitment; -pub mod ics24_host; -pub mod ics26_routing; diff --git a/modules/src/dynamic_typing.rs b/modules/src/dynamic_typing.rs deleted file mode 100644 index 22eb9e11be..0000000000 --- a/modules/src/dynamic_typing.rs +++ /dev/null @@ -1,11 +0,0 @@ -use core::any::Any; - -pub trait AsAny: Any { - fn as_any(&self) -> &dyn Any; -} - -impl AsAny for M { - fn as_any(&self) -> &dyn Any { - self - } -} diff --git a/modules/src/events.rs b/modules/src/events.rs deleted file mode 100644 index 4c083829dd..0000000000 --- a/modules/src/events.rs +++ /dev/null @@ -1,482 +0,0 @@ -use crate::prelude::*; -use crate::utils::pretty::PrettyVec; - -use core::convert::{TryFrom, TryInto}; -use core::fmt::{Display, Error as FmtError, Formatter}; -use core::str::FromStr; -use flex_error::{define_error, TraceError}; -use serde_derive::{Deserialize, Serialize}; -use tendermint::abci::tag::Tag; -use tendermint::abci::Event as AbciEvent; - -use crate::core::ics02_client::error as client_error; -use crate::core::ics02_client::events::NewBlock; -use crate::core::ics02_client::events::{self as ClientEvents}; -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::packet::Packet; -use crate::core::ics24_host::error::ValidationError; -use crate::core::ics26_routing::context::ModuleId; -use crate::timestamp::ParseTimestampError; - -define_error! { - Error { - Height - | _ | { "error parsing height" }, - - Parse - [ ValidationError ] - | _ | { "parse error" }, - - Client - [ client_error::Error ] - | _ | { "ICS02 client error" }, - - Connection - [ connection_error::Error ] - | _ | { "connection error" }, - - Channel - [ channel_error::Error ] - | _ | { "channel error" }, - - Timestamp - [ ParseTimestampError ] - | _ | { "error parsing timestamp" }, - - MissingKey - { key: String } - | e | { format_args!("missing event key {}", e.key) }, - - Decode - [ TraceError ] - | _ | { "error decoding protobuf" }, - - SubtleEncoding - [ TraceError ] - | _ | { "error decoding hex" }, - - MissingActionString - | _ | { "missing action string" }, - - IncorrectEventType - { event: String } - | e | { format_args!("incorrect event type: {}", e.event) }, - - MalformedModuleEvent - { event: ModuleEvent } - | e | { format_args!("module event cannot use core event types: {:?}", e.event) }, - - UnsupportedAbciEvent - {event_type: String} - |e| { format_args!("Unable to parse abci event type '{}' into IbcEvent", e.event_type)} - } -} - -/// Events whose data is not included in the app state and must be extracted using tendermint RPCs -/// (i.e. /tx_search or /block_search) -#[derive(Debug, Clone, Deserialize, Serialize)] -pub enum WithBlockDataType { - CreateClient, - UpdateClient, - SendPacket, - WriteAck, -} - -impl WithBlockDataType { - pub fn as_str(&self) -> &'static str { - match *self { - WithBlockDataType::CreateClient => "create_client", - WithBlockDataType::UpdateClient => "update_client", - WithBlockDataType::SendPacket => "send_packet", - WithBlockDataType::WriteAck => "write_acknowledgement", - } - } -} - -const NEW_BLOCK_EVENT: &str = "new_block"; -const EMPTY_EVENT: &str = "empty"; -const CHAIN_ERROR_EVENT: &str = "chain_error"; -const APP_MODULE_EVENT: &str = "app_module"; -/// Client event types -const CREATE_CLIENT_EVENT: &str = "create_client"; -const UPDATE_CLIENT_EVENT: &str = "update_client"; -const CLIENT_MISBEHAVIOUR_EVENT: &str = "client_misbehaviour"; -const UPGRADE_CLIENT_EVENT: &str = "upgrade_client"; -/// Connection event types -const CONNECTION_INIT_EVENT: &str = "connection_open_init"; -const CONNECTION_TRY_EVENT: &str = "connection_open_try"; -const CONNECTION_ACK_EVENT: &str = "connection_open_ack"; -const CONNECTION_CONFIRM_EVENT: &str = "connection_open_confirm"; -/// Channel event types -const CHANNEL_OPEN_INIT_EVENT: &str = "channel_open_init"; -const CHANNEL_OPEN_TRY_EVENT: &str = "channel_open_try"; -const CHANNEL_OPEN_ACK_EVENT: &str = "channel_open_ack"; -const CHANNEL_OPEN_CONFIRM_EVENT: &str = "channel_open_confirm"; -const CHANNEL_CLOSE_INIT_EVENT: &str = "channel_close_init"; -const CHANNEL_CLOSE_CONFIRM_EVENT: &str = "channel_close_confirm"; -/// Packet event types -const SEND_PACKET_EVENT: &str = "send_packet"; -const RECEIVE_PACKET_EVENT: &str = "receive_packet"; -const WRITE_ACK_EVENT: &str = "write_acknowledgement"; -const ACK_PACKET_EVENT: &str = "acknowledge_packet"; -const TIMEOUT_EVENT: &str = "timeout_packet"; -const TIMEOUT_ON_CLOSE_EVENT: &str = "timeout_packet_on_close"; - -/// Events types -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] -pub enum IbcEventType { - NewBlock, - CreateClient, - UpdateClient, - UpgradeClient, - ClientMisbehaviour, - OpenInitConnection, - OpenTryConnection, - OpenAckConnection, - OpenConfirmConnection, - OpenInitChannel, - OpenTryChannel, - OpenAckChannel, - OpenConfirmChannel, - CloseInitChannel, - CloseConfirmChannel, - SendPacket, - ReceivePacket, - WriteAck, - AckPacket, - Timeout, - TimeoutOnClose, - AppModule, - Empty, - ChainError, -} - -impl IbcEventType { - pub fn as_str(&self) -> &'static str { - match *self { - IbcEventType::NewBlock => NEW_BLOCK_EVENT, - IbcEventType::CreateClient => CREATE_CLIENT_EVENT, - IbcEventType::UpdateClient => UPDATE_CLIENT_EVENT, - IbcEventType::UpgradeClient => UPGRADE_CLIENT_EVENT, - IbcEventType::ClientMisbehaviour => CLIENT_MISBEHAVIOUR_EVENT, - IbcEventType::OpenInitConnection => CONNECTION_INIT_EVENT, - IbcEventType::OpenTryConnection => CONNECTION_TRY_EVENT, - IbcEventType::OpenAckConnection => CONNECTION_ACK_EVENT, - IbcEventType::OpenConfirmConnection => CONNECTION_CONFIRM_EVENT, - IbcEventType::OpenInitChannel => CHANNEL_OPEN_INIT_EVENT, - IbcEventType::OpenTryChannel => CHANNEL_OPEN_TRY_EVENT, - IbcEventType::OpenAckChannel => CHANNEL_OPEN_ACK_EVENT, - IbcEventType::OpenConfirmChannel => CHANNEL_OPEN_CONFIRM_EVENT, - IbcEventType::CloseInitChannel => CHANNEL_CLOSE_INIT_EVENT, - IbcEventType::CloseConfirmChannel => CHANNEL_CLOSE_CONFIRM_EVENT, - IbcEventType::SendPacket => SEND_PACKET_EVENT, - IbcEventType::ReceivePacket => RECEIVE_PACKET_EVENT, - IbcEventType::WriteAck => WRITE_ACK_EVENT, - IbcEventType::AckPacket => ACK_PACKET_EVENT, - IbcEventType::Timeout => TIMEOUT_EVENT, - IbcEventType::TimeoutOnClose => TIMEOUT_ON_CLOSE_EVENT, - IbcEventType::AppModule => APP_MODULE_EVENT, - IbcEventType::Empty => EMPTY_EVENT, - IbcEventType::ChainError => CHAIN_ERROR_EVENT, - } - } -} - -impl FromStr for IbcEventType { - type Err = Error; - - fn from_str(s: &str) -> Result { - match s { - NEW_BLOCK_EVENT => Ok(IbcEventType::NewBlock), - CREATE_CLIENT_EVENT => Ok(IbcEventType::CreateClient), - UPDATE_CLIENT_EVENT => Ok(IbcEventType::UpdateClient), - UPGRADE_CLIENT_EVENT => Ok(IbcEventType::UpgradeClient), - CLIENT_MISBEHAVIOUR_EVENT => Ok(IbcEventType::ClientMisbehaviour), - CONNECTION_INIT_EVENT => Ok(IbcEventType::OpenInitConnection), - CONNECTION_TRY_EVENT => Ok(IbcEventType::OpenTryConnection), - CONNECTION_ACK_EVENT => Ok(IbcEventType::OpenAckConnection), - CONNECTION_CONFIRM_EVENT => Ok(IbcEventType::OpenConfirmConnection), - CHANNEL_OPEN_INIT_EVENT => Ok(IbcEventType::OpenInitChannel), - CHANNEL_OPEN_TRY_EVENT => Ok(IbcEventType::OpenTryChannel), - CHANNEL_OPEN_ACK_EVENT => Ok(IbcEventType::OpenAckChannel), - CHANNEL_OPEN_CONFIRM_EVENT => Ok(IbcEventType::OpenConfirmChannel), - CHANNEL_CLOSE_INIT_EVENT => Ok(IbcEventType::CloseInitChannel), - CHANNEL_CLOSE_CONFIRM_EVENT => Ok(IbcEventType::CloseConfirmChannel), - SEND_PACKET_EVENT => Ok(IbcEventType::SendPacket), - RECEIVE_PACKET_EVENT => Ok(IbcEventType::ReceivePacket), - WRITE_ACK_EVENT => Ok(IbcEventType::WriteAck), - ACK_PACKET_EVENT => Ok(IbcEventType::AckPacket), - TIMEOUT_EVENT => Ok(IbcEventType::Timeout), - TIMEOUT_ON_CLOSE_EVENT => Ok(IbcEventType::TimeoutOnClose), - EMPTY_EVENT => Ok(IbcEventType::Empty), - CHAIN_ERROR_EVENT => Ok(IbcEventType::ChainError), - // from_str() for `APP_MODULE_EVENT` MUST fail because a `ModuleEvent`'s type isn't constant - _ => Err(Error::incorrect_event_type(s.to_string())), - } - } -} - -/// Events created by the IBC component of a chain, destined for a relayer. -#[derive(Debug, Clone, Serialize)] -pub enum IbcEvent { - NewBlock(NewBlock), - - CreateClient(ClientEvents::CreateClient), - UpdateClient(ClientEvents::UpdateClient), - UpgradeClient(ClientEvents::UpgradeClient), - ClientMisbehaviour(ClientEvents::ClientMisbehaviour), - - OpenInitConnection(ConnectionEvents::OpenInit), - OpenTryConnection(ConnectionEvents::OpenTry), - OpenAckConnection(ConnectionEvents::OpenAck), - OpenConfirmConnection(ConnectionEvents::OpenConfirm), - - OpenInitChannel(ChannelEvents::OpenInit), - OpenTryChannel(ChannelEvents::OpenTry), - OpenAckChannel(ChannelEvents::OpenAck), - OpenConfirmChannel(ChannelEvents::OpenConfirm), - CloseInitChannel(ChannelEvents::CloseInit), - CloseConfirmChannel(ChannelEvents::CloseConfirm), - - SendPacket(ChannelEvents::SendPacket), - ReceivePacket(ChannelEvents::ReceivePacket), - WriteAcknowledgement(ChannelEvents::WriteAcknowledgement), - AcknowledgePacket(ChannelEvents::AcknowledgePacket), - TimeoutPacket(ChannelEvents::TimeoutPacket), - TimeoutOnClosePacket(ChannelEvents::TimeoutOnClosePacket), - - AppModule(ModuleEvent), - - ChainError(String), // Special event, signifying an error on CheckTx or DeliverTx -} - -impl Display for IbcEvent { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - match self { - IbcEvent::NewBlock(ev) => write!(f, "NewBlock({})", ev.height), - - IbcEvent::CreateClient(ev) => write!(f, "CreateClient({})", ev), - IbcEvent::UpdateClient(ev) => write!(f, "UpdateClient({})", ev), - IbcEvent::UpgradeClient(ev) => write!(f, "UpgradeClient({})", ev), - IbcEvent::ClientMisbehaviour(ev) => write!(f, "ClientMisbehaviour({})", ev), - - IbcEvent::OpenInitConnection(ev) => write!(f, "OpenInitConnection({})", ev), - IbcEvent::OpenTryConnection(ev) => write!(f, "OpenTryConnection({})", ev), - IbcEvent::OpenAckConnection(ev) => write!(f, "OpenAckConnection({})", ev), - IbcEvent::OpenConfirmConnection(ev) => write!(f, "OpenConfirmConnection({})", ev), - - IbcEvent::OpenInitChannel(ev) => write!(f, "OpenInitChannel({})", ev), - IbcEvent::OpenTryChannel(ev) => write!(f, "OpenTryChannel({})", ev), - IbcEvent::OpenAckChannel(ev) => write!(f, "OpenAckChannel({})", ev), - IbcEvent::OpenConfirmChannel(ev) => write!(f, "OpenConfirmChannel({})", ev), - IbcEvent::CloseInitChannel(ev) => write!(f, "CloseInitChannel({})", ev), - IbcEvent::CloseConfirmChannel(ev) => write!(f, "CloseConfirmChannel({})", ev), - - IbcEvent::SendPacket(ev) => write!(f, "SendPacket({})", ev), - IbcEvent::ReceivePacket(ev) => write!(f, "ReceivePacket({})", ev), - IbcEvent::WriteAcknowledgement(ev) => write!(f, "WriteAcknowledgement({})", ev), - IbcEvent::AcknowledgePacket(ev) => write!(f, "AcknowledgePacket({})", ev), - IbcEvent::TimeoutPacket(ev) => write!(f, "TimeoutPacket({})", ev), - IbcEvent::TimeoutOnClosePacket(ev) => write!(f, "TimeoutOnClosePacket({})", ev), - - IbcEvent::AppModule(ev) => write!(f, "AppModule({})", ev), - - IbcEvent::ChainError(ev) => write!(f, "ChainError({})", ev), - } - } -} - -impl TryFrom for AbciEvent { - type Error = Error; - - fn try_from(event: IbcEvent) -> Result { - Ok(match event { - IbcEvent::CreateClient(event) => event.into(), - IbcEvent::UpdateClient(event) => event.into(), - IbcEvent::UpgradeClient(event) => event.into(), - IbcEvent::ClientMisbehaviour(event) => event.into(), - IbcEvent::OpenInitConnection(event) => event.into(), - IbcEvent::OpenTryConnection(event) => event.into(), - IbcEvent::OpenAckConnection(event) => event.into(), - IbcEvent::OpenConfirmConnection(event) => event.into(), - IbcEvent::OpenInitChannel(event) => event.into(), - IbcEvent::OpenTryChannel(event) => event.into(), - IbcEvent::OpenAckChannel(event) => event.into(), - IbcEvent::OpenConfirmChannel(event) => event.into(), - IbcEvent::CloseInitChannel(event) => event.into(), - IbcEvent::CloseConfirmChannel(event) => event.into(), - IbcEvent::SendPacket(event) => event.try_into().map_err(Error::channel)?, - IbcEvent::ReceivePacket(event) => event.try_into().map_err(Error::channel)?, - IbcEvent::WriteAcknowledgement(event) => event.try_into().map_err(Error::channel)?, - IbcEvent::AcknowledgePacket(event) => event.try_into().map_err(Error::channel)?, - IbcEvent::TimeoutPacket(event) => event.try_into().map_err(Error::channel)?, - IbcEvent::TimeoutOnClosePacket(event) => event.try_into().map_err(Error::channel)?, - IbcEvent::AppModule(event) => event.try_into()?, - IbcEvent::NewBlock(_) | IbcEvent::ChainError(_) => { - return Err(Error::incorrect_event_type(event.to_string())) - } - }) - } -} - -impl IbcEvent { - pub fn to_json(&self) -> String { - match serde_json::to_string(self) { - Ok(value) => value, - Err(_) => format!("{:?}", self), // Fallback to debug printing - } - } - - pub fn event_type(&self) -> IbcEventType { - match self { - IbcEvent::NewBlock(_) => IbcEventType::NewBlock, - IbcEvent::CreateClient(_) => IbcEventType::CreateClient, - IbcEvent::UpdateClient(_) => IbcEventType::UpdateClient, - IbcEvent::ClientMisbehaviour(_) => IbcEventType::ClientMisbehaviour, - IbcEvent::UpgradeClient(_) => IbcEventType::UpgradeClient, - IbcEvent::OpenInitConnection(_) => IbcEventType::OpenInitConnection, - IbcEvent::OpenTryConnection(_) => IbcEventType::OpenTryConnection, - IbcEvent::OpenAckConnection(_) => IbcEventType::OpenAckConnection, - IbcEvent::OpenConfirmConnection(_) => IbcEventType::OpenConfirmConnection, - IbcEvent::OpenInitChannel(_) => IbcEventType::OpenInitChannel, - IbcEvent::OpenTryChannel(_) => IbcEventType::OpenTryChannel, - IbcEvent::OpenAckChannel(_) => IbcEventType::OpenAckChannel, - IbcEvent::OpenConfirmChannel(_) => IbcEventType::OpenConfirmChannel, - IbcEvent::CloseInitChannel(_) => IbcEventType::CloseInitChannel, - IbcEvent::CloseConfirmChannel(_) => IbcEventType::CloseConfirmChannel, - IbcEvent::SendPacket(_) => IbcEventType::SendPacket, - IbcEvent::ReceivePacket(_) => IbcEventType::ReceivePacket, - IbcEvent::WriteAcknowledgement(_) => IbcEventType::WriteAck, - IbcEvent::AcknowledgePacket(_) => IbcEventType::AckPacket, - IbcEvent::TimeoutPacket(_) => IbcEventType::Timeout, - IbcEvent::TimeoutOnClosePacket(_) => IbcEventType::TimeoutOnClose, - IbcEvent::AppModule(_) => IbcEventType::AppModule, - IbcEvent::ChainError(_) => IbcEventType::ChainError, - } - } - - pub fn channel_attributes(self) -> Option { - match self { - IbcEvent::OpenInitChannel(ev) => Some(ev.into()), - IbcEvent::OpenTryChannel(ev) => Some(ev.into()), - IbcEvent::OpenAckChannel(ev) => Some(ev.into()), - IbcEvent::OpenConfirmChannel(ev) => Some(ev.into()), - _ => None, - } - } - - pub fn connection_attributes(&self) -> Option<&ConnectionAttributes> { - match self { - IbcEvent::OpenInitConnection(ev) => Some(ev.attributes()), - IbcEvent::OpenTryConnection(ev) => Some(ev.attributes()), - IbcEvent::OpenAckConnection(ev) => Some(ev.attributes()), - IbcEvent::OpenConfirmConnection(ev) => Some(ev.attributes()), - _ => None, - } - } - - pub fn packet(&self) -> Option<&Packet> { - match self { - IbcEvent::SendPacket(ev) => Some(&ev.packet), - IbcEvent::ReceivePacket(ev) => Some(&ev.packet), - IbcEvent::WriteAcknowledgement(ev) => Some(&ev.packet), - IbcEvent::AcknowledgePacket(ev) => Some(&ev.packet), - IbcEvent::TimeoutPacket(ev) => Some(&ev.packet), - IbcEvent::TimeoutOnClosePacket(ev) => Some(&ev.packet), - _ => None, - } - } - - pub fn ack(&self) -> Option<&[u8]> { - match self { - IbcEvent::WriteAcknowledgement(ev) => Some(&ev.ack), - _ => None, - } - } -} - -#[derive(Debug, Clone, Serialize, PartialEq, Eq)] -pub struct ModuleEvent { - pub kind: String, - pub module_name: ModuleId, - pub attributes: Vec, -} - -impl Display for ModuleEvent { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!( - f, - "ModuleEvent {{ kind: {}, module_name: {}, attributes: {} }}", - self.kind, - self.module_name, - PrettyVec(&self.attributes) - ) - } -} - -impl TryFrom for AbciEvent { - type Error = Error; - - fn try_from(event: ModuleEvent) -> Result { - if IbcEventType::from_str(event.kind.as_str()).is_ok() { - return Err(Error::malformed_module_event(event)); - } - - let attributes = event.attributes.into_iter().map(Into::into).collect(); - Ok(AbciEvent { - type_str: event.kind, - attributes, - }) - } -} - -impl From for IbcEvent { - fn from(e: ModuleEvent) -> Self { - IbcEvent::AppModule(e) - } -} - -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] -pub struct ModuleEventAttribute { - pub key: String, - pub value: String, -} - -impl Display for ModuleEventAttribute { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!( - f, - "ModuleEventAttribute {{ key: {}, value: {} }}", - self.key, self.value - ) - } -} - -impl From<(K, V)> for ModuleEventAttribute { - fn from((k, v): (K, V)) -> Self { - Self { - key: k.to_string(), - value: v.to_string(), - } - } -} - -impl From for Tag { - fn from(attr: ModuleEventAttribute) -> Self { - Self { - key: attr - .key - .parse() - .expect("Key::from_str() impl is infallible"), - value: attr - .key - .parse() - .expect("Value::from_str() impl is infallible"), - } - } -} diff --git a/modules/src/handler.rs b/modules/src/handler.rs deleted file mode 100644 index f8bf203ebb..0000000000 --- a/modules/src/handler.rs +++ /dev/null @@ -1,79 +0,0 @@ -use crate::events::IbcEvent; -use crate::prelude::*; -use core::marker::PhantomData; - -pub type HandlerResult = Result, E>; - -#[derive(Clone, Debug)] -pub struct HandlerOutput { - pub result: T, - pub log: Vec, - pub events: Vec, -} - -impl HandlerOutput { - pub fn builder() -> HandlerOutputBuilder { - HandlerOutputBuilder::new() - } -} - -#[derive(Clone, Debug, Default)] -pub struct HandlerOutputBuilder { - log: Vec, - events: Vec, - marker: PhantomData, -} - -impl HandlerOutputBuilder { - pub fn new() -> Self { - Self { - log: Vec::new(), - events: Vec::new(), - marker: PhantomData, - } - } - - pub fn with_log(mut self, log: impl Into>) -> Self { - self.log.append(&mut log.into()); - self - } - - pub fn log(&mut self, log: impl Into) { - self.log.push(log.into()); - } - - pub fn with_events(mut self, mut events: Vec) -> Self { - self.events.append(&mut events); - self - } - - pub fn emit(&mut self, event: E) { - self.events.push(event); - } - - pub fn with_result(self, result: T) -> HandlerOutput { - HandlerOutput { - result, - log: self.log, - events: self.events, - } - } - - pub fn merge>(&mut self, other: HandlerOutputBuilder<(), Event>) { - let HandlerOutputBuilder { - mut log, events, .. - } = other; - self.log.append(&mut log); - self.events - .append(&mut events.into_iter().map(Into::into).collect()); - } - - pub fn merge_output>(&mut self, other: HandlerOutput<(), Event>) { - let HandlerOutput { - mut log, events, .. - } = other; - self.log.append(&mut log); - self.events - .append(&mut events.into_iter().map(Into::into).collect()); - } -} diff --git a/modules/src/keys.rs b/modules/src/keys.rs deleted file mode 100644 index b16ee0b546..0000000000 --- a/modules/src/keys.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub const MODULE_NAME: &str = "ibc"; -pub const STORE_KEY: &str = MODULE_NAME; -pub const QUERIER_ROUTE: &str = MODULE_NAME; -pub const ROUTER_KEY: &str = MODULE_NAME; diff --git a/modules/src/lib.rs b/modules/src/lib.rs deleted file mode 100644 index b3a4eec68c..0000000000 --- a/modules/src/lib.rs +++ /dev/null @@ -1,82 +0,0 @@ -// TODO: disable unwraps: -// https://github.com/informalsystems/ibc-rs/issues/987 -// #![cfg_attr(not(test), deny(clippy::unwrap_used))] - -#![no_std] -#![allow(clippy::large_enum_variant)] -#![deny( - warnings, - trivial_casts, - trivial_numeric_casts, - unused_import_braces, - unused_qualifications, - rust_2018_idioms -)] -#![forbid(unsafe_code)] - -//! This library implements the InterBlockchain Communication (IBC) protocol in Rust. IBC is -//! a distributed protocol that enables communication between distinct sovereign blockchains. -//! Loose analogies may be drawn between the IBC protocol and the TCP/UDP protocols that enable -//! communication over the internet via packet streaming. Indeed, IBC also encodes the notion of -//! ordered and unordered packet streams. -//! -//! The layout of this crate mirrors the classification of the [Interchain -//! Standards][ics-standards]. The classification consists of [Core][core], [Clients][clients], -//! [Applications][applications], and [Relayer][relayer]. -//! -//! `Core` consists of the designs and logic pertaining to the transport, authentication, and -//! ordering layers of the IBC protocol, the fundamental pieces. -//! -//! `Clients` consists of implementations of client verification algorithms (following the base -//! client interface that is defined in `Core`) for specific types of chains. A chain uses these -//! verification algorithms to verify the state of remote chains. -//! -//! `Applications` consists of various packet encoding and processing semantics which underpin the -//! various types of transactions that users can perform on any IBC-compliant chain. -//! -//! `Relayer` contains utilities for testing the `ibc` crate against the [Hermes IBC relayer][relayer-repo]. It acts -//! as scaffolding for gluing the `ibc` crate with Hermes for testing purposes. -//! -//! [core]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/core -//! [clients]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/clients -//! [applications]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/applications -//! [ics-standards]: https://github.com/cosmos/ibc#interchain-standards -//! [relayer]: https://github.com/informalsystems/ibc-rs/tree/master/modules/src/relayer -//! [relayer-repo]: https://github.com/informalsystems/ibc-rs/tree/master/relayer - -extern crate alloc; - -#[cfg(feature = "std")] -extern crate std; - -mod prelude; - -pub mod applications; -pub mod bigint; -pub mod clients; -pub mod core; -pub mod dynamic_typing; -pub mod events; -pub mod handler; -pub mod keys; -pub mod macros; -pub mod proofs; -pub mod relayer; -pub mod signer; -pub mod timestamp; -pub mod tx_msg; -pub mod utils; - -mod serializers; - -/// Re-export of ICS 002 Height domain type -pub type Height = crate::core::ics02_client::height::Height; - -#[cfg(test)] -mod test; - -#[cfg(any(test, feature = "mocks"))] -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/modules/src/macros.rs b/modules/src/macros.rs deleted file mode 100644 index c4ad6655d7..0000000000 --- a/modules/src/macros.rs +++ /dev/null @@ -1,49 +0,0 @@ -/// Downcast the given arguments to the associated enum variant. -/// -/// ## Note -/// Only works for enums whose variants only hold a single value. -/// -/// ## Example -/// -/// ```rust -/// use ibc::downcast; -/// -/// enum Foo { -/// Bar(u32), -/// Baz(bool), -/// } -/// -/// let bar = Foo::Bar(42); -/// let baz = Foo::Baz(true); -/// -/// if let Some(value) = downcast!(bar => Foo::Bar) { -/// println!("value is a u32: {}", value); -/// } -/// -/// if let Some(value) = downcast!(baz => Foo::Baz) { -/// println!("value is a bool: {}", value); -/// } -/// -/// if let Some((a, b)) = downcast!(bar => Foo::Bar, baz => Foo::Baz) { -/// println!("a is a u32: {}", a); -/// println!("b is a bool: {}", b); -/// } -/// ``` -#[macro_export] -macro_rules! downcast { - ( $e1:expr => $p1:path, $( $e:expr => $p:path ),+ $(,)? ) => { - downcast!($e1 => $p1).zip(downcast!($($e => $p),+)) - }; - - ($e:expr => $p:path) => { - match $e { - $p(e) => Some(e), - #[allow(unreachable_patterns)] - _ => None, - } - }; - - () => { - None - } -} diff --git a/modules/src/mock/client_state.rs b/modules/src/mock/client_state.rs deleted file mode 100644 index be43112bac..0000000000 --- a/modules/src/mock/client_state.rs +++ /dev/null @@ -1,321 +0,0 @@ -use crate::core::ics02_client::context::ClientReader; -use crate::core::ics03_connection::connection::ConnectionEnd; -use crate::core::ics04_channel::channel::ChannelEnd; -use crate::core::ics04_channel::commitment::{AcknowledgementCommitment, PacketCommitment}; -use crate::core::ics04_channel::context::ChannelReader; -use crate::core::ics04_channel::packet::Sequence; -use crate::core::ics23_commitment::commitment::{ - CommitmentPrefix, CommitmentProofBytes, CommitmentRoot, -}; -use crate::core::ics23_commitment::merkle::apply_prefix; -use crate::core::ics24_host::path::ClientConsensusStatePath; -use crate::core::ics24_host::Path; -use crate::prelude::*; - -use alloc::collections::btree_map::BTreeMap as HashMap; -use core::time::Duration; -use dyn_clone::clone_box; -use ibc_proto::ibc::core::commitment::v1::MerkleProof; - -use ibc_proto::google::protobuf::Any; -use ibc_proto::ibc::mock::ClientState as RawMockClientState; -use ibc_proto::protobuf::Protobuf; -use serde::{Deserialize, Serialize}; - -use crate::core::ics02_client::client_state::{ClientState, UpdatedState, UpgradeOptions}; -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::ics24_host::identifier::{ChainId, ChannelId, ClientId, ConnectionId, PortId}; -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 an IBC client record as it is stored in a mock context. -/// For testing ICS02 handlers mostly, cf. `MockClientContext`. -#[derive(Clone, Debug)] -pub struct MockClientRecord { - /// The type of this client. - pub client_type: ClientType, - - /// The client state (representing only the latest height at the moment). - pub client_state: Option>, - - /// Mapping of heights to consensus states for this client. - pub consensus_states: HashMap>, -} - -/// 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() - } - - pub fn refresh_time(&self) -> Option { - None - } -} - -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::unknown_client_state_type(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) - .expect("encoding to `Any` from `MockClientState`"), - } - } -} - -impl ClientState for MockClientState { - 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: &dyn UpgradeOptions, - _chain_id: ChainId, - ) { - unimplemented!() - } - - fn expired(&self, _elapsed: Duration) -> bool { - false - } - - fn initialise(&self, consensus_state: Any) -> Result, Error> { - MockConsensusState::try_from(consensus_state).map(MockConsensusState::into_box) - } - - fn check_header_and_update_state( - &self, - _ctx: &dyn ClientReader, - _client_id: ClientId, - header: Any, - ) -> Result { - let header = MockHeader::try_from(header)?; - - if self.latest_height() >= header.height() { - return Err(Error::low_header_height( - header.height(), - self.latest_height(), - )); - } - - Ok(UpdatedState { - client_state: MockClientState::new(header).into_box(), - consensus_state: MockConsensusState::new(header).into_box(), - }) - } - - fn verify_upgrade_and_update_state( - &self, - consensus_state: Any, - _proof_upgrade_client: MerkleProof, - _proof_upgrade_consensus_state: MerkleProof, - ) -> Result { - let consensus_state = MockConsensusState::try_from(consensus_state)?; - Ok(UpdatedState { - client_state: clone_box(self), - consensus_state: consensus_state.into_box(), - }) - } - - fn verify_client_consensus_state( - &self, - _height: Height, - prefix: &CommitmentPrefix, - _proof: &CommitmentProofBytes, - _root: &CommitmentRoot, - client_id: &ClientId, - consensus_height: Height, - _expected_consensus_state: &dyn ConsensusState, - ) -> Result<(), Error> { - let client_prefixed_path = Path::ClientConsensusState(ClientConsensusStatePath { - client_id: client_id.clone(), - epoch: consensus_height.revision_number(), - height: consensus_height.revision_height(), - }) - .to_string(); - - let _path = apply_prefix(prefix, vec![client_prefixed_path]); - - Ok(()) - } - - fn verify_connection_state( - &self, - _height: Height, - _prefix: &CommitmentPrefix, - _proof: &CommitmentProofBytes, - _root: &CommitmentRoot, - _connection_id: &ConnectionId, - _expected_connection_end: &ConnectionEnd, - ) -> Result<(), Error> { - Ok(()) - } - - fn verify_channel_state( - &self, - _height: Height, - _prefix: &CommitmentPrefix, - _proof: &CommitmentProofBytes, - _root: &CommitmentRoot, - _port_id: &PortId, - _channel_id: &ChannelId, - _expected_channel_end: &ChannelEnd, - ) -> Result<(), Error> { - Ok(()) - } - - fn verify_client_full_state( - &self, - _height: Height, - _prefix: &CommitmentPrefix, - _proof: &CommitmentProofBytes, - _root: &CommitmentRoot, - _client_id: &ClientId, - _expected_client_state: Any, - ) -> Result<(), Error> { - Ok(()) - } - - fn verify_packet_data( - &self, - _ctx: &dyn ChannelReader, - _height: Height, - _connection_end: &ConnectionEnd, - _proof: &CommitmentProofBytes, - _root: &CommitmentRoot, - _port_id: &PortId, - _channel_id: &ChannelId, - _sequence: Sequence, - _commitment: PacketCommitment, - ) -> Result<(), Error> { - Ok(()) - } - - fn verify_packet_acknowledgement( - &self, - _ctx: &dyn ChannelReader, - _height: Height, - _connection_end: &ConnectionEnd, - _proof: &CommitmentProofBytes, - _root: &CommitmentRoot, - _port_id: &PortId, - _channel_id: &ChannelId, - _sequence: Sequence, - _ack: AcknowledgementCommitment, - ) -> Result<(), Error> { - Ok(()) - } - - fn verify_next_sequence_recv( - &self, - _ctx: &dyn ChannelReader, - _height: Height, - _connection_end: &ConnectionEnd, - _proof: &CommitmentProofBytes, - _root: &CommitmentRoot, - _port_id: &PortId, - _channel_id: &ChannelId, - _sequence: Sequence, - ) -> Result<(), Error> { - Ok(()) - } - - fn verify_packet_receipt_absence( - &self, - _ctx: &dyn ChannelReader, - _height: Height, - _connection_end: &ConnectionEnd, - _proof: &CommitmentProofBytes, - _root: &CommitmentRoot, - _port_id: &PortId, - _channel_id: &ChannelId, - _sequence: Sequence, - ) -> Result<(), Error> { - Ok(()) - } -} - -impl From for MockClientState { - fn from(cs: MockConsensusState) -> Self { - Self::new(cs.header) - } -} diff --git a/modules/src/mock/consensus_state.rs b/modules/src/mock/consensus_state.rs deleted file mode 100644 index 5fcb8a40aa..0000000000 --- a/modules/src/mock/consensus_state.rs +++ /dev/null @@ -1,109 +0,0 @@ -use crate::prelude::*; - -use ibc_proto::google::protobuf::Any; -use ibc_proto::ibc::mock::ConsensusState as RawMockConsensusState; -use ibc_proto::protobuf::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) - .expect("encoding to `Any` from `MockConsensusState`"), - } - } -} - -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/modules/src/mock/context.rs b/modules/src/mock/context.rs deleted file mode 100644 index dae726f028..0000000000 --- a/modules/src/mock/context.rs +++ /dev/null @@ -1,1700 +0,0 @@ -//! Implementation of a global context mock. Used in testing handlers of all IBC modules. - -use crate::prelude::*; - -use alloc::collections::btree_map::BTreeMap; -use alloc::sync::Arc; -use core::borrow::Borrow; -use core::cmp::min; -use core::fmt::{Debug, Formatter}; -use core::ops::{Add, Sub}; -use core::time::Duration; -use std::sync::Mutex; - -use ibc_proto::google::protobuf::Any; -use sha2::Digest; -use tracing::debug; - -use crate::clients::ics07_tendermint::client_state::test_util::get_dummy_tendermint_client_state; -use crate::clients::ics07_tendermint::client_state::ClientState as TmClientState; -use crate::core::ics02_client::client_state::ClientState; -use crate::core::ics02_client::client_type::ClientType; -use crate::core::ics02_client::consensus_state::ConsensusState; -use crate::core::ics02_client::context::{ClientKeeper, ClientReader}; -use crate::core::ics02_client::error::Error as Ics02Error; -use crate::core::ics02_client::header::Header; -use crate::core::ics03_connection::connection::ConnectionEnd; -use crate::core::ics03_connection::context::{ConnectionKeeper, ConnectionReader}; -use crate::core::ics03_connection::error::Error as Ics03Error; -use crate::core::ics04_channel::channel::ChannelEnd; -use crate::core::ics04_channel::commitment::{AcknowledgementCommitment, PacketCommitment}; -use crate::core::ics04_channel::context::{ChannelKeeper, ChannelReader}; -use crate::core::ics04_channel::error::Error as Ics04Error; -use crate::core::ics04_channel::packet::{Receipt, Sequence}; -use crate::core::ics05_port::context::PortReader; -use crate::core::ics05_port::error::Error as Ics05Error; -use crate::core::ics05_port::error::Error; -use crate::core::ics23_commitment::commitment::CommitmentPrefix; -use crate::core::ics24_host::identifier::{ChainId, ChannelId, ClientId, ConnectionId, PortId}; -use crate::core::ics26_routing::context::{Ics26Context, Module, ModuleId, Router, RouterBuilder}; -use crate::core::ics26_routing::handler::{deliver, dispatch, MsgReceipt}; -use crate::core::ics26_routing::msgs::Ics26Envelope; -use crate::events::IbcEvent; -use crate::mock::client_state::{MockClientRecord, MockClientState}; -use crate::mock::consensus_state::MockConsensusState; -use crate::mock::header::MockHeader; -use crate::mock::host::{HostBlock, HostType}; -use crate::relayer::ics18_relayer::context::Ics18Context; -use crate::relayer::ics18_relayer::error::Error as Ics18Error; -use crate::signer::Signer; -use crate::timestamp::Timestamp; -use crate::Height; - -pub const DEFAULT_BLOCK_TIME_SECS: u64 = 3; - -/// A context implementing the dependencies necessary for testing any IBC module. -#[derive(Debug)] -pub struct MockContext { - /// The type of host chain underlying this mock context. - host_chain_type: HostType, - - /// Host chain identifier. - host_chain_id: ChainId, - - /// Maximum size for the history of the host chain. Any block older than this is pruned. - max_history_size: usize, - - /// The chain of blocks underlying this context. A vector of size up to `max_history_size` - /// blocks, ascending order by their height (latest block is on the last position). - history: Vec, - - /// Average time duration between blocks - block_time: Duration, - - /// An object that stores all IBC related data. - pub ibc_store: Arc>, - - /// ICS26 router impl - router: MockRouter, -} - -/// Returns a MockContext with bare minimum initialization: no clients, no connections and no channels are -/// present, and the chain has Height(5). This should be used sparingly, mostly for testing the -/// creation of new domain objects. -impl Default for MockContext { - fn default() -> Self { - Self::new( - ChainId::new("mockgaia".to_string(), 0), - HostType::Mock, - 5, - Height::new(0, 5).unwrap(), - ) - } -} - -/// A manual clone impl is provided because the tests are oblivious to the fact that the `ibc_store` -/// is a shared ptr. -impl Clone for MockContext { - fn clone(&self) -> Self { - let ibc_store = { - let ibc_store = self.ibc_store.lock().unwrap().clone(); - Arc::new(Mutex::new(ibc_store)) - }; - Self { - host_chain_type: self.host_chain_type, - host_chain_id: self.host_chain_id.clone(), - max_history_size: self.max_history_size, - history: self.history.clone(), - block_time: self.block_time, - ibc_store, - router: self.router.clone(), - } - } -} - -/// Implementation of internal interface for use in testing. The methods in this interface should -/// _not_ be accessible to any Ics handler. -impl MockContext { - /// Creates a mock context. Parameter `max_history_size` determines how many blocks will - /// the chain maintain in its history, which also determines the pruning window. Parameter - /// `latest_height` determines the current height of the chain. This context - /// has support to emulate two type of underlying chains: Mock or SyntheticTendermint. - pub fn new( - host_id: ChainId, - host_type: HostType, - max_history_size: usize, - latest_height: Height, - ) -> Self { - assert_ne!( - max_history_size, 0, - "The chain must have a non-zero max_history_size" - ); - - assert_ne!( - latest_height.revision_height(), - 0, - "The chain must have a non-zero revision_height" - ); - - // Compute the number of blocks to store. - let n = min(max_history_size as u64, latest_height.revision_height()); - - assert_eq!( - host_id.version(), - latest_height.revision_number(), - "The version in the chain identifier must match the version in the latest height" - ); - - let block_time = Duration::from_secs(DEFAULT_BLOCK_TIME_SECS); - let next_block_timestamp = Timestamp::now().add(block_time).unwrap(); - MockContext { - host_chain_type: host_type, - host_chain_id: host_id.clone(), - max_history_size, - history: (0..n) - .rev() - .map(|i| { - // generate blocks with timestamps -> N, N - BT, N - 2BT, ... - // where N = now(), BT = block_time - HostBlock::generate_block( - host_id.clone(), - host_type, - latest_height.sub(i).unwrap().revision_height(), - next_block_timestamp - .sub(Duration::from_secs(DEFAULT_BLOCK_TIME_SECS * (i + 1))) - .unwrap(), - ) - }) - .collect(), - block_time, - ibc_store: Arc::new(Mutex::new(MockIbcStore::default())), - router: Default::default(), - } - } - - /// Associates a client record to this context. - /// Given a client id and a height, registers a new client in the context and also associates - /// to this client a mock client state and a mock consensus state for height `height`. The type - /// of this client is implicitly assumed to be Mock. - pub fn with_client(self, client_id: &ClientId, height: Height) -> Self { - self.with_client_parametrized(client_id, height, Some(ClientType::Mock), Some(height)) - } - - /// Similar to `with_client`, this function associates a client record to this context, but - /// additionally permits to parametrize two details of the client. If `client_type` is None, - /// then the client will have type Mock, otherwise the specified type. If - /// `consensus_state_height` is None, then the client will be initialized with a consensus - /// state matching the same height as the client state (`client_state_height`). - pub fn with_client_parametrized( - self, - client_id: &ClientId, - client_state_height: Height, - client_type: Option, - consensus_state_height: Option, - ) -> Self { - let cs_height = consensus_state_height.unwrap_or(client_state_height); - - let client_type = client_type.unwrap_or(ClientType::Mock); - let (client_state, consensus_state) = match client_type { - // If it's a mock client, create the corresponding mock states. - ClientType::Mock => ( - Some(MockClientState::new(MockHeader::new(client_state_height)).into_box()), - MockConsensusState::new(MockHeader::new(cs_height)).into_box(), - ), - // If it's a Tendermint client, we need TM states. - ClientType::Tendermint => { - let light_block = HostBlock::generate_tm_block( - self.host_chain_id.clone(), - cs_height.revision_height(), - Timestamp::now(), - ); - - let client_state = - get_dummy_tendermint_client_state(light_block.header().clone()).into_box(); - - // Return the tuple. - (Some(client_state), light_block.into()) - } - }; - let consensus_states = vec![(cs_height, consensus_state)].into_iter().collect(); - - debug!("consensus states: {:?}", consensus_states); - - let client_record = MockClientRecord { - client_type, - client_state, - consensus_states, - }; - self.ibc_store - .lock() - .unwrap() - .clients - .insert(client_id.clone(), client_record); - self - } - - pub fn with_client_parametrized_history( - self, - client_id: &ClientId, - client_state_height: Height, - client_type: Option, - consensus_state_height: Option, - ) -> Self { - let cs_height = consensus_state_height.unwrap_or(client_state_height); - let prev_cs_height = cs_height.clone().sub(1).unwrap_or(client_state_height); - - let client_type = client_type.unwrap_or(ClientType::Mock); - let now = Timestamp::now(); - - let (client_state, consensus_state) = match client_type { - // If it's a mock client, create the corresponding mock states. - ClientType::Mock => ( - Some(MockClientState::new(MockHeader::new(client_state_height)).into_box()), - MockConsensusState::new(MockHeader::new(cs_height)).into_box(), - ), - // If it's a Tendermint client, we need TM states. - ClientType::Tendermint => { - let light_block = HostBlock::generate_tm_block( - self.host_chain_id.clone(), - cs_height.revision_height(), - now, - ); - - let client_state = - get_dummy_tendermint_client_state(light_block.header().clone()).into_box(); - - // Return the tuple. - (Some(client_state), light_block.into()) - } - }; - - let prev_consensus_state = match client_type { - // If it's a mock client, create the corresponding mock states. - ClientType::Mock => MockConsensusState::new(MockHeader::new(prev_cs_height)).into_box(), - // If it's a Tendermint client, we need TM states. - ClientType::Tendermint => { - let light_block = HostBlock::generate_tm_block( - self.host_chain_id.clone(), - prev_cs_height.revision_height(), - now.sub(self.block_time).unwrap(), - ); - light_block.into() - } - }; - - let consensus_states = vec![ - (prev_cs_height, prev_consensus_state), - (cs_height, consensus_state), - ] - .into_iter() - .collect(); - - debug!("consensus states: {:?}", consensus_states); - - let client_record = MockClientRecord { - client_type, - client_state, - consensus_states, - }; - - self.ibc_store - .lock() - .unwrap() - .clients - .insert(client_id.clone(), client_record); - self - } - - /// Associates a connection to this context. - pub fn with_connection( - self, - connection_id: ConnectionId, - connection_end: ConnectionEnd, - ) -> Self { - self.ibc_store - .lock() - .unwrap() - .connections - .insert(connection_id, connection_end); - self - } - - /// Associates a channel (in an arbitrary state) to this context. - pub fn with_channel( - self, - port_id: PortId, - chan_id: ChannelId, - channel_end: ChannelEnd, - ) -> Self { - let mut channels = self.ibc_store.lock().unwrap().channels.clone(); - channels - .entry(port_id) - .or_default() - .insert(chan_id, channel_end); - self.ibc_store.lock().unwrap().channels = channels; - self - } - - pub fn with_send_sequence( - self, - port_id: PortId, - chan_id: ChannelId, - seq_number: Sequence, - ) -> Self { - let mut next_sequence_send = self.ibc_store.lock().unwrap().next_sequence_send.clone(); - next_sequence_send - .entry(port_id) - .or_default() - .insert(chan_id, seq_number); - self.ibc_store.lock().unwrap().next_sequence_send = next_sequence_send; - self - } - - pub fn with_recv_sequence( - self, - port_id: PortId, - chan_id: ChannelId, - seq_number: Sequence, - ) -> Self { - let mut next_sequence_recv = self.ibc_store.lock().unwrap().next_sequence_recv.clone(); - next_sequence_recv - .entry(port_id) - .or_default() - .insert(chan_id, seq_number); - self.ibc_store.lock().unwrap().next_sequence_recv = next_sequence_recv; - self - } - - pub fn with_ack_sequence( - self, - port_id: PortId, - chan_id: ChannelId, - seq_number: Sequence, - ) -> Self { - let mut next_sequence_ack = self.ibc_store.lock().unwrap().next_sequence_send.clone(); - next_sequence_ack - .entry(port_id) - .or_default() - .insert(chan_id, seq_number); - self.ibc_store.lock().unwrap().next_sequence_ack = next_sequence_ack; - self - } - - pub fn with_height(self, target_height: Height) -> Self { - let latest_height = self.latest_height(); - if target_height.revision_number() > latest_height.revision_number() { - unimplemented!() - } else if target_height.revision_number() < latest_height.revision_number() { - panic!("Cannot rewind history of the chain to a smaller revision number!") - } else if target_height.revision_height() < latest_height.revision_height() { - panic!("Cannot rewind history of the chain to a smaller revision height!") - } else if target_height.revision_height() > latest_height.revision_height() { - // Repeatedly advance the host chain height till we hit the desired height - let mut ctx = MockContext { ..self }; - while ctx.latest_height().revision_height() < target_height.revision_height() { - ctx.advance_host_chain_height() - } - ctx - } else { - // Both the revision number and height match - self - } - } - - pub fn with_packet_commitment( - self, - port_id: PortId, - chan_id: ChannelId, - seq: Sequence, - data: PacketCommitment, - ) -> Self { - let mut packet_commitment = self.ibc_store.lock().unwrap().packet_commitment.clone(); - packet_commitment - .entry(port_id) - .or_default() - .entry(chan_id) - .or_default() - .insert(seq, data); - self.ibc_store.lock().unwrap().packet_commitment = packet_commitment; - self - } - - pub fn with_router(self, router: MockRouter) -> Self { - Self { router, ..self } - } - - /// Accessor for a block of the local (host) chain from this context. - /// Returns `None` if the block at the requested height does not exist. - pub fn host_block(&self, target_height: Height) -> Option<&HostBlock> { - let target = target_height.revision_height() as usize; - let latest = self.latest_height().revision_height() as usize; - - // Check that the block is not too advanced, nor has it been pruned. - if (target > latest) || (target <= latest - self.history.len()) { - None // Block for requested height does not exist in history. - } else { - Some(&self.history[self.history.len() + target - latest - 1]) - } - } - - /// Triggers the advancing of the host chain, by extending the history of blocks (or headers). - pub fn advance_host_chain_height(&mut self) { - let latest_block = self.history.last().expect("history cannot be empty"); - let new_block = HostBlock::generate_block( - self.host_chain_id.clone(), - self.host_chain_type, - latest_block.height().increment().revision_height(), - latest_block.timestamp().add(self.block_time).unwrap(), - ); - - // Append the new header at the tip of the history. - if self.history.len() >= self.max_history_size { - // History is full, we rotate and replace the tip with the new header. - self.history.rotate_left(1); - self.history[self.max_history_size - 1] = new_block; - } else { - // History is not full yet. - self.history.push(new_block); - } - } - - /// A datagram passes from the relayer to the IBC module (on host chain). - /// Alternative method to `Ics18Context::send` that does not exercise any serialization. - /// Used in testing the Ics18 algorithms, hence this may return a Ics18Error. - pub fn deliver(&mut self, msg: Ics26Envelope) -> Result<(), Ics18Error> { - dispatch(self, msg).map_err(Ics18Error::transaction_failed)?; - // Create a new block. - self.advance_host_chain_height(); - Ok(()) - } - - /// Validates this context. Should be called after the context is mutated by a test. - pub fn validate(&self) -> Result<(), String> { - // Check that the number of entries is not higher than window size. - if self.history.len() > self.max_history_size { - return Err("too many entries".to_string()); - } - - // Check the content of the history. - if !self.history.is_empty() { - // Get the highest block. - let lh = &self.history[self.history.len() - 1]; - // Check latest is properly updated with highest header height. - if lh.height() != self.latest_height() { - return Err("latest height is not updated".to_string()); - } - } - - // Check that headers in the history are in sequential order. - for i in 1..self.history.len() { - let ph = &self.history[i - 1]; - let h = &self.history[i]; - if ph.height().increment() != h.height() { - return Err("headers in history not sequential".to_string()); - } - } - Ok(()) - } - - pub fn add_port(&mut self, port_id: PortId) { - let module_id = ModuleId::new(format!("module{}", port_id).into()).unwrap(); - self.ibc_store - .lock() - .unwrap() - .port_to_module - .insert(port_id, module_id); - } - - pub fn scope_port_to_module(&mut self, port_id: PortId, module_id: ModuleId) { - self.ibc_store - .lock() - .unwrap() - .port_to_module - .insert(port_id, module_id); - } - - pub fn latest_client_states(&self, client_id: &ClientId) -> Box { - self.ibc_store.lock().unwrap().clients[client_id] - .client_state - .as_ref() - .unwrap() - .clone() - } - - pub fn latest_consensus_states( - &self, - client_id: &ClientId, - height: &Height, - ) -> Box { - dyn_clone::clone_box( - self.ibc_store.lock().unwrap().clients[client_id] - .consensus_states - .get(height) - .unwrap() - .as_ref(), - ) - } - - #[inline] - fn latest_height(&self) -> Height { - self.history - .last() - .expect("history cannot be empty") - .height() - } - - pub fn ibc_store_share(&self) -> Arc> { - self.ibc_store.clone() - } -} - -type PortChannelIdMap = BTreeMap>; - -/// An object that stores all IBC related data. -#[derive(Clone, Debug, Default)] -pub struct MockIbcStore { - /// The set of all clients, indexed by their id. - pub clients: BTreeMap, - - /// Tracks the processed time for clients header updates - pub client_processed_times: BTreeMap<(ClientId, Height), Timestamp>, - - /// Tracks the processed height for the clients - pub client_processed_heights: BTreeMap<(ClientId, Height), Height>, - - /// Counter for the client identifiers, necessary for `increase_client_counter` and the - /// `client_counter` methods. - pub client_ids_counter: u64, - - /// Association between client ids and connection ids. - pub client_connections: BTreeMap, - - /// All the connections in the store. - pub connections: BTreeMap, - - /// Counter for connection identifiers (see `increase_connection_counter`). - pub connection_ids_counter: u64, - - /// Association between connection ids and channel ids. - pub connection_channels: BTreeMap>, - - /// Counter for channel identifiers (see `increase_channel_counter`). - pub channel_ids_counter: u64, - - /// All the channels in the store. TODO Make new key PortId X ChanneId - pub channels: PortChannelIdMap, - - /// Tracks the sequence number for the next packet to be sent. - pub next_sequence_send: PortChannelIdMap, - - /// Tracks the sequence number for the next packet to be received. - pub next_sequence_recv: PortChannelIdMap, - - /// Tracks the sequence number for the next packet to be acknowledged. - pub next_sequence_ack: PortChannelIdMap, - - pub packet_acknowledgement: PortChannelIdMap>, - - /// Maps ports to the the module that owns it - pub port_to_module: BTreeMap, - - /// Constant-size commitments to packets data fields - pub packet_commitment: PortChannelIdMap>, - - // Used by unordered channel - pub packet_receipt: PortChannelIdMap>, -} - -#[derive(Default)] -pub struct MockRouterBuilder(MockRouter); - -impl RouterBuilder for MockRouterBuilder { - type Router = MockRouter; - - fn add_route(mut self, module_id: ModuleId, module: impl Module) -> Result { - match self.0 .0.insert(module_id, Arc::new(module)) { - None => Ok(self), - Some(_) => Err("Duplicate module_id".to_owned()), - } - } - - fn build(self) -> Self::Router { - self.0 - } -} - -#[derive(Clone, Default)] -pub struct MockRouter(BTreeMap>); - -impl Debug for MockRouter { - fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - write!(f, "{:?}", self.0.keys().collect::>()) - } -} - -impl Router for MockRouter { - fn get_route_mut(&mut self, module_id: &impl Borrow) -> Option<&mut dyn Module> { - self.0.get_mut(module_id.borrow()).and_then(Arc::get_mut) - } - - fn has_route(&self, module_id: &impl Borrow) -> bool { - self.0.get(module_id.borrow()).is_some() - } -} - -impl Ics26Context for MockContext { - type Router = MockRouter; - - fn router(&self) -> &Self::Router { - &self.router - } - - fn router_mut(&mut self) -> &mut Self::Router { - &mut self.router - } -} - -impl PortReader for MockContext { - fn lookup_module_by_port(&self, port_id: &PortId) -> Result { - match self.ibc_store.lock().unwrap().port_to_module.get(port_id) { - Some(mod_id) => Ok(mod_id.clone()), - None => Err(Ics05Error::unknown_port(port_id.clone())), - } - } -} - -impl ChannelReader for MockContext { - fn channel_end( - &self, - port_id: &PortId, - channel_id: &ChannelId, - ) -> Result { - match self - .ibc_store - .lock() - .unwrap() - .channels - .get(port_id) - .and_then(|map| map.get(channel_id)) - { - Some(channel_end) => Ok(channel_end.clone()), - None => Err(Ics04Error::channel_not_found( - port_id.clone(), - channel_id.clone(), - )), - } - } - - fn connection_end(&self, cid: &ConnectionId) -> Result { - ConnectionReader::connection_end(self, cid).map_err(Ics04Error::ics03_connection) - } - - fn connection_channels( - &self, - cid: &ConnectionId, - ) -> Result, Ics04Error> { - match self.ibc_store.lock().unwrap().connection_channels.get(cid) { - Some(pcid) => Ok(pcid.clone()), - None => Err(Ics04Error::missing_channel()), - } - } - - fn client_state(&self, client_id: &ClientId) -> Result, Ics04Error> { - ClientReader::client_state(self, client_id) - .map_err(|e| Ics04Error::ics03_connection(Ics03Error::ics02_client(e))) - } - - fn client_consensus_state( - &self, - client_id: &ClientId, - height: Height, - ) -> Result, Ics04Error> { - ClientReader::consensus_state(self, client_id, height) - .map_err(|e| Ics04Error::ics03_connection(Ics03Error::ics02_client(e))) - } - - fn get_next_sequence_send( - &self, - port_id: &PortId, - channel_id: &ChannelId, - ) -> Result { - match self - .ibc_store - .lock() - .unwrap() - .next_sequence_send - .get(port_id) - .and_then(|map| map.get(channel_id)) - { - Some(sequence) => Ok(*sequence), - None => Err(Ics04Error::missing_next_send_seq( - port_id.clone(), - channel_id.clone(), - )), - } - } - - fn get_next_sequence_recv( - &self, - port_id: &PortId, - channel_id: &ChannelId, - ) -> Result { - match self - .ibc_store - .lock() - .unwrap() - .next_sequence_recv - .get(port_id) - .and_then(|map| map.get(channel_id)) - { - Some(sequence) => Ok(*sequence), - None => Err(Ics04Error::missing_next_recv_seq( - port_id.clone(), - channel_id.clone(), - )), - } - } - - fn get_next_sequence_ack( - &self, - port_id: &PortId, - channel_id: &ChannelId, - ) -> Result { - match self - .ibc_store - .lock() - .unwrap() - .next_sequence_ack - .get(port_id) - .and_then(|map| map.get(channel_id)) - { - Some(sequence) => Ok(*sequence), - None => Err(Ics04Error::missing_next_ack_seq( - port_id.clone(), - channel_id.clone(), - )), - } - } - - fn get_packet_commitment( - &self, - port_id: &PortId, - channel_id: &ChannelId, - seq: Sequence, - ) -> Result { - match self - .ibc_store - .lock() - .unwrap() - .packet_commitment - .get(port_id) - .and_then(|map| map.get(channel_id)) - .and_then(|map| map.get(&seq)) - { - Some(commitment) => Ok(commitment.clone()), - None => Err(Ics04Error::packet_commitment_not_found(seq)), - } - } - - fn get_packet_receipt( - &self, - port_id: &PortId, - channel_id: &ChannelId, - seq: Sequence, - ) -> Result { - match self - .ibc_store - .lock() - .unwrap() - .packet_receipt - .get(port_id) - .and_then(|map| map.get(channel_id)) - .and_then(|map| map.get(&seq)) - { - Some(receipt) => Ok(receipt.clone()), - None => Err(Ics04Error::packet_receipt_not_found(seq)), - } - } - - fn get_packet_acknowledgement( - &self, - port_id: &PortId, - channel_id: &ChannelId, - seq: Sequence, - ) -> Result { - match self - .ibc_store - .lock() - .unwrap() - .packet_acknowledgement - .get(port_id) - .and_then(|map| map.get(channel_id)) - .and_then(|map| map.get(&seq)) - { - Some(ack) => Ok(ack.clone()), - None => Err(Ics04Error::packet_acknowledgement_not_found(seq)), - } - } - - fn hash(&self, value: Vec) -> Vec { - sha2::Sha256::digest(value).to_vec() - } - - fn host_height(&self) -> Height { - self.latest_height() - } - - fn host_timestamp(&self) -> Timestamp { - ClientReader::host_timestamp(self) - } - - fn host_consensus_state(&self, height: Height) -> Result, Ics04Error> { - ConnectionReader::host_consensus_state(self, height).map_err(Ics04Error::ics03_connection) - } - - fn pending_host_consensus_state(&self) -> Result, Ics04Error> { - ClientReader::pending_host_consensus_state(self) - .map_err(|e| Ics04Error::ics03_connection(Ics03Error::ics02_client(e))) - } - - fn client_update_time( - &self, - client_id: &ClientId, - height: Height, - ) -> Result { - match self - .ibc_store - .lock() - .unwrap() - .client_processed_times - .get(&(client_id.clone(), height)) - { - Some(time) => Ok(*time), - None => Err(Ics04Error::processed_time_not_found( - client_id.clone(), - height, - )), - } - } - - fn client_update_height( - &self, - client_id: &ClientId, - height: Height, - ) -> Result { - match self - .ibc_store - .lock() - .unwrap() - .client_processed_heights - .get(&(client_id.clone(), height)) - { - Some(height) => Ok(*height), - None => Err(Ics04Error::processed_height_not_found( - client_id.clone(), - height, - )), - } - } - - fn channel_counter(&self) -> Result { - Ok(self.ibc_store.lock().unwrap().channel_ids_counter) - } - - fn max_expected_time_per_block(&self) -> Duration { - self.block_time - } -} - -impl ChannelKeeper for MockContext { - fn store_packet_commitment( - &mut self, - port_id: PortId, - channel_id: ChannelId, - seq: Sequence, - commitment: PacketCommitment, - ) -> Result<(), Ics04Error> { - self.ibc_store - .lock() - .unwrap() - .packet_commitment - .entry(port_id) - .or_default() - .entry(channel_id) - .or_default() - .insert(seq, commitment); - Ok(()) - } - - fn store_packet_acknowledgement( - &mut self, - port_id: PortId, - channel_id: ChannelId, - seq: Sequence, - ack_commitment: AcknowledgementCommitment, - ) -> Result<(), Ics04Error> { - self.ibc_store - .lock() - .unwrap() - .packet_acknowledgement - .entry(port_id) - .or_default() - .entry(channel_id) - .or_default() - .insert(seq, ack_commitment); - Ok(()) - } - - fn delete_packet_acknowledgement( - &mut self, - port_id: &PortId, - channel_id: &ChannelId, - seq: Sequence, - ) -> Result<(), Ics04Error> { - self.ibc_store - .lock() - .unwrap() - .packet_acknowledgement - .get_mut(port_id) - .and_then(|map| map.get_mut(channel_id)) - .and_then(|map| map.remove(&seq)); - Ok(()) - } - - fn store_connection_channels( - &mut self, - cid: ConnectionId, - port_id: PortId, - channel_id: ChannelId, - ) -> Result<(), Ics04Error> { - self.ibc_store - .lock() - .unwrap() - .connection_channels - .entry(cid) - .or_insert_with(Vec::new) - .push((port_id, channel_id)); - Ok(()) - } - - fn store_channel( - &mut self, - port_id: PortId, - channel_id: ChannelId, - channel_end: ChannelEnd, - ) -> Result<(), Ics04Error> { - self.ibc_store - .lock() - .unwrap() - .channels - .entry(port_id) - .or_default() - .insert(channel_id, channel_end); - Ok(()) - } - - fn store_next_sequence_send( - &mut self, - port_id: PortId, - channel_id: ChannelId, - seq: Sequence, - ) -> Result<(), Ics04Error> { - self.ibc_store - .lock() - .unwrap() - .next_sequence_send - .entry(port_id) - .or_default() - .insert(channel_id, seq); - Ok(()) - } - - fn store_next_sequence_recv( - &mut self, - port_id: PortId, - channel_id: ChannelId, - seq: Sequence, - ) -> Result<(), Ics04Error> { - self.ibc_store - .lock() - .unwrap() - .next_sequence_recv - .entry(port_id) - .or_default() - .insert(channel_id, seq); - Ok(()) - } - - fn store_next_sequence_ack( - &mut self, - port_id: PortId, - channel_id: ChannelId, - seq: Sequence, - ) -> Result<(), Ics04Error> { - self.ibc_store - .lock() - .unwrap() - .next_sequence_ack - .entry(port_id) - .or_default() - .insert(channel_id, seq); - Ok(()) - } - - fn increase_channel_counter(&mut self) { - self.ibc_store.lock().unwrap().channel_ids_counter += 1; - } - - fn delete_packet_commitment( - &mut self, - port_id: &PortId, - channel_id: &ChannelId, - seq: Sequence, - ) -> Result<(), Ics04Error> { - self.ibc_store - .lock() - .unwrap() - .packet_commitment - .get_mut(port_id) - .and_then(|map| map.get_mut(channel_id)) - .and_then(|map| map.remove(&seq)); - Ok(()) - } - - fn store_packet_receipt( - &mut self, - port_id: PortId, - channel_id: ChannelId, - seq: Sequence, - receipt: Receipt, - ) -> Result<(), Ics04Error> { - self.ibc_store - .lock() - .unwrap() - .packet_receipt - .entry(port_id) - .or_default() - .entry(channel_id) - .or_default() - .insert(seq, receipt); - Ok(()) - } -} - -impl ConnectionReader for MockContext { - fn connection_end(&self, cid: &ConnectionId) -> Result { - match self.ibc_store.lock().unwrap().connections.get(cid) { - Some(connection_end) => Ok(connection_end.clone()), - None => Err(Ics03Error::connection_not_found(cid.clone())), - } - } - - fn client_state(&self, client_id: &ClientId) -> Result, Ics03Error> { - // Forward method call to the Ics2 Client-specific method. - ClientReader::client_state(self, client_id).map_err(Ics03Error::ics02_client) - } - - fn decode_client_state(&self, client_state: Any) -> Result, Ics03Error> { - ClientReader::decode_client_state(self, client_state).map_err(Ics03Error::ics02_client) - } - - fn host_current_height(&self) -> Height { - self.latest_height() - } - - fn host_oldest_height(&self) -> Height { - // history must be non-empty, so `self.history[0]` is valid - self.history[0].height() - } - - fn commitment_prefix(&self) -> CommitmentPrefix { - CommitmentPrefix::try_from(b"mock".to_vec()).unwrap() - } - - fn client_consensus_state( - &self, - client_id: &ClientId, - height: Height, - ) -> Result, Ics03Error> { - // Forward method call to the Ics2Client-specific method. - self.consensus_state(client_id, height) - .map_err(Ics03Error::ics02_client) - } - - fn host_consensus_state(&self, height: Height) -> Result, Ics03Error> { - ClientReader::host_consensus_state(self, height).map_err(Ics03Error::ics02_client) - } - - fn connection_counter(&self) -> Result { - Ok(self.ibc_store.lock().unwrap().connection_ids_counter) - } -} - -impl ConnectionKeeper for MockContext { - fn store_connection( - &mut self, - connection_id: ConnectionId, - connection_end: &ConnectionEnd, - ) -> Result<(), Ics03Error> { - self.ibc_store - .lock() - .unwrap() - .connections - .insert(connection_id, connection_end.clone()); - Ok(()) - } - - fn store_connection_to_client( - &mut self, - connection_id: ConnectionId, - client_id: &ClientId, - ) -> Result<(), Ics03Error> { - self.ibc_store - .lock() - .unwrap() - .client_connections - .insert(client_id.clone(), connection_id); - Ok(()) - } - - fn increase_connection_counter(&mut self) { - self.ibc_store.lock().unwrap().connection_ids_counter += 1; - } -} - -impl ClientReader for MockContext { - fn client_type(&self, client_id: &ClientId) -> Result { - match self.ibc_store.lock().unwrap().clients.get(client_id) { - Some(client_record) => Ok(client_record.client_type), - None => Err(Ics02Error::client_not_found(client_id.clone())), - } - } - - fn client_state(&self, client_id: &ClientId) -> Result, Ics02Error> { - match self.ibc_store.lock().unwrap().clients.get(client_id) { - Some(client_record) => client_record - .client_state - .clone() - .ok_or_else(|| Ics02Error::client_not_found(client_id.clone())), - None => Err(Ics02Error::client_not_found(client_id.clone())), - } - } - - fn decode_client_state(&self, client_state: Any) -> Result, Ics02Error> { - if let Ok(client_state) = TmClientState::try_from(client_state.clone()) { - Ok(client_state.into_box()) - } else if let Ok(client_state) = MockClientState::try_from(client_state.clone()) { - Ok(client_state.into_box()) - } else { - Err(Ics02Error::unknown_client_state_type(client_state.type_url)) - } - } - - fn consensus_state( - &self, - client_id: &ClientId, - height: Height, - ) -> Result, Ics02Error> { - match self.ibc_store.lock().unwrap().clients.get(client_id) { - Some(client_record) => match client_record.consensus_states.get(&height) { - Some(consensus_state) => Ok(consensus_state.clone()), - None => Err(Ics02Error::consensus_state_not_found( - client_id.clone(), - height, - )), - }, - None => Err(Ics02Error::consensus_state_not_found( - client_id.clone(), - height, - )), - } - } - - /// Search for the lowest consensus state higher than `height`. - fn next_consensus_state( - &self, - client_id: &ClientId, - height: Height, - ) -> Result>, Ics02Error> { - let ibc_store = self.ibc_store.lock().unwrap(); - let client_record = ibc_store - .clients - .get(client_id) - .ok_or_else(|| Ics02Error::client_not_found(client_id.clone()))?; - - // Get the consensus state heights and sort them in ascending order. - let mut heights: Vec = client_record.consensus_states.keys().cloned().collect(); - heights.sort(); - - // Search for next state. - for h in heights { - if h > height { - // unwrap should never happen, as the consensus state for h must exist - return Ok(Some( - client_record.consensus_states.get(&h).unwrap().clone(), - )); - } - } - Ok(None) - } - - /// Search for the highest consensus state lower than `height`. - fn prev_consensus_state( - &self, - client_id: &ClientId, - height: Height, - ) -> Result>, Ics02Error> { - let ibc_store = self.ibc_store.lock().unwrap(); - let client_record = ibc_store - .clients - .get(client_id) - .ok_or_else(|| Ics02Error::client_not_found(client_id.clone()))?; - - // Get the consensus state heights and sort them in descending order. - let mut heights: Vec = client_record.consensus_states.keys().cloned().collect(); - heights.sort_by(|a, b| b.cmp(a)); - - // Search for previous state. - for h in heights { - if h < height { - // unwrap should never happen, as the consensus state for h must exist - return Ok(Some( - client_record.consensus_states.get(&h).unwrap().clone(), - )); - } - } - Ok(None) - } - - fn host_height(&self) -> Height { - self.latest_height() - } - - fn host_timestamp(&self) -> Timestamp { - self.history - .last() - .expect("history cannot be empty") - .timestamp() - .add(self.block_time) - .unwrap() - } - - fn host_consensus_state(&self, height: Height) -> Result, Ics02Error> { - match self.host_block(height) { - Some(block_ref) => Ok(block_ref.clone().into()), - None => Err(Ics02Error::missing_local_consensus_state(height)), - } - } - - fn pending_host_consensus_state(&self) -> Result, Ics02Error> { - Err(Ics02Error::implementation_specific()) - } - - fn client_counter(&self) -> Result { - Ok(self.ibc_store.lock().unwrap().client_ids_counter) - } -} - -impl ClientKeeper for MockContext { - fn store_client_type( - &mut self, - client_id: ClientId, - client_type: ClientType, - ) -> Result<(), Ics02Error> { - let mut ibc_store = self.ibc_store.lock().unwrap(); - let client_record = ibc_store - .clients - .entry(client_id) - .or_insert(MockClientRecord { - client_type, - consensus_states: Default::default(), - client_state: Default::default(), - }); - - client_record.client_type = client_type; - Ok(()) - } - - fn store_client_state( - &mut self, - client_id: ClientId, - client_state: Box, - ) -> Result<(), Ics02Error> { - let mut ibc_store = self.ibc_store.lock().unwrap(); - let client_record = ibc_store - .clients - .entry(client_id) - .or_insert(MockClientRecord { - client_type: client_state.client_type(), - consensus_states: Default::default(), - client_state: Default::default(), - }); - - client_record.client_state = Some(client_state); - Ok(()) - } - - fn store_consensus_state( - &mut self, - client_id: ClientId, - height: Height, - consensus_state: Box, - ) -> Result<(), Ics02Error> { - let mut ibc_store = self.ibc_store.lock().unwrap(); - let client_record = ibc_store - .clients - .entry(client_id) - .or_insert(MockClientRecord { - client_type: ClientType::Mock, - consensus_states: Default::default(), - client_state: Default::default(), - }); - - client_record - .consensus_states - .insert(height, consensus_state); - Ok(()) - } - - fn increase_client_counter(&mut self) { - self.ibc_store.lock().unwrap().client_ids_counter += 1 - } - - fn store_update_time( - &mut self, - client_id: ClientId, - height: Height, - timestamp: Timestamp, - ) -> Result<(), Ics02Error> { - let _ = self - .ibc_store - .lock() - .unwrap() - .client_processed_times - .insert((client_id, height), timestamp); - Ok(()) - } - - fn store_update_height( - &mut self, - client_id: ClientId, - height: Height, - host_height: Height, - ) -> Result<(), Ics02Error> { - let _ = self - .ibc_store - .lock() - .unwrap() - .client_processed_heights - .insert((client_id, height), host_height); - Ok(()) - } -} - -impl Ics18Context for MockContext { - fn query_latest_height(&self) -> Height { - self.host_current_height() - } - - fn query_client_full_state(&self, client_id: &ClientId) -> Option> { - // Forward call to Ics2. - ClientReader::client_state(self, client_id).ok() - } - - fn query_latest_header(&self) -> Option> { - let block_ref = self.host_block(self.host_current_height()); - block_ref.cloned().map(Header::into_box) - } - - fn send(&mut self, msgs: Vec) -> Result, Ics18Error> { - // Forward call to Ics26 delivery method. - let mut all_events = vec![]; - for msg in msgs { - let MsgReceipt { mut events, .. } = - deliver(self, msg).map_err(Ics18Error::transaction_failed)?; - all_events.append(&mut events); - } - self.advance_host_chain_height(); // Advance chain height - Ok(all_events) - } - - fn signer(&self) -> Signer { - "0CDA3F47EF3C4906693B170EF650EB968C5F4B2C".parse().unwrap() - } -} - -#[cfg(test)] -mod tests { - use test_log::test; - - use alloc::str::FromStr; - - use crate::core::ics04_channel::channel::{Counterparty, Order}; - use crate::core::ics04_channel::error::Error; - use crate::core::ics04_channel::packet::Packet; - use crate::core::ics04_channel::Version; - use crate::core::ics24_host::identifier::ChainId; - use crate::core::ics24_host::identifier::{ChannelId, ConnectionId, PortId}; - use crate::core::ics26_routing::context::{ - Acknowledgement, Module, ModuleId, ModuleOutputBuilder, OnRecvPacketAck, Router, - RouterBuilder, - }; - use crate::mock::context::MockContext; - use crate::mock::context::MockRouterBuilder; - use crate::mock::host::HostType; - use crate::prelude::*; - use crate::signer::Signer; - use crate::test_utils::get_dummy_bech32_account; - use crate::Height; - - #[test] - fn test_history_manipulation() { - pub struct Test { - name: String, - ctx: MockContext, - } - let cv = 1; // The version to use for all chains. - - let tests: Vec = vec![ - Test { - name: "Empty history, small pruning window".to_string(), - ctx: MockContext::new( - ChainId::new("mockgaia".to_string(), cv), - HostType::Mock, - 2, - Height::new(cv, 1).unwrap(), - ), - }, - Test { - name: "[Synthetic TM host] Empty history, small pruning window".to_string(), - ctx: MockContext::new( - ChainId::new("mocksgaia".to_string(), cv), - HostType::SyntheticTendermint, - 2, - Height::new(cv, 1).unwrap(), - ), - }, - Test { - name: "Large pruning window".to_string(), - ctx: MockContext::new( - ChainId::new("mockgaia".to_string(), cv), - HostType::Mock, - 30, - Height::new(cv, 2).unwrap(), - ), - }, - Test { - name: "[Synthetic TM host] Large pruning window".to_string(), - ctx: MockContext::new( - ChainId::new("mocksgaia".to_string(), cv), - HostType::SyntheticTendermint, - 30, - Height::new(cv, 2).unwrap(), - ), - }, - Test { - name: "Small pruning window".to_string(), - ctx: MockContext::new( - ChainId::new("mockgaia".to_string(), cv), - HostType::Mock, - 3, - Height::new(cv, 30).unwrap(), - ), - }, - Test { - name: "[Synthetic TM host] Small pruning window".to_string(), - ctx: MockContext::new( - ChainId::new("mockgaia".to_string(), cv), - HostType::SyntheticTendermint, - 3, - Height::new(cv, 30).unwrap(), - ), - }, - Test { - name: "Small pruning window, small starting height".to_string(), - ctx: MockContext::new( - ChainId::new("mockgaia".to_string(), cv), - HostType::Mock, - 3, - Height::new(cv, 2).unwrap(), - ), - }, - Test { - name: "[Synthetic TM host] Small pruning window, small starting height".to_string(), - ctx: MockContext::new( - ChainId::new("mockgaia".to_string(), cv), - HostType::SyntheticTendermint, - 3, - Height::new(cv, 2).unwrap(), - ), - }, - Test { - name: "Large pruning window, large starting height".to_string(), - ctx: MockContext::new( - ChainId::new("mockgaia".to_string(), cv), - HostType::Mock, - 50, - Height::new(cv, 2000).unwrap(), - ), - }, - Test { - name: "[Synthetic TM host] Large pruning window, large starting height".to_string(), - ctx: MockContext::new( - ChainId::new("mockgaia".to_string(), cv), - HostType::SyntheticTendermint, - 50, - Height::new(cv, 2000).unwrap(), - ), - }, - ]; - - for mut test in tests { - // All tests should yield a valid context after initialization. - assert!( - test.ctx.validate().is_ok(), - "failed in test {} while validating context {:?}", - test.name, - test.ctx - ); - - let current_height = test.ctx.latest_height(); - - // After advancing the chain's height, the context should still be valid. - test.ctx.advance_host_chain_height(); - assert!( - test.ctx.validate().is_ok(), - "failed in test {} while validating context {:?}", - test.name, - test.ctx - ); - - let next_height = current_height.increment(); - assert_eq!( - test.ctx.latest_height(), - next_height, - "failed while increasing height for context {:?}", - test.ctx - ); - - assert_eq!( - test.ctx.host_block(current_height).unwrap().height(), - current_height, - "failed while fetching height {:?} of context {:?}", - current_height, - test.ctx - ); - } - } - - #[test] - fn test_router() { - #[derive(Default)] - struct MockAck(Vec); - - impl AsRef<[u8]> for MockAck { - fn as_ref(&self) -> &[u8] { - self.0.as_slice() - } - } - - impl Acknowledgement for MockAck {} - - #[derive(Debug, Default)] - struct FooModule { - counter: usize, - } - - impl Module for FooModule { - fn on_chan_open_try( - &mut self, - _output: &mut ModuleOutputBuilder, - _order: Order, - _connection_hops: &[ConnectionId], - _port_id: &PortId, - _channel_id: &ChannelId, - _counterparty: &Counterparty, - _version: &Version, - counterparty_version: &Version, - ) -> Result { - Ok(counterparty_version.clone()) - } - - fn on_recv_packet( - &self, - _output: &mut ModuleOutputBuilder, - _packet: &Packet, - _relayer: &Signer, - ) -> OnRecvPacketAck { - OnRecvPacketAck::Successful( - Box::new(MockAck::default()), - Box::new(|module| { - let module = module.downcast_mut::().unwrap(); - module.counter += 1; - Ok(()) - }), - ) - } - } - - #[derive(Debug, Default)] - struct BarModule; - - impl Module for BarModule { - fn on_chan_open_try( - &mut self, - _output: &mut ModuleOutputBuilder, - _order: Order, - _connection_hops: &[ConnectionId], - _port_id: &PortId, - _channel_id: &ChannelId, - _counterparty: &Counterparty, - _version: &Version, - counterparty_version: &Version, - ) -> Result { - Ok(counterparty_version.clone()) - } - } - - let r = MockRouterBuilder::default() - .add_route("foomodule".parse().unwrap(), FooModule::default()) - .unwrap() - .add_route("barmodule".parse().unwrap(), BarModule::default()) - .unwrap() - .build(); - - let mut ctx = MockContext::new( - ChainId::new("mockgaia".to_string(), 1), - HostType::Mock, - 1, - Height::new(1, 1).unwrap(), - ) - .with_router(r); - - let mut on_recv_packet_result = |module_id: &'static str| { - let module_id = ModuleId::from_str(module_id).unwrap(); - let m = ctx.router.get_route_mut(&module_id).unwrap(); - let result = m.on_recv_packet( - &mut ModuleOutputBuilder::new(), - &Packet::default(), - &get_dummy_bech32_account().parse().unwrap(), - ); - (module_id, result) - }; - - let results = vec![ - on_recv_packet_result("foomodule"), - on_recv_packet_result("barmodule"), - ]; - results - .into_iter() - .filter_map(|(mid, result)| match result { - OnRecvPacketAck::Nil(write_fn) | OnRecvPacketAck::Successful(_, write_fn) => { - Some((mid, write_fn)) - } - _ => None, - }) - .for_each(|(mid, write_fn)| { - write_fn(ctx.router.get_route_mut(&mid).unwrap().as_any_mut()).unwrap() - }); - } -} diff --git a/modules/src/mock/header.rs b/modules/src/mock/header.rs deleted file mode 100644 index 570b11fe22..0000000000 --- a/modules/src/mock/header.rs +++ /dev/null @@ -1,142 +0,0 @@ -use alloc::string::ToString; -use core::fmt::{Display, Error as FmtError, Formatter}; - -use ibc_proto::google::protobuf::Any; -use ibc_proto::ibc::mock::Header as RawMockHeader; -use ibc_proto::protobuf::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) - .expect("encoding to `Any` from `TmHeader`"), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use ibc_proto::protobuf::Protobuf; - - #[test] - fn encode_any() { - let header = MockHeader::new(Height::new(1, 10).unwrap()).with_timestamp(Timestamp::none()); - let bytes = >::encode_vec(&header).unwrap(); - - assert_eq!( - &bytes, - &[ - 10, 16, 47, 105, 98, 99, 46, 109, 111, 99, 107, 46, 72, 101, 97, 100, 101, 114, 18, - 6, 10, 4, 8, 1, 16, 10 - ] - ); - } -} diff --git a/modules/src/mock/host.rs b/modules/src/mock/host.rs deleted file mode 100644 index 4fd6d95957..0000000000 --- a/modules/src/mock/host.rs +++ /dev/null @@ -1,192 +0,0 @@ -//! Host chain types and methods, used by context mock. - -use ibc_proto::google::protobuf::Any; -use ibc_proto::ibc::lightclients::tendermint::v1::Header as RawHeader; -use ibc_proto::protobuf::Protobuf as ErasedProtobuf; -use serde::Serialize; -use tendermint::block::Header as TmHeader; -use tendermint_testgen::light_block::TmLightBlock; -use tendermint_testgen::{Generator, LightBlock as TestgenLightBlock}; - -use crate::clients::ics07_tendermint::consensus_state::ConsensusState as TMConsensusState; -use crate::clients::ics07_tendermint::header::TENDERMINT_HEADER_TYPE_URL; -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::ics02_client::header::Header; -use crate::core::ics24_host::identifier::ChainId; -use crate::mock::consensus_state::MockConsensusState; -use crate::mock::header::MockHeader; -use crate::prelude::*; -use crate::timestamp::Timestamp; -use crate::Height; - -/// Defines the different types of host chains that a mock context can emulate. -/// The variants are as follows: -/// - `Mock` defines that the context history consists of `MockHeader` blocks. -/// - `SyntheticTendermint`: the context has synthetically-generated Tendermint (light) blocks. -/// See also the `HostBlock` enum to get more insights into the underlying block type. -#[derive(Clone, Debug, Copy)] -pub enum HostType { - Mock, - SyntheticTendermint, -} - -#[derive(Clone, Debug, PartialEq, Serialize)] -pub struct SyntheticTmBlock { - pub trusted_height: Height, - pub light_block: TmLightBlock, -} - -impl SyntheticTmBlock { - pub fn header(&self) -> &TmHeader { - &self.light_block.signed_header.header - } -} - -/// Depending on `HostType` (the type of host chain underlying a context mock), this enum defines -/// the type of blocks composing the history of the host chain. -#[derive(Clone, Debug, PartialEq, Serialize)] -pub enum HostBlock { - Mock(MockHeader), - SyntheticTendermint(SyntheticTmBlock), -} - -impl HostBlock { - /// Returns the height of a block. - pub fn height(&self) -> Height { - match self { - HostBlock::Mock(header) => header.height(), - HostBlock::SyntheticTendermint(light_block) => Height::new( - ChainId::chain_version(light_block.header().chain_id.as_str()), - light_block.header().height.value(), - ) - .unwrap(), - } - } - - pub fn set_trusted_height(&mut self, height: Height) { - match self { - HostBlock::Mock(_) => {} - HostBlock::SyntheticTendermint(light_block) => light_block.trusted_height = height, - } - } - - /// Returns the timestamp of a block. - pub fn timestamp(&self) -> Timestamp { - match self { - HostBlock::Mock(header) => header.timestamp, - HostBlock::SyntheticTendermint(light_block) => light_block.header().time.into(), - } - } - - /// Generates a new block at `height` for the given chain identifier and chain type. - pub fn generate_block( - chain_id: ChainId, - chain_type: HostType, - height: u64, - timestamp: Timestamp, - ) -> HostBlock { - match chain_type { - HostType::Mock => HostBlock::Mock(MockHeader { - height: Height::new(chain_id.version(), height).unwrap(), - timestamp, - }), - HostType::SyntheticTendermint => { - HostBlock::SyntheticTendermint(Self::generate_tm_block(chain_id, height, timestamp)) - } - } - } - - pub fn generate_tm_block( - chain_id: ChainId, - height: u64, - timestamp: Timestamp, - ) -> SyntheticTmBlock { - let light_block = TestgenLightBlock::new_default_with_time_and_chain_id( - chain_id.to_string(), - timestamp.into_tm_time().unwrap(), - height, - ) - .generate() - .unwrap(); - SyntheticTmBlock { - trusted_height: Height::new(chain_id.version(), 1).unwrap(), - light_block, - } - } -} - -impl From for Box { - fn from(light_block: SyntheticTmBlock) -> Self { - let cs = TMConsensusState::from(light_block.header().clone()); - cs.into_box() - } -} - -impl From for Box { - fn from(any_block: HostBlock) -> Self { - match any_block { - HostBlock::Mock(mock_header) => MockConsensusState::new(mock_header).into_box(), - HostBlock::SyntheticTendermint(light_block) => { - TMConsensusState::from(light_block.header().clone()).into_box() - } - } - } -} - -impl ErasedProtobuf for HostBlock {} - -impl TryFrom for HostBlock { - type Error = Error; - - fn try_from(_raw: Any) -> Result { - todo!() - } -} - -impl From for Any { - fn from(value: HostBlock) -> Self { - fn encode_light_block(light_block: SyntheticTmBlock) -> Vec { - use prost::Message; - - let SyntheticTmBlock { - trusted_height, - light_block, - } = light_block; - - RawHeader { - signed_header: Some(light_block.signed_header.into()), - validator_set: Some(light_block.validators.into()), - trusted_height: Some(trusted_height.into()), - trusted_validators: Some(light_block.next_validators.into()), - } - .encode_to_vec() - } - - match value { - HostBlock::Mock(mock_header) => mock_header.into(), - HostBlock::SyntheticTendermint(light_block_box) => Self { - type_url: TENDERMINT_HEADER_TYPE_URL.to_string(), - value: encode_light_block(light_block_box), - }, - } - } -} - -impl Header for HostBlock { - fn client_type(&self) -> ClientType { - match self { - HostBlock::Mock(_) => ClientType::Mock, - HostBlock::SyntheticTendermint(_) => ClientType::Tendermint, - } - } - - fn height(&self) -> Height { - HostBlock::height(self) - } - - fn timestamp(&self) -> Timestamp { - HostBlock::timestamp(self) - } -} diff --git a/modules/src/mock/misbehaviour.rs b/modules/src/mock/misbehaviour.rs deleted file mode 100644 index e75cdb3e10..0000000000 --- a/modules/src/mock/misbehaviour.rs +++ /dev/null @@ -1,59 +0,0 @@ -use crate::prelude::*; - -use ibc_proto::ibc::mock::Misbehaviour as RawMisbehaviour; -use ibc_proto::protobuf::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/modules/src/mock/mod.rs b/modules/src/mock/mod.rs deleted file mode 100644 index 8ac0c3bcbf..0000000000 --- a/modules/src/mock/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -//! Implementation of mocks for context, host chain, and client. - -pub mod client_state; -pub mod consensus_state; -pub mod context; -pub mod header; -pub mod host; -pub mod misbehaviour; diff --git a/modules/src/prelude.rs b/modules/src/prelude.rs deleted file mode 100644 index bdce26208e..0000000000 --- a/modules/src/prelude.rs +++ /dev/null @@ -1,15 +0,0 @@ -pub use core::prelude::v1::*; - -// Re-export according to alloc::prelude::v1 because it is not yet stabilized -// https://doc.rust-lang.org/src/alloc/prelude/v1.rs.html -pub use alloc::borrow::ToOwned; -pub use alloc::boxed::Box; -pub use alloc::string::{String, ToString}; -pub use alloc::vec::Vec; - -pub use alloc::format; -pub use alloc::vec; - -// Those are exported by default in the std prelude in Rust 2021 -pub use core::convert::{TryFrom, TryInto}; -pub use core::iter::FromIterator; diff --git a/modules/src/proofs.rs b/modules/src/proofs.rs deleted file mode 100644 index dead167490..0000000000 --- a/modules/src/proofs.rs +++ /dev/null @@ -1,103 +0,0 @@ -use serde::Serialize; - -use crate::core::ics23_commitment::commitment::CommitmentProofBytes; -use crate::Height; -use flex_error::define_error; - -define_error! { - #[derive(Debug, PartialEq, Eq)] - ProofError { - ZeroHeight - | _ | { format_args!("proof height cannot be zero") }, - EmptyProof - | _ | { format_args!("proof cannot be empty") }, - } -} - -/// Structure comprising proofs in a message. Proofs are typically present in messages for -/// handshake protocols, e.g., ICS3 connection (open) handshake or ICS4 channel (open and close) -/// handshake, as well as for ICS4 packets, timeouts, and acknowledgements. -#[derive(Clone, Debug, PartialEq, Eq, Serialize)] -pub struct Proofs { - object_proof: CommitmentProofBytes, - client_proof: Option, - consensus_proof: Option, - /// Currently used for proof_close for MsgTimeoutOnCLose where object_proof is proof_unreceived - other_proof: Option, - /// Height for the commitment root for proving the proofs above. - /// When creating these proofs, the chain is queried at `height-1`. - height: Height, -} - -impl Proofs { - pub fn new( - object_proof: CommitmentProofBytes, - client_proof: Option, - consensus_proof: Option, - other_proof: Option, - height: Height, - ) -> Result { - Ok(Self { - object_proof, - client_proof, - consensus_proof, - other_proof, - height, - }) - } - - /// Getter for the consensus_proof field of this proof. Intuitively, this is a proof that a - /// client on the source chain stores a consensus state for the destination chain. - pub fn consensus_proof(&self) -> Option { - self.consensus_proof.clone() - } - - /// Getter for the height field of this proof (i.e., the consensus height where this proof was - /// created). - pub fn height(&self) -> Height { - self.height - } - - /// Getter for the object-specific proof (e.g., proof for connection state or channel state). - pub fn object_proof(&self) -> &CommitmentProofBytes { - &self.object_proof - } - - /// Getter for the client_proof. - pub fn client_proof(&self) -> &Option { - &self.client_proof - } - - /// Getter for the other_proof. - pub fn other_proof(&self) -> &Option { - &self.other_proof - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize)] -pub struct ConsensusProof { - proof: CommitmentProofBytes, - height: Height, -} - -impl ConsensusProof { - pub fn new( - consensus_proof: CommitmentProofBytes, - consensus_height: Height, - ) -> Result { - Ok(Self { - proof: consensus_proof, - height: consensus_height, - }) - } - - /// Getter for the height field of this consensus proof. - pub fn height(&self) -> Height { - self.height - } - - /// Getter for the proof (CommitmentProof) field of this consensus proof. - pub fn proof(&self) -> &CommitmentProofBytes { - &self.proof - } -} diff --git a/modules/src/relayer/ics18_relayer/context.rs b/modules/src/relayer/ics18_relayer/context.rs deleted file mode 100644 index 50b4bc643e..0000000000 --- a/modules/src/relayer/ics18_relayer/context.rs +++ /dev/null @@ -1,35 +0,0 @@ -use crate::prelude::*; -use ibc_proto::google::protobuf::Any; - -use crate::core::ics02_client::client_state::ClientState; -use crate::core::ics02_client::header::Header; -use crate::events::IbcEvent; - -use crate::core::ics24_host::identifier::ClientId; -use crate::relayer::ics18_relayer::error::Error; -use crate::signer::Signer; -use crate::Height; - -/// Trait capturing all dependencies (i.e., the context) which algorithms in ICS18 require to -/// relay packets between chains. This trait comprises the dependencies towards a single chain. -/// Most of the functions in this represent wrappers over the ABCI interface. -/// This trait mimics the `Chain` trait, but at a lower level of abstraction (no networking, header -/// types, light client, RPC client, etc.) -pub trait Ics18Context { - /// Returns the latest height of the chain. - fn query_latest_height(&self) -> Height; - - /// Returns this client state for the given `client_id` on this chain. - /// Wrapper over the `/abci_query?path=..` endpoint. - fn query_client_full_state(&self, client_id: &ClientId) -> Option>; - - /// Returns the most advanced header of this chain. - fn query_latest_header(&self) -> Option>; - - /// Interface that the relayer uses to submit a datagram to this chain. - /// One can think of this as wrapping around the `/broadcast_tx_commit` ABCI endpoint. - fn send(&mut self, msgs: Vec) -> Result, Error>; - - /// Temporary solution. Similar to `CosmosSDKChain::key_and_signer()` but simpler. - fn signer(&self) -> Signer; -} diff --git a/modules/src/relayer/ics18_relayer/error.rs b/modules/src/relayer/ics18_relayer/error.rs deleted file mode 100644 index e975de5a3a..0000000000 --- a/modules/src/relayer/ics18_relayer/error.rs +++ /dev/null @@ -1,38 +0,0 @@ -use crate::core::ics24_host::identifier::ClientId; -use crate::core::ics26_routing::error::Error as RoutingError; -use crate::Height; -use flex_error::define_error; - -define_error! { - Error { - ClientStateNotFound - { client_id: ClientId } - | e | { format_args!("client state on destination chain not found, (client id: {0})", e.client_id) }, - - ClientAlreadyUpToDate - { - client_id: ClientId, - source_height: Height, - destination_height: Height, - } - | e | { - format_args!("the client on destination chain is already up-to-date (client id: {0}, source height: {1}, dest height: {2})", - e.client_id, e.source_height, e.destination_height) - }, - - ClientAtHigherHeight - { - client_id: ClientId, - source_height: Height, - destination_height: Height, - } - | e | { - format_args!("the client on destination chain is at a higher height (client id: {0}, source height: {1}, dest height: {2})", - e.client_id, e.source_height, e.destination_height) - }, - - TransactionFailed - [ RoutingError ] - | _ | { "transaction processing by modules failed" }, - } -} diff --git a/modules/src/relayer/ics18_relayer/mod.rs b/modules/src/relayer/ics18_relayer/mod.rs deleted file mode 100644 index 254c69aa4e..0000000000 --- a/modules/src/relayer/ics18_relayer/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -//! ICS 18: Relayer contains utilities for testing `ibc` against the Hermes relayer. - -pub mod context; -pub mod error; -pub mod utils; diff --git a/modules/src/relayer/ics18_relayer/utils.rs b/modules/src/relayer/ics18_relayer/utils.rs deleted file mode 100644 index f626627be2..0000000000 --- a/modules/src/relayer/ics18_relayer/utils.rs +++ /dev/null @@ -1,211 +0,0 @@ -use crate::core::ics02_client::header::Header; -use crate::core::ics02_client::msgs::update_client::MsgUpdateClient; -use crate::core::ics02_client::msgs::ClientMsg; -use crate::core::ics24_host::identifier::ClientId; -use crate::relayer::ics18_relayer::context::Ics18Context; -use crate::relayer::ics18_relayer::error::Error; - -/// Builds a `ClientMsg::UpdateClient` for a client with id `client_id` running on the `dest` -/// context, assuming that the latest header on the source context is `src_header`. -pub fn build_client_update_datagram( - dest: &Ctx, - client_id: &ClientId, - src_header: &dyn Header, -) -> Result -where - Ctx: Ics18Context, -{ - // Check if client for ibc0 on ibc1 has been updated to latest height: - // - query client state on destination chain - let dest_client_state = dest - .query_client_full_state(client_id) - .ok_or_else(|| Error::client_state_not_found(client_id.clone()))?; - - let dest_client_latest_height = dest_client_state.latest_height(); - - if src_header.height() == dest_client_latest_height { - return Err(Error::client_already_up_to_date( - client_id.clone(), - src_header.height(), - dest_client_latest_height, - )); - }; - - if dest_client_latest_height > src_header.height() { - return Err(Error::client_at_higher_height( - client_id.clone(), - src_header.height(), - dest_client_latest_height, - )); - }; - - // Client on destination chain can be updated. - Ok(ClientMsg::UpdateClient(MsgUpdateClient { - client_id: client_id.clone(), - header: src_header.clone_into(), - signer: dest.signer(), - })) -} - -#[cfg(test)] -mod tests { - use crate::core::ics02_client::client_type::ClientType; - use crate::core::ics02_client::header::{downcast_header, Header}; - use crate::core::ics24_host::identifier::{ChainId, ClientId}; - use crate::core::ics26_routing::msgs::Ics26Envelope; - use crate::mock::context::MockContext; - use crate::mock::host::{HostBlock, HostType}; - use crate::prelude::*; - use crate::relayer::ics18_relayer::context::Ics18Context; - use crate::relayer::ics18_relayer::utils::build_client_update_datagram; - use crate::Height; - - use test_log::test; - use tracing::debug; - - #[test] - /// Serves to test both ICS 26 `dispatch` & `build_client_update_datagram` functions. - /// Implements a "ping pong" of client update messages, so that two chains repeatedly - /// process a client update message and update their height in succession. - fn client_update_ping_pong() { - let chain_a_start_height = Height::new(1, 11).unwrap(); - let chain_b_start_height = Height::new(1, 20).unwrap(); - let client_on_b_for_a_height = Height::new(1, 10).unwrap(); // Should be smaller than `chain_a_start_height` - let client_on_a_for_b_height = Height::new(1, 20).unwrap(); // Should be smaller than `chain_b_start_height` - let num_iterations = 4; - - let client_on_a_for_b = ClientId::new(ClientType::Tendermint, 0).unwrap(); - let client_on_b_for_a = ClientId::new(ClientType::Mock, 0).unwrap(); - - // Create two mock contexts, one for each chain. - let mut ctx_a = MockContext::new( - ChainId::new("mockgaiaA".to_string(), 1), - HostType::Mock, - 5, - chain_a_start_height, - ) - .with_client_parametrized( - &client_on_a_for_b, - client_on_a_for_b_height, - Some(ClientType::Tendermint), // The target host chain (B) is synthetic TM. - Some(client_on_a_for_b_height), - ); - let mut ctx_b = MockContext::new( - ChainId::new("mockgaiaB".to_string(), 1), - HostType::SyntheticTendermint, - 5, - chain_b_start_height, - ) - .with_client_parametrized( - &client_on_b_for_a, - client_on_b_for_a_height, - Some(ClientType::Mock), // The target host chain is mock. - Some(client_on_b_for_a_height), - ); - - for _i in 0..num_iterations { - // Update client on chain B to latest height of A. - // - create the client update message with the latest header from A - let a_latest_header = ctx_a.query_latest_header().unwrap(); - assert_eq!( - a_latest_header.client_type(), - ClientType::Mock, - "Client type verification in header failed for context A (Mock); got {:?} but expected {:?}", - a_latest_header.client_type(), - ClientType::Mock - ); - - let client_msg_b_res = - build_client_update_datagram(&ctx_b, &client_on_b_for_a, a_latest_header.as_ref()); - - assert!( - client_msg_b_res.is_ok(), - "create_client_update failed for context destination {:?}, error: {:?}", - ctx_b, - client_msg_b_res - ); - - let client_msg_b = client_msg_b_res.unwrap(); - - // - send the message to B. We bypass ICS18 interface and call directly into - // MockContext `recv` method (to avoid additional serialization steps). - let dispatch_res_b = ctx_b.deliver(Ics26Envelope::Ics2Msg(client_msg_b)); - let validation_res = ctx_b.validate(); - assert!( - validation_res.is_ok(), - "context validation failed with error {:?} for context {:?}", - validation_res, - ctx_b - ); - - // Check if the update succeeded. - assert!( - dispatch_res_b.is_ok(), - "Dispatch failed for host chain b with error: {:?}", - dispatch_res_b - ); - let client_height_b = ctx_b - .query_client_full_state(&client_on_b_for_a) - .unwrap() - .latest_height(); - assert_eq!(client_height_b, ctx_a.query_latest_height()); - - // Update client on chain B to latest height of B. - // - create the client update message with the latest header from B - // The test uses LightClientBlock that does not store the trusted height - let b_latest_header = ctx_b.query_latest_header().unwrap(); - let b_latest_header: &HostBlock = downcast_header(b_latest_header.as_ref()).unwrap(); - let mut b_latest_header = b_latest_header.clone(); - - let th = b_latest_header.height(); - b_latest_header.set_trusted_height(th.decrement().unwrap()); - - assert_eq!( - b_latest_header.client_type(), - ClientType::Tendermint, - "Client type verification in header failed for context B (TM); got {:?} but expected {:?}", - b_latest_header.client_type(), - ClientType::Tendermint - ); - - let client_msg_a_res = build_client_update_datagram( - &ctx_a, - &client_on_a_for_b, - b_latest_header.into_box().as_ref(), - ); - - assert!( - client_msg_a_res.is_ok(), - "create_client_update failed for context destination {:?}, error: {:?}", - ctx_a, - client_msg_a_res - ); - - let client_msg_a = client_msg_a_res.unwrap(); - - debug!("client_msg_a = {:?}", client_msg_a); - - // - send the message to A - let dispatch_res_a = ctx_a.deliver(Ics26Envelope::Ics2Msg(client_msg_a)); - let validation_res = ctx_a.validate(); - assert!( - validation_res.is_ok(), - "context validation failed with error {:?} for context {:?}", - validation_res, - ctx_a - ); - - // Check if the update succeeded. - assert!( - dispatch_res_a.is_ok(), - "Dispatch failed for host chain a with error: {:?}", - dispatch_res_a - ); - let client_height_a = ctx_a - .query_client_full_state(&client_on_a_for_b) - .unwrap() - .latest_height(); - assert_eq!(client_height_a, ctx_b.query_latest_height()); - } - } -} diff --git a/modules/src/relayer/mod.rs b/modules/src/relayer/mod.rs deleted file mode 100644 index e88996bcd5..0000000000 --- a/modules/src/relayer/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -//! Utilities for testing the `ibc` crate against the [Hermes IBC relayer][relayer-repo]. -//! -//! [relayer-repo]: https://github.com/informalsystems/ibc-rs/tree/master/relayer - -pub mod ics18_relayer; diff --git a/modules/src/serializers.rs b/modules/src/serializers.rs deleted file mode 100644 index bd6f346336..0000000000 --- a/modules/src/serializers.rs +++ /dev/null @@ -1,38 +0,0 @@ -use serde::ser::{Serialize, Serializer}; -use subtle_encoding::{Encoding, Hex}; - -pub fn ser_hex_upper(data: T, serializer: S) -> Result -where - S: Serializer, - T: AsRef<[u8]>, -{ - let hex = Hex::upper_case().encode_to_string(data).unwrap(); - hex.serialize(serializer) -} - -pub mod serde_string { - use alloc::string::String; - use core::fmt::Display; - use core::str::FromStr; - - use serde::{de, Deserialize, Deserializer, Serializer}; - - pub fn serialize(value: &T, serializer: S) -> Result - where - T: Display, - S: Serializer, - { - serializer.collect_str(value) - } - - pub fn deserialize<'de, T, D>(deserializer: D) -> Result - where - T: FromStr, - T::Err: Display, - D: Deserializer<'de>, - { - String::deserialize(deserializer)? - .parse() - .map_err(de::Error::custom) - } -} diff --git a/modules/src/signer.rs b/modules/src/signer.rs deleted file mode 100644 index 21c62bf116..0000000000 --- a/modules/src/signer.rs +++ /dev/null @@ -1,36 +0,0 @@ -use core::str::FromStr; - -use crate::prelude::*; - -use derive_more::Display; -use flex_error::define_error; -use serde::{Deserialize, Serialize}; - -define_error! { - #[derive(Debug, PartialEq, Eq)] - SignerError { - EmptySigner - | _ | { "signer cannot be empty" }, - } -} - -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, Display)] -pub struct Signer(String); - -impl FromStr for Signer { - type Err = SignerError; - - fn from_str(s: &str) -> Result { - let s = s.to_string(); - if s.trim().is_empty() { - return Err(SignerError::empty_signer()); - } - Ok(Self(s)) - } -} - -impl AsRef for Signer { - fn as_ref(&self) -> &str { - self.0.as_str() - } -} diff --git a/modules/src/test.rs b/modules/src/test.rs deleted file mode 100644 index b6a9cb1f34..0000000000 --- a/modules/src/test.rs +++ /dev/null @@ -1,27 +0,0 @@ -use core::fmt::Debug; -use serde::{de::DeserializeOwned, Serialize}; - -/// Test that a struct `T` can be: -/// -/// - parsed out of the provided JSON data -/// - serialized back to JSON -/// - parsed back from the serialized JSON of the previous step -/// - that the two parsed structs are equal according to their `PartialEq` impl -pub fn test_serialization_roundtrip(json_data: &str) -where - T: Debug + Serialize + DeserializeOwned, -{ - let parsed0 = serde_json::from_str::(json_data); - assert!(parsed0.is_ok()); - let parsed0 = parsed0.unwrap(); - - let serialized = serde_json::to_string(&parsed0); - assert!(serialized.is_ok()); - let serialized = serialized.unwrap(); - - let parsed1 = serde_json::from_str::(&serialized); - assert!(parsed1.is_ok()); - - // TODO - fix PartialEq bound issue in AbciQuery - //assert_eq!(parsed0, parsed1); -} diff --git a/modules/src/test_utils.rs b/modules/src/test_utils.rs deleted file mode 100644 index 20762792ca..0000000000 --- a/modules/src/test_utils.rs +++ /dev/null @@ -1,443 +0,0 @@ -use std::sync::{Arc, Mutex}; -use std::time::Duration; - -use subtle_encoding::bech32; -use tendermint::{block, consensus, evidence, public_key::Algorithm}; - -use crate::applications::transfer::context::{ - cosmos_adr028_escrow_address, BankKeeper, Ics20Context, Ics20Keeper, Ics20Reader, -}; -use crate::applications::transfer::{error::Error as Ics20Error, PrefixedCoin}; -use crate::core::ics02_client::client_state::ClientState; -use crate::core::ics02_client::consensus_state::ConsensusState; -use crate::core::ics02_client::error::Error as Ics02Error; -use crate::core::ics03_connection::connection::ConnectionEnd; -use crate::core::ics03_connection::error::Error as Ics03Error; -use crate::core::ics04_channel::channel::{ChannelEnd, Counterparty, Order}; -use crate::core::ics04_channel::commitment::{AcknowledgementCommitment, PacketCommitment}; -use crate::core::ics04_channel::context::{ChannelKeeper, ChannelReader}; -use crate::core::ics04_channel::error::Error; -use crate::core::ics04_channel::packet::{Receipt, Sequence}; -use crate::core::ics04_channel::Version; -use crate::core::ics05_port::context::PortReader; -use crate::core::ics05_port::error::Error as PortError; -use crate::core::ics24_host::identifier::{ChannelId, ClientId, ConnectionId, PortId}; -use crate::core::ics26_routing::context::{Module, ModuleId, ModuleOutputBuilder}; -use crate::mock::context::MockIbcStore; -use crate::prelude::*; -use crate::signer::Signer; -use crate::timestamp::Timestamp; -use crate::Height; - -// Needed in mocks. -pub fn default_consensus_params() -> consensus::Params { - consensus::Params { - block: block::Size { - max_bytes: 22020096, - max_gas: -1, - time_iota_ms: 1000, - }, - evidence: evidence::Params { - max_age_num_blocks: 100000, - max_age_duration: evidence::Duration(core::time::Duration::new(48 * 3600, 0)), - max_bytes: 0, - }, - validator: consensus::params::ValidatorParams { - pub_key_types: vec![Algorithm::Ed25519], - }, - version: Some(consensus::params::VersionParams::default()), - } -} - -pub fn get_dummy_proof() -> Vec { - "Y29uc2Vuc3VzU3RhdGUvaWJjb25lY2xpZW50LzIy" - .as_bytes() - .to_vec() -} - -pub fn get_dummy_account_id() -> Signer { - "0CDA3F47EF3C4906693B170EF650EB968C5F4B2C".parse().unwrap() -} - -pub fn get_dummy_bech32_account() -> String { - "cosmos1wxeyh7zgn4tctjzs0vtqpc6p5cxq5t2muzl7ng".to_string() -} - -#[derive(Debug)] -pub struct DummyTransferModule { - ibc_store: Arc>, -} - -impl DummyTransferModule { - pub fn new(ibc_store: Arc>) -> Self { - Self { ibc_store } - } -} - -impl Module for DummyTransferModule { - fn on_chan_open_try( - &mut self, - _output: &mut ModuleOutputBuilder, - _order: Order, - _connection_hops: &[ConnectionId], - _port_id: &PortId, - _channel_id: &ChannelId, - _counterparty: &Counterparty, - _version: &Version, - counterparty_version: &Version, - ) -> Result { - Ok(counterparty_version.clone()) - } -} - -impl Ics20Keeper for DummyTransferModule { - type AccountId = Signer; -} - -impl ChannelKeeper for DummyTransferModule { - fn store_packet_commitment( - &mut self, - port_id: PortId, - channel_id: ChannelId, - seq: Sequence, - commitment: PacketCommitment, - ) -> Result<(), Error> { - self.ibc_store - .lock() - .unwrap() - .packet_commitment - .entry(port_id) - .or_default() - .entry(channel_id) - .or_default() - .insert(seq, commitment); - Ok(()) - } - - fn delete_packet_commitment( - &mut self, - _port_id: &PortId, - _channel_id: &ChannelId, - _seq: Sequence, - ) -> Result<(), Error> { - unimplemented!() - } - - fn store_packet_receipt( - &mut self, - _port_id: PortId, - _channel_id: ChannelId, - _seq: Sequence, - _receipt: Receipt, - ) -> Result<(), Error> { - unimplemented!() - } - - fn store_packet_acknowledgement( - &mut self, - _port_id: PortId, - _channel_id: ChannelId, - _seq: Sequence, - _ack: AcknowledgementCommitment, - ) -> Result<(), Error> { - unimplemented!() - } - - fn delete_packet_acknowledgement( - &mut self, - _port_id: &PortId, - _channel_id: &ChannelId, - _seq: Sequence, - ) -> Result<(), Error> { - unimplemented!() - } - - fn store_connection_channels( - &mut self, - _conn_id: ConnectionId, - _port_id: PortId, - _channel_id: ChannelId, - ) -> Result<(), Error> { - unimplemented!() - } - - fn store_channel( - &mut self, - _port_id: PortId, - _channel_id: ChannelId, - _channel_end: ChannelEnd, - ) -> Result<(), Error> { - unimplemented!() - } - - fn store_next_sequence_send( - &mut self, - port_id: PortId, - channel_id: ChannelId, - seq: Sequence, - ) -> Result<(), Error> { - self.ibc_store - .lock() - .unwrap() - .next_sequence_send - .entry(port_id) - .or_default() - .insert(channel_id, seq); - Ok(()) - } - - fn store_next_sequence_recv( - &mut self, - _port_id: PortId, - _channel_id: ChannelId, - _seq: Sequence, - ) -> Result<(), Error> { - unimplemented!() - } - - fn store_next_sequence_ack( - &mut self, - _port_id: PortId, - _channel_id: ChannelId, - _seq: Sequence, - ) -> Result<(), Error> { - unimplemented!() - } - - fn increase_channel_counter(&mut self) { - unimplemented!() - } -} - -impl PortReader for DummyTransferModule { - fn lookup_module_by_port(&self, _port_id: &PortId) -> Result { - unimplemented!() - } -} - -impl BankKeeper for DummyTransferModule { - type AccountId = Signer; - - fn send_coins( - &mut self, - _from: &Self::AccountId, - _to: &Self::AccountId, - _amt: &PrefixedCoin, - ) -> Result<(), Ics20Error> { - Ok(()) - } - - fn mint_coins( - &mut self, - _account: &Self::AccountId, - _amt: &PrefixedCoin, - ) -> Result<(), Ics20Error> { - Ok(()) - } - - fn burn_coins( - &mut self, - _account: &Self::AccountId, - _amt: &PrefixedCoin, - ) -> Result<(), Ics20Error> { - Ok(()) - } -} - -impl Ics20Reader for DummyTransferModule { - type AccountId = Signer; - - fn get_port(&self) -> Result { - Ok(PortId::transfer()) - } - - fn get_channel_escrow_address( - &self, - port_id: &PortId, - channel_id: &ChannelId, - ) -> Result<::AccountId, Ics20Error> { - let addr = cosmos_adr028_escrow_address(port_id, channel_id); - Ok(bech32::encode("cosmos", addr).parse().unwrap()) - } - - fn is_send_enabled(&self) -> bool { - true - } - - fn is_receive_enabled(&self) -> bool { - true - } -} - -impl ChannelReader for DummyTransferModule { - fn channel_end(&self, port_id: &PortId, channel_id: &ChannelId) -> Result { - match self - .ibc_store - .lock() - .unwrap() - .channels - .get(port_id) - .and_then(|map| map.get(channel_id)) - { - Some(channel_end) => Ok(channel_end.clone()), - None => Err(Error::channel_not_found( - port_id.clone(), - channel_id.clone(), - )), - } - } - - fn connection_end(&self, cid: &ConnectionId) -> Result { - match self.ibc_store.lock().unwrap().connections.get(cid) { - Some(connection_end) => Ok(connection_end.clone()), - None => Err(Ics03Error::connection_not_found(cid.clone())), - } - .map_err(Error::ics03_connection) - } - - fn connection_channels(&self, _cid: &ConnectionId) -> Result, Error> { - unimplemented!() - } - - fn client_state(&self, client_id: &ClientId) -> Result, Error> { - match self.ibc_store.lock().unwrap().clients.get(client_id) { - Some(client_record) => client_record - .client_state - .clone() - .ok_or_else(|| Ics02Error::client_not_found(client_id.clone())), - None => Err(Ics02Error::client_not_found(client_id.clone())), - } - .map_err(|e| Error::ics03_connection(Ics03Error::ics02_client(e))) - } - - fn client_consensus_state( - &self, - client_id: &ClientId, - height: Height, - ) -> Result, Error> { - match self.ibc_store.lock().unwrap().clients.get(client_id) { - Some(client_record) => match client_record.consensus_states.get(&height) { - Some(consensus_state) => Ok(consensus_state.clone()), - None => Err(Ics02Error::consensus_state_not_found( - client_id.clone(), - height, - )), - }, - None => Err(Ics02Error::consensus_state_not_found( - client_id.clone(), - height, - )), - } - .map_err(|e| Error::ics03_connection(Ics03Error::ics02_client(e))) - } - - fn get_next_sequence_send( - &self, - port_id: &PortId, - channel_id: &ChannelId, - ) -> Result { - match self - .ibc_store - .lock() - .unwrap() - .next_sequence_send - .get(port_id) - .and_then(|map| map.get(channel_id)) - { - Some(sequence) => Ok(*sequence), - None => Err(Error::missing_next_send_seq( - port_id.clone(), - channel_id.clone(), - )), - } - } - - fn get_next_sequence_recv( - &self, - _port_id: &PortId, - _channel_id: &ChannelId, - ) -> Result { - unimplemented!() - } - - fn get_next_sequence_ack( - &self, - _port_id: &PortId, - _channel_id: &ChannelId, - ) -> Result { - unimplemented!() - } - - fn get_packet_commitment( - &self, - _port_id: &PortId, - _channel_id: &ChannelId, - _seq: Sequence, - ) -> Result { - unimplemented!() - } - - fn get_packet_receipt( - &self, - _port_id: &PortId, - _channel_id: &ChannelId, - _seq: Sequence, - ) -> Result { - unimplemented!() - } - - fn get_packet_acknowledgement( - &self, - _port_id: &PortId, - _channel_id: &ChannelId, - _seq: Sequence, - ) -> Result { - unimplemented!() - } - - fn hash(&self, value: Vec) -> Vec { - use sha2::Digest; - - sha2::Sha256::digest(value).to_vec() - } - - fn host_height(&self) -> Height { - Height::new(0, 1).unwrap() - } - - fn host_consensus_state(&self, _height: Height) -> Result, Error> { - unimplemented!() - } - - fn pending_host_consensus_state(&self) -> Result, Error> { - unimplemented!() - } - - fn client_update_time( - &self, - _client_id: &ClientId, - _height: Height, - ) -> Result { - unimplemented!() - } - - fn client_update_height( - &self, - _client_id: &ClientId, - _height: Height, - ) -> Result { - unimplemented!() - } - - fn channel_counter(&self) -> Result { - unimplemented!() - } - - fn max_expected_time_per_block(&self) -> Duration { - unimplemented!() - } -} - -impl Ics20Context for DummyTransferModule { - type AccountId = Signer; -} diff --git a/modules/src/timestamp.rs b/modules/src/timestamp.rs deleted file mode 100644 index c3d655185d..0000000000 --- a/modules/src/timestamp.rs +++ /dev/null @@ -1,320 +0,0 @@ -use crate::prelude::*; - -use core::fmt::{Display, Error as FmtError, Formatter}; -use core::hash::{Hash, Hasher}; -use core::num::ParseIntError; -use core::ops::{Add, Sub}; -use core::str::FromStr; -use core::time::Duration; - -use flex_error::{define_error, TraceError}; -use serde_derive::{Deserialize, Serialize}; -use tendermint::Time; -use time::OffsetDateTime; - -pub const ZERO_DURATION: Duration = Duration::from_secs(0); - -/// A newtype wrapper over `Option