From 68f5ebc84d94d7b243451e803bf8d0b50f11d1ad Mon Sep 17 00:00:00 2001 From: Yuanchao Sun Date: Wed, 5 Oct 2022 15:11:09 +0800 Subject: [PATCH] Feature/add pallet ibc (#79) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * generate_storage_alias: Rewrite as proc macro attribute (#11387) * generate_storage_alias: Rewrite as proc macro attribute This rewrites the `generate_storage_alias!` declarative macro as proc-macro attribute. While doing this the name is changed to `storage_alias`. The prefix can now also be the name of a pallet. This makes storage aliases work in migrations for all kind of chains and not just for the ones that use predefined prefixes. * Fix compilation and FMT * Moare fixes * :facepalm: * ...... * Rework the syntax and support instancing * FMT * Prefix variants with `Storage` * Make it compile * Fix where clause on rust stable * Prune some duplicated dependencies in the dep graph (#11433) Signed-off-by: koushiro * contracts: Get rid of `#[pallet::without_storage_info]` (#11414) * Implement `MaxEncodeLen` for pallet-contracts storage * Remove redundant debug println * Move code len check to PrefabWasmModule::from_code * Return a successful response on repeated small block request (#11429) * [ci] Adjust job order in pipeline test stage with Gitlab DAG (#11442) * [Do Not Merge] Test gitlab DAG in pipeline * add jobs for pipeline cancel * add check-tracing to cancel-pipeline * Allow to set the max supply for collection (#11441) * Allow to set the max supply for collection * Update error * Add weights info * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_uniques --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/uniques/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Update frame/uniques/src/lib.rs Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Parity Bot Co-authored-by: Oliver Tale-Yazdi * disable check-dependent-cumulus (#11450) * trie: Optimize `keys` function (#11457) * trie: Optimize `keys` function Instead of iterating the entire state and collecting all keys that match the given prefix, we can directly use the optimized prefix iterator. * Add a test * add GHA support to dependabot (#11448) * add GHA support to dependabot * fix formatting * add labels * add label * contracts: Add `set_code` root dispatchable (#11451) * Add `set_code` dispatchable * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_contracts --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/contracts/src/weights.rs --template=./.maintain/frame-weight-template.hbs Co-authored-by: Parity Bot * Switch to pooling copy-on-write instantiation strategy for WASM (#11232) * Switch to pooling copy-on-write instantiation strategy for WASM * Fix benchmark compilation * Fix `cargo fmt` * Fix compilation of another benchmark I've missed * Cleanups according to review comments * Move `max_memory_size` to `Semantics` * Set `memory_guaranteed_dense_image_size` to `max_memory_size` * Rename `wasm_instantiation_strategy` to `wasmtime_instantiation_strategy` * Update the doc-comments regarding the instantiation strategy * Extend the integration tests to test every instantiation strategy * Don't drop the temporary directory until the runtime is dropped in benchmarks * Don't drop the temporary directory until the runtime is dropped in tests * Make fields of `EraRewardPoints` public (#11422) * add missing events to elections fallback (#11436) * add missing events to elections fallback * Update frame/election-provider-multi-phase/src/lib.rs Co-authored-by: Bastian Köcher * Update frame/election-provider-multi-phase/src/lib.rs Co-authored-by: Bastian Köcher * add test * fix * fmt * Update frame/support/src/storage/types/nmap.rs Co-authored-by: Bastian Köcher * Fix renaming artifacts (#11455) * Add Score to Bags List (#11357) * Add Score to Bags List * fix ordering * make compile * in progress migration * make migration compile * remove old check * remove runtime specific migration * fix warning * Apply suggestions from code review Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * improve migration * fix * fix merge * fmt * Update migrations.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Stabilize ecdsa_ functions (#11486) * Bump actions/checkout from 2 to 3 (#11463) Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v2...v3) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump gaurav-nelson/github-action-markdown-link-check from 1.0.9 to 1.0.14 (#11464) * Bump gaurav-nelson/github-action-markdown-link-check Bumps [gaurav-nelson/github-action-markdown-link-check](https://github.com/gaurav-nelson/github-action-markdown-link-check) from 1.0.9 to 1.0.14. - [Release notes](https://github.com/gaurav-nelson/github-action-markdown-link-check/releases) - [Commits](https://github.com/gaurav-nelson/github-action-markdown-link-check/compare/7481451f70251762f149d69596e3e276ebf2b236...58f84fd654812d0d8da4e4d4a559eda087daf8ce) --- updated-dependencies: - dependency-name: gaurav-nelson/github-action-markdown-link-check dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Update .github/workflows/md-link-check.yml Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Denis Pisarev * RPC: Mark storage methods as `blocking` (#11459) * client/api: Make `storage_keys` blocking Signed-off-by: Alexandru Vasile * client/api: Ensure `state_*` RPC methods are blocking Signed-off-by: Alexandru Vasile * client/rpc: Ensure `childstate_*` RPC methods are blocking Signed-off-by: Alexandru Vasile * client/rpc: `ChainApi` make RPC methods sync Signed-off-by: Alexandru Vasile * Remove unused async-traits Signed-off-by: Alexandru Vasile * client/rpc-api: Make chain RPC methods blocking Signed-off-by: Alexandru Vasile * Update client/rpc/src/state/state_full.rs Co-authored-by: Bastian Köcher * Add `blocking` to `state_getKeysPaged` RPC call Signed-off-by: Alexandru Vasile * Fix build and warning Signed-off-by: Alexandru Vasile * Remove `async_trait` tidyup Signed-off-by: Alexandru Vasile Co-authored-by: Bastian Köcher * InMemoryBackend: Make it generic over the key hasher (#11488) * InMemoryBackend: Make it generic over the key hasher * Update primitives/state-machine/src/in_memory_backend.rs Co-authored-by: cheme * Update primitives/state-machine/src/in_memory_backend.rs Co-authored-by: cheme * FMT Co-authored-by: cheme * Unify rpc api and implementation name (#11469) * Unify rpc api and implementation name Signed-off-by: koushiro * MauanlSeal ==> ManualSealRpc Signed-off-by: koushiro * Remove extra Rpc naming in the structs Signed-off-by: koushiro * Update doc Signed-off-by: koushiro * fix merge Co-authored-by: Shawn Tabrizi * rpc servers CLI: add `--max--subscriptions--per--connection` + fix a few bugs (#11461) * cli: fix RPC CLI nits * remove needless lines * cargo fmt * Update client/service/src/lib.rs Co-authored-by: James Wilson Co-authored-by: James Wilson * Make `--dev` listen by default on `/ip4/0.0.0.0/tcp/30333` (#11492) If `--validator` is passed we also listen on this address and as `--dev` is a shortcut for multiple CLI args, including `--validator`, we should make it consistent. * Fix State Trie Migration Benchmarks (#11502) * enable signed migrations in benchmarks * T instead of Test Signed-off-by: Oliver Tale-Yazdi * Remove 'mut' Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi * Use API for pr-custom-review (#11487) * use API for pr-custom-review * bump action tag * temporary: disable draft skip * temporary: use staging * try it with the prod instance * revert draft skip * Introduce #[pallet::call_index] attribute to dispatchables (#11381) * Introduce #[pallet::call_index] attribute to dispatchables * cargo fmt * Add more docs and prevent duplicates of call indices * Add UI test for conflicting call indices * cargo fmt Co-authored-by: parity-processbot <> * Create Script to Run All Benchmarks (#11493) * Create run_all_benchmarks.sh * Update run_all_benchmarks.sh * Update run_all_benchmarks.sh * Review fixes Signed-off-by: Oliver Tale-Yazdi * Update scripts/run_all_benchmarks.sh Co-authored-by: Bastian Köcher * typo Signed-off-by: Oliver Tale-Yazdi * add default for $1 * Typo Signed-off-by: Oliver Tale-Yazdi * Update run_all_benchmarks.sh * new weights on benchmarking machine * prefer `--chain=dev` * fix compile * fix command * fmt * dont use square brackets * Extend doc Signed-off-by: Oliver Tale-Yazdi * Remove +nightly Signed-off-by: Oliver Tale-Yazdi * Add error file an run execute everything optimistically Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Bastian Köcher * Adjust maximum memory pages hard limit for the pooling instantiation strategy (#11482) * Run `sc-executor-wasmtime` unit tests for all instantiation strategies * Adjust maximum memory pages hard limit for the pooling instantiation strategy * Optimize offchain worker memory usage a bit. (#11454) * add missing events to elections fallback * Merged * add some logs and stuff * undo a bunch of things * undo lock file * remove unused err * fix build * add rule to the ci job (#11511) * Contracts pallet: removal on idle (#11202) * on_initialize -> on_idle * use remaining_weight info * no weight_limit for on_idle * call on_idle in tests * attempt to fix tests * run on_initiaize when queue full * add on_idle to weight info * add on_idle weight info to on_idle hook * add basic test for on_initialize with full queue * disbale check for all keys gone in full queue, full block test * queue_deth as usize, add comment * comment was removed by accident * Update frame/contracts/src/lib.rs Co-authored-by: Alexander Theißen * cargo +nightly fmt * update lazy_removal_does_no_run_on_full_queue_and_full_block * remove changes in weights.rs * weights on_idle -> on_process_deletion_queue_batch * use block number for on_idle * use BlockNumber for on_initialize * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_contracts --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/contracts/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Update frame/contracts/src/lib.rs Co-authored-by: Alexander Theißen * remove outcommented code * add check that queue still full for test * cargo fmt * cargo +nightly fmt * Update frame/contracts/src/benchmarking/mod.rs Co-authored-by: Alexander Gryaznov * fix weights.rs * add lazy_removal_does_no_run_on_low_remaining_weight test * Apply suggestions from code review Co-authored-by: Alexander Gryaznov Co-authored-by: Alexander Theißen Co-authored-by: Parity Bot Co-authored-by: Alexander Gryaznov * Fix Babe revert when last finalized block is a leaf (#11500) * Fix Babe revert when a leaf is the last finalized block Without this fix the last finalized block weight data is wrongly removed on revert scenario where the last finalized block is a leaf. * Remove redundant check * Added test to exercise the fix * Rename test * Give variables better names * Document benchmarking CLI (#11246) * Decrese default repeats Signed-off-by: Oliver Tale-Yazdi * Add benchmarking READMEs Signed-off-by: Oliver Tale-Yazdi * Update docs Signed-off-by: Oliver Tale-Yazdi * Update docs Signed-off-by: Oliver Tale-Yazdi * Update README Signed-off-by: Oliver Tale-Yazdi * Review fixes Co-authored-by: Shawn Tabrizi Co-authored-by: parity-processbot <> Co-authored-by: Shawn Tabrizi * Introduce `WeightToFee` trait instead of `WeightToFeePolynomial` and make `WeightToFeePolynomial` implement it instead (#11415) * Introduce `WeightToFee` trait instead of `WeightToFeePolynomial` and make `WeightToFeePolynomial` implement it instead * Rename `WeightToFee::calc()` to `WeightToFee::wight_to_fee()` * Fix typo * Fix node lookup on fork-tree after a warp-sync (#11476) * Fix node lookup on fork-tree after a warp-sync After a warp-sync, the error condition was triggered by the absence of the parent node of the first imported block. The previous lookup implementation was traversing the tree using a recursive **post-order** DFS, this technique doesn't trigger the issue. In the last iterative implementation we were using a BFS instead. * Added internal doc warning * Small optimization * Specify post-order DFS in the comment * Test for the fork-tree post-order DFS traversal requirement (#11521) * Test for the fork-tree post-order DFS traversal requirement * Fixed typo * Storage Layer for All FRAME Extrinsics (#11431) * add new trait * implement DispatchableWithStorageLayer * at least one transactional * all dispatch is at least transactional * storage_layer api * add test * storage layer tests * deprecate transactional tag * i guess no reason to deprecate * remove transactional from batch_all * update tests * extend trait * cargo run --quiet --profile=production --features runtime-benchmarks --manifest-path bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_balances --extrinsic=* --execution=wasm --wasm-execution=compiled --output=./frame/balances/src/weights.rs --template=./.maintain/frame-weight-template.hbs * cargo run --quiet --profile=production --features runtime-benchmarks --manifest-path bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_balances --extrinsic=* --execution=wasm --wasm-execution=compiled --output=./frame/balances/src/weights.rs --template=./.maintain/frame-weight-template.hbs * cargo run --quiet --profile=production --features runtime-benchmarks --manifest-path bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_staking --extrinsic=* --execution=wasm --wasm-execution=compiled --output=./frame/staking/src/weights.rs --template=./.maintain/frame-weight-template.hbs * fix copy paste name * cargo run --quiet --profile=production --features runtime-benchmarks --manifest-path bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_utility --extrinsic=* --execution=wasm --wasm-execution=compiled --output=./frame/utility/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Create run_all_benchmarks.sh * uncomment build * update number of steps and repeats * add skip build * Update run_all_benchmarks.sh * Update run_all_benchmarks.sh * new benchmarks * Update frame/support/src/traits/dispatch.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/support/src/traits/dispatch.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/support/test/tests/storage_layers.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/support/test/tests/storage_layers.rs * weights * Update dispatch.rs * doc link * decl_macro support Co-authored-by: Parity Bot Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * CI: github no longer checks whitelisted actions this way (#11507) * CI: github no longer checks whitelisted actions this way * CI: actually this one is needed and no one knows it's related to a Markdown Link Check * Fork-Tree import requires post-order DFS traversal (#11531) * Fork-tree insert requires post-order dfs traversal * Add dedicated test for methods requireing post-order traversal * Fixed pruning docs (#11519) * fix broken links (#11536) * Safe and sane multi-item storage removal (#11490) * Fix overlay prefix removal result * Second part of the overlay prefix removal fix. * Report only items deleted from storage in clear_prefix * Fix kill_prefix * Formatting * Remove unused code * Fixes * Fixes * Introduce clear_prefix host function v3 * Formatting * Use v2 for now * Fixes * Formatting * Docs * Child prefix removal should also hide v3 for now * Fixes * Fixes * Formatting * Fixes * apply_to_keys_whle takes start_at * apply_to_keys_whle takes start_at * apply_to_keys_whle takes start_at * Cursor API; force limits * Use unsafe deprecated functions * Formatting * Fixes * Grumbles * Fixes * Docs * Some nitpicks :see_no_evil: * Update primitives/externalities/src/lib.rs Co-authored-by: Bastian Köcher * Formatting * Fixes * cargo fmt * Fixes * Update primitives/io/src/lib.rs Co-authored-by: Keith Yeung * Formatting * Fixes Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher Co-authored-by: Keith Yeung * Use `loops` rather than `backend` for compatibility. (#11542) * Use `loops` rather than `backend` for compatibility. * Move over other converters * sp-core: impl serde for some offchain types (#11512) * sp-core: impl serde for some offchain types * Update primitives/core/src/offchain/mod.rs Co-authored-by: Bastian Köcher * remove serde impls from OpaqueNetworkState/OpaqueMultiaddr * derive default Co-authored-by: Bastian Köcher * Several tweaks needed for Governance 2.0 (#11124) * Add stepped curve for referenda * Treasury SpendOrigin * Add tests * Better Origin Or-gating * Reciprocal curve * Tests for reciprical and rounding in PerThings * Tweaks and new quad curve * Const derivation of reciprocal curve parameters * Remove some unneeded code * Actually useful linear curve * Fixes * Provisional curves * Rejig 'turnout' as 'support' * Use TypedGet * Fixes * Enable curve's ceil to be configured * Formatting * Fixes * Fixes * Fixes * Remove EnsureOneOf * Fixes * Fixes * Fixes * Formatting * Fixes * Update frame/support/src/traits/dispatch.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Grumbles * Formatting * Fixes * APIs of VoteTally should include class * Fixes * Fix overlay prefix removal result * Second part of the overlay prefix removal fix. * Formatting * Fixes * Add some tests and make clear rounding algo * Fixes * Formatting * Revert questionable fix * Introduce test for kill_prefix * Fixes * Formatting * Fixes * Fix possible overflow * Docs * Add benchmark test * Formatting * Update frame/referenda/src/types.rs Co-authored-by: Keith Yeung * Docs * Fixes * Use latest API in tests * Formatting * Whitespace * Use latest API in tests Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Keith Yeung * change impl FnOnce() to generic type + trait bound (#11534) * change impl FnOnce() to generic type + trait bound with_transaction() function can not be used with explicit generic arguments because of this issue: https://github.com/rust-lang/rust/issues/83701 * make the same changes elsewhere Co-authored-by: Shawn Tabrizi * Introduce `rusty-cachier` (#11462) * Introduce `rusty-cachier` * Return LF at the end of file * Use `entrypoint` to `unshare(1)` into a new mount namespace * Use `rusty-cachier`-provided absolute path for `CARGO_TARGET_DIR` everywhere * Debug single `build-rustdoc` job * CI: debug * CI: debug * CI: debug * `unshare(1)` is no longer needed * CI: remove debug * Revert "Debug single `build-rustdoc` job" * Formatiing * Update scripts/ci/gitlab/pipeline/build.yml Co-authored-by: Denis Pisarev * Clean up `#[transactional]` (#11546) * Deprecate #[transactional] attribute Signed-off-by: Oliver Tale-Yazdi * Remove #[transactional] from nomination pools Signed-off-by: Oliver Tale-Yazdi * Review fix Co-authored-by: Bastian Köcher * Fix NOOP test Signed-off-by: Oliver Tale-Yazdi * Suppress warnings Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Bastian Köcher * Add `rusty-cachier notify` job (#11554) * Add `rusty-cachier notify` job * Add comments * Fix CI after `rusty-cachier` introduction (#11556) * Fix CI after `rusty-cachier` introduction * Replace anchor with `extends` * Introduce `EnsureOrigin::try_successul_origin` (#11558) * Introduce `EnsureOrigin::try_successul_origin` * Formatting * Fixes * Add Morph * Fixes * Formatting * Sync: Improve major sync detection (#11547) * Sync: Improve major sync detection When we still have a full import queue, we should still report that we are in major sync mode, otherwise validators may will already start producing blocks. * Use median * Review comments * Fix clippy on master (#11559) * Fix link in node-template README (#11529) The lorri repository has moved from https://github.com/target/lorri to https://github.com/nix-community/lorri. * Fix minor typos (#11550) * Fix minor typos * FMT Co-authored-by: Bastian Köcher * Short circuit Treasury::Spend benchmark for NeverEnsureOrigin (#11562) Signed-off-by: Oliver Tale-Yazdi Co-authored-by: parity-processbot <> * Do not require Ord for pallet_offences::Config::IdentificationTuple (#11563) * Ranked Collective pallet (#11548) * Ranked Collective pallet * Fixes * benchmarks * Weights * Allow class voting in rank Use bare ayes for calculating support. Allow only promotion/demotion by one rank only. Allow removal of member with rank zero only. Use new Tally API * Index by rank, still O(1). * Custom vote weights * Formatting * Update frame/ranked-collective/src/lib.rs * Broken :( * origin guard; cleanup uses new API * Formatting * Promote/demote by rank * Formatting * Use new API * Remove code in another PR * Remove code in another PR * Formatting * Remove code in another PR * Docs * Docs * Bump * Fixes * Formatting * Fixes * Introduce set function into storage maps (#11564) * Introduce `SubmitOrigin` to Referenda pallet config (#11567) * Don't limit `test-linux-stable-int` job output (#11560) * Fix all warnings when building for wasm (#11569) * Fix all warnings when building for wasm Besides that it also enables warnings as errors for wasm builds in the CI. * FMT * Make clippy happy * Helper macro for `Morph` impls (#11570) * Helper macro for Morph impls * No need to deprecate for now * Improved macro * Doc tests * Grumbles * `rusty-cachier` pipeline impovements and fixes (#11572) * CI: fix `build-subkey-macos` build job (#11573) * CI: fix `build-subkey-macos` build job * CI: use full path for the `CARGO_TARGET_DIR` default value * aura: export change_authorities and initialize_authorities (#11468) * aura: export change_authorities and initialize_authorities * add docs * fix docs * Reduce call size of Referenda pallet (#11578) * Reduce call size of Referenda pallet * Fixes * Fixes * Fixes * Docs * reactivate check-dependent-cumulus (#11506) * re-enable check-dependent-cumulus * temporary: use handle-extra-dependencies * temporary: trim CI * CI: include build stage * CI: include test stage * CI: include test stage * Revert "temporary: trim CI" This reverts commit dcf4ae8d842bc445a065c7ccdc3b6a603034faa4. * CI: fix weird revert * Revert "temporary: use handle-extra-dependencies" This reverts commit bc0dc0f21f10284a23f66fdd8509ca6df89f2586. * CI undebug Co-authored-by: TriplEight * wasm-builder: Rerun the build if the generated file changed (#11582) * [ci] use cargo nextest instead cargo test in test-linux-stable (#11576) * [DO NOT MERGE] Experimenting with nextest * enable jobs * enable stages * add comment * create test-frame-support job * Expose ValidatedTransaction from transaction pool (#11588) This is required to make a tx pool wrapper for some custom transaction validation, specificially required to make a wrapper around the `LocalTransactionPool` implementation (https://github.com/subspace/subspace/blob/f54881a9b5/crates/subspace-service/src/pool.rs#L232-L269). Related: https://github.com/paritytech/substrate/discussions/11520 * Tracable defensive errors (#11532) * Tracable defensive errors * small fixes * fix * refactored * switched to defensive_ok_or * Remove unnecessary type annotations and conversions * cargo fmt * Fixes Co-authored-by: Keith Yeung * Remove `#[pallet::without_storage_info]` for pallet-remark (#11590) * Add host info to weight templates (#11583) * Add host info to weight templates Signed-off-by: Oliver Tale-Yazdi * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=frame_system --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/system/src/weights.rs --template=./.maintain/frame-weight-template.hbs Co-authored-by: Parity Bot * Expose Benchmarking Component Ranges (#11545) * Add component ranges to benchmarking Signed-off-by: Oliver Tale-Yazdi * Adding component ranges to templates Signed-off-by: Oliver Tale-Yazdi * Fix tests Signed-off-by: Oliver Tale-Yazdi * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=frame_system --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/system/src/weights.rs --template=./.maintain/frame-weight-template.hbs * tweak script to reduce diff * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_identity --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/identity/src/weights.rs --template=./.maintain/frame-weight-template.hbs Co-authored-by: Parity Bot Co-authored-by: Shawn Tabrizi * make era public (#11575) * MEL for Ranked Collective (#11602) * Fix one-by-off in `BoundedSlice::try_from` (#11600) * Remove a max supply record on collection's destruction (#11593) * Remove a max supply record on collection's destruction * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_utility --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/utility/src/weights.rs --template=./.maintain/frame-weight-template.hbs * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_uniques --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/uniques/src/weights.rs --template=./.maintain/frame-weight-template.hbs * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_uniques --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/uniques/src/weights.rs --template=./.maintain/frame-weight-template.hbs Co-authored-by: Parity Bot * Implement more IntoIter traits for bounded types (#11616) * Remove `without_storage_info` for membership pallet (#11591) * Improve docs on `--keep-blocks` CLI parameter and related data structures (#11611) * Improve docs on `--keep-blocks` CLI parameter and related data structures * Update client/db/src/lib.rs Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher * Improve inspection and generation of node keys (#11525) * Improve inspection and generation of node keys * Lock stdout before write * Fix typo * Fix offset * Remove useless code * Set inspect-node-key 'network' option as obsolete * Better transaction pool error (#11629) * Better transaction pool error * Do not use `Debug` when printing errors * Use BoundedVec in aura pallet (#11617) * Use BoundedVec in aura pallet * cargo fmt * pallet alliance (#11112) * Add pallet-alliance Signed-off-by: koushiro * Update multihash/cid and format Signed-off-by: koushiro * Remove useless deps Signed-off-by: koushiro * Add pallet-alliance into node runtime Signed-off-by: koushiro * Fix has_identity Signed-off-by: koushiro * Add TooMantBlacklist Error Signed-off-by: koushiro * Add TooLongWebsiteUrlLength Error Signed-off-by: koushiro * Add remove_announcement Signed-off-by: koushiro * Derive pallet_identity::Config and Fix test/benchmarking Signed-off-by: koushiro * Add part weight for call of pallet-alliance Signed-off-by: koushiro * Remove pallet_identity Config trait Signed-off-by: koushiro * Fix propose arguments Signed-off-by: koushiro * Some nits Signed-off-by: koushiro * cargo fmt Signed-off-by: koushiro * Fix benchmarking of add_blacklist/remove_blacklist Signed-off-by: koushiro * Some nits Signed-off-by: koushiro * Add benchmarking for init_members Signed-off-by: koushiro * Add benchmarking for propose/vote/veto Signed-off-by: koushiro * Fix benchmarking Signed-off-by: koushiro * Remove some useless Signed-off-by: koushiro * fix some compile issue * more fix * all checks * refactor * refactor event * refactor * cleanup * cleanup * fix benchmarking * fix warning * fmt * fix benchmarks * with storage info * fmt * add new config * fix benchmarks * fix * fmt * Apply suggestions from code review Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * improvements * fix * update docs * rename events, errors, and functions * make kicking events clearer * fix * fix tests * fix tests * fix runtime * fix build * remove unneeded change * remove Candidate role from Alliance * fmt grumbles * update lock * update recursion limit * benchmarks * convert-try * benchmark assertions * fmt , * cargo lock * Update frame/alliance/src/benchmarking.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * add docs to public interfaces * Apply suggestions from code review Co-authored-by: Squirrel * fix build (node) * review * use EitherOfDiverse * update cargo toml * make all dispatch class Normal * change blacklist to unscrupulous * formatting * fmt oops * rename benchmarking unscrupulous account creator Co-authored-by: koushiro Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: joepetrowski Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Co-authored-by: Squirrel * Add fixed u64 (#11555) Co-authored-by: parity-processbot <> Co-authored-by: Oliver Tale-Yazdi * Remove storage `MaxValues` limits (#11643) * Remove limits Signed-off-by: Oliver Tale-Yazdi * Remove more Signed-off-by: Oliver Tale-Yazdi * Added an event for cancel_proposal (#11620) * Added an event for cancel_proposal * test * pallet-grandpa: Improve/Clarify docs of `note_stalled` (#11623) * Bump crossbeam-utils from 0.8.5 to 0.8.8 (#11605) Bumps [crossbeam-utils](https://github.com/crossbeam-rs/crossbeam) from 0.8.5 to 0.8.8. - [Release notes](https://github.com/crossbeam-rs/crossbeam/releases) - [Changelog](https://github.com/crossbeam-rs/crossbeam/blob/master/CHANGELOG.md) - [Commits](https://github.com/crossbeam-rs/crossbeam/compare/crossbeam-utils-0.8.5...crossbeam-utils-0.8.8) --- updated-dependencies: - dependency-name: crossbeam-utils dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix pallet_uniques docs link (#11651) * MEL bound `state-trie-migration` (#11639) * MEL bound state-trie-migration Signed-off-by: Oliver Tale-Yazdi * wip Signed-off-by: Oliver Tale-Yazdi * Add tests Signed-off-by: Oliver Tale-Yazdi * Use sp_std Co-authored-by: cheme * Add doc Signed-off-by: Oliver Tale-Yazdi * Set MaxKeyLen default to 512 Just to be sure that it will work. There is also no real penalty from over-estimating it. Signed-off-by: Oliver Tale-Yazdi * Add more doc Signed-off-by: Oliver Tale-Yazdi * Clippy Signed-off-by: Oliver Tale-Yazdi * fmt Signed-off-by: Oliver Tale-Yazdi * Fix assert_err_with_weight macro Looks like I'm the only one using it anyway... Signed-off-by: Oliver Tale-Yazdi * Fix tests that use env macro Signed-off-by: Oliver Tale-Yazdi * Fix test Signed-off-by: Oliver Tale-Yazdi Co-authored-by: cheme * Move bounded type definitions to sp-runtime (#11645) * Move bounded type definitions to sp-runtime * cargo fmt * Fix compile error Signed-off-by: Oliver Tale-Yazdi * Move TryCollect to sp-runtime * Write some docs * Import missing types Co-authored-by: Oliver Tale-Yazdi * Implement MaxEncodedLen on pallet-beefy (#11584) * Implement MaxEncodedLen on pallet-beefy * Return Result in intialize_authorities * Update docs * Log error when authorities list gets truncated * Update frame/beefy/src/lib.rs Co-authored-by: Adrian Catangiu * cargo fmt Co-authored-by: Adrian Catangiu * Implement PartialOrd and Ord on BoundedSlice and WeakBoundedVec (#11655) * Implement PartialOrd and Ord on BoundedSlice and WeakBoundedVec * More implementations of PartialEq and PartialOrd * cargo fmt * Fixes * Allow nomination pools to chill + fix dismantle scenario (#11426) * make pool roles optional * undo lock file changes? * add migration * add the ability for pools to chill themselves * boilerplate of tests * somewhat stable, but I think I found another bug as well * Fix it all * Add more more sophisticated test + capture one more bug. * Update frame/staking/src/lib.rs * reduce the diff a little bit * add some test for the slashing bug * cleanup * fix lock file? * Fix * fmt * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/mock.rs Co-authored-by: Oliver Tale-Yazdi * Fix build * fix some fishy tests.. * add one last integrity check for MinCreateBond * remove bad assertion -- needs to be dealt with later * nits * fix tests and add benchmarks for chill * remove stuff * fix benchmarks * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_nomination_pools --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/nomination-pools/src/weights.rs --template=./.maintain/frame-weight-template.hbs * remove defensive Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Shawn Tabrizi Co-authored-by: Parity Bot * Properly implement Debug on bounded types (#11659) * remove flaky rpc subscription tests (#11653) * Add `TypeInfo` (#11599) * wasm-builder: Fix constant re-running of `build.rs` scripts. (#11624) Recently we added the wasm binaries to the `rerun-if-changed` list. The problem with that is that they have a later mtime than the `invoked.timestamp` file and this file's mtime is used to determine if the `build.rs` script needs to be re-run. The solution to this is that we copy the mtime of this `invoked.timestamp` file and add it to the wasm binaries. Then cargo/rustc doesn't constantly wants to rerun the `build.rs` script. * Increment subkey version to 2.0.2 (#11656) * Increment subkey version to 2.0.2 * Update Cargo.lock Co-authored-by: Davide Galassi * Implement `Deref` for `BoundedSlice` (#11660) * Impl Deref for BoundedSlice Signed-off-by: Oliver Tale-Yazdi * Update primitives/runtime/src/bounded/bounded_vec.rs Co-authored-by: Keith Yeung Co-authored-by: Bastian Köcher Co-authored-by: Keith Yeung * grandpa: fix creation of justification with equivocating precommits in commit (#11302) * grandpa: fix creation of justification ancestry we would reject commits that have precommits targeting blocks lower than the commit target. when there is an equivocation (or if it the commit is not minimal) it is possible to have such precommits and we should assume that they are the round base. * grandpa: bump to 0.16.0 * grandpa: add test for justification with equivocation * grandpa: fix failing test * Make it possible to disable RocksDB completely (#11537) * Make it possible to disable RocksDB completely * Make ParityDB non-optional * Address review comments * rpc servers: update jsonrpsee to fix host filtering + WS server-side pings (#11661) * bump jsonrpsee to fix #11480 In addition it adds WebSocket server-side pings which is configured to send out pings periodically every 30 seconds. * use released crates.io version * Update Cargo.toml * Include the chain specs instead of trying to open them by path (#11625) This makes it possible to run the tests manually, without them expecting to be run in a special folder etc. * Remove `without_storage_info` from pallet `transaction-storage` (#11668) * Introduce BoundedVec * Fix typos * Add comments to the bounds * Remove migration * Improve bound value access syntax * combine iteratons and tolerance in sp-npos-elections API (#11498) * Initial implementation of mms * Some more attempts at `mms` * Functioning `MMS` algorithm implementation. Adding some tests too * More tests and typos fixed. * Adding fuzzer for `mms` (but could not test it on Mac M1) * Missing imports * Fixing rustdoc * More accurate implementation of `mms` * Removing the fuzzer `mms` implementation * Implementing `NposSolver` for `MMS` had to add the `Clone` trait, maybe I could see if I can get rid of it. * Fixing rust docs by adding () to resolve ambiguity * Amending `unwrap` to `expect` removing unneeded `Clone` trait * Removing redundant `mms3.rs` * Implementing `BalancingConfig` and rustdoc changes * Implementing `weight` for `MMS` * Implementing `weight` for `MMS` * Fixing post merge * Initial implementation of mms * Some more attempts at `mms` * Functioning `MMS` algorithm implementation. Adding some tests too * More tests and typos fixed. * Adding fuzzer for `mms` (but could not test it on Mac M1) * Missing imports * Fixing rustdoc * More accurate implementation of `mms` * Removing the fuzzer `mms` implementation * Implementing `NposSolver` for `MMS` had to add the `Clone` trait, maybe I could see if I can get rid of it. * Amending `unwrap` to `expect` removing unneeded `Clone` trait * Fixing rust docs by adding () to resolve ambiguity * Removing redundant `mms3.rs` * Implementing `BalancingConfig` and rustdoc changes * Implementing `weight` for `MMS` * Implementing `weight` for `MMS` * Fixing post merge * Removing left over from rebase * Fixing tests * Removing unneeded import * Removing unneeded functions * Removing useless imports Co-authored-by: kianenigma * Add Event to Pallet Transaction Payment (#11618) * add Event to Pallet Transaction Payment * Fix tests in Pallet Balance * Fix tests in Pallet Balance/Executive/Asset-tx-payment. * Fix * fmt * Fix * Fix * Update Cargo.lock * Fix tests in executor * Update frame/transaction-payment/src/lib.rs Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * update the name of the event and fmt. Co-authored-by: Shawn Tabrizi Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * Remove `without_storage_info` for the authorship pallet (#11610) * Remove `without_storage_info` for the authorship pallet * Tweak impl bounds style * Use `defensive_proof` instead of `expect` * MEL: Origin, Referenda, ConvictionVoting (#11631) * Referenda & CV pallets ready * Fix build * Add mel_bound for Voting and Casting types * Add mel_bound on Tally * Add mel_bound on another Tally * Add mel_bound for pallet_collective::RawOrigin Co-authored-by: Keith Yeung * Remove multiply_by_rational (#11598) * Removed multiply_by_rational Replaced with multiply_by_rational_with_rounding * fixes * Test Fixes * nightly fmt * Test Fix * Fixed fuzzer. * Upgrade to libp2p 0.45.1 (#11682) * Upgrade to libp2p 0.45.1 * Limit max_negotiating_inbound_streams to 512 * Upgrade prost-build to 0.10 * Set max_negotiating_inbound_streams to 2048 Co-authored-by: Pierre Krieger * Fix authority discovery protobuf * Fix comments in authority-discovery schema Co-authored-by: Pierre Krieger * Add a comment about transport initialization Co-authored-by: Pierre Krieger * chore: reducing codec times (#11688) * chore: reduce uxt encode times (#11698) * chore: reduce uxt encode times * fmt * Simplified code using existing APIs (#11702) Signed-off-by: Emison Lu * `storage-alias`: Check that prefix is not an underscore (#11704) Besides that it also adds some UI tests. * Bump twox-hash from 1.6.2 to 1.6.3 (#11423) Bumps [twox-hash](https://github.com/shepmaster/twox-hash) from 1.6.2 to 1.6.3. - [Release notes](https://github.com/shepmaster/twox-hash/releases) - [Commits](https://github.com/shepmaster/twox-hash/compare/v1.6.2...v1.6.3) --- updated-dependencies: - dependency-name: twox-hash dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Update syn and fix compilation (#11707) * Update syn and fix compilation * Bump pin-project * check-dependent-cumulus should only be executed for PRs (#11693) the script executed by check-dependent-cumulus only works for PRs, as shown in https://gitlab.parity.io/parity/mirrors/substrate/-/jobs/1630771#L87, which comes from https://github.com/paritytech/pipeline-scripts/blob/3ad10ddc0d985ef5326974a1143229c6429befab/check_dependent_project.sh#L443 * Pump the gossip engine while waiting for the BEEFY runtime pallet (memory leak fix) (#11694) * Pump the gossip engine while waiting for the BEEFY runtime pallet This fixes a memory leak when the BEEFY gadget is turned on, but the runtime doesn't actually use BEEFY. * Implement `FusedFuture` for `GossipEngine` * Fuse futures outside of loops * Implement Serialize/Deserialize on WeakBoundedVec (#11713) * Implement Serialize/Deserialize on WeakBoundedVec * cargo fmt * Warn when there are too many elements while deserializing WeakBoundedVec * More robust grandpa revert procedure (#11719) * More robust revert procedure Return an error if revert is called in a node that is not actively running grandpa, i.e. grandpa genesis data has not been initialized. Previous implementation was just firing an `unreachable!` code exception. Furthermore we skip revert hassle if there is nothing to revert. * Nit * Fix typo in weights.rs (#11724) overriden -> overridden * WrapperOpaque: Use `decode_all` to decode from the `Vec` (#11726) This ensures that there isn't any extra data attached that isn't used. * Respect cargo offline env variable in wasm builder (#11735) * Support offline env variable in wasm builder * Clean up * Improve checks Co-authored-by: Bastian Köcher * Update crate docs * Add docs to `lib.rs` and introduce helper method `offline_build` Co-authored-by: Bastian Köcher * contracts: Reduce size of deletion queue depth (#11696) * contracts: Reduce size of deletion queue depth * Remove unused import * Put `rusty-cachier` before PR merge into `master` for `cargo-check-benches` job (#11737) * epochs: don't use gap when there's at least one genesis epoch imported (#11725) * epochs: don't use gap when there's at least one genesis epoch imported * epochs: add test for genesis gap fix * pallet-beefy-mmr: add API for BEEFY Authority Sets (#11406) * pallet-beefy: add Config::OnNewValidatorSet type Add a hook to pallet-beefy for doing specific work when BEEFY validator set changes. For example, this can be used by pallet-beefy-mmr to cache a lightweight MMR root over validators and make it available to light clients. * pallet-beefy-mmr: implement OnNewValidatorSet Implement pallet-beefy::OnNewValidatorSet to be notified of BEEFY validator set changes. Use the notifications to compute and cache a light weight 'BEEFY authority set' which is an MMR root over BEEFY validator set plus some extra info. Previously, pallet-beefy-mmr was interogating pallet-beefy about validator set id on every block to find out when it needs to recompute the authority set. By using the event-driven approach in this commit, we also save one extra state interogation per block. * pallet-beefy-mmr: add new authority_set() API Expose current and next BEEFY authority sets through runtime API. These can be directly used by light clients to avoid having them compute them themselves based on BEEFY validator sets. Signed-off-by: acatangiu * rename BeefyMmr exposed runtime api * make pallet-tips & pallet-bounties instantiable (#11473) * make pallet-tips & pallet-bounties instantiable * update test * add default instance * update * cargo fmt * update * update * update * update * fix merge * fix tests * bounties benchmarking instantiable * fix benchmarks * make tips benchmarks instantible Co-authored-by: Shawn Tabrizi * [contracts] Implement transparent hashing for contract storage (#11501) * save * builds and old tests pass save: temporary value dropped while borrowed save: finally builds test updated but still fails * type names enhanced * VarSizedKey bounded to new Config param * improved wasm runtime updated funcs * unstable-interface tests fixed * benchmarks fixed * Apply suggestions from code review Co-authored-by: Alexander Theißen * fixes on feedback * fixes on feedback applied + make it build * benchmarks build but fail (old) * "Original code too large" * seal_clear_storage bench fixed (code size workaround hack removal tbd) * bench_seal_clear_storage pass * bench_seal_take_storage ... ok * added new seal_set_storage + updated benchmarks * added new seal_get_storage + updated benchmarks * added new seal_contains_storage + updated benchmarks * added tests for _transparent exec functions * wasm test for clear_storage * wasm test for take_storage * wasm test for new set_storage * wasm test for new get_storage * wasm test for new contains_storage * CI fix * ci fix * ci fix * ci fix * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_contracts --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/contracts/src/weights.rs --template=./.maintain/frame-weight-template.hbs * fixes according to the review feedback * tests & benchmarks fixed * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_contracts --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/contracts/src/weights.rs --template=./.maintain/frame-weight-template.hbs * refactoring * fix to runtime api * ci fix * ctx.get_storage() factored out * ctx.contains_storage() factored out * number of batches reduced for transparent hashing storage benchmarks * contracts RPC & pallet::get_storage to use transparent hashing * node and rpc updated to use get_storage with VarSizedKey * refactored (more concize) * refactored contains_storage (DRYed) * refactored contains_storage (DRYed) * fix rpc * fmt fix * more fixes in rpc * rollback `Pallet:get_storage` to Vec and rpc and node parts related to it * added `KeyDecodingFailed` error * Revert weird "fmt fix" This reverts commit c582cfff4b5cb2c9929fd5e3b45519bb24aeb657. * node-executor basic test update * fix node-executor basic test * benchmarks fix * more benchmarks fix * FixedSizedKey is hidden from pub, VarSizedKey is exported as StorageKey * ci fix * set_storage benchmark fix * ci fix * ci fix * comments improved * new error code to rpc: KEY_DECODING_FAILED * Put `rusty-cachier` before PR merge into `master` for `cargo-check-benches` job * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_contracts --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/contracts/src/weights.rs --template=./.maintain/frame-weight-template.hbs * minor optimization Co-authored-by: Alexander Theißen Co-authored-by: Parity Bot Co-authored-by: Vladimir Istyufeev Co-authored-by: command-bot <> * Explain why `rusty-cachier` is put first (#11740) * Bump `wasmtime` to 0.38.0 and `zstd` to 0.11.2 (#11720) * Bump `wasmtime` to 0.37.0 and `zstd` to 0.11.2 * Bump `wasmtime` to 0.38.0 * Avoid a duplicate block request when syncing from a fork (#11094) * Separate queueing blocks for import from removal * Add regression tests * Remove unnecessary log * Clear queued blocks when processed * Move check out of match block * Track queued block ranges * Update client/network/sync/src/blocks.rs * Update client/network/sync/src/blocks.rs * Update client/network/sync/src/blocks.rs * Update client/network/sync/src/blocks.rs * FMT Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher * Democracy.fast_track not allowed with zero voting period (#11666) * Democracy.fast_track not allowed with zero voting period * revert static parameter alter line * ensure voting period greater zero * update doc for fast_track * unit test: instant fast track to the next block referendum is backed * fix typos in comments * Prevent unsoundness in environments with broken `madvise(MADV_DONTNEED)` (#11722) * Prevend unsoundness in environments with broken `madvise(MADV_DONTNEED)` * Add the `std` feature to `rustix` dependency Apparently not having this breaks compilation on non-nightly toolchains. * Autodetect the page size when checking whether `madvise` works * Only make sure that the madvice check doesn't return `Err` * Refund weight in `system::fillBlock` (#11754) * fix * pushed * node: fix fee multiplier test Co-authored-by: André Silva * nomination-pools fix (#11748) * Nomination pool fix * fmt * [ci] Remove polkadot-companion-labels GHA (#11774) * [contracts] Fixed the bug with transfer value for delegate call (#11771) * Fixed the bug with transfer value. * Apply suggestions from code review Co-authored-by: Alexander Theißen * Moved check into `initial_transfer` * Fmt Co-authored-by: Alexander Theißen * Fix clearing queued blocks in the sync module (#11763) * pallet-mmr: handle forks without collisions in offchain storage (#11594) * pallet-mmr: fix some typos * pallet-mmr: make the MMR resilient to chain forks * pallet-mmr: get hash for block that added node * beefy-mmr: add debug logging * add explanatory comment * account for block offset of pallet activation * add support for finding all nodes added by leaf * minor improvements * add helper to return all nodes added to mmr with a leaf append * simplify leaf_node_index_to_leaf_index summing the (shifted) differences in peak positions adds up to the (shifted) final position, so don't need to fold over positions. * dead fish: this also doesn't work The idea was to keep a rolling window of `(parent_hash, pos)` leaf entries in the offchain db, with the window matching the one that provides `block_num -> block_hash` mappings in `frame_system`. Once a leaf exits the window it would be "canonicalized" by switching its offchain db key from `(parent_hash, pos)` to simple `pos`. This doesn't work however because there's no way to get leaf contents from offchain db while in runtime context.. so no way to get+clear+set leaf to change its key in offchain db. Ideas: 1. move the "canonicalization" logic to offchain worker 2. enhance IndexingApi with "offchain::move(old_key, new_key)" This is weird, but correct, deterministic and safe AFAICT, so it could be exposed to runtime. * simplify rightmost_leaf_node_index_from_pos * minor fix * move leaf canonicalization to offchain worker * move storage related code to storage.rs * on offchain reads use canonic key for old leaves * fix offchain worker write using canon key * fix pallet-mmr tests * add documentation and fix logging * add offchain mmr canonicalization test * test canon + generate + verify * fix pallet-beefy-mmr tests * implement review suggestions * improve test * pallet-mmr: add offchain pruning of forks * pallet-mmr: improve offchain pruning Instead of keeping pruning map as single blob in offchain db, keep individual parent-hash lists with block-num identifier as part of the offchain key. Signed-off-by: acatangiu * pallet-mmr: improve MMRStore::get() Do the math and retrieve node using correct (canon or non-canon) offchain db key, instead of blindly looking in both canon and non-canon offchain db locations for each node. Still fallback on looking at both if for any reason it's not where expected. Signed-off-by: acatangiu * pallet-mmr: storage: improve logs * fix tests: correctly persist overlay runtime indexing API works on overlay, whereas offchain context bypasses overlay, so for loops > canon-window, canon would fail. * pallet-mmr: fix numeric typo in test * add comment around LeafData requirements Signed-off-by: acatangiu Co-authored-by: Robert Hambrock * expose grandpa BeforeBestBlockBy voting rule (#11798) * Un-deprecate Transactional Macro (#11807) * un-deprecate transactional macro * add transactional back to nomination pools * sync: Fixed clearing subsequent ranges (#11815) * sync: Fixed clearing subsequent ranges * Warp sync fix * Better documentation * CLI flag to configure tx ban duration (#11786) * add tx-ban-seconds * fix * trigger CI * trigger CI * remove test print * Update client/cli/src/params/transaction_pool_params.rs Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * Upgrade libp2p to 0.46.1 (#11787) * Update libp2p to 0.46.0 * Update libp2p to 0.46.1 * Fix telemetry initialization * Fix tests * prep council election pallet for being dissolved (#11790) * prep council election pallet for being dissolved + make it temporarily bounded * fix tests * fix * Update frame/elections-phragmen/src/lib.rs * fix bench? * Network sync refactoring (part 4) (#11412) * Remove direct dependency of `sc-network` on `sc-network-light` * Move `WarpSyncProvider` trait and surrounding data structures into `sc-network-common` * Move `WarpSyncProvider` trait and surrounding data structures into `sc-network-common` * Create `sync` module in `sc-network-common`, create `ChainSync` trait there (not used yet), move a bunch of associated data structures from `sc-network-sync` * Switch from concrete implementation to `ChainSync` trait from `sc-network-common` * Introduce `OpaqueStateRequest`/`OpaqueStateResponse` to remove generics from `StateSync` trait * Introduce `OpaqueBlockRequest`/`OpaqueBlockResponse`, make `scheme` module of `sc-network-sync` private * Surface `sc-network-sync` into `sc-service` and make `sc-network` not depend on it anymore * Remove now unnecessary dependency from `sc-network` * Replace crate links with just text since dependencies are gone now * Remove `warp_sync` re-export from `sc-network-common` * Update copyright in network-related files * Address review comments about documentation * Apply review suggestion * Rename `extra_requests` module to `metrics` Co-authored-by: Bastian Köcher * Fix off by one error in proportional slashing (#11782) * Fix proportional slashing logic * Update frame/nomination-pools/test-staking/src/lib.rs Co-authored-by: David * Update frame/staking/src/lib.rs Co-authored-by: David * Update frame/staking/src/lib.rs Co-authored-by: David * Update frame/staking/src/lib.rs Co-authored-by: David * fmt * Update frame/nomination-pools/test-staking/src/lib.rs * clean * fix * last fixes * doc Co-authored-by: David * Buy&Sell methods for Uniques (#11398) * Allow to set item's price * Clean the state when we transfer/burn an item or destroy a collection * Allow to buy an item * Remove redundant checks * Improve events * Cover with tests * Add comments * Apply suggestions * Fmt * Improvements for price validation * Improve validation * Update to use the new terminology * Remove multi-assets support * Chore * Weights + benchmarking * Shield against human error * Test when we pass the higher item's price * fmt fix * Chore * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_uniques --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/uniques/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Remove is_frozen check when setting the price * Try to fix benchmarking * Fix benchmarking * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_uniques --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/uniques/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Add transactional * Add 'allow deprecated' flag for transactional * Remove #[allow(deprecated)] * ".git/.scripts/bench-bot.sh" pallet dev pallet_uniques Co-authored-by: Parity Bot Co-authored-by: command-bot <> * Revamp nomination pool reward scheme (#11669) * make pool roles optional * undo lock file changes? * add migration * add the ability for pools to chill themselves * boilerplate of tests * somewhat stable, but I think I found another bug as well * Fix it all * Add more more sophisticated test + capture one more bug. * Update frame/staking/src/lib.rs * reduce the diff a little bit * add some test for the slashing bug * cleanup * fix lock file? * Fix * fmt * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/mock.rs Co-authored-by: Oliver Tale-Yazdi * Fix build * fix some fishy tests.. * add one last integrity check for MinCreateBond * remove bad assertion -- needs to be dealt with later * nits * fix tests and add benchmarks for chill * remove stuff * fix benchmarks * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_nomination_pools --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/nomination-pools/src/weights.rs --template=./.maintain/frame-weight-template.hbs * remove defensive * first working version * bring back all tests * ALL new tests work now * cleanup * make sure benchmarks and all work * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_nomination_pools --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/nomination-pools/src/weights.rs --template=./.maintain/frame-weight-template.hbs * round of self-review, make arithmetic safe * fix warn * add migration code * Fix doc * add precision notes * make arithmetic fallible * fix node runtime * a lot of precision tests and notes and stuff * document MaxPOintsToBalance better * :round of self-review * fmt * fix some comments * Fix proportional slashing logic * Update frame/nomination-pools/src/tests.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/tests.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * track poinst in migration * fix * fmt * fix migration * remove event read * Apply suggestions from code review * Update frame/staking/src/lib.rs Co-authored-by: Shawn Tabrizi * Update frame/nomination-pools/src/lib.rs Co-authored-by: Shawn Tabrizi * Update frame/nomination-pools/src/lib.rs Co-authored-by: Shawn Tabrizi * update * fmt * fmt * add one last test * fmt Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Shawn Tabrizi Co-authored-by: Parity Bot * Fix typo (#11832) * Fix nomination pools unbonding logic (#11746) * make pool roles optional * undo lock file changes? * add migration * add the ability for pools to chill themselves * boilerplate of tests * somewhat stable, but I think I found another bug as well * Fix it all * Add more more sophisticated test + capture one more bug. * Update frame/staking/src/lib.rs * reduce the diff a little bit * add some test for the slashing bug * cleanup * fix lock file? * Fix * fmt * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/mock.rs Co-authored-by: Oliver Tale-Yazdi * Fix build * fix some fishy tests.. * add one last integrity check for MinCreateBond * remove bad assertion -- needs to be dealt with later * nits * fix tests and add benchmarks for chill * remove stuff * fix benchmarks * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_nomination_pools --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/nomination-pools/src/weights.rs --template=./.maintain/frame-weight-template.hbs * remove defensive * first working version * bring back all tests * ALL new tests work now * cleanup * make sure benchmarks and all work * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_nomination_pools --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/nomination-pools/src/weights.rs --template=./.maintain/frame-weight-template.hbs * round of self-review, make arithmetic safe * fix warn * add migration code * Fix doc * add precision notes * make arithmetic fallible * fix node runtime * a lot of precision tests and notes and stuff * document MaxPOintsToBalance better * :round of self-review * fmt * fix some comments * new logic, some broken tests * Check if after unbonding remaining balance is more or equal to MinJoinBond and is not zero * incorporate nikos' work * make it work again * merge * Fix all tests * fix all tests * some updates * Add tests * remove erroneoysly placed comment * Try to make lint pass * Try to make lint pass * revamp the tests for unbond * fix docs * Fix proportional slashing logic * Update frame/nomination-pools/src/tests.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/tests.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * track poinst in migration * fix * fmt * fix migration * remove event read * Apply suggestions from code review * Update frame/nomination-pools/src/lib.rs Co-authored-by: Shawn Tabrizi * remove log * Update frame/staking/src/lib.rs Co-authored-by: Shawn Tabrizi * Update frame/nomination-pools/src/lib.rs Co-authored-by: Shawn Tabrizi * Update frame/nomination-pools/src/lib.rs Co-authored-by: Shawn Tabrizi * update * fmt * fmt * add one last test * fmrt * Update frame/nomination-pools/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/nomination-pools/src/tests.rs Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Shawn Tabrizi Co-authored-by: Parity Bot Co-authored-by: wirednkod * contracts: Composable `ChainExtension` (#11816) * Add `RegisteredChainExtension` * Add tests * Update frame/contracts/src/chain_extension.rs Co-authored-by: Michael Müller * Add more docs * Remove debugging leftover * Make ChainExtension-registry lowercase * Apply suggestions from code review Co-authored-by: Hernando Castano * Improve clarity of test inputs Co-authored-by: Michael Müller Co-authored-by: Hernando Castano * [ci] fix job `cancel-pipeline` (#11844) * [ci] fix cancel-pipeline job * test fail * remove debug * Speed up `rusty-cachier-notify` job (#11841) * Speed up `rusty-cachier-notify` job * Don't forget to setup `rusty-cachier` first * [ci] improvments to make pipeline faster (#11829) * [DO NOT MERGE] test-linux-stable parallel on 3 ci nodes * add debug message * adjust rusty-cachier * empty commit * move test-linux-stable to test.yml * make cargo-check-benches and test-wasmer-sandbox parallel * fix comment * Update scripts/ci/gitlab/pipeline/test.yml Co-authored-by: Denis Pisarev * Update scripts/ci/gitlab/pipeline/test.yml Co-authored-by: Denis Pisarev * if to case * use case instead if in cargo-check-benches * format * add comments to output * add comment * add quotes * Update scripts/ci/gitlab/pipeline/test.yml Co-authored-by: Denis Pisarev Co-authored-by: parity-processbot <> Co-authored-by: Denis Pisarev * Fixed sync target detection (#11817) * Fixed sync target detection * Always report sync_target metric * Clamp median across all peers * Ignore boot and reserved nodes with peer ID the same as in local node itself (#11851) * removed evaluation.rs (#11766) * removed evaluation.rs * no need for parent_hash * fix * assert noop notifies that storage has been mutated (#11805) * arrange node-template service (#11795) * make template more clear * fmt check_equivocation Co-authored-by: Bastian Köcher * Expose and link trie migration weights (#11775) * expose and link trie migration weights * actually limit to one trait * Run test on dummy weights * fmt Co-authored-by: Bastian Köcher * Improve `wasmtime` error reporting (#11856) * Improve `wasmtime` error reporting * cargo fmt * Fix invalid state transitions in pallet-bounties (#11630) * Pallet-bounty: disallow invalid state transitions * Fix tests: funding only at even block numbers * Fix benchmarks: bounties need to be funded * fix on_initialize Co-authored-by: Shawn Tabrizi * Disable the interest cache (#11854) * Disable the interest cache The feature is currently broken with the latest `tracing-core`. We will enable it again, when it is fixed upstream. * FMT * Add `benchmark extrinsic` command (#11456) * Benchmark extrinsic Signed-off-by: Oliver Tale-Yazdi * Reduce warmup and repeat Running this 1000 times with a full block takes ~33 minutes 🙈. Reducing it to ~3 minutes per default. Signed-off-by: Oliver Tale-Yazdi * Make ExistentialDeposit public Signed-off-by: Oliver Tale-Yazdi * Add 'bechmark extrinsic' command Signed-off-by: Oliver Tale-Yazdi * fmt Signed-off-by: Oliver Tale-Yazdi * Add --list and cleanup Signed-off-by: Oliver Tale-Yazdi * Unrelated Clippy Signed-off-by: Oliver Tale-Yazdi * Clippy Signed-off-by: Oliver Tale-Yazdi * Fix tests and doc Signed-off-by: Oliver Tale-Yazdi * Move implementations up + fmt Signed-off-by: Oliver Tale-Yazdi * Dont use parameter_types macro Signed-off-by: Oliver Tale-Yazdi * Cache to_lowercase() call The .to_lowercase() on the builder is actually not needes since its already documented to only return lower case. Signed-off-by: Oliver Tale-Yazdi * Spelling Signed-off-by: Oliver Tale-Yazdi * Use correct nightly for fmt... Signed-off-by: Oliver Tale-Yazdi * Rename ED Signed-off-by: Oliver Tale-Yazdi * Fix compile Signed-off-by: Oliver Tale-Yazdi * Subtract block base weight Signed-off-by: Oliver Tale-Yazdi * Fixes Signed-off-by: Oliver Tale-Yazdi * Use tmp folder for test This should already be the case since --dev is passed but somehow not... Signed-off-by: Oliver Tale-Yazdi * Fix test Signed-off-by: Oliver Tale-Yazdi * Don't download artifacts into the `rusty-cachier-notify` job (#11850) * Bump wasmtime default-pages (#11864) Signed-off-by: Oliver Tale-Yazdi * Make reading json genesis file faster (#11868) * Make reading json genesis file faster * Formatting * fmt * Cleanup light client leftovers (#11865) * Remove --light cli option * Cleanup light client leftovers * Remove commented-out code and clean-up more light client leftovers * Fix formatting with `cargo +nightly fmt` * Remove FIXME regarding db directory structure Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher * Stop RPC servers on drop (#11679) * Stop RPC servers on drop * Switch to existing wrappers that stop RPC servers * Apply formatting * [ci] Generate rustdocs without dependencies (#11885) * pallet-mmr: fix batch proof failures (#11840) * pallet-mmr: extend batch proof verification test covers all possible 2-leaf combinations now, including current verification failures that batch proof item count limit is too low sometimes. * raise upper bound on proof item number as described in https://github.com/paritytech/substrate/issues/11753#issuecomment-1179838174 * test for powerset of leaves * refactor batch proof verification test * test all batch proofs for mmr sizes up to n=13 * limit mmr size to reduce batch proof test duration * use saturating integer addition for proof check * extract common chain building in batch proof tests note: right now, since not killing old chain, it keeps growing by 7 blocks for every leaf selection (added after proof generation), hence heavier to compute. * only add blocks after a proof generation once * increase batch proof testing range * register offchain extensions only once * fmt & remove unused util * Clarify wrong bootnode peer ID error message (#11872) * Fix for 'note_applied_extrinsic' - consider also 'extract_actual_pays_fee' (#11849) * pallet-assets: Update docs (#11877) * Fix typo in limits.rs (#11894) alway -> always * [ci] fix node-bench-regression-guard job (#11901) * [Do not merge] [ci] debug node-bench-regression-guard * debug * fix artifacts path * add debug job * debug * debug * fix job, return pipeline * Remove unused leaves-set fields (#11895) * Remove unused leaves-set fields * Fix undo_import method Old leaf sould be inserted using the displaced number * Fix leaves count * Apply code review suggestions Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher * Add era to `Unbonded` event (#11770) * Add era to `Unbonded` event fixes #11749 * Fix missing tests * Add comment for `era` field in `Unbonded` struct. Co-authored-by: parity-processbot <> * remove FunctionOf (#11897) * remove FunctionOf * fix docs Co-authored-by: parity-processbot <> * contracts: Allow `ChainExtension::call()` to access `&mut self` (#11874) * Give chain extensions the ability to store some temporary values * Update frame/contracts/src/wasm/runtime.rs Co-authored-by: Hernando Castano * Rename func_id -> id * Replace `id` param by two functions on `env` Co-authored-by: Hernando Castano * Pruned duplicated dependencies (#11900) * Update comfy-table v5.0.1 => v6.0.0 Signed-off-by: koushiro * Update strum v0.23.0 => v0.24.1 Signed-off-by: koushiro * Update h2 v0.3.9 => v0.3.13 Signed-off-by: koushiro * Update file-per-thread-logger v0.1.4 => v0.1.5 Signed-off-by: koushiro * Update mio v0.8.0 => v0.8.4 Signed-off-by: koushiro * revert twox-hash Signed-off-by: koushiro * Update secp256k1 v0.21.2 => v0.24.0 Signed-off-by: koushiro * Fix typos (#11914) * Rpc for pending rewards (#11831) * rpc pending rewards * commit * remove unused imports * fix * fix * fmt * fix * fmt * fix * docs * docs & formatting * better formatting * temporary fix * error handling * fix? * fmt * use to_string * fmt * fixed error handling * fix * rpc added to client * Update Cargo.toml * Update Cargo.toml * fix wrong reward counter * expose function * move implementation * docs * docs * docs * Update lib.rs * Update lib.rs * unexpose functions * unused dependency * update Cargo.lock * Update frame/nomination-pools/src/lib.rs * Update lib.rs * Update lib.rs * Update frame/nomination-pools/rpc/runtime-api/src/lib.rs Co-authored-by: Bastian Köcher * remove rpc * remove rpc directory * final fix Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Bastian Köcher * [ci] remove cargo-check-nixos job (#11873) * [ci] remove cargo-check-nixos job * remove shell.nix * Prepare for rust 1.62.1 (#11903) * Update UI test output for rust 1.62.1 * switch ci to staging image to check that everything works * fix artifacts node-bench-regression-guard * Imeplement `scale_info::TypeInfo` manually to silence aggressive rust warning * Fix more clippy lints * Make clippy happy by relying on auto-deref were possible * Add tracking issue to the comments * pin ci image Co-authored-by: alvicsam * Properly defer slashes (#11823) * initial draft of fixing slashing * fix test * Update frame/staking/src/tests.rs Co-authored-by: Piotr Mikołajczyk * last touches * add more detail about unbonding * add migration * fmt Co-authored-by: Piotr Mikołajczyk Co-authored-by: parity-processbot <> * [ci] Return production image (#11920) * Make New Storage Layer Truly Default (#11918) * with storage layer truly default * fmt Co-authored-by: parity-processbot <> * Remove `retain_mut` crate (#11926) * Remove retain_mut crate * Remove reain_mut crate from babe-consensus * Fix slashing migration to v10 (#11924) * Fix slashing migration to v10 * add some logs * Fix default version * fmt * Move doc to struct Co-authored-by: Wilfried Kopp * Enrich the sync log on handling the block request (#11747) Add more info to the log to help debug the issue like https://github.com/paritytech/substrate/issues/11732. Co-authored-by: Bastian Köcher * Prevent double allocation of the payload when calling `sp_io::storage::get` (#11523) * Expose allocation stats in `FreeingBumpHeapAllocator` * Return allocation stats when calling into the runtime * Bump `parity-scale-codec` to 3.1.3 (fork) * Prevent double allocation of the payload when calling `sp_io::storage::get` * Fix tests * Remove unnecessary `mut` * Enable the `bytes` feature for `parity-scale-codec` in `sp-runtime-interface` * Update client/allocator/src/freeing_bump.rs Co-authored-by: Bastian Köcher * Bump `parity-scale-codec` to 3.1.3 * Fix some of the UI tests Co-authored-by: Bastian Köcher * construct_runtime!: Support parsing `struct Runtime` (#11932) * construct_runtime!: Support parsing `struct Runtime` * FMT * feat: add propose method for SimpleSlotWorker (#11692) * feat: add propose method for SimpleSlotWorker * remove param slot * improve code * fmt * Require Alliance Initialisation Before Joining (#11917) * require alliance initialisation before joining * use noop * make one definition of initialization * rename event * add todo comment * update doc * Integrate automatic update of substrate-node-template (#11931) * Integrate automatic update of substrate-node-template * Update scripts/ci/gitlab/pipeline/publish.yml Co-authored-by: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Co-authored-by: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> * Always allocate slots for reserved nodes (#11909) * Always allocate slots for reserved nodes * minor: replace no-slot peer counter with a set * Lean BEEFY to Full BEEFY - don't skip (older) mandatory blocks and import justifications (#11821) * client/beefy: don't accept vote for older rounds * client/beefy: clean up and reorg the worker struct * client/beefy: first step towards Full BEEFY The first step from Lean->Full BEEFY is to have the worker enforce uninterrupted line of BEEFY finalized mandatory blocks. There is one mandatory block per session (the first block in the session). As such, votes processing and votes generation now enforces that all mandatory blocks are finalized in strict monotonically increasing sequence and no block 'N' will be worked on if there is any GRANDPA finalized but BEEFY non-final mandatory block 'M', where 'M < N'. Implementation details: - Introduced 'VoterOracle' to separate the voting decisions logic, and track new/pending sessions. - New sessions get queued up with the worker operating either: 1. up-to-date - all mandatory blocks leading up to current GRANDPA finalized: queue has ONE element, the 'current session' where `mandatory_done == true`, 2. lagging behind GRANDPA: queue has [1, N] elements, where all `mandatory_done == false`. In this state, everytime a session gets its mandatory block BEEFY finalized, the session is popped off the queue, eventually getting to operating mode `1. up-to-date`. - Votes get triaged and those that fall withing the `VoterOracle` allowed window get processed, the others get dropped if stale, or buffered for later processing (when they reach the window). - Worker general code was also updated to fall in one of two roles: 1. react to external events and change internal 'state', 2. generate events/votes based on internal 'state'. Signed-off-by: acatangiu * client/beefy: sketch idea for block import and sync Signed-off-by: acatangiu * client/beefy: add BEEFY block import * client/beefy: process justifications from block import * client/beefy: add TODOs for sync protocol * client/beefy: add more docs and comments * client/beefy-rpc: fix RPC error * client/beefy: verify justification validity on block import * client/beefy: more tests * client/beefy: small fixes - first handle and note the self vote before gossiping it, - don't shortcircuit on err when processing pending votes. * client/beefy: remove invalid justifications at block import * todo: beefy block import tests * RFC: ideas for multiple justifications per block * Revert "RFC: ideas for multiple justifications per block" This reverts commit 8256fb07d3124db69daf252720b3c0208202624d. * client/beefy: append justif to backend on block import * client/beefy: groundwork for block import test * client/beefy: groundwork2 for block import test * client/beefy: groundwork3 for block import test * client/beefy: add block import test * client/beefy: add required trait bounds to block import builder * remove client from beefy block import, backend gets the job done Signed-off-by: acatangiu * Add Event to Pallet Asset-Tx-Payment (#11690) * Add Event to Pallet Asset-Tx-Payment * add asset_id into the Event Co-authored-by: parity-processbot <> * Network sync refactoring (part 5) (#11825) * Make `chain_sync` an explicit networking parameter instead of offering factory method * Derive `Copy` on `SyncMode` and remove cloning * feat: generalize ConsensusDataProvider for manual-seal (#11827) * feat: generalize ConsensusDataProvider for manual-seal * rename all generic type param `proof`/`PROOF` to `P` * rename a missing thing * Update client/consensus/manual-seal/src/consensus.rs Co-authored-by: Davide Galassi * Update client/consensus/manual-seal/src/consensus/babe.rs Co-authored-by: Davide Galassi * Update client/consensus/manual-seal/src/consensus/aura.rs Co-authored-by: Davide Galassi Co-authored-by: Davide Galassi * Auto-incremental CollectionId (#11796) * autoincrementing CollectionId * fix * benchmarking fix * fmt * fix * update before checking * fmt * fix * fmt * commit * tests & fix * fix * commit * docs * safe math * unexpose function * benchmark * fmt * better naming * fix? * merge fixes * fmt * ".git/.scripts/bench-bot.sh" pallet dev pallet_uniques * wrong weight * Update frame/uniques/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Update frame/uniques/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * using substrate trait instead of num-traits * remove unnecessary trait * emit NextCollectionIdIncremented in do_create_collection * fix in benchmarks * check for event & group import * docs Co-authored-by: Sergej Sakač Co-authored-by: command-bot <> Co-authored-by: Oliver Tale-Yazdi * remove unused staking trait bound (#11942) * Add and implement MaxEncodedLen to token traits (#11945) * Add and implement MaxEncodedLen bounds to token traits * cargo fmt * Update UI test expectations * Remove `remove_member_wrong_refund` from `phragmen` WeightInfo (#11952) * Remove 'remove_member_wrong_refund' from WeightInfo Signed-off-by: Oliver Tale-Yazdi * ".git/.scripts/bench-bot.sh" pallet dev pallet_elections_phragmen Co-authored-by: command-bot <> * Update the link to the runtime versioning topic (#11957) * fix(rpc middleware): fix `is_error` bug (#11951) * fix(rpc middleware): fix `is_error` bug * Update client/rpc-servers/src/middleware.rs * benchmarking f32 step calculation (#11890) * benchmark steps with f32 * divide by self.steps - 1 * avoid steps <= 1 * Fix step size Signed-off-by: Oliver Tale-Yazdi * Fix 'steps' print and print number of args Signed-off-by: Oliver Tale-Yazdi * Add Test Signed-off-by: Oliver Tale-Yazdi * fix comments * Remove unneeded comment Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Oliver Tale-Yazdi Co-authored-by: parity-processbot <> * [ci] chores: remove cargo install nextest (#11961) * Rename `node-runtime` to `node-kitchensink-runtime` (#11930) * Rename node=runtime to kithensink-runtime * Undo md formatting * rpc: Update jsonrpsee v0.15.1 (#11939) * Bump jsonrpsee to v0.15.1 Signed-off-by: Alexandru Vasile * Update cargo.lock Signed-off-by: Alexandru Vasile * rpc-servers: Adjust RpcMiddleware to WS and HTTP traits Signed-off-by: Alexandru Vasile * rpc/author: Use `SubscriptionSink` Signed-off-by: Alexandru Vasile * rpc/chain: Use `SubscriptionSink` Signed-off-by: Alexandru Vasile * rpc/state: Use `SubscriptionSink` Signed-off-by: Alexandru Vasile * rpc/finality-grandpa: Use `SubscriptionSink` Signed-off-by: Alexandru Vasile * rpc/beefy: Use `SubscriptionSink` Signed-off-by: Alexandru Vasile * client: Extract RPC string result from queries Signed-off-by: Alexandru Vasile * Apply rust-fmt Signed-off-by: Alexandru Vasile * Fix warnings Signed-off-by: Alexandru Vasile * Fix testing Signed-off-by: Alexandru Vasile * rpc/tests: Remove trailing comma Signed-off-by: Alexandru Vasile * rpc: Use `SubscriptionResult` for implementations Signed-off-by: Alexandru Vasile * rpc: Remove comment Signed-off-by: Alexandru Vasile * rpc: Delegate middleware calls to `RpcMiddleware` Signed-off-by: Alexandru Vasile * rpc: Remove comment Signed-off-by: Alexandru Vasile * Revert Cargo.lock Signed-off-by: Alexandru Vasile * Update Cargo.lock with minimal changes Signed-off-by: Alexandru Vasile * rpc: Update imports for `SubscriptionResult` Signed-off-by: Alexandru Vasile * Apply cargo fmt Signed-off-by: Alexandru Vasile * rpc/tests: Submit raw json requests to validate DenyUnsafe Signed-off-by: Alexandru Vasile * offences: make fn slash_fraction non-static (#11956) * offences: make fn slash_fraction non-static * Bastifmt (inline variable) * Revert non-best block (#11716) * Revert non-best block This makes `revert` also revert non-best blocks. * Update client/db/src/lib.rs * Do not count leaves against the maximum number to revert * Add some explanation * Fix bug * Apply suggestions from code review Co-authored-by: Davide Galassi Co-authored-by: Davide Galassi * Fix docs urls (#11966) * Fix docs urls * Update bin/node-template/README.md * Update frame/aura/src/lib.rs * Run cargo +nightly fmt Co-authored-by: Bastian Köcher * nit improvements to pallet template (#11968) * Update node-template's docker-compose.yml (#11802) * Update docker-compose.yml * Use production image Co-authored-by: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Co-authored-by: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Co-authored-by: parity-processbot <> * Beefy: use VersionedFinalityProof instead of SignedCommitment (#11962) * beefy: use VersionedFinalityProof instead of SignedCommitment. * Change the exposed RPC API to support versioned proofs. Co-authored-by: Adrian Catangiu * Timestamp: `set_timestamp` sets `DidUpdate` (#11960) * Timestamp: `set_timestamp` sets `DidUpdate` There exists the `set_timestamp` in the Timestamp pallet for setting the current timestamp. The problem is that it doesn't set `DidUpdate`. This results in `on_finalize` panicking. There is no real reason why the function doesn't also set `DidUpdate`. * Update frame/timestamp/src/lib.rs Co-authored-by: Oliver Tale-Yazdi * Fix Babe tests Co-authored-by: Oliver Tale-Yazdi * Prevent duplicated leaves in the backend (#11941) * Prevent duplicated leaves in the backend * Comments... * Use highest known heaf as a shortcut for not existing header detection * Apply code review suggestion Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher * Change on-the-wire protocol names to include genesis hash & fork id (#11938) * Rename transactions protocol to include genesis hash * Add protocol name generation to sc_network::utils * Use utils functions for transactions protocol name generation * Extract protocol name generation into public module * Use sc_network::protocol_name::standard_protocol_name() for BEEFY and GRANDPA * minor: add missing newline at EOF * Change block-announces protocol name to include genesis_hash & fork_id * Change protocol names to include genesis hash and fork id Protocols changed: - sync - state - light - sync/warp * Revert "Use sc_network::protocol_name::standard_protocol_name() for BEEFY and GRANDPA" This reverts commit 29aa556ef947e2cfd48264db2a9fc8bc528d7ddb. * Get rid of `protocol_name` module * `sync` protocol now can have negotiated fallback name (#11982) * system_syncState: Always return highest block (#11979) Before `highestBlock` was an optional that was omitted when it was `None`. We recently changed the way the `highestBlock` is determined, this resulted in having this value in 99.99% of the time being `None` when the node is syncing blocks at the tip. Now we always return a block for `highestBlock`. If sync doesn't return us any best seen block, we return our own local best block as `highestBlock`. This should mainly reflect the same behavior to before we changed the way the best seen block is determined. * Rename --pruning and --keep-blocks to be more similar to one another (#11934) * rename prunning and keep-blocks flags * Add aliases in keep-blocks and pruning for backward compatibility * Rename in code variables from and to and * Fix 16bit func_id (#11985) * chore: fix typos and sort trait impls (#11989) * contracts: Apply depth limit when decoding (#11991) * Restore `wasmtime`'s default stack size limit to 1MB (#11993) * Restore `wasmtime`'s default stack size limit to 1MB * Add extra comments * Enforce different maximum call depth in release mode * Split the call depth limit in two * Network sync refactoring (part 6) (#11940) * Extract `NetworkKVProvider` trait in `sc-authority-discovery` and remove unnecessary dependency * Extract `NetworkSyncForkRequest` trait in `sc-finality-grandpa` * Relax requirements on `SyncOracle` trait, remove extra native methods from `NetworkService` that are already provided by trait impls * Move `NetworkSigner` trait from `sc-authority-discovery` into `sc-network-common` and de-duplicate methods on `NetworkService` * Move `NetworkKVProvider` trait from `sc-authority-discovery` into `sc-network-common` and de-duplicate methods on `NetworkService` * Minimize `sc-authority-discovery` dependency on `sc-network` * Move `NetworkSyncForkRequest` trait from `sc-finality-grandpa` to `sc-network-common` and de-duplicate methods in `NetworkService` * Extract `NetworkStatusProvider` trait and de-duplicate methods on `NetworkService` * Extract `NetworkPeers` trait and de-duplicate methods on `NetworkService` * Extract `NetworkEventStream` trait and de-duplicate methods on `NetworkService` * Move more methods from `NetworkService` into `NetworkPeers` trait * Move `NetworkStateInfo` trait into `sc-network-common` * Extract `NetworkNotification` trait and de-duplicate methods on `NetworkService` * Extract `NetworkRequest` trait and de-duplicate methods on `NetworkService` * Remove `NetworkService::local_peer_id()`, it is already provided by `NetworkStateInfo` impl * Extract `NetworkTransaction` trait and de-duplicate methods on `NetworkService` * Extract `NetworkBlock` trait and de-duplicate methods on `NetworkService` * Remove dependencies on `NetworkService` from most of the methods of `sc-service` * Address simple review comments * Add BoundedVec::sort_by_key (#11998) Signed-off-by: Oliver Tale-Yazdi * Transaction payment runtime api: query call info and fee details (#11819) * Transaction payment RPC calls: query call info * transaction payment pallet - runtime api - add query_call info and fee_details * remove unused deps * separate call runtime api * undo fmt for unchanged code * system config call bounded to GetDispatchInfo, drop Call generic for query call info/fee * impl GetDispatchInfo for Extrinsics within runtime test-utils * introduced runtime api methods accept encoded Call instead of Call type * replace Bytes by Vec, docs for for new api, drop len argument, drop GetDispatchInfo bound from system_Config::Call * clean up toml and extra impl for dropped bound * panic if Call can not be decoded * revert to 6d0ca79 * fmt and docs * rustfmt * Use `#[pallet::unbounded]` tag in FRAME System (#11946) * use unbounded in system * update ui tests * transactional: Wrap `pallet::calls` directly in storage layers (#11927) * transactional: Wrap `pallet::calls` directly in storage layers Before this pr we only wrapped `pallet::calls` into storage layers when executing the calls with `dispatch`. This pr is solving that by wrapping each call function inside a storage layer. * Teach `BasicExternalities` transactions support * Fix crates * FMT * Fix benchmarking tests * Use correct span * Support old decl macros * Fix test * Apply suggestions from code review Co-authored-by: Oliver Tale-Yazdi * Update frame/state-trie-migration/src/lib.rs * Update frame/state-trie-migration/src/lib.rs * Update frame/state-trie-migration/src/lib.rs * Feedback * Apply suggestions from code review Co-authored-by: cheme Co-authored-by: Oliver Tale-Yazdi Co-authored-by: cheme * add substrate-ibc * remove something * format code * update readme * Delete Cargo.lock * Delete LICENSE * Delete Makefile * update readme * add license notion * format code * Reset Cargo.lock Signed-off-by: koushiro Signed-off-by: Oliver Tale-Yazdi Signed-off-by: Emison Lu Signed-off-by: acatangiu Signed-off-by: Alexandru Vasile Co-authored-by: Bastian Köcher Co-authored-by: Qinxuan Chen Co-authored-by: Alexander Theißen Co-authored-by: Nathan Whitaker <17734409+nathanwhit@users.noreply.github.com> Co-authored-by: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> Co-authored-by: Parity Bot Co-authored-by: Oliver Tale-Yazdi Co-authored-by: João Paulo Silva de Souza <77391175+joao-paulo-parity@users.noreply.github.com> Co-authored-by: Sergejs Kostjucenko <85877331+sergejparity@users.noreply.github.com> Co-authored-by: Koute Co-authored-by: kostekIV <27210860+kostekIV@users.noreply.github.com> Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Shawn Tabrizi Co-authored-by: Alexander Gryaznov Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Denis Pisarev Co-authored-by: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Co-authored-by: cheme Co-authored-by: Niklas Adolfsson Co-authored-by: James Wilson Co-authored-by: Keith Yeung Co-authored-by: Achim Schneider Co-authored-by: Davide Galassi Co-authored-by: Nazar Mokrynskyi Co-authored-by: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Co-authored-by: Gavin Wood Co-authored-by: Bastian Köcher Co-authored-by: yjh Co-authored-by: mikolaichuk <45576473+mikolaichuk@users.noreply.github.com> Co-authored-by: Vlad Co-authored-by: koenw Co-authored-by: Sacha Lansky Co-authored-by: MOZGIII Co-authored-by: Liu-Cheng Xu Co-authored-by: zqhxuyuan Co-authored-by: Sebastian Kunert Co-authored-by: Xiliang Chen Co-authored-by: joepetrowski Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Co-authored-by: Squirrel Co-authored-by: Tarek Mohamed Abdalla Co-authored-by: Yongjin Huang <20609724+doutv@users.noreply.github.com> Co-authored-by: Adrian Catangiu Co-authored-by: bear Co-authored-by: Leonardo <14614620+aardbol@users.noreply.github.com> Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> Co-authored-by: Georges Co-authored-by: kianenigma Co-authored-by: ZhiYong Co-authored-by: Boluwatife Bakre Co-authored-by: Roman Co-authored-by: Pierre Krieger Co-authored-by: Zhenghao Lu <54395432+EmisonLu@users.noreply.github.com> Co-authored-by: Ikko Ashimine Co-authored-by: Doordashcon Co-authored-by: Muharem Ismailov Co-authored-by: André Silva Co-authored-by: GreenBaneling | Supercolony Co-authored-by: Arkadiy Paronyan Co-authored-by: Robert Hambrock Co-authored-by: Andronik Co-authored-by: David Co-authored-by: Emre Surmeli Co-authored-by: wirednkod Co-authored-by: Michael Müller Co-authored-by: Hernando Castano Co-authored-by: lumir-mrkva Co-authored-by: Torsten Stüber Co-authored-by: Alan Sapede Co-authored-by: Dmitry Markin Co-authored-by: Branislav Kontur Co-authored-by: Falco Hirschenberger Co-authored-by: alvicsam Co-authored-by: Piotr Mikołajczyk Co-authored-by: Wilfried Kopp Co-authored-by: Mak Co-authored-by: ZhiYong Co-authored-by: Sergej Sakač Co-authored-by: lisa-parity <92225469+lisa-parity@users.noreply.github.com> Co-authored-by: bernardo Co-authored-by: lucasvanmol Co-authored-by: Kevin Wang Co-authored-by: Davirain --- Cargo.toml | 1 + frame/ibc/Cargo.toml | 84 +++ frame/ibc/README.md | 17 + frame/ibc/src/context.rs | 67 ++ frame/ibc/src/events.rs | 356 ++++++++++ frame/ibc/src/lib.rs | 672 ++++++++++++++++++ frame/ibc/src/mock.rs | 235 ++++++ frame/ibc/src/module/applications/mod.rs | 18 + .../module/applications/transfer/channel.rs | 302 ++++++++ .../src/module/applications/transfer/mod.rs | 288 ++++++++ .../transfer/transfer_handle_callback.rs | 178 +++++ frame/ibc/src/module/core/ics02_client.rs | 252 +++++++ frame/ibc/src/module/core/ics03_connection.rs | 128 ++++ frame/ibc/src/module/core/ics04_channel.rs | 542 ++++++++++++++ frame/ibc/src/module/core/ics05_port.rs | 41 ++ frame/ibc/src/module/core/ics24_host.rs | 272 +++++++ frame/ibc/src/module/core/ics26_routing.rs | 82 +++ frame/ibc/src/module/core/mod.rs | 23 + frame/ibc/src/module/mod.rs | 20 + frame/ibc/src/module/relayer/mod.rs | 64 ++ frame/ibc/src/tests.rs | 430 +++++++++++ frame/ibc/src/traits.rs | 27 + frame/ibc/src/utils.rs | 64 ++ 23 files changed, 4163 insertions(+) create mode 100644 frame/ibc/Cargo.toml create mode 100644 frame/ibc/README.md create mode 100644 frame/ibc/src/context.rs create mode 100644 frame/ibc/src/events.rs create mode 100644 frame/ibc/src/lib.rs create mode 100644 frame/ibc/src/mock.rs create mode 100644 frame/ibc/src/module/applications/mod.rs create mode 100644 frame/ibc/src/module/applications/transfer/channel.rs create mode 100644 frame/ibc/src/module/applications/transfer/mod.rs create mode 100644 frame/ibc/src/module/applications/transfer/transfer_handle_callback.rs create mode 100644 frame/ibc/src/module/core/ics02_client.rs create mode 100644 frame/ibc/src/module/core/ics03_connection.rs create mode 100644 frame/ibc/src/module/core/ics04_channel.rs create mode 100644 frame/ibc/src/module/core/ics05_port.rs create mode 100644 frame/ibc/src/module/core/ics24_host.rs create mode 100644 frame/ibc/src/module/core/ics26_routing.rs create mode 100644 frame/ibc/src/module/core/mod.rs create mode 100644 frame/ibc/src/module/mod.rs create mode 100644 frame/ibc/src/module/relayer/mod.rs create mode 100644 frame/ibc/src/tests.rs create mode 100644 frame/ibc/src/traits.rs create mode 100644 frame/ibc/src/utils.rs diff --git a/Cargo.toml b/Cargo.toml index 02bc6aede8669..66e69f71a7b08 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -157,6 +157,7 @@ members = [ "frame/utility", "frame/vesting", "frame/whitelist", + "frame/ibc", "primitives/api", "primitives/api/proc-macro", "primitives/api/test", diff --git a/frame/ibc/Cargo.toml b/frame/ibc/Cargo.toml new file mode 100644 index 0000000000000..15b11038342d5 --- /dev/null +++ b/frame/ibc/Cargo.toml @@ -0,0 +1,84 @@ +[package] +name = 'pallet-ibc' +version = "3.0.0-pre.0" +authors = ['Octopus Network '] +edition = '2021' +license = "Apache-2.0" +homepage = "https://docs.substrate.io/" +repository = "https://github.com/octopus-network/substrate-ibc/" +description = "An IBC implementation on Substrate." +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.2", default-features = false, features = ["derive"] } +log = { version = "0.4.0", default-features = false } +prost-types = { version = "0.11", default-features = false } +prost = { version = "0.11", default-features = false } +serde_json = { version = "1.0", default-features = false } +serde = { version = "1.0", default-features = false } +flex-error = { version = "0.4.4", default-features = false } +hex = {version = "0.4.0", default-features = false } + +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +sp-tracing = { version = "5.0.0", default-features = false, path = "../../primitives/tracing" } +time = { version = "0.3.11", features = ["macros","parsing"], default-features = false} + +ibc = { version = "0.18.0", default-features = false } +ibc-proto = { version = "0.20.0", default-features = false } +tendermint-proto = { version = "=0.23.9", default-features = false } + +frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } + +[dev-dependencies] +hex = '0.4.0' +sha2 = '0.10.2' +serde = { version = "1.0" } +ibc = { version = "0.18.0", features = ["mocks"] } +sp-io = { version = "6.0.0", path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", path = "../../primitives/std" } +sp-keyring = { version = "6.0.0", path = "../../primitives/keyring" } +frame-support = { version = "4.0.0-dev", path = "../support" } +pallet-assets = { version = "4.0.0-dev", path = "../assets" } +pallet-balances = { version = "4.0.0-dev", path = "../balances" } +pallet-timestamp = { version = "4.0.0-dev", path = "../timestamp" } +pallet-babe = { version = "4.0.0-dev", path = "../babe" } +sp-version = { version = "5.0.0", path = "../../primitives/version" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } +chrono = "0.4.19" + +[features] +default = ['std'] +std = [ + 'codec/std', + 'log/std', + "scale-info/std", + 'frame-benchmarking/std', + 'frame-support/std', + 'frame-system/std', + 'sp-core/std', + 'sp-runtime/std', + 'sp-std/std', + 'sp-io/std', + 'sp-tracing/std', + 'prost-types/std', + 'prost/std', + 'ibc/std', + 'ibc-proto/std', + 'serde_json/std', + 'serde/std', + 'flex-error/std', + 'hex/std', + 'time/std', +] +runtime-benchmarks = ["frame-benchmarking"] +try-runtime = ["frame-support/try-runtime"] \ No newline at end of file diff --git a/frame/ibc/README.md b/frame/ibc/README.md new file mode 100644 index 0000000000000..2bb71b0b97cd6 --- /dev/null +++ b/frame/ibc/README.md @@ -0,0 +1,17 @@ +# Substrate IBC Pallet (work in progress) + +This project is [funded by Interchain Foundation](https://interchain-io.medium.com/ibc-on-substrate-with-cdot-a7025e521028). + +## Overview + +This pallet implements the standard [IBC protocol](https://github.com/cosmos/ics). + +The goal of this pallet is to allow the blockchains built on Substrate to gain the ability to interact with other chains in a trustless way via IBC protocol. + +The pallet implements the chain specific logic of [ICS spec](https://github.com/cosmos/ibc/tree/51f0c9e8d8ebcbe6f7f023a8b80f65a8fab705e3/spec), and is integrated with [ibc-rs](https://github.com/informalsystems/ibc-rs), which implements the generic cross-chain logic in [ICS spec](https://github.com/cosmos/ibc/tree/51f0c9e8d8ebcbe6f7f023a8b80f65a8fab705e3/spec). + +## Interface + +### Dispatchable Functions +- `deliver` - This function acts as an entry for most of the IBC request. I.e., create clients, update clients, handshakes to create channels, ...etc +- `raw_transfer` - ICS20 fungible token transfer, Handling transfer request as sending chain or receiving chain. \ No newline at end of file diff --git a/frame/ibc/src/context.rs b/frame/ibc/src/context.rs new file mode 100644 index 0000000000000..8508e5e65c650 --- /dev/null +++ b/frame/ibc/src/context.rs @@ -0,0 +1,67 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://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. + +use crate::*; +use alloc::{ + borrow::{Borrow, Cow, ToOwned}, + collections::BTreeMap, + sync::Arc, +}; +use scale_info::TypeInfo; + +use crate::module::applications::transfer::transfer_handle_callback::TransferModule; +use ibc::{ + applications::transfer::{context::Ics20Context, error::Error as ICS20Error, MODULE_ID_STR}, + core::{ + ics04_channel::{ + channel::{Counterparty, Order}, + error::Error as Ics04Error, + Version, + }, + ics24_host::identifier::{ChannelId, ConnectionId, PortId}, + ics26_routing::context::{ + Ics26Context, Module, ModuleId, ModuleOutputBuilder, RouterBuilder, + }, + }, +}; + +use crate::module::core::ics26_routing::{Router, SubRouterBuilder}; + +/// A struct capturing all the functional dependencies (i.e., context) +/// which the ICS26 module requires to be able to dispatch and process IBC messages. +#[derive(Clone, Debug)] +pub struct Context { + pub _pd: PhantomData, + pub router: Router, +} + +impl Context { + pub fn new() -> Self { + let r = SubRouterBuilder::default() + .add_route(MODULE_ID_STR.parse().unwrap(), TransferModule(PhantomData::)) // register transfer Module + .unwrap() + .build(); + + Self { _pd: PhantomData::default(), router: r } + } +} + +impl Default for Context { + fn default() -> Self { + Self::new() + } +} diff --git a/frame/ibc/src/events.rs b/frame/ibc/src/events.rs new file mode 100644 index 0000000000000..92db60337f2d3 --- /dev/null +++ b/frame/ibc/src/events.rs @@ -0,0 +1,356 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://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. + +use crate::*; +use core::borrow::Borrow; +use ibc::{core::ics26_routing, events::IbcEvent as RawIbcEvent}; + +/// ibc-rs' `ModuleEvent` representation in substrate +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct ModuleEvent { + pub kind: Vec, + pub module_name: ModuleId, + pub attributes: Vec, +} + +impl From for ModuleEvent { + fn from(module_event: ibc::events::ModuleEvent) -> Self { + Self { + kind: module_event.kind.as_bytes().to_vec(), + module_name: module_event.module_name.into(), + attributes: module_event.attributes.into_iter().map(|event| event.into()).collect(), + } + } +} + +impl From for ibc::events::ModuleEvent { + fn from(module_event: ModuleEvent) -> Self { + Self { + kind: String::from_utf8(module_event.kind).expect("never failed"), + module_name: module_event.module_name.into(), + attributes: module_event.attributes.into_iter().map(|event| event.into()).collect(), + } + } +} + +/// ibc-rs' `ModuleId` representation in substrate +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct ModuleId(pub Vec); + +impl From for ModuleId { + fn from(module_id: ics26_routing::context::ModuleId) -> Self { + Self(format!("{}", module_id).as_bytes().to_vec()) + } +} + +impl From for ics26_routing::context::ModuleId { + fn from(module_id: ModuleId) -> Self { + ics26_routing::context::ModuleId::from_str( + &String::from_utf8(module_id.0).expect("Convert From UTF8 Never Faild"), + ) + .expect("should never fiaild") + } +} + +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct ModuleEventAttribute { + pub key: Vec, + pub value: Vec, +} + +impl From for ModuleEventAttribute { + fn from(module_event_attribute: ibc::events::ModuleEventAttribute) -> Self { + Self { + key: module_event_attribute.key.as_bytes().to_vec(), + value: module_event_attribute.value.as_bytes().to_vec(), + } + } +} + +impl From for ibc::events::ModuleEventAttribute { + fn from(module_event_attribute: ModuleEventAttribute) -> Self { + Self { + key: String::from_utf8(module_event_attribute.key).expect("should not be faild"), + value: String::from_utf8(module_event_attribute.value).expect("should not be faild"), + } + } +} + +impl From for Event { + fn from(value: RawIbcEvent) -> Self { + match value { + RawIbcEvent::NewBlock(value) => Event::::NewBlock { height: value.height.into() }, + RawIbcEvent::CreateClient(value) => { + let height = value.0.height; + let client_id = value.0.client_id; + let client_type = value.0.client_type; + let consensus_height = value.0.consensus_height; + Event::::CreateClient { + height: height.into(), + client_id: client_id.into(), + client_type: client_type.into(), + consensus_height: consensus_height.into(), + } + }, + RawIbcEvent::UpdateClient(value) => { + let height = value.common.height; + let client_id = value.common.client_id; + let client_type = value.common.client_type; + let consensus_height = value.common.consensus_height; + Event::::UpdateClient { + height: height.into(), + client_id: client_id.into(), + client_type: client_type.into(), + consensus_height: consensus_height.into(), + } + }, + // Upgrade client events are not currently being used + RawIbcEvent::UpgradeClient(value) => { + let height = value.0.height; + let client_id = value.0.client_id; + let client_type = value.0.client_type; + let consensus_height = value.0.consensus_height; + Event::::UpgradeClient { + height: height.into(), + client_id: client_id.into(), + client_type: client_type.into(), + consensus_height: consensus_height.into(), + } + }, + RawIbcEvent::ClientMisbehaviour(value) => { + let height = value.0.height; + let client_id = value.0.client_id; + let client_type = value.0.client_type; + let consensus_height = value.0.consensus_height; + Event::::ClientMisbehaviour { + height: height.into(), + client_id: client_id.into(), + client_type: client_type.into(), + consensus_height: consensus_height.into(), + } + }, + RawIbcEvent::OpenInitConnection(value) => { + let height = value.attributes().height; + let connection_id: Option = + value.attributes().connection_id.clone().map(|val| val.into()); + let client_id = value.attributes().client_id.clone(); + let counterparty_connection_id: Option = + value.attributes().counterparty_connection_id.clone().map(|val| val.into()); + + let counterparty_client_id = value.attributes().counterparty_client_id.clone(); + Event::::OpenInitConnection { + height: height.into(), + connection_id, + client_id: client_id.into(), + counterparty_connection_id, + counterparty_client_id: counterparty_client_id.into(), + } + }, + RawIbcEvent::OpenTryConnection(value) => { + let height = value.attributes().height; + let connection_id: Option = + value.attributes().connection_id.clone().map(|val| val.into()); + let client_id = value.attributes().client_id.clone(); + let counterparty_connection_id: Option = + value.attributes().counterparty_connection_id.clone().map(|val| val.into()); + + let counterparty_client_id = value.attributes().counterparty_client_id.clone(); + Event::::OpenTryConnection { + height: height.into(), + connection_id, + client_id: client_id.into(), + counterparty_connection_id, + counterparty_client_id: counterparty_client_id.into(), + } + }, + RawIbcEvent::OpenAckConnection(value) => { + let height = value.attributes().height; + let connection_id: Option = + value.attributes().connection_id.clone().map(|val| val.into()); + let client_id = value.attributes().client_id.clone(); + let counterparty_connection_id: Option = + value.attributes().counterparty_connection_id.clone().map(|val| val.into()); + + let counterparty_client_id = value.attributes().counterparty_client_id.clone(); + Event::::OpenAckConnection { + height: height.into(), + connection_id, + client_id: client_id.into(), + counterparty_connection_id, + counterparty_client_id: counterparty_client_id.into(), + } + }, + RawIbcEvent::OpenConfirmConnection(value) => { + let height = value.attributes().height; + let connection_id: Option = + value.attributes().connection_id.clone().map(|val| val.into()); + let client_id = value.attributes().client_id.clone(); + let counterparty_connection_id: Option = + value.attributes().counterparty_connection_id.clone().map(|val| val.into()); + + let counterparty_client_id = value.attributes().counterparty_client_id.clone(); + Event::::OpenConfirmConnection { + height: height.into(), + connection_id, + client_id: client_id.into(), + counterparty_connection_id, + counterparty_client_id: counterparty_client_id.into(), + } + }, + RawIbcEvent::OpenInitChannel(value) => { + let height = value.height; + let port_id = value.port_id.clone(); + let channel_id: Option = value.channel_id.clone().map(|val| val.into()); + let connection_id = value.connection_id.clone(); + let counterparty_port_id = value.counterparty_port_id.clone(); + let counterparty_channel_id: Option = + value.channel_id.map(|val| val.into()); + Event::::OpenInitChannel { + height: height.into(), + port_id: port_id.into(), + channel_id, + connection_id: connection_id.into(), + counterparty_port_id: counterparty_port_id.into(), + counterparty_channel_id, + } + }, + RawIbcEvent::OpenTryChannel(value) => { + let height = value.height; + let port_id = value.port_id.clone(); + let channel_id: Option = value.channel_id.clone().map(|val| val.into()); + let connection_id = value.connection_id.clone(); + let counterparty_port_id = value.counterparty_port_id.clone(); + let counterparty_channel_id: Option = + value.channel_id.map(|val| val.into()); + Event::::OpenTryChannel { + height: height.into(), + port_id: port_id.into(), + channel_id, + connection_id: connection_id.into(), + counterparty_port_id: counterparty_port_id.into(), + counterparty_channel_id, + } + }, + RawIbcEvent::OpenAckChannel(value) => { + let height = value.height; + let port_id = value.port_id.clone(); + let channel_id: Option = value.channel_id.clone().map(|val| val.into()); + let connection_id = value.connection_id.clone(); + let counterparty_port_id = value.counterparty_port_id.clone(); + let counterparty_channel_id: Option = + value.channel_id.map(|val| val.into()); + Event::::OpenAckChannel { + height: height.into(), + port_id: port_id.into(), + channel_id, + connection_id: connection_id.into(), + counterparty_port_id: counterparty_port_id.into(), + counterparty_channel_id, + } + }, + RawIbcEvent::OpenConfirmChannel(value) => { + let height = value.height; + let port_id = value.port_id.clone(); + let channel_id: Option = value.channel_id.clone().map(|val| val.into()); + let connection_id = value.connection_id.clone(); + let counterparty_port_id = value.counterparty_port_id; + let counterparty_channel_id: Option = + value.channel_id.map(|val| val.into()); + Event::::OpenConfirmChannel { + height: height.into(), + port_id: port_id.into(), + channel_id, + connection_id: connection_id.into(), + counterparty_port_id: counterparty_port_id.into(), + counterparty_channel_id, + } + }, + RawIbcEvent::CloseInitChannel(value) => { + let height = value.height; + let port_id = value.port_id.clone(); + let channel_id: Option = Some(value.channel_id.into()); + let connection_id = value.connection_id.clone(); + let counterparty_port_id = value.counterparty_port_id; + let counterparty_channel_id: Option = + value.counterparty_channel_id.map(|val| val.into()); + Event::::CloseInitChannel { + height: height.into(), + port_id: port_id.into(), + channel_id, + connection_id: connection_id.into(), + counterparty_port_id: counterparty_port_id.into(), + counterparty_channel_id, + } + }, + RawIbcEvent::CloseConfirmChannel(value) => { + let height = value.height; + let port_id = value.port_id.clone(); + let channel_id: Option = value.channel_id.clone().map(|val| val.into()); + let connection_id = value.connection_id.clone(); + let counterparty_port_id = value.counterparty_port_id.clone(); + let counterparty_channel_id: Option = + value.channel_id.map(|val| val.into()); + Event::::CloseConfirmChannel { + height: height.into(), + port_id: port_id.into(), + channel_id, + connection_id: connection_id.into(), + counterparty_port_id: counterparty_port_id.into(), + counterparty_channel_id, + } + }, + RawIbcEvent::SendPacket(value) => { + let height = value.height; + let packet = value.packet; + Event::::SendPacket { height: height.into(), packet: packet.into() } + }, + RawIbcEvent::ReceivePacket(value) => { + let height = value.height; + let packet = value.packet; + Event::::ReceivePacket { height: height.into(), packet: packet.into() } + }, + RawIbcEvent::WriteAcknowledgement(value) => { + let height = value.height; + let packet = value.packet; + let ack = value.ack; + + Event::::WriteAcknowledgement { + height: height.into(), + packet: packet.into(), + ack, + } + }, + RawIbcEvent::AcknowledgePacket(value) => { + let height = value.height; + let packet = value.packet; + Event::::AcknowledgePacket { height: height.into(), packet: packet.into() } + }, + RawIbcEvent::TimeoutPacket(value) => { + let height = value.height; + let packet = value.packet; + Event::::TimeoutPacket { height: height.into(), packet: packet.into() } + }, + RawIbcEvent::TimeoutOnClosePacket(value) => { + let height = value.height; + let packet = value.packet; + Event::::TimeoutOnClosePacket { height: height.into(), packet: packet.into() } + }, + RawIbcEvent::AppModule(value) => Event::::AppModule(value.into()), + RawIbcEvent::ChainError(value) => Event::::ChainError(value.as_bytes().to_vec()), + } + } +} diff --git a/frame/ibc/src/lib.rs b/frame/ibc/src/lib.rs new file mode 100644 index 0000000000000..867e0e7917542 --- /dev/null +++ b/frame/ibc/src/lib.rs @@ -0,0 +1,672 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://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. + +//! # Substrate IBC Pallet (work in progress) +//! +//! This project is [funded by Interchain Foundation](https://interchain-io.medium.com/ibc-on-substrate-with-cdot-a7025e521028). +//! +//! ## Overview +//! +//! This pallet implements the standard [IBC protocol](https://github.com/cosmos/ics). +//! +//! The goal of this pallet is to allow the blockchains built on Substrate to gain the ability to +//! interact with other chains in a trustless way via IBC protocol. +//! +//! The pallet implements the chain specific logic of [ICS spec](https://github.com/cosmos/ibc/tree/51f0c9e8d8ebcbe6f7f023a8b80f65a8fab705e3/spec), and is integrated with [ibc-rs](https://github.com/informalsystems/ibc-rs), which implements the generic cross-chain logic in [ICS spec](https://github.com/cosmos/ibc/tree/51f0c9e8d8ebcbe6f7f023a8b80f65a8fab705e3/spec). +//! +//! ## Interface +//! +//! ### Dispatchable Functions +//! - `deliver` - This function acts as an entry for most of the IBC request. I.e., create clients, +//! update clients, handshakes to create channels, ...etc +//! - `raw_transfer` - ICS20 fungible token transfer, Handling transfer request as sending chain or +//! receiving chain. + +#![cfg_attr(not(feature = "std"), no_std)] +// todo need in future to remove +#![allow(unreachable_code)] +#![allow(unreachable_patterns)] +#![allow(clippy::type_complexity)] +#![allow(non_camel_case_types)] +#![allow(dead_code)] +#![allow(unused_assignments)] +#![allow(unused_imports)] +#![allow(unused_variables)] +#![allow(clippy::too_many_arguments)] + +extern crate alloc; +extern crate core; + +pub use pallet::*; + +use alloc::{ + format, + string::{String, ToString}, +}; +use core::{marker::PhantomData, str::FromStr}; +use scale_info::{prelude::vec, TypeInfo}; +use serde::{Deserialize, Serialize}; + +use codec::{Codec, Decode, Encode}; + +use frame_support::{ + sp_runtime::traits::{AtLeast32BitUnsigned, CheckedConversion}, + sp_std::fmt::Debug, + traits::{tokens::fungibles, Currency, ExistenceRequirement::AllowDeath}, + PalletId, +}; +use frame_system::ensure_signed; +use sp_runtime::{traits::AccountIdConversion, DispatchError, RuntimeDebug, TypeId}; +use sp_std::prelude::*; + +use ibc::{ + applications::transfer::msgs::transfer::MsgTransfer, + core::{ + ics02_client::{client_state::AnyClientState, height}, + ics04_channel::timeout::TimeoutHeight, + ics24_host::identifier::{self, ChainId as ICS24ChainId, ChannelId as IbcChannelId}, + ics26_routing::msgs::Ics26Envelope, + }, + timestamp, + tx_msg::Msg, +}; + +use tendermint_proto::Protobuf; + +pub mod context; +pub mod events; +pub mod module; +pub mod traits; +pub mod utils; + +use crate::{context::Context, traits::AssetIdAndNameProvider}; + +use crate::module::core::ics24_host::{ + ChannelId, ClientId, ClientType, ConnectionId, Height, Packet, PortId, Timestamp, +}; + +pub const REVISION_NUMBER: u64 = 8888; + +type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; + +/// A struct corresponds to `Any` in crate "prost-types", used in ibc-rs. +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct Any { + pub type_url: Vec, + pub value: Vec, +} + +impl From for Any { + fn from(any: ibc_proto::google::protobuf::Any) -> Self { + Self { type_url: any.type_url.as_bytes().to_vec(), value: any.value } + } +} + +#[cfg(test)] +mod mock; + +#[cfg(test)] +mod tests; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use crate::{ + events::ModuleEvent, + module::{ + applications::transfer::transfer_handle_callback::TransferModule, + core::ics24_host::{ + ChannelId, ClientId, ClientType, ConnectionId, Height, Packet, PortId, Sequence, + Timestamp, + }, + }, + }; + use frame_support::{ + dispatch::DispatchResult, + pallet_prelude::*, + traits::{ + fungibles::{Inspect, Mutate, Transfer}, + UnixTime, + }, + }; + use frame_system::pallet_prelude::*; + use ibc::{ + applications::transfer::context::Ics20Context, + core::{ + ics02_client::client_consensus::AnyConsensusState, + ics04_channel::{ + channel::{Counterparty, Order}, + context::ChannelKeeper, + events::WriteAcknowledgement, + Version, + }, + ics24_host::{ + identifier::{ChannelId as IbcChannelId, PortId as IbcPortId}, + path::{ClientConsensusStatePath, ClientStatePath}, + }, + ics26_routing::error::Error as Ics26Error, + }, + events::IbcEvent, + handler::{HandlerOutput, HandlerOutputBuilder}, + signer::Signer, + }; + use sp_runtime::traits::IdentifyAccount; + + /// Configure the pallet by specifying the parameters and types on which it depends. + #[pallet::config] + pub trait Config: frame_system::Config + Sync + Send + Debug { + /// The overarching event type. + type Event: From> + IsType<::Event>; + + /// The provider providing timestamp of host chain + type TimeProvider: UnixTime; + + /// The currency type of the runtime + type Currency: Currency; + + /// Identifier for the class of asset. + type AssetId: Member + + Parameter + + AtLeast32BitUnsigned + + Codec + + Copy + + Debug + + Default + + MaybeSerializeDeserialize; + + /// The units in which we record balances. + type AssetBalance: Parameter + + Member + + AtLeast32BitUnsigned + + Codec + + Default + + From + + Into + + Copy + + MaybeSerializeDeserialize + + Debug; + + /// Expose customizable associated type of asset transfer, lock and unlock + type Assets: Transfer + + Mutate + + Inspect; + + /// Map of cross-chain asset ID & name + type AssetIdByName: AssetIdAndNameProvider; + + /// Account Id Conversion from SS58 string or hex string + type AccountIdConversion: TryFrom + + IdentifyAccount + + Clone + + PartialEq + + Debug; + + // The native token name + const NATIVE_TOKEN_NAME: &'static [u8]; + } + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] + pub struct Pallet(_); + + #[pallet::storage] + /// ClientStatePath(client_id) => ClientState + pub type ClientStates = + StorageMap<_, Blake2_128Concat, Vec, Vec, ValueQuery>; + + #[pallet::storage] + /// (client_id, height) => timestamp + pub type ClientProcessedTimes = StorageDoubleMap< + _, + Blake2_128Concat, + Vec, + Blake2_128Concat, + Vec, + Vec, + ValueQuery, + >; + + #[pallet::storage] + /// (client_id, height) => host_height + pub type ClientProcessedHeights = StorageDoubleMap< + _, + Blake2_128Concat, + Vec, + Blake2_128Concat, + Vec, + Vec, + ValueQuery, + >; + + #[pallet::storage] + /// ClientConsensusStatePath(client_id, Height) => ConsensusState + pub type ConsensusStates = + StorageMap<_, Blake2_128Concat, Vec, Vec, ValueQuery>; + + #[pallet::storage] + /// ConnectionsPath(connection_id) => ConnectionEnd + pub type Connections = StorageMap<_, Blake2_128Concat, Vec, Vec, ValueQuery>; + + #[pallet::storage] + /// ChannelEndPath(port_id, channel_id) => ChannelEnd + pub type Channels = StorageMap<_, Blake2_128Concat, Vec, Vec, ValueQuery>; + + #[pallet::storage] + /// ConnectionsPath(connection_id) => Vec + pub type ChannelsConnection = + StorageMap<_, Blake2_128Concat, Vec, Vec>, ValueQuery>; + + #[pallet::storage] + /// SeqSendsPath(port_id, channel_id) => sequence + pub type NextSequenceSend = + StorageMap<_, Blake2_128Concat, Vec, u64, ValueQuery>; + + #[pallet::storage] + /// SeqRecvsPath(port_id, channel_id) => sequence + pub type NextSequenceRecv = + StorageMap<_, Blake2_128Concat, Vec, u64, ValueQuery>; + + #[pallet::storage] + /// SeqAcksPath(port_id, channel_id) => sequence + pub type NextSequenceAck = StorageMap<_, Blake2_128Concat, Vec, u64, ValueQuery>; + + #[pallet::storage] + /// AcksPath(port_id, channel_id, sequence) => hash of acknowledgement + pub type Acknowledgements = + StorageMap<_, Blake2_128Concat, Vec, Vec, ValueQuery>; + + #[pallet::storage] + /// ClientTypePath(client_id) => client_type + pub type Clients = StorageMap<_, Blake2_128Concat, Vec, Vec, ValueQuery>; + + #[pallet::storage] + #[pallet::getter(fn client_counter)] + /// client counter + pub type ClientCounter = StorageValue<_, u64, ValueQuery>; + + #[pallet::storage] + #[pallet::getter(fn connection_counter)] + /// connection counter + pub type ConnectionCounter = StorageValue<_, u64, ValueQuery>; + + #[pallet::storage] + /// channel counter + pub type ChannelCounter = StorageValue<_, u64, ValueQuery>; + + #[pallet::storage] + /// ClientConnectionsPath(client_id) => connection_id + pub type ConnectionClient = + StorageMap<_, Blake2_128Concat, Vec, Vec, ValueQuery>; + + #[pallet::storage] + /// ReceiptsPath(port_id, channel_id, sequence) => receipt + pub type PacketReceipt = + StorageMap<_, Blake2_128Concat, Vec, Vec, ValueQuery>; + + #[pallet::storage] + /// CommitmentsPath(port_id, channel_id, sequence) => hash of (timestamp, height, packet) + pub type PacketCommitment = + StorageMap<_, Blake2_128Concat, Vec, Vec, ValueQuery>; + + #[pallet::storage] + /// (height, port_id, channel_id, sequence) => send-packet event + pub type SendPacketEvent = StorageNMap< + _, + ( + NMapKey>, + NMapKey>, + NMapKey, + ), + Vec, + ValueQuery, + >; + + #[pallet::storage] + /// (port_id, channel_id, sequence) => writ ack event + pub type WriteAckPacketEvent = StorageNMap< + _, + ( + NMapKey>, + NMapKey>, + NMapKey, + ), + Vec, + ValueQuery, + >; + + #[pallet::storage] + /// Latest height + pub type LatestHeight = StorageValue<_, Vec, ValueQuery>; + + #[pallet::storage] + /// Previous host block height + pub type OldHeight = StorageValue<_, u64, ValueQuery>; + + #[pallet::storage] + /// (asset name) => asset id + pub type AssetIdByName = + StorageMap<_, Twox64Concat, Vec, T::AssetId, ValueQuery>; + + #[pallet::genesis_config] + pub struct GenesisConfig { + pub asset_id_by_name: Vec<(String, T::AssetId)>, + } + + #[cfg(feature = "std")] + impl Default for GenesisConfig { + fn default() -> Self { + Self { asset_id_by_name: Vec::new() } + } + } + + #[pallet::genesis_build] + impl GenesisBuild for GenesisConfig { + fn build(&self) { + for (token_id, id) in self.asset_id_by_name.iter() { + >::insert(token_id.as_bytes(), id); + } + } + } + + /// Substrate IBC event list + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// New block + NewBlock { height: Height }, + /// Client Create + CreateClient { + height: Height, + client_id: ClientId, + client_type: ClientType, + consensus_height: Height, + }, + /// Client update + UpdateClient { + height: Height, + client_id: ClientId, + client_type: ClientType, + consensus_height: Height, + }, + /// Client upgraded + UpgradeClient { + height: Height, + client_id: ClientId, + client_type: ClientType, + consensus_height: Height, + }, + /// Client misbehaviour + ClientMisbehaviour { + height: Height, + client_id: ClientId, + client_type: ClientType, + consensus_height: Height, + }, + /// Connection open init + OpenInitConnection { + height: Height, + connection_id: Option, + client_id: ClientId, + counterparty_connection_id: Option, + counterparty_client_id: ClientId, + }, + /// Connection open try + OpenTryConnection { + height: Height, + connection_id: Option, + client_id: ClientId, + counterparty_connection_id: Option, + counterparty_client_id: ClientId, + }, + /// Connection open ack + OpenAckConnection { + height: Height, + connection_id: Option, + client_id: ClientId, + counterparty_connection_id: Option, + counterparty_client_id: ClientId, + }, + /// Connection open confirm + OpenConfirmConnection { + height: Height, + connection_id: Option, + client_id: ClientId, + counterparty_connection_id: Option, + counterparty_client_id: ClientId, + }, + /// Channel open init + OpenInitChannel { + height: Height, + port_id: PortId, + channel_id: Option, + connection_id: ConnectionId, + counterparty_port_id: PortId, + counterparty_channel_id: Option, + }, + /// Channel open try + OpenTryChannel { + height: Height, + port_id: PortId, + channel_id: Option, + connection_id: ConnectionId, + counterparty_port_id: PortId, + counterparty_channel_id: Option, + }, + /// Channel open ack + OpenAckChannel { + height: Height, + port_id: PortId, + channel_id: Option, + connection_id: ConnectionId, + counterparty_port_id: PortId, + counterparty_channel_id: Option, + }, + /// Channel open confirm + OpenConfirmChannel { + height: Height, + port_id: PortId, + channel_id: Option, + connection_id: ConnectionId, + counterparty_port_id: PortId, + counterparty_channel_id: Option, + }, + /// Channel close init + CloseInitChannel { + height: Height, + port_id: PortId, + channel_id: Option, + connection_id: ConnectionId, + counterparty_port_id: PortId, + counterparty_channel_id: Option, + }, + /// Channel close confirm + CloseConfirmChannel { + height: Height, + port_id: PortId, + channel_id: Option, + connection_id: ConnectionId, + counterparty_port_id: PortId, + counterparty_channel_id: Option, + }, + /// Send packet + SendPacket { height: Height, packet: Packet }, + /// Receive packet + ReceivePacket { height: Height, packet: Packet }, + /// WriteAcknowledgement packet + WriteAcknowledgement { height: Height, packet: Packet, ack: Vec }, + /// Acknowledgements packet + AcknowledgePacket { height: Height, packet: Packet }, + /// Timeout packet + TimeoutPacket { height: Height, packet: Packet }, + /// TimoutOnClose packet + TimeoutOnClosePacket { height: Height, packet: Packet }, + /// Chain error + ChainError(Vec), + /// App Module + AppModule(ModuleEvent), + /// Transfer native token + TransferNativeToken(T::AccountIdConversion, T::AccountIdConversion, BalanceOf), + /// Transfer non-native token + TransferNoNativeToken( + T::AccountIdConversion, + T::AccountIdConversion, + ::AssetBalance, + ), + /// Burn cross chain token + BurnToken(T::AssetId, T::AccountIdConversion, T::AssetBalance), + /// Mint chairperson token + MintToken(T::AssetId, T::AccountIdConversion, T::AssetBalance), + } + + /// Errors in MMR verification informing users that something went wrong. + #[pallet::error] + pub enum Error { + /// Invalid token id + InvalidTokenId, + /// Wrong assert id + WrongAssetId, + // Parser Msg Transfer Error + ParserMsgTransferError, + } + + /// Dispatchable functions allows users to interact with the pallet and invoke state changes. + /// These functions materialize as "extrinsic", which are often compared to transactions. + /// Dispatch able functions must be annotated with a weight and must return a DispatchResult. + #[pallet::call] + impl Pallet { + /// This function acts as an entry for most of the IBC request. + /// I.e., create clients, update clients, handshakes to create channels, ...etc + /// + /// The origin must be Signed and the sender must have sufficient funds fee. + /// + /// Parameters: + /// - `messages`: The arbitrary ICS message's representation in Substrate, which contains an + /// URL and + /// a serialized protocol buffer message. The URL name that uniquely identifies the type of + /// the serialized protocol buffer message. + /// + /// The relevant events are emitted when successful. + #[pallet::weight(0)] + pub fn deliver(origin: OriginFor, messages: Vec) -> DispatchResultWithPostInfo { + let _sender = ensure_signed(origin)?; + let mut ctx = Context::::new(); + + let messages: Vec = messages + .into_iter() + .map(|message| ibc_proto::google::protobuf::Any { + type_url: String::from_utf8(message.type_url.clone()) + .expect("Convert From UTF8 Never Faild"), + value: message.value, + }) + .collect(); + + for (_, message) in messages.clone().into_iter().enumerate() { + match ibc::core::ics26_routing::handler::deliver(&mut ctx, message.clone()) { + Ok(ibc::core::ics26_routing::handler::MsgReceipt { events, log: _log }) => { + // deposit events about send packet event and ics20 transfer event + for event in events { + Self::deposit_event(event.clone().into()); + } + }, + Err(error) => { + log::error!("deliver error : {:?} ", error); + }, + }; + } + + Ok(().into()) + } + + /// ICS20 fungible token transfer. + /// Handling transfer request as sending chain or receiving chain. + /// + /// Parameters: + /// - `messages`: A serialized protocol buffer message containing the transfer request. + /// + /// The relevant events are emitted when successful. + #[pallet::weight(0)] + pub fn raw_transfer( + origin: OriginFor, + messages: Vec, + ) -> DispatchResultWithPostInfo { + let _sender = ensure_signed(origin)?; + let mut ctx = TransferModule(PhantomData::); + + let messages: Vec = messages + .into_iter() + .map(|message| ibc_proto::google::protobuf::Any { + type_url: String::from_utf8(message.type_url.clone()) + .expect("Convert From UTF8 Never Faild"), + value: message.value, + }) + .collect(); + for message in messages { + let mut handle_out = HandlerOutputBuilder::new(); + let msg_transfer = MsgTransfer::try_from(message) + .map_err(|_| Error::::ParserMsgTransferError)?; + let result = ibc::applications::transfer::relay::send_transfer::send_transfer( + &mut ctx, + &mut handle_out, + msg_transfer, + ); + match result { + Ok(_value) => { + log::trace!("raw_transfer Successful!"); + }, + Err(error) => { + log::trace!("raw_transfer Error : {:?} ", error); + }, + } + + let HandlerOutput::<()> { result, log, events } = handle_out.with_result(()); + + // deposit events about send packet event and ics20 transfer event + for event in events { + Self::deposit_event(event.clone().into()); + } + } + + Ok(().into()) + } + } +} + +impl AssetIdAndNameProvider for Pallet { + type Err = Error; + + fn try_get_asset_id(name: impl AsRef<[u8]>) -> Result<::AssetId, Self::Err> { + let asset_id = >::try_get(name.as_ref().to_vec()); + match asset_id { + Ok(id) => Ok(id), + _ => Err(Error::::InvalidTokenId), + } + } + + fn try_get_asset_name(asset_id: T::AssetId) -> Result, Self::Err> { + let token_id = >::iter().find(|p| p.1 == asset_id).map(|p| p.0); + match token_id { + Some(id) => Ok(id), + _ => Err(Error::::WrongAssetId), + } + } +} + +pub fn from_channel_id_to_vec(value: IbcChannelId) -> Vec { + value.to_string().as_bytes().to_vec() +} diff --git a/frame/ibc/src/mock.rs b/frame/ibc/src/mock.rs new file mode 100644 index 0000000000000..2ce8fa8c563c6 --- /dev/null +++ b/frame/ibc/src/mock.rs @@ -0,0 +1,235 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://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. + +//! Test utilities + +use crate as pallet_ibc; +pub use frame_support::{ + construct_runtime, parameter_types, + traits::{ + ConstU128, ConstU16, ConstU32, ConstU8, KeyOwnerProofSystem, Randomness, StorageInfo, + }, + weights::{ + constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND}, + DispatchClass, IdentityFee, Weight, + }, + StorageValue, +}; +use frame_system as system; +use frame_system::{ + limits::{BlockLength, BlockWeights}, + EnsureRoot, +}; +use sp_core::{crypto::KeyTypeId, OpaqueMetadata, H256}; +use sp_runtime::{ + create_runtime_str, + generic::{self, Era}, + testing::Header, + traits::{AccountIdLookup, BlakeTwo256, IdentifyAccount, IdentityLookup, Verify}, + MultiSignature, +}; +use sp_version::RuntimeVersion; +use std::time::{Duration, Instant}; + +pub type Signature = MultiSignature; +pub(crate) type AccountId = <::Signer as IdentifyAccount>::AccountId; + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; + +// Configure a mock runtime to test the pallet. +construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system, + Assets: pallet_assets::, + Balances: pallet_balances, + Ibc: pallet_ibc, + } +); + +/// A hash of some data used by the chain. +pub type Hash = sp_core::H256; + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const SS58Prefix: u8 = 42; +} + +/// Index of a transaction in the chain. +pub type Index = u32; +/// An index to a block. +pub type BlockNumber = u32; + +impl frame_system::Config for Test { + /// The basic call filter to use in dispatchable. + type BaseCallFilter = frame_support::traits::Everything; + /// Block & extrinsics weights: base values and limits. + type BlockWeights = (); + /// The maximum length of a block (in bytes). + type BlockLength = (); + /// The identifier used to distinguish between accounts. + type AccountId = AccountId; + /// The aggregated dispatch type that is available for extrinsics. + type Call = Call; + /// The lookup mechanism to get account ID from whatever is passed in dispatchers. + type Lookup = AccountIdLookup; + /// The index type for storing how many extrinsics an account has signed. + type Index = Index; + /// The index type for blocks. + type BlockNumber = BlockNumber; + /// The type for hashing blocks and tries. + type Hash = Hash; + /// The hashing algorithm used. + type Hashing = BlakeTwo256; + /// The header type. + type Header = generic::Header; + /// The ubiquitous event type. + type Event = Event; + /// The ubiquitous origin type. + type Origin = Origin; + /// Maximum number of block number to block hash mappings to keep (oldest pruned first). + type BlockHashCount = (); + /// The weight of database operations that the runtime can invoke. + type DbWeight = (); + /// Version of the runtime. + type Version = (); + /// Converts a module to the index of the module in `construct_runtime!`. + /// + /// This type is being generated by `construct_runtime!`. + type PalletInfo = PalletInfo; + /// What to do if a new account is created. + type OnNewAccount = (); + /// What to do if an account is fully reaped from the system. + type OnKilledAccount = (); + /// The data to be stored in an account. + type AccountData = pallet_balances::AccountData; + /// Weight information for the extrinsics of this pallet. + type SystemWeightInfo = (); + /// This is used as an identifier of the chain. 42 is the generic substrate prefix. + type SS58Prefix = ConstU16<42>; + /// The set code logic, just the default since we're not a parachain. + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +pub type Balance = u128; +/// Type used for expressing timestamp. +pub type Moment = u64; + +pub const MILLICENTS: Balance = 10_000_000_000_000; +pub const CENTS: Balance = 1_000 * MILLICENTS; // assume this is worth about a cent. +pub const DOLLARS: Balance = 100 * CENTS; + +parameter_types! { + pub const AssetDeposit: Balance = 100 * DOLLARS; + pub const ApprovalDeposit: Balance = 1 * DOLLARS; + pub const StringLimit: u32 = 50; + pub const MetadataDepositBase: Balance = 10 * DOLLARS; + pub const MetadataDepositPerByte: Balance = 1 * DOLLARS; +} + +impl pallet_assets::Config for Test { + type Event = Event; + type Balance = AssetBalance; + type AssetId = AssetId; + type Currency = Balances; + type ForceOrigin = EnsureRoot; + type AssetDeposit = AssetDeposit; + type AssetAccountDeposit = ConstU128; + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type ApprovalDeposit = ApprovalDeposit; + type StringLimit = StringLimit; + type Freezer = (); + type Extra = (); + type WeightInfo = pallet_assets::weights::SubstrateWeight; +} + +parameter_types! { + pub const ExistentialDeposit: Balance = 1 * DOLLARS; + // For weight estimation, we assume that the most locks on an individual account will be 50. + // This number may need to be adjusted in the future if this assumption no longer holds true. + pub const MaxLocks: u32 = 50; + pub const MaxReserves: u32 = 50; +} + +impl pallet_balances::Config for Test { + type MaxLocks = MaxLocks; + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 8]; + /// The type for recording an account's balance. + type Balance = Balance; + /// The ubiquitous event type. + type Event = Event; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = frame_system::Pallet; + type WeightInfo = pallet_balances::weights::SubstrateWeight; +} + +parameter_types! { + pub const MinimumPeriod: Moment = SLOT_DURATION / 2; +} + +impl pallet_timestamp::Config for Test { + /// A timestamp: milliseconds since the unix epoch. + type Moment = Moment; + type OnTimestampSet = (); + type MinimumPeriod = MinimumPeriod; + type WeightInfo = (); +} + +parameter_types! { + pub const MaxAuthorities: u32 = 100; + pub const MaxKeys: u32 = 10_000; + pub const MaxPeerInHeartbeats: u32 = 10_000; + pub const MaxPeerDataEncodingSize: u32 = 1_000; +} + +pub const MILLISECS_PER_BLOCK: Moment = 6000; +pub const SECS_PER_BLOCK: Moment = MILLISECS_PER_BLOCK / 1000; + +// NOTE: Currently it is not possible to change the slot duration after the chain has started. +// Attempting to do so will brick block production. +pub const SLOT_DURATION: Moment = MILLISECS_PER_BLOCK; + +// 1 in 4 blocks (on average, not counting collisions) will be primary BABE blocks. +pub const PRIMARY_PROBABILITY: (u64, u64) = (1, 4); + +pub type AssetBalance = u128; +pub type AssetId = u32; + +impl super::pallet::Config for Test { + type Event = Event; + type TimeProvider = pallet_timestamp::Pallet; + type Currency = Balances; + type AssetId = AssetId; + type AssetBalance = AssetBalance; + type Assets = Assets; + type AssetIdByName = Ibc; + type AccountIdConversion = pallet_ibc::module::applications::transfer::IbcAccount; + const NATIVE_TOKEN_NAME: &'static [u8] = b"DEMO"; +} + +// Build genesis storage according to the mock runtime. +pub fn new_test_ext() -> sp_io::TestExternalities { + system::GenesisConfig::default().build_storage::().unwrap().into() +} diff --git a/frame/ibc/src/module/applications/mod.rs b/frame/ibc/src/module/applications/mod.rs new file mode 100644 index 0000000000000..dc8a5fa54cd3a --- /dev/null +++ b/frame/ibc/src/module/applications/mod.rs @@ -0,0 +1,18 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://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. + +pub mod transfer; diff --git a/frame/ibc/src/module/applications/transfer/channel.rs b/frame/ibc/src/module/applications/transfer/channel.rs new file mode 100644 index 0000000000000..7d116fff5e906 --- /dev/null +++ b/frame/ibc/src/module/applications/transfer/channel.rs @@ -0,0 +1,302 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://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. + +use super::transfer_handle_callback::TransferModule; +use crate::*; +use core::{str::FromStr, time::Duration}; +use log::{error, info, trace, warn}; + +use crate::context::Context; +use ibc::{ + core::{ + ics02_client::{ + client_consensus::AnyConsensusState, client_state::AnyClientState, + context::ClientReader, + }, + ics03_connection::{ + connection::ConnectionEnd, context::ConnectionReader, error::Error as ICS03Error, + }, + ics04_channel::{ + channel::ChannelEnd, + commitment::{ + AcknowledgementCommitment as IbcAcknowledgementCommitment, + PacketCommitment as IbcPacketCommitment, + }, + context::{ChannelKeeper, ChannelReader}, + error::Error as Ics04Error, + packet::{Receipt, Sequence}, + }, + ics05_port::{context::PortReader, error::Error as Ics05Error}, + ics24_host::{ + identifier::{ChannelId, ClientId, ConnectionId, PortId}, + path::{ + AcksPath, ChannelEndsPath, CommitmentsPath, ConnectionsPath, ReceiptsPath, + SeqAcksPath, SeqRecvsPath, SeqSendsPath, + }, + Path, + }, + ics26_routing::context::ModuleId, + }, + timestamp::Timestamp, + Height, +}; + +impl ChannelReader for TransferModule { + fn channel_end(&self, port_channel_id: &(PortId, ChannelId)) -> Result { + let connect = Context::::new(); + connect.channel_end(port_channel_id) + } + + fn connection_end(&self, connection_id: &ConnectionId) -> Result { + let connect = Context::::new(); + ChannelReader::connection_end(&connect, connection_id) + } + + /// Returns the `ChannelsConnection` for the given identifier `conn_id`. + fn connection_channels( + &self, + conn_id: &ConnectionId, + ) -> Result, Ics04Error> { + let connect = Context::::new(); + connect.connection_channels(conn_id) + } + + fn client_state(&self, client_id: &ClientId) -> Result { + let connect = Context::::new(); + + ChannelReader::client_state(&connect, client_id) + } + + fn client_consensus_state( + &self, + client_id: &ClientId, + height: Height, + ) -> Result { + let connect = Context::::new(); + ChannelReader::client_consensus_state(&connect, client_id, height) + } + + fn get_next_sequence_send( + &self, + port_channel_id: &(PortId, ChannelId), + ) -> Result { + let connect = Context::::new(); + connect.get_next_sequence_send(port_channel_id) + } + + fn get_next_sequence_recv( + &self, + port_channel_id: &(PortId, ChannelId), + ) -> Result { + let connect = Context::::new(); + connect.get_next_sequence_recv(port_channel_id) + } + + fn get_next_sequence_ack( + &self, + port_channel_id: &(PortId, ChannelId), + ) -> Result { + let connect = Context::::new(); + connect.get_next_sequence_ack(port_channel_id) + } + + /// Returns the `PacketCommitment` for the given identifier `(PortId, ChannelId, Sequence)`. + fn get_packet_commitment( + &self, + key: &(PortId, ChannelId, Sequence), + ) -> Result { + let connect = Context::::new(); + connect.get_packet_commitment(key) + } + + fn get_packet_receipt( + &self, + key: &(PortId, ChannelId, Sequence), + ) -> Result { + let connect = Context::::new(); + connect.get_packet_receipt(key) + } + + /// Returns the `Acknowledgements` for the given identifier `(PortId, ChannelId, Sequence)`. + fn get_packet_acknowledgement( + &self, + key: &(PortId, ChannelId, Sequence), + ) -> Result { + let connect = Context::::new(); + connect.get_packet_acknowledgement(key) + } + + /// A hashing function for packet commitments + fn hash(&self, value: Vec) -> Vec { + let connect = Context::::new(); + connect.hash(value) + } + + /// Returns the current height of the local chain. + fn host_height(&self) -> Height { + let connect = Context::::new(); + ChannelReader::host_height(&connect) + } + + /// Returns the current timestamp of the local chain. + fn host_timestamp(&self) -> Timestamp { + let connect = Context::::new(); + ChannelReader::host_timestamp(&connect) + } + + /// Returns the `AnyConsensusState` for the given identifier `height`. + fn host_consensus_state(&self, height: Height) -> Result { + let connect = Context::::new(); + ConnectionReader::host_consensus_state(&connect, height) + .map_err(Ics04Error::ics03_connection) + } + + fn pending_host_consensus_state(&self) -> Result { + let connect = Context::::new(); + ClientReader::pending_host_consensus_state(&connect) + .map_err(|e| Ics04Error::ics03_connection(ICS03Error::ics02_client(e))) + } + + /// Returns the `ClientProcessedTimes` for the given identifier `client_id` & `height`. + fn client_update_time( + &self, + client_id: &ClientId, + height: Height, + ) -> Result { + let connect = Context::::new(); + connect.client_update_time(client_id, height) + } + + fn client_update_height( + &self, + client_id: &ClientId, + height: Height, + ) -> Result { + let connect = Context::::new(); + connect.client_update_height(client_id, height) + } + + /// 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 { + let connect = Context::::new(); + connect.channel_counter() + } + + fn max_expected_time_per_block(&self) -> Duration { + let connect = Context::::new(); + connect.max_expected_time_per_block() + } +} + +impl ChannelKeeper for TransferModule { + fn store_packet_commitment( + &mut self, + key: (PortId, ChannelId, Sequence), + commitment: IbcPacketCommitment, + ) -> Result<(), Ics04Error> { + let mut connect = Context::::new(); + connect.store_packet_commitment(key, commitment) + } + + fn delete_packet_commitment( + &mut self, + key: (PortId, ChannelId, Sequence), + ) -> Result<(), Ics04Error> { + let mut connect = Context::::new(); + connect.delete_packet_commitment(key) + } + + fn store_packet_receipt( + &mut self, + key: (PortId, ChannelId, Sequence), + receipt: Receipt, + ) -> Result<(), Ics04Error> { + let mut connect = Context::::new(); + connect.store_packet_receipt(key, receipt) + } + + fn store_packet_acknowledgement( + &mut self, + key: (PortId, ChannelId, Sequence), + ack_commitment: IbcAcknowledgementCommitment, + ) -> Result<(), Ics04Error> { + let mut connect = Context::::new(); + + connect.store_packet_acknowledgement(key, ack_commitment) + } + + fn delete_packet_acknowledgement( + &mut self, + key: (PortId, ChannelId, Sequence), + ) -> Result<(), Ics04Error> { + let mut connect = Context::::new(); + connect.delete_packet_acknowledgement(key) + } + + fn store_connection_channels( + &mut self, + conn_id: ConnectionId, + port_channel_id: &(PortId, ChannelId), + ) -> Result<(), Ics04Error> { + let mut connect = Context::::new(); + connect.store_connection_channels(conn_id, port_channel_id) + } + + /// Stores the given channel_end at a path associated with the port_id and channel_id. + fn store_channel( + &mut self, + port_channel_id: (PortId, ChannelId), + channel_end: &ChannelEnd, + ) -> Result<(), Ics04Error> { + let mut connect = Context::::new(); + connect.store_channel(port_channel_id, channel_end) + } + + fn store_next_sequence_send( + &mut self, + port_channel_id: (PortId, ChannelId), + seq: Sequence, + ) -> Result<(), Ics04Error> { + let mut connect = Context::::new(); + connect.store_next_sequence_send(port_channel_id, seq) + } + + fn store_next_sequence_recv( + &mut self, + port_channel_id: (PortId, ChannelId), + seq: Sequence, + ) -> Result<(), Ics04Error> { + let mut connect = Context::::new(); + connect.store_next_sequence_recv(port_channel_id, seq) + } + + fn store_next_sequence_ack( + &mut self, + port_channel_id: (PortId, ChannelId), + seq: Sequence, + ) -> Result<(), Ics04Error> { + let mut connect = Context::::new(); + connect.store_next_sequence_ack(port_channel_id, seq) + } + + fn increase_channel_counter(&mut self) { + let mut connect = Context::::new(); + connect.increase_channel_counter() + } +} diff --git a/frame/ibc/src/module/applications/transfer/mod.rs b/frame/ibc/src/module/applications/transfer/mod.rs new file mode 100644 index 0000000000000..2c638c7f9d54f --- /dev/null +++ b/frame/ibc/src/module/applications/transfer/mod.rs @@ -0,0 +1,288 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://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. + +pub mod channel; +pub mod transfer_handle_callback; + +use crate::{context::Context, *}; +use frame_support::traits::{ + fungibles::{Mutate, Transfer}, + ExistenceRequirement::AllowDeath, +}; +use log::{error, trace}; + +use crate::utils::get_channel_escrow_address; +use ibc::{ + applications::transfer::{ + context::{BankKeeper, Ics20Context, Ics20Keeper, Ics20Reader}, + error::Error as Ics20Error, + PrefixedCoin, PORT_ID_STR, + }, + core::ics24_host::identifier::PortId, + signer::Signer, +}; +use sp_runtime::{ + traits::{CheckedConversion, IdentifyAccount, Verify}, + MultiSignature, +}; + +use transfer_handle_callback::TransferModule; + +impl Ics20Keeper for TransferModule { + type AccountId = ::AccountId; +} + +impl BankKeeper for TransferModule { + type AccountId = ::AccountId; + + fn send_coins( + &mut self, + from: &Self::AccountId, + to: &Self::AccountId, + amt: &PrefixedCoin, + ) -> Result<(), Ics20Error> { + // TODO(davirain): trace_path now is private + // let is_native_asset = amt.denom.trace_path().is_empty(); + let is_native_asset = true; + match is_native_asset { + // transfer native token + true => { + // TODO(davirain): amount now is private, and base_denom is private + // let amount = amt.amount.as_u256().low_u128().checked_into().expect("Convert MUST + // NOT Failed"); let ibc_token_name = amt.denom.base_denom().as_str().as_bytes(); + let amount = todo!(); + let ibc_token_name = &[1, 1, 2, 3]; + let native_token_name = T::NATIVE_TOKEN_NAME; + + // assert native token name equal want to send ibc token name + assert_eq!( + native_token_name, ibc_token_name, + "send ibc token name is not native token name" + ); + + >::transfer( + &from.clone().into_account(), + &to.clone().into_account(), + amount, + AllowDeath, + ) + .map_err(|error| { + error!("❌ [send_coins] : Error: ({:?})", error); + Ics20Error::invalid_token() + })?; + + // add emit transfer native token event + Pallet::::deposit_event(Event::::TransferNativeToken( + from.clone(), + to.clone(), + amount, + )) + }, + // transfer non-native token + false => { + // TODO(davirain): amount now is private, and base_denom is private + // let amount = amt.amount.as_u256().low_u128().into(); + // let denom = amt.denom.base_denom().as_str(); + let amount = todo!(); + let denom = &[1, 1, 2, 3]; + // look cross chain asset have register in host chain + match T::AssetIdByName::try_get_asset_id(denom) { + Ok(token_id) => { + >::transfer( + token_id.into(), + &from.clone().into_account(), + &to.clone().into_account(), + amount, + true, + ) + .map_err(|error| { + error!("❌ [send_coins] : Error: ({:?})", error); + Ics20Error::invalid_token() + })?; + + // add emit transfer no native token event + Pallet::::deposit_event(Event::::TransferNoNativeToken( + from.clone(), + to.clone(), + amount, + )); + }, + Err(_error) => { + error!("❌ [send_coins]: denom: ({:?})", denom); + return Err(Ics20Error::invalid_token()) + }, + } + }, + } + + Ok(()) + } + + fn mint_coins( + &mut self, + account: &Self::AccountId, + amt: &PrefixedCoin, + ) -> Result<(), Ics20Error> { + // TODO(davirain): amount now is private, and base_denom is private + // let amount = amt.amount.as_u256().low_u128().into(); + // let denom = amt.denom.base_denom().as_str(); + let amount = todo!(); + let denom = &[1, 1, 2, 3]; + // look cross chain asset have register in host chain + match T::AssetIdByName::try_get_asset_id(denom) { + Ok(token_id) => { + >::mint_into( + token_id.into(), + &account.clone().into_account(), + amount, + ) + .map_err(|error| { + error!("❌ [mint_coins] : Error: ({:?})", error); + Ics20Error::invalid_token() + })?; + + // add mint token event + Pallet::::deposit_event(Event::::MintToken( + token_id, + account.clone(), + amount, + )); + }, + Err(_error) => { + error!("❌ [mint_coins]: denom: ({:?})", denom); + return Err(Ics20Error::invalid_token()) + }, + } + Ok(()) + } + + fn burn_coins( + &mut self, + account: &Self::AccountId, + amt: &PrefixedCoin, + ) -> Result<(), Ics20Error> { + // TODO(davirain): amount now is private, and base_denom is private + // let amount = amt.amount.as_u256().low_u128().into(); + // let denom = amt.denom.base_denom().as_str(); + let amount = todo!(); + let denom = &[1, 1, 2, 3]; + // look cross chain asset have register in host chain + match T::AssetIdByName::try_get_asset_id(denom) { + Ok(token_id) => { + >::burn_from( + token_id.into(), + &account.clone().into_account(), + amount, + ) + .map_err(|error| { + error!("❌ [burn_coins] : Error: ({:?})", error); + Ics20Error::invalid_token() + })?; + + // add burn token event + Pallet::::deposit_event(Event::::BurnToken( + token_id, + account.clone(), + amount, + )); + }, + Err(_error) => { + error!("❌ [burn_coins]: denom: ({:?})", denom); + return Err(Ics20Error::invalid_token()) + }, + } + Ok(()) + } +} + +impl Ics20Reader for TransferModule { + type AccountId = ::AccountId; + + fn get_port(&self) -> Result { + PortId::from_str(PORT_ID_STR) + .map_err(|e| Ics20Error::invalid_port_id(PORT_ID_STR.to_string(), e)) + } + + fn get_channel_escrow_address( + &self, + port_id: &PortId, + channel_id: &IbcChannelId, + ) -> Result { + get_channel_escrow_address(port_id, channel_id)? + .try_into() + .map_err(|_| Ics20Error::parse_account_failure()) + } + + fn is_send_enabled(&self) -> bool { + // TODO(davirain), need according channelEnd def + true + } + + fn is_receive_enabled(&self) -> bool { + // TODO(davirain), need according channelEnd def + true + } +} + +impl Ics20Context for TransferModule { + type AccountId = ::AccountIdConversion; // Need Setting Account TODO(davirian) +} + +/// Alias to 512-bit hash when used in the context of a transaction signature on the chain. +pub type Signature = MultiSignature; + +/// Some way of identifying an account on the chain. We intentionally make it equivalent +/// to the public key of our transaction signing scheme. +pub type AccountId = <::Signer as IdentifyAccount>::AccountId; + +#[derive(Clone, Debug, PartialEq, TypeInfo, Encode, Decode)] +pub struct IbcAccount(AccountId); + +impl IdentifyAccount for IbcAccount { + type AccountId = AccountId; + fn into_account(self) -> Self::AccountId { + self.0 + } +} + +impl TryFrom for IbcAccount +where + AccountId: From<[u8; 32]>, +{ + type Error = &'static str; + + /// Convert a signer to an IBC account. + /// Only valid hex strings are supported for now. + fn try_from(signer: Signer) -> Result { + let acc_str = signer.as_ref(); + if acc_str.starts_with("0x") { + match acc_str.strip_prefix("0x") { + Some(hex_string) => TryInto::<[u8; 32]>::try_into( + hex::decode(hex_string).map_err(|_| "Error decoding invalid hex string")?, + ) + .map_err(|_| "Invalid account id hex string") + .map(|acc| Self(acc.into())), + _ => Err("Signer does not hold a valid hex string"), + } + } + // Do SS58 decoding instead + else { + error!("Convert Signer ❌ : Failed! "); + Err("invalid ibc address or substrate address") + } + } +} diff --git a/frame/ibc/src/module/applications/transfer/transfer_handle_callback.rs b/frame/ibc/src/module/applications/transfer/transfer_handle_callback.rs new file mode 100644 index 0000000000000..4abf0f625bba4 --- /dev/null +++ b/frame/ibc/src/module/applications/transfer/transfer_handle_callback.rs @@ -0,0 +1,178 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://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. + +use crate::*; + +use crate::utils::host_height; +use ibc::{ + applications::transfer::{acknowledgement::Acknowledgement, error::Error as Ics20Error}, + core::{ + ics04_channel::{ + channel::{Counterparty, Order}, + context::ChannelKeeper, + error::Error as Ics04Error, + msgs::acknowledgement::Acknowledgement as GenericAcknowledgement, + packet::{Packet as IbcPacket, PacketResult}, + Version, + }, + ics24_host::identifier::{ChannelId as IbcChannelId, ConnectionId, PortId}, + ics26_routing::context::{Module, ModuleOutputBuilder, OnRecvPacketAck}, + }, + events::IbcEvent, + signer::Signer, +}; + +/// A structure handling ICS20 callback +#[derive(Debug)] +pub struct TransferModule(pub PhantomData); + +impl Module for TransferModule { + fn on_chan_open_init( + &mut self, + output: &mut ModuleOutputBuilder, + order: Order, + connection_hops: &[ConnectionId], + port_id: &PortId, + channel_id: &IbcChannelId, + counterparty: &Counterparty, + version: &Version, + ) -> Result<(), Ics04Error> { + ibc::applications::transfer::context::on_chan_open_init( + self, + output, + order, + connection_hops, + port_id, + channel_id, + counterparty, + version, + ) + .map_err(|value| Ics04Error::app_module(value.to_string())) + } + + fn on_chan_open_try( + &mut self, + output: &mut ModuleOutputBuilder, + order: Order, + connection_hops: &[ConnectionId], + port_id: &PortId, + channel_id: &IbcChannelId, + counterparty: &Counterparty, + version: &Version, + counterparty_version: &Version, + ) -> Result { + ibc::applications::transfer::context::on_chan_open_try( + self, + output, + order, + connection_hops, + port_id, + channel_id, + counterparty, + version, + counterparty_version, + ) + .map_err(|value| Ics04Error::app_module(value.to_string())) + } + + fn on_chan_open_ack( + &mut self, + output: &mut ModuleOutputBuilder, + port_id: &PortId, + channel_id: &IbcChannelId, + counterparty_version: &Version, + ) -> Result<(), Ics04Error> { + ibc::applications::transfer::context::on_chan_open_ack( + self, + output, + port_id, + channel_id, + counterparty_version, + ) + .map_err(|value| Ics04Error::app_module(value.to_string())) + } + + fn on_chan_open_confirm( + &mut self, + output: &mut ModuleOutputBuilder, + port_id: &PortId, + channel_id: &IbcChannelId, + ) -> Result<(), Ics04Error> { + ibc::applications::transfer::context::on_chan_open_confirm( + self, output, port_id, channel_id, + ) + .map_err(|value| Ics04Error::app_module(value.to_string())) + } + + fn on_chan_close_init( + &mut self, + output: &mut ModuleOutputBuilder, + port_id: &PortId, + channel_id: &IbcChannelId, + ) -> Result<(), Ics04Error> { + ibc::applications::transfer::context::on_chan_close_init(self, output, port_id, channel_id) + .map_err(|value| Ics04Error::app_module(value.to_string())) + } + + fn on_chan_close_confirm( + &mut self, + output: &mut ModuleOutputBuilder, + port_id: &PortId, + channel_id: &IbcChannelId, + ) -> Result<(), Ics04Error> { + ibc::applications::transfer::context::on_chan_close_confirm( + self, output, port_id, channel_id, + ) + .map_err(|value| Ics04Error::app_module(value.to_string())) + } + + fn on_recv_packet( + &self, + output: &mut ModuleOutputBuilder, + packet: &IbcPacket, + relayer: &Signer, + ) -> OnRecvPacketAck { + ibc::applications::transfer::context::on_recv_packet(self, output, packet, relayer) + } + + fn on_acknowledgement_packet( + &mut self, + output: &mut ModuleOutputBuilder, + packet: &IbcPacket, + acknowledgement: &GenericAcknowledgement, + relayer: &Signer, + ) -> Result<(), Ics04Error> { + ibc::applications::transfer::context::on_acknowledgement_packet( + self, + output, + packet, + acknowledgement, + relayer, + ) + .map_err(|value| Ics04Error::app_module(value.to_string())) + } + + fn on_timeout_packet( + &mut self, + output: &mut ModuleOutputBuilder, + packet: &IbcPacket, + relayer: &Signer, + ) -> Result<(), Ics04Error> { + ibc::applications::transfer::context::on_timeout_packet(self, output, packet, relayer) + .map_err(|value| Ics04Error::app_module(value.to_string())) + } +} diff --git a/frame/ibc/src/module/core/ics02_client.rs b/frame/ibc/src/module/core/ics02_client.rs new file mode 100644 index 0000000000000..e555dec03d738 --- /dev/null +++ b/frame/ibc/src/module/core/ics02_client.rs @@ -0,0 +1,252 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://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. + +use crate::*; +use alloc::string::ToString; +use core::str::FromStr; +use log::{error, info, trace, warn}; + +use crate::context::Context; +use ibc::{ + core::{ + ics02_client::{ + client_consensus::AnyConsensusState, + client_state::AnyClientState, + client_type::ClientType, + context::{ClientKeeper, ClientReader}, + error::Error as Ics02Error, + }, + ics24_host::{ + identifier::ClientId, + path::{ClientConsensusStatePath, ClientStatePath, ClientTypePath}, + }, + }, + timestamp::Timestamp, + Height, +}; + +impl ClientReader for Context { + fn client_type(&self, client_id: &ClientId) -> Result { + let client_type_path = ClientTypePath(client_id.clone()).to_string().as_bytes().to_vec(); + if >::contains_key(client_type_path.clone()) { + let data = >::get(client_type_path); + let data = + String::from_utf8(data).map_err(|_| Ics02Error::implementation_specific())?; + ClientType::from_str(&data).map_err(|e| Ics02Error::unknown_client_type(e.to_string())) + } else { + Err(Ics02Error::client_not_found(client_id.clone())) + } + } + + fn client_state(&self, client_id: &ClientId) -> Result { + let client_state_path = ClientStatePath(client_id.clone()).to_string().as_bytes().to_vec(); + + if >::contains_key(&client_state_path) { + let data = >::get(&client_state_path); + AnyClientState::decode_vec(&*data).map_err(|_| Ics02Error::implementation_specific()) + } else { + Err(Ics02Error::client_not_found(client_id.clone())) + } + } + + fn consensus_state( + &self, + client_id: &ClientId, + height: Height, + ) -> Result { + // search key + let client_consensus_state_path = ClientConsensusStatePath { + client_id: client_id.clone(), + epoch: height.revision_number(), + height: height.revision_height(), + } + .to_string() + .as_bytes() + .to_vec(); + + if >::contains_key(client_consensus_state_path.clone()) { + let values = >::get(client_consensus_state_path.clone()); + AnyConsensusState::decode_vec(&*values) + .map_err(|_| Ics02Error::implementation_specific()) + } else { + Err(Ics02Error::consensus_state_not_found(client_id.clone(), height)) + } + } + + fn next_consensus_state( + &self, + client_id: &ClientId, + height: Height, + ) -> Result, Ics02Error> { + // search key + let client_consensus_state_path = ClientConsensusStatePath { + client_id: client_id.clone(), + epoch: height.revision_number(), + height: height.revision_height(), + } + .to_string() + .as_bytes() + .to_vec(); + + if >::contains_key(client_consensus_state_path.clone()) { + let values = >::get(client_consensus_state_path.clone()); + let any_consensus_state = AnyConsensusState::decode_vec(&*values) + .map_err(|_| Ics02Error::implementation_specific())?; + Ok(Some(any_consensus_state)) + } else { + Err(Ics02Error::consensus_state_not_found(client_id.clone(), height)) + } + } + + fn prev_consensus_state( + &self, + client_id: &ClientId, + height: Height, + ) -> Result, Ics02Error> { + // search key + let client_consensus_state_path = ClientConsensusStatePath { + client_id: client_id.clone(), + epoch: height.revision_number(), + height: height.revision_height(), + } + .to_string() + .as_bytes() + .to_vec(); + + if >::contains_key(client_consensus_state_path.clone()) { + let values = >::get(client_consensus_state_path.clone()); + let any_consensus_state = AnyConsensusState::decode_vec(&*values).unwrap(); + Ok(Some(any_consensus_state)) + } else { + Err(Ics02Error::consensus_state_not_found(client_id.clone(), height)) + } + } + + fn host_height(&self) -> Height { + let block_number = format!("{:?}", >::block_number()); + let current_height: u64 = block_number.parse().unwrap_or_default(); + Height::new(REVISION_NUMBER, current_height).expect("Contruct Heigjt Never failed") + } + + fn host_consensus_state(&self, _height: Height) -> Result { + todo!() + } + + fn pending_host_consensus_state(&self) -> Result { + todo!() + } + + fn client_counter(&self) -> Result { + Ok(>::get()) + } +} + +impl ClientKeeper for Context { + fn store_client_type( + &mut self, + client_id: ClientId, + client_type: ClientType, + ) -> Result<(), Ics02Error> { + let client_type_path = ClientTypePath(client_id.clone()).to_string().as_bytes().to_vec(); + let client_type = client_type.as_str().encode(); + >::insert(client_type_path, client_type); + Ok(()) + } + + fn store_client_state( + &mut self, + client_id: ClientId, + client_state: AnyClientState, + ) -> Result<(), Ics02Error> { + let client_state_path = ClientStatePath(client_id.clone()).to_string().as_bytes().to_vec(); + + let data = client_state.encode_vec().map_err(|_| Ics02Error::implementation_specific())?; + // store client states key-value + >::insert(client_state_path.clone(), data); + + Ok(()) + } + + fn store_consensus_state( + &mut self, + client_id: ClientId, + height: Height, + consensus_state: AnyConsensusState, + ) -> Result<(), Ics02Error> { + // store key + let client_consensus_state_path = ClientConsensusStatePath { + client_id: client_id.clone(), + epoch: height.revision_number(), + height: height.revision_height(), + } + .to_string() + .as_bytes() + .to_vec(); + + // store value + let consensus_state = consensus_state + .encode_vec() + .map_err(|_| Ics02Error::implementation_specific())?; + // store client_consensus_state path as key, consensus_state as value + >::insert(client_consensus_state_path, consensus_state); + + Ok(()) + } + + fn increase_client_counter(&mut self) { + let ret = >::try_mutate(|val| -> Result<(), Ics02Error> { + let new = val.checked_add(1).expect("Never Overflow"); + *val = new; + Ok(()) + }); + } + + fn store_update_time( + &mut self, + client_id: ClientId, + height: Height, + timestamp: Timestamp, + ) -> Result<(), Ics02Error> { + let encode_timestamp = serde_json::to_string(×tamp) + .map_err(|_| Ics02Error::implementation_specific())? + .as_bytes() + .to_vec(); + + >::insert( + client_id.as_bytes(), + height.encode_vec().map_err(|_| Ics02Error::implementation_specific())?, + encode_timestamp, + ); + + Ok(()) + } + + fn store_update_height( + &mut self, + client_id: ClientId, + height: Height, + host_height: Height, + ) -> Result<(), Ics02Error> { + >::insert( + client_id.as_bytes(), + height.encode_vec().map_err(|_| Ics02Error::implementation_specific())?, + host_height.encode_vec().map_err(|_| Ics02Error::implementation_specific())?, + ); + + Ok(()) + } +} diff --git a/frame/ibc/src/module/core/ics03_connection.rs b/frame/ibc/src/module/core/ics03_connection.rs new file mode 100644 index 0000000000000..82a9803cfa972 --- /dev/null +++ b/frame/ibc/src/module/core/ics03_connection.rs @@ -0,0 +1,128 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://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. + +use crate::*; + +use crate::context::Context; +use log::{error, info, trace, warn}; + +use ibc::{ + core::{ + ics02_client::{ + client_consensus::AnyConsensusState, client_state::AnyClientState, + context::ClientReader, + }, + ics03_connection::{ + connection::ConnectionEnd, + context::{ConnectionKeeper, ConnectionReader}, + error::Error as Ics03Error, + }, + ics23_commitment::commitment::CommitmentPrefix, + ics24_host::{ + identifier::{ClientId, ConnectionId}, + path::{ClientConnectionsPath, ConnectionsPath}, + }, + }, + Height, +}; + +impl ConnectionReader for Context { + fn connection_end(&self, conn_id: &ConnectionId) -> Result { + let connections_path = ConnectionsPath(conn_id.clone()).to_string().as_bytes().to_vec(); + + if >::contains_key(&connections_path) { + let data = >::get(&connections_path); + ConnectionEnd::decode_vec(&*data).map_err(|_| Ics03Error::implementation_specific()) + } else { + Err(Ics03Error::connection_mismatch(conn_id.clone())) + } + } + + fn client_state(&self, client_id: &ClientId) -> Result { + ClientReader::client_state(self, client_id).map_err(Ics03Error::ics02_client) + } + + fn host_current_height(&self) -> Height { + let block_number = format!("{:?}", >::block_number()); + let current_height: u64 = block_number.parse().unwrap_or_default(); + >::put(current_height); + Height::new(REVISION_NUMBER, current_height).expect("Contruct Height Never faild") + } + + fn host_oldest_height(&self) -> Height { + let height = >::get(); + Height::new(REVISION_NUMBER, height).expect("get host oldest height Never faild") + } + + fn commitment_prefix(&self) -> CommitmentPrefix { + "ibc".as_bytes().to_vec().try_into().unwrap_or_default() + } + + fn client_consensus_state( + &self, + client_id: &ClientId, + height: Height, + ) -> Result { + ClientReader::consensus_state(self, client_id, height).map_err(Ics03Error::ics02_client) + } + + fn host_consensus_state(&self, _height: Height) -> Result { + todo!() + } + + fn connection_counter(&self) -> Result { + Ok(>::get()) + } +} + +impl ConnectionKeeper for Context { + fn store_connection( + &mut self, + connection_id: ConnectionId, + connection_end: &ConnectionEnd, + ) -> Result<(), Ics03Error> { + let connections_path = + ConnectionsPath(connection_id.clone()).to_string().as_bytes().to_vec(); + let data = + connection_end.encode_vec().map_err(|_| Ics03Error::implementation_specific())?; + + // store connection end + >::insert(connections_path, data); + + Ok(()) + } + + fn store_connection_to_client( + &mut self, + connection_id: ConnectionId, + client_id: &ClientId, + ) -> Result<(), Ics03Error> { + let client_connection_paths = + ClientConnectionsPath(client_id.clone()).to_string().as_bytes().to_vec(); + + >::insert(client_connection_paths, connection_id.as_bytes().to_vec()); + Ok(()) + } + + fn increase_connection_counter(&mut self) { + let ret = >::try_mutate(|val| -> Result<(), Ics03Error> { + let new = val.checked_add(1).expect("Never Overflow"); + *val = new; + Ok(()) + }); + } +} diff --git a/frame/ibc/src/module/core/ics04_channel.rs b/frame/ibc/src/module/core/ics04_channel.rs new file mode 100644 index 0000000000000..b17a4a48dd6c4 --- /dev/null +++ b/frame/ibc/src/module/core/ics04_channel.rs @@ -0,0 +1,542 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://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. + +use crate::*; +use core::{str::FromStr, time::Duration}; +use log::{error, info, trace, warn}; + +use crate::context::Context; +use ibc::{ + core::{ + ics02_client::{ + client_consensus::AnyConsensusState, client_state::AnyClientState, + context::ClientReader, + }, + ics03_connection::{ + connection::ConnectionEnd, context::ConnectionReader, error::Error as ICS03Error, + }, + ics04_channel::{ + channel::ChannelEnd, + commitment::{ + AcknowledgementCommitment as IbcAcknowledgementCommitment, + PacketCommitment as IbcPacketCommitment, + }, + context::{ChannelKeeper, ChannelReader}, + error::Error as Ics04Error, + packet::{Receipt, Sequence}, + }, + ics05_port::{context::PortReader, error::Error as Ics05Error}, + ics24_host::{ + identifier::{ChannelId, ClientId, ConnectionId, PortId}, + path::{ + AcksPath, ChannelEndsPath, CommitmentsPath, ConnectionsPath, ReceiptsPath, + SeqAcksPath, SeqRecvsPath, SeqSendsPath, + }, + Path, + }, + ics26_routing::context::ModuleId, + }, + timestamp::Timestamp, + Height, +}; + +impl ChannelReader for Context { + fn channel_end(&self, port_channel_id: &(PortId, ChannelId)) -> Result { + let channel_end_path = + ChannelEndsPath(port_channel_id.0.clone(), port_channel_id.1.clone()) + .to_string() + .as_bytes() + .to_vec(); + + let data = >::get(channel_end_path); + + ChannelEnd::decode_vec(&*data).map_err(|_| { + Ics04Error::channel_not_found(port_channel_id.clone().0, port_channel_id.clone().1) + }) + } + + fn connection_end(&self, connection_id: &ConnectionId) -> Result { + ConnectionReader::connection_end(self, connection_id).map_err(Ics04Error::ics03_connection) + } + + /// Returns the `ChannelsConnection` for the given identifier `conn_id`. + fn connection_channels( + &self, + conn_id: &ConnectionId, + ) -> Result, Ics04Error> { + // store key + let connections_path = ConnectionsPath(conn_id.clone()).to_string().as_bytes().to_vec(); + + if >::contains_key(&connections_path) { + let channel_ends_paths = >::get(&connections_path); + + let mut result = vec![]; + + for item in channel_ends_paths.into_iter() { + let raw_path = + String::from_utf8(item).map_err(|_| Ics04Error::implementation_specific())?; + // decode key + let path = + Path::from_str(&raw_path).map_err(|_| Ics04Error::implementation_specific())?; + + if let Path::ChannelEnds(channel_ends_path) = path { + let ChannelEndsPath(port_id, channel_id) = channel_ends_path; + result.push((port_id, channel_id)); + } + } + + Ok(result) + } else { + Err(Ics04Error::connection_not_open(conn_id.clone())) + } + } + + fn client_state(&self, client_id: &ClientId) -> Result { + ClientReader::client_state(self, client_id) + .map_err(|_| Ics04Error::implementation_specific()) + } + + fn client_consensus_state( + &self, + client_id: &ClientId, + height: Height, + ) -> Result { + ClientReader::consensus_state(self, client_id, height) + .map_err(|_| Ics04Error::implementation_specific()) + } + + fn get_next_sequence_send( + &self, + port_channel_id: &(PortId, ChannelId), + ) -> Result { + let seq_sends_path = SeqSendsPath(port_channel_id.0.clone(), port_channel_id.1.clone()) + .to_string() + .as_bytes() + .to_vec(); + + if >::contains_key(&seq_sends_path) { + let sequence = >::get(&seq_sends_path); + Ok(Sequence::from(sequence)) + } else { + Err(Ics04Error::missing_next_send_seq(port_channel_id.clone())) + } + } + + fn get_next_sequence_recv( + &self, + port_channel_id: &(PortId, ChannelId), + ) -> Result { + let seq_recvs_path = SeqRecvsPath(port_channel_id.0.clone(), port_channel_id.1.clone()) + .to_string() + .as_bytes() + .to_vec(); + + if >::contains_key(&seq_recvs_path) { + let sequence = >::get(&seq_recvs_path); + + Ok(Sequence::from(sequence)) + } else { + Err(Ics04Error::missing_next_recv_seq(port_channel_id.clone())) + } + } + + fn get_next_sequence_ack( + &self, + port_channel_id: &(PortId, ChannelId), + ) -> Result { + let seq_acks_path = SeqAcksPath(port_channel_id.0.clone(), port_channel_id.1.clone()) + .to_string() + .as_bytes() + .to_vec(); + + if >::contains_key(&seq_acks_path) { + let sequence = >::get(&seq_acks_path); + + Ok(Sequence::from(sequence)) + } else { + Err(Ics04Error::missing_next_ack_seq(port_channel_id.clone())) + } + } + + /// Returns the `PacketCommitment` for the given identifier `(PortId, ChannelId, Sequence)`. + fn get_packet_commitment( + &self, + key: &(PortId, ChannelId, Sequence), + ) -> Result { + let packet_commitments_path = CommitmentsPath { + port_id: key.0.clone(), + channel_id: key.1.clone(), + sequence: key.2.clone(), + } + .to_string() + .as_bytes() + .to_vec(); + + if >::contains_key(&packet_commitments_path) { + let data = >::get(&packet_commitments_path); + + let packet_commitment = IbcPacketCommitment::from(data); + + Ok(packet_commitment) + } else { + Err(Ics04Error::packet_commitment_not_found(key.2)) + } + } + + fn get_packet_receipt( + &self, + key: &(PortId, ChannelId, Sequence), + ) -> Result { + let packet_receipt_path = ReceiptsPath { + port_id: key.0.clone(), + channel_id: key.1.clone(), + sequence: key.2.clone(), + } + .to_string() + .as_bytes() + .to_vec(); + + if >::contains_key(&packet_receipt_path) { + let data = >::get(&packet_receipt_path); + let data = + String::from_utf8(data).map_err(|_| Ics04Error::implementation_specific())?; + let data = match data.as_ref() { + "Ok" => Receipt::Ok, + _ => unreachable!(), + }; + Ok(data) + } else { + Err(Ics04Error::packet_receipt_not_found(key.2)) + } + } + + /// Returns the `Acknowledgements` for the given identifier `(PortId, ChannelId, Sequence)`. + fn get_packet_acknowledgement( + &self, + key: &(PortId, ChannelId, Sequence), + ) -> Result { + let acks_path = + AcksPath { port_id: key.0.clone(), channel_id: key.1.clone(), sequence: key.2.clone() } + .to_string() + .as_bytes() + .to_vec(); + + if >::contains_key(&acks_path) { + let data = >::get(&acks_path); + + let acknowledgement = IbcAcknowledgementCommitment::from(data); + Ok(acknowledgement) + } else { + Err(Ics04Error::packet_acknowledgement_not_found(key.2)) + } + } + + /// A hashing function for packet commitments + fn hash(&self, value: Vec) -> Vec { + sp_io::hashing::sha2_256(&value).to_vec() + } + + /// Returns the current height of the local chain. + fn host_height(&self) -> Height { + //todo this can improve + let block_number = format!("{:?}", >::block_number()); + let current_height: u64 = block_number.parse().unwrap_or_default(); + + Height::new(REVISION_NUMBER, current_height).expect("Contruct Height Never Faild") + } + + /// Returns the current timestamp of the local chain. + fn host_timestamp(&self) -> Timestamp { + use frame_support::traits::UnixTime; + let time = T::TimeProvider::now(); + + Timestamp::from_nanoseconds(time.as_nanos() as u64).expect("Convert Timestamp Never Faild") + } + + /// Returns the `AnyConsensusState` for the given identifier `height`. + fn host_consensus_state(&self, height: Height) -> Result { + ConnectionReader::host_consensus_state(self, height).map_err(Ics04Error::ics03_connection) + } + + fn pending_host_consensus_state(&self) -> Result { + ClientReader::pending_host_consensus_state(self) + .map_err(|e| Ics04Error::ics03_connection(ICS03Error::ics02_client(e))) + } + + /// Returns the `ClientProcessedTimes` for the given identifier `client_id` & `height`. + fn client_update_time( + &self, + client_id: &ClientId, + height: Height, + ) -> Result { + if >::contains_key( + client_id.as_bytes(), + height.encode_vec().map_err(|_| Ics04Error::implementation_specific())?, + ) { + let time = >::get( + client_id.as_bytes(), + height.encode_vec().map_err(|_| Ics04Error::implementation_specific())?, + ); + let timestamp = + String::from_utf8(time).map_err(|_| Ics04Error::implementation_specific())?; + let time: Timestamp = serde_json::from_str(×tamp) + .map_err(|_| Ics04Error::implementation_specific())?; + Ok(time) + } else { + Err(Ics04Error::processed_time_not_found(client_id.clone(), height)) + } + } + + fn client_update_height( + &self, + client_id: &ClientId, + height: Height, + ) -> Result { + if >::contains_key( + client_id.as_bytes(), + height.encode_vec().map_err(|_| Ics04Error::implementation_specific())?, + ) { + let host_height = >::get( + client_id.as_bytes(), + height.encode_vec().map_err(|_| Ics04Error::implementation_specific())?, + ); + Height::decode(&mut &host_height[..]).map_err(|_| Ics04Error::implementation_specific()) + } else { + Err(Ics04Error::processed_height_not_found(client_id.clone(), height)) + } + } + + /// 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 { + Ok( as Store>::ChannelCounter::get()) + } + + fn max_expected_time_per_block(&self) -> Duration { + Duration::from_secs(6) + } +} + +impl ChannelKeeper for Context { + fn store_packet_commitment( + &mut self, + key: (PortId, ChannelId, Sequence), + commitment: IbcPacketCommitment, + ) -> Result<(), Ics04Error> { + let packet_commitments_path = CommitmentsPath { + port_id: key.0.clone(), + channel_id: key.1.clone(), + sequence: key.2.clone(), + } + .to_string() + .as_bytes() + .to_vec(); + + // insert packet commitment key-value + >::insert(packet_commitments_path, commitment.into_vec()); + + Ok(()) + } + + fn delete_packet_commitment( + &mut self, + key: (PortId, ChannelId, Sequence), + ) -> Result<(), Ics04Error> { + let packet_commitments_path = CommitmentsPath { + port_id: key.0.clone(), + channel_id: key.1.clone(), + sequence: key.2.clone(), + } + .to_string() + .as_bytes() + .to_vec(); + + // delete packet commitment + >::remove(&packet_commitments_path); + + Ok(()) + } + + fn store_packet_receipt( + &mut self, + key: (PortId, ChannelId, Sequence), + receipt: Receipt, + ) -> Result<(), Ics04Error> { + let packet_receipt_path = ReceiptsPath { + port_id: key.0.clone(), + channel_id: key.1.clone(), + sequence: key.2.clone(), + } + .to_string() + .as_bytes() + .to_vec(); + + let receipt = match receipt { + Receipt::Ok => "Ok".as_bytes().to_vec(), + }; + + >::insert(packet_receipt_path, receipt); + + Ok(()) + } + + fn store_packet_acknowledgement( + &mut self, + key: (PortId, ChannelId, Sequence), + ack_commitment: IbcAcknowledgementCommitment, + ) -> Result<(), Ics04Error> { + let acks_path = + AcksPath { port_id: key.0.clone(), channel_id: key.1.clone(), sequence: key.2.clone() } + .to_string() + .as_bytes() + .to_vec(); + + // store packet acknowledgement key-value + >::insert(&acks_path, ack_commitment.into_vec()); + + Ok(()) + } + + fn delete_packet_acknowledgement( + &mut self, + key: (PortId, ChannelId, Sequence), + ) -> Result<(), Ics04Error> { + let acks_path = + AcksPath { port_id: key.0.clone(), channel_id: key.1.clone(), sequence: key.2.clone() } + .to_string() + .as_bytes() + .to_vec(); + + // remove acknowledgements + >::remove(&acks_path); + + Ok(()) + } + + fn store_connection_channels( + &mut self, + conn_id: ConnectionId, + port_channel_id: &(PortId, ChannelId), + ) -> Result<(), Ics04Error> { + // store key + let connections_path = ConnectionsPath(conn_id.clone()).to_string().as_bytes().to_vec(); + + // store value + let channel_ends_path = + ChannelEndsPath(port_channel_id.0.clone(), port_channel_id.1.clone()) + .to_string() + .as_bytes() + .to_vec(); + + if >::contains_key(&connections_path) { + // if connection_id exist + >::try_mutate( + &connections_path, + |val| -> Result<(), Ics04Error> { + val.push(channel_ends_path.clone()); + Ok(()) + }, + ) + .expect("channels Connection mutate Error") + } else { + >::insert(connections_path, vec![channel_ends_path]); + } + + Ok(()) + } + + /// Stores the given channel_end at a path associated with the port_id and channel_id. + fn store_channel( + &mut self, + port_channel_id: (PortId, ChannelId), + channel_end: &ChannelEnd, + ) -> Result<(), Ics04Error> { + let channel_end_path = + ChannelEndsPath(port_channel_id.0.clone(), port_channel_id.1.clone()) + .to_string() + .as_bytes() + .to_vec(); + let channel_end = + channel_end.encode_vec().map_err(|_| Ics04Error::implementation_specific())?; + + // store channels key-value + >::insert(channel_end_path, channel_end); + + Ok(()) + } + + fn store_next_sequence_send( + &mut self, + port_channel_id: (PortId, ChannelId), + seq: Sequence, + ) -> Result<(), Ics04Error> { + let seq_sends_path = SeqSendsPath(port_channel_id.0.clone(), port_channel_id.1.clone()) + .to_string() + .as_bytes() + .to_vec(); + + let sequence = u64::from(seq); + + >::insert(seq_sends_path, sequence); + + Ok(()) + } + + fn store_next_sequence_recv( + &mut self, + port_channel_id: (PortId, ChannelId), + seq: Sequence, + ) -> Result<(), Ics04Error> { + let seq_recvs_path = SeqRecvsPath(port_channel_id.0.clone(), port_channel_id.1.clone()) + .to_string() + .as_bytes() + .to_vec(); + let sequence = u64::from(seq); + + >::insert(seq_recvs_path, sequence); + + Ok(()) + } + + fn store_next_sequence_ack( + &mut self, + port_channel_id: (PortId, ChannelId), + seq: Sequence, + ) -> Result<(), Ics04Error> { + let seq_acks_path = SeqAcksPath(port_channel_id.0.clone(), port_channel_id.1.clone()) + .to_string() + .as_bytes() + .to_vec(); + let sequence = u64::from(seq); + + >::insert(seq_acks_path, sequence); + + Ok(()) + } + + /// 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) { + let ret = >::try_mutate(|val| -> Result<(), Ics04Error> { + let new = val.checked_add(1).expect("Never Overflow"); + *val = new; + Ok(()) + }); + } +} diff --git a/frame/ibc/src/module/core/ics05_port.rs b/frame/ibc/src/module/core/ics05_port.rs new file mode 100644 index 0000000000000..5ac325bbb6ed8 --- /dev/null +++ b/frame/ibc/src/module/core/ics05_port.rs @@ -0,0 +1,41 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://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. + +use crate::*; +use log::trace; + +use crate::context::Context; +use ibc::{ + applications::transfer::{ + MODULE_ID_STR as TRANSFER_MODULE_ID, PORT_ID_STR as TRANSFER_PORT_ID, + }, + core::{ + ics05_port::{context::PortReader, error::Error as ICS05Error}, + ics24_host::identifier::PortId, + ics26_routing::context::ModuleId, + }, +}; + +impl PortReader for Context { + fn lookup_module_by_port(&self, port_id: &PortId) -> Result { + match port_id.as_str() { + TRANSFER_PORT_ID => Ok(ModuleId::from_str(TRANSFER_MODULE_ID) + .map_err(|_| ICS05Error::module_not_found(port_id.clone()))?), + _ => Err(ICS05Error::module_not_found(port_id.clone())), + } + } +} diff --git a/frame/ibc/src/module/core/ics24_host.rs b/frame/ibc/src/module/core/ics24_host.rs new file mode 100644 index 0000000000000..6d08244f1f1e8 --- /dev/null +++ b/frame/ibc/src/module/core/ics24_host.rs @@ -0,0 +1,272 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://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. + +use crate::{alloc::string::ToString, from_channel_id_to_vec, Config, Event, REVISION_NUMBER}; +use alloc::string::String; +use ibc::{ + core::{ + ics02_client::{client_type::ClientType as IbcClientType, height::Height as IbcHeight}, + ics04_channel::packet::{Packet as IbcPacket, Sequence as IbcSequence}, + ics24_host::{ + error::ValidationError, + identifier::{ + ChainId as IbcChainId, ChannelId as IbcChannelId, ClientId as IbcClientId, + ConnectionId as IbcConnectionId, PortId as IbcPortId, + }, + }, + }, + timestamp::Timestamp as IbcTimestamp, +}; +use sp_std::{str::FromStr, vec::Vec}; + +use codec::{Decode, Encode}; +use scale_info::TypeInfo; + +use sp_runtime::RuntimeDebug; + +use flex_error::{define_error, DisplayOnly, TraceError}; +use ibc::core::ics04_channel::timeout::TimeoutHeight; +use tendermint_proto::Error as TendermintError; + +define_error! { + #[derive(Debug, PartialEq, Eq)] + Error { + InvalidFromUtf8 + [DisplayOnly] + | _ | { "invalid from utf8 error" }, + InvalidDecode + [DisplayOnly] + | _ | { "invalid decode error" }, + ParseTimestampFailed + [DisplayOnly] + | _ | { "invalid parse timestamp error" }, + ValidationFailed + [DisplayOnly] + | _ | { "invalid validation error"}, + InvalidChainId + [DisplayOnly] + |_| { "invalid chain id error" }, + } +} + +/// ibc-rs' `PortId` representation in substrate +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct PortId(pub Vec); + +impl From for PortId { + fn from(value: IbcPortId) -> Self { + let value = value.as_str().as_bytes().to_vec(); + Self(value) + } +} + +impl From for IbcPortId { + fn from(value: PortId) -> Self { + let value = String::from_utf8(value.0).expect("convert Never faild"); + IbcPortId::from_str(&value).expect("convert Never faild") + } +} + +/// ibc-rs' `ChannelId` representation in substrate +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct ChannelId(pub Vec); + +impl From for ChannelId { + fn from(value: IbcChannelId) -> Self { + let value = from_channel_id_to_vec(value); + Self(value) + } +} + +impl From for IbcChannelId { + fn from(value: ChannelId) -> Self { + let value = String::from_utf8(value.0).expect("convert Never faild"); + Self::from_str(&value).expect("convert Never faild") + } +} + +/// ibc-rs' `Height` representation in substrate +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct Height { + /// Previously known as "epoch" + pub revision_number: u64, + + /// The height of a block + pub revision_height: u64, +} + +impl From for Height { + fn from(ibc_height: IbcHeight) -> Self { + Height::new(ibc_height.revision_number(), ibc_height.revision_height()) + } +} + +impl From for IbcHeight { + fn from(height: Height) -> Self { + IbcHeight::new(REVISION_NUMBER, height.revision_height) + .expect("Contruct IbcHeight Never faild") + } +} + +impl Height { + pub fn new(revision_number: u64, revision_height: u64) -> Self { + Self { revision_number, revision_height } + } +} + +/// ibc-rs' `ClientType` representation in substrate +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] +pub enum ClientType { + Tendermint, + Grandpa, +} + +impl From for ClientType { + fn from(value: IbcClientType) -> Self { + match value { + IbcClientType::Tendermint => ClientType::Tendermint, + _ => unreachable!(), + } + } +} + +impl ClientType { + pub fn to_ibc_client_type(self) -> IbcClientType { + match self { + ClientType::Tendermint => IbcClientType::Tendermint, + _ => unreachable!(), + } + } +} + +/// ibc-rs' `ClientId` representation in substrate +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct ClientId(pub Vec); + +impl From for ClientId { + fn from(value: IbcClientId) -> Self { + let value = value.as_str().as_bytes().to_vec(); + Self(value) + } +} + +impl From for IbcClientId { + fn from(value: ClientId) -> Self { + let value = String::from_utf8(value.0).expect("convert Never faild"); + IbcClientId::from_str(&value).expect("convert Never faild") + } +} + +/// ibc-rs' `ConnectionId` representation in substrate +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct ConnectionId(pub Vec); + +impl From for ConnectionId { + fn from(value: IbcConnectionId) -> Self { + let value = value.as_str().as_bytes().to_vec(); + Self(value) + } +} + +impl From for IbcConnectionId { + fn from(value: ConnectionId) -> Self { + let value = String::from_utf8(value.0).expect("convert Never faild"); + IbcConnectionId::from_str(&value).expect("convert Never faild") + } +} + +/// ibc-rs' `Timestamp` representation in substrate +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct Timestamp { + pub time: Vec, +} + +impl From for Timestamp { + fn from(val: IbcTimestamp) -> Self { + Self { time: val.nanoseconds().to_string().as_bytes().to_vec() } + } +} + +impl From for IbcTimestamp { + fn from(value: Timestamp) -> Self { + let value = String::from_utf8(value.time).expect("convert Never faild"); + Self::from_str(&value).expect("convert Never faild") + } +} + +/// ibc-rs' `Sequence` representation in substrate + +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct Sequence(u64); + +impl From for Sequence { + fn from(val: IbcSequence) -> Self { + Self(u64::from(val)) + } +} + +impl From for IbcSequence { + fn from(val: Sequence) -> Self { + IbcSequence::from(val.0) + } +} + +/// ibc-rs' `Packet` representation in substrate +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct Packet { + pub sequence: Sequence, + pub source_port: PortId, + pub source_channel: ChannelId, + pub destination_port: PortId, + pub destination_channel: ChannelId, + pub data: Vec, + pub timeout_height: Height, + pub timeout_timestamp: Timestamp, +} + +impl From for Packet { + fn from(val: IbcPacket) -> Self { + Self { + sequence: val.sequence.into(), + source_port: val.source_port.into(), + source_channel: val.source_channel.into(), + destination_port: val.destination_port.into(), + destination_channel: val.destination_channel.into(), + data: val.data, + timeout_height: match val.timeout_height { + TimeoutHeight::Never => Height::new(REVISION_NUMBER, u64::MAX), + TimeoutHeight::At(value) => value.into(), + }, + timeout_timestamp: val.timeout_timestamp.into(), + } + } +} + +impl From for IbcPacket { + fn from(value: Packet) -> Self { + Self { + sequence: value.sequence.into(), + source_port: value.source_port.into(), + source_channel: value.source_channel.into(), + destination_port: value.destination_port.into(), + destination_channel: value.destination_channel.into(), + data: value.data, + timeout_height: TimeoutHeight::At(value.timeout_height.into()), + timeout_timestamp: value.timeout_timestamp.into(), + } + } +} diff --git a/frame/ibc/src/module/core/ics26_routing.rs b/frame/ibc/src/module/core/ics26_routing.rs new file mode 100644 index 0000000000000..fedfeba33e675 --- /dev/null +++ b/frame/ibc/src/module/core/ics26_routing.rs @@ -0,0 +1,82 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://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. + +use crate::{context::Context, *}; +use alloc::{ + borrow::{Borrow, Cow, ToOwned}, + collections::BTreeMap, + fmt::format, + sync::Arc, +}; +use core::fmt::Formatter; +use ibc::core::ics26_routing::context::{Ics26Context, Module, ModuleId, RouterBuilder}; +use log::{error, info, trace, warn}; +use scale_info::TypeInfo; + +#[derive(Default)] +pub struct SubRouterBuilder(Router); + +impl RouterBuilder for SubRouterBuilder { + type Router = Router; + + 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(Default, Clone)] +pub struct Router(BTreeMap>); + +impl Debug for Router { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + let mut keys = vec![]; + for (key, _) in self.0.iter() { + keys.push(format!("{}", key)); + } + + write!(f, "MockRouter(BTreeMap(key({:?})", keys.join(",")) + } +} + +impl ibc::core::ics26_routing::context::Router for Router { + 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 Context { + type Router = Router; + + fn router(&self) -> &Self::Router { + &self.router + } + + fn router_mut(&mut self) -> &mut Self::Router { + &mut self.router + } +} diff --git a/frame/ibc/src/module/core/mod.rs b/frame/ibc/src/module/core/mod.rs new file mode 100644 index 0000000000000..9b9d7c270089d --- /dev/null +++ b/frame/ibc/src/module/core/mod.rs @@ -0,0 +1,23 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://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. + +pub mod ics02_client; +pub mod ics03_connection; +pub mod ics04_channel; +pub mod ics05_port; +pub mod ics24_host; +pub mod ics26_routing; diff --git a/frame/ibc/src/module/mod.rs b/frame/ibc/src/module/mod.rs new file mode 100644 index 0000000000000..d475ce0d9fff3 --- /dev/null +++ b/frame/ibc/src/module/mod.rs @@ -0,0 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://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. + +pub mod applications; +pub mod core; +pub mod relayer; diff --git a/frame/ibc/src/module/relayer/mod.rs b/frame/ibc/src/module/relayer/mod.rs new file mode 100644 index 0000000000000..3f18d85aa2537 --- /dev/null +++ b/frame/ibc/src/module/relayer/mod.rs @@ -0,0 +1,64 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://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. + +use crate::{ + alloc::string::ToString, context::Context, utils::host_height, Config, REVISION_NUMBER, +}; +use ibc::{ + core::{ + ics02_client::{client_state::AnyClientState, context::ClientReader, header::AnyHeader}, + ics24_host::identifier::ClientId, + ics26_routing::handler::{deliver, MsgReceipt}, + }, + events::IbcEvent, + relayer::ics18_relayer::{context::Ics18Context, error::Error as ICS18Error}, + signer::Signer, + Height, +}; +use ibc_proto::google::protobuf::Any; +use scale_info::prelude::{vec, vec::Vec}; + +impl Ics18Context for Context { + fn query_latest_height(&self) -> Height { + let revision_height = host_height::(); + Height::new(REVISION_NUMBER, revision_height).expect(&REVISION_NUMBER.to_string()) + } + + 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 { + todo!() + } + + 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); + } + Ok(all_events) + } + + fn signer(&self) -> Signer { + "0CDA3F47EF3C4906693B170EF650EB968C5F4B2C".parse().unwrap() + } +} diff --git a/frame/ibc/src/tests.rs b/frame/ibc/src/tests.rs new file mode 100644 index 0000000000000..1a30744f43137 --- /dev/null +++ b/frame/ibc/src/tests.rs @@ -0,0 +1,430 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://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. + +//! Tests for the ibc pallet. +use super::*; +use crate::{mock::*, Context}; +use core::str::FromStr; + +use ibc::{ + applications::transfer::{context::Ics20Context, error::Error as ICS20Error}, + core::{ + ics02_client::{ + client_consensus::AnyConsensusState, + client_state::AnyClientState, + client_type::ClientType, + context::{ClientKeeper, ClientReader}, + error::Error as ICS02Error, + }, + ics03_connection::{ + connection::{ConnectionEnd, State}, + context::{ConnectionKeeper, ConnectionReader}, + error::Error as ICS03Error, + }, + ics04_channel::{ + channel::ChannelEnd, + context::{ChannelKeeper, ChannelReader}, + error::Error as ICS04Error, + packet::Sequence, + }, + ics23_commitment::commitment::CommitmentRoot, + ics24_host::identifier::{ChainId, ChannelId, ClientId, ConnectionId, PortId}, + }, + timestamp::Timestamp, + Height, +}; + +// test store and read client-type +#[test] +fn test_store_client_type_ok() { + let gp_client_type = ClientType::Tendermint; + let gp_client_id = ClientId::default(); + + let mut context: Context = Context::new(); + + new_test_ext().execute_with(|| { + assert!(context.store_client_type(gp_client_id.clone(), gp_client_type).is_ok()); + }) +} + +#[test] +fn test_read_client_type_failed_by_supply_error_client_id() { + let gp_client_type = ClientType::Tendermint; + let gp_client_id = ClientId::new(gp_client_type, 0).unwrap(); + let gp_client_id_failed = ClientId::new(gp_client_type, 1).unwrap(); + let mut context: Context = Context::new(); + + new_test_ext().execute_with(|| { + assert!(context.store_client_type(gp_client_id.clone(), gp_client_type).is_ok()); + + let ret = context.client_type(&gp_client_id_failed).unwrap_err().to_string(); + + assert_eq!(ret, ICS02Error::client_not_found(gp_client_id_failed).to_string()); + }) +} +#[test] +fn test_get_packet_commitment_state_ok() { + use ibc::core::ics04_channel::commitment::PacketCommitment; + + let mut context: Context = Context::new(); + + let range = (0..10).into_iter().collect::>(); + + let mut port_id_vec = vec![]; + let mut channel_id_vec = vec![]; + let mut sequence_vec = vec![]; + + for index in range.clone() { + port_id_vec.push(PortId::default()); + channel_id_vec.push(ChannelId::default()); + let sequence = Sequence::from(index as u64); + sequence_vec.push(sequence); + } + let com = PacketCommitment::from(vec![1, 2, 3]); + + new_test_ext().execute_with(|| { + for index in 0..range.len() { + assert!(context + .store_packet_commitment( + ( + port_id_vec[index].clone(), + channel_id_vec[index].clone(), + sequence_vec[index] + ), + com.clone(), + ) + .is_ok()); + } + }) +} + +#[test] +fn test_connection_ok() { + use codec::alloc::collections::HashMap; + + let mut input: HashMap = HashMap::new(); + + let connection_id0 = ConnectionId::default(); + let connection_end0 = ConnectionEnd::default(); + + let connection_id1 = ConnectionId::default(); + let connection_end1 = ConnectionEnd::default(); + + let connection_id2 = ConnectionId::default(); + let connection_end2 = ConnectionEnd::default(); + + input.insert(connection_id0.clone(), connection_end0.clone()); + input.insert(connection_id1.clone(), connection_end1.clone()); + input.insert(connection_id2.clone(), connection_end2.clone()); + + let mut context: Context = Context::new(); + new_test_ext().execute_with(|| { + assert_eq!( + ConnectionKeeper::store_connection( + &mut context, + connection_id0.clone(), + input.get(&connection_id0.clone()).unwrap() + ) + .is_ok(), + true + ); + + let ret = ConnectionReader::connection_end(&mut context, &connection_id0).unwrap(); + assert_eq!(ret, *input.get(&connection_id0.clone()).unwrap()); + + assert_eq!( + ConnectionKeeper::store_connection( + &mut context, + connection_id1.clone(), + input.get(&connection_id1.clone()).unwrap() + ) + .is_ok(), + true + ); + + assert_eq!( + ConnectionKeeper::store_connection( + &mut context, + connection_id2.clone(), + input.get(&connection_id2.clone()).unwrap() + ) + .is_ok(), + true + ); + }) +} + +#[test] +fn test_connection_fail() { + let connection_id0 = ConnectionId::default(); + let context: Context = Context::new(); + new_test_ext().execute_with(|| { + let ret = ConnectionReader::connection_end(&context, &connection_id0.clone()) + .unwrap_err() + .to_string(); + assert_eq!(ret, ICS03Error::connection_mismatch(connection_id0).to_string()); + }) +} + +#[test] +fn test_connection_client_ok() { + let gp_client_id = ClientId::default(); + let connection_id = ConnectionId::new(0); + let mut context: Context = Context::new(); + + new_test_ext().execute_with(|| { + assert!(context.store_connection_to_client(connection_id, &gp_client_id).is_ok()); + }) +} + +#[test] +fn test_delete_packet_acknowledgement_ok() { + use ibc::core::ics04_channel::commitment::AcknowledgementCommitment; + + let port_id = PortId::default(); + let channel_id = ChannelId::default(); + let sequence = Sequence::from(0); + let ack = AcknowledgementCommitment::from(vec![1, 2, 3]); + + let mut context: Context = Context::new(); + + new_test_ext().execute_with(|| { + assert!(context + .store_packet_acknowledgement( + (port_id.clone(), channel_id.clone(), sequence), + ack.clone() + ) + .is_ok()); + + assert!(context + .delete_packet_acknowledgement((port_id.clone(), channel_id.clone(), sequence)) + .is_ok()); + + let result = context + .get_packet_acknowledgement(&(port_id, channel_id, sequence)) + .unwrap_err() + .to_string(); + + assert_eq!(result, ICS04Error::packet_acknowledgement_not_found(sequence).to_string()); + }) +} + +#[test] +fn test_get_acknowledge_state() { + use ibc::core::ics04_channel::commitment::AcknowledgementCommitment; + let range = (0..10).into_iter().collect::>(); + + let mut port_id_vec = vec![]; + let mut channel_id_vec = vec![]; + let mut sequence_vec = vec![]; + let mut ack_vec = vec![]; + + let mut value_vec = vec![]; + + let mut context: Context = Context::new(); + + for index in 0..range.len() { + port_id_vec.push(PortId::default()); + channel_id_vec.push(ChannelId::default()); + let sequence = Sequence::from(index as u64); + sequence_vec.push(sequence); + ack_vec.push(AcknowledgementCommitment::from(vec![index as u8])); + value_vec.push(ChannelReader::hash(&context, vec![index as u8]).encode()); + } + + new_test_ext().execute_with(|| { + for index in 0..range.len() { + assert!(context + .store_packet_acknowledgement( + ( + port_id_vec[index].clone(), + channel_id_vec[index].clone(), + sequence_vec[index] + ), + ack_vec[index].clone() + ) + .is_ok()); + } + }) +} + +#[test] +fn test_store_connection_channles_ok() { + let connection_id = ConnectionId::default(); + let port_id = PortId::default(); + let channel_id = ChannelId::default(); + + let mut context: Context = Context::new(); + new_test_ext().execute_with(|| { + assert!(context + .store_connection_channels( + connection_id.clone(), + &(port_id.clone(), channel_id.clone()) + ) + .is_ok()); + + let result = context.connection_channels(&connection_id).unwrap(); + + assert_eq!(result.len(), 1); + + assert_eq!(result[0].0, port_id); + assert_eq!(result[0].1, channel_id); + }) +} + +#[test] +fn test_next_sequence_send_ok() { + let sequence_id = Sequence::from(0); + let port_channel = (PortId::default(), ChannelId::default()); + let mut context: Context = Context::new(); + + new_test_ext().execute_with(|| { + assert!(context.store_next_sequence_send(port_channel.clone(), sequence_id).is_ok()); + let result = context.get_next_sequence_send(&port_channel).unwrap(); + assert_eq!(result, sequence_id); + }) +} + +#[test] +fn test_read_conection_channels_failed_by_suppley_error_conneciton_id() { + let connection_id = ConnectionId::new(0); + let connection_id_failed = ConnectionId::new(1); + let port_id = PortId::from_str(String::from_str("port-0").unwrap().as_str()).unwrap(); + let channel_id = ChannelId::from_str(String::from_str("channel-0").unwrap().as_str()).unwrap(); + + let mut context: Context = Context::new(); + new_test_ext().execute_with(|| { + assert!(context + .store_connection_channels( + connection_id.clone(), + &(port_id.clone(), channel_id.clone()) + ) + .is_ok()); + + let result = context.connection_channels(&connection_id_failed).unwrap_err().to_string(); + + assert_eq!( + result, + ICS04Error::connection_not_open(connection_id_failed.clone()).to_string() + ); + }) +} + +#[test] +fn test_store_channel_ok() { + let port_id = PortId::default(); + let channel_id = ChannelId::default(); + let channel_end = ChannelEnd::default(); + + let mut context: Context = Context::new(); + + new_test_ext().execute_with(|| { + assert!(context + .store_channel((port_id.clone(), channel_id.clone()), &channel_end) + .is_ok()); + + let result = context.channel_end(&(port_id.clone(), channel_id.clone())).unwrap(); + + assert_eq!(result, channel_end); + }) +} + +#[test] + +fn test_next_sequence_send_fail() { + let port_channel = (PortId::default(), ChannelId::default()); + let context: Context = Context::new(); + + new_test_ext().execute_with(|| { + let result = context.get_next_sequence_send(&port_channel.clone()).unwrap_err().to_string(); + assert_eq!(result, ICS04Error::missing_next_send_seq(port_channel).to_string()); + }) +} + +#[test] +fn test_next_sequence_recv_ok() { + let sequence_id = Sequence::from(0); + let port_channel = (PortId::default(), ChannelId::default()); + let mut context: Context = Context::new(); + + new_test_ext().execute_with(|| { + assert!(context.store_next_sequence_recv(port_channel.clone(), sequence_id).is_ok()); + let result = context.get_next_sequence_recv(&port_channel).unwrap(); + assert_eq!(result, sequence_id); + }) +} + +#[test] +fn test_get_identified_channel_end() { + let range = (0..10).into_iter().collect::>(); + + let mut port_id_vec = vec![]; + let mut channel_id_vec = vec![]; + let channel_end_vec = vec![ChannelEnd::default(); range.len()]; + + for index in 0..range.len() { + port_id_vec.push(PortId::default()); + channel_id_vec.push(ChannelId::default()); + } + + let mut context: Context = Context::new(); + new_test_ext().execute_with(|| { + for index in 0..range.len() { + assert!(context + .store_channel( + (port_id_vec[index].clone(), channel_id_vec[index].clone()), + &channel_end_vec[index].clone() + ) + .is_ok()); + } + }) +} + +#[test] +fn test_next_sequence_recv_fail() { + let port_channel = (PortId::default(), ChannelId::default()); + let context: Context = Context::new(); + + new_test_ext().execute_with(|| { + let result = context.get_next_sequence_recv(&port_channel.clone()).unwrap_err().to_string(); + assert_eq!(result, ICS04Error::missing_next_recv_seq(port_channel).to_string()); + }) +} + +#[test] +fn test_next_sequence_ack_ok() { + let sequence_id = Sequence::from(0); + let port_channel = (PortId::default(), ChannelId::default()); + let mut context: Context = Context::new(); + + new_test_ext().execute_with(|| { + assert!(context.store_next_sequence_ack(port_channel.clone(), sequence_id).is_ok()); + let result = context.get_next_sequence_ack(&port_channel).unwrap(); + assert_eq!(result, sequence_id); + }) +} + +#[test] +fn test_next_sequence_ack_fail() { + let port_channel = (PortId::default(), ChannelId::default()); + let context: Context = Context::new(); + + new_test_ext().execute_with(|| { + let result = context.get_next_sequence_ack(&port_channel.clone()).unwrap_err().to_string(); + assert_eq!(result, ICS04Error::missing_next_ack_seq(port_channel).to_string()); + }) +} diff --git a/frame/ibc/src/traits.rs b/frame/ibc/src/traits.rs new file mode 100644 index 0000000000000..6ff204fc02a0c --- /dev/null +++ b/frame/ibc/src/traits.rs @@ -0,0 +1,27 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://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. + +use alloc::vec::Vec; + +/// A trait handling asset ID and name +pub trait AssetIdAndNameProvider { + type Err; + + fn try_get_asset_id(name: impl AsRef<[u8]>) -> Result; + + fn try_get_asset_name(asset_id: AssetId) -> Result, Self::Err>; +} diff --git a/frame/ibc/src/utils.rs b/frame/ibc/src/utils.rs new file mode 100644 index 0000000000000..cd1917b5e7e98 --- /dev/null +++ b/frame/ibc/src/utils.rs @@ -0,0 +1,64 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://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. + +use crate::Config; +use codec::Encode; +use scale_info::prelude::{fmt::Debug, format, vec::Vec}; + +use super::*; +use ibc::{ + applications::transfer::{error::Error as Ics20Error, VERSION}, + core::ics24_host::identifier::{ChannelId as IbcChannelId, PortId}, + signer::Signer, +}; + +use ibc::{ + core::{ + ics02_client::msgs::ClientMsg, + ics03_connection::msgs::ConnectionMsg, + ics04_channel::msgs::{ChannelMsg, PacketMsg}, + ics26_routing::{handler, msgs::Ics26Envelope}, + }, + events::IbcEvent, +}; + +/// Get the latest block height of the host chain +pub fn host_height() -> u64 { + let block_number = format!("{:?}", >::block_number()); + let current_height: u64 = block_number.parse().unwrap_or_default(); + current_height +} + +/// In ICS20 fungible token transfer, get the escrow address by channel ID and port ID +/// +/// Parameters: +/// - `port_id`: The ID of the port corresponding to the escrow. +/// - `channel_id`: The ID of the channel corresponding to the escrow. +pub fn get_channel_escrow_address( + port_id: &PortId, + channel_id: &IbcChannelId, +) -> Result { + let contents = format!("{}/{}", port_id, channel_id); + let mut data = VERSION.as_bytes().to_vec(); + data.extend_from_slice(&[0]); + data.extend_from_slice(contents.as_bytes()); + + let hash = sp_io::hashing::sha2_256(&data).to_vec(); + let mut hex_string = hex::encode_upper(hash); + hex_string.insert_str(0, "0x"); + hex_string.parse::().map_err(Ics20Error::signer) +}