From 5dd6a4ba47ee3536ed1c3d791c20e3cc24c7a82c Mon Sep 17 00:00:00 2001 From: Chevdor Date: Tue, 5 Dec 2023 17:29:13 +0100 Subject: [PATCH 01/59] Fix PRdoc that have been previously drafted with older schema (#2623) Several PRs started introducing `prdoc` files before the schema was final. This PR fixes those former prdoc to ensure that pass the check and comply with the current prdoc schema. --------- Co-authored-by: command-bot <> --- prdoc/pr_1178.prdoc | 5 ++--- prdoc/pr_1246.prdoc | 6 +++--- prdoc/pr_1289.prdoc | 15 ++++++++------- prdoc/pr_1805.prdoc | 6 ++---- prdoc/pr_1926.prdoc | 22 ++++++++-------------- prdoc/pr_2086.prdoc | 11 ++++------- prdoc/pr_2107.prdoc | 4 +++- prdoc/pr_2142.prdoc | 4 ++-- prdoc/pr_2165.prdoc | 5 ++--- prdoc/pr_2253.prdoc | 2 +- 10 files changed, 35 insertions(+), 45 deletions(-) diff --git a/prdoc/pr_1178.prdoc b/prdoc/pr_1178.prdoc index 36c3b05c7a3..528e523c432 100644 --- a/prdoc/pr_1178.prdoc +++ b/prdoc/pr_1178.prdoc @@ -6,9 +6,9 @@ doc: Changed approval-voting, approval-distribution to send all messages tranche0 assignments in one message. This required: * A new parachains_db version. - * A new validation protocol to support the new message types. + * A new validation protocol to support the new message types. The new logic will be disabled and will be enabled at a later date after all validators have upgraded. - + migrations: db: - name: Parachains database change from v3 to v4. @@ -18,6 +18,5 @@ migrations: crates: - name: "polkadot" - semver: patch host_functions: [] diff --git a/prdoc/pr_1246.prdoc b/prdoc/pr_1246.prdoc index f9c86781233..a4d270c45cb 100644 --- a/prdoc/pr_1246.prdoc +++ b/prdoc/pr_1246.prdoc @@ -1,17 +1,17 @@ title: Use the `Message Queue` Pallet for DMP and XCMP dispatch queueing doc: - - audience: Parachain Dev + - audience: Runtime Dev description: Replaces the queueing capabilities of the `DMP and `XCMP-Queue` pallet for incoming messages with the `MessageQueue` pallet. This simplifies the code and improves security. migrations: runtime: - - pallet: "cumulus_pallet_dmp_queue" + reference: cumulus_pallet_dmp_queue description: "Messages from the DMP dispatch queue will be moved over to the MQ pallet via `on_initialize`. This happens over multiple blocks and emits a `Completed` event at the end. The pallet can be un-deployed and deleted afterwards. Note that the migration reverses the order of messages, which should be acceptable as a one-off." crates: - - name: "cumulus_pallet_xcmp_queue" + - name: cumulus_pallet_xcmp_queue note: Pallet config must be altered according to the MR description. host_functions: [] diff --git a/prdoc/pr_1289.prdoc b/prdoc/pr_1289.prdoc index f3d8801d9d8..059d7608ba6 100644 --- a/prdoc/pr_1289.prdoc +++ b/prdoc/pr_1289.prdoc @@ -4,25 +4,26 @@ title: Supporting paged rewards allowing all nominators to be rewarded doc: - - audience: Validator + - audience: Node Operator description: | We used to clip top `MaxNominatorRewardedPerValidator` nominators by stake that are eligible for staking reward. This was done to limit computation cost of paying out rewards. This PR introduces paging to reward payouts, meaning we still clip nominators upto MaxExposurePageSize per page and there could be multiple pages of rewards to be paid out. Validators get commission pro-rata to the amount of reward that is paid out for the page. - notes: - - payout_stakers should be called multiple times, once for each page of nominators. - - payout_stakers_by_page can be used to pay out rewards for a specific page. - - Some old non-paged era storage items are deprecated, and can be removed in a future upgrade. + notes: + - payout_stakers should be called multiple times, once for each page of nominators. + - payout_stakers_by_page can be used to pay out rewards for a specific page. + - Some old non-paged era storage items are deprecated, and can be removed in a future upgrade. migrations: db: [] runtime: - - { pallet: "pallet-staking", description: "v14: Migration of era exposure storage items to paged exposures."} + - reference: pallet-staking + description: "v14: Migration of era exposure storage items to paged exposures." crates: - name: pallet-staking -host_functions: [] \ No newline at end of file +host_functions: [] diff --git a/prdoc/pr_1805.prdoc b/prdoc/pr_1805.prdoc index 8a8e6c2fde2..30f0fbea307 100644 --- a/prdoc/pr_1805.prdoc +++ b/prdoc/pr_1805.prdoc @@ -1,7 +1,7 @@ title: Introduce state decoding check after runtime upgrades. doc: - - audience: Core Dev + - audience: Runtime Dev description: | Adds a check to the try-runtime logic that will verify that all pallet on-chain storage still decodes. This can help to spot missing migrations before they become a problem. The check is enabled as soon as the `--checks` option of the `try-runtime` CLI is not `None`. @@ -10,10 +10,8 @@ migrations: runtime: [] -crates: +crates: - name: frame-support - semver: minor - name: frame-support-procedural - semver: minor host_functions: [] diff --git a/prdoc/pr_1926.prdoc b/prdoc/pr_1926.prdoc index 9dc656f1260..e7c4293d9fd 100644 --- a/prdoc/pr_1926.prdoc +++ b/prdoc/pr_1926.prdoc @@ -1,10 +1,10 @@ title: Adds syntax for marking calls feeless doc: - - audience: Core Dev + - audience: Runtime Dev description: | 1. Adds an attribute `#[pallet::feeless_if]` that can be optionally attached to a `pallet::call`. - 2. Adds a signed extension SkipCheckIfFeeless that wraps a transaction + 2. Adds a signed extension SkipCheckIfFeeless that wraps a transaction payment processor to potentially skip payment fees for such calls. Note that both the attribute and the signed extension are needed to make the call feeless. @@ -14,17 +14,11 @@ migrations: runtime: [] crates: - - name: "frame-support-procedural" - semver: minor - - name: "pallet-skip-feeless-payment" - semver: major - - pallet-example-kitchensink - semver: patch - - kitchensink-runtime - semver: major - - node-testing - semver: patch - - node-cli - semver: patch + - name: frame-support-procedural + - name: pallet-skip-feeless-payment + - name: pallet-example-kitchensink + - name: kitchensink-runtime + - name: node-testing + - name: node-cli host_functions: [] diff --git a/prdoc/pr_2086.prdoc b/prdoc/pr_2086.prdoc index a9bbd0729d5..3bd568cc139 100644 --- a/prdoc/pr_2086.prdoc +++ b/prdoc/pr_2086.prdoc @@ -1,15 +1,12 @@ title: "Contracts: Add XCM traits to interface with contracts" doc: - - audience: Core Dev + - audience: Runtime Dev description: | We are introducing a new set of `XcmController` traits in `pallet-xcm`. - These traits extract functionality from `pallet-xcm` and provide high-level interaction with XCM. + These traits extract functionality from `pallet-xcm` and provide high-level interaction with XCM. They enable other pallets, like `pallet_contracts`, to rely on these traits instead of tight coupling to `pallet-xcm` itself. crates: - - name: "pallet-xcm" - semver: patch - - name: "xcm-executor" - semver: patch - + - name: pallet-xcm + - name: xcm-executor diff --git a/prdoc/pr_2107.prdoc b/prdoc/pr_2107.prdoc index 0e33680555a..be71828cbad 100644 --- a/prdoc/pr_2107.prdoc +++ b/prdoc/pr_2107.prdoc @@ -4,14 +4,16 @@ title: Add a builder pattern to create XCM programs doc: - - audience: Core Dev + - audience: Runtime Dev description: | XCMs can now be built using a builder pattern like so: + ``` Xcm::builder() .withdraw_asset(assets) .buy_execution(fees, weight_limit) .deposit_asset(assets, beneficiary) .build(); + ``` migrations: db: [] diff --git a/prdoc/pr_2142.prdoc b/prdoc/pr_2142.prdoc index ae2ac3db9dd..1d379411346 100644 --- a/prdoc/pr_2142.prdoc +++ b/prdoc/pr_2142.prdoc @@ -1,12 +1,12 @@ title: Cleanup XCMP `QueueConfigData` doc: - - audience: Parachain Dev + - audience: Runtime Dev description: Removes obsolete fields from the `QueueConfigData` structure. For the remaining fields, if they use the old defaults, we replace them with the new defaults. migrations: runtime: - - pallet: "cumulus_pallet_xcmp_queue" + - reference: cumulus_pallet_xcmp_queue description: "v4: Removes obsolete fields from the `QueueConfigData` structure. For the remaining fields, if they use the old defaults, we replace them with the new defaults." crates: [] diff --git a/prdoc/pr_2165.prdoc b/prdoc/pr_2165.prdoc index 31cb691c43a..3b10bcfe6a5 100644 --- a/prdoc/pr_2165.prdoc +++ b/prdoc/pr_2165.prdoc @@ -1,7 +1,7 @@ -title: Add sudo::remove_key +title: Add `sudo::remove_key` doc: - - audience: Core Dev + - audience: Runtime User description: | Pallet `Sudo` now has the ability to remove the sudo key via `remove_key`. This is a less-invasive way of rendering the sudo pallet useless without needing a code upgrade. @@ -12,6 +12,5 @@ migrations: crates: - name: pallet-sudo - semver: minor host_functions: [] diff --git a/prdoc/pr_2253.prdoc b/prdoc/pr_2253.prdoc index 398b0a29066..8a6dac754d1 100644 --- a/prdoc/pr_2253.prdoc +++ b/prdoc/pr_2253.prdoc @@ -4,7 +4,7 @@ title: Different builder pattern constructors for XCM doc: - - audience: Core Dev + - audience: Runtime Dev description: | The `builder()` constructor for XCM programs now only allows building messages that pay for fees, i.e. messages that would pass the `AllowTopLevelPaidExecutionFrom` barrier. -- GitLab From 0239cedd0f1cde235e62e146cf57c41b8b90b419 Mon Sep 17 00:00:00 2001 From: dzmitry-lahoda Date: Tue, 5 Dec 2023 22:22:28 +0000 Subject: [PATCH 02/59] chore: fixed std wasm build of xcm (#2535) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description just ensures ```sh cargo check --package staging-xcm --no-default-features --target wasm32-unknown-unknown --features=std ``` work (for CosmWasm) # Checklist - [x] My PR includes a detailed description as outlined in the "Description" section above - [ ] My PR follows the [labeling requirements](CONTRIBUTING.md#Process) of this project (at minimum one label for `T` required) - [x] I have made corresponding changes to the documentation (if applicable) - [ ] I have added tests that prove my fix is effective or that my feature works (if applicable) --------- Co-authored-by: Bastian Köcher --- Cargo.lock | 2 +- substrate/primitives/weights/Cargo.toml | 6 +++--- substrate/primitives/weights/src/lib.rs | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 10d279a305d..c3a93a221c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18079,12 +18079,12 @@ dependencies = [ name = "sp-weights" version = "20.0.0" dependencies = [ + "bounded-collections", "parity-scale-codec", "scale-info", "serde", "smallvec", "sp-arithmetic", - "sp-core", "sp-debug-derive 8.0.0", "sp-std 8.0.0", ] diff --git a/substrate/primitives/weights/Cargo.toml b/substrate/primitives/weights/Cargo.toml index a573495ff91..163b241276c 100644 --- a/substrate/primitives/weights/Cargo.toml +++ b/substrate/primitives/weights/Cargo.toml @@ -13,23 +13,23 @@ documentation = "https://docs.rs/sp-wasm-interface" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +bounded-collections = { version = "0.1.4", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.193", default-features = false, optional = true, features = ["alloc", "derive"] } smallvec = "1.11.0" sp-arithmetic = { path = "../arithmetic", default-features = false } -sp-core = { path = "../core", default-features = false } sp-debug-derive = { path = "../debug-derive", default-features = false } sp-std = { path = "../std", default-features = false } [features] default = ["std"] std = [ + "bounded-collections/std", "codec/std", "scale-info/std", "serde/std", "sp-arithmetic/std", - "sp-core/std", "sp-debug-derive/std", "sp-std/std", ] @@ -39,8 +39,8 @@ full-metadata-docs = ["scale-info/docs"] # Serde support without relying on std features. serde = [ + "bounded-collections/serde", "dep:serde", "scale-info/serde", "sp-arithmetic/serde", - "sp-core/serde", ] diff --git a/substrate/primitives/weights/src/lib.rs b/substrate/primitives/weights/src/lib.rs index ececb622fa0..ef431bddee2 100644 --- a/substrate/primitives/weights/src/lib.rs +++ b/substrate/primitives/weights/src/lib.rs @@ -27,6 +27,7 @@ extern crate self as sp_weights; mod weight_meter; mod weight_v2; +use bounded_collections::Get; use codec::{CompactAs, Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; #[cfg(feature = "serde")] @@ -36,7 +37,6 @@ use sp_arithmetic::{ traits::{BaseArithmetic, SaturatedConversion, Unsigned}, Perbill, }; -use sp_core::Get; use sp_debug_derive::RuntimeDebug; pub use weight_meter::*; @@ -270,7 +270,7 @@ pub type NoFee = FixedFee<0, T>; /// # Example /// /// ``` -/// # use sp_core::ConstU128; +/// # use bounded_collections::ConstU128; /// # use sp_weights::ConstantMultiplier; /// // Results in a multiplier of 10 for each unit of weight (or length) /// type LengthToFee = ConstantMultiplier::>; @@ -360,7 +360,7 @@ mod tests { #[test] fn constant_fee_works() { - use sp_core::ConstU128; + use bounded_collections::ConstU128; assert_eq!( ConstantMultiplier::>::weight_to_fee(&Weight::zero()), 0 -- GitLab From 333edb0514de083991548d816494411413ec3d19 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Dec 2023 23:44:56 +0100 Subject: [PATCH 03/59] Bump tracing-core from 0.1.31 to 0.1.32 (#2618) Bumps [tracing-core](https://github.com/tokio-rs/tracing) from 0.1.31 to 0.1.32.
Release notes

Sourced from tracing-core's releases.

tracing-core 0.1.32

Documented

  • Fix typo in field docs (#2611)
  • Remove duplicate wording (#2674)

Changed

  • Allow ValueSets of any length (#2508)

#2611: tokio-rs/tracing#2611 #2674: tokio-rs/tracing#2674 #2508: tokio-rs/tracing#2508

Commits
  • c4b2a56 chore: prepare tracing-core 0.1.32 (#2754)
  • 2502f19 chore: prepare tracing-attributes 0.1.27 (#2756)
  • 9048762 Revert "log: update to env_logger 0.10 to fix GHSA-g98v-hv3f-hcfr (#2740)" (#...
  • 6ba5af2 docs: remove mention of Registration on v0.1.x (#2753)
  • 11aac9a log: deprecate env_logger in favor of tracing_subscriber::fmt::Subscriber...
  • 2f27752 chore: remove env_logger from hyper example
  • f96846d attributes: fix typo "overriden" => "overridden" (#2719)
  • 71b5b2c subscriber: make format::Writer::new() public (#2680)
  • f8c0002 attributes: fix clippy warning in attributes tests (#2742)
  • 60b2dc3 journald: fix clippy unwrap_or_default warning (#2742)
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=tracing-core&package-manager=cargo&previous-version=0.1.31&new-version=0.1.32)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
--------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: command-bot <> Co-authored-by: Liam Aharon --- Cargo.lock | 4 ++-- substrate/primitives/io/Cargo.toml | 2 +- substrate/primitives/runtime-interface/test/Cargo.toml | 2 +- substrate/primitives/tracing/Cargo.toml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c3a93a221c7..13ff6ef32fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19558,9 +19558,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", "valuable", diff --git a/substrate/primitives/io/Cargo.toml b/substrate/primitives/io/Cargo.toml index e95a9302d24..5239860c710 100644 --- a/substrate/primitives/io/Cargo.toml +++ b/substrate/primitives/io/Cargo.toml @@ -30,7 +30,7 @@ sp-tracing = { path = "../tracing", default-features = false } log = { version = "0.4.17", optional = true } secp256k1 = { version = "0.28.0", features = ["global-context", "recovery"], optional = true } tracing = { version = "0.1.29", default-features = false } -tracing-core = { version = "0.1.28", default-features = false } +tracing-core = { version = "0.1.32", default-features = false } # Required for backwards compatibility reason, but only used for verifying when `UseDalekExt` is set. ed25519-dalek = { version = "2.0", default-features = false, optional = true } diff --git a/substrate/primitives/runtime-interface/test/Cargo.toml b/substrate/primitives/runtime-interface/test/Cargo.toml index feb6a454af1..661af1fa391 100644 --- a/substrate/primitives/runtime-interface/test/Cargo.toml +++ b/substrate/primitives/runtime-interface/test/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] tracing = "0.1.29" -tracing-core = "0.1.28" +tracing-core = "0.1.32" sc-executor = { path = "../../../client/executor" } sc-executor-common = { path = "../../../client/executor/common" } sp-io = { path = "../../io" } diff --git a/substrate/primitives/tracing/Cargo.toml b/substrate/primitives/tracing/Cargo.toml index 43b3683fb06..964dbbca144 100644 --- a/substrate/primitives/tracing/Cargo.toml +++ b/substrate/primitives/tracing/Cargo.toml @@ -23,7 +23,7 @@ codec = { version = "3.6.1", package = "parity-scale-codec", default-features = "derive", ] } tracing = { version = "0.1.29", default-features = false } -tracing-core = { version = "0.1.28", default-features = false } +tracing-core = { version = "0.1.32", default-features = false } tracing-subscriber = { version = "0.2.25", optional = true, features = [ "tracing-log", ] } -- GitLab From 91cbe087dece64a86bf8145198cb79214b9510a2 Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Wed, 6 Dec 2023 06:53:25 +0800 Subject: [PATCH 04/59] chore: fix typo (#2596) Co-authored-by: Liam Aharon --- substrate/client/chain-spec/src/extension.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/client/chain-spec/src/extension.rs b/substrate/client/chain-spec/src/extension.rs index 25ab011a05b..f2939741535 100644 --- a/substrate/client/chain-spec/src/extension.rs +++ b/substrate/client/chain-spec/src/extension.rs @@ -284,7 +284,7 @@ where } } -/// A subset if the `Extension` trait that only allows for quering extensions. +/// A subset of the `Extension` trait that only allows for quering extensions. pub trait GetExtension { /// Get an extension of specific type. fn get_any(&self, t: TypeId) -> &dyn Any; -- GitLab From 1f023deab8d021c5bab08731e13aa12590ed4026 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Wed, 6 Dec 2023 00:19:56 +0000 Subject: [PATCH 05/59] sp-core: Rename VrfOutput to VrfPreOutput (#2534) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will make more sense after https://github.com/paritytech/polkadot-sdk/pull/2524 since the schnorrkel type for VRF outputs is also renamed in the latest version. Can be reviewed independently though. Can be merged after https://github.com/paritytech/polkadot-sdk/pull/1577 so that there is less pain for @davxy. --------- Co-authored-by: Bastian Köcher --- .../src/approval_db/v2/migration_helpers.rs | 10 ++- .../node/core/approval-voting/src/criteria.rs | 18 ++-- .../node/core/approval-voting/src/tests.rs | 16 ++-- .../approval-distribution/src/tests.rs | 10 +-- polkadot/node/primitives/src/approval.rs | 20 ++--- .../client/consensus/babe/src/authorship.rs | 2 +- substrate/client/consensus/babe/src/tests.rs | 8 +- .../client/consensus/babe/src/verification.rs | 2 +- substrate/client/keystore/src/local.rs | 22 ++--- substrate/frame/babe/src/lib.rs | 6 +- substrate/frame/sassafras/src/lib.rs | 22 ++--- substrate/frame/sassafras/src/mock.rs | 4 +- .../primitives/consensus/babe/src/lib.rs | 2 +- .../primitives/consensus/sassafras/src/vrf.rs | 24 +++--- substrate/primitives/core/src/bandersnatch.rs | 86 ++++++++++--------- substrate/primitives/core/src/crypto.rs | 8 +- substrate/primitives/core/src/sr25519.rs | 52 +++++------ substrate/primitives/keystore/src/lib.rs | 24 +++--- substrate/primitives/keystore/src/testing.rs | 29 ++++--- 19 files changed, 193 insertions(+), 172 deletions(-) diff --git a/polkadot/node/core/approval-voting/src/approval_db/v2/migration_helpers.rs b/polkadot/node/core/approval-voting/src/approval_db/v2/migration_helpers.rs index 74e997c7af8..efdba41b57a 100644 --- a/polkadot/node/core/approval-voting/src/approval_db/v2/migration_helpers.rs +++ b/polkadot/node/core/approval-voting/src/approval_db/v2/migration_helpers.rs @@ -18,7 +18,8 @@ use super::*; use crate::backend::Backend; use polkadot_node_primitives::approval::v1::{ - AssignmentCert, AssignmentCertKind, VrfOutput, VrfProof, VrfSignature, RELAY_VRF_MODULO_CONTEXT, + AssignmentCert, AssignmentCertKind, VrfPreOutput, VrfProof, VrfSignature, + RELAY_VRF_MODULO_CONTEXT, }; use polkadot_node_subsystem_util::database::Database; use sp_application_crypto::sp_core::H256; @@ -30,9 +31,12 @@ fn dummy_assignment_cert(kind: AssignmentCertKind) -> AssignmentCert { let mut prng = rand_core::OsRng; let keypair = schnorrkel::Keypair::generate_with(&mut prng); let (inout, proof, _) = keypair.vrf_sign(ctx.bytes(msg)); - let out = inout.to_output(); + let preout = inout.to_output(); - AssignmentCert { kind, vrf: VrfSignature { output: VrfOutput(out), proof: VrfProof(proof) } } + AssignmentCert { + kind, + vrf: VrfSignature { pre_output: VrfPreOutput(preout), proof: VrfProof(proof) }, + } } fn make_block_entry_v1( diff --git a/polkadot/node/core/approval-voting/src/criteria.rs b/polkadot/node/core/approval-voting/src/criteria.rs index 2bb5a151fe2..acad1c66a43 100644 --- a/polkadot/node/core/approval-voting/src/criteria.rs +++ b/polkadot/node/core/approval-voting/src/criteria.rs @@ -21,7 +21,9 @@ use parity_scale_codec::{Decode, Encode}; use polkadot_node_primitives::approval::{ self as approval_types, v1::{AssignmentCert, AssignmentCertKind, DelayTranche, RelayVRFStory}, - v2::{AssignmentCertKindV2, AssignmentCertV2, CoreBitfield, VrfOutput, VrfProof, VrfSignature}, + v2::{ + AssignmentCertKindV2, AssignmentCertV2, CoreBitfield, VrfPreOutput, VrfProof, VrfSignature, + }, }; use polkadot_primitives::{ AssignmentId, AssignmentPair, CandidateHash, CoreIndex, GroupIndex, IndexedVec, SessionInfo, @@ -459,7 +461,7 @@ fn compute_relay_vrf_modulo_assignments_v1( let cert = AssignmentCert { kind: AssignmentCertKind::RelayVRFModulo { sample: rvm_sample }, vrf: VrfSignature { - output: VrfOutput(vrf_in_out.to_output()), + pre_output: VrfPreOutput(vrf_in_out.to_output()), proof: VrfProof(vrf_proof), }, }; @@ -539,7 +541,7 @@ fn compute_relay_vrf_modulo_assignments_v2( core_bitfield: assignment_bitfield.clone(), }, vrf: VrfSignature { - output: VrfOutput(vrf_in_out.to_output()), + pre_output: VrfPreOutput(vrf_in_out.to_output()), proof: VrfProof(vrf_proof), }, }; @@ -574,7 +576,7 @@ fn compute_relay_vrf_delay_assignments( let cert = AssignmentCertV2 { kind: AssignmentCertKindV2::RelayVRFDelay { core_index: core }, vrf: VrfSignature { - output: VrfOutput(vrf_in_out.to_output()), + pre_output: VrfPreOutput(vrf_in_out.to_output()), proof: VrfProof(vrf_proof), }, }; @@ -689,7 +691,7 @@ pub(crate) fn check_assignment_cert( } } - let vrf_output = &assignment.vrf.output; + let vrf_pre_output = &assignment.vrf.pre_output; let vrf_proof = &assignment.vrf.proof; let first_claimed_core_index = claimed_core_indices.first_one().expect("Checked above; qed") as u32; @@ -704,7 +706,7 @@ pub(crate) fn check_assignment_cert( let (vrf_in_out, _) = public .vrf_verify_extra( relay_vrf_modulo_transcript_v2(relay_vrf_story), - &vrf_output.0, + &vrf_pre_output.0, &vrf_proof.0, assigned_cores_transcript(core_bitfield), ) @@ -753,7 +755,7 @@ pub(crate) fn check_assignment_cert( let (vrf_in_out, _) = public .vrf_verify_extra( relay_vrf_modulo_transcript_v1(relay_vrf_story, *sample), - &vrf_output.0, + &vrf_pre_output.0, &vrf_proof.0, assigned_core_transcript(CoreIndex(first_claimed_core_index)), ) @@ -791,7 +793,7 @@ pub(crate) fn check_assignment_cert( let (vrf_in_out, _) = public .vrf_verify( relay_vrf_delay_transcript(relay_vrf_story, *core_index), - &vrf_output.0, + &vrf_pre_output.0, &vrf_proof.0, ) .map_err(|_| InvalidAssignment(Reason::VRFDelayOutputMismatch))?; diff --git a/polkadot/node/core/approval-voting/src/tests.rs b/polkadot/node/core/approval-voting/src/tests.rs index 11bcba9c388..e1ec194cb54 100644 --- a/polkadot/node/core/approval-voting/src/tests.rs +++ b/polkadot/node/core/approval-voting/src/tests.rs @@ -20,7 +20,7 @@ use crate::backend::V1ReadBackend; use polkadot_node_primitives::{ approval::{ v1::{ - AssignmentCert, AssignmentCertKind, DelayTranche, VrfOutput, VrfProof, VrfSignature, + AssignmentCert, AssignmentCertKind, DelayTranche, VrfPreOutput, VrfProof, VrfSignature, RELAY_VRF_MODULO_CONTEXT, }, v2::{AssignmentCertKindV2, AssignmentCertV2}, @@ -415,9 +415,12 @@ fn garbage_assignment_cert(kind: AssignmentCertKind) -> AssignmentCert { let mut prng = rand_core::OsRng; let keypair = schnorrkel::Keypair::generate_with(&mut prng); let (inout, proof, _) = keypair.vrf_sign(ctx.bytes(msg)); - let out = inout.to_output(); + let preout = inout.to_output(); - AssignmentCert { kind, vrf: VrfSignature { output: VrfOutput(out), proof: VrfProof(proof) } } + AssignmentCert { + kind, + vrf: VrfSignature { pre_output: VrfPreOutput(preout), proof: VrfProof(proof) }, + } } fn garbage_assignment_cert_v2(kind: AssignmentCertKindV2) -> AssignmentCertV2 { @@ -426,9 +429,12 @@ fn garbage_assignment_cert_v2(kind: AssignmentCertKindV2) -> AssignmentCertV2 { let mut prng = rand_core::OsRng; let keypair = schnorrkel::Keypair::generate_with(&mut prng); let (inout, proof, _) = keypair.vrf_sign(ctx.bytes(msg)); - let out = inout.to_output(); + let preout = inout.to_output(); - AssignmentCertV2 { kind, vrf: VrfSignature { output: VrfOutput(out), proof: VrfProof(proof) } } + AssignmentCertV2 { + kind, + vrf: VrfSignature { pre_output: VrfPreOutput(preout), proof: VrfProof(proof) }, + } } fn sign_approval( diff --git a/polkadot/node/network/approval-distribution/src/tests.rs b/polkadot/node/network/approval-distribution/src/tests.rs index 33c38c7c5df..4d272d7af0e 100644 --- a/polkadot/node/network/approval-distribution/src/tests.rs +++ b/polkadot/node/network/approval-distribution/src/tests.rs @@ -25,7 +25,7 @@ use polkadot_node_network_protocol::{ }; use polkadot_node_primitives::approval::{ v1::{ - AssignmentCert, AssignmentCertKind, IndirectAssignmentCert, VrfOutput, VrfProof, + AssignmentCert, AssignmentCertKind, IndirectAssignmentCert, VrfPreOutput, VrfProof, VrfSignature, }, v2::{ @@ -298,14 +298,14 @@ fn fake_assignment_cert(block_hash: Hash, validator: ValidatorIndex) -> Indirect let mut prng = rand_core::OsRng; let keypair = schnorrkel::Keypair::generate_with(&mut prng); let (inout, proof, _) = keypair.vrf_sign(ctx.bytes(msg)); - let out = inout.to_output(); + let preout = inout.to_output(); IndirectAssignmentCert { block_hash, validator, cert: AssignmentCert { kind: AssignmentCertKind::RelayVRFModulo { sample: 1 }, - vrf: VrfSignature { output: VrfOutput(out), proof: VrfProof(proof) }, + vrf: VrfSignature { pre_output: VrfPreOutput(preout), proof: VrfProof(proof) }, }, } } @@ -320,14 +320,14 @@ fn fake_assignment_cert_v2( let mut prng = rand_core::OsRng; let keypair = schnorrkel::Keypair::generate_with(&mut prng); let (inout, proof, _) = keypair.vrf_sign(ctx.bytes(msg)); - let out = inout.to_output(); + let preout = inout.to_output(); IndirectAssignmentCertV2 { block_hash, validator, cert: AssignmentCertV2 { kind: AssignmentCertKindV2::RelayVRFModuloCompact { core_bitfield }, - vrf: VrfSignature { output: VrfOutput(out), proof: VrfProof(proof) }, + vrf: VrfSignature { pre_output: VrfPreOutput(preout), proof: VrfProof(proof) }, }, } } diff --git a/polkadot/node/primitives/src/approval.rs b/polkadot/node/primitives/src/approval.rs index e5ae24f7a51..cc9136b8ae3 100644 --- a/polkadot/node/primitives/src/approval.rs +++ b/polkadot/node/primitives/src/approval.rs @@ -20,7 +20,7 @@ pub mod v1 { use sp_consensus_babe as babe_primitives; pub use sp_consensus_babe::{ - Randomness, Slot, VrfOutput, VrfProof, VrfSignature, VrfTranscript, + Randomness, Slot, VrfPreOutput, VrfProof, VrfSignature, VrfTranscript, }; use parity_scale_codec::{Decode, Encode}; @@ -145,14 +145,14 @@ pub mod v1 { AuthorityOutOfBounds(usize), } - /// An unsafe VRF output. Provide BABE Epoch info to create a `RelayVRFStory`. - pub struct UnsafeVRFOutput { - vrf_output: VrfOutput, + /// An unsafe VRF pre-output. Provide BABE Epoch info to create a `RelayVRFStory`. + pub struct UnsafeVRFPreOutput { + vrf_pre_output: VrfPreOutput, slot: Slot, authority_index: u32, } - impl UnsafeVRFOutput { + impl UnsafeVRFPreOutput { /// Get the slot. pub fn slot(&self) -> Slot { self.slot @@ -177,7 +177,7 @@ pub mod v1 { sp_consensus_babe::make_vrf_transcript(randomness, self.slot, epoch_index); let inout = self - .vrf_output + .vrf_pre_output .0 .attach_input_hash(&pubkey, transcript.0) .map_err(ApprovalError::SchnorrkelSignature)?; @@ -190,7 +190,7 @@ pub mod v1 { /// This fails if either there is no BABE `PreRuntime` digest or /// the digest has type `SecondaryPlain`, which Substrate nodes do /// not produce or accept anymore. - pub fn babe_unsafe_vrf_info(header: &Header) -> Option { + pub fn babe_unsafe_vrf_info(header: &Header) -> Option { use babe_primitives::digests::CompatibleDigestItem; for digest in &header.digest.logs { @@ -198,8 +198,8 @@ pub mod v1 { let slot = pre.slot(); let authority_index = pre.authority_index(); - return pre.vrf_signature().map(|sig| UnsafeVRFOutput { - vrf_output: sig.output.clone(), + return pre.vrf_signature().map(|sig| UnsafeVRFPreOutput { + vrf_pre_output: sig.pre_output.clone(), slot, authority_index, }) @@ -214,7 +214,7 @@ pub mod v1 { pub mod v2 { use parity_scale_codec::{Decode, Encode}; pub use sp_consensus_babe::{ - Randomness, Slot, VrfOutput, VrfProof, VrfSignature, VrfTranscript, + Randomness, Slot, VrfPreOutput, VrfProof, VrfSignature, VrfTranscript, }; use std::ops::BitOr; diff --git a/substrate/client/consensus/babe/src/authorship.rs b/substrate/client/consensus/babe/src/authorship.rs index 3580caba746..fb172239801 100644 --- a/substrate/client/consensus/babe/src/authorship.rs +++ b/substrate/client/consensus/babe/src/authorship.rs @@ -249,7 +249,7 @@ fn claim_primary_slot( .make_bytes::( AUTHORING_SCORE_VRF_CONTEXT, &data.as_ref(), - &vrf_signature.output, + &vrf_signature.pre_output, ) .map(|bytes| u128::from_le_bytes(bytes) < threshold) .unwrap_or_default(); diff --git a/substrate/client/consensus/babe/src/tests.rs b/substrate/client/consensus/babe/src/tests.rs index d097f37c325..e7096832eb3 100644 --- a/substrate/client/consensus/babe/src/tests.rs +++ b/substrate/client/consensus/babe/src/tests.rs @@ -580,7 +580,7 @@ fn claim_vrf_check() { }; let data = make_vrf_sign_data(&epoch.randomness.clone(), 0.into(), epoch.epoch_index); let sign = keystore.sr25519_vrf_sign(AuthorityId::ID, &public, &data).unwrap().unwrap(); - assert_eq!(pre_digest.vrf_signature.output, sign.output); + assert_eq!(pre_digest.vrf_signature.pre_output, sign.pre_output); // We expect a SecondaryVRF claim for slot 1 let pre_digest = match claim_slot(1.into(), &epoch, &keystore).unwrap().0 { @@ -589,7 +589,7 @@ fn claim_vrf_check() { }; let data = make_vrf_sign_data(&epoch.randomness.clone(), 1.into(), epoch.epoch_index); let sign = keystore.sr25519_vrf_sign(AuthorityId::ID, &public, &data).unwrap().unwrap(); - assert_eq!(pre_digest.vrf_signature.output, sign.output); + assert_eq!(pre_digest.vrf_signature.pre_output, sign.pre_output); // Check that correct epoch index has been used if epochs are skipped (primary VRF) let slot = Slot::from(103); @@ -601,7 +601,7 @@ fn claim_vrf_check() { let data = make_vrf_sign_data(&epoch.randomness.clone(), slot, fixed_epoch.epoch_index); let sign = keystore.sr25519_vrf_sign(AuthorityId::ID, &public, &data).unwrap().unwrap(); assert_eq!(fixed_epoch.epoch_index, 11); - assert_eq!(claim.vrf_signature.output, sign.output); + assert_eq!(claim.vrf_signature.pre_output, sign.pre_output); // Check that correct epoch index has been used if epochs are skipped (secondary VRF) let slot = Slot::from(100); @@ -613,7 +613,7 @@ fn claim_vrf_check() { let data = make_vrf_sign_data(&epoch.randomness.clone(), slot, fixed_epoch.epoch_index); let sign = keystore.sr25519_vrf_sign(AuthorityId::ID, &public, &data).unwrap().unwrap(); assert_eq!(fixed_epoch.epoch_index, 11); - assert_eq!(pre_digest.vrf_signature.output, sign.output); + assert_eq!(pre_digest.vrf_signature.pre_output, sign.pre_output); } // Propose and import a new BABE block on top of the given parent. diff --git a/substrate/client/consensus/babe/src/verification.rs b/substrate/client/consensus/babe/src/verification.rs index 3de5eacc2c5..c6e4ec0c10c 100644 --- a/substrate/client/consensus/babe/src/verification.rs +++ b/substrate/client/consensus/babe/src/verification.rs @@ -185,7 +185,7 @@ fn check_primary_header( .make_bytes::( AUTHORING_SCORE_VRF_CONTEXT, &data.as_ref(), - &pre_digest.vrf_signature.output, + &pre_digest.vrf_signature.pre_output, ) .map(u128::from_le_bytes) .map_err(|_| babe_err(Error::VrfVerificationFailed))?; diff --git a/substrate/client/keystore/src/local.rs b/substrate/client/keystore/src/local.rs index 8089dbba035..3b29f435e2a 100644 --- a/substrate/client/keystore/src/local.rs +++ b/substrate/client/keystore/src/local.rs @@ -120,18 +120,18 @@ impl LocalKeystore { Ok(sig) } - fn vrf_output( + fn vrf_pre_output( &self, key_type: KeyTypeId, public: &T::Public, input: &T::VrfInput, - ) -> std::result::Result, TraitError> { - let preout = self + ) -> std::result::Result, TraitError> { + let pre_output = self .0 .read() .key_pair_by_type::(public, key_type)? - .map(|pair| pair.vrf_output(input)); - Ok(preout) + .map(|pair| pair.vrf_pre_output(input)); + Ok(pre_output) } } @@ -188,13 +188,13 @@ impl Keystore for LocalKeystore { self.vrf_sign::(key_type, public, data) } - fn sr25519_vrf_output( + fn sr25519_vrf_pre_output( &self, key_type: KeyTypeId, public: &sr25519::Public, input: &sr25519::vrf::VrfInput, - ) -> std::result::Result, TraitError> { - self.vrf_output::(key_type, public, input) + ) -> std::result::Result, TraitError> { + self.vrf_pre_output::(key_type, public, input) } fn ed25519_public_keys(&self, key_type: KeyTypeId) -> Vec { @@ -293,13 +293,13 @@ impl Keystore for LocalKeystore { self.vrf_sign::(key_type, public, data) } - fn bandersnatch_vrf_output( + fn bandersnatch_vrf_pre_output( &self, key_type: KeyTypeId, public: &bandersnatch::Public, input: &bandersnatch::vrf::VrfInput, - ) -> std::result::Result, TraitError> { - self.vrf_output::(key_type, public, input) + ) -> std::result::Result, TraitError> { + self.vrf_pre_output::(key_type, public, input) } fn bandersnatch_ring_vrf_sign( diff --git a/substrate/frame/babe/src/lib.rs b/substrate/frame/babe/src/lib.rs index 57e1dbb6b53..a6e44390dbc 100644 --- a/substrate/frame/babe/src/lib.rs +++ b/substrate/frame/babe/src/lib.rs @@ -384,7 +384,11 @@ pub mod pallet { }); public - .make_bytes(RANDOMNESS_VRF_CONTEXT, &transcript, &signature.output) + .make_bytes( + RANDOMNESS_VRF_CONTEXT, + &transcript, + &signature.pre_output, + ) .ok() }); diff --git a/substrate/frame/sassafras/src/lib.rs b/substrate/frame/sassafras/src/lib.rs index b6f405f5654..0ee8657489b 100644 --- a/substrate/frame/sassafras/src/lib.rs +++ b/substrate/frame/sassafras/src/lib.rs @@ -272,11 +272,11 @@ pub mod pallet { #[pallet::storage] pub type RingVerifierData = StorageValue<_, vrf::RingVerifierData>; - /// Slot claim vrf-preoutput used to generate per-slot randomness. + /// Slot claim VRF pre-output used to generate per-slot randomness. /// /// The value is ephemeral and is cleared on block finalization. #[pallet::storage] - pub(crate) type ClaimTemporaryData = StorageValue<_, vrf::VrfOutput>; + pub(crate) type ClaimTemporaryData = StorageValue<_, vrf::VrfPreOutput>; /// Genesis configuration for Sassafras protocol. #[pallet::genesis_config] @@ -324,12 +324,12 @@ pub mod pallet { Self::post_genesis_initialize(claim.slot); } - let randomness_output = claim + let randomness_pre_output = claim .vrf_signature - .outputs + .pre_outputs .get(0) - .expect("Valid claim must have vrf signature; qed"); - ClaimTemporaryData::::put(randomness_output); + .expect("Valid claim must have VRF signature; qed"); + ClaimTemporaryData::::put(randomness_pre_output); let trigger_weight = T::EpochChangeTrigger::trigger::(block_num); @@ -346,9 +346,9 @@ pub mod pallet { CurrentSlot::::get(), EpochIndex::::get(), ); - let randomness_output = ClaimTemporaryData::::take() + let randomness_pre_output = ClaimTemporaryData::::take() .expect("Unconditionally populated in `on_initialize`; `on_finalize` is always called after; qed"); - let randomness = randomness_output + let randomness = randomness_pre_output .make_bytes::(RANDOMNESS_VRF_CONTEXT, &randomness_input); Self::deposit_slot_randomness(&randomness); @@ -422,15 +422,15 @@ pub mod pallet { for ticket in tickets { debug!(target: LOG_TARGET, "Checking ring proof"); - let Some(ticket_id_output) = ticket.signature.outputs.get(0) else { - debug!(target: LOG_TARGET, "Missing ticket vrf output from ring signature"); + let Some(ticket_id_pre_output) = ticket.signature.pre_outputs.get(0) else { + debug!(target: LOG_TARGET, "Missing ticket VRF pre-output from ring signature"); continue }; let ticket_id_input = vrf::ticket_id_input(&randomness, ticket.body.attempt_idx, epoch_idx); // Check threshold constraint - let ticket_id = vrf::make_ticket_id(&ticket_id_input, &ticket_id_output); + let ticket_id = vrf::make_ticket_id(&ticket_id_input, &ticket_id_pre_output); if ticket_id >= ticket_threshold { debug!(target: LOG_TARGET, "Ignoring ticket over threshold ({:032x} >= {:032x})", ticket_id, ticket_threshold); continue diff --git a/substrate/frame/sassafras/src/mock.rs b/substrate/frame/sassafras/src/mock.rs index b700207c499..5aca815cc21 100644 --- a/substrate/frame/sassafras/src/mock.rs +++ b/substrate/frame/sassafras/src/mock.rs @@ -190,9 +190,9 @@ pub fn make_ticket_body(attempt_idx: u32, pair: &AuthorityPair) -> (TicketId, Ti let randomness = Sassafras::next_randomness(); let ticket_id_input = vrf::ticket_id_input(&randomness, attempt_idx, epoch); - let ticket_id_output = pair.as_inner_ref().vrf_output(&ticket_id_input); + let ticket_id_pre_output = pair.as_inner_ref().vrf_pre_output(&ticket_id_input); - let id = vrf::make_ticket_id(&ticket_id_input, &ticket_id_output); + let id = vrf::make_ticket_id(&ticket_id_input, &ticket_id_pre_output); // Make a dummy ephemeral public that hopefully is unique within one test instance. // In the tests, the values within the erased public are just used to compare diff --git a/substrate/primitives/consensus/babe/src/lib.rs b/substrate/primitives/consensus/babe/src/lib.rs index c083bfd9a31..d6b2cdd55e0 100644 --- a/substrate/primitives/consensus/babe/src/lib.rs +++ b/substrate/primitives/consensus/babe/src/lib.rs @@ -33,7 +33,7 @@ use sp_std::vec::Vec; use crate::digests::{NextConfigDescriptor, NextEpochDescriptor}; pub use sp_core::sr25519::vrf::{ - VrfInput, VrfOutput, VrfProof, VrfSignData, VrfSignature, VrfTranscript, + VrfInput, VrfPreOutput, VrfProof, VrfSignData, VrfSignature, VrfTranscript, }; /// Key type for BABE module. diff --git a/substrate/primitives/consensus/sassafras/src/vrf.rs b/substrate/primitives/consensus/sassafras/src/vrf.rs index afcb1d09f8f..5deacd8e994 100644 --- a/substrate/primitives/consensus/sassafras/src/vrf.rs +++ b/substrate/primitives/consensus/sassafras/src/vrf.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Utilities related to VRF input, output and signatures. +//! Utilities related to VRF input, pre-output and signatures. use crate::{Randomness, TicketBody, TicketId}; use scale_codec::Encode; @@ -24,7 +24,7 @@ use sp_std::vec::Vec; pub use sp_core::bandersnatch::{ ring_vrf::{RingProver, RingVerifier, RingVerifierData, RingVrfSignature}, - vrf::{VrfInput, VrfOutput, VrfSignData, VrfSignature}, + vrf::{VrfInput, VrfPreOutput, VrfSignData, VrfSignature}, }; /// Ring VRF domain size for Sassafras consensus. @@ -90,21 +90,21 @@ pub fn ticket_body_sign_data(ticket_body: &TicketBody, ticket_id_input: VrfInput ) } -/// Make ticket-id from the given VRF input and output. +/// Make ticket-id from the given VRF input and pre-output. /// /// Input should have been obtained via [`ticket_id_input`]. -/// Output should have been obtained from the input directly using the vrf secret key -/// or from the vrf signature outputs. -pub fn make_ticket_id(input: &VrfInput, output: &VrfOutput) -> TicketId { - let bytes = output.make_bytes::<16>(b"ticket-id", input); +/// Pre-output should have been obtained from the input directly using the vrf +/// secret key or from the vrf signature pre-outputs. +pub fn make_ticket_id(input: &VrfInput, pre_output: &VrfPreOutput) -> TicketId { + let bytes = pre_output.make_bytes::<16>(b"ticket-id", input); u128::from_le_bytes(bytes) } -/// Make revealed key seed from a given VRF input and ouput. +/// Make revealed key seed from a given VRF input and pre-ouput. /// /// Input should have been obtained via [`revealed_key_input`]. -/// Output should have been obtained from the input directly using the vrf secret key -/// or from the vrf signature outputs. -pub fn make_revealed_key_seed(input: &VrfInput, output: &VrfOutput) -> [u8; 32] { - output.make_bytes::<32>(b"revealed-seed", input) +/// Pre-output should have been obtained from the input directly using the vrf +/// secret key or from the vrf signature pre-outputs. +pub fn make_revealed_key_seed(input: &VrfInput, pre_output: &VrfPreOutput) -> [u8; 32] { + pre_output.make_bytes::<32>(b"revealed-seed", input) } diff --git a/substrate/primitives/core/src/bandersnatch.rs b/substrate/primitives/core/src/bandersnatch.rs index b91c001a7de..463d49fd889 100644 --- a/substrate/primitives/core/src/bandersnatch.rs +++ b/substrate/primitives/core/src/bandersnatch.rs @@ -295,7 +295,7 @@ impl TraitPair for Pair { fn verify>(signature: &Signature, data: M, public: &Public) -> bool { let data = vrf::VrfSignData::new_unchecked(SIGNING_CTX, &[data.as_ref()], None); let signature = - vrf::VrfSignature { signature: *signature, outputs: vrf::VrfIosVec::default() }; + vrf::VrfSignature { signature: *signature, pre_outputs: vrf::VrfIosVec::default() }; public.vrf_verify(&data, &signature) } @@ -319,18 +319,18 @@ pub mod vrf { ThinVrfSignature, Transcript, }; - /// Max number of inputs/outputs which can be handled by the VRF signing procedures. + /// Max number of inputs/pre-outputs which can be handled by the VRF signing procedures. /// /// The number is quite arbitrary and chosen to fulfill the use cases found so far. /// If required it can be extended in the future. pub const MAX_VRF_IOS: u32 = 3; - /// Bounded vector used for VRF inputs and outputs. + /// Bounded vector used for VRF inputs and pre-outputs. /// /// Can contain at most [`MAX_VRF_IOS`] elements. pub type VrfIosVec = BoundedVec>; - /// VRF input to construct a [`VrfOutput`] instance and embeddable in [`VrfSignData`]. + /// VRF input to construct a [`VrfPreOutput`] instance and embeddable in [`VrfSignData`]. #[derive(Clone, Debug)] pub struct VrfInput(pub(super) bandersnatch_vrfs::VrfInput); @@ -342,15 +342,15 @@ pub mod vrf { } } - /// VRF (pre)output derived from [`VrfInput`] using a [`VrfSecret`]. + /// VRF pre-output derived from [`VrfInput`] using a [`VrfSecret`]. /// /// This object is used to produce an arbitrary number of verifiable pseudo random /// bytes and is often called pre-output to emphasize that this is not the actual /// output of the VRF but an object capable of generating the output. #[derive(Clone, Debug, PartialEq, Eq)] - pub struct VrfOutput(pub(super) bandersnatch_vrfs::VrfPreOut); + pub struct VrfPreOutput(pub(super) bandersnatch_vrfs::VrfPreOut); - impl Encode for VrfOutput { + impl Encode for VrfPreOutput { fn encode(&self) -> Vec { let mut bytes = [0; PREOUT_SERIALIZED_SIZE]; self.0 @@ -360,25 +360,25 @@ pub mod vrf { } } - impl Decode for VrfOutput { + impl Decode for VrfPreOutput { fn decode(i: &mut R) -> Result { let buf = <[u8; PREOUT_SERIALIZED_SIZE]>::decode(i)?; let preout = bandersnatch_vrfs::VrfPreOut::deserialize_compressed_unchecked(buf.as_slice()) .map_err(|_| "vrf-preout decode error: bad preout")?; - Ok(VrfOutput(preout)) + Ok(VrfPreOutput(preout)) } } - impl EncodeLike for VrfOutput {} + impl EncodeLike for VrfPreOutput {} - impl MaxEncodedLen for VrfOutput { + impl MaxEncodedLen for VrfPreOutput { fn max_encoded_len() -> usize { <[u8; PREOUT_SERIALIZED_SIZE]>::max_encoded_len() } } - impl TypeInfo for VrfOutput { + impl TypeInfo for VrfPreOutput { type Identity = [u8; PREOUT_SERIALIZED_SIZE]; fn type_info() -> scale_info::Type { @@ -395,14 +395,14 @@ pub mod vrf { /// A good explaination of the topic can be found in Merlin [docs](https://merlin.cool/) /// /// The `inputs` is a sequence of [`VrfInput`]s which, during the signing procedure, are - /// first transformed to [`VrfOutput`]s. Both inputs and outputs are then appended to + /// first transformed to [`VrfPreOutput`]s. Both inputs and pre-outputs are then appended to /// the transcript before signing the Fiat-Shamir transform result (the challenge). /// /// In practice, as a user, all these technical details can be easily ignored. /// What is important to remember is: /// - *Transcript* is an object defining the protocol and used to produce the signature. This - /// object doesn't influence the `VrfOutput`s values. - /// - *Vrf inputs* is some additional data which is used to produce *vrf outputs*. This data + /// object doesn't influence the `VrfPreOutput`s values. + /// - *Vrf inputs* is some additional data which is used to produce *vrf pre-outputs*. This data /// will contribute to the signature as well. #[derive(Clone)] pub struct VrfSignData { @@ -473,7 +473,7 @@ pub mod vrf { /// VRF signature. /// - /// Includes both the transcript `signature` and the `outputs` generated from the + /// Includes both the transcript `signature` and the `pre-outputs` generated from the /// [`VrfSignData::inputs`]. /// /// Refer to [`VrfSignData`] for more details. @@ -481,14 +481,14 @@ pub mod vrf { pub struct VrfSignature { /// Transcript signature. pub signature: Signature, - /// VRF (pre)outputs. - pub outputs: VrfIosVec, + /// VRF pre-outputs. + pub pre_outputs: VrfIosVec, } #[cfg(feature = "full_crypto")] impl VrfCrypto for Pair { type VrfInput = VrfInput; - type VrfOutput = VrfOutput; + type VrfPreOutput = VrfPreOutput; type VrfSignData = VrfSignData; type VrfSignature = VrfSignature; } @@ -507,15 +507,15 @@ pub mod vrf { } } - fn vrf_output(&self, input: &Self::VrfInput) -> Self::VrfOutput { - let output = self.secret.vrf_preout(&input.0); - VrfOutput(output) + fn vrf_pre_output(&self, input: &Self::VrfInput) -> Self::VrfPreOutput { + let pre_output = self.secret.vrf_preout(&input.0); + VrfPreOutput(pre_output) } } impl VrfCrypto for Public { type VrfInput = VrfInput; - type VrfOutput = VrfOutput; + type VrfPreOutput = VrfPreOutput; type VrfSignData = VrfSignData; type VrfSignature = VrfSignature; } @@ -523,12 +523,12 @@ pub mod vrf { impl VrfPublic for Public { fn vrf_verify(&self, data: &Self::VrfSignData, signature: &Self::VrfSignature) -> bool { const _: () = assert!(MAX_VRF_IOS == 3, "`MAX_VRF_IOS` expected to be 3"); - let outputs_len = signature.outputs.len(); - if outputs_len != data.inputs.len() { + let pre_outputs_len = signature.pre_outputs.len(); + if pre_outputs_len != data.inputs.len() { return false } // Workaround to overcome backend signature generic over the number of IOs. - match outputs_len { + match pre_outputs_len { 0 => self.vrf_verify_gen::<0>(data, signature), 1 => self.vrf_verify_gen::<1>(data, signature), 2 => self.vrf_verify_gen::<2>(data, signature), @@ -546,11 +546,12 @@ pub mod vrf { let thin_signature: ThinVrfSignature = self.secret.sign_thin_vrf(data.transcript.clone(), &ios); - let outputs: Vec<_> = thin_signature.preouts.into_iter().map(VrfOutput).collect(); - let outputs = VrfIosVec::truncate_from(outputs); + let pre_outputs: Vec<_> = + thin_signature.preouts.into_iter().map(VrfPreOutput).collect(); + let pre_outputs = VrfIosVec::truncate_from(pre_outputs); let mut signature = - VrfSignature { signature: Signature([0; SIGNATURE_SERIALIZED_SIZE]), outputs }; + VrfSignature { signature: Signature([0; SIGNATURE_SERIALIZED_SIZE]), pre_outputs }; thin_signature .proof @@ -583,7 +584,7 @@ pub mod vrf { }; let preouts: [bandersnatch_vrfs::VrfPreOut; N] = - core::array::from_fn(|i| signature.outputs[i].0); + core::array::from_fn(|i| signature.pre_outputs[i].0); // Deserialize only the proof, the rest has already been deserialized // This is another hack used because backend signature type is generic over @@ -602,7 +603,7 @@ pub mod vrf { } } - impl VrfOutput { + impl VrfPreOutput { /// Generate an arbitrary number of bytes from the given `context` and VRF `input`. pub fn make_bytes( &self, @@ -804,8 +805,8 @@ pub mod ring_vrf { pub struct RingVrfSignature { /// Ring signature. pub signature: [u8; RING_SIGNATURE_SERIALIZED_SIZE], - /// VRF (pre)outputs. - pub outputs: VrfIosVec, + /// VRF pre-outputs. + pub pre_outputs: VrfIosVec, } #[cfg(feature = "full_crypto")] @@ -838,11 +839,12 @@ pub mod ring_vrf { bandersnatch_vrfs::RingProver { ring_prover: prover, secret: &self.secret } .sign_ring_vrf(data.transcript.clone(), &ios); - let outputs: Vec<_> = ring_signature.preouts.into_iter().map(VrfOutput).collect(); - let outputs = VrfIosVec::truncate_from(outputs); + let pre_outputs: Vec<_> = + ring_signature.preouts.into_iter().map(VrfPreOutput).collect(); + let pre_outputs = VrfIosVec::truncate_from(pre_outputs); let mut signature = - RingVrfSignature { outputs, signature: [0; RING_SIGNATURE_SERIALIZED_SIZE] }; + RingVrfSignature { pre_outputs, signature: [0; RING_SIGNATURE_SERIALIZED_SIZE] }; ring_signature .proof @@ -860,7 +862,7 @@ pub mod ring_vrf { /// from which the [`RingVerifier`] has been constructed. pub fn ring_vrf_verify(&self, data: &VrfSignData, verifier: &RingVerifier) -> bool { const _: () = assert!(MAX_VRF_IOS == 3, "`MAX_VRF_IOS` expected to be 3"); - let preouts_len = self.outputs.len(); + let preouts_len = self.pre_outputs.len(); if preouts_len != data.inputs.len() { return false } @@ -888,7 +890,7 @@ pub mod ring_vrf { }; let preouts: [bandersnatch_vrfs::VrfPreOut; N] = - core::array::from_fn(|i| self.outputs[i].0); + core::array::from_fn(|i| self.pre_outputs[i].0); let signature = bandersnatch_vrfs::RingVrfSignature { proof: vrf_signature.proof, preouts }; @@ -1038,11 +1040,11 @@ mod tests { let signature = pair.vrf_sign(&data); let o10 = pair.make_bytes::<32>(b"ctx1", &i1); - let o11 = signature.outputs[0].make_bytes::<32>(b"ctx1", &i1); + let o11 = signature.pre_outputs[0].make_bytes::<32>(b"ctx1", &i1); assert_eq!(o10, o11); let o20 = pair.make_bytes::<48>(b"ctx2", &i2); - let o21 = signature.outputs[1].make_bytes::<48>(b"ctx2", &i2); + let o21 = signature.pre_outputs[1].make_bytes::<48>(b"ctx2", &i2); assert_eq!(o20, o21); } @@ -1142,11 +1144,11 @@ mod tests { let signature = pair.ring_vrf_sign(&data, &prover); let o10 = pair.make_bytes::<32>(b"ctx1", &i1); - let o11 = signature.outputs[0].make_bytes::<32>(b"ctx1", &i1); + let o11 = signature.pre_outputs[0].make_bytes::<32>(b"ctx1", &i1); assert_eq!(o10, o11); let o20 = pair.make_bytes::<48>(b"ctx2", &i2); - let o21 = signature.outputs[1].make_bytes::<48>(b"ctx2", &i2); + let o21 = signature.pre_outputs[1].make_bytes::<48>(b"ctx2", &i2); assert_eq!(o20, o21); } diff --git a/substrate/primitives/core/src/crypto.rs b/substrate/primitives/core/src/crypto.rs index c9719e344d3..1f3ae744533 100644 --- a/substrate/primitives/core/src/crypto.rs +++ b/substrate/primitives/core/src/crypto.rs @@ -1109,8 +1109,8 @@ impl<'a> TryFrom<&'a str> for KeyTypeId { pub trait VrfCrypto { /// VRF input. type VrfInput; - /// VRF output. - type VrfOutput; + /// VRF pre-output. + type VrfPreOutput; /// VRF signing data. type VrfSignData; /// VRF signature. @@ -1119,8 +1119,8 @@ pub trait VrfCrypto { /// VRF Secret Key. pub trait VrfSecret: VrfCrypto { - /// Get VRF-specific output . - fn vrf_output(&self, data: &Self::VrfInput) -> Self::VrfOutput; + /// Get VRF-specific pre-output. + fn vrf_pre_output(&self, data: &Self::VrfInput) -> Self::VrfPreOutput; /// Sign VRF-specific data. fn vrf_sign(&self, input: &Self::VrfSignData) -> Self::VrfSignature; diff --git a/substrate/primitives/core/src/sr25519.rs b/substrate/primitives/core/src/sr25519.rs index ffa52ef97d1..71d9c3b3247 100644 --- a/substrate/primitives/core/src/sr25519.rs +++ b/substrate/primitives/core/src/sr25519.rs @@ -628,36 +628,36 @@ pub mod vrf { /// VRF signature data #[derive(Clone, Debug, PartialEq, Eq, Encode, Decode, MaxEncodedLen, TypeInfo)] pub struct VrfSignature { - /// VRF output. - pub output: VrfOutput, + /// VRF pre-output. + pub pre_output: VrfPreOutput, /// VRF proof. pub proof: VrfProof, } - /// VRF output type suitable for schnorrkel operations. + /// VRF pre-output type suitable for schnorrkel operations. #[derive(Clone, Debug, PartialEq, Eq)] - pub struct VrfOutput(pub schnorrkel::vrf::VRFOutput); + pub struct VrfPreOutput(pub schnorrkel::vrf::VRFOutput); - impl Encode for VrfOutput { + impl Encode for VrfPreOutput { fn encode(&self) -> Vec { self.0.as_bytes().encode() } } - impl Decode for VrfOutput { + impl Decode for VrfPreOutput { fn decode(i: &mut R) -> Result { let decoded = <[u8; VRF_OUTPUT_LENGTH]>::decode(i)?; Ok(Self(schnorrkel::vrf::VRFOutput::from_bytes(&decoded).map_err(convert_error)?)) } } - impl MaxEncodedLen for VrfOutput { + impl MaxEncodedLen for VrfPreOutput { fn max_encoded_len() -> usize { <[u8; VRF_OUTPUT_LENGTH]>::max_encoded_len() } } - impl TypeInfo for VrfOutput { + impl TypeInfo for VrfPreOutput { type Identity = [u8; VRF_OUTPUT_LENGTH]; fn type_info() -> scale_info::Type { @@ -699,7 +699,7 @@ pub mod vrf { #[cfg(feature = "full_crypto")] impl VrfCrypto for Pair { type VrfInput = VrfTranscript; - type VrfOutput = VrfOutput; + type VrfPreOutput = VrfPreOutput; type VrfSignData = VrfSignData; type VrfSignature = VrfSignature; } @@ -717,18 +717,18 @@ pub mod vrf { let proof = self.0.dleq_proove(extra, &inout, true).0; - VrfSignature { output: VrfOutput(inout.to_output()), proof: VrfProof(proof) } + VrfSignature { pre_output: VrfPreOutput(inout.to_output()), proof: VrfProof(proof) } } - fn vrf_output(&self, input: &Self::VrfInput) -> Self::VrfOutput { - let output = self.0.vrf_create_hash(input.0.clone()).to_output(); - VrfOutput(output) + fn vrf_pre_output(&self, input: &Self::VrfInput) -> Self::VrfPreOutput { + let pre_output = self.0.vrf_create_hash(input.0.clone()).to_output(); + VrfPreOutput(pre_output) } } impl VrfCrypto for Public { type VrfInput = VrfTranscript; - type VrfOutput = VrfOutput; + type VrfPreOutput = VrfPreOutput; type VrfSignData = VrfSignData; type VrfSignature = VrfSignature; } @@ -739,7 +739,7 @@ pub mod vrf { let public = schnorrkel::PublicKey::from_bytes(self)?; let inout = - signature.output.0.attach_input_hash(&public, data.transcript.0.clone())?; + signature.pre_output.0.attach_input_hash(&public, data.transcript.0.clone())?; let extra = data .extra @@ -802,19 +802,21 @@ pub mod vrf { &self, context: &[u8], input: &VrfInput, - output: &VrfOutput, + pre_output: &VrfPreOutput, ) -> Result<[u8; N], codec::Error> where [u8; N]: Default, { let pubkey = schnorrkel::PublicKey::from_bytes(&self.0).map_err(convert_error)?; - let inout = - output.0.attach_input_hash(&pubkey, input.0.clone()).map_err(convert_error)?; + let inout = pre_output + .0 + .attach_input_hash(&pubkey, input.0.clone()) + .map_err(convert_error)?; Ok(inout.make_bytes::<[u8; N]>(context)) } } - impl VrfOutput { + impl VrfPreOutput { /// Generate output bytes from the given VRF configuration. pub fn make_bytes( &self, @@ -1097,10 +1099,10 @@ mod tests { let input = VrfTranscript::new(b"label", &[(b"domain1", b"data1")]); - let output = pair.vrf_output(&input); + let pre_output = pair.vrf_pre_output(&input); let out1 = pair.make_bytes::<32>(ctx, &input); - let out2 = output.make_bytes::<32>(ctx, &input, &public).unwrap(); + let out2 = pre_output.make_bytes::<32>(ctx, &input, &public).unwrap(); assert_eq!(out1, out2); let extra = VrfTranscript::new(b"extra", &[(b"domain2", b"data2")]); @@ -1108,7 +1110,7 @@ mod tests { let signature = pair.vrf_sign(&data); assert!(public.vrf_verify(&data, &signature)); - let out3 = public.make_bytes::<32>(ctx, &input, &signature.output).unwrap(); + let out3 = public.make_bytes::<32>(ctx, &input, &signature.pre_output).unwrap(); assert_eq!(out2, out3); } @@ -1126,7 +1128,7 @@ mod tests { assert!(public.vrf_verify(&data, &signature)); let out1 = pair.make_bytes::<32>(ctx, &input); - let out2 = public.make_bytes::<32>(ctx, &input, &signature.output).unwrap(); + let out2 = public.make_bytes::<32>(ctx, &input, &signature.pre_output).unwrap(); assert_eq!(out1, out2); // Direct call to backend version of sign after check with extra params @@ -1139,9 +1141,9 @@ mod tests { }) .unwrap(); let signature2 = - VrfSignature { output: VrfOutput(inout.to_output()), proof: VrfProof(proof) }; + VrfSignature { pre_output: VrfPreOutput(inout.to_output()), proof: VrfProof(proof) }; assert!(public.vrf_verify(&data, &signature2)); - assert_eq!(signature.output, signature2.output); + assert_eq!(signature.pre_output, signature2.pre_output); } } diff --git a/substrate/primitives/keystore/src/lib.rs b/substrate/primitives/keystore/src/lib.rs index e415080779c..07c4e2d5fd1 100644 --- a/substrate/primitives/keystore/src/lib.rs +++ b/substrate/primitives/keystore/src/lib.rs @@ -92,19 +92,19 @@ pub trait Keystore: Send + Sync { data: &sr25519::vrf::VrfSignData, ) -> Result, Error>; - /// Generate an sr25519 VRF output for a given input data. + /// Generate an sr25519 VRF pre-output for a given input data. /// /// Receives [`KeyTypeId`] and an [`sr25519::Public`] key to be able to map /// them to a private key that exists in the keystore. /// /// Returns `None` if the given `key_type` and `public` combination doesn't /// exist in the keystore or an `Err` when something failed. - fn sr25519_vrf_output( + fn sr25519_vrf_pre_output( &self, key_type: KeyTypeId, public: &sr25519::Public, input: &sr25519::vrf::VrfInput, - ) -> Result, Error>; + ) -> Result, Error>; /// Returns all ed25519 public keys for the given key type. fn ed25519_public_keys(&self, key_type: KeyTypeId) -> Vec; @@ -223,7 +223,7 @@ pub trait Keystore: Send + Sync { input: &bandersnatch::vrf::VrfSignData, ) -> Result, Error>; - /// Generate a bandersnatch VRF (pre)output for a given input data. + /// Generate a bandersnatch VRF pre-output for a given input data. /// /// Receives [`KeyTypeId`] and an [`bandersnatch::Public`] key to be able to map /// them to a private key that exists in the keystore. @@ -231,12 +231,12 @@ pub trait Keystore: Send + Sync { /// Returns `None` if the given `key_type` and `public` combination doesn't /// exist in the keystore or an `Err` when something failed. #[cfg(feature = "bandersnatch-experimental")] - fn bandersnatch_vrf_output( + fn bandersnatch_vrf_pre_output( &self, key_type: KeyTypeId, public: &bandersnatch::Public, input: &bandersnatch::vrf::VrfInput, - ) -> Result, Error>; + ) -> Result, Error>; /// Generate a bandersnatch ring-VRF signature for the given data. /// @@ -474,13 +474,13 @@ impl Keystore for Arc { (**self).sr25519_vrf_sign(key_type, public, data) } - fn sr25519_vrf_output( + fn sr25519_vrf_pre_output( &self, key_type: KeyTypeId, public: &sr25519::Public, input: &sr25519::vrf::VrfInput, - ) -> Result, Error> { - (**self).sr25519_vrf_output(key_type, public, input) + ) -> Result, Error> { + (**self).sr25519_vrf_pre_output(key_type, public, input) } fn ed25519_public_keys(&self, key_type: KeyTypeId) -> Vec { @@ -569,13 +569,13 @@ impl Keystore for Arc { } #[cfg(feature = "bandersnatch-experimental")] - fn bandersnatch_vrf_output( + fn bandersnatch_vrf_pre_output( &self, key_type: KeyTypeId, public: &bandersnatch::Public, input: &bandersnatch::vrf::VrfInput, - ) -> Result, Error> { - (**self).bandersnatch_vrf_output(key_type, public, input) + ) -> Result, Error> { + (**self).bandersnatch_vrf_pre_output(key_type, public, input) } #[cfg(feature = "bandersnatch-experimental")] diff --git a/substrate/primitives/keystore/src/testing.rs b/substrate/primitives/keystore/src/testing.rs index 9b59b6d09ea..585efba0283 100644 --- a/substrate/primitives/keystore/src/testing.rs +++ b/substrate/primitives/keystore/src/testing.rs @@ -113,14 +113,14 @@ impl MemoryKeystore { Ok(sig) } - fn vrf_output( + fn vrf_pre_output( &self, key_type: KeyTypeId, public: &T::Public, input: &T::VrfInput, - ) -> Result, Error> { - let preout = self.pair::(key_type, public).map(|pair| pair.vrf_output(input)); - Ok(preout) + ) -> Result, Error> { + let pre_output = self.pair::(key_type, public).map(|pair| pair.vrf_pre_output(input)); + Ok(pre_output) } } @@ -155,13 +155,13 @@ impl Keystore for MemoryKeystore { self.vrf_sign::(key_type, public, data) } - fn sr25519_vrf_output( + fn sr25519_vrf_pre_output( &self, key_type: KeyTypeId, public: &sr25519::Public, input: &sr25519::vrf::VrfInput, - ) -> Result, Error> { - self.vrf_output::(key_type, public, input) + ) -> Result, Error> { + self.vrf_pre_output::(key_type, public, input) } fn ed25519_public_keys(&self, key_type: KeyTypeId) -> Vec { @@ -265,13 +265,13 @@ impl Keystore for MemoryKeystore { } #[cfg(feature = "bandersnatch-experimental")] - fn bandersnatch_vrf_output( + fn bandersnatch_vrf_pre_output( &self, key_type: KeyTypeId, public: &bandersnatch::Public, input: &bandersnatch::vrf::VrfInput, - ) -> Result, Error> { - self.vrf_output::(key_type, public, input) + ) -> Result, Error> { + self.vrf_pre_output::(key_type, public, input) } #[cfg(feature = "bls-experimental")] @@ -443,7 +443,7 @@ mod tests { } #[test] - fn sr25519_vrf_output() { + fn sr25519_vrf_pre_output() { let store = MemoryKeystore::new(); let secret_uri = "//Alice"; @@ -458,16 +458,17 @@ mod tests { ], ); - let result = store.sr25519_vrf_output(SR25519, &pair.public(), &input); + let result = store.sr25519_vrf_pre_output(SR25519, &pair.public(), &input); assert!(result.unwrap().is_none()); store .insert(SR25519, secret_uri, pair.public().as_ref()) .expect("Inserts unknown key"); - let preout = store.sr25519_vrf_output(SR25519, &pair.public(), &input).unwrap().unwrap(); + let pre_output = + store.sr25519_vrf_pre_output(SR25519, &pair.public(), &input).unwrap().unwrap(); - let result = preout.make_bytes::<32>(b"rand", &input, &pair.public()); + let result = pre_output.make_bytes::<32>(b"rand", &input, &pair.public()); assert!(result.is_ok()); } -- GitLab From 19bf94d6378aa01e5b8e9747ad44719f2aa18d47 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Dec 2023 09:43:21 +0100 Subject: [PATCH 06/59] Bump parity-db from 0.4.10 to 0.4.12 (#2635) Bumps [parity-db](https://github.com/paritytech/parity-db) from 0.4.10 to 0.4.12.
Changelog

Sourced from parity-db's changelog.

[v0.4.12] - 2023-10-12

[v0.4.11] - 2023-09-13

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=parity-db&package-manager=cargo&previous-version=0.4.10&new-version=0.4.12)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- polkadot/node/service/Cargo.toml | 2 +- polkadot/node/subsystem-util/Cargo.toml | 2 +- substrate/bin/node/bench/Cargo.toml | 2 +- substrate/client/db/Cargo.toml | 2 +- substrate/client/statement-store/Cargo.toml | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 13ff6ef32fa..0afacd1fc21 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11278,9 +11278,9 @@ dependencies = [ [[package]] name = "parity-db" -version = "0.4.10" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78f19d20a0d2cc52327a88d131fa1c4ea81ea4a04714aedcfeca2dd410049cf8" +checksum = "59e9ab494af9e6e813c72170f0d3c1de1500990d62c97cc05cc7576f91aa402f" dependencies = [ "blake2 0.10.6", "crc32fast", diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index b48302edf52..448ab605aa9 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -87,7 +87,7 @@ serde_json = "1.0.108" thiserror = "1.0.48" kvdb = "0.13.0" kvdb-rocksdb = { version = "0.19.0", optional = true } -parity-db = { version = "0.4.8", optional = true } +parity-db = { version = "0.4.12", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1" } parking_lot = "0.12.1" diff --git a/polkadot/node/subsystem-util/Cargo.toml b/polkadot/node/subsystem-util/Cargo.toml index 94e1f5a3f12..9150fddc2bb 100644 --- a/polkadot/node/subsystem-util/Cargo.toml +++ b/polkadot/node/subsystem-util/Cargo.toml @@ -37,7 +37,7 @@ sp-keystore = { path = "../../../substrate/primitives/keystore" } sc-client-api = { path = "../../../substrate/client/api" } kvdb = "0.13.0" -parity-db = { version = "0.4.8" } +parity-db = { version = "0.4.12" } [dev-dependencies] assert_matches = "1.4.0" diff --git a/substrate/bin/node/bench/Cargo.toml b/substrate/bin/node/bench/Cargo.toml index 5ce91dc3c44..903eb4de7e6 100644 --- a/substrate/bin/node/bench/Cargo.toml +++ b/substrate/bin/node/bench/Cargo.toml @@ -38,7 +38,7 @@ tempfile = "3.1.0" fs_extra = "1" rand = { version = "0.8.5", features = ["small_rng"] } lazy_static = "1.4.0" -parity-db = "0.4.8" +parity-db = "0.4.12" sc-transaction-pool = { path = "../../../client/transaction-pool" } sc-transaction-pool-api = { path = "../../../client/transaction-pool/api" } futures = { version = "0.3.21", features = ["thread-pool"] } diff --git a/substrate/client/db/Cargo.toml b/substrate/client/db/Cargo.toml index 867e2908d6c..bb22ff4c6c1 100644 --- a/substrate/client/db/Cargo.toml +++ b/substrate/client/db/Cargo.toml @@ -22,7 +22,7 @@ kvdb-memorydb = "0.13.0" kvdb-rocksdb = { version = "0.19.0", optional = true } linked-hash-map = "0.5.4" log = "0.4.17" -parity-db = "0.4.8" +parity-db = "0.4.12" parking_lot = "0.12.1" sc-client-api = { path = "../api" } sc-state-db = { path = "../state-db" } diff --git a/substrate/client/statement-store/Cargo.toml b/substrate/client/statement-store/Cargo.toml index 371d6736916..e7bfd544afe 100644 --- a/substrate/client/statement-store/Cargo.toml +++ b/substrate/client/statement-store/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = "0.4.17" parking_lot = "0.12.1" -parity-db = "0.4.8" +parity-db = "0.4.12" tokio = { version = "1.22.0", features = ["time"] } sp-statement-store = { path = "../../primitives/statement-store" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } -- GitLab From 066bad6329cc327b0ff310309128832d411c4370 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Wed, 6 Dec 2023 10:36:49 +0100 Subject: [PATCH 07/59] [ci] Move rust-features.sh script to .gitlab folder (#2630) --- .gitlab/pipeline/check.yml | 6 +-- .gitlab/rust-features.sh | 87 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 5 deletions(-) create mode 100755 .gitlab/rust-features.sh diff --git a/.gitlab/pipeline/check.yml b/.gitlab/pipeline/check.yml index f95bd224fb4..7d98b9cc71c 100644 --- a/.gitlab/pipeline/check.yml +++ b/.gitlab/pipeline/check.yml @@ -65,11 +65,7 @@ test-rust-features: - .kubernetes-env - .test-refs-no-trigger-prs-only script: - - git clone - --depth=1 - --branch="master" - https://github.com/paritytech/pipeline-scripts - - bash ./pipeline-scripts/rust-features.sh . + - bash .gitlab/rust-features.sh . job-starter: stage: check diff --git a/.gitlab/rust-features.sh b/.gitlab/rust-features.sh new file mode 100755 index 00000000000..c0ac192a6ec --- /dev/null +++ b/.gitlab/rust-features.sh @@ -0,0 +1,87 @@ +#!/usr/bin/env bash + +############################################################################## +# +# This script checks that crates to not carelessly enable features that +# should stay disabled. It's important to check that since features +# are used to gate specific functionality which should only be enabled +# when the feature is explicitly enabled. +# +# Invocation scheme: +# ./rust-features.sh +# +# Example: +# ./rust-features.sh path/to/substrate +# +# The steps of this script: +# 1. Check that all required dependencies are installed. +# 2. Check that all rules are fullfilled for the whole workspace. If not: +# 4. Check all crates to find the offending ones. +# 5. Print all offending crates and exit with code 1. +# +############################################################################## + +set -eu + +# Check that cargo and grep are installed - otherwise abort. +command -v cargo >/dev/null 2>&1 || { echo >&2 "cargo is required but not installed. Aborting."; exit 1; } +command -v grep >/dev/null 2>&1 || { echo >&2 "grep is required but not installed. Aborting."; exit 1; } + +# Enter the workspace root folder. +cd "$1" +echo "Workspace root is $PWD" + +function main() { + feature_does_not_imply 'default' 'runtime-benchmarks' + feature_does_not_imply 'std' 'runtime-benchmarks' + feature_does_not_imply 'default' 'try-runtime' + feature_does_not_imply 'std' 'try-runtime' +} + +# Accepts two feature names as arguments. +# Checks that the first feature does not imply the second one. +function feature_does_not_imply() { + ENABLED=$1 + STAYS_DISABLED=$2 + echo "📏 Checking that $ENABLED does not imply $STAYS_DISABLED ..." + + # Check if the forbidden feature is enabled anywhere in the workspace. + # But only check "normal" dependencies, so no "dev" or "build" dependencies. + if cargo tree --no-default-features --locked --workspace -e features,normal --features "$ENABLED" | grep -qF "feature \"$STAYS_DISABLED\""; then + echo "❌ $ENABLED implies $STAYS_DISABLED in the workspace" + else + echo "✅ $ENABLED does not imply $STAYS_DISABLED in the workspace" + return + fi + + # Find all Cargo.toml files but exclude the root one since we already know that it is broken. + CARGOS=`find . -name Cargo.toml -not -path ./Cargo.toml` + NUM_CRATES=`echo "$CARGOS" | wc -l` + FAILED=0 + PASSED=0 + echo "🔍 Checking all $NUM_CRATES crates - this takes some time." + + for CARGO in $CARGOS; do + OUTPUT=$(cargo tree --no-default-features --locked --offline -e features,normal --features $ENABLED --manifest-path $CARGO 2>&1 || true) + + if echo "$OUTPUT" | grep -qF "not supported for packages in this workspace"; then + # This case just means that the pallet does not support the + # requested feature which is fine. + PASSED=$((PASSED+1)) + elif echo "$OUTPUT" | grep -qF "feature \"$STAYS_DISABLED\""; then + echo "❌ Violation in $CARGO by dependency:" + # Best effort hint for which dependency needs to be fixed. + echo "$OUTPUT" | grep -wF "feature \"$STAYS_DISABLED\"" | head -n 1 + FAILED=$((FAILED+1)) + else + PASSED=$((PASSED+1)) + fi + done + + echo "Checked $NUM_CRATES crates in total of which $FAILED failed and $PASSED passed." + echo "Exiting with code 1" + exit 1 +} + +main "$@" + -- GitLab From e7651cf41b2d775dedcc897e17ead16e200a4fff Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Wed, 6 Dec 2023 13:18:12 +0200 Subject: [PATCH 08/59] pallet-xcm: add new flexible `transfer_assets()` call/extrinsic (#2388) # Motivation (+testing) ### Enable easy `ForeignAssets` transfers using `pallet-xcm` We had just previously added capabilities to teleport fees during reserve-based transfers, but what about reserve-transferring fees when needing to teleport some non-fee asset? This PR aligns everything under either explicit reserve-transfer, explicit teleport, or this new flexible `transfer_assets()` which can mix and match as needed with fewer artificial constraints imposed to the user. This will enable, for example, a (non-system) parachain to teleport their `ForeignAssets` assets to AssetHub while using DOT to pay fees. (the assets are teleported - as foreign assets should from their owner chain - while DOT used for fees can only be reserve-based transferred between said parachain and AssetHub). Added `xcm-emulator` tests for this scenario ^. # Description Reverts `(limited_)reserve_transfer_assets` to only allow reserve-based transfers for all `assets` including fees. Similarly `(limited_)teleport_assets` only allows teleports for all `assets` including fees. For complex combinations of asset transfers where assets and fees may have different reserves or different reserve/teleport trust configurations, users can use the newly added `transfer_assets()` extrinsic which is more flexible in allowing more complex scenarios. `assets` (excluding `fees`) must have same reserve location or otherwise be teleportable to `dest`. No limitations imposed on `fees`. - for local reserve: transfer assets to sovereign account of destination chain and forward a notification XCM to `dest` to mint and deposit reserve-based assets to `beneficiary`. - for destination reserve: burn local assets and forward a notification to `dest` chain to withdraw the reserve assets from this chain's sovereign account and deposit them to `beneficiary`. - for remote reserve: burn local assets, forward XCM to reserve chain to move reserves from this chain's SA to `dest` chain's SA, and forward another XCM to `dest` to mint and deposit reserve-based assets to `beneficiary`. - for teleports: burn local assets and forward XCM to `dest` chain to mint/teleport assets and deposit them to `beneficiary`. ## Review notes Only around 500 lines are prod code (see `pallet_xcm/src/lib.rs`), the rest of the PR is new tests and improving existing tests. --------- Co-authored-by: command-bot <> --- Cargo.lock | 2 - .../parachains/testing/penpal/src/lib.rs | 2 + .../emulated/common/src/macros.rs | 99 ++ .../emulated/common/src/xcm_helpers.rs | 14 + .../tests/assets/asset-hub-rococo/Cargo.toml | 1 - .../assets/asset-hub-rococo/src/tests/mod.rs | 8 + .../src/tests/reserve_transfer.rs | 28 +- .../assets/asset-hub-rococo/src/tests/swap.rs | 157 +- .../asset-hub-rococo/src/tests/teleport.rs | 337 +++++ .../tests/assets/asset-hub-westend/Cargo.toml | 1 - .../assets/asset-hub-westend/src/tests/mod.rs | 8 + .../src/tests/reserve_transfer.rs | 16 +- .../asset-hub-westend/src/tests/swap.rs | 156 +- .../asset-hub-westend/src/tests/teleport.rs | 337 +++++ .../assets/asset-hub-rococo/src/lib.rs | 49 + .../src/weights/pallet_xcm.rs | 154 +- .../assets/asset-hub-westend/src/lib.rs | 49 + .../src/weights/pallet_xcm.rs | 154 +- .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 12 + .../src/weights/pallet_xcm.rs | 191 ++- .../bridge-hubs/bridge-hub-westend/src/lib.rs | 12 + .../src/weights/pallet_xcm.rs | 220 +-- .../collectives-westend/src/lib.rs | 12 + .../src/weights/pallet_xcm.rs | 117 +- .../contracts/contracts-rococo/src/lib.rs | 12 + .../runtimes/testing/penpal/src/xcm_config.rs | 47 +- polkadot/runtime/rococo/src/lib.rs | 14 + .../runtime/rococo/src/weights/pallet_xcm.rs | 4 + polkadot/runtime/westend/src/lib.rs | 15 + .../runtime/westend/src/weights/pallet_xcm.rs | 4 + polkadot/xcm/pallet-xcm/src/benchmarking.rs | 71 +- polkadot/xcm/pallet-xcm/src/lib.rs | 568 +++++-- polkadot/xcm/pallet-xcm/src/mock.rs | 45 + .../pallet-xcm/src/tests/assets_transfer.rs | 1331 ++++++++++++++--- polkadot/xcm/pallet-xcm/src/tests/mod.rs | 2 +- prdoc/pr_2388.prdoc | 26 + substrate/frame/assets/src/benchmarking.rs | 2 +- substrate/frame/assets/src/lib.rs | 2 +- 38 files changed, 3322 insertions(+), 957 deletions(-) create mode 100644 prdoc/pr_2388.prdoc diff --git a/Cargo.lock b/Cargo.lock index 0afacd1fc21..f2693730b91 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -761,7 +761,6 @@ dependencies = [ "pallet-xcm", "parachains-common", "parity-scale-codec", - "penpal-runtime", "rococo-runtime", "rococo-system-emulated-network", "sp-runtime", @@ -884,7 +883,6 @@ dependencies = [ "pallet-xcm", "parachains-common", "parity-scale-codec", - "penpal-runtime", "polkadot-runtime-common", "sp-runtime", "staging-xcm", diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs index c76120adb79..62bafb5cb30 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs @@ -15,6 +15,7 @@ mod genesis; pub use genesis::{genesis, ED, PARA_ID_A, PARA_ID_B}; +pub use penpal_runtime::xcm_config::{LocalTeleportableToAssetHub, XcmConfig}; // Substrate use frame_support::traits::OnInitialize; @@ -67,6 +68,7 @@ decl_test_parachains! { // Penpal implementation impl_accounts_helpers_for_parachain!(PenpalA); +impl_accounts_helpers_for_parachain!(PenpalB); impl_assets_helpers_for_parachain!(PenpalA, Rococo); impl_assets_helpers_for_parachain!(PenpalB, Westend); impl_assert_events_helpers_for_parachain!(PenpalA); diff --git a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs index 6ea3524ed4a..8718f1e83a0 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs @@ -120,3 +120,102 @@ macro_rules! test_parachain_is_trusted_teleporter { } }; } + +#[macro_export] +macro_rules! include_penpal_create_foreign_asset_on_asset_hub { + ( $penpal:ident, $asset_hub:ident, $relay_ed:expr, $weight_to_fee:expr) => { + $crate::impls::paste::paste! { + pub fn penpal_create_foreign_asset_on_asset_hub( + asset_id_on_penpal: u32, + foreign_asset_at_asset_hub: MultiLocation, + ah_as_seen_by_penpal: MultiLocation, + is_sufficient: bool, + asset_owner: AccountId, + prefund_amount: u128, + ) { + use frame_support::weights::WeightToFee; + let ah_check_account = $asset_hub::execute_with(|| { + <$asset_hub as [<$asset_hub Pallet>]>::PolkadotXcm::check_account() + }); + let penpal_check_account = + $penpal::execute_with(|| <$penpal as [<$penpal Pallet>]>::PolkadotXcm::check_account()); + let penpal_as_seen_by_ah = $asset_hub::sibling_location_of($penpal::para_id()); + + // prefund SA of Penpal on AssetHub with enough native tokens to pay for creating + // new foreign asset, also prefund CheckingAccount with ED, because teleported asset + // itself might not be sufficient and CheckingAccount cannot be created otherwise + let sov_penpal_on_ah = $asset_hub::sovereign_account_id_of(penpal_as_seen_by_ah); + $asset_hub::fund_accounts(vec![ + (sov_penpal_on_ah.clone().into(), $relay_ed * 100_000_000_000), + (ah_check_account.clone().into(), $relay_ed * 1000), + ]); + + // prefund SA of AssetHub on Penpal with native asset + let sov_ah_on_penpal = $penpal::sovereign_account_id_of(ah_as_seen_by_penpal); + $penpal::fund_accounts(vec![ + (sov_ah_on_penpal.into(), $relay_ed * 1_000_000_000), + (penpal_check_account.clone().into(), $relay_ed * 1000), + ]); + + // Force create asset on $penpal and prefund [<$penpal Sender>] + $penpal::force_create_and_mint_asset( + asset_id_on_penpal, + ASSET_MIN_BALANCE, + is_sufficient, + asset_owner, + None, + prefund_amount, + ); + + let require_weight_at_most = Weight::from_parts(1_100_000_000_000, 30_000); + // `OriginKind::Xcm` required by ForeignCreators pallet-assets origin filter + let origin_kind = OriginKind::Xcm; + let call_create_foreign_assets = + <$asset_hub as Chain>::RuntimeCall::ForeignAssets(pallet_assets::Call::< + <$asset_hub as Chain>::Runtime, + pallet_assets::Instance2, + >::create { + id: foreign_asset_at_asset_hub, + min_balance: ASSET_MIN_BALANCE, + admin: sov_penpal_on_ah.into(), + }) + .encode(); + let buy_execution_fee_amount = $weight_to_fee::weight_to_fee( + &Weight::from_parts(10_100_000_000_000, 300_000), + ); + let buy_execution_fee = MultiAsset { + id: Concrete(MultiLocation { parents: 1, interior: Here }), + fun: Fungible(buy_execution_fee_amount), + }; + let xcm = VersionedXcm::from(Xcm(vec![ + WithdrawAsset { 0: vec![buy_execution_fee.clone()].into() }, + BuyExecution { fees: buy_execution_fee.clone(), weight_limit: Unlimited }, + Transact { require_weight_at_most, origin_kind, call: call_create_foreign_assets.into() }, + ExpectTransactStatus(MaybeErrorCode::Success), + RefundSurplus, + DepositAsset { assets: All.into(), beneficiary: penpal_as_seen_by_ah }, + ])); + // Send XCM message from penpal => asset_hub + let sudo_penpal_origin = <$penpal as Chain>::RuntimeOrigin::root(); + $penpal::execute_with(|| { + assert_ok!(<$penpal as [<$penpal Pallet>]>::PolkadotXcm::send( + sudo_penpal_origin.clone(), + bx!(ah_as_seen_by_penpal.into()), + bx!(xcm), + )); + type RuntimeEvent = <$penpal as Chain>::RuntimeEvent; + assert_expected_events!( + $penpal, + vec![ + RuntimeEvent::PolkadotXcm(pallet_xcm::Event::Sent { .. }) => {}, + ] + ); + }); + $asset_hub::execute_with(|| { + type ForeignAssets = <$asset_hub as [<$asset_hub Pallet>]>::ForeignAssets; + assert!(ForeignAssets::asset_exists(foreign_asset_at_asset_hub)); + }); + } + } + }; +} diff --git a/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs b/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs index 47e92ed075f..70a9408c309 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/xcm_helpers.rs @@ -59,3 +59,17 @@ pub fn xcm_transact_unpaid_execution( Transact { require_weight_at_most, origin_kind, call }, ])) } + +/// Helper method to get the non-fee asset used in multiple assets transfer +pub fn non_fee_asset(assets: &MultiAssets, fee_idx: usize) -> Option<(MultiLocation, u128)> { + let asset = assets.inner().into_iter().enumerate().find(|a| a.0 != fee_idx)?.1.clone(); + let asset_id = match asset.id { + Concrete(id) => id, + _ => return None, + }; + let asset_amount = match asset.fun { + Fungible(amount) => amount, + _ => return None, + }; + Some((asset_id, asset_amount)) +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml index 16e2f736bdf..bc4e7cfe376 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml @@ -30,5 +30,4 @@ asset-test-utils = { path = "../../../../../runtimes/assets/test-utils" } parachains-common = { path = "../../../../../../parachains/common" } asset-hub-rococo-runtime = { path = "../../../../../runtimes/assets/asset-hub-rococo" } emulated-integration-tests-common = { path = "../../../common", default-features = false } -penpal-runtime = { path = "../../../../../runtimes/testing/penpal" } rococo-system-emulated-network = { path = "../../../networks/rococo-system" } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/mod.rs index b3841af0e6c..c9270934ddf 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/mod.rs @@ -18,3 +18,11 @@ mod send; mod set_xcm_versions; mod swap; mod teleport; + +use crate::*; +emulated_integration_tests_common::include_penpal_create_foreign_asset_on_asset_hub!( + PenpalA, + AssetHubRococo, + ROCOCO_ED, + parachains_common::rococo::fee::WeightToFee +); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs index 18483762ae1..e6142e29b7c 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/reserve_transfer.rs @@ -15,14 +15,12 @@ use crate::*; use asset_hub_rococo_runtime::xcm_config::XcmConfig as AssetHubRococoXcmConfig; -use penpal_runtime::xcm_config::XcmConfig as PenpalRococoXcmConfig; use rococo_runtime::xcm_config::XcmConfig as RococoXcmConfig; +use rococo_system_emulated_network::penpal_emulated_chain::XcmConfig as PenpalRococoXcmConfig; fn relay_to_para_sender_assertions(t: RelayToParaTest) { type RuntimeEvent = ::RuntimeEvent; - Rococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(864_610_000, 8_799))); - assert_expected_events!( Rococo, vec![ @@ -42,12 +40,10 @@ fn relay_to_para_sender_assertions(t: RelayToParaTest) { fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; - AssetHubRococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( 864_610_000, 8_799, ))); - assert_expected_events!( AssetHubRococo, vec![ @@ -80,9 +76,7 @@ fn para_receiver_assertions(_: Test) { fn para_to_system_para_sender_assertions(t: ParaToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; - PenpalA::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts(864_610_000, 8_799))); - assert_expected_events!( PenpalA, vec![ @@ -99,15 +93,13 @@ fn para_to_system_para_sender_assertions(t: ParaToSystemParaTest) { fn para_to_system_para_receiver_assertions(t: ParaToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; - let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of( AssetHubRococo::sibling_location_of(PenpalA::para_id()), ); - assert_expected_events!( AssetHubRococo, vec![ - // Amount to reserve transfer is transferred to Parachain's Sovereign account + // Amount to reserve transfer is withdrawn from Parachain's Sovereign account RuntimeEvent::Balances( pallet_balances::Event::Withdraw { who, amount } ) => { @@ -124,12 +116,10 @@ fn para_to_system_para_receiver_assertions(t: ParaToSystemParaTest) { fn system_para_to_para_assets_sender_assertions(t: SystemParaToParaTest) { type RuntimeEvent = ::RuntimeEvent; - AssetHubRococo::assert_xcm_pallet_attempted_complete(Some(Weight::from_parts( 864_610_000, 8799, ))); - assert_expected_events!( AssetHubRococo, vec![ @@ -162,7 +152,7 @@ fn system_para_to_para_assets_receiver_assertions(_: Test) { ); } -fn relay_to_para_limited_reserve_transfer_assets(t: RelayToParaTest) -> DispatchResult { +fn relay_to_para_reserve_transfer_assets(t: RelayToParaTest) -> DispatchResult { ::XcmPallet::limited_reserve_transfer_assets( t.signed_origin, bx!(t.args.dest.into()), @@ -173,7 +163,7 @@ fn relay_to_para_limited_reserve_transfer_assets(t: RelayToParaTest) -> Dispatch ) } -fn system_para_to_para_limited_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { +fn system_para_to_para_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { ::PolkadotXcm::limited_reserve_transfer_assets( t.signed_origin, bx!(t.args.dest.into()), @@ -184,7 +174,7 @@ fn system_para_to_para_limited_reserve_transfer_assets(t: SystemParaToParaTest) ) } -fn para_to_system_para_limited_reserve_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult { +fn para_to_system_para_reserve_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult { ::PolkadotXcm::limited_reserve_transfer_assets( t.signed_origin, bx!(t.args.dest.into()), @@ -285,7 +275,7 @@ fn reserve_transfer_native_asset_from_relay_to_para() { test.set_assertion::(relay_to_para_sender_assertions); test.set_assertion::(para_receiver_assertions); - test.set_dispatchable::(relay_to_para_limited_reserve_transfer_assets); + test.set_dispatchable::(relay_to_para_reserve_transfer_assets); test.assert(); let delivery_fees = Rococo::execute_with(|| { @@ -329,7 +319,7 @@ fn reserve_transfer_native_asset_from_system_para_to_para() { test.set_assertion::(system_para_to_para_sender_assertions); test.set_assertion::(para_receiver_assertions); - test.set_dispatchable::(system_para_to_para_limited_reserve_transfer_assets); + test.set_dispatchable::(system_para_to_para_reserve_transfer_assets); test.assert(); let sender_balance_after = test.sender.balance; @@ -379,7 +369,7 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { test.set_assertion::(para_to_system_para_sender_assertions); test.set_assertion::(para_to_system_para_receiver_assertions); - test.set_dispatchable::(para_to_system_para_limited_reserve_transfer_assets); + test.set_dispatchable::(para_to_system_para_reserve_transfer_assets); test.assert(); let sender_balance_after = test.sender.balance; @@ -474,7 +464,7 @@ fn reserve_transfer_assets_from_system_para_to_para() { test.set_assertion::(system_para_to_para_assets_sender_assertions); test.set_assertion::(system_para_to_para_assets_receiver_assertions); - test.set_dispatchable::(system_para_to_para_limited_reserve_transfer_assets); + test.set_dispatchable::(system_para_to_para_reserve_transfer_assets); test.assert(); let sender_balance_after = test.sender.balance; diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs index 9e691bf02f1..35a660ed3c4 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/swap.rs @@ -14,9 +14,10 @@ // limitations under the License. use crate::*; -use frame_support::{instances::Instance2, BoundedVec}; +use frame_support::BoundedVec; use parachains_common::rococo::currency::EXISTENTIAL_DEPOSIT; -use sp_runtime::{DispatchError, ModuleError}; +use rococo_system_emulated_network::penpal_emulated_chain::LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub; +use sp_runtime::ModuleError; #[test] fn swap_locally_on_chain_using_local_assets() { @@ -112,114 +113,37 @@ fn swap_locally_on_chain_using_local_assets() { #[test] fn swap_locally_on_chain_using_foreign_assets() { - use frame_support::weights::WeightToFee; - let asset_native = Box::new(asset_hub_rococo_runtime::xcm_config::TokenLocation::get()); + let ah_as_seen_by_penpal = PenpalA::sibling_location_of(AssetHubRococo::para_id()); + let asset_location_on_penpal = PenpalLocalTeleportableToAssetHub::get(); + let asset_id_on_penpal = match asset_location_on_penpal.last() { + Some(GeneralIndex(id)) => *id as u32, + _ => unreachable!(), + }; + let asset_owner_on_penpal = PenpalASender::get(); + let foreign_asset_at_asset_hub_rococo = + MultiLocation { parents: 1, interior: X1(Parachain(PenpalA::para_id().into())) } + .appended_with(asset_location_on_penpal) + .unwrap(); + + // 1. Create asset on penpal and, 2. Create foreign asset on asset_hub_rococo + super::penpal_create_foreign_asset_on_asset_hub( + asset_id_on_penpal, + foreign_asset_at_asset_hub_rococo, + ah_as_seen_by_penpal, + true, + asset_owner_on_penpal, + ASSET_MIN_BALANCE * 1_000_000, + ); - let foreign_asset1_at_asset_hub_rococo = Box::new(MultiLocation { - parents: 1, - interior: X3( - Parachain(PenpalA::para_id().into()), - PalletInstance(ASSETS_PALLET_ID), - GeneralIndex(ASSET_ID.into()), - ), - }); - - let assets_para_destination: VersionedMultiLocation = - MultiLocation { parents: 1, interior: X1(Parachain(AssetHubRococo::para_id().into())) } - .into(); - - let penpal_location = - MultiLocation { parents: 1, interior: X1(Parachain(PenpalA::para_id().into())) }; - - // 1. Create asset on penpal: - PenpalA::execute_with(|| { - assert_ok!(::Assets::create( - ::RuntimeOrigin::signed(PenpalASender::get()), - ASSET_ID.into(), - PenpalASender::get().into(), - 1000, - )); - - assert!(::Assets::asset_exists(ASSET_ID)); - }); - - // 2. Create foreign asset on asset_hub_rococo: - - let require_weight_at_most = Weight::from_parts(1_100_000_000_000, 30_000); - let origin_kind = OriginKind::Xcm; - let sov_penpal_on_asset_hub_rococo = AssetHubRococo::sovereign_account_id_of(penpal_location); - + let penpal_as_seen_by_ah = AssetHubRococo::sibling_location_of(PenpalA::para_id()); + let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of(penpal_as_seen_by_ah); AssetHubRococo::fund_accounts(vec![ (AssetHubRococoSender::get().into(), 5_000_000 * ROCOCO_ED), /* An account to swap dot * for something else. */ - (sov_penpal_on_asset_hub_rococo.clone().into(), 1000_000_000_000_000_000 * ROCOCO_ED), ]); - let sov_penpal_on_asset_hub_rococo_as_location: MultiLocation = MultiLocation { - parents: 0, - interior: X1(AccountId32Junction { - network: None, - id: sov_penpal_on_asset_hub_rococo.clone().into(), - }), - }; - - let call_foreign_assets_create = - ::RuntimeCall::ForeignAssets(pallet_assets::Call::< - ::Runtime, - Instance2, - >::create { - id: *foreign_asset1_at_asset_hub_rococo, - min_balance: 1000, - admin: sov_penpal_on_asset_hub_rococo.clone().into(), - }) - .encode() - .into(); - - let buy_execution_fee_amount = parachains_common::rococo::fee::WeightToFee::weight_to_fee( - &Weight::from_parts(10_100_000_000_000, 300_000), - ); - let buy_execution_fee = MultiAsset { - id: Concrete(MultiLocation { parents: 1, interior: Here }), - fun: Fungible(buy_execution_fee_amount), - }; - - let xcm = VersionedXcm::from(Xcm(vec![ - WithdrawAsset { 0: vec![buy_execution_fee.clone()].into() }, - BuyExecution { fees: buy_execution_fee.clone(), weight_limit: Unlimited }, - Transact { require_weight_at_most, origin_kind, call: call_foreign_assets_create }, - RefundSurplus, - DepositAsset { - assets: All.into(), - beneficiary: sov_penpal_on_asset_hub_rococo_as_location, - }, - ])); - - // Send XCM message from penpal => asset_hub_rococo - let sudo_penpal_origin = ::RuntimeOrigin::root(); - PenpalA::execute_with(|| { - assert_ok!(::PolkadotXcm::send( - sudo_penpal_origin.clone(), - bx!(assets_para_destination.clone()), - bx!(xcm), - )); - - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - PenpalA, - vec![ - RuntimeEvent::PolkadotXcm(pallet_xcm::Event::Sent { .. }) => {}, - ] - ); - }); - - // Receive XCM message in Assets Parachain AssetHubRococo::execute_with(|| { - assert!(::ForeignAssets::asset_exists( - *foreign_asset1_at_asset_hub_rococo - )); - // 3: Mint foreign asset on asset_hub_rococo: // // (While it might be nice to use batch, @@ -228,11 +152,9 @@ fn swap_locally_on_chain_using_foreign_assets() { type RuntimeEvent = ::RuntimeEvent; // 3. Mint foreign asset (in reality this should be a teleport or some such) assert_ok!(::ForeignAssets::mint( - ::RuntimeOrigin::signed( - sov_penpal_on_asset_hub_rococo.clone().into() - ), - *foreign_asset1_at_asset_hub_rococo, - sov_penpal_on_asset_hub_rococo.clone().into(), + ::RuntimeOrigin::signed(sov_penpal_on_ahr.clone().into()), + foreign_asset_at_asset_hub_rococo, + sov_penpal_on_ahr.clone().into(), 3_000_000_000_000, )); @@ -243,11 +165,12 @@ fn swap_locally_on_chain_using_foreign_assets() { ] ); + let foreign_asset_at_asset_hub_rococo = Box::new(foreign_asset_at_asset_hub_rococo); // 4. Create pool: assert_ok!(::AssetConversion::create_pool( ::RuntimeOrigin::signed(AssetHubRococoSender::get()), asset_native.clone(), - foreign_asset1_at_asset_hub_rococo.clone(), + foreign_asset_at_asset_hub_rococo.clone(), )); assert_expected_events!( @@ -259,16 +182,14 @@ fn swap_locally_on_chain_using_foreign_assets() { // 5. Add liquidity: assert_ok!(::AssetConversion::add_liquidity( - ::RuntimeOrigin::signed( - sov_penpal_on_asset_hub_rococo.clone() - ), + ::RuntimeOrigin::signed(sov_penpal_on_ahr.clone()), asset_native.clone(), - foreign_asset1_at_asset_hub_rococo.clone(), + foreign_asset_at_asset_hub_rococo.clone(), 1_000_000_000_000, 2_000_000_000_000, 0, 0, - sov_penpal_on_asset_hub_rococo.clone().into() + sov_penpal_on_ahr.clone().into() )); assert_expected_events!( @@ -283,7 +204,7 @@ fn swap_locally_on_chain_using_foreign_assets() { // 6. Swap! let path = BoundedVec::<_, _>::truncate_from(vec![ asset_native.clone(), - foreign_asset1_at_asset_hub_rococo.clone(), + foreign_asset_at_asset_hub_rococo.clone(), ]); assert_ok!( @@ -309,15 +230,13 @@ fn swap_locally_on_chain_using_foreign_assets() { // 7. Remove liquidity assert_ok!(::AssetConversion::remove_liquidity( - ::RuntimeOrigin::signed( - sov_penpal_on_asset_hub_rococo.clone() - ), + ::RuntimeOrigin::signed(sov_penpal_on_ahr.clone()), asset_native, - foreign_asset1_at_asset_hub_rococo, + foreign_asset_at_asset_hub_rococo, 1414213562273 - 2_000_000_000, // all but the 2 EDs can't be retrieved. 0, 0, - sov_penpal_on_asset_hub_rococo.clone().into(), + sov_penpal_on_ahr.clone().into(), )); }); } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs index f8017f7a1c5..e64c02f5258 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs @@ -15,7 +15,9 @@ use crate::*; use asset_hub_rococo_runtime::xcm_config::XcmConfig as AssetHubRococoXcmConfig; +use emulated_integration_tests_common::xcm_helpers::non_fee_asset; use rococo_runtime::xcm_config::XcmConfig as RococoXcmConfig; +use rococo_system_emulated_network::penpal_emulated_chain::LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub; fn relay_origin_assertions(t: RelayToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; @@ -110,6 +112,123 @@ fn para_dest_assertions(t: RelayToSystemParaTest) { ); } +fn penpal_to_ah_foreign_assets_sender_assertions(t: ParaToSystemParaTest) { + type RuntimeEvent = ::RuntimeEvent; + PenpalA::assert_xcm_pallet_attempted_complete(None); + let expected_asset_id = t.args.asset_id.unwrap(); + let (_, expected_asset_amount) = + non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap(); + assert_expected_events!( + PenpalA, + vec![ + RuntimeEvent::Balances( + pallet_balances::Event::Withdraw { who, amount } + ) => { + who: *who == t.sender.account_id, + amount: *amount == t.args.amount, + }, + RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { + asset_id: *asset_id == expected_asset_id, + owner: *owner == t.sender.account_id, + balance: *balance == expected_asset_amount, + }, + ] + ); +} + +fn penpal_to_ah_foreign_assets_receiver_assertions(t: ParaToSystemParaTest) { + type RuntimeEvent = ::RuntimeEvent; + let sov_penpal_on_ahr = AssetHubRococo::sovereign_account_id_of( + AssetHubRococo::sibling_location_of(PenpalA::para_id()), + ); + let (expected_foreign_asset_id, expected_foreign_asset_amount) = + non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap(); + assert_expected_events!( + AssetHubRococo, + vec![ + // native asset reserve transfer for paying fees, withdrawn from Penpal's sov account + RuntimeEvent::Balances( + pallet_balances::Event::Withdraw { who, amount } + ) => { + who: *who == sov_penpal_on_ahr.clone().into(), + amount: *amount == t.args.amount, + }, + RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { + who: *who == t.receiver.account_id, + }, + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, amount }) => { + asset_id: *asset_id == expected_foreign_asset_id, + owner: *owner == t.receiver.account_id, + amount: *amount == expected_foreign_asset_amount, + }, + RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); +} + +fn ah_to_penpal_foreign_assets_sender_assertions(t: SystemParaToParaTest) { + type RuntimeEvent = ::RuntimeEvent; + AssetHubRococo::assert_xcm_pallet_attempted_complete(None); + let (expected_foreign_asset_id, expected_foreign_asset_amount) = + non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap(); + assert_expected_events!( + AssetHubRococo, + vec![ + // native asset used for fees is transferred to Parachain's Sovereign account as reserve + RuntimeEvent::Balances( + pallet_balances::Event::Transfer { from, to, amount } + ) => { + from: *from == t.sender.account_id, + to: *to == AssetHubRococo::sovereign_account_id_of( + t.args.dest + ), + amount: *amount == t.args.amount, + }, + // foreign asset is burned locally as part of teleportation + RuntimeEvent::ForeignAssets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { + asset_id: *asset_id == expected_foreign_asset_id, + owner: *owner == t.sender.account_id, + balance: *balance == expected_foreign_asset_amount, + }, + ] + ); +} + +fn ah_to_penpal_foreign_assets_receiver_assertions(t: SystemParaToParaTest) { + type RuntimeEvent = ::RuntimeEvent; + let expected_asset_id = t.args.asset_id.unwrap(); + let (_, expected_asset_amount) = + non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap(); + let checking_account = ::PolkadotXcm::check_account(); + assert_expected_events!( + PenpalA, + vec![ + // checking account burns local asset as part of incoming teleport + RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { + asset_id: *asset_id == expected_asset_id, + owner: *owner == checking_account, + balance: *balance == expected_asset_amount, + }, + // local asset is teleported into account of receiver + RuntimeEvent::Assets(pallet_assets::Event::Issued { asset_id, owner, amount }) => { + asset_id: *asset_id == expected_asset_id, + owner: *owner == t.receiver.account_id, + amount: *amount == expected_asset_amount, + }, + // native asset for fee is deposited to receiver + RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { + who: *who == t.receiver.account_id, + }, + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); +} + fn relay_limited_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult { ::XcmPallet::limited_teleport_assets( t.signed_origin, @@ -152,6 +271,28 @@ fn system_para_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { ) } +fn para_to_system_para_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult { + ::PolkadotXcm::transfer_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + t.args.weight_limit, + ) +} + +fn system_para_to_para_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { + ::PolkadotXcm::transfer_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + t.args.weight_limit, + ) +} + /// Limited Teleport of native asset from Relay Chain to the System Parachain should work #[test] fn limited_teleport_native_assets_from_relay_to_system_para_works() { @@ -410,3 +551,199 @@ fn teleport_to_other_system_parachains_works() { (native_asset, amount) ); } + +/// Bidirectional teleports of local Penpal assets to Asset Hub as foreign assets should work +/// (using native reserve-based transfer for fees) +#[test] +fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { + let ah_as_seen_by_penpal = PenpalA::sibling_location_of(AssetHubRococo::para_id()); + let asset_location_on_penpal = PenpalLocalTeleportableToAssetHub::get(); + let asset_id_on_penpal = match asset_location_on_penpal.last() { + Some(GeneralIndex(id)) => *id as u32, + _ => unreachable!(), + }; + let asset_owner_on_penpal = PenpalASender::get(); + let foreign_asset_at_asset_hub_rococo = + MultiLocation { parents: 1, interior: X1(Parachain(PenpalA::para_id().into())) } + .appended_with(asset_location_on_penpal) + .unwrap(); + super::penpal_create_foreign_asset_on_asset_hub( + asset_id_on_penpal, + foreign_asset_at_asset_hub_rococo, + ah_as_seen_by_penpal, + false, + asset_owner_on_penpal, + ASSET_MIN_BALANCE * 1_000_000, + ); + let penpal_to_ah_beneficiary_id = AssetHubRococoReceiver::get(); + + let fee_amount_to_send = ASSET_HUB_ROCOCO_ED * 10_000; + let asset_amount_to_send = ASSET_MIN_BALANCE * 1000; + + let penpal_assets: MultiAssets = vec![ + (Parent, fee_amount_to_send).into(), + (asset_location_on_penpal, asset_amount_to_send).into(), + ] + .into(); + let fee_asset_index = penpal_assets + .inner() + .iter() + .position(|r| r == &(Parent, fee_amount_to_send).into()) + .unwrap() as u32; + + // Penpal to AH test args + let penpal_to_ah_test_args = TestContext { + sender: PenpalASender::get(), + receiver: AssetHubRococoReceiver::get(), + args: para_test_args( + ah_as_seen_by_penpal, + penpal_to_ah_beneficiary_id, + asset_amount_to_send, + penpal_assets, + Some(asset_id_on_penpal), + fee_asset_index, + ), + }; + let mut penpal_to_ah = ParaToSystemParaTest::new(penpal_to_ah_test_args); + + let penpal_sender_balance_before = penpal_to_ah.sender.balance; + let ah_receiver_balance_before = penpal_to_ah.receiver.balance; + + let penpal_sender_assets_before = PenpalA::execute_with(|| { + type Assets = ::Assets; + >::balance(asset_id_on_penpal, &PenpalASender::get()) + }); + let ah_receiver_assets_before = AssetHubRococo::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance( + foreign_asset_at_asset_hub_rococo, + &AssetHubRococoReceiver::get(), + ) + }); + + penpal_to_ah.set_assertion::(penpal_to_ah_foreign_assets_sender_assertions); + penpal_to_ah.set_assertion::(penpal_to_ah_foreign_assets_receiver_assertions); + penpal_to_ah.set_dispatchable::(para_to_system_para_transfer_assets); + penpal_to_ah.assert(); + + let penpal_sender_balance_after = penpal_to_ah.sender.balance; + let ah_receiver_balance_after = penpal_to_ah.receiver.balance; + + let penpal_sender_assets_after = PenpalA::execute_with(|| { + type Assets = ::Assets; + >::balance(asset_id_on_penpal, &PenpalASender::get()) + }); + let ah_receiver_assets_after = AssetHubRococo::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance( + foreign_asset_at_asset_hub_rococo, + &AssetHubRococoReceiver::get(), + ) + }); + + // Sender's balance is reduced + assert!(penpal_sender_balance_after < penpal_sender_balance_before); + // Receiver's balance is increased + assert!(ah_receiver_balance_after > ah_receiver_balance_before); + // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; + // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but + // should be non-zero + assert!(ah_receiver_balance_after < ah_receiver_balance_before + fee_amount_to_send); + + // Sender's balance is reduced by exact amount + assert_eq!(penpal_sender_assets_before - asset_amount_to_send, penpal_sender_assets_after); + // Receiver's balance is increased by exact amount + assert_eq!(ah_receiver_assets_after, ah_receiver_assets_before + asset_amount_to_send); + + /////////////////////////////////////////////////////////////////////// + // Now test transferring foreign assets back from AssetHub to Penpal // + /////////////////////////////////////////////////////////////////////// + + // Move funds on AH from AHReceiver to AHSender + AssetHubRococo::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + assert_ok!(ForeignAssets::transfer( + ::RuntimeOrigin::signed(AssetHubRococoReceiver::get()), + foreign_asset_at_asset_hub_rococo, + AssetHubRococoSender::get().into(), + asset_amount_to_send, + )); + }); + + let ah_to_penpal_beneficiary_id = PenpalAReceiver::get(); + let penpal_as_seen_by_ah = AssetHubRococo::sibling_location_of(PenpalA::para_id()); + let ah_assets: MultiAssets = vec![ + (Parent, fee_amount_to_send).into(), + (foreign_asset_at_asset_hub_rococo, asset_amount_to_send).into(), + ] + .into(); + let fee_asset_index = ah_assets + .inner() + .iter() + .position(|r| r == &(Parent, fee_amount_to_send).into()) + .unwrap() as u32; + + // AH to Penpal test args + let ah_to_penpal_test_args = TestContext { + sender: AssetHubRococoSender::get(), + receiver: PenpalAReceiver::get(), + args: para_test_args( + penpal_as_seen_by_ah, + ah_to_penpal_beneficiary_id, + asset_amount_to_send, + ah_assets, + Some(asset_id_on_penpal), + fee_asset_index, + ), + }; + let mut ah_to_penpal = SystemParaToParaTest::new(ah_to_penpal_test_args); + + let ah_sender_balance_before = ah_to_penpal.sender.balance; + let penpal_receiver_balance_before = ah_to_penpal.receiver.balance; + + let ah_sender_assets_before = AssetHubRococo::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance( + foreign_asset_at_asset_hub_rococo, + &AssetHubRococoSender::get(), + ) + }); + let penpal_receiver_assets_before = PenpalA::execute_with(|| { + type Assets = ::Assets; + >::balance(asset_id_on_penpal, &PenpalAReceiver::get()) + }); + + ah_to_penpal.set_assertion::(ah_to_penpal_foreign_assets_sender_assertions); + ah_to_penpal.set_assertion::(ah_to_penpal_foreign_assets_receiver_assertions); + ah_to_penpal.set_dispatchable::(system_para_to_para_transfer_assets); + ah_to_penpal.assert(); + + let ah_sender_balance_after = ah_to_penpal.sender.balance; + let penpal_receiver_balance_after = ah_to_penpal.receiver.balance; + + let ah_sender_assets_after = AssetHubRococo::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance( + foreign_asset_at_asset_hub_rococo, + &AssetHubRococoSender::get(), + ) + }); + let penpal_receiver_assets_after = PenpalA::execute_with(|| { + type Assets = ::Assets; + >::balance(asset_id_on_penpal, &PenpalAReceiver::get()) + }); + + // Sender's balance is reduced + assert!(ah_sender_balance_after < ah_sender_balance_before); + // Receiver's balance is increased + assert!(penpal_receiver_balance_after > penpal_receiver_balance_before); + // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; + // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but + // should be non-zero + assert!(penpal_receiver_balance_after < penpal_receiver_balance_before + fee_amount_to_send); + + // Sender's balance is reduced by exact amount + assert_eq!(ah_sender_assets_before - asset_amount_to_send, ah_sender_assets_after); + // Receiver's balance is increased by exact amount + assert_eq!(penpal_receiver_assets_after, penpal_receiver_assets_before + asset_amount_to_send); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml index 74e6660d4d4..cdaa65f02cb 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml @@ -38,5 +38,4 @@ asset-test-utils = { path = "../../../../../runtimes/assets/test-utils" } cumulus-pallet-dmp-queue = { default-features = false, path = "../../../../../../pallets/dmp-queue" } cumulus-pallet-parachain-system = { default-features = false, path = "../../../../../../pallets/parachain-system" } emulated-integration-tests-common = { path = "../../../common", default-features = false } -penpal-runtime = { path = "../../../../../runtimes/testing/penpal" } westend-system-emulated-network = { path = "../../../networks/westend-system" } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs index 0c9de89c5f9..d2127b63048 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs @@ -19,3 +19,11 @@ mod set_xcm_versions; mod swap; mod teleport; mod treasury; + +use crate::*; +emulated_integration_tests_common::include_penpal_create_foreign_asset_on_asset_hub!( + PenpalB, + AssetHubWestend, + WESTEND_ED, + parachains_common::westend::fee::WeightToFee +); diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs index 1a69a4f3f71..7472445c4ba 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/reserve_transfer.rs @@ -15,8 +15,8 @@ use crate::*; use asset_hub_westend_runtime::xcm_config::XcmConfig as AssetHubWestendXcmConfig; -use penpal_runtime::xcm_config::XcmConfig as PenpalWestendXcmConfig; use westend_runtime::xcm_config::XcmConfig as WestendXcmConfig; +use westend_system_emulated_network::penpal_emulated_chain::XcmConfig as PenpalWestendXcmConfig; fn relay_to_para_sender_assertions(t: RelayToParaTest) { type RuntimeEvent = ::RuntimeEvent; @@ -162,7 +162,7 @@ fn system_para_to_para_assets_receiver_assertions(_: Test) { ); } -fn relay_to_para_limited_reserve_transfer_assets(t: RelayToParaTest) -> DispatchResult { +fn relay_to_para_reserve_transfer_assets(t: RelayToParaTest) -> DispatchResult { ::XcmPallet::limited_reserve_transfer_assets( t.signed_origin, bx!(t.args.dest.into()), @@ -173,7 +173,7 @@ fn relay_to_para_limited_reserve_transfer_assets(t: RelayToParaTest) -> Dispatch ) } -fn system_para_to_para_limited_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { +fn system_para_to_para_reserve_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { ::PolkadotXcm::limited_reserve_transfer_assets( t.signed_origin, bx!(t.args.dest.into()), @@ -184,7 +184,7 @@ fn system_para_to_para_limited_reserve_transfer_assets(t: SystemParaToParaTest) ) } -fn para_to_system_para_limited_reserve_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult { +fn para_to_system_para_reserve_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult { ::PolkadotXcm::limited_reserve_transfer_assets( t.signed_origin, bx!(t.args.dest.into()), @@ -284,7 +284,7 @@ fn reserve_transfer_native_asset_from_relay_to_para() { test.set_assertion::(relay_to_para_sender_assertions); test.set_assertion::(para_receiver_assertions); - test.set_dispatchable::(relay_to_para_limited_reserve_transfer_assets); + test.set_dispatchable::(relay_to_para_reserve_transfer_assets); test.assert(); let delivery_fees = Westend::execute_with(|| { @@ -328,7 +328,7 @@ fn reserve_transfer_native_asset_from_system_para_to_para() { test.set_assertion::(system_para_to_para_sender_assertions); test.set_assertion::(para_receiver_assertions); - test.set_dispatchable::(system_para_to_para_limited_reserve_transfer_assets); + test.set_dispatchable::(system_para_to_para_reserve_transfer_assets); test.assert(); let sender_balance_after = test.sender.balance; @@ -379,7 +379,7 @@ fn reserve_transfer_native_asset_from_para_to_system_para() { test.set_assertion::(para_to_system_para_sender_assertions); test.set_assertion::(para_to_system_para_receiver_assertions); - test.set_dispatchable::(para_to_system_para_limited_reserve_transfer_assets); + test.set_dispatchable::(para_to_system_para_reserve_transfer_assets); test.assert(); let sender_balance_after = test.sender.balance; @@ -474,7 +474,7 @@ fn reserve_transfer_assets_from_system_para_to_para() { test.set_assertion::(system_para_to_para_assets_sender_assertions); test.set_assertion::(system_para_to_para_assets_receiver_assertions); - test.set_dispatchable::(system_para_to_para_limited_reserve_transfer_assets); + test.set_dispatchable::(system_para_to_para_reserve_transfer_assets); test.assert(); let sender_balance_after = test.sender.balance; diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs index aca60f68802..1fa77bd4565 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/swap.rs @@ -14,6 +14,7 @@ // limitations under the License. use crate::*; +use westend_system_emulated_network::penpal_emulated_chain::LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub; #[test] fn swap_locally_on_chain_using_local_assets() { @@ -107,113 +108,37 @@ fn swap_locally_on_chain_using_local_assets() { #[test] fn swap_locally_on_chain_using_foreign_assets() { - use frame_support::weights::WeightToFee; - let asset_native = Box::new(asset_hub_westend_runtime::xcm_config::WestendLocation::get()); - - let foreign_asset1_at_asset_hub_westend = Box::new(MultiLocation { - parents: 1, - interior: X3( - Parachain(PenpalB::para_id().into()), - PalletInstance(ASSETS_PALLET_ID), - GeneralIndex(ASSET_ID.into()), - ), - }); - - let assets_para_destination: VersionedMultiLocation = - MultiLocation { parents: 1, interior: X1(Parachain(AssetHubWestend::para_id().into())) } - .into(); - - let penpal_location = - MultiLocation { parents: 1, interior: X1(Parachain(PenpalB::para_id().into())) }; - - // 1. Create asset on penpal: - PenpalB::execute_with(|| { - assert_ok!(::Assets::create( - ::RuntimeOrigin::signed(PenpalBSender::get()), - ASSET_ID.into(), - PenpalBSender::get().into(), - 1000, - )); - - assert!(::Assets::asset_exists(ASSET_ID)); - }); - - // 2. Create foreign asset on asset_hub_westend: - - let require_weight_at_most = Weight::from_parts(1_100_000_000_000, 30_000); - let origin_kind = OriginKind::Xcm; - let sov_penpal_on_asset_hub_westend = AssetHubWestend::sovereign_account_id_of(penpal_location); - - AssetHubWestend::fund_accounts(vec![ - (AssetHubWestendSender::get().into(), 5_000_000 * WESTEND_ED), - (sov_penpal_on_asset_hub_westend.clone().into(), 1000_000_000_000_000_000 * WESTEND_ED), - ]); - - let sov_penpal_on_asset_hub_westend_as_location: MultiLocation = MultiLocation { - parents: 0, - interior: X1(AccountId32Junction { - network: None, - id: sov_penpal_on_asset_hub_westend.clone().into(), - }), + let ah_as_seen_by_penpal = PenpalB::sibling_location_of(AssetHubWestend::para_id()); + let asset_location_on_penpal = PenpalLocalTeleportableToAssetHub::get(); + let asset_id_on_penpal = match asset_location_on_penpal.last() { + Some(GeneralIndex(id)) => *id as u32, + _ => unreachable!(), }; - - let call_foreign_assets_create = - ::RuntimeCall::ForeignAssets(pallet_assets::Call::< - ::Runtime, - Instance2, - >::create { - id: *foreign_asset1_at_asset_hub_westend, - min_balance: 1000, - admin: sov_penpal_on_asset_hub_westend.clone().into(), - }) - .encode() - .into(); - - let buy_execution_fee_amount = parachains_common::westend::fee::WeightToFee::weight_to_fee( - &Weight::from_parts(10_100_000_000_000, 300_000), + let asset_owner_on_penpal = PenpalBSender::get(); + let foreign_asset_at_asset_hub_westend = + MultiLocation { parents: 1, interior: X1(Parachain(PenpalB::para_id().into())) } + .appended_with(asset_location_on_penpal) + .unwrap(); + + // 1. Create asset on penpal and, 2. Create foreign asset on asset_hub_westend + super::penpal_create_foreign_asset_on_asset_hub( + asset_id_on_penpal, + foreign_asset_at_asset_hub_westend, + ah_as_seen_by_penpal, + true, + asset_owner_on_penpal, + ASSET_MIN_BALANCE * 1_000_000, ); - let buy_execution_fee = MultiAsset { - id: Concrete(MultiLocation { parents: 1, interior: Here }), - fun: Fungible(buy_execution_fee_amount), - }; - - let xcm = VersionedXcm::from(Xcm(vec![ - WithdrawAsset { 0: vec![buy_execution_fee.clone()].into() }, - BuyExecution { fees: buy_execution_fee.clone(), weight_limit: Unlimited }, - Transact { require_weight_at_most, origin_kind, call: call_foreign_assets_create }, - RefundSurplus, - DepositAsset { - assets: All.into(), - beneficiary: sov_penpal_on_asset_hub_westend_as_location, - }, - ])); - - // Send XCM message from penpal => asset_hub_westend - let sudo_penpal_origin = ::RuntimeOrigin::root(); - PenpalB::execute_with(|| { - assert_ok!(::PolkadotXcm::send( - sudo_penpal_origin.clone(), - bx!(assets_para_destination.clone()), - bx!(xcm), - )); - - type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - PenpalB, - vec![ - RuntimeEvent::PolkadotXcm(pallet_xcm::Event::Sent { .. }) => {}, - ] - ); - }); + let penpal_as_seen_by_ah = AssetHubWestend::sibling_location_of(PenpalB::para_id()); + let sov_penpal_on_ahw = AssetHubWestend::sovereign_account_id_of(penpal_as_seen_by_ah); + AssetHubWestend::fund_accounts(vec![ + (AssetHubWestendSender::get().into(), 5_000_000 * WESTEND_ED), /* An account to swap dot + * for something else. */ + ]); - // Receive XCM message in Assets Parachain in the next block. AssetHubWestend::execute_with(|| { - assert!(::ForeignAssets::asset_exists( - *foreign_asset1_at_asset_hub_westend - )); - // 3: Mint foreign asset on asset_hub_westend: // // (While it might be nice to use batch, @@ -222,11 +147,9 @@ fn swap_locally_on_chain_using_foreign_assets() { type RuntimeEvent = ::RuntimeEvent; // 3. Mint foreign asset (in reality this should be a teleport or some such) assert_ok!(::ForeignAssets::mint( - ::RuntimeOrigin::signed( - sov_penpal_on_asset_hub_westend.clone().into() - ), - *foreign_asset1_at_asset_hub_westend, - sov_penpal_on_asset_hub_westend.clone().into(), + ::RuntimeOrigin::signed(sov_penpal_on_ahw.clone().into()), + foreign_asset_at_asset_hub_westend, + sov_penpal_on_ahw.clone().into(), 3_000_000_000_000, )); @@ -237,11 +160,12 @@ fn swap_locally_on_chain_using_foreign_assets() { ] ); + let foreign_asset_at_asset_hub_westend = Box::new(foreign_asset_at_asset_hub_westend); // 4. Create pool: assert_ok!(::AssetConversion::create_pool( ::RuntimeOrigin::signed(AssetHubWestendSender::get()), asset_native.clone(), - foreign_asset1_at_asset_hub_westend.clone(), + foreign_asset_at_asset_hub_westend.clone(), )); assert_expected_events!( @@ -253,16 +177,14 @@ fn swap_locally_on_chain_using_foreign_assets() { // 5. Add liquidity: assert_ok!(::AssetConversion::add_liquidity( - ::RuntimeOrigin::signed( - sov_penpal_on_asset_hub_westend.clone() - ), + ::RuntimeOrigin::signed(sov_penpal_on_ahw.clone()), asset_native.clone(), - foreign_asset1_at_asset_hub_westend.clone(), + foreign_asset_at_asset_hub_westend.clone(), 1_000_000_000_000, 2_000_000_000_000, 0, 0, - sov_penpal_on_asset_hub_westend.clone().into() + sov_penpal_on_ahw.clone().into() )); assert_expected_events!( @@ -277,7 +199,7 @@ fn swap_locally_on_chain_using_foreign_assets() { // 6. Swap! let path = BoundedVec::<_, _>::truncate_from(vec![ asset_native.clone(), - foreign_asset1_at_asset_hub_westend.clone(), + foreign_asset_at_asset_hub_westend.clone(), ]); assert_ok!(::AssetConversion::swap_exact_tokens_for_tokens( @@ -301,15 +223,13 @@ fn swap_locally_on_chain_using_foreign_assets() { // 7. Remove liquidity assert_ok!(::AssetConversion::remove_liquidity( - ::RuntimeOrigin::signed( - sov_penpal_on_asset_hub_westend.clone() - ), + ::RuntimeOrigin::signed(sov_penpal_on_ahw.clone()), asset_native, - foreign_asset1_at_asset_hub_westend, + foreign_asset_at_asset_hub_westend, 1414213562273 - 2_000_000_000, // all but the 2 EDs can't be retrieved. 0, 0, - sov_penpal_on_asset_hub_westend.clone().into(), + sov_penpal_on_ahw.clone().into(), )); }); } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs index 2c43bb9d801..2dd68ae3a83 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs @@ -15,7 +15,9 @@ use crate::*; use asset_hub_westend_runtime::xcm_config::XcmConfig as AssetHubWestendXcmConfig; +use emulated_integration_tests_common::xcm_helpers::non_fee_asset; use westend_runtime::xcm_config::XcmConfig as WestendXcmConfig; +use westend_system_emulated_network::penpal_emulated_chain::LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub; fn relay_origin_assertions(t: RelayToSystemParaTest) { type RuntimeEvent = ::RuntimeEvent; @@ -110,6 +112,123 @@ fn para_dest_assertions(t: RelayToSystemParaTest) { ); } +fn penpal_to_ah_foreign_assets_sender_assertions(t: ParaToSystemParaTest) { + type RuntimeEvent = ::RuntimeEvent; + PenpalB::assert_xcm_pallet_attempted_complete(None); + let expected_asset_id = t.args.asset_id.unwrap(); + let (_, expected_asset_amount) = + non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap(); + assert_expected_events!( + PenpalB, + vec![ + RuntimeEvent::Balances( + pallet_balances::Event::Withdraw { who, amount } + ) => { + who: *who == t.sender.account_id, + amount: *amount == t.args.amount, + }, + RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { + asset_id: *asset_id == expected_asset_id, + owner: *owner == t.sender.account_id, + balance: *balance == expected_asset_amount, + }, + ] + ); +} + +fn penpal_to_ah_foreign_assets_receiver_assertions(t: ParaToSystemParaTest) { + type RuntimeEvent = ::RuntimeEvent; + let sov_penpal_on_ahr = AssetHubWestend::sovereign_account_id_of( + AssetHubWestend::sibling_location_of(PenpalB::para_id()), + ); + let (expected_foreign_asset_id, expected_foreign_asset_amount) = + non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap(); + assert_expected_events!( + AssetHubWestend, + vec![ + // native asset reserve transfer for paying fees, withdrawn from Penpal's sov account + RuntimeEvent::Balances( + pallet_balances::Event::Withdraw { who, amount } + ) => { + who: *who == sov_penpal_on_ahr.clone().into(), + amount: *amount == t.args.amount, + }, + RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { + who: *who == t.receiver.account_id, + }, + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { asset_id, owner, amount }) => { + asset_id: *asset_id == expected_foreign_asset_id, + owner: *owner == t.receiver.account_id, + amount: *amount == expected_foreign_asset_amount, + }, + RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) => {}, + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); +} + +fn ah_to_penpal_foreign_assets_sender_assertions(t: SystemParaToParaTest) { + type RuntimeEvent = ::RuntimeEvent; + AssetHubWestend::assert_xcm_pallet_attempted_complete(None); + let (expected_foreign_asset_id, expected_foreign_asset_amount) = + non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap(); + assert_expected_events!( + AssetHubWestend, + vec![ + // native asset used for fees is transferred to Parachain's Sovereign account as reserve + RuntimeEvent::Balances( + pallet_balances::Event::Transfer { from, to, amount } + ) => { + from: *from == t.sender.account_id, + to: *to == AssetHubWestend::sovereign_account_id_of( + t.args.dest + ), + amount: *amount == t.args.amount, + }, + // foreign asset is burned locally as part of teleportation + RuntimeEvent::ForeignAssets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { + asset_id: *asset_id == expected_foreign_asset_id, + owner: *owner == t.sender.account_id, + balance: *balance == expected_foreign_asset_amount, + }, + ] + ); +} + +fn ah_to_penpal_foreign_assets_receiver_assertions(t: SystemParaToParaTest) { + type RuntimeEvent = ::RuntimeEvent; + let expected_asset_id = t.args.asset_id.unwrap(); + let (_, expected_asset_amount) = + non_fee_asset(&t.args.assets, t.args.fee_asset_item as usize).unwrap(); + let checking_account = ::PolkadotXcm::check_account(); + assert_expected_events!( + PenpalB, + vec![ + // checking account burns local asset as part of incoming teleport + RuntimeEvent::Assets(pallet_assets::Event::Burned { asset_id, owner, balance }) => { + asset_id: *asset_id == expected_asset_id, + owner: *owner == checking_account, + balance: *balance == expected_asset_amount, + }, + // local asset is teleported into account of receiver + RuntimeEvent::Assets(pallet_assets::Event::Issued { asset_id, owner, amount }) => { + asset_id: *asset_id == expected_asset_id, + owner: *owner == t.receiver.account_id, + amount: *amount == expected_asset_amount, + }, + // native asset for fee is deposited to receiver + RuntimeEvent::Balances(pallet_balances::Event::Deposit { who, .. }) => { + who: *who == t.receiver.account_id, + }, + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); +} + fn relay_limited_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult { ::XcmPallet::limited_teleport_assets( t.signed_origin, @@ -152,6 +271,28 @@ fn system_para_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { ) } +fn system_para_to_para_transfer_assets(t: SystemParaToParaTest) -> DispatchResult { + ::PolkadotXcm::transfer_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + t.args.weight_limit, + ) +} + +fn para_to_system_para_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult { + ::PolkadotXcm::transfer_assets( + t.signed_origin, + bx!(t.args.dest.into()), + bx!(t.args.beneficiary.into()), + bx!(t.args.assets.into()), + t.args.fee_asset_item, + t.args.weight_limit, + ) +} + /// Limited Teleport of native asset from Relay Chain to the System Parachain should work #[test] fn limited_teleport_native_assets_from_relay_to_system_para_works() { @@ -410,3 +551,199 @@ fn teleport_to_other_system_parachains_works() { (native_asset, amount) ); } + +/// Bidirectional teleports of local Penpal assets to Asset Hub as foreign assets should work +/// (using native reserve-based transfer for fees) +#[test] +fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { + let ah_as_seen_by_penpal = PenpalB::sibling_location_of(AssetHubWestend::para_id()); + let asset_location_on_penpal = PenpalLocalTeleportableToAssetHub::get(); + let asset_id_on_penpal = match asset_location_on_penpal.last() { + Some(GeneralIndex(id)) => *id as u32, + _ => unreachable!(), + }; + let asset_owner_on_penpal = PenpalBSender::get(); + let foreign_asset_at_asset_hub_westend = + MultiLocation { parents: 1, interior: X1(Parachain(PenpalB::para_id().into())) } + .appended_with(asset_location_on_penpal) + .unwrap(); + super::penpal_create_foreign_asset_on_asset_hub( + asset_id_on_penpal, + foreign_asset_at_asset_hub_westend, + ah_as_seen_by_penpal, + false, + asset_owner_on_penpal, + ASSET_MIN_BALANCE * 1_000_000, + ); + let penpal_to_ah_beneficiary_id = AssetHubWestendReceiver::get(); + + let fee_amount_to_send = ASSET_HUB_WESTEND_ED * 1000; + let asset_amount_to_send = ASSET_MIN_BALANCE * 1000; + + let penpal_assets: MultiAssets = vec![ + (Parent, fee_amount_to_send).into(), + (asset_location_on_penpal, asset_amount_to_send).into(), + ] + .into(); + let fee_asset_index = penpal_assets + .inner() + .iter() + .position(|r| r == &(Parent, fee_amount_to_send).into()) + .unwrap() as u32; + + // Penpal to AH test args + let penpal_to_ah_test_args = TestContext { + sender: PenpalBSender::get(), + receiver: AssetHubWestendReceiver::get(), + args: para_test_args( + ah_as_seen_by_penpal, + penpal_to_ah_beneficiary_id, + asset_amount_to_send, + penpal_assets, + Some(asset_id_on_penpal), + fee_asset_index, + ), + }; + let mut penpal_to_ah = ParaToSystemParaTest::new(penpal_to_ah_test_args); + + let penpal_sender_balance_before = penpal_to_ah.sender.balance; + let ah_receiver_balance_before = penpal_to_ah.receiver.balance; + + let penpal_sender_assets_before = PenpalB::execute_with(|| { + type Assets = ::Assets; + >::balance(asset_id_on_penpal, &PenpalBSender::get()) + }); + let ah_receiver_assets_before = AssetHubWestend::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance( + foreign_asset_at_asset_hub_westend, + &AssetHubWestendReceiver::get(), + ) + }); + + penpal_to_ah.set_assertion::(penpal_to_ah_foreign_assets_sender_assertions); + penpal_to_ah.set_assertion::(penpal_to_ah_foreign_assets_receiver_assertions); + penpal_to_ah.set_dispatchable::(para_to_system_para_transfer_assets); + penpal_to_ah.assert(); + + let penpal_sender_balance_after = penpal_to_ah.sender.balance; + let ah_receiver_balance_after = penpal_to_ah.receiver.balance; + + let penpal_sender_assets_after = PenpalB::execute_with(|| { + type Assets = ::Assets; + >::balance(asset_id_on_penpal, &PenpalBSender::get()) + }); + let ah_receiver_assets_after = AssetHubWestend::execute_with(|| { + type Assets = ::ForeignAssets; + >::balance( + foreign_asset_at_asset_hub_westend, + &AssetHubWestendReceiver::get(), + ) + }); + + // Sender's balance is reduced + assert!(penpal_sender_balance_after < penpal_sender_balance_before); + // Receiver's balance is increased + assert!(ah_receiver_balance_after > ah_receiver_balance_before); + // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; + // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but + // should be non-zero + assert!(ah_receiver_balance_after < ah_receiver_balance_before + fee_amount_to_send); + + // Sender's balance is reduced by exact amount + assert_eq!(penpal_sender_assets_before - asset_amount_to_send, penpal_sender_assets_after); + // Receiver's balance is increased by exact amount + assert_eq!(ah_receiver_assets_after, ah_receiver_assets_before + asset_amount_to_send); + + /////////////////////////////////////////////////////////////////////// + // Now test transferring foreign assets back from AssetHub to Penpal // + /////////////////////////////////////////////////////////////////////// + + // Move funds on AH from AHReceiver to AHSender + AssetHubWestend::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + assert_ok!(ForeignAssets::transfer( + ::RuntimeOrigin::signed(AssetHubWestendReceiver::get()), + foreign_asset_at_asset_hub_westend, + AssetHubWestendSender::get().into(), + asset_amount_to_send, + )); + }); + + let ah_to_penpal_beneficiary_id = PenpalBReceiver::get(); + let penpal_as_seen_by_ah = AssetHubWestend::sibling_location_of(PenpalB::para_id()); + let ah_assets: MultiAssets = vec![ + (Parent, fee_amount_to_send).into(), + (foreign_asset_at_asset_hub_westend, asset_amount_to_send).into(), + ] + .into(); + let fee_asset_index = ah_assets + .inner() + .iter() + .position(|r| r == &(Parent, fee_amount_to_send).into()) + .unwrap() as u32; + + // AH to Penpal test args + let ah_to_penpal_test_args = TestContext { + sender: AssetHubWestendSender::get(), + receiver: PenpalBReceiver::get(), + args: para_test_args( + penpal_as_seen_by_ah, + ah_to_penpal_beneficiary_id, + asset_amount_to_send, + ah_assets, + Some(asset_id_on_penpal), + fee_asset_index, + ), + }; + let mut ah_to_penpal = SystemParaToParaTest::new(ah_to_penpal_test_args); + + let ah_sender_balance_before = ah_to_penpal.sender.balance; + let penpal_receiver_balance_before = ah_to_penpal.receiver.balance; + + let ah_sender_assets_before = AssetHubWestend::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance( + foreign_asset_at_asset_hub_westend, + &AssetHubWestendSender::get(), + ) + }); + let penpal_receiver_assets_before = PenpalB::execute_with(|| { + type Assets = ::Assets; + >::balance(asset_id_on_penpal, &PenpalBReceiver::get()) + }); + + ah_to_penpal.set_assertion::(ah_to_penpal_foreign_assets_sender_assertions); + ah_to_penpal.set_assertion::(ah_to_penpal_foreign_assets_receiver_assertions); + ah_to_penpal.set_dispatchable::(system_para_to_para_transfer_assets); + ah_to_penpal.assert(); + + let ah_sender_balance_after = ah_to_penpal.sender.balance; + let penpal_receiver_balance_after = ah_to_penpal.receiver.balance; + + let ah_sender_assets_after = AssetHubWestend::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance( + foreign_asset_at_asset_hub_westend, + &AssetHubWestendSender::get(), + ) + }); + let penpal_receiver_assets_after = PenpalB::execute_with(|| { + type Assets = ::Assets; + >::balance(asset_id_on_penpal, &PenpalBReceiver::get()) + }); + + // Sender's balance is reduced + assert!(ah_sender_balance_after < ah_sender_balance_before); + // Receiver's balance is increased + assert!(penpal_receiver_balance_after > penpal_receiver_balance_before); + // Receiver's balance increased by `amount_to_send - delivery_fees - bought_execution`; + // `delivery_fees` might be paid from transfer or JIT, also `bought_execution` is unknown but + // should be non-zero + assert!(penpal_receiver_balance_after < penpal_receiver_balance_before + fee_amount_to_send); + + // Sender's balance is reduced by exact amount + assert_eq!(ah_sender_assets_before - asset_amount_to_send, ah_sender_assets_after); + // Receiver's balance is increased by exact amount + assert_eq!(penpal_receiver_assets_after, penpal_receiver_assets_before + asset_amount_to_send); +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index 46bca804a9c..86000a20b5b 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -1359,6 +1359,55 @@ impl_runtime_apis! { ParentThen(Parachain(random_para_id).into()).into(), )) } + + fn set_up_complex_asset_transfer( + ) -> Option<(MultiAssets, u32, MultiLocation, Box)> { + // Transfer to Relay some local AH asset (local-reserve-transfer) while paying + // fees using teleported native token. + // (We don't care that Relay doesn't accept incoming unknown AH local asset) + let dest = Parent.into(); + + let fee_amount = EXISTENTIAL_DEPOSIT; + let fee_asset: MultiAsset = (MultiLocation::parent(), fee_amount).into(); + + let who = frame_benchmarking::whitelisted_caller(); + // Give some multiple of the existential deposit + let balance = fee_amount + EXISTENTIAL_DEPOSIT * 1000; + let _ = >::make_free_balance_be( + &who, balance, + ); + // verify initial balance + assert_eq!(Balances::free_balance(&who), balance); + + // set up local asset + let asset_amount = 10u128; + let initial_asset_amount = asset_amount * 10; + let (asset_id, _, _) = pallet_assets::benchmarking::create_default_minted_asset::< + Runtime, + pallet_assets::Instance1 + >(true, initial_asset_amount); + let asset_location = MultiLocation::new( + 0, + X2(PalletInstance(50), GeneralIndex(u32::from(asset_id).into())) + ); + let transfer_asset: MultiAsset = (asset_location, asset_amount).into(); + + let assets: MultiAssets = vec![fee_asset.clone(), transfer_asset].into(); + let fee_index = if assets.get(0).unwrap().eq(&fee_asset) { 0 } else { 1 }; + + // verify transferred successfully + let verify = Box::new(move || { + // verify native balance after transfer, decreased by transferred fee amount + // (plus transport fees) + assert!(Balances::free_balance(&who) <= balance - fee_amount); + // verify asset balance decreased by exactly transferred amount + assert_eq!( + Assets::balance(asset_id.into(), &who), + initial_asset_amount - asset_amount, + ); + }); + Some((assets, fee_index as u32, dest, verify)) + } } impl XcmBridgeHubRouterConfig for Runtime { diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs index afe85fdaf28..f8820bbb58c 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-12-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-r43aesjn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -64,37 +64,95 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 24_498_000 picoseconds. - Weight::from_parts(25_385_000, 0) + // Minimum execution time: 25_003_000 picoseconds. + Weight::from_parts(25_800_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) - /// Proof: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn teleport_assets() -> Weight { // Proof Size summary in bytes: - // Measured: `39` - // Estimated: `3504` - // Minimum execution time: 19_746_000 picoseconds. - Weight::from_parts(20_535_000, 0) - .saturating_add(Weight::from_parts(0, 3504)) - .saturating_add(T::DbWeight::get().reads(2)) + // Measured: `145` + // Estimated: `3610` + // Minimum execution time: 88_832_000 picoseconds. + Weight::from_parts(90_491_000, 0) + .saturating_add(Weight::from_parts(0, 3610)) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) - /// Proof: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) + /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::OutboundXcmpMessages` (r:0 w:1) + /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) fn reserve_transfer_assets() -> Weight { // Proof Size summary in bytes: - // Measured: `39` - // Estimated: `3504` - // Minimum execution time: 15_059_000 picoseconds. - Weight::from_parts(15_386_000, 0) - .saturating_add(Weight::from_parts(0, 3504)) - .saturating_add(T::DbWeight::get().reads(2)) + // Measured: `400` + // Estimated: `6196` + // Minimum execution time: 138_911_000 picoseconds. + Weight::from_parts(142_483_000, 0) + .saturating_add(Weight::from_parts(0, 6196)) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:2 w:2) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn transfer_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `496` + // Estimated: `6208` + // Minimum execution time: 146_932_000 picoseconds. + Weight::from_parts(153_200_000, 0) + .saturating_add(Weight::from_parts(0, 6208)) + .saturating_add(T::DbWeight::get().reads(12)) + .saturating_add(T::DbWeight::get().writes(7)) } /// Storage: `Benchmark::Override` (r:0 w:0) /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -112,8 +170,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_108_000 picoseconds. - Weight::from_parts(7_458_000, 0) + // Minimum execution time: 7_081_000 picoseconds. + Weight::from_parts(7_397_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -123,8 +181,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_205_000 picoseconds. - Weight::from_parts(2_360_000, 0) + // Minimum execution time: 2_007_000 picoseconds. + Weight::from_parts(2_183_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -150,8 +208,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 29_099_000 picoseconds. - Weight::from_parts(29_580_000, 0) + // Minimum execution time: 28_790_000 picoseconds. + Weight::from_parts(29_767_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(5)) @@ -176,8 +234,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `363` // Estimated: `3828` - // Minimum execution time: 31_161_000 picoseconds. - Weight::from_parts(31_933_000, 0) + // Minimum execution time: 30_951_000 picoseconds. + Weight::from_parts(31_804_000, 0) .saturating_add(Weight::from_parts(0, 3828)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) @@ -188,8 +246,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_158_000 picoseconds. - Weight::from_parts(2_316_000, 0) + // Minimum execution time: 2_164_000 picoseconds. + Weight::from_parts(2_311_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -199,8 +257,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `162` // Estimated: `11052` - // Minimum execution time: 16_934_000 picoseconds. - Weight::from_parts(17_655_000, 0) + // Minimum execution time: 16_906_000 picoseconds. + Weight::from_parts(17_612_000, 0) .saturating_add(Weight::from_parts(0, 11052)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -211,8 +269,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `166` // Estimated: `11056` - // Minimum execution time: 17_658_000 picoseconds. - Weight::from_parts(17_973_000, 0) + // Minimum execution time: 17_443_000 picoseconds. + Weight::from_parts(18_032_000, 0) .saturating_add(Weight::from_parts(0, 11056)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -223,8 +281,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `173` // Estimated: `13538` - // Minimum execution time: 18_673_000 picoseconds. - Weight::from_parts(19_027_000, 0) + // Minimum execution time: 18_992_000 picoseconds. + Weight::from_parts(19_464_000, 0) .saturating_add(Weight::from_parts(0, 13538)) .saturating_add(T::DbWeight::get().reads(5)) } @@ -246,8 +304,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `212` // Estimated: `6152` - // Minimum execution time: 27_171_000 picoseconds. - Weight::from_parts(27_802_000, 0) + // Minimum execution time: 28_011_000 picoseconds. + Weight::from_parts(28_716_000, 0) .saturating_add(Weight::from_parts(0, 6152)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) @@ -258,8 +316,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `206` // Estimated: `8621` - // Minimum execution time: 9_423_000 picoseconds. - Weight::from_parts(9_636_000, 0) + // Minimum execution time: 9_533_000 picoseconds. + Weight::from_parts(9_856_000, 0) .saturating_add(Weight::from_parts(0, 8621)) .saturating_add(T::DbWeight::get().reads(3)) } @@ -269,8 +327,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `173` // Estimated: `11063` - // Minimum execution time: 17_442_000 picoseconds. - Weight::from_parts(17_941_000, 0) + // Minimum execution time: 17_628_000 picoseconds. + Weight::from_parts(18_146_000, 0) .saturating_add(Weight::from_parts(0, 11063)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -293,8 +351,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `215` // Estimated: `11105` - // Minimum execution time: 34_340_000 picoseconds. - Weight::from_parts(34_934_000, 0) + // Minimum execution time: 34_877_000 picoseconds. + Weight::from_parts(35_607_000, 0) .saturating_add(Weight::from_parts(0, 11105)) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) @@ -307,8 +365,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `1588` - // Minimum execution time: 5_496_000 picoseconds. - Weight::from_parts(5_652_000, 0) + // Minimum execution time: 5_370_000 picoseconds. + Weight::from_parts(5_616_000, 0) .saturating_add(Weight::from_parts(0, 1588)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -319,8 +377,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7740` // Estimated: `11205` - // Minimum execution time: 26_140_000 picoseconds. - Weight::from_parts(26_824_000, 0) + // Minimum execution time: 26_820_000 picoseconds. + Weight::from_parts(27_143_000, 0) .saturating_add(Weight::from_parts(0, 11205)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index dfe4990df96..6709a20b275 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -1431,6 +1431,55 @@ impl_runtime_apis! { ParentThen(Parachain(random_para_id).into()).into(), )) } + + fn set_up_complex_asset_transfer( + ) -> Option<(MultiAssets, u32, MultiLocation, Box)> { + // Transfer to Relay some local AH asset (local-reserve-transfer) while paying + // fees using teleported native token. + // (We don't care that Relay doesn't accept incoming unknown AH local asset) + let dest = Parent.into(); + + let fee_amount = EXISTENTIAL_DEPOSIT; + let fee_asset: MultiAsset = (MultiLocation::parent(), fee_amount).into(); + + let who = frame_benchmarking::whitelisted_caller(); + // Give some multiple of the existential deposit + let balance = fee_amount + EXISTENTIAL_DEPOSIT * 1000; + let _ = >::make_free_balance_be( + &who, balance, + ); + // verify initial balance + assert_eq!(Balances::free_balance(&who), balance); + + // set up local asset + let asset_amount = 10u128; + let initial_asset_amount = asset_amount * 10; + let (asset_id, _, _) = pallet_assets::benchmarking::create_default_minted_asset::< + Runtime, + pallet_assets::Instance1 + >(true, initial_asset_amount); + let asset_location = MultiLocation::new( + 0, + X2(PalletInstance(50), GeneralIndex(u32::from(asset_id).into())) + ); + let transfer_asset: MultiAsset = (asset_location, asset_amount).into(); + + let assets: MultiAssets = vec![fee_asset.clone(), transfer_asset].into(); + let fee_index = if assets.get(0).unwrap().eq(&fee_asset) { 0 } else { 1 }; + + // verify transferred successfully + let verify = Box::new(move || { + // verify native balance after transfer, decreased by transferred fee amount + // (plus transport fees) + assert!(Balances::free_balance(&who) <= balance - fee_amount); + // verify asset balance decreased by exactly transferred amount + assert_eq!( + Assets::balance(asset_id.into(), &who), + initial_asset_amount - asset_amount, + ); + }); + Some((assets, fee_index as u32, dest, verify)) + } } use pallet_xcm_bridge_hub_router::benchmarking::{ diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs index 340edafb0b0..504731f4a9e 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-12-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-r43aesjn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -64,40 +64,102 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 25_534_000 picoseconds. - Weight::from_parts(26_413_000, 0) + // Minimum execution time: 25_482_000 picoseconds. + Weight::from_parts(26_622_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn teleport_assets() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `1489` - // Minimum execution time: 20_513_000 picoseconds. - Weight::from_parts(20_837_000, 0) - .saturating_add(Weight::from_parts(0, 1489)) - .saturating_add(T::DbWeight::get().reads(1)) + // Measured: `145` + // Estimated: `3610` + // Minimum execution time: 87_319_000 picoseconds. + Weight::from_parts(89_764_000, 0) + .saturating_add(Weight::from_parts(0, 3610)) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) + /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::OutboundXcmpMessages` (r:0 w:1) + /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) fn reserve_transfer_assets() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `1489` - // Minimum execution time: 14_977_000 picoseconds. - Weight::from_parts(15_207_000, 0) - .saturating_add(Weight::from_parts(0, 1489)) - .saturating_add(T::DbWeight::get().reads(1)) + // Measured: `367` + // Estimated: `6196` + // Minimum execution time: 139_133_000 picoseconds. + Weight::from_parts(141_507_000, 0) + .saturating_add(Weight::from_parts(0, 6196)) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(5)) + } + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:1 w:1) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:2 w:2) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn transfer_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `496` + // Estimated: `6208` + // Minimum execution time: 144_241_000 picoseconds. + Weight::from_parts(149_709_000, 0) + .saturating_add(Weight::from_parts(0, 6208)) + .saturating_add(T::DbWeight::get().reads(12)) + .saturating_add(T::DbWeight::get().writes(7)) } fn execute() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_440_000 picoseconds. - Weight::from_parts(7_651_000, 0) + // Minimum execution time: 10_392_000 picoseconds. + Weight::from_parts(10_779_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1) @@ -106,8 +168,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_253_000 picoseconds. - Weight::from_parts(7_584_000, 0) + // Minimum execution time: 7_088_000 picoseconds. + Weight::from_parts(7_257_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -117,8 +179,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_299_000 picoseconds. - Weight::from_parts(2_435_000, 0) + // Minimum execution time: 2_095_000 picoseconds. + Weight::from_parts(2_136_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -144,8 +206,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 29_440_000 picoseconds. - Weight::from_parts(30_675_000, 0) + // Minimum execution time: 28_728_000 picoseconds. + Weight::from_parts(29_349_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(5)) @@ -170,8 +232,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `363` // Estimated: `3828` - // Minimum execution time: 31_876_000 picoseconds. - Weight::from_parts(32_588_000, 0) + // Minimum execution time: 30_605_000 picoseconds. + Weight::from_parts(31_477_000, 0) .saturating_add(Weight::from_parts(0, 3828)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) @@ -182,8 +244,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_385_000 picoseconds. - Weight::from_parts(2_607_000, 0) + // Minimum execution time: 2_137_000 picoseconds. + Weight::from_parts(2_303_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -193,8 +255,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `162` // Estimated: `11052` - // Minimum execution time: 16_927_000 picoseconds. - Weight::from_parts(17_554_000, 0) + // Minimum execution time: 16_719_000 picoseconds. + Weight::from_parts(17_329_000, 0) .saturating_add(Weight::from_parts(0, 11052)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -205,8 +267,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `166` // Estimated: `11056` - // Minimum execution time: 16_965_000 picoseconds. - Weight::from_parts(17_807_000, 0) + // Minimum execution time: 16_687_000 picoseconds. + Weight::from_parts(17_405_000, 0) .saturating_add(Weight::from_parts(0, 11056)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -217,8 +279,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `173` // Estimated: `13538` - // Minimum execution time: 18_763_000 picoseconds. - Weight::from_parts(19_359_000, 0) + // Minimum execution time: 18_751_000 picoseconds. + Weight::from_parts(19_130_000, 0) .saturating_add(Weight::from_parts(0, 13538)) .saturating_add(T::DbWeight::get().reads(5)) } @@ -240,8 +302,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `212` // Estimated: `6152` - // Minimum execution time: 27_371_000 picoseconds. - Weight::from_parts(28_185_000, 0) + // Minimum execution time: 27_189_000 picoseconds. + Weight::from_parts(27_760_000, 0) .saturating_add(Weight::from_parts(0, 6152)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) @@ -252,8 +314,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `206` // Estimated: `8621` - // Minimum execution time: 9_165_000 picoseconds. - Weight::from_parts(9_539_000, 0) + // Minimum execution time: 9_307_000 picoseconds. + Weight::from_parts(9_691_000, 0) .saturating_add(Weight::from_parts(0, 8621)) .saturating_add(T::DbWeight::get().reads(3)) } @@ -263,8 +325,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `173` // Estimated: `11063` - // Minimum execution time: 17_384_000 picoseconds. - Weight::from_parts(17_777_000, 0) + // Minimum execution time: 17_607_000 picoseconds. + Weight::from_parts(18_090_000, 0) .saturating_add(Weight::from_parts(0, 11063)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -287,8 +349,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `215` // Estimated: `11105` - // Minimum execution time: 34_260_000 picoseconds. - Weight::from_parts(35_428_000, 0) + // Minimum execution time: 34_322_000 picoseconds. + Weight::from_parts(35_754_000, 0) .saturating_add(Weight::from_parts(0, 11105)) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) @@ -301,8 +363,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `1588` - // Minimum execution time: 4_710_000 picoseconds. - Weight::from_parts(4_900_000, 0) + // Minimum execution time: 4_513_000 picoseconds. + Weight::from_parts(4_754_000, 0) .saturating_add(Weight::from_parts(0, 1588)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -313,8 +375,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7740` // Estimated: `11205` - // Minimum execution time: 26_843_000 picoseconds. - Weight::from_parts(27_404_000, 0) + // Minimum execution time: 27_860_000 picoseconds. + Weight::from_parts(28_279_000, 0) .saturating_add(Weight::from_parts(0, 11205)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index 01efb9d20cc..7dbf015de50 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -823,6 +823,18 @@ impl_runtime_apis! { // Reserve transfers are disabled on BH. None } + + fn set_up_complex_asset_transfer( + ) -> Option<(MultiAssets, u32, MultiLocation, Box)> { + // BH only supports teleports to system parachain. + // Relay/native token can be teleported between BH and Relay. + let native_location = Parent.into(); + let dest = Parent.into(); + pallet_xcm::benchmarking::helpers::native_teleport_as_asset_transfer::( + native_location, + dest + ) + } } use xcm::latest::prelude::*; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs index 5aa4999c624..5faded42aa8 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-12-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-r43aesjn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -62,26 +62,39 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn send() -> Weight { // Proof Size summary in bytes: - // Measured: `75` - // Estimated: `3540` - // Minimum execution time: 24_179_000 picoseconds. - Weight::from_parts(24_684_000, 0) - .saturating_add(Weight::from_parts(0, 3540)) + // Measured: `38` + // Estimated: `3503` + // Minimum execution time: 23_683_000 picoseconds. + Weight::from_parts(24_199_000, 0) + .saturating_add(Weight::from_parts(0, 3503)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) - /// Proof: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn teleport_assets() -> Weight { // Proof Size summary in bytes: - // Measured: `38` - // Estimated: `3503` - // Minimum execution time: 21_093_000 picoseconds. - Weight::from_parts(21_523_000, 0) - .saturating_add(Weight::from_parts(0, 3503)) - .saturating_add(T::DbWeight::get().reads(2)) + // Measured: `70` + // Estimated: `3593` + // Minimum execution time: 89_524_000 picoseconds. + Weight::from_parts(91_401_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Benchmark::Override` (r:0 w:0) /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -93,6 +106,32 @@ impl pallet_xcm::WeightInfo for WeightInfo { Weight::from_parts(18_446_744_073_709_551_000, 0) .saturating_add(Weight::from_parts(0, 0)) } + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn transfer_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `70` + // Estimated: `3593` + // Minimum execution time: 91_890_000 picoseconds. + Weight::from_parts(93_460_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(3)) + } /// Storage: `Benchmark::Override` (r:0 w:0) /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) fn execute() -> Weight { @@ -109,8 +148,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_938_000 picoseconds. - Weight::from_parts(7_243_000, 0) + // Minimum execution time: 7_152_000 picoseconds. + Weight::from_parts(7_355_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -120,8 +159,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_159_000 picoseconds. - Weight::from_parts(2_290_000, 0) + // Minimum execution time: 2_081_000 picoseconds. + Weight::from_parts(2_258_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -145,11 +184,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_subscribe_version_notify() -> Weight { // Proof Size summary in bytes: - // Measured: `75` - // Estimated: `3540` - // Minimum execution time: 28_337_000 picoseconds. - Weight::from_parts(29_265_000, 0) - .saturating_add(Weight::from_parts(0, 3540)) + // Measured: `38` + // Estimated: `3503` + // Minimum execution time: 28_067_000 picoseconds. + Weight::from_parts(28_693_000, 0) + .saturating_add(Weight::from_parts(0, 3503)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -171,11 +210,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_unsubscribe_version_notify() -> Weight { // Proof Size summary in bytes: - // Measured: `292` - // Estimated: `3757` - // Minimum execution time: 30_599_000 picoseconds. - Weight::from_parts(31_272_000, 0) - .saturating_add(Weight::from_parts(0, 3757)) + // Measured: `255` + // Estimated: `3720` + // Minimum execution time: 30_420_000 picoseconds. + Weight::from_parts(31_373_000, 0) + .saturating_add(Weight::from_parts(0, 3720)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -185,8 +224,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_132_000 picoseconds. - Weight::from_parts(2_280_000, 0) + // Minimum execution time: 2_087_000 picoseconds. + Weight::from_parts(2_243_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -194,11 +233,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: - // Measured: `187` - // Estimated: `11077` - // Minimum execution time: 18_262_000 picoseconds. - Weight::from_parts(18_640_000, 0) - .saturating_add(Weight::from_parts(0, 11077)) + // Measured: `95` + // Estimated: `10985` + // Minimum execution time: 15_142_000 picoseconds. + Weight::from_parts(15_598_000, 0) + .saturating_add(Weight::from_parts(0, 10985)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -206,11 +245,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notifiers() -> Weight { // Proof Size summary in bytes: - // Measured: `191` - // Estimated: `11081` - // Minimum execution time: 18_512_000 picoseconds. - Weight::from_parts(18_888_000, 0) - .saturating_add(Weight::from_parts(0, 11081)) + // Measured: `99` + // Estimated: `10989` + // Minimum execution time: 15_041_000 picoseconds. + Weight::from_parts(15_493_000, 0) + .saturating_add(Weight::from_parts(0, 10989)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -218,11 +257,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn already_notified_target() -> Weight { // Proof Size summary in bytes: - // Measured: `198` - // Estimated: `13563` - // Minimum execution time: 19_362_000 picoseconds. - Weight::from_parts(20_056_000, 0) - .saturating_add(Weight::from_parts(0, 13563)) + // Measured: `106` + // Estimated: `13471` + // Minimum execution time: 16_624_000 picoseconds. + Weight::from_parts(17_031_000, 0) + .saturating_add(Weight::from_parts(0, 13471)) .saturating_add(T::DbWeight::get().reads(5)) } /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:2 w:1) @@ -241,11 +280,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn notify_current_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `142` - // Estimated: `6082` - // Minimum execution time: 27_318_000 picoseconds. - Weight::from_parts(28_075_000, 0) - .saturating_add(Weight::from_parts(0, 6082)) + // Measured: `106` + // Estimated: `6046` + // Minimum execution time: 26_398_000 picoseconds. + Weight::from_parts(26_847_000, 0) + .saturating_add(Weight::from_parts(0, 6046)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -253,22 +292,22 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: - // Measured: `172` - // Estimated: `8587` - // Minimum execution time: 9_930_000 picoseconds. - Weight::from_parts(10_192_000, 0) - .saturating_add(Weight::from_parts(0, 8587)) + // Measured: `136` + // Estimated: `8551` + // Minimum execution time: 8_741_000 picoseconds. + Weight::from_parts(8_954_000, 0) + .saturating_add(Weight::from_parts(0, 8551)) .saturating_add(T::DbWeight::get().reads(3)) } /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `198` - // Estimated: `11088` - // Minimum execution time: 18_305_000 picoseconds. - Weight::from_parts(18_738_000, 0) - .saturating_add(Weight::from_parts(0, 11088)) + // Measured: `106` + // Estimated: `10996` + // Minimum execution time: 15_306_000 picoseconds. + Weight::from_parts(15_760_000, 0) + .saturating_add(Weight::from_parts(0, 10996)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -288,11 +327,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `204` - // Estimated: `11094` - // Minimum execution time: 34_559_000 picoseconds. - Weight::from_parts(35_241_000, 0) - .saturating_add(Weight::from_parts(0, 11094)) + // Measured: `112` + // Estimated: `11002` + // Minimum execution time: 33_127_000 picoseconds. + Weight::from_parts(33_938_000, 0) + .saturating_add(Weight::from_parts(0, 11002)) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -302,11 +341,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn new_query() -> Weight { // Proof Size summary in bytes: - // Measured: `69` - // Estimated: `1554` - // Minimum execution time: 4_512_000 picoseconds. - Weight::from_parts(4_671_000, 0) - .saturating_add(Weight::from_parts(0, 1554)) + // Measured: `32` + // Estimated: `1517` + // Minimum execution time: 4_290_000 picoseconds. + Weight::from_parts(4_450_000, 0) + .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -314,11 +353,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn take_response() -> Weight { // Proof Size summary in bytes: - // Measured: `7706` - // Estimated: `11171` - // Minimum execution time: 26_473_000 picoseconds. - Weight::from_parts(26_960_000, 0) - .saturating_add(Weight::from_parts(0, 11171)) + // Measured: `7669` + // Estimated: `11134` + // Minimum execution time: 26_408_000 picoseconds. + Weight::from_parts(26_900_000, 0) + .saturating_add(Weight::from_parts(0, 11134)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index 39ce4e04ed1..e77184351ed 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -813,6 +813,18 @@ impl_runtime_apis! { // Reserve transfers are disabled on BH. None } + + fn set_up_complex_asset_transfer( + ) -> Option<(MultiAssets, u32, MultiLocation, Box)> { + // BH only supports teleports to system parachain. + // Relay/native token can be teleported between BH and Relay. + let native_location = Parent.into(); + let dest = Parent.into(); + pallet_xcm::benchmarking::helpers::native_teleport_as_asset_transfer::( + native_location, + dest + ) + } } use xcm::latest::prelude::*; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs index 9f17d327024..83e4260e771 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_xcm.rs @@ -17,27 +17,25 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-12-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `runner-r43aesjn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot-parachain +// target/production/polkadot-parachain // benchmark // pallet -// --chain=bridge-hub-rococo-dev -// --wasm-execution=compiled -// --pallet=pallet_xcm -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* // --steps=50 // --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/ +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_xcm +// --chain=bridge-hub-westend-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,6 +48,8 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -62,24 +62,39 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn send() -> Weight { // Proof Size summary in bytes: - // Measured: `75` - // Estimated: `3540` - // Minimum execution time: 29_724_000 picoseconds. - Weight::from_parts(30_440_000, 0) - .saturating_add(Weight::from_parts(0, 3540)) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `38` + // Estimated: `3503` + // Minimum execution time: 23_219_000 picoseconds. + Weight::from_parts(23_818_000, 0) + .saturating_add(Weight::from_parts(0, 3503)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn teleport_assets() -> Weight { // Proof Size summary in bytes: - // Measured: `32` - // Estimated: `1489` - // Minimum execution time: 26_779_000 picoseconds. - Weight::from_parts(27_249_000, 0) - .saturating_add(Weight::from_parts(0, 1489)) - .saturating_add(T::DbWeight::get().reads(1)) + // Measured: `70` + // Estimated: `3593` + // Minimum execution time: 90_120_000 picoseconds. + Weight::from_parts(92_545_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Benchmark::Override` (r:0 w:0) /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -91,6 +106,32 @@ impl pallet_xcm::WeightInfo for WeightInfo { Weight::from_parts(18_446_744_073_709_551_000, 0) .saturating_add(Weight::from_parts(0, 0)) } + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn transfer_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `70` + // Estimated: `3593` + // Minimum execution time: 91_339_000 picoseconds. + Weight::from_parts(93_204_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(3)) + } /// Storage: `Benchmark::Override` (r:0 w:0) /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) fn execute() -> Weight { @@ -107,8 +148,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_170_000 picoseconds. - Weight::from_parts(9_629_000, 0) + // Minimum execution time: 6_976_000 picoseconds. + Weight::from_parts(7_284_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -118,8 +159,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_769_000 picoseconds. - Weight::from_parts(2_933_000, 0) + // Minimum execution time: 2_044_000 picoseconds. + Weight::from_parts(2_223_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -127,6 +168,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) /// Proof: `PolkadotXcm::QueryCounter` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -141,16 +184,18 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_subscribe_version_notify() -> Weight { // Proof Size summary in bytes: - // Measured: `75` - // Estimated: `3540` - // Minimum execution time: 34_547_000 picoseconds. - Weight::from_parts(35_653_000, 0) - .saturating_add(Weight::from_parts(0, 3540)) - .saturating_add(T::DbWeight::get().reads(7)) + // Measured: `38` + // Estimated: `3503` + // Minimum execution time: 27_778_000 picoseconds. + Weight::from_parts(28_318_000, 0) + .saturating_add(Weight::from_parts(0, 3503)) + .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: `PolkadotXcm::VersionNotifiers` (r:1 w:1) /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -165,12 +210,12 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn force_unsubscribe_version_notify() -> Weight { // Proof Size summary in bytes: - // Measured: `292` - // Estimated: `3757` - // Minimum execution time: 36_274_000 picoseconds. - Weight::from_parts(37_281_000, 0) - .saturating_add(Weight::from_parts(0, 3757)) - .saturating_add(T::DbWeight::get().reads(6)) + // Measured: `255` + // Estimated: `3720` + // Minimum execution time: 30_446_000 picoseconds. + Weight::from_parts(31_925_000, 0) + .saturating_add(Weight::from_parts(0, 3720)) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `PolkadotXcm::XcmExecutionSuspended` (r:0 w:1) @@ -179,8 +224,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_749_000 picoseconds. - Weight::from_parts(2_917_000, 0) + // Minimum execution time: 2_037_000 picoseconds. + Weight::from_parts(2_211_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -188,11 +233,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: - // Measured: `187` - // Estimated: `11077` - // Minimum execution time: 17_649_000 picoseconds. - Weight::from_parts(17_964_000, 0) - .saturating_add(Weight::from_parts(0, 11077)) + // Measured: `95` + // Estimated: `10985` + // Minimum execution time: 15_620_000 picoseconds. + Weight::from_parts(15_984_000, 0) + .saturating_add(Weight::from_parts(0, 10985)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -200,11 +245,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `PolkadotXcm::VersionNotifiers` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notifiers() -> Weight { // Proof Size summary in bytes: - // Measured: `191` - // Estimated: `11081` - // Minimum execution time: 17_551_000 picoseconds. - Weight::from_parts(18_176_000, 0) - .saturating_add(Weight::from_parts(0, 11081)) + // Measured: `99` + // Estimated: `10989` + // Minimum execution time: 15_689_000 picoseconds. + Weight::from_parts(16_093_000, 0) + .saturating_add(Weight::from_parts(0, 10989)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -212,15 +257,17 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn already_notified_target() -> Weight { // Proof Size summary in bytes: - // Measured: `198` - // Estimated: `13563` - // Minimum execution time: 19_261_000 picoseconds. - Weight::from_parts(19_714_000, 0) - .saturating_add(Weight::from_parts(0, 13563)) + // Measured: `106` + // Estimated: `13471` + // Minimum execution time: 16_946_000 picoseconds. + Weight::from_parts(17_192_000, 0) + .saturating_add(Weight::from_parts(0, 13471)) .saturating_add(T::DbWeight::get().reads(5)) } /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:2 w:1) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -233,39 +280,41 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn notify_current_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `142` - // Estimated: `6082` - // Minimum execution time: 31_630_000 picoseconds. - Weight::from_parts(32_340_000, 0) - .saturating_add(Weight::from_parts(0, 6082)) - .saturating_add(T::DbWeight::get().reads(7)) + // Measured: `106` + // Estimated: `6046` + // Minimum execution time: 27_164_000 picoseconds. + Weight::from_parts(27_760_000, 0) + .saturating_add(Weight::from_parts(0, 6046)) + .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:3 w:0) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: - // Measured: `172` - // Estimated: `8587` - // Minimum execution time: 9_218_000 picoseconds. - Weight::from_parts(9_558_000, 0) - .saturating_add(Weight::from_parts(0, 8587)) + // Measured: `136` + // Estimated: `8551` + // Minimum execution time: 8_689_000 picoseconds. + Weight::from_parts(8_874_000, 0) + .saturating_add(Weight::from_parts(0, 8551)) .saturating_add(T::DbWeight::get().reads(3)) } /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `198` - // Estimated: `11088` - // Minimum execution time: 18_133_000 picoseconds. - Weight::from_parts(18_663_000, 0) - .saturating_add(Weight::from_parts(0, 11088)) + // Measured: `106` + // Estimated: `10996` + // Minimum execution time: 15_944_000 picoseconds. + Weight::from_parts(16_381_000, 0) + .saturating_add(Weight::from_parts(0, 10996)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `PolkadotXcm::VersionNotifyTargets` (r:4 w:2) /// Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) @@ -278,12 +327,12 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `204` - // Estimated: `11094` - // Minimum execution time: 38_878_000 picoseconds. - Weight::from_parts(39_779_000, 0) - .saturating_add(Weight::from_parts(0, 11094)) - .saturating_add(T::DbWeight::get().reads(9)) + // Measured: `112` + // Estimated: `11002` + // Minimum execution time: 33_826_000 picoseconds. + Weight::from_parts(34_784_000, 0) + .saturating_add(Weight::from_parts(0, 11002)) + .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) @@ -294,8 +343,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `1517` - // Minimum execution time: 4_142_000 picoseconds. - Weight::from_parts(4_308_000, 0) + // Minimum execution time: 4_257_000 picoseconds. + Weight::from_parts(4_383_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -306,11 +355,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7669` // Estimated: `11134` - // Minimum execution time: 25_814_000 picoseconds. - Weight::from_parts(26_213_000, 0) + // Minimum execution time: 26_924_000 picoseconds. + Weight::from_parts(27_455_000, 0) .saturating_add(Weight::from_parts(0, 11134)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } } - diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs index 842ddbe54f2..d6f8d32628e 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs @@ -969,6 +969,18 @@ impl_runtime_apis! { // Reserve transfers are disabled on Collectives. None } + + fn set_up_complex_asset_transfer( + ) -> Option<(MultiAssets, u32, MultiLocation, Box)> { + // Collectives only supports teleports to system parachain. + // Relay/native token can be teleported between Collectives and Relay. + let native_location = Parent.into(); + let dest = Parent.into(); + pallet_xcm::benchmarking::helpers::native_teleport_as_asset_transfer::( + native_location, + dest + ) + } } let whitelist: Vec = vec![ diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs index a3b42cb86c4..50dfbffde01 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_xcm.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-12-05, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-r43aesjn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -64,22 +64,37 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 25_746_000 picoseconds. - Weight::from_parts(26_349_000, 0) + // Minimum execution time: 24_540_000 picoseconds. + Weight::from_parts(25_439_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn teleport_assets() -> Weight { // Proof Size summary in bytes: - // Measured: `69` - // Estimated: `1489` - // Minimum execution time: 22_660_000 picoseconds. - Weight::from_parts(23_173_000, 0) - .saturating_add(Weight::from_parts(0, 1489)) - .saturating_add(T::DbWeight::get().reads(1)) + // Measured: `214` + // Estimated: `3679` + // Minimum execution time: 86_614_000 picoseconds. + Weight::from_parts(88_884_000, 0) + .saturating_add(Weight::from_parts(0, 3679)) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Benchmark::Override` (r:0 w:0) /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -91,6 +106,32 @@ impl pallet_xcm::WeightInfo for WeightInfo { Weight::from_parts(18_446_744_073_709_551_000, 0) .saturating_add(Weight::from_parts(0, 0)) } + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) + /// Proof: `ParachainSystem::UpwardDeliveryFeeFactor` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ParachainSystem::HostConfiguration` (r:1 w:0) + /// Proof: `ParachainSystem::HostConfiguration` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::PendingUpwardMessages` (r:1 w:1) + /// Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn transfer_assets() -> Weight { + // Proof Size summary in bytes: + // Measured: `214` + // Estimated: `3679` + // Minimum execution time: 87_915_000 picoseconds. + Weight::from_parts(90_219_000, 0) + .saturating_add(Weight::from_parts(0, 3679)) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(3)) + } /// Storage: `Benchmark::Override` (r:0 w:0) /// Proof: `Benchmark::Override` (`max_values`: None, `max_size`: None, mode: `Measured`) fn execute() -> Weight { @@ -107,8 +148,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_321_000 picoseconds. - Weight::from_parts(7_542_000, 0) + // Minimum execution time: 6_872_000 picoseconds. + Weight::from_parts(7_110_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -118,8 +159,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_232_000 picoseconds. - Weight::from_parts(2_395_000, 0) + // Minimum execution time: 2_009_000 picoseconds. + Weight::from_parts(2_163_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -145,8 +186,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 29_006_000 picoseconds. - Weight::from_parts(29_777_000, 0) + // Minimum execution time: 28_858_000 picoseconds. + Weight::from_parts(29_355_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(5)) @@ -171,8 +212,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `363` // Estimated: `3828` - // Minimum execution time: 31_245_000 picoseconds. - Weight::from_parts(32_125_000, 0) + // Minimum execution time: 30_598_000 picoseconds. + Weight::from_parts(31_168_000, 0) .saturating_add(Weight::from_parts(0, 3828)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) @@ -183,8 +224,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_255_000 picoseconds. - Weight::from_parts(2_399_000, 0) + // Minimum execution time: 2_090_000 picoseconds. + Weight::from_parts(2_253_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -194,8 +235,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `162` // Estimated: `11052` - // Minimum execution time: 16_521_000 picoseconds. - Weight::from_parts(17_001_000, 0) + // Minimum execution time: 16_133_000 picoseconds. + Weight::from_parts(16_433_000, 0) .saturating_add(Weight::from_parts(0, 11052)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -206,8 +247,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `166` // Estimated: `11056` - // Minimum execution time: 16_486_000 picoseconds. - Weight::from_parts(16_729_000, 0) + // Minimum execution time: 16_012_000 picoseconds. + Weight::from_parts(16_449_000, 0) .saturating_add(Weight::from_parts(0, 11056)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -218,8 +259,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `173` // Estimated: `13538` - // Minimum execution time: 18_037_000 picoseconds. - Weight::from_parts(18_310_000, 0) + // Minimum execution time: 17_922_000 picoseconds. + Weight::from_parts(18_426_000, 0) .saturating_add(Weight::from_parts(0, 13538)) .saturating_add(T::DbWeight::get().reads(5)) } @@ -241,8 +282,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `212` // Estimated: `6152` - // Minimum execution time: 27_901_000 picoseconds. - Weight::from_parts(28_566_000, 0) + // Minimum execution time: 27_280_000 picoseconds. + Weight::from_parts(28_026_000, 0) .saturating_add(Weight::from_parts(0, 6152)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) @@ -253,8 +294,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `206` // Estimated: `8621` - // Minimum execution time: 9_299_000 picoseconds. - Weight::from_parts(9_547_000, 0) + // Minimum execution time: 9_387_000 picoseconds. + Weight::from_parts(9_644_000, 0) .saturating_add(Weight::from_parts(0, 8621)) .saturating_add(T::DbWeight::get().reads(3)) } @@ -264,8 +305,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `173` // Estimated: `11063` - // Minimum execution time: 16_768_000 picoseconds. - Weight::from_parts(17_215_000, 0) + // Minimum execution time: 16_649_000 picoseconds. + Weight::from_parts(17_025_000, 0) .saturating_add(Weight::from_parts(0, 11063)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -288,8 +329,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `215` // Estimated: `11105` - // Minimum execution time: 35_134_000 picoseconds. - Weight::from_parts(35_883_000, 0) + // Minimum execution time: 34_355_000 picoseconds. + Weight::from_parts(35_295_000, 0) .saturating_add(Weight::from_parts(0, 11105)) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) @@ -302,8 +343,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `1588` - // Minimum execution time: 4_562_000 picoseconds. - Weight::from_parts(4_802_000, 0) + // Minimum execution time: 4_527_000 picoseconds. + Weight::from_parts(4_699_000, 0) .saturating_add(Weight::from_parts(0, 1588)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -314,8 +355,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7740` // Estimated: `11205` - // Minimum execution time: 26_865_000 picoseconds. - Weight::from_parts(27_400_000, 0) + // Minimum execution time: 27_011_000 picoseconds. + Weight::from_parts(27_398_000, 0) .saturating_add(Weight::from_parts(0, 11205)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index 81cc8558a2b..4ab3014cace 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -723,6 +723,18 @@ impl_runtime_apis! { // Reserve transfers are disabled on Contracts-System-Para. None } + + fn set_up_complex_asset_transfer( + ) -> Option<(MultiAssets, u32, MultiLocation, Box)> { + // Contracts-System-Para only supports teleports to system parachain. + // Relay/native token can be teleported between Contracts-System-Para and Relay. + let native_location = Parent.into(); + let dest = Parent.into(); + pallet_xcm::benchmarking::helpers::native_teleport_as_asset_transfer::( + native_location, + dest + ) + } } let whitelist: Vec = vec![ diff --git a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs index 74d9a0b071d..21f421f8285 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs @@ -94,12 +94,24 @@ pub type FungiblesTransactor = FungiblesAdapter< // Use this fungibles implementation: Assets, // Use this currency when it is a fungible asset matching the given location or name: - ConvertedConcreteId< - AssetIdPalletAssets, - Balance, - AsPrefixedGeneralIndex, - JustTry, - >, + ( + ConvertedConcreteId< + AssetIdPalletAssets, + Balance, + AsPrefixedGeneralIndex, + JustTry, + >, + ConvertedConcreteId< + AssetIdPalletAssets, + Balance, + AsPrefixedGeneralIndex< + SystemAssetHubAssetsPalletLocation, + AssetIdPalletAssets, + JustTry, + >, + JustTry, + >, + ), // Convert an XCM MultiLocation into a local account id: LocationToAccountId, // Our chain's account ID type (we can't get away without mentioning it explicitly): @@ -237,6 +249,8 @@ where } } +// This asset can be added to AH as ForeignAsset and teleported between Penpal and AH +pub const TELEPORTABLE_ASSET_ID: u32 = 2; parameter_types! { /// The location that this chain recognizes as the Relay network's Asset Hub. pub SystemAssetHubLocation: MultiLocation = MultiLocation::new(1, X1(Parachain(1000))); @@ -244,11 +258,30 @@ parameter_types! { // the Relay Chain's Asset Hub's Assets pallet index pub SystemAssetHubAssetsPalletLocation: MultiLocation = MultiLocation::new(1, X2(Parachain(1000), PalletInstance(50))); + pub AssetsPalletLocation: MultiLocation = + MultiLocation::new(0, X1(PalletInstance(50))); pub CheckingAccount: AccountId = PolkadotXcm::check_account(); + pub LocalTeleportableToAssetHub: MultiLocation = MultiLocation::new( + 0, + X2(PalletInstance(50), GeneralIndex(TELEPORTABLE_ASSET_ID.into())) + ); +} + +/// Accepts asset with ID `AssetLocation` and is coming from `Origin` chain. +pub struct AssetFromChain(PhantomData<(AssetLocation, Origin)>); +impl, Origin: Get> + ContainsPair for AssetFromChain +{ + fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool { + log::trace!(target: "xcm::contains", "AssetFromChain asset: {:?}, origin: {:?}", asset, origin); + *origin == Origin::get() && matches!(asset.id, Concrete(id) if id == AssetLocation::get()) + } } pub type Reserves = (NativeAsset, AssetsFrom, NativeAssetFrom); +pub type TrustedTeleporters = + (AssetFromChain,); pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { @@ -259,7 +292,7 @@ impl xcm_executor::Config for XcmConfig { type OriginConverter = XcmOriginToTransactDispatchOrigin; type IsReserve = Reserves; // no teleport trust established with other chains - type IsTeleporter = NativeAsset; + type IsTeleporter = TrustedTeleporters; type UniversalLocation = UniversalLocation; type Barrier = Barrier; type Weigher = FixedWeightBounds; diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 21d4088df19..26670cdcc23 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -2261,6 +2261,20 @@ sp_api::impl_runtime_apis! { Parachain(43211234).into(), )) } + + fn set_up_complex_asset_transfer( + ) -> Option<(MultiAssets, u32, MultiLocation, Box)> { + // Relay supports only native token, either reserve transfer it to non-system parachains, + // or teleport it to system parachain. Use the teleport case for benchmarking as it's + // slightly heavier. + // Relay/native token can be teleported to/from AH. + let native_location = Here.into(); + let dest = crate::xcm_config::AssetHub::get(); + pallet_xcm::benchmarking::helpers::native_teleport_as_asset_transfer::( + native_location, + dest + ) + } } impl pallet_xcm_benchmarks::Config for Runtime { type XcmConfig = XcmConfig; diff --git a/polkadot/runtime/rococo/src/weights/pallet_xcm.rs b/polkadot/runtime/rococo/src/weights/pallet_xcm.rs index aafded3f731..177407ef708 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_xcm.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_xcm.rs @@ -48,6 +48,10 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + fn transfer_assets() -> Weight { + // TODO: run benchmarks + Weight::zero() + } /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index afc2e5ea3da..04723ef0d9b 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -2295,6 +2295,21 @@ sp_api::impl_runtime_apis! { crate::Junction::Parachain(43211234).into(), )) } + + fn set_up_complex_asset_transfer( + ) -> Option<(MultiAssets, u32, MultiLocation, Box)> { + // Relay supports only native token, either reserve transfer it to non-system parachains, + // or teleport it to system parachain. Use the teleport case for benchmarking as it's + // slightly heavier. + + // Relay/native token can be teleported to/from AH. + let native_location = Here.into(); + let dest = crate::xcm_config::AssetHub::get(); + pallet_xcm::benchmarking::helpers::native_teleport_as_asset_transfer::( + native_location, + dest + ) + } } impl frame_system_benchmarking::Config for Runtime {} impl pallet_nomination_pools_benchmarking::Config for Runtime {} diff --git a/polkadot/runtime/westend/src/weights/pallet_xcm.rs b/polkadot/runtime/westend/src/weights/pallet_xcm.rs index cca4bdbd91e..493acd0f9e7 100644 --- a/polkadot/runtime/westend/src/weights/pallet_xcm.rs +++ b/polkadot/runtime/westend/src/weights/pallet_xcm.rs @@ -50,6 +50,10 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm`. pub struct WeightInfo(PhantomData); impl pallet_xcm::WeightInfo for WeightInfo { + fn transfer_assets() -> Weight { + // TODO: run benchmarks + Weight::zero() + } /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) diff --git a/polkadot/xcm/pallet-xcm/src/benchmarking.rs b/polkadot/xcm/pallet-xcm/src/benchmarking.rs index f0289512399..28a198f40a0 100644 --- a/polkadot/xcm/pallet-xcm/src/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm/src/benchmarking.rs @@ -44,7 +44,7 @@ pub trait Config: crate::Config { /// /// Implementation should also make sure `dest` is reachable/connected. /// - /// If `None`, the benchmarks that depend on this will be skipped. + /// If `None`, the benchmarks that depend on this will default to `Weight::MAX`. fn teleportable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { None } @@ -54,10 +54,27 @@ pub trait Config: crate::Config { /// /// Implementation should also make sure `dest` is reachable/connected. /// - /// If `None`, the benchmarks that depend on this will be skipped. + /// If `None`, the benchmarks that depend on this will default to `Weight::MAX`. fn reserve_transferable_asset_and_dest() -> Option<(MultiAsset, MultiLocation)> { None } + + /// Sets up a complex transfer (usually consisting of a teleport and reserve-based transfer), so + /// that runtime can properly benchmark `transfer_assets()` extrinsic. Should return a tuple + /// `(MultiAsset, u32, MultiLocation, dyn FnOnce())` representing the assets to transfer, the + /// `u32` index of the asset to be used for fees, the destination chain for the transfer, and a + /// `verify()` closure to verify the intended transfer side-effects. + /// + /// Implementation should make sure the provided assets can be transacted by the runtime, there + /// are enough balances in the involved accounts, and that `dest` is reachable/connected. + /// + /// Used only in benchmarks. + /// + /// If `None`, the benchmarks that depend on this will default to `Weight::MAX`. + fn set_up_complex_asset_transfer( + ) -> Option<(MultiAssets, u32, MultiLocation, Box)> { + None + } } benchmarks! { @@ -158,6 +175,23 @@ benchmarks! { assert!(pallet_balances::Pallet::::free_balance(&caller) <= balance - transferred_amount); } + transfer_assets { + let (assets, fee_index, destination, verify) = T::set_up_complex_asset_transfer().ok_or( + BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)), + )?; + let caller: T::AccountId = whitelisted_caller(); + let send_origin = RawOrigin::Signed(caller.clone()); + let recipient = [0u8; 32]; + let versioned_dest: VersionedMultiLocation = destination.into(); + let versioned_beneficiary: VersionedMultiLocation = + AccountId32 { network: None, id: recipient.into() }.into(); + let versioned_assets: VersionedMultiAssets = assets.into(); + }: _>(send_origin.into(), Box::new(versioned_dest), Box::new(versioned_beneficiary), Box::new(versioned_assets), 0, WeightLimit::Unlimited) + verify { + // run provided verification function + verify(); + } + execute { let execute_origin = T::ExecuteXcmOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; @@ -302,3 +336,36 @@ benchmarks! { crate::mock::Test ); } + +pub mod helpers { + use super::*; + pub fn native_teleport_as_asset_transfer( + native_asset_location: MultiLocation, + destination: MultiLocation, + ) -> Option<(MultiAssets, u32, MultiLocation, Box)> + where + T: Config + pallet_balances::Config, + u128: From<::Balance>, + { + // Relay/native token can be teleported to/from AH. + let amount = T::ExistentialDeposit::get() * 100u32.into(); + let assets: MultiAssets = + MultiAsset { fun: Fungible(amount.into()), id: Concrete(native_asset_location) }.into(); + let fee_index = 0u32; + + // Give some multiple of transferred amount + let balance = amount * 10u32.into(); + let who = whitelisted_caller(); + let _ = + as frame_support::traits::Currency<_>>::make_free_balance_be(&who, balance); + // verify initial balance + assert_eq!(pallet_balances::Pallet::::free_balance(&who), balance); + + // verify transferred successfully + let verify = Box::new(move || { + // verify balance after transfer, decreased by transferred amount (and delivery fees) + assert!(pallet_balances::Pallet::::free_balance(&who) <= balance - amount); + }); + Some((assets, fee_index, destination, verify)) + } +} diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 74a24b132da..ab4403f6caa 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -66,6 +66,7 @@ pub trait WeightInfo { fn send() -> Weight; fn teleport_assets() -> Weight; fn reserve_transfer_assets() -> Weight; + fn transfer_assets() -> Weight; fn execute() -> Weight; fn force_xcm_version() -> Weight; fn force_default_xcm_version() -> Weight; @@ -98,6 +99,10 @@ impl WeightInfo for TestWeightInfo { Weight::from_parts(100_000_000, 0) } + fn transfer_assets() -> Weight { + Weight::from_parts(100_000_000, 0) + } + fn execute() -> Weight { Weight::from_parts(100_000_000, 0) } @@ -905,8 +910,8 @@ pub mod pallet { /// from relay to parachain. /// - `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will /// generally be an `AccountId32` value. - /// - `assets`: The assets to be withdrawn. The first item should be the currency used to to - /// pay the fee on the `dest` side. May not be empty. + /// - `assets`: The assets to be withdrawn. This should include the assets used to pay the + /// fee on the `dest` chain. /// - `fee_asset_item`: The index into `assets` of the item which should be used to pay /// fees. #[pallet::call_index(1)] @@ -937,8 +942,19 @@ pub mod pallet { Self::do_teleport_assets(origin, dest, beneficiary, assets, fee_asset_item, Unlimited) } - /// Transfer some assets from the local chain to the sovereign account of a destination - /// chain and forward a notification XCM. + /// Transfer some assets from the local chain to the destination chain through their local, + /// destination or remote reserve. + /// + /// `assets` must have same reserve location and may not be teleportable to `dest`. + /// - `assets` have local reserve: transfer assets to sovereign account of destination + /// chain and forward a notification XCM to `dest` to mint and deposit reserve-based + /// assets to `beneficiary`. + /// - `assets` have destination reserve: burn local assets and forward a notification to + /// `dest` chain to withdraw the reserve assets from this chain's sovereign account and + /// deposit them to `beneficiary`. + /// - `assets` have remote reserve: burn local assets, forward XCM to reserve chain to move + /// reserves from this chain's SA to `dest` chain's SA, and forward another XCM to `dest` + /// to mint and deposit reserve-based assets to `beneficiary`. /// /// **This function is deprecated: Use `limited_reserve_transfer_assets` instead.** /// @@ -953,7 +969,7 @@ pub mod pallet { /// - `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will /// generally be an `AccountId32` value. /// - `assets`: The assets to be withdrawn. This should include the assets used to pay the - /// fee on the `dest` side. + /// fee on the `dest` (and possibly reserve) chains. /// - `fee_asset_item`: The index into `assets` of the item which should be used to pay /// fees. #[pallet::call_index(2)] @@ -1105,8 +1121,19 @@ pub mod pallet { }) } - /// Transfer some assets from the local chain to the sovereign account of a destination - /// chain and forward a notification XCM. + /// Transfer some assets from the local chain to the destination chain through their local, + /// destination or remote reserve. + /// + /// `assets` must have same reserve location and may not be teleportable to `dest`. + /// - `assets` have local reserve: transfer assets to sovereign account of destination + /// chain and forward a notification XCM to `dest` to mint and deposit reserve-based + /// assets to `beneficiary`. + /// - `assets` have destination reserve: burn local assets and forward a notification to + /// `dest` chain to withdraw the reserve assets from this chain's sovereign account and + /// deposit them to `beneficiary`. + /// - `assets` have remote reserve: burn local assets, forward XCM to reserve chain to move + /// reserves from this chain's SA to `dest` chain's SA, and forward another XCM to `dest` + /// to mint and deposit reserve-based assets to `beneficiary`. /// /// Fee payment on the destination side is made from the asset in the `assets` vector of /// index `fee_asset_item`, up to enough to pay for `weight_limit` of weight. If more weight @@ -1120,7 +1147,7 @@ pub mod pallet { /// - `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will /// generally be an `AccountId32` value. /// - `assets`: The assets to be withdrawn. This should include the assets used to pay the - /// fee on the `dest` side. + /// fee on the `dest` (and possibly reserve) chains. /// - `fee_asset_item`: The index into `assets` of the item which should be used to pay /// fees. /// - `weight_limit`: The remote-side weight limit, if any, for the XCM fee purchase. @@ -1173,8 +1200,8 @@ pub mod pallet { /// from relay to parachain. /// - `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will /// generally be an `AccountId32` value. - /// - `assets`: The assets to be withdrawn. The first item should be the currency used to to - /// pay the fee on the `dest` side. May not be empty. + /// - `assets`: The assets to be withdrawn. This should include the assets used to pay the + /// fee on the `dest` chain. /// - `fee_asset_item`: The index into `assets` of the item which should be used to pay /// fees. /// - `weight_limit`: The remote-side weight limit, if any, for the XCM fee purchase. @@ -1225,12 +1252,162 @@ pub mod pallet { XcmExecutionSuspended::::set(suspended); Ok(()) } + + /// Transfer some assets from the local chain to the destination chain through their local, + /// destination or remote reserve, or through teleports. + /// + /// Fee payment on the destination side is made from the asset in the `assets` vector of + /// index `fee_asset_item` (hence referred to as `fees`), up to enough to pay for + /// `weight_limit` of weight. If more weight is needed than `weight_limit`, then the + /// operation will fail and the assets sent may be at risk. + /// + /// `assets` (excluding `fees`) must have same reserve location or otherwise be teleportable + /// to `dest`, no limitations imposed on `fees`. + /// - for local reserve: transfer assets to sovereign account of destination chain and + /// forward a notification XCM to `dest` to mint and deposit reserve-based assets to + /// `beneficiary`. + /// - for destination reserve: burn local assets and forward a notification to `dest` chain + /// to withdraw the reserve assets from this chain's sovereign account and deposit them + /// to `beneficiary`. + /// - for remote reserve: burn local assets, forward XCM to reserve chain to move reserves + /// from this chain's SA to `dest` chain's SA, and forward another XCM to `dest` to mint + /// and deposit reserve-based assets to `beneficiary`. + /// - for teleports: burn local assets and forward XCM to `dest` chain to mint/teleport + /// assets and deposit them to `beneficiary`. + /// + /// - `origin`: Must be capable of withdrawing the `assets` and executing XCM. + /// - `dest`: Destination context for the assets. Will typically be `X2(Parent, + /// Parachain(..))` to send from parachain to parachain, or `X1(Parachain(..))` to send + /// from relay to parachain. + /// - `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will + /// generally be an `AccountId32` value. + /// - `assets`: The assets to be withdrawn. This should include the assets used to pay the + /// fee on the `dest` (and possibly reserve) chains. + /// - `fee_asset_item`: The index into `assets` of the item which should be used to pay + /// fees. + /// - `weight_limit`: The remote-side weight limit, if any, for the XCM fee purchase. + #[pallet::call_index(11)] + #[pallet::weight({ + let maybe_assets: Result = (*assets.clone()).try_into(); + let maybe_dest: Result = (*dest.clone()).try_into(); + match (maybe_assets, maybe_dest) { + (Ok(assets), Ok(dest)) => { + use sp_std::vec; + // heaviest version of locally executed XCM program: equivalent in weight to withdrawing fees, + // burning them, transferring rest of assets to SA, reanchoring them, extending XCM program, + // and sending onward XCM + let mut message = Xcm(vec![ + SetFeesMode { jit_withdraw: true }, + WithdrawAsset(assets.clone()), + BurnAsset(assets.clone()), + TransferReserveAsset { assets, dest, xcm: Xcm(vec![]) } + ]); + T::Weigher::weight(&mut message).map_or(Weight::MAX, |w| T::WeightInfo::transfer_assets().saturating_add(w)) + } + _ => Weight::MAX, + } + })] + pub fn transfer_assets( + origin: OriginFor, + dest: Box, + beneficiary: Box, + assets: Box, + fee_asset_item: u32, + weight_limit: WeightLimit, + ) -> DispatchResult { + let origin = T::ExecuteXcmOrigin::ensure_origin(origin)?; + let dest = (*dest).try_into().map_err(|()| Error::::BadVersion)?; + let beneficiary: MultiLocation = + (*beneficiary).try_into().map_err(|()| Error::::BadVersion)?; + let assets: MultiAssets = (*assets).try_into().map_err(|()| Error::::BadVersion)?; + log::debug!( + target: "xcm::pallet_xcm::transfer_assets", + "origin {:?}, dest {:?}, beneficiary {:?}, assets {:?}, fee-idx {:?}, weight_limit {:?}", + origin, dest, beneficiary, assets, fee_asset_item, weight_limit, + ); + + ensure!(assets.len() <= MAX_ASSETS_FOR_TRANSFER, Error::::TooManyAssets); + let mut assets = assets.into_inner(); + let fee_asset_item = fee_asset_item as usize; + let fees = assets.get(fee_asset_item as usize).ok_or(Error::::Empty)?.clone(); + // Find transfer types for fee and non-fee assets. + let (fees_transfer_type, assets_transfer_type) = + Self::find_fee_and_assets_transfer_types(&assets, fee_asset_item, &dest)?; + + // local and remote XCM programs to potentially handle fees separately + let fees = if fees_transfer_type == assets_transfer_type { + // no need for custom fees instructions, fees are batched with assets + FeesHandling::Batched { fees } + } else { + // Disallow _remote reserves_ unless assets & fees have same remote reserve (covered + // by branch above). The reason for this is that we'd need to send XCMs to separate + // chains with no guarantee of delivery order on final destination; therefore we + // cannot guarantee to have fees in place on final destination chain to pay for + // assets transfer. + ensure!( + !matches!(assets_transfer_type, TransferType::RemoteReserve(_)), + Error::::InvalidAssetUnsupportedReserve + ); + let weight_limit = weight_limit.clone(); + // remove `fees` from `assets` and build separate fees transfer instructions to be + // added to assets transfers XCM programs + let fees = assets.remove(fee_asset_item); + let (local_xcm, remote_xcm) = match fees_transfer_type { + TransferType::LocalReserve => + Self::local_reserve_fees_instructions(origin, dest, fees, weight_limit)?, + TransferType::DestinationReserve => + Self::destination_reserve_fees_instructions( + origin, + dest, + fees, + weight_limit, + )?, + TransferType::Teleport => + Self::teleport_fees_instructions(origin, dest, fees, weight_limit)?, + TransferType::RemoteReserve(_) => + return Err(Error::::InvalidAssetUnsupportedReserve.into()), + }; + FeesHandling::Separate { local_xcm, remote_xcm } + }; + + Self::build_and_execute_xcm_transfer_type( + origin, + dest, + beneficiary, + assets, + assets_transfer_type, + fees, + weight_limit, + ) + } } } /// The maximum number of distinct assets allowed to be transferred in a single helper extrinsic. const MAX_ASSETS_FOR_TRANSFER: usize = 2; +/// Specify how assets used for fees are handled during asset transfers. +#[derive(Clone, PartialEq)] +enum FeesHandling { + /// `fees` asset can be batch-transferred with rest of assets using same XCM instructions. + Batched { fees: MultiAsset }, + /// fees cannot be batched, they are handled separately using XCM programs here. + Separate { local_xcm: Xcm<::RuntimeCall>, remote_xcm: Xcm<()> }, +} + +impl sp_std::fmt::Debug for FeesHandling { + fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { + match self { + Self::Batched { fees } => write!(f, "FeesHandling::Batched({:?})", fees), + Self::Separate { local_xcm, remote_xcm } => write!( + f, + "FeesHandling::Separate(local: {:?}, remote: {:?})", + local_xcm, remote_xcm + ), + } + } +} + impl QueryHandler for Pallet { type QueryId = u64; type BlockNumber = BlockNumberFor; @@ -1292,31 +1469,45 @@ impl QueryHandler for Pallet { } impl Pallet { - /// Validate `assets` to be reserve-transferred and return their reserve location. - fn validate_assets_and_find_reserve( + /// Find `TransferType`s for `assets` and fee identified through `fee_asset_item`, when + /// transferring to `dest`. + /// + /// Validate `assets` to all have same `TransferType`. + fn find_fee_and_assets_transfer_types( assets: &[MultiAsset], + fee_asset_item: usize, dest: &MultiLocation, - ) -> Result> { - let mut reserve = None; - for asset in assets.iter() { + ) -> Result<(TransferType, TransferType), Error> { + let mut fees_transfer_type = None; + let mut assets_transfer_type = None; + for (idx, asset) in assets.iter().enumerate() { if let Fungible(x) = asset.fun { // If fungible asset, ensure non-zero amount. ensure!(!x.is_zero(), Error::::Empty); } let transfer_type = T::XcmExecutor::determine_for(&asset, dest).map_err(Error::::from)?; - // Ensure asset is not teleportable to `dest`. - ensure!(transfer_type != TransferType::Teleport, Error::::Filtered); - if let Some(reserve) = reserve.as_ref() { - // Ensure transfer for multiple assets uses same reserve location (only fee may have - // different reserve location) - ensure!(reserve == &transfer_type, Error::::TooManyReserves); + if idx == fee_asset_item { + fees_transfer_type = Some(transfer_type); } else { - // asset reserve identified - reserve = Some(transfer_type); + if let Some(existing) = assets_transfer_type.as_ref() { + // Ensure transfer for multiple assets uses same transfer type (only fee may + // have different transfer type/path) + ensure!(existing == &transfer_type, Error::::TooManyReserves); + } else { + // asset reserve identified + assets_transfer_type = Some(transfer_type); + } } } - reserve.ok_or(Error::::Empty) + // single asset also marked as fee item + if assets.len() == 1 { + assets_transfer_type = fees_transfer_type + } + Ok(( + fees_transfer_type.ok_or(Error::::Empty)?, + assets_transfer_type.ok_or(Error::::Empty)?, + )) } fn do_reserve_transfer_assets( @@ -1332,7 +1523,7 @@ impl Pallet { let beneficiary: MultiLocation = (*beneficiary).try_into().map_err(|()| Error::::BadVersion)?; let assets: MultiAssets = (*assets).try_into().map_err(|()| Error::::BadVersion)?; - log::trace!( + log::debug!( target: "xcm::pallet_xcm::do_reserve_transfer_assets", "origin {:?}, dest {:?}, beneficiary {:?}, assets {:?}, fee-idx {:?}", origin_location, dest, beneficiary, assets, fee_asset_item, @@ -1341,64 +1532,26 @@ impl Pallet { ensure!(assets.len() <= MAX_ASSETS_FOR_TRANSFER, Error::::TooManyAssets); let value = (origin_location, assets.into_inner()); ensure!(T::XcmReserveTransferFilter::contains(&value), Error::::Filtered); - let (origin_location, mut assets) = value; + let (origin, assets) = value; - if fee_asset_item as usize >= assets.len() { - return Err(Error::::Empty.into()) - } - let fees = assets.swap_remove(fee_asset_item as usize); - let fees_transfer_type = - T::XcmExecutor::determine_for(&fees, &dest).map_err(Error::::from)?; - let assets_transfer_type = if assets.is_empty() { - // Single asset to transfer (one used for fees where transfer type is determined above). - ensure!(fees_transfer_type != TransferType::Teleport, Error::::Filtered); - fees_transfer_type - } else { - // Find reserve for non-fee assets. - Self::validate_assets_and_find_reserve(&assets, &dest)? - }; + let fee_asset_item = fee_asset_item as usize; + let fees = assets.get(fee_asset_item as usize).ok_or(Error::::Empty)?.clone(); - // local and remote XCM programs to potentially handle fees separately - let separate_fees_instructions: Option<(Xcm<::RuntimeCall>, Xcm<()>)>; - if fees_transfer_type == assets_transfer_type { - // Same reserve location (fees not teleportable), we can batch together fees and assets - // in same reserve-based-transfer. - assets.push(fees.clone()); - // no need for custom fees instructions, fees are batched with assets - separate_fees_instructions = None; - } else { - // Disallow _remote reserves_ unless assets & fees have same remote reserve (covered by - // branch above). The reason for this is that we'd need to send XCMs to separate chains - // with no guarantee of delivery order on final destination; therefore we cannot - // guarantee to have fees in place on final destination chain to pay for assets - // transfer. - ensure!( - !matches!(assets_transfer_type, TransferType::RemoteReserve(_)), - Error::::InvalidAssetUnsupportedReserve - ); - let fees = fees.clone(); - let weight_limit = weight_limit.clone(); - // build fees transfer instructions to be added to assets transfers XCM programs - separate_fees_instructions = Some(match fees_transfer_type { - TransferType::LocalReserve => - Self::local_reserve_fees_instructions(dest, fees, weight_limit)?, - TransferType::DestinationReserve => - Self::destination_reserve_fees_instructions(dest, fees, weight_limit)?, - TransferType::Teleport => - Self::teleport_fees_instructions(origin_location, dest, fees, weight_limit)?, - TransferType::RemoteReserve(_) => - return Err(Error::::InvalidAssetUnsupportedReserve.into()), - }); - }; + // Find transfer types for fee and non-fee assets. + let (fees_transfer_type, assets_transfer_type) = + Self::find_fee_and_assets_transfer_types(&assets, fee_asset_item, &dest)?; + // Ensure assets (and fees according to check below) are not teleportable to `dest`. + ensure!(assets_transfer_type != TransferType::Teleport, Error::::Filtered); + // Ensure all assets (including fees) have same reserve location. + ensure!(assets_transfer_type == fees_transfer_type, Error::::TooManyReserves); Self::build_and_execute_xcm_transfer_type( - origin_location, + origin, dest, beneficiary, assets, assets_transfer_type, - fees, - separate_fees_instructions, + FeesHandling::Batched { fees }, weight_limit, ) } @@ -1416,6 +1569,11 @@ impl Pallet { let beneficiary: MultiLocation = (*beneficiary).try_into().map_err(|()| Error::::BadVersion)?; let assets: MultiAssets = (*assets).try_into().map_err(|()| Error::::BadVersion)?; + log::debug!( + target: "xcm::pallet_xcm::do_teleport_assets", + "origin {:?}, dest {:?}, beneficiary {:?}, assets {:?}, fee-idx {:?}, weight_limit {:?}", + origin_location, dest, beneficiary, assets, fee_asset_item, weight_limit, + ); ensure!(assets.len() <= MAX_ASSETS_FOR_TRANSFER, Error::::TooManyAssets); let value = (origin_location, assets.into_inner()); @@ -1424,7 +1582,7 @@ impl Pallet { for asset in assets.iter() { let transfer_type = T::XcmExecutor::determine_for(asset, &dest).map_err(Error::::from)?; - ensure!(matches!(transfer_type, TransferType::Teleport), Error::::Filtered); + ensure!(transfer_type == TransferType::Teleport, Error::::Filtered); } let fees = assets.get(fee_asset_item as usize).ok_or(Error::::Empty)?.clone(); @@ -1434,8 +1592,7 @@ impl Pallet { beneficiary, assets, TransferType::Teleport, - fees, - None, + FeesHandling::Batched { fees }, weight_limit, ) } @@ -1446,54 +1603,65 @@ impl Pallet { beneficiary: MultiLocation, assets: Vec, transfer_type: TransferType, - fees: MultiAsset, - separate_fees_instructions: Option<(Xcm<::RuntimeCall>, Xcm<()>)>, + fees: FeesHandling, weight_limit: WeightLimit, ) -> DispatchResult { - log::trace!( + log::debug!( target: "xcm::pallet_xcm::build_and_execute_xcm_transfer_type", "origin {:?}, dest {:?}, beneficiary {:?}, assets {:?}, transfer_type {:?}, \ - fees {:?}, fees_xcm: {:?}, weight_limit: {:?}", - origin, dest, beneficiary, assets, transfer_type, fees, separate_fees_instructions, weight_limit, + fees_handling {:?}, weight_limit: {:?}", + origin, dest, beneficiary, assets, transfer_type, fees, weight_limit, ); let (mut local_xcm, remote_xcm) = match transfer_type { TransferType::LocalReserve => { let (local, remote) = Self::local_reserve_transfer_programs( + origin, dest, beneficiary, assets, fees, - separate_fees_instructions, weight_limit, )?; (local, Some(remote)) }, TransferType::DestinationReserve => { let (local, remote) = Self::destination_reserve_transfer_programs( + origin, dest, beneficiary, assets, fees, - separate_fees_instructions, weight_limit, )?; (local, Some(remote)) }, - TransferType::RemoteReserve(reserve) => ( - Self::remote_reserve_transfer_program( + TransferType::RemoteReserve(reserve) => { + let fees = match fees { + FeesHandling::Batched { fees } => fees, + _ => return Err(Error::::InvalidAssetUnsupportedReserve.into()), + }; + let local = Self::remote_reserve_transfer_program( + origin, reserve, dest, beneficiary, assets, fees, weight_limit, - )?, - None, - ), - TransferType::Teleport => ( - Self::teleport_assets_program(dest, beneficiary, assets, fees, weight_limit)?, - None, - ), + )?; + (local, None) + }, + TransferType::Teleport => { + let (local, remote) = Self::teleport_assets_program( + origin, + dest, + beneficiary, + assets, + fees, + weight_limit, + )?; + (local, Some(remote)) + }, }; let weight = T::Weigher::weight(&mut local_xcm).map_err(|()| Error::::UnweighableMessage)?; @@ -1529,11 +1697,45 @@ impl Pallet { Ok(()) } + fn add_fees_to_xcm( + dest: MultiLocation, + fees: FeesHandling, + weight_limit: WeightLimit, + local: &mut Xcm<::RuntimeCall>, + remote: &mut Xcm<()>, + ) -> Result<(), Error> { + match fees { + FeesHandling::Batched { fees } => { + let context = T::UniversalLocation::get(); + // no custom fees instructions, they are batched together with `assets` transfer; + // BuyExecution happens after receiving all `assets` + let reanchored_fees = + fees.reanchored(&dest, context).map_err(|_| Error::::CannotReanchor)?; + // buy execution using `fees` batched together with above `reanchored_assets` + remote.inner_mut().push(BuyExecution { fees: reanchored_fees, weight_limit }); + }, + FeesHandling::Separate { local_xcm: mut local_fees, remote_xcm: mut remote_fees } => { + // fees are handled by separate XCM instructions, prepend fees instructions (for + // remote XCM they have to be prepended instead of appended to pass barriers). + sp_std::mem::swap(local, &mut local_fees); + sp_std::mem::swap(remote, &mut remote_fees); + // these are now swapped so fees actually go first + local.inner_mut().append(&mut local_fees.into_inner()); + remote.inner_mut().append(&mut remote_fees.into_inner()); + }, + } + Ok(()) + } + fn local_reserve_fees_instructions( + origin: MultiLocation, dest: MultiLocation, fees: MultiAsset, weight_limit: WeightLimit, ) -> Result<(Xcm<::RuntimeCall>, Xcm<()>), Error> { + let value = (origin, vec![fees.clone()]); + ensure!(T::XcmReserveTransferFilter::contains(&value), Error::::Filtered); + let context = T::UniversalLocation::get(); let reanchored_fees = fees .clone() @@ -1554,16 +1756,20 @@ impl Pallet { } fn local_reserve_transfer_programs( + origin: MultiLocation, dest: MultiLocation, beneficiary: MultiLocation, assets: Vec, - fees: MultiAsset, - separate_fees_instructions: Option<(Xcm<::RuntimeCall>, Xcm<()>)>, + fees: FeesHandling, weight_limit: WeightLimit, ) -> Result<(Xcm<::RuntimeCall>, Xcm<()>), Error> { + let value = (origin, assets); + ensure!(T::XcmReserveTransferFilter::contains(&value), Error::::Filtered); + let (_, assets) = value; + // max assets is `assets` (+ potentially separately handled fee) let max_assets = - assets.len() as u32 + separate_fees_instructions.as_ref().map(|_| 1).unwrap_or(0); + assets.len() as u32 + if matches!(&fees, FeesHandling::Batched { .. }) { 0 } else { 1 }; let assets: MultiAssets = assets.into(); let context = T::UniversalLocation::get(); let mut reanchored_assets = assets.clone(); @@ -1571,45 +1777,37 @@ impl Pallet { .reanchor(&dest, context) .map_err(|_| Error::::CannotReanchor)?; - // fees are either handled through dedicated instructions, or batched together with assets - let fees_already_handled = separate_fees_instructions.is_some(); - let (fees_local_xcm, fees_remote_xcm) = separate_fees_instructions - .map(|(local, remote)| (local.into_inner(), remote.into_inner())) - .unwrap_or_default(); - - // start off with any necessary local fees specific instructions - let mut local_execute_xcm = fees_local_xcm; - // move `assets` to `dest`s local sovereign account - local_execute_xcm.push(TransferAsset { assets, beneficiary: dest }); - - // on destination chain, start off with custom fee instructions - let mut xcm_on_dest = fees_remote_xcm; - // continue with rest of assets - xcm_on_dest.extend_from_slice(&[ + // XCM instructions to be executed on local chain + let mut local_execute_xcm = Xcm(vec![ + // locally move `assets` to `dest`s local sovereign account + TransferAsset { assets, beneficiary: dest }, + ]); + // XCM instructions to be executed on destination chain + let mut xcm_on_dest = Xcm(vec![ // let (dest) chain know assets are in its SA on reserve ReserveAssetDeposited(reanchored_assets), // following instructions are not exec'ed on behalf of origin chain anymore ClearOrigin, ]); - if !fees_already_handled { - // no custom fees instructions, they are batched together with `assets` transfer; - // BuyExecution happens after receiving all `assets` - let reanchored_fees = - fees.reanchored(&dest, context).map_err(|_| Error::::CannotReanchor)?; - // buy execution using `fees` batched together with above `reanchored_assets` - xcm_on_dest.push(BuyExecution { fees: reanchored_fees, weight_limit }); - } + // handle fees + Self::add_fees_to_xcm(dest, fees, weight_limit, &mut local_execute_xcm, &mut xcm_on_dest)?; // deposit all remaining assets in holding to `beneficiary` location - xcm_on_dest.push(DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }); + xcm_on_dest + .inner_mut() + .push(DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }); - Ok((Xcm(local_execute_xcm), Xcm(xcm_on_dest))) + Ok((local_execute_xcm, xcm_on_dest)) } fn destination_reserve_fees_instructions( + origin: MultiLocation, dest: MultiLocation, fees: MultiAsset, weight_limit: WeightLimit, ) -> Result<(Xcm<::RuntimeCall>, Xcm<()>), Error> { + let value = (origin, vec![fees.clone()]); + ensure!(T::XcmReserveTransferFilter::contains(&value), Error::::Filtered); + let context = T::UniversalLocation::get(); let reanchored_fees = fees .clone() @@ -1633,16 +1831,20 @@ impl Pallet { } fn destination_reserve_transfer_programs( + origin: MultiLocation, dest: MultiLocation, beneficiary: MultiLocation, assets: Vec, - fees: MultiAsset, - separate_fees_instructions: Option<(Xcm<::RuntimeCall>, Xcm<()>)>, + fees: FeesHandling, weight_limit: WeightLimit, ) -> Result<(Xcm<::RuntimeCall>, Xcm<()>), Error> { + let value = (origin, assets); + ensure!(T::XcmReserveTransferFilter::contains(&value), Error::::Filtered); + let (_, assets) = value; + // max assets is `assets` (+ potentially separately handled fee) let max_assets = - assets.len() as u32 + separate_fees_instructions.as_ref().map(|_| 1).unwrap_or(0); + assets.len() as u32 + if matches!(&fees, FeesHandling::Batched { .. }) { 0 } else { 1 }; let assets: MultiAssets = assets.into(); let context = T::UniversalLocation::get(); let mut reanchored_assets = assets.clone(); @@ -1650,47 +1852,33 @@ impl Pallet { .reanchor(&dest, context) .map_err(|_| Error::::CannotReanchor)?; - // fees are either handled through dedicated instructions, or batched together with assets - let fees_already_handled = separate_fees_instructions.is_some(); - let (fees_local_xcm, fees_remote_xcm) = separate_fees_instructions - .map(|(local, remote)| (local.into_inner(), remote.into_inner())) - .unwrap_or_default(); - - // start off with any necessary local fees specific instructions - let mut local_execute_xcm = fees_local_xcm; - // continue with rest of assets - local_execute_xcm.extend_from_slice(&[ + // XCM instructions to be executed on local chain + let mut local_execute_xcm = Xcm(vec![ // withdraw reserve-based assets WithdrawAsset(assets.clone()), // burn reserve-based assets BurnAsset(assets), ]); - - // on destination chain, start off with custom fee instructions - let mut xcm_on_dest = fees_remote_xcm; - // continue with rest of assets - xcm_on_dest.extend_from_slice(&[ + // XCM instructions to be executed on destination chain + let mut xcm_on_dest = Xcm(vec![ // withdraw `assets` from origin chain's sovereign account WithdrawAsset(reanchored_assets), // following instructions are not exec'ed on behalf of origin chain anymore ClearOrigin, ]); - if !fees_already_handled { - // no custom fees instructions, they are batched together with `assets` transfer; - // BuyExecution happens after receiving all `assets` - let reanchored_fees = - fees.reanchored(&dest, context).map_err(|_| Error::::CannotReanchor)?; - // buy execution using `fees` batched together with above `reanchored_assets` - xcm_on_dest.push(BuyExecution { fees: reanchored_fees, weight_limit }); - } + // handle fees + Self::add_fees_to_xcm(dest, fees, weight_limit, &mut local_execute_xcm, &mut xcm_on_dest)?; // deposit all remaining assets in holding to `beneficiary` location - xcm_on_dest.push(DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }); + xcm_on_dest + .inner_mut() + .push(DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }); - Ok((Xcm(local_execute_xcm), Xcm(xcm_on_dest))) + Ok((local_execute_xcm, xcm_on_dest)) } // function assumes fees and assets have the same remote reserve fn remote_reserve_transfer_program( + origin: MultiLocation, reserve: MultiLocation, dest: MultiLocation, beneficiary: MultiLocation, @@ -1698,6 +1886,10 @@ impl Pallet { fees: MultiAsset, weight_limit: WeightLimit, ) -> Result::RuntimeCall>, Error> { + let value = (origin, assets); + ensure!(T::XcmReserveTransferFilter::contains(&value), Error::::Filtered); + let (_, assets) = value; + let max_assets = assets.len() as u32; let context = T::UniversalLocation::get(); // we spend up to half of fees for execution on reserve and other half for execution on @@ -1760,6 +1952,8 @@ impl Pallet { &dummy_context, ) .map_err(|_| Error::::CannotCheckOutTeleport)?; + // safe to do this here, we're in a transactional call that will be reverted on any + // errors down the line ::AssetTransactor::check_out( &dest, &fees, @@ -1783,24 +1977,74 @@ impl Pallet { } fn teleport_assets_program( + origin: MultiLocation, dest: MultiLocation, beneficiary: MultiLocation, assets: Vec, - mut fees: MultiAsset, + fees: FeesHandling, weight_limit: WeightLimit, - ) -> Result::RuntimeCall>, Error> { + ) -> Result<(Xcm<::RuntimeCall>, Xcm<()>), Error> { + let value = (origin, assets); + ensure!(T::XcmTeleportFilter::contains(&value), Error::::Filtered); + let (_, assets) = value; + + // max assets is `assets` (+ potentially separately handled fee) + let max_assets = + assets.len() as u32 + if matches!(&fees, FeesHandling::Batched { .. }) { 0 } else { 1 }; let context = T::UniversalLocation::get(); - fees.reanchor(&dest, context).map_err(|_| Error::::CannotReanchor)?; - let max_assets = assets.len() as u32; - let xcm_on_dest = Xcm(vec![ - BuyExecution { fees, weight_limit }, - DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }, + let assets: MultiAssets = assets.into(); + let mut reanchored_assets = assets.clone(); + reanchored_assets + .reanchor(&dest, context) + .map_err(|_| Error::::CannotReanchor)?; + + // XcmContext irrelevant in teleports checks + let dummy_context = + XcmContext { origin: None, message_id: Default::default(), topic: None }; + for asset in assets.inner() { + // We should check that the asset can actually be teleported out (for this to + // be in error, there would need to be an accounting violation by ourselves, + // so it's unlikely, but we don't want to allow that kind of bug to leak into + // a trusted chain. + ::AssetTransactor::can_check_out( + &dest, + asset, + &dummy_context, + ) + .map_err(|_| Error::::CannotCheckOutTeleport)?; + } + for asset in assets.inner() { + // safe to do this here, we're in a transactional call that will be reverted on any + // errors down the line + ::AssetTransactor::check_out( + &dest, + asset, + &dummy_context, + ); + } + + // XCM instructions to be executed on local chain + let mut local_execute_xcm = Xcm(vec![ + // withdraw assets to be teleported + WithdrawAsset(assets.clone()), + // burn assets on local chain + BurnAsset(assets), ]); - Ok(Xcm(vec![ - WithdrawAsset(assets.into()), - SetFeesMode { jit_withdraw: true }, - InitiateTeleport { assets: Wild(AllCounted(max_assets)), dest, xcm: xcm_on_dest }, - ])) + // XCM instructions to be executed on destination chain + let mut xcm_on_dest = Xcm(vec![ + // teleport `assets` in from origin chain + ReceiveTeleportedAsset(reanchored_assets), + // following instructions are not exec'ed on behalf of origin chain anymore + ClearOrigin, + ]); + // handle fees + Self::add_fees_to_xcm(dest, fees, weight_limit, &mut local_execute_xcm, &mut xcm_on_dest)?; + // deposit all remaining assets in holding to `beneficiary` location + xcm_on_dest + .inner_mut() + .push(DepositAsset { assets: Wild(AllCounted(max_assets)), beneficiary }); + + Ok((local_execute_xcm, xcm_on_dest)) } /// Halve `fees` fungible amount. diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index 606d51bb8bc..9a734d0f276 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -579,6 +579,51 @@ impl super::benchmarking::Config for Test { Parachain(OTHER_PARA_ID).into(), )) } + + fn set_up_complex_asset_transfer( + ) -> Option<(MultiAssets, u32, MultiLocation, Box)> { + use crate::tests::assets_transfer::{into_multiassets_checked, set_up_foreign_asset}; + // Transfer native asset (local reserve) to `USDT_PARA_ID`. Using teleport-trusted USDT for + // fees. + + let asset_amount = 10u128; + let fee_amount = 2u128; + + // create sufficient foreign asset USDT + let usdt_initial_local_amount = fee_amount * 10; + let (usdt_chain, _, usdt_id_multilocation) = + set_up_foreign_asset(USDT_PARA_ID, None, usdt_initial_local_amount, true); + + // native assets transfer destination is USDT chain (teleport trust only for USDT) + let dest = usdt_chain; + let (assets, fee_index, _, _) = into_multiassets_checked( + // USDT for fees (is sufficient on local chain too) - teleported + (usdt_id_multilocation, fee_amount).into(), + // native asset to transfer (not used for fees) - local reserve + (MultiLocation::here(), asset_amount).into(), + ); + + let existential_deposit = ExistentialDeposit::get(); + let caller = frame_benchmarking::whitelisted_caller(); + // Give some multiple of the existential deposit + let balance = asset_amount + existential_deposit * 1000; + let _ = >::make_free_balance_be( + &caller, balance, + ); + // verify initial balance + assert_eq!(Balances::free_balance(&caller), balance); + + // verify transferred successfully + let verify = Box::new(move || { + // verify balance after transfer, decreased by transferred amount + assert_eq!(Balances::free_balance(&caller), balance - asset_amount); + assert_eq!( + Assets::balance(usdt_id_multilocation, &caller), + usdt_initial_local_amount - fee_amount + ); + }); + Some((assets, fee_index as u32, dest, verify)) + } } pub(crate) fn last_event() -> RuntimeEvent { diff --git a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs index d1b298765e2..fb0bef26ebd 100644 --- a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs @@ -19,6 +19,7 @@ use crate::{ mock::*, tests::{ALICE, BOB, FEE_AMOUNT, INITIAL_BALANCE, SEND_AMOUNT}, + DispatchResult, OriginFor, }; use frame_support::{ assert_ok, @@ -32,6 +33,7 @@ use xcm_executor::traits::ConvertLocation; // Helper function to deduplicate testing different teleport types. fn do_test_and_verify_teleport_assets( + origin_location: MultiLocation, expected_beneficiary: MultiLocation, call: Call, expected_weight_limit: WeightLimit, @@ -40,8 +42,9 @@ fn do_test_and_verify_teleport_assets( (ALICE, INITIAL_BALANCE), (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), ]; + let dest = RelayLocation::get().into(); new_test_ext_with_balances(balances).execute_with(|| { - let weight = BaseXcmWeight::get() * 3; + let weight = BaseXcmWeight::get() * 2; assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE); // call extrinsic call(); @@ -49,7 +52,7 @@ fn do_test_and_verify_teleport_assets( assert_eq!( sent_xcm(), vec![( - RelayLocation::get().into(), + dest, Xcm(vec![ ReceiveTeleportedAsset((Here, SEND_AMOUNT).into()), ClearOrigin, @@ -63,10 +66,23 @@ fn do_test_and_verify_teleport_assets( ); let versioned_sent = VersionedXcm::from(sent_xcm().into_iter().next().unwrap().1); let _check_v2_ok: xcm::v2::Xcm<()> = versioned_sent.try_into().unwrap(); + + let mut last_events = last_events(3).into_iter(); assert_eq!( - last_event(), + last_events.next().unwrap(), RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) ); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::FeesPaid { + paying: origin_location, + fees: MultiAssets::new(), + }) + ); + assert!(matches!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Sent { .. }) + )); }); } @@ -76,8 +92,10 @@ fn do_test_and_verify_teleport_assets( /// local effects. #[test] fn teleport_assets_works() { + let origin_location: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); let beneficiary: MultiLocation = AccountId32 { network: None, id: BOB.into() }.into(); do_test_and_verify_teleport_assets( + origin_location, beneficiary, || { assert_ok!(XcmPallet::teleport_assets( @@ -98,10 +116,12 @@ fn teleport_assets_works() { /// local effects. #[test] fn limited_teleport_assets_works() { + let origin_location: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); let beneficiary: MultiLocation = AccountId32 { network: None, id: BOB.into() }.into(); let weight_limit = WeightLimit::Limited(Weight::from_parts(5000, 5000)); let expected_weight_limit = weight_limit.clone(); do_test_and_verify_teleport_assets( + origin_location, beneficiary, || { assert_ok!(XcmPallet::limited_teleport_assets( @@ -160,7 +180,7 @@ fn reserve_transfer_assets_with_paid_router_works() { let xcm_router_fee_amount = Para3000PaymentAmount::get(); let weight = BaseXcmWeight::get(); let dest: MultiLocation = - Junction::AccountId32 { network: None, id: user_account.clone().into() }.into(); + AccountId32 { network: None, id: user_account.clone().into() }.into(); assert_eq!(Balances::total_balance(&user_account), INITIAL_BALANCE); assert_ok!(XcmPallet::reserve_transfer_assets( RuntimeOrigin::signed(user_account.clone()), @@ -221,7 +241,7 @@ fn reserve_transfer_assets_with_paid_router_works() { }); } -fn set_up_foreign_asset( +pub(crate) fn set_up_foreign_asset( reserve_para_id: u32, inner_junction: Option, initial_amount: u128, @@ -238,7 +258,7 @@ fn set_up_foreign_asset( reserve_location }; - // create sufficient (to be used as fees as well) foreign asset (0 total issuance) + // create sufficient (to be used as fees as well) foreign asset assert_ok!(Assets::force_create( RuntimeOrigin::root(), foreign_asset_id_multilocation, @@ -260,7 +280,7 @@ fn set_up_foreign_asset( // Helper function that provides correct `fee_index` after `sort()` done by // `vec![MultiAsset, MultiAsset].into()`. -fn into_multiassets_checked( +pub(crate) fn into_multiassets_checked( fee_asset: MultiAsset, transfer_asset: MultiAsset, ) -> (MultiAssets, usize, MultiAsset, MultiAsset) { @@ -269,29 +289,31 @@ fn into_multiassets_checked( (assets, fee_index, fee_asset, transfer_asset) } -/// Test `limited_reserve_transfer_assets` with local asset reserve and local fee reserve. +/// Test `tested_call` with local asset reserve and local fee reserve. /// /// Transferring native asset (local reserve) to some `OTHER_PARA_ID` (no teleport trust). /// Using native asset for fees as well. /// -/// ```nocompile -/// Here (source) OTHER_PARA_ID (destination) -/// | `assets` reserve -/// | `fees` reserve -/// | -/// | 1. execute `TransferReserveAsset(assets_and_fees_batched_together)` -/// | \--> sends `ReserveAssetDeposited(both), ClearOrigin, BuyExecution(fees), DepositAsset` -/// \------------------------------------------> -/// ``` -#[test] -fn limited_reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserve_works() { +/// Verifies `expected_result` +fn local_asset_reserve_and_local_fee_reserve_call( + tested_call: Call, + expected_result: DispatchResult, +) where + Call: FnOnce( + OriginFor, + Box, + Box, + Box, + u32, + WeightLimit, + ) -> DispatchResult, +{ let balances = vec![ (ALICE, INITIAL_BALANCE), (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), ]; - - let beneficiary: MultiLocation = - Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + let origin_location: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); + let beneficiary: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); let weight_limit = WeightLimit::Limited(Weight::from_parts(5000, 5000)); let expected_weight_limit = weight_limit.clone(); let expected_beneficiary = beneficiary; @@ -301,14 +323,19 @@ fn limited_reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserv let weight = BaseXcmWeight::get(); assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE); // call extrinsic - assert_ok!(XcmPallet::limited_reserve_transfer_assets( + let result = tested_call( RuntimeOrigin::signed(ALICE), Box::new(dest.into()), Box::new(beneficiary.into()), Box::new((Here, SEND_AMOUNT).into()), 0, weight_limit, - )); + ); + assert_eq!(result, expected_result); + if expected_result.is_err() { + // short-circuit here for tests where we expect failure + return + } // Alice spent amount assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - SEND_AMOUNT); // Destination account (parachain account) has amount @@ -337,7 +364,7 @@ fn limited_reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserv assert_eq!( last_events.next().unwrap(), RuntimeEvent::XcmPallet(crate::Event::FeesPaid { - paying: expected_beneficiary, + paying: origin_location, fees: MultiAssets::new(), }) ); @@ -348,33 +375,66 @@ fn limited_reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserv }); } -/// Test `reserve_transfer_assets` with destination asset reserve and local fee reserve. +/// Test `transfer_assets` with local asset reserve and local fee reserve works. +#[test] +fn transfer_assets_with_local_asset_reserve_and_local_fee_reserve_works() { + let expected_result = Ok(()); + local_asset_reserve_and_local_fee_reserve_call(XcmPallet::transfer_assets, expected_result); +} + +/// Test `limited_reserve_transfer_assets` with local asset reserve and local fee reserve works. +#[test] +fn reserve_transfer_assets_with_local_asset_reserve_and_local_fee_reserve_works() { + let expected_result = Ok(()); + local_asset_reserve_and_local_fee_reserve_call( + XcmPallet::limited_reserve_transfer_assets, + expected_result, + ); +} + +/// Test `limited_teleport_assets` with local asset reserve and local fee reserve disallowed. +#[test] +fn teleport_assets_with_local_asset_reserve_and_local_fee_reserve_disallowed() { + let expected_result = Err(DispatchError::Module(ModuleError { + index: 4, + error: [2, 0, 0, 0], + message: Some("Filtered"), + })); + local_asset_reserve_and_local_fee_reserve_call( + XcmPallet::limited_teleport_assets, + expected_result, + ); +} + +/// Test `tested_call` with destination asset reserve and local fee reserve. /// /// Transferring foreign asset (`FOREIGN_ASSET_RESERVE_PARA_ID` reserve) to /// `FOREIGN_ASSET_RESERVE_PARA_ID` (no teleport trust). /// Using native asset (local reserve) for fees. /// -/// ```nocompile -/// Here (source) FOREIGN_ASSET_RESERVE_PARA_ID (destination) -/// | `fees` reserve `assets` reserve -/// | -/// | 1. execute `TransferReserveAsset(fees)` -/// | \-> sends `ReserveAssetDeposited(fees), ClearOrigin, BuyExecution(fees), DepositAsset` -/// | 2. execute `InitiateReserveWithdraw(assets)` -/// | \--> sends `WithdrawAsset(assets), ClearOrigin, BuyExecution(fees), DepositAsset` -/// \------------------------------------------> -/// ``` -/// /// Asserts that the sender's balance is decreased and the beneficiary's balance /// is increased. Verifies the correct message is sent and event is emitted. -#[test] -fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_works() { +/// +/// Verifies `expected_result`. +fn destination_asset_reserve_and_local_fee_reserve_call( + tested_call: Call, + expected_result: DispatchResult, +) where + Call: FnOnce( + OriginFor, + Box, + Box, + Box, + u32, + WeightLimit, + ) -> DispatchResult, +{ let weight = BaseXcmWeight::get() * 3; let balances = vec![(ALICE, INITIAL_BALANCE)]; - let beneficiary: MultiLocation = - Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + let origin_location: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); + let beneficiary: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); new_test_ext_with_balances(balances).execute_with(|| { - // create non-sufficient foreign asset BLA (0 total issuance) + // create non-sufficient foreign asset BLA let foreign_initial_amount = 142; let (reserve_location, reserve_sovereign_account, foreign_asset_id_multilocation) = set_up_foreign_asset( @@ -404,14 +464,19 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_ assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); // do the transfer - assert_ok!(XcmPallet::limited_reserve_transfer_assets( + let result = tested_call( RuntimeOrigin::signed(ALICE), Box::new(dest.into()), Box::new(beneficiary.into()), Box::new(assets.into()), fee_index as u32, Unlimited, - )); + ); + assert_eq!(result, expected_result); + if expected_result.is_err() { + // short-circuit here for tests where we expect failure + return + } let mut last_events = last_events(3).into_iter(); assert_eq!( @@ -454,7 +519,7 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_ assert_eq!( last_events.next().unwrap(), RuntimeEvent::XcmPallet(crate::Event::FeesPaid { - paying: beneficiary, + paying: origin_location, fees: MultiAssets::new(), }) ); @@ -465,17 +530,67 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_ }); } -/// Test `reserve_transfer_assets` with remote asset reserve and local fee reserve. +/// Test `transfer_assets` with destination asset reserve and local fee reserve. +#[test] +fn transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_works() { + let expected_result = Ok(()); + destination_asset_reserve_and_local_fee_reserve_call( + XcmPallet::transfer_assets, + expected_result, + ); +} + +/// Test `limited_reserve_transfer_assets` with destination asset reserve and local fee reserve +/// disallowed. +#[test] +fn reserve_transfer_assets_with_destination_asset_reserve_and_local_fee_reserve_disallowed() { + let expected_result = Err(DispatchError::Module(ModuleError { + index: 4, + error: [23, 0, 0, 0], + message: Some("TooManyReserves"), + })); + destination_asset_reserve_and_local_fee_reserve_call( + XcmPallet::limited_reserve_transfer_assets, + expected_result, + ); +} + +/// Test `limited_teleport_assets` with destination asset reserve and local fee reserve +/// disallowed. +#[test] +fn teleport_assets_with_destination_asset_reserve_and_local_fee_reserve_disallowed() { + let expected_result = Err(DispatchError::Module(ModuleError { + index: 4, + error: [2, 0, 0, 0], + message: Some("Filtered"), + })); + destination_asset_reserve_and_local_fee_reserve_call( + XcmPallet::limited_teleport_assets, + expected_result, + ); +} + +/// Test `tested_call` with remote asset reserve and local fee reserve is disallowed. /// /// Transferring foreign asset (reserve on `FOREIGN_ASSET_RESERVE_PARA_ID`) to `OTHER_PARA_ID`. /// Using native (local reserve) as fee should be disallowed. -#[test] -fn reserve_transfer_assets_with_remote_asset_reserve_and_local_fee_reserve_disallowed() { +fn remote_asset_reserve_and_local_fee_reserve_call_disallowed( + tested_call: Call, + expected_result: DispatchResult, +) where + Call: FnOnce( + OriginFor, + Box, + Box, + Box, + u32, + WeightLimit, + ) -> DispatchResult, +{ let balances = vec![(ALICE, INITIAL_BALANCE)]; - let beneficiary: MultiLocation = - Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + let beneficiary: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); new_test_ext_with_balances(balances).execute_with(|| { - // create non-sufficient foreign asset BLA (0 total issuance) + // create non-sufficient foreign asset BLA let foreign_initial_amount = 142; let (_, _, foreign_asset_id_multilocation) = set_up_foreign_asset( FOREIGN_ASSET_RESERVE_PARA_ID, @@ -500,7 +615,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_local_fee_reserve_disal assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); // try the transfer - let result = XcmPallet::limited_reserve_transfer_assets( + let result = tested_call( RuntimeOrigin::signed(ALICE), Box::new(dest.into()), Box::new(beneficiary.into()), @@ -508,14 +623,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_local_fee_reserve_disal fee_index as u32, Unlimited, ); - assert_eq!( - result, - Err(DispatchError::Module(ModuleError { - index: 4, - error: [22, 0, 0, 0], - message: Some("InvalidAssetUnsupportedReserve") - })) - ); + assert_eq!(result, expected_result); // Alice transferred nothing assert_eq!(Assets::balance(foreign_asset_id_multilocation, ALICE), foreign_initial_amount); @@ -529,28 +637,76 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_local_fee_reserve_disal }); } -/// Test `reserve_transfer_assets` with local asset reserve and destination fee reserve. +/// Test `transfer_assets` with remote asset reserve and local fee reserve is disallowed. +#[test] +fn transfer_assets_with_remote_asset_reserve_and_local_fee_reserve_disallowed() { + let expected_result = Err(DispatchError::Module(ModuleError { + index: 4, + error: [22, 0, 0, 0], + message: Some("InvalidAssetUnsupportedReserve"), + })); + remote_asset_reserve_and_local_fee_reserve_call_disallowed( + XcmPallet::transfer_assets, + expected_result, + ); +} + +/// Test `limited_reserve_transfer_assets` with remote asset reserve and local fee reserve is +/// disallowed. +#[test] +fn reserve_transfer_assets_with_remote_asset_reserve_and_local_fee_reserve_disallowed() { + let expected_result = Err(DispatchError::Module(ModuleError { + index: 4, + error: [23, 0, 0, 0], + message: Some("TooManyReserves"), + })); + remote_asset_reserve_and_local_fee_reserve_call_disallowed( + XcmPallet::limited_reserve_transfer_assets, + expected_result, + ); +} + +/// Test `limited_teleport_assets` with remote asset reserve and local fee reserve is disallowed. +#[test] +fn teleport_assets_with_remote_asset_reserve_and_local_fee_reserve_disallowed() { + let expected_result = Err(DispatchError::Module(ModuleError { + index: 4, + error: [2, 0, 0, 0], + message: Some("Filtered"), + })); + remote_asset_reserve_and_local_fee_reserve_call_disallowed( + XcmPallet::limited_teleport_assets, + expected_result, + ); +} + +/// Test `tested_call` with local asset reserve and destination fee reserve. /// /// Transferring native asset (local reserve) to `USDC_RESERVE_PARA_ID` (no teleport trust). Using /// foreign asset (`USDC_RESERVE_PARA_ID` reserve) for fees. /// -/// ```nocompile -/// Here (source) USDC_RESERVE_PARA_ID (destination) -/// | `assets` reserve `fees` reserve -/// | -/// | 1. execute `InitiateReserveWithdraw(fees)` -/// | \--> sends `WithdrawAsset(fees), ClearOrigin, BuyExecution(fees), DepositAsset` -/// | 2. execute `TransferReserveAsset(assets)` -/// | \-> sends `ReserveAssetDeposited(assets), ClearOrigin, BuyExecution(fees), DepositAsset` -/// \------------------------------------------> -/// ``` -#[test] -fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_works() { +/// Asserts that the sender's balance is decreased and the beneficiary's balance +/// is increased. Verifies the correct message is sent and event is emitted. +/// +/// Verifies `expected_result`. +fn local_asset_reserve_and_destination_fee_reserve_call( + tested_call: Call, + expected_result: DispatchResult, +) where + Call: FnOnce( + OriginFor, + Box, + Box, + Box, + u32, + WeightLimit, + ) -> DispatchResult, +{ let balances = vec![(ALICE, INITIAL_BALANCE)]; - let beneficiary: MultiLocation = - Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + let origin_location: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); + let beneficiary: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); new_test_ext_with_balances(balances).execute_with(|| { - // create sufficient foreign asset USDC (0 total issuance) + // create sufficient foreign asset USDC let usdc_initial_local_amount = 142; let (usdc_reserve_location, usdc_chain_sovereign_account, usdc_id_multilocation) = set_up_foreign_asset( @@ -580,14 +736,20 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_ assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); // do the transfer - assert_ok!(XcmPallet::limited_reserve_transfer_assets( + let result = tested_call( RuntimeOrigin::signed(ALICE), Box::new(dest.into()), Box::new(beneficiary.into()), Box::new(assets.into()), fee_index as u32, Unlimited, - )); + ); + assert_eq!(result, expected_result); + if expected_result.is_err() { + // short-circuit here for tests where we expect failure + return + } + let weight = BaseXcmWeight::get() * 3; let mut last_events = last_events(3).into_iter(); assert_eq!( @@ -597,7 +759,7 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_ assert_eq!( last_events.next().unwrap(), RuntimeEvent::XcmPallet(crate::Event::FeesPaid { - paying: beneficiary, + paying: origin_location, fees: MultiAssets::new(), }) ); @@ -642,22 +804,64 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_ }); } -/// Test `reserve_transfer_assets` with destination asset reserve and destination fee reserve. -/// -/// ```nocompile -/// Here (source) FOREIGN_ASSET_RESERVE_PARA_ID (destination) -/// | `fees` reserve -/// | `assets` reserve -/// | -/// | 1. execute `InitiateReserveWithdraw(assets_and_fees_batched_together)` -/// | \--> sends `WithdrawAsset(batch), ClearOrigin, BuyExecution(fees), DepositAsset` -/// \------------------------------------------> -/// ``` +/// Test `transfer_assets` with local asset reserve and destination fee reserve. #[test] -fn reserve_transfer_assets_with_destination_asset_reserve_and_destination_fee_reserve_works() { +fn transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_works() { + let expected_result = Ok(()); + local_asset_reserve_and_destination_fee_reserve_call( + XcmPallet::transfer_assets, + expected_result, + ); +} + +/// Test `limited_reserve_transfer_assets` with local asset reserve and destination fee reserve +/// disallowed. +#[test] +fn reserve_transfer_assets_with_local_asset_reserve_and_destination_fee_reserve_disallowed() { + let expected_result = Err(DispatchError::Module(ModuleError { + index: 4, + error: [23, 0, 0, 0], + message: Some("TooManyReserves"), + })); + local_asset_reserve_and_destination_fee_reserve_call( + XcmPallet::limited_reserve_transfer_assets, + expected_result, + ); +} + +/// Test `limited_teleport_assets` with local asset reserve and destination fee reserve disallowed. +#[test] +fn teleport_assets_with_local_asset_reserve_and_destination_fee_reserve_disallowed() { + let expected_result = Err(DispatchError::Module(ModuleError { + index: 4, + error: [2, 0, 0, 0], + message: Some("Filtered"), + })); + local_asset_reserve_and_destination_fee_reserve_call( + XcmPallet::limited_teleport_assets, + expected_result, + ); +} + +/// Test `tested_call` with destination asset reserve and destination fee reserve. +/// +/// Verifies `expected_result` +fn destination_asset_reserve_and_destination_fee_reserve_call( + tested_call: Call, + expected_result: DispatchResult, +) where + Call: FnOnce( + OriginFor, + Box, + Box, + Box, + u32, + WeightLimit, + ) -> DispatchResult, +{ let balances = vec![(ALICE, INITIAL_BALANCE)]; - let beneficiary: MultiLocation = - Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + let origin_location: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); + let beneficiary: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); new_test_ext_with_balances(balances).execute_with(|| { // we'll send just this foreign asset back to its reserve location and use it for fees as // well @@ -684,14 +888,19 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_destination_fee_re assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); // do the transfer - assert_ok!(XcmPallet::limited_reserve_transfer_assets( + let result = tested_call( RuntimeOrigin::signed(ALICE), Box::new(dest.into()), Box::new(beneficiary.into()), Box::new(assets.into()), fee_index, Unlimited, - )); + ); + assert_eq!(result, expected_result); + if expected_result.is_err() { + // short-circuit here for tests where we expect failure + return + } let weight = BaseXcmWeight::get() * 2; let mut last_events = last_events(3).into_iter(); @@ -702,7 +911,7 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_destination_fee_re assert_eq!( last_events.next().unwrap(), RuntimeEvent::XcmPallet(crate::Event::FeesPaid { - paying: beneficiary, + paying: origin_location, fees: MultiAssets::new(), }) ); @@ -743,18 +952,63 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_destination_fee_re }); } -/// Test `reserve_transfer_assets` with remote asset reserve and destination fee reserve is +/// Test `transfer_assets` with destination asset reserve and destination fee reserve. +#[test] +fn transfer_assets_with_destination_asset_reserve_and_destination_fee_reserve_works() { + let expected_result = Ok(()); + destination_asset_reserve_and_destination_fee_reserve_call( + XcmPallet::transfer_assets, + expected_result, + ); +} + +/// Test `limited_reserve_transfer_assets` with destination asset reserve and destination fee +/// reserve. +#[test] +fn reserve_transfer_assets_with_destination_asset_reserve_and_destination_fee_reserve_works() { + let expected_result = Ok(()); + destination_asset_reserve_and_destination_fee_reserve_call( + XcmPallet::limited_reserve_transfer_assets, + expected_result, + ); +} + +/// Test `limited_teleport_assets` with destination asset reserve and destination fee reserve /// disallowed. +#[test] +fn teleport_assets_with_destination_asset_reserve_and_destination_fee_reserve_disallowed() { + let expected_result = Err(DispatchError::Module(ModuleError { + index: 4, + error: [2, 0, 0, 0], + message: Some("Filtered"), + })); + destination_asset_reserve_and_destination_fee_reserve_call( + XcmPallet::limited_teleport_assets, + expected_result, + ); +} + +/// Test `transfer_assets` with remote asset reserve and destination fee reserve is disallowed. /// /// Transferring foreign asset (reserve on `FOREIGN_ASSET_RESERVE_PARA_ID`) to /// `USDC_RESERVE_PARA_ID`. Using USDC (destination reserve) as fee. -#[test] -fn reserve_transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve_disallowed() { +fn remote_asset_reserve_and_destination_fee_reserve_call_disallowed( + tested_call: Call, + expected_result: DispatchResult, +) where + Call: FnOnce( + OriginFor, + Box, + Box, + Box, + u32, + WeightLimit, + ) -> DispatchResult, +{ let balances = vec![(ALICE, INITIAL_BALANCE)]; - let beneficiary: MultiLocation = - Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + let beneficiary: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); new_test_ext_with_balances(balances).execute_with(|| { - // create sufficient foreign asset USDC (0 total issuance) + // create sufficient foreign asset USDC let usdc_initial_local_amount = 42; let (usdc_chain, _, usdc_id_multilocation) = set_up_foreign_asset( USDC_RESERVE_PARA_ID, @@ -763,7 +1017,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve true, ); - // create non-sufficient foreign asset BLA (0 total issuance) + // create non-sufficient foreign asset BLA let foreign_initial_amount = 142; let (_, _, foreign_asset_id_multilocation) = set_up_foreign_asset( FOREIGN_ASSET_RESERVE_PARA_ID, @@ -789,7 +1043,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); // do the transfer - let result = XcmPallet::limited_reserve_transfer_assets( + let result = tested_call( RuntimeOrigin::signed(ALICE), Box::new(dest.into()), Box::new(beneficiary.into()), @@ -797,14 +1051,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve fee_index as u32, Unlimited, ); - assert_eq!( - result, - Err(DispatchError::Module(ModuleError { - index: 4, - error: [22, 0, 0, 0], - message: Some("InvalidAssetUnsupportedReserve") - })) - ); + assert_eq!(result, expected_result); // Alice native asset untouched assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); @@ -819,17 +1066,71 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve }); } -/// Test `reserve_transfer_assets` with local asset reserve and remote fee reserve is disallowed. +/// Test `transfer_assets` with remote asset reserve and destination fee reserve is disallowed. +#[test] +fn transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve_disallowed() { + let expected_result = Err(DispatchError::Module(ModuleError { + index: 4, + error: [22, 0, 0, 0], + message: Some("InvalidAssetUnsupportedReserve"), + })); + remote_asset_reserve_and_destination_fee_reserve_call_disallowed( + XcmPallet::transfer_assets, + expected_result, + ); +} + +/// Test `limited_reserve_transfer_assets` with remote asset reserve and destination fee reserve is +/// disallowed. +#[test] +fn reserve_transfer_assets_with_remote_asset_reserve_and_destination_fee_reserve_disallowed() { + let expected_result = Err(DispatchError::Module(ModuleError { + index: 4, + error: [23, 0, 0, 0], + message: Some("TooManyReserves"), + })); + remote_asset_reserve_and_destination_fee_reserve_call_disallowed( + XcmPallet::limited_reserve_transfer_assets, + expected_result, + ); +} + +/// Test `limited_teleport_assets` with remote asset reserve and destination fee reserve is +/// disallowed. +#[test] +fn teleport_assets_with_remote_asset_reserve_and_destination_fee_reserve_disallowed() { + let expected_result = Err(DispatchError::Module(ModuleError { + index: 4, + error: [2, 0, 0, 0], + message: Some("Filtered"), + })); + remote_asset_reserve_and_destination_fee_reserve_call_disallowed( + XcmPallet::limited_teleport_assets, + expected_result, + ); +} + +/// Test `tested_call` with local asset reserve and remote fee reserve is disallowed. /// /// Transferring native asset (local reserve) to `OTHER_PARA_ID` (no teleport trust). Using foreign /// asset (`USDC_RESERVE_PARA_ID` remote reserve) for fees. -#[test] -fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_disallowed() { +fn local_asset_reserve_and_remote_fee_reserve_call_disallowed( + tested_call: Call, + expected_result: DispatchResult, +) where + Call: FnOnce( + OriginFor, + Box, + Box, + Box, + u32, + WeightLimit, + ) -> DispatchResult, +{ let balances = vec![(ALICE, INITIAL_BALANCE)]; - let beneficiary: MultiLocation = - Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + let beneficiary: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); new_test_ext_with_balances(balances).execute_with(|| { - // create sufficient foreign asset USDC (0 total issuance) + // create sufficient foreign asset USDC let usdc_initial_local_amount = 142; let (_, usdc_chain_sovereign_account, usdc_id_multilocation) = set_up_foreign_asset( USDC_RESERVE_PARA_ID, @@ -854,7 +1155,7 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_disal assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); // do the transfer - let result = XcmPallet::limited_reserve_transfer_assets( + let result = tested_call( RuntimeOrigin::signed(ALICE), Box::new(dest.into()), Box::new(beneficiary.into()), @@ -862,14 +1163,7 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_disal fee_index as u32, Unlimited, ); - assert_eq!( - result, - Err(DispatchError::Module(ModuleError { - index: 4, - error: [22, 0, 0, 0], - message: Some("InvalidAssetUnsupportedReserve") - })) - ); + assert_eq!(result, expected_result); assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); // Sovereign account of reserve parachain is unchanged @@ -882,18 +1176,70 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_disal }); } -/// Test `reserve_transfer_assets` with destination asset reserve and remote fee reserve is +/// Test `transfer_assets` with local asset reserve and remote fee reserve is disallowed. +#[test] +fn transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_disallowed() { + let expected_result = Err(DispatchError::Module(ModuleError { + index: 4, + error: [22, 0, 0, 0], + message: Some("InvalidAssetUnsupportedReserve"), + })); + local_asset_reserve_and_remote_fee_reserve_call_disallowed( + XcmPallet::transfer_assets, + expected_result, + ); +} + +/// Test `limited_reserve_transfer_assets` with local asset reserve and remote fee reserve is /// disallowed. +#[test] +fn reserve_transfer_assets_with_local_asset_reserve_and_remote_fee_reserve_disallowed() { + let expected_result = Err(DispatchError::Module(ModuleError { + index: 4, + error: [23, 0, 0, 0], + message: Some("TooManyReserves"), + })); + local_asset_reserve_and_remote_fee_reserve_call_disallowed( + XcmPallet::limited_reserve_transfer_assets, + expected_result, + ); +} + +/// Test `limited_teleport_assets` with local asset reserve and remote fee reserve is disallowed. +#[test] +fn teleport_assets_with_local_asset_reserve_and_remote_fee_reserve_disallowed() { + let expected_result = Err(DispatchError::Module(ModuleError { + index: 4, + error: [2, 0, 0, 0], + message: Some("Filtered"), + })); + local_asset_reserve_and_remote_fee_reserve_call_disallowed( + XcmPallet::limited_teleport_assets, + expected_result, + ); +} + +/// Test `tested_call` with destination asset reserve and remote fee reserve is disallowed. /// /// Transferring native asset (local reserve) to `OTHER_PARA_ID` (no teleport trust). Using foreign /// asset (`USDC_RESERVE_PARA_ID` remote reserve) for fees. -#[test] -fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve_disallowed() { +fn destination_asset_reserve_and_remote_fee_reserve_call_disallowed( + tested_call: Call, + expected_result: DispatchResult, +) where + Call: FnOnce( + OriginFor, + Box, + Box, + Box, + u32, + WeightLimit, + ) -> DispatchResult, +{ let balances = vec![(ALICE, INITIAL_BALANCE)]; - let beneficiary: MultiLocation = - Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + let beneficiary: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); new_test_ext_with_balances(balances).execute_with(|| { - // create sufficient foreign asset USDC (0 total issuance) + // create sufficient foreign asset USDC let usdc_initial_local_amount = 42; let (_, usdc_chain_sovereign_account, usdc_id_multilocation) = set_up_foreign_asset( USDC_RESERVE_PARA_ID, @@ -902,7 +1248,7 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve true, ); - // create non-sufficient foreign asset BLA (0 total issuance) + // create non-sufficient foreign asset BLA let foreign_initial_amount = 142; let (reserve_location, foreign_sovereign_account, foreign_asset_id_multilocation) = set_up_foreign_asset( @@ -928,7 +1274,7 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); // do the transfer - let result = XcmPallet::limited_reserve_transfer_assets( + let result = tested_call( RuntimeOrigin::signed(ALICE), Box::new(dest.into()), Box::new(beneficiary.into()), @@ -936,14 +1282,7 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve fee_index as u32, Unlimited, ); - assert_eq!( - result, - Err(DispatchError::Module(ModuleError { - index: 4, - error: [22, 0, 0, 0], - message: Some("InvalidAssetUnsupportedReserve") - })) - ); + assert_eq!(result, expected_result); // Alice native asset untouched assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); assert_eq!(Assets::balance(usdc_id_multilocation, ALICE), usdc_initial_local_amount); @@ -961,7 +1300,51 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve }); } -/// Test `reserve_transfer_assets` with remote asset reserve and (same) remote fee reserve. +/// Test `transfer_assets` with destination asset reserve and remote fee reserve is disallowed. +#[test] +fn transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve_disallowed() { + let expected_result = Err(DispatchError::Module(ModuleError { + index: 4, + error: [22, 0, 0, 0], + message: Some("InvalidAssetUnsupportedReserve"), + })); + destination_asset_reserve_and_remote_fee_reserve_call_disallowed( + XcmPallet::transfer_assets, + expected_result, + ); +} + +/// Test `limited_reserve_transfer_assets` with destination asset reserve and remote fee reserve is +/// disallowed. +#[test] +fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve_disallowed() { + let expected_result = Err(DispatchError::Module(ModuleError { + index: 4, + error: [23, 0, 0, 0], + message: Some("TooManyReserves"), + })); + destination_asset_reserve_and_remote_fee_reserve_call_disallowed( + XcmPallet::limited_reserve_transfer_assets, + expected_result, + ); +} + +/// Test `limited_teleport_assets` with destination asset reserve and remote fee reserve is +/// disallowed. +#[test] +fn teleport_assets_with_destination_asset_reserve_and_remote_fee_reserve_disallowed() { + let expected_result = Err(DispatchError::Module(ModuleError { + index: 4, + error: [2, 0, 0, 0], + message: Some("Filtered"), + })); + destination_asset_reserve_and_remote_fee_reserve_call_disallowed( + XcmPallet::limited_teleport_assets, + expected_result, + ); +} + +/// Test `tested_call` with remote asset reserve and (same) remote fee reserve. /// /// Transferring native asset (local reserve) to `OTHER_PARA_ID` (no teleport trust). Using foreign /// asset (`USDC_RESERVE_PARA_ID` remote reserve) for fees. @@ -976,13 +1359,25 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_remote_fee_reserve /// | -----------------> `C` executes `DepositReserveAsset(both)` dest `B` /// | --------------------------> `DepositAsset(both)` /// ``` -#[test] -fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_works() { +/// +/// Verifies `expected_result` +fn remote_asset_reserve_and_remote_fee_reserve_call( + tested_call: Call, + expected_result: DispatchResult, +) where + Call: FnOnce( + OriginFor, + Box, + Box, + Box, + u32, + WeightLimit, + ) -> DispatchResult, +{ let balances = vec![(ALICE, INITIAL_BALANCE)]; - let beneficiary: MultiLocation = - Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + let beneficiary: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); new_test_ext_with_balances(balances).execute_with(|| { - // create sufficient foreign asset USDC (0 total issuance) + // create sufficient foreign asset USDC let usdc_initial_local_amount = 142; let (usdc_chain, usdc_chain_sovereign_account, usdc_id_multilocation) = set_up_foreign_asset( @@ -996,12 +1391,12 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_work let dest = RelayLocation::get().pushed_with_interior(Parachain(OTHER_PARA_ID)).unwrap(); let assets: MultiAssets = vec![(usdc_id_multilocation, SEND_AMOUNT).into()].into(); - let fee_index = 0; + let fee_index = 0u32; // reanchor according to test-case let context = UniversalLocation::get(); let expected_dest_on_reserve = dest.reanchored(&usdc_chain, context).unwrap(); - let fees = assets.get(fee_index).unwrap().clone(); + let fees = assets.get(fee_index as usize).unwrap().clone(); let (fees_half_1, fees_half_2) = XcmPallet::halve_fees(fees).unwrap(); let mut expected_assets_on_reserve = assets.clone(); expected_assets_on_reserve.reanchor(&usdc_chain, context).unwrap(); @@ -1013,14 +1408,20 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_work assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); // do the transfer - assert_ok!(XcmPallet::limited_reserve_transfer_assets( + let result = tested_call( RuntimeOrigin::signed(ALICE), Box::new(dest.into()), Box::new(beneficiary.into()), Box::new(assets.into()), - fee_index as u32, + fee_index, Unlimited, - )); + ); + assert_eq!(result, expected_result); + if expected_result.is_err() { + // short-circuit here for tests where we expect failure + return + } + assert!(matches!( last_event(), RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(_) }) @@ -1067,28 +1468,62 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_work }); } -/// Test `reserve_transfer_assets` with local asset reserve and teleported fee. +/// Test `transfer_assets` with remote asset reserve and (same) remote fee reserve. +#[test] +fn transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_works() { + let expected_result = Ok(()); + remote_asset_reserve_and_remote_fee_reserve_call(XcmPallet::transfer_assets, expected_result); +} + +/// Test `limited_reserve_transfer_assets` with remote asset reserve and (same) remote fee reserve. +#[test] +fn reserve_transfer_assets_with_remote_asset_reserve_and_remote_fee_reserve_works() { + let expected_result = Ok(()); + remote_asset_reserve_and_remote_fee_reserve_call( + XcmPallet::limited_reserve_transfer_assets, + expected_result, + ); +} + +/// Test `limited_teleport_assets` with remote asset reserve and (same) remote fee reserve +/// disallowed. +#[test] +fn teleport_assets_with_remote_asset_reserve_and_remote_fee_reserve_disallowed() { + let expected_result = Err(DispatchError::Module(ModuleError { + index: 4, + error: [2, 0, 0, 0], + message: Some("Filtered"), + })); + remote_asset_reserve_and_remote_fee_reserve_call( + XcmPallet::limited_teleport_assets, + expected_result, + ); +} + +/// Test `tested_call` with local asset reserve and teleported fee. /// /// Transferring native asset (local reserve) to `USDT_PARA_ID`. Using teleport-trusted USDT for /// fees. /// -/// ```nocompile -/// Here (source) USDT_PARA_ID (destination) -/// | `assets` reserve `fees` teleport-trust -/// | -/// | 1. execute `InitiateTeleport(fees)` -/// | \--> sends `ReceiveTeleportedAsset(fees), .., DepositAsset(fees)` -/// | 2. execute `TransferReserveAsset(assets)` -/// | \-> sends `ReserveAssetDeposited(assets), ClearOrigin, BuyExecution(fees), DepositAsset` -/// \------------------------------------------> -/// ``` -#[test] -fn reserve_transfer_assets_with_local_asset_reserve_and_teleported_fee_works() { +/// Verifies `expected_result` +fn local_asset_reserve_and_teleported_fee_call( + tested_call: Call, + expected_result: DispatchResult, +) where + Call: FnOnce( + OriginFor, + Box, + Box, + Box, + u32, + WeightLimit, + ) -> DispatchResult, +{ let balances = vec![(ALICE, INITIAL_BALANCE)]; - let beneficiary: MultiLocation = - Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + let origin_location: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); + let beneficiary: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); new_test_ext_with_balances(balances).execute_with(|| { - // create sufficient foreign asset USDT (0 total issuance) + // create sufficient foreign asset USDT let usdt_initial_local_amount = 42; let (usdt_chain, usdt_chain_sovereign_account, usdt_id_multilocation) = set_up_foreign_asset(USDT_PARA_ID, None, usdt_initial_local_amount, true); @@ -1113,14 +1548,20 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_teleported_fee_works() { assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); // do the transfer - assert_ok!(XcmPallet::limited_reserve_transfer_assets( + let result = tested_call( RuntimeOrigin::signed(ALICE), Box::new(dest.into()), Box::new(beneficiary.into()), Box::new(assets.into()), fee_index as u32, Unlimited, - )); + ); + assert_eq!(result, expected_result); + if expected_result.is_err() { + // short-circuit here for tests where we expect failure + return + } + let weight = BaseXcmWeight::get() * 3; let mut last_events = last_events(3).into_iter(); assert_eq!( @@ -1130,7 +1571,7 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_teleported_fee_works() { assert_eq!( last_events.next().unwrap(), RuntimeEvent::XcmPallet(crate::Event::FeesPaid { - paying: beneficiary, + paying: origin_location, fees: MultiAssets::new(), }) ); @@ -1173,34 +1614,70 @@ fn reserve_transfer_assets_with_local_asset_reserve_and_teleported_fee_works() { }); } -/// Test `reserve_transfer_assets` with destination asset reserve and teleported fee. +/// Test `transfer_assets` with local asset reserve and teleported fee. +#[test] +fn transfer_assets_with_local_asset_reserve_and_teleported_fee_works() { + let expected_result = Ok(()); + local_asset_reserve_and_teleported_fee_call(XcmPallet::transfer_assets, expected_result); +} + +/// Test `limited_reserve_transfer_assets` with local asset reserve and teleported fee disallowed. +#[test] +fn reserve_transfer_assets_with_local_asset_reserve_and_teleported_fee_disallowed() { + let expected_result = Err(DispatchError::Module(ModuleError { + index: 4, + error: [23, 0, 0, 0], + message: Some("TooManyReserves"), + })); + local_asset_reserve_and_teleported_fee_call( + XcmPallet::limited_reserve_transfer_assets, + expected_result, + ); +} + +/// Test `limited_teleport_assets` with local asset reserve and teleported fee disallowed. +#[test] +fn teleport_assets_with_local_asset_reserve_and_teleported_fee_disallowed() { + let expected_result = Err(DispatchError::Module(ModuleError { + index: 4, + error: [2, 0, 0, 0], + message: Some("Filtered"), + })); + local_asset_reserve_and_teleported_fee_call( + XcmPallet::limited_teleport_assets, + expected_result, + ); +} + +/// Test `tested_call` with destination asset reserve and teleported fee. /// /// Transferring foreign asset (destination reserve) to `FOREIGN_ASSET_RESERVE_PARA_ID`. Using /// teleport-trusted USDT for fees. /// -/// ```nocompile -/// Here (source) FOREIGN_ASSET_RESERVE_PARA_ID (destination) -/// | `fees` (USDT) teleport-trust -/// | `assets` reserve -/// | -/// | 1. execute `InitiateTeleport(fees)` -/// | \--> sends `ReceiveTeleportedAsset(fees), .., DepositAsset(fees)` -/// | 2. execute `InitiateReserveWithdraw(assets)` -/// | \--> sends `WithdrawAsset(asset), ClearOrigin, BuyExecution(fees), DepositAsset` -/// \------------------------------------------> -/// ``` -#[test] -fn reserve_transfer_assets_with_destination_asset_reserve_and_teleported_fee_works() { +/// Verifies `expected_result` +fn destination_asset_reserve_and_teleported_fee_call( + tested_call: Call, + expected_result: DispatchResult, +) where + Call: FnOnce( + OriginFor, + Box, + Box, + Box, + u32, + WeightLimit, + ) -> DispatchResult, +{ let balances = vec![(ALICE, INITIAL_BALANCE)]; - let beneficiary: MultiLocation = - Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + let origin_location: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); + let beneficiary: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); new_test_ext_with_balances(balances).execute_with(|| { - // create sufficient foreign asset USDT (0 total issuance) + // create sufficient foreign asset USDT let usdt_initial_local_amount = 42; let (_, usdt_chain_sovereign_account, usdt_id_multilocation) = set_up_foreign_asset(USDT_PARA_ID, None, usdt_initial_local_amount, true); - // create non-sufficient foreign asset BLA (0 total issuance) + // create non-sufficient foreign asset BLA let foreign_initial_amount = 142; let (reserve_location, foreign_sovereign_account, foreign_asset_id_multilocation) = set_up_foreign_asset( @@ -1231,14 +1708,20 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_teleported_fee_wor assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); // do the transfer - assert_ok!(XcmPallet::limited_reserve_transfer_assets( + let result = tested_call( RuntimeOrigin::signed(ALICE), Box::new(dest.into()), Box::new(beneficiary.into()), Box::new(assets.into()), fee_index as u32, Unlimited, - )); + ); + assert_eq!(result, expected_result); + if expected_result.is_err() { + // short-circuit here for tests where we expect failure + return + } + let weight = BaseXcmWeight::get() * 4; let mut last_events = last_events(3).into_iter(); assert_eq!( @@ -1248,7 +1731,7 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_teleported_fee_wor assert_eq!( last_events.next().unwrap(), RuntimeEvent::XcmPallet(crate::Event::FeesPaid { - paying: beneficiary, + paying: origin_location, fees: MultiAssets::new(), }) ); @@ -1303,22 +1786,68 @@ fn reserve_transfer_assets_with_destination_asset_reserve_and_teleported_fee_wor }); } -/// Test `reserve_transfer_assets` with remote asset reserve and teleported fee is disallowed. +/// Test `transfer_assets` with destination asset reserve and teleported fee. +#[test] +fn transfer_assets_with_destination_asset_reserve_and_teleported_fee_works() { + let expected_result = Ok(()); + destination_asset_reserve_and_teleported_fee_call(XcmPallet::transfer_assets, expected_result); +} + +/// Test `limited_reserve_transfer_assets` with destination asset reserve and teleported fee +/// disallowed. +#[test] +fn reserve_transfer_assets_with_destination_asset_reserve_and_teleported_fee_disallowed() { + let expected_result = Err(DispatchError::Module(ModuleError { + index: 4, + error: [23, 0, 0, 0], + message: Some("TooManyReserves"), + })); + destination_asset_reserve_and_teleported_fee_call( + XcmPallet::limited_reserve_transfer_assets, + expected_result, + ); +} + +/// Test `limited_teleport_assets` with destination asset reserve and teleported fee disallowed. +#[test] +fn teleport_assets_with_destination_asset_reserve_and_teleported_fee_disallowed() { + let expected_result = Err(DispatchError::Module(ModuleError { + index: 4, + error: [2, 0, 0, 0], + message: Some("Filtered"), + })); + destination_asset_reserve_and_teleported_fee_call( + XcmPallet::limited_teleport_assets, + expected_result, + ); +} + +/// Test `tested_call` with remote asset reserve and teleported fee is disallowed. /// /// Transferring foreign asset (reserve on `FOREIGN_ASSET_RESERVE_PARA_ID`) to `USDT_PARA_ID`. /// Using teleport-trusted USDT for fees. -#[test] -fn reserve_transfer_assets_with_remote_asset_reserve_and_teleported_fee_disallowed() { +fn remote_asset_reserve_and_teleported_fee_reserve_call_disallowed( + tested_call: Call, + expected_result: DispatchResult, +) where + Call: FnOnce( + OriginFor, + Box, + Box, + Box, + u32, + WeightLimit, + ) -> DispatchResult, +{ let balances = vec![(ALICE, INITIAL_BALANCE)]; - let beneficiary: MultiLocation = - Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + let beneficiary: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); new_test_ext_with_balances(balances).execute_with(|| { - // create sufficient foreign asset USDT (0 total issuance) + // create sufficient foreign asset USDT let usdt_initial_local_amount = 42; let (usdt_chain, usdt_chain_sovereign_account, usdt_id_multilocation) = set_up_foreign_asset(USDT_PARA_ID, None, usdt_initial_local_amount, true); - // create non-sufficient foreign asset BLA (0 total issuance) + // create non-sufficient foreign asset BLA let foreign_initial_amount = 142; let (_, reserve_sovereign_account, foreign_asset_id_multilocation) = set_up_foreign_asset( FOREIGN_ASSET_RESERVE_PARA_ID, @@ -1341,8 +1870,8 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_teleported_fee_disallow assert_eq!(Assets::balance(usdt_id_multilocation, ALICE), usdt_initial_local_amount); assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); - // do the transfer - let result = XcmPallet::limited_reserve_transfer_assets( + // try the transfer + let result = tested_call( RuntimeOrigin::signed(ALICE), Box::new(dest.into()), Box::new(beneficiary.into()), @@ -1350,14 +1879,7 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_teleported_fee_disallow fee_index as u32, Unlimited, ); - assert_eq!( - result, - Err(DispatchError::Module(ModuleError { - index: 4, - error: [22, 0, 0, 0], - message: Some("InvalidAssetUnsupportedReserve") - })) - ); + assert_eq!(result, expected_result); // Alice native asset untouched assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); assert_eq!(Assets::balance(usdt_id_multilocation, ALICE), usdt_initial_local_amount); @@ -1375,17 +1897,59 @@ fn reserve_transfer_assets_with_remote_asset_reserve_and_teleported_fee_disallow }); } +/// Test `transfer_assets` with remote asset reserve and teleported fee is disallowed. +#[test] +fn transfer_assets_with_remote_asset_reserve_and_teleported_fee_disallowed() { + let expected_result = Err(DispatchError::Module(ModuleError { + index: 4, + error: [22, 0, 0, 0], + message: Some("InvalidAssetUnsupportedReserve"), + })); + remote_asset_reserve_and_teleported_fee_reserve_call_disallowed( + XcmPallet::transfer_assets, + expected_result, + ); +} + +/// Test `limited_reserve_transfer_assets` with remote asset reserve and teleported fee is +/// disallowed. +#[test] +fn reserve_transfer_assets_with_remote_asset_reserve_and_teleported_fee_disallowed() { + let expected_result = Err(DispatchError::Module(ModuleError { + index: 4, + error: [23, 0, 0, 0], + message: Some("TooManyReserves"), + })); + remote_asset_reserve_and_teleported_fee_reserve_call_disallowed( + XcmPallet::limited_reserve_transfer_assets, + expected_result, + ); +} + +/// Test `limited_teleport_assets` with remote asset reserve and teleported fee is disallowed. +#[test] +fn teleport_assets_with_remote_asset_reserve_and_teleported_fee_disallowed() { + let expected_result = Err(DispatchError::Module(ModuleError { + index: 4, + error: [2, 0, 0, 0], + message: Some("Filtered"), + })); + remote_asset_reserve_and_teleported_fee_reserve_call_disallowed( + XcmPallet::limited_teleport_assets, + expected_result, + ); +} + /// Test `reserve_transfer_assets` single asset which is teleportable - should fail. /// /// Attempting to reserve-transfer teleport-trusted USDT to `USDT_PARA_ID` should fail. #[test] -fn reserve_transfer_assets_with_teleportable_asset_fails() { +fn reserve_transfer_assets_with_teleportable_asset_disallowed() { let balances = vec![(ALICE, INITIAL_BALANCE)]; - let beneficiary: MultiLocation = - Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + let beneficiary: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); new_test_ext_with_balances(balances).execute_with(|| { - // create sufficient foreign asset USDT (0 total issuance) + // create sufficient foreign asset USDT let usdt_initial_local_amount = 42; let (usdt_chain, usdt_chain_sovereign_account, usdt_id_multilocation) = set_up_foreign_asset(USDT_PARA_ID, None, usdt_initial_local_amount, true); @@ -1428,9 +1992,9 @@ fn reserve_transfer_assets_with_teleportable_asset_fails() { }); } -/// Test `reserve_transfer_assets` with teleportable fee that is filtered - should fail. +/// Test `transfer_assets` with teleportable fee that is filtered - should fail. #[test] -fn reserve_transfer_assets_with_filtered_teleported_fee_disallowed() { +fn transfer_assets_with_filtered_teleported_fee_disallowed() { let beneficiary: MultiLocation = AccountId32 { network: None, id: BOB.into() }.into(); new_test_ext_with_balances(vec![(ALICE, INITIAL_BALANCE)]).execute_with(|| { let (assets, fee_index, _, _) = into_multiassets_checked( @@ -1439,7 +2003,7 @@ fn reserve_transfer_assets_with_filtered_teleported_fee_disallowed() { // native asset to transfer (not used for fees) - local reserve (MultiLocation::here(), SEND_AMOUNT).into(), ); - let result = XcmPallet::limited_reserve_transfer_assets( + let result = XcmPallet::transfer_assets( RuntimeOrigin::signed(ALICE), Box::new(FilteredTeleportLocation::get().into()), Box::new(beneficiary.into()), @@ -1466,10 +2030,9 @@ fn reserve_transfer_assets_with_filtered_teleported_fee_disallowed() { #[test] fn intermediary_error_reverts_side_effects() { let balances = vec![(ALICE, INITIAL_BALANCE)]; - let beneficiary: MultiLocation = - Junction::AccountId32 { network: None, id: ALICE.into() }.into(); + let beneficiary: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); new_test_ext_with_balances(balances).execute_with(|| { - // create sufficient foreign asset USDC (0 total issuance) + // create sufficient foreign asset USDC let usdc_initial_local_amount = 142; let (_, usdc_chain_sovereign_account, usdc_id_multilocation) = set_up_foreign_asset( USDC_RESERVE_PARA_ID, @@ -1515,3 +2078,329 @@ fn intermediary_error_reverts_side_effects() { assert_eq!(sent_xcm(), vec![]); }); } + +/// Test `tested_call` with teleportable asset and local fee reserve. +/// +/// Transferring USDT to `USDT_PARA_ID` (teleport trust). Using native asset (local reserve) for +/// fees. +/// +/// Verifies `expected_result` +fn teleport_asset_using_local_fee_reserve_call( + tested_call: Call, + expected_result: DispatchResult, +) where + Call: FnOnce( + OriginFor, + Box, + Box, + Box, + u32, + WeightLimit, + ) -> DispatchResult, +{ + let weight = BaseXcmWeight::get() * 3; + let balances = vec![(ALICE, INITIAL_BALANCE)]; + let origin_location: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); + let beneficiary: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); + new_test_ext_with_balances(balances).execute_with(|| { + // create non-sufficient foreign asset USDT + let usdt_initial_local_amount = 42; + let (usdt_chain, usdt_chain_sovereign_account, usdt_id_multilocation) = + set_up_foreign_asset(USDT_PARA_ID, None, usdt_initial_local_amount, false); + + // transfer destination is reserve location (no teleport trust) + let dest = usdt_chain; + + let (assets, fee_index, fee_asset, xfer_asset) = into_multiassets_checked( + // native asset for fee - local reserve + (MultiLocation::here(), FEE_AMOUNT).into(), + // USDT to transfer - destination reserve + (usdt_id_multilocation, SEND_AMOUNT).into(), + ); + + // reanchor according to test-case + let context = UniversalLocation::get(); + let expected_fee = fee_asset.reanchored(&dest, context).unwrap(); + let expected_asset = xfer_asset.reanchored(&dest, context).unwrap(); + + // balances checks before + assert_eq!(Assets::balance(usdt_id_multilocation, ALICE), usdt_initial_local_amount); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + + // do the transfer + let result = tested_call( + RuntimeOrigin::signed(ALICE), + Box::new(dest.into()), + Box::new(beneficiary.into()), + Box::new(assets.into()), + fee_index as u32, + Unlimited, + ); + assert_eq!(result, expected_result); + if expected_result.is_err() { + // short-circuit here for tests where we expect failure + return + } + + let mut last_events = last_events(3).into_iter(); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) + ); + + // Alice spent (transferred) amount + assert_eq!( + Assets::balance(usdt_id_multilocation, ALICE), + usdt_initial_local_amount - SEND_AMOUNT + ); + // Alice used native asset for fees + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE - FEE_AMOUNT); + // Destination account (parachain account) added native reserve to balances + assert_eq!(Balances::free_balance(usdt_chain_sovereign_account.clone()), FEE_AMOUNT); + assert_eq!(Assets::balance(usdt_id_multilocation, usdt_chain_sovereign_account), 0); + // Verify total and active issuance of foreign BLA have decreased (burned on + // reserve-withdraw) + let expected_issuance = usdt_initial_local_amount - SEND_AMOUNT; + assert_eq!(Assets::total_issuance(usdt_id_multilocation), expected_issuance); + assert_eq!(Assets::active_issuance(usdt_id_multilocation), expected_issuance); + + // Verify sent XCM program + assert_eq!( + sent_xcm(), + vec![( + dest, + // `fees` are being sent through local-reserve transfer because fee reserve is + // local chain; `assets` are burned on source and withdrawn from SA here + Xcm(vec![ + ReserveAssetDeposited(expected_fee.clone().into()), + buy_limited_execution(expected_fee, Unlimited), + ReceiveTeleportedAsset(expected_asset.into()), + ClearOrigin, + DepositAsset { assets: AllCounted(2).into(), beneficiary }, + ]) + )] + ); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::FeesPaid { + paying: origin_location, + fees: MultiAssets::new(), + }) + ); + assert!(matches!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Sent { .. }) + )); + }); +} + +/// Test `transfer_assets` with teleportable asset and local fee reserve. +#[test] +fn transfer_assets_with_teleportable_asset_and_local_fee_reserve_works() { + let expected_result = Ok(()); + teleport_asset_using_local_fee_reserve_call(XcmPallet::transfer_assets, expected_result); +} + +/// Test `limited_reserve_transfer_assets` with teleportable asset and local fee reserve disallowed. +#[test] +fn reserve_transfer_assets_with_teleportable_asset_and_local_fee_reserve_disallowed() { + let expected_result = Err(DispatchError::Module(ModuleError { + index: 4, + error: [2, 0, 0, 0], + message: Some("Filtered"), + })); + teleport_asset_using_local_fee_reserve_call( + XcmPallet::limited_reserve_transfer_assets, + expected_result, + ); +} + +/// Test `limited_teleport_assets` with teleportable asset and local fee reserve disallowed. +#[test] +fn teleport_assets_with_teleportable_asset_and_local_fee_reserve_disallowed() { + let expected_result = Err(DispatchError::Module(ModuleError { + index: 4, + error: [2, 0, 0, 0], + message: Some("Filtered"), + })); + teleport_asset_using_local_fee_reserve_call( + XcmPallet::limited_teleport_assets, + expected_result, + ); +} + +/// Test `tested_call` with teleported asset reserve and destination fee. +/// +/// Transferring USDT to `FOREIGN_ASSET_RESERVE_PARA_ID` (teleport trust). Using foreign asset +/// (destination reserve) for fees. +/// +/// Verifies `expected_result` +fn teleported_asset_using_destination_reserve_fee_call( + tested_call: Call, + expected_result: DispatchResult, +) where + Call: FnOnce( + OriginFor, + Box, + Box, + Box, + u32, + WeightLimit, + ) -> DispatchResult, +{ + let balances = vec![(ALICE, INITIAL_BALANCE)]; + let origin_location: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); + let beneficiary: MultiLocation = AccountId32 { network: None, id: ALICE.into() }.into(); + new_test_ext_with_balances(balances).execute_with(|| { + // create sufficient foreign asset BLA to be used for fees + let foreign_initial_amount = 142; + let (reserve_location, foreign_sovereign_account, foreign_asset_id_multilocation) = + set_up_foreign_asset( + FOREIGN_ASSET_RESERVE_PARA_ID, + Some(FOREIGN_ASSET_INNER_JUNCTION), + foreign_initial_amount, + true, + ); + + // create non-sufficient foreign asset USDT + let usdt_initial_local_amount = 42; + let (_, usdt_chain_sovereign_account, usdt_id_multilocation) = + set_up_foreign_asset(USDT_PARA_ID, None, usdt_initial_local_amount, false); + + // transfer destination is BLA reserve location + let dest = reserve_location; + let dest_sovereign_account = foreign_sovereign_account; + + let (assets, fee_index, fee_asset, xfer_asset) = into_multiassets_checked( + // foreign asset BLA used for fees - destination reserve + (foreign_asset_id_multilocation, FEE_AMOUNT).into(), + // USDT to transfer - teleported + (usdt_id_multilocation, SEND_AMOUNT).into(), + ); + + // reanchor according to test-case + let context = UniversalLocation::get(); + let expected_fee = fee_asset.reanchored(&dest, context).unwrap(); + let expected_asset = xfer_asset.reanchored(&dest, context).unwrap(); + + // balances checks before + assert_eq!(Assets::balance(usdt_id_multilocation, ALICE), usdt_initial_local_amount); + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + + // do the transfer + let result = tested_call( + RuntimeOrigin::signed(ALICE), + Box::new(dest.into()), + Box::new(beneficiary.into()), + Box::new(assets.into()), + fee_index as u32, + Unlimited, + ); + assert_eq!(result, expected_result); + if expected_result.is_err() { + // short-circuit here for tests where we expect failure + return + } + + let weight = BaseXcmWeight::get() * 4; + let mut last_events = last_events(3).into_iter(); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Attempted { outcome: Outcome::Complete(weight) }) + ); + assert_eq!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::FeesPaid { + paying: origin_location, + fees: MultiAssets::new(), + }) + ); + assert!(matches!( + last_events.next().unwrap(), + RuntimeEvent::XcmPallet(crate::Event::Sent { .. }) + )); + // Alice native asset untouched + assert_eq!(Balances::free_balance(ALICE), INITIAL_BALANCE); + // Alice spent USDT for fees + assert_eq!( + Assets::balance(usdt_id_multilocation, ALICE), + usdt_initial_local_amount - SEND_AMOUNT + ); + // Alice transferred BLA + assert_eq!( + Assets::balance(foreign_asset_id_multilocation, ALICE), + foreign_initial_amount - FEE_AMOUNT + ); + // Verify balances of USDT reserve parachain + assert_eq!(Balances::free_balance(usdt_chain_sovereign_account.clone()), 0); + assert_eq!(Assets::balance(usdt_id_multilocation, usdt_chain_sovereign_account), 0); + // Verify balances of transferred-asset reserve parachain + assert_eq!(Balances::free_balance(dest_sovereign_account.clone()), 0); + assert_eq!(Assets::balance(foreign_asset_id_multilocation, dest_sovereign_account), 0); + // Verify total and active issuance of USDT have decreased (teleported) + let expected_usdt_issuance = usdt_initial_local_amount - SEND_AMOUNT; + assert_eq!(Assets::total_issuance(usdt_id_multilocation), expected_usdt_issuance); + assert_eq!(Assets::active_issuance(usdt_id_multilocation), expected_usdt_issuance); + // Verify total and active issuance of foreign BLA asset have decreased (burned on + // reserve-withdraw) + let expected_bla_issuance = foreign_initial_amount - FEE_AMOUNT; + assert_eq!(Assets::total_issuance(foreign_asset_id_multilocation), expected_bla_issuance); + assert_eq!(Assets::active_issuance(foreign_asset_id_multilocation), expected_bla_issuance); + + // Verify sent XCM program + assert_eq!( + sent_xcm(), + vec![( + dest, + Xcm(vec![ + // fees are withdrawn from origin's local SA + WithdrawAsset(expected_fee.clone().into()), + buy_limited_execution(expected_fee, Unlimited), + // assets are teleported to destination chain + ReceiveTeleportedAsset(expected_asset.into()), + ClearOrigin, + DepositAsset { assets: AllCounted(2).into(), beneficiary }, + ]) + )] + ); + }); +} + +/// Test `transfer_assets` with teleported asset reserve and destination fee. +#[test] +fn transfer_teleported_assets_using_destination_reserve_fee_works() { + let expected_result = Ok(()); + teleported_asset_using_destination_reserve_fee_call( + XcmPallet::transfer_assets, + expected_result, + ); +} + +/// Test `limited_reserve_transfer_assets` with teleported asset reserve and destination fee +/// disallowed. +#[test] +fn reserve_transfer_teleported_assets_using_destination_reserve_fee_disallowed() { + let expected_result = Err(DispatchError::Module(ModuleError { + index: 4, + error: [2, 0, 0, 0], + message: Some("Filtered"), + })); + teleported_asset_using_destination_reserve_fee_call( + XcmPallet::limited_reserve_transfer_assets, + expected_result, + ); +} + +/// Test `limited_teleport_assets` with teleported asset reserve and destination fee disallowed. +#[test] +fn teleport_assets_using_destination_reserve_fee_disallowed() { + let expected_result = Err(DispatchError::Module(ModuleError { + index: 4, + error: [2, 0, 0, 0], + message: Some("Filtered"), + })); + teleported_asset_using_destination_reserve_fee_call( + XcmPallet::limited_teleport_assets, + expected_result, + ); +} diff --git a/polkadot/xcm/pallet-xcm/src/tests/mod.rs b/polkadot/xcm/pallet-xcm/src/tests/mod.rs index 056c7dcc196..5829eb6edec 100644 --- a/polkadot/xcm/pallet-xcm/src/tests/mod.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/mod.rs @@ -16,7 +16,7 @@ #![cfg(test)] -mod assets_transfer; +pub(crate) mod assets_transfer; use crate::{ mock::*, AssetTraps, CurrentMigration, Error, LatestVersionedMultiLocation, Queries, diff --git a/prdoc/pr_2388.prdoc b/prdoc/pr_2388.prdoc new file mode 100644 index 00000000000..fa560197aff --- /dev/null +++ b/prdoc/pr_2388.prdoc @@ -0,0 +1,26 @@ +# Schema: Parity PR Documentation Schema (prdoc) +# See doc at https://github.com/paritytech/prdoc + +title: Add new flexible `pallet_xcm::transfer_assets()` call/extrinsic + +doc: + - audience: Builder + description: | + For complex combinations of asset transfers where assets and fees may have different reserves or + different reserve/teleport trust configurations, users can use the newly added `transfer_assets()` + extrinsic which is more flexible in allowing more complex scenarios. + The new extrinsic enables, for example, a (non-system) parachain to teleport their `ForeignAssets` + assets to `AssetHub` while using (reserve-based) `DOT` to pay fees. + notes: + - Now `(limited_)reserve_transfer_assets()` only allow reserve-based transfers for all assets + including fees, similarly `(limited_)teleport_assets()` only allows teleports for all assets + including fees. + +migrations: + db: [] + + runtime: [] + +crates: pallet-xcm + +host_functions: [] diff --git a/substrate/frame/assets/src/benchmarking.rs b/substrate/frame/assets/src/benchmarking.rs index c9b0825542d..f8495a1c8f2 100644 --- a/substrate/frame/assets/src/benchmarking.rs +++ b/substrate/frame/assets/src/benchmarking.rs @@ -54,7 +54,7 @@ fn create_default_asset, I: 'static>( (asset_id, caller, caller_lookup) } -fn create_default_minted_asset, I: 'static>( +pub fn create_default_minted_asset, I: 'static>( is_sufficient: bool, amount: T::Balance, ) -> (T::AssetIdParameter, T::AccountId, AccountIdLookupOf) { diff --git a/substrate/frame/assets/src/lib.rs b/substrate/frame/assets/src/lib.rs index 79e4fe30018..13aee138ad3 100644 --- a/substrate/frame/assets/src/lib.rs +++ b/substrate/frame/assets/src/lib.rs @@ -141,7 +141,7 @@ #![cfg_attr(not(feature = "std"), no_std)] #[cfg(feature = "runtime-benchmarks")] -mod benchmarking; +pub mod benchmarking; pub mod migration; #[cfg(test)] pub mod mock; -- GitLab From be500fc2022cbde6e66abec0b8f20175b24652d1 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Wed, 6 Dec 2023 18:05:05 +0100 Subject: [PATCH 09/59] Bridges subtree update (#2602) ## Summary This PR aligns Rococo/Westend bridge with latest Bridges repo development: - https://github.com/paritytech/parity-bridges-common/pull/2727 - https://github.com/paritytech/parity-bridges-common/pull/2728 - https://github.com/paritytech/parity-bridges-common/pull/2729 Part of: https://github.com/paritytech/parity-bridges-common/issues/2452 --- Cargo.lock | 36 ++ Cargo.toml | 2 + bridges/bin/runtime-common/Cargo.toml | 2 + .../src/messages_xcm_extension.rs | 109 +++--- bridges/bin/runtime-common/src/mock.rs | 4 +- bridges/modules/grandpa/src/call_ext.rs | 29 +- bridges/modules/grandpa/src/mock.rs | 4 +- bridges/modules/parachains/src/mock.rs | 8 +- bridges/modules/xcm-bridge-hub/Cargo.toml | 74 ++++ .../modules/xcm-bridge-hub/src/exporter.rs | 208 +++++++++++ bridges/modules/xcm-bridge-hub/src/lib.rs | 96 +++++ bridges/modules/xcm-bridge-hub/src/mock.rs | 328 ++++++++++++++++++ bridges/primitives/chain-kusama/src/lib.rs | 4 +- .../chain-polkadot-bulletin/src/lib.rs | 8 +- bridges/primitives/chain-polkadot/src/lib.rs | 4 +- bridges/primitives/chain-rococo/src/lib.rs | 4 +- bridges/primitives/chain-westend/src/lib.rs | 4 +- .../header-chain/src/justification/mod.rs | 4 +- bridges/primitives/header-chain/src/lib.rs | 93 ++++- bridges/primitives/polkadot-core/src/lib.rs | 18 +- bridges/primitives/xcm-bridge-hub/Cargo.toml | 16 + bridges/primitives/xcm-bridge-hub/src/lib.rs | 24 ++ .../bridge-hub-rococo/src/tests/send_xcm.rs | 37 +- .../bridge-hub-westend/src/tests/send_xcm.rs | 37 +- .../bridge-hubs/bridge-hub-rococo/Cargo.toml | 4 + .../src/bridge_to_westend_config.rs | 50 ++- .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 10 +- .../bridge-hub-rococo/tests/tests.rs | 2 +- .../bridge-hubs/bridge-hub-westend/Cargo.toml | 6 + .../src/bridge_to_rococo_config.rs | 49 ++- .../bridge-hubs/bridge-hub-westend/src/lib.rs | 9 +- .../bridge-hub-westend/tests/tests.rs | 2 +- .../bridge-hubs/test-utils/src/test_cases.rs | 4 +- 33 files changed, 1057 insertions(+), 232 deletions(-) create mode 100644 bridges/modules/xcm-bridge-hub/Cargo.toml create mode 100644 bridges/modules/xcm-bridge-hub/src/exporter.rs create mode 100644 bridges/modules/xcm-bridge-hub/src/lib.rs create mode 100644 bridges/modules/xcm-bridge-hub/src/mock.rs create mode 100644 bridges/primitives/xcm-bridge-hub/Cargo.toml create mode 100644 bridges/primitives/xcm-bridge-hub/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index f2693730b91..a37d24d50a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1817,6 +1817,13 @@ dependencies = [ "sp-std 8.0.0", ] +[[package]] +name = "bp-xcm-bridge-hub" +version = "0.1.0" +dependencies = [ + "sp-std 8.0.0", +] + [[package]] name = "bp-xcm-bridge-hub-router" version = "0.1.0" @@ -1915,6 +1922,7 @@ dependencies = [ "pallet-utility", "pallet-xcm", "pallet-xcm-benchmarks", + "pallet-xcm-bridge-hub", "parachains-common", "parity-scale-codec", "polkadot-core-primitives", @@ -2032,6 +2040,7 @@ dependencies = [ name = "bridge-hub-westend-runtime" version = "0.1.0" dependencies = [ + "bp-asset-hub-rococo", "bp-asset-hub-westend", "bp-bridge-hub-rococo", "bp-bridge-hub-westend", @@ -2078,6 +2087,7 @@ dependencies = [ "pallet-utility", "pallet-xcm", "pallet-xcm-benchmarks", + "pallet-xcm-bridge-hub", "parachains-common", "parity-scale-codec", "polkadot-core-primitives", @@ -2121,6 +2131,7 @@ dependencies = [ "bp-relayers", "bp-runtime", "bp-test-utils", + "bp-xcm-bridge-hub", "bp-xcm-bridge-hub-router", "frame-support", "frame-system", @@ -11072,6 +11083,31 @@ dependencies = [ "staging-xcm-executor", ] +[[package]] +name = "pallet-xcm-bridge-hub" +version = "0.1.0" +dependencies = [ + "bp-header-chain", + "bp-messages", + "bp-runtime", + "bp-xcm-bridge-hub", + "bridge-runtime-common", + "frame-support", + "frame-system", + "log", + "pallet-balances", + "pallet-bridge-messages", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 8.0.0", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", +] + [[package]] name = "pallet-xcm-bridge-hub-router" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index b694afb3f5e..85ba2c5bc93 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ members = [ "bridges/modules/messages", "bridges/modules/parachains", "bridges/modules/relayers", + "bridges/modules/xcm-bridge-hub", "bridges/modules/xcm-bridge-hub-router", "bridges/primitives/chain-asset-hub-rococo", "bridges/primitives/chain-asset-hub-westend", @@ -33,6 +34,7 @@ members = [ "bridges/primitives/relayers", "bridges/primitives/runtime", "bridges/primitives/test-utils", + "bridges/primitives/xcm-bridge-hub", "bridges/primitives/xcm-bridge-hub-router", "cumulus/client/cli", "cumulus/client/collator", diff --git a/bridges/bin/runtime-common/Cargo.toml b/bridges/bin/runtime-common/Cargo.toml index a5aa53f2633..bac54a0a7a2 100644 --- a/bridges/bin/runtime-common/Cargo.toml +++ b/bridges/bin/runtime-common/Cargo.toml @@ -22,6 +22,7 @@ bp-parachains = { path = "../../primitives/parachains", default-features = false bp-polkadot-core = { path = "../../primitives/polkadot-core", default-features = false } bp-relayers = { path = "../../primitives/relayers", default-features = false } bp-runtime = { path = "../../primitives/runtime", default-features = false } +bp-xcm-bridge-hub = { path = "../../primitives/xcm-bridge-hub", default-features = false } bp-xcm-bridge-hub-router = { path = "../../primitives/xcm-bridge-hub-router", default-features = false } pallet-bridge-grandpa = { path = "../../modules/grandpa", default-features = false } pallet-bridge-messages = { path = "../../modules/messages", default-features = false } @@ -59,6 +60,7 @@ std = [ "bp-relayers/std", "bp-runtime/std", "bp-xcm-bridge-hub-router/std", + "bp-xcm-bridge-hub/std", "codec/std", "frame-support/std", "frame-system/std", diff --git a/bridges/bin/runtime-common/src/messages_xcm_extension.rs b/bridges/bin/runtime-common/src/messages_xcm_extension.rs index 77c23db3b2b..0159ede6481 100644 --- a/bridges/bin/runtime-common/src/messages_xcm_extension.rs +++ b/bridges/bin/runtime-common/src/messages_xcm_extension.rs @@ -22,26 +22,23 @@ //! `XcmRouter` <- `MessageDispatch` <- `InboundMessageQueue` use bp_messages::{ - source_chain::{MessagesBridge, OnMessagesDelivered}, + source_chain::OnMessagesDelivered, target_chain::{DispatchMessage, MessageDispatch}, LaneId, MessageNonce, }; use bp_runtime::messages::MessageDispatchResult; +pub use bp_xcm_bridge_hub::XcmAsPlainPayload; use bp_xcm_bridge_hub_router::XcmChannelStatusProvider; use codec::{Decode, Encode}; use frame_support::{traits::Get, weights::Weight, CloneNoBound, EqNoBound, PartialEqNoBound}; use pallet_bridge_messages::{ - Config as MessagesConfig, OutboundLanesCongestedSignals, Pallet as MessagesPallet, - WeightInfoExt as MessagesPalletWeights, + Config as MessagesConfig, OutboundLanesCongestedSignals, WeightInfoExt as MessagesPalletWeights, }; use scale_info::TypeInfo; use sp_runtime::SaturatedConversion; use sp_std::{fmt::Debug, marker::PhantomData}; use xcm::prelude::*; -use xcm_builder::{DispatchBlob, DispatchBlobError, HaulBlob, HaulBlobError}; - -/// Plain "XCM" payload, which we transfer through bridge -pub type XcmAsPlainPayload = sp_std::prelude::Vec; +use xcm_builder::{DispatchBlob, DispatchBlobError}; /// Message dispatch result type for single message #[derive(CloneNoBound, EqNoBound, PartialEqNoBound, Encode, Decode, Debug, TypeInfo)] @@ -123,6 +120,7 @@ impl< /// A pair of sending chain location and message lane, used by this chain to send messages /// over the bridge. +#[cfg_attr(feature = "std", derive(Debug, Eq, PartialEq))] pub struct SenderAndLane { /// Sending chain relative location. pub location: MultiLocation, @@ -144,8 +142,6 @@ pub trait XcmBlobHauler { type Runtime: MessagesConfig; /// Instance of the messages pallet that is used to send messages. type MessagesInstance: 'static; - /// Returns lane used by this hauler. - type SenderAndLane: Get; /// Actual XCM message sender (`HRMP` or `UMP`) to the source chain /// location (`Self::SenderAndLane::get().location`). @@ -166,54 +162,25 @@ pub trait XcmBlobHauler { /// makes sure that XCM blob is sent to the outbound lane to be relayed. /// /// It needs to be used at the source bridge hub. -pub struct XcmBlobHaulerAdapter(sp_std::marker::PhantomData); +pub struct XcmBlobHaulerAdapter( + sp_std::marker::PhantomData<(XcmBlobHauler, Lanes)>, +); -impl HaulBlob for XcmBlobHaulerAdapter -where - H::Runtime: MessagesConfig, +impl< + H: XcmBlobHauler, + Lanes: Get>, + > OnMessagesDelivered for XcmBlobHaulerAdapter { - fn haul_blob(blob: sp_std::prelude::Vec) -> Result<(), HaulBlobError> { - let sender_and_lane = H::SenderAndLane::get(); - MessagesPallet::::send_message(sender_and_lane.lane, blob) - .map(|artifacts| { - log::info!( - target: crate::LOG_TARGET_BRIDGE_DISPATCH, - "haul_blob result - ok: {:?} on lane: {:?}. Enqueued messages: {}", - artifacts.nonce, - sender_and_lane.lane, - artifacts.enqueued_messages, - ); - - // notify XCM queue manager about updated lane state - LocalXcmQueueManager::::on_bridge_message_enqueued( - &sender_and_lane, - artifacts.enqueued_messages, - ); - }) - .map_err(|error| { - log::error!( - target: crate::LOG_TARGET_BRIDGE_DISPATCH, - "haul_blob result - error: {:?} on lane: {:?}", - error, - sender_and_lane.lane, - ); - HaulBlobError::Transport("MessageSenderError") - }) - } -} - -impl OnMessagesDelivered for XcmBlobHaulerAdapter { fn on_messages_delivered(lane: LaneId, enqueued_messages: MessageNonce) { - let sender_and_lane = H::SenderAndLane::get(); - if sender_and_lane.lane != lane { - return + if let Some(sender_and_lane) = + Lanes::get().iter().find(|link| link.0.lane == lane).map(|link| &link.0) + { + // notify XCM queue manager about updated lane state + LocalXcmQueueManager::::on_bridge_messages_delivered( + sender_and_lane, + enqueued_messages, + ); } - - // notify XCM queue manager about updated lane state - LocalXcmQueueManager::::on_bridge_messages_delivered( - &sender_and_lane, - enqueued_messages, - ); } } @@ -356,6 +323,9 @@ mod tests { location: MultiLocation::new(1, X1(Parachain(1000))), lane: TEST_LANE_ID, }; + pub TestLanes: sp_std::vec::Vec<(SenderAndLane, (NetworkId, InteriorMultiLocation))> = sp_std::vec![ + (TestSenderAndLane::get(), (NetworkId::ByGenesis([0; 32]), InteriorMultiLocation::Here)) + ]; pub DummyXcmMessage: Xcm<()> = Xcm::new(); } @@ -389,37 +359,44 @@ mod tests { impl XcmBlobHauler for TestBlobHauler { type Runtime = TestRuntime; type MessagesInstance = (); - type SenderAndLane = TestSenderAndLane; type ToSourceChainSender = DummySendXcm; type CongestedMessage = DummyXcmMessage; type UncongestedMessage = DummyXcmMessage; } - type TestBlobHaulerAdapter = XcmBlobHaulerAdapter; + type TestBlobHaulerAdapter = XcmBlobHaulerAdapter; - fn fill_up_lane_to_congestion() { + fn fill_up_lane_to_congestion() -> MessageNonce { + let latest_generated_nonce = OUTBOUND_LANE_CONGESTED_THRESHOLD; OutboundLanes::::insert( TEST_LANE_ID, OutboundLaneData { oldest_unpruned_nonce: 0, latest_received_nonce: 0, - latest_generated_nonce: OUTBOUND_LANE_CONGESTED_THRESHOLD, + latest_generated_nonce, }, ); + latest_generated_nonce } #[test] fn congested_signal_is_not_sent_twice() { run_test(|| { - fill_up_lane_to_congestion(); + let enqueued = fill_up_lane_to_congestion(); // next sent message leads to congested signal - TestBlobHaulerAdapter::haul_blob(vec![42]).unwrap(); + LocalXcmQueueManager::::on_bridge_message_enqueued( + &TestSenderAndLane::get(), + enqueued + 1, + ); assert_eq!(DummySendXcm::messages_sent(), 1); // next sent message => we don't sent another congested signal - TestBlobHaulerAdapter::haul_blob(vec![42]).unwrap(); + LocalXcmQueueManager::::on_bridge_message_enqueued( + &TestSenderAndLane::get(), + enqueued, + ); assert_eq!(DummySendXcm::messages_sent(), 1); }); } @@ -427,7 +404,10 @@ mod tests { #[test] fn congested_signal_is_not_sent_when_outbound_lane_is_not_congested() { run_test(|| { - TestBlobHaulerAdapter::haul_blob(vec![42]).unwrap(); + LocalXcmQueueManager::::on_bridge_message_enqueued( + &TestSenderAndLane::get(), + 1, + ); assert_eq!(DummySendXcm::messages_sent(), 0); }); } @@ -435,10 +415,13 @@ mod tests { #[test] fn congested_signal_is_sent_when_outbound_lane_is_congested() { run_test(|| { - fill_up_lane_to_congestion(); + let enqueued = fill_up_lane_to_congestion(); // next sent message leads to congested signal - TestBlobHaulerAdapter::haul_blob(vec![42]).unwrap(); + LocalXcmQueueManager::::on_bridge_message_enqueued( + &TestSenderAndLane::get(), + enqueued + 1, + ); assert_eq!(DummySendXcm::messages_sent(), 1); assert!(LocalXcmQueueManager::::is_congested_signal_sent(TEST_LANE_ID)); }); diff --git a/bridges/bin/runtime-common/src/mock.rs b/bridges/bin/runtime-common/src/mock.rs index ffabf7f6e2f..bd47d37fc07 100644 --- a/bridges/bin/runtime-common/src/mock.rs +++ b/bridges/bin/runtime-common/src/mock.rs @@ -376,8 +376,8 @@ impl ChainWithGrandpa for BridgedUnderlyingChain { const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = ""; const MAX_AUTHORITIES_COUNT: u32 = 16; const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 = 8; - const MAX_HEADER_SIZE: u32 = 256; - const AVERAGE_HEADER_SIZE_IN_JUSTIFICATION: u32 = 64; + const MAX_MANDATORY_HEADER_SIZE: u32 = 256; + const AVERAGE_HEADER_SIZE: u32 = 64; } impl Chain for BridgedUnderlyingParachain { diff --git a/bridges/modules/grandpa/src/call_ext.rs b/bridges/modules/grandpa/src/call_ext.rs index f238064f92b..c1585020be1 100644 --- a/bridges/modules/grandpa/src/call_ext.rs +++ b/bridges/modules/grandpa/src/call_ext.rs @@ -15,7 +15,10 @@ // along with Parity Bridges Common. If not, see . use crate::{weights::WeightInfo, BridgedBlockNumber, BridgedHeader, Config, Error, Pallet}; -use bp_header_chain::{justification::GrandpaJustification, ChainWithGrandpa}; +use bp_header_chain::{ + justification::GrandpaJustification, max_expected_submit_finality_proof_arguments_size, + ChainWithGrandpa, GrandpaConsensusLogReader, +}; use bp_runtime::{BlockNumberOf, OwnedBridgeModule}; use codec::Encode; use frame_support::{dispatch::CallableCallFor, traits::IsSubType, weights::Weight}; @@ -169,28 +172,28 @@ pub(crate) fn submit_finality_proof_info_from_args, I: 'static>( Weight::zero() }; + // check if the `finality_target` is a mandatory header. If so, we are ready to refund larger + // size + let is_mandatory_finality_target = + GrandpaConsensusLogReader::>::find_scheduled_change( + finality_target.digest(), + ) + .is_some(); + // we can estimate extra call size easily, without any additional significant overhead let actual_call_size: u32 = finality_target .encoded_size() .saturating_add(justification.encoded_size()) .saturated_into(); - let max_expected_call_size = max_expected_call_size::(required_precommits); + let max_expected_call_size = max_expected_submit_finality_proof_arguments_size::( + is_mandatory_finality_target, + required_precommits, + ); let extra_size = actual_call_size.saturating_sub(max_expected_call_size); SubmitFinalityProofInfo { block_number, extra_weight, extra_size } } -/// Returns maximal expected size of `submit_finality_proof` call arguments. -fn max_expected_call_size, I: 'static>(required_precommits: u32) -> u32 { - let max_expected_justification_size = - GrandpaJustification::>::max_reasonable_size::( - required_precommits, - ); - - // call arguments are header and justification - T::BridgedChain::MAX_HEADER_SIZE.saturating_add(max_expected_justification_size) -} - #[cfg(test)] mod tests { use crate::{ diff --git a/bridges/modules/grandpa/src/mock.rs b/bridges/modules/grandpa/src/mock.rs index 7efa84971fe..a54f56c4a62 100644 --- a/bridges/modules/grandpa/src/mock.rs +++ b/bridges/modules/grandpa/src/mock.rs @@ -86,8 +86,8 @@ impl ChainWithGrandpa for TestBridgedChain { const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = ""; const MAX_AUTHORITIES_COUNT: u32 = MAX_BRIDGED_AUTHORITIES; const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 = 8; - const MAX_HEADER_SIZE: u32 = 256; - const AVERAGE_HEADER_SIZE_IN_JUSTIFICATION: u32 = 64; + const MAX_MANDATORY_HEADER_SIZE: u32 = 256; + const AVERAGE_HEADER_SIZE: u32 = 64; } /// Return test externalities to use in tests. diff --git a/bridges/modules/parachains/src/mock.rs b/bridges/modules/parachains/src/mock.rs index d95e76f3108..1c7851364d1 100644 --- a/bridges/modules/parachains/src/mock.rs +++ b/bridges/modules/parachains/src/mock.rs @@ -252,8 +252,8 @@ impl ChainWithGrandpa for TestBridgedChain { const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = ""; const MAX_AUTHORITIES_COUNT: u32 = 16; const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 = 8; - const MAX_HEADER_SIZE: u32 = 256; - const AVERAGE_HEADER_SIZE_IN_JUSTIFICATION: u32 = 64; + const MAX_MANDATORY_HEADER_SIZE: u32 = 256; + const AVERAGE_HEADER_SIZE: u32 = 64; } #[derive(Debug)] @@ -283,8 +283,8 @@ impl ChainWithGrandpa for OtherBridgedChain { const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = ""; const MAX_AUTHORITIES_COUNT: u32 = 16; const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 = 8; - const MAX_HEADER_SIZE: u32 = 256; - const AVERAGE_HEADER_SIZE_IN_JUSTIFICATION: u32 = 64; + const MAX_MANDATORY_HEADER_SIZE: u32 = 256; + const AVERAGE_HEADER_SIZE: u32 = 64; } /// Return test externalities to use in tests. diff --git a/bridges/modules/xcm-bridge-hub/Cargo.toml b/bridges/modules/xcm-bridge-hub/Cargo.toml new file mode 100644 index 00000000000..03ef18170ae --- /dev/null +++ b/bridges/modules/xcm-bridge-hub/Cargo.toml @@ -0,0 +1,74 @@ +[package] +name = "pallet-xcm-bridge-hub" +description = "Module that adds dynamic bridges/lanes support to XCM infrastucture at the bridge hub." +version = "0.1.0" +authors.workspace = true +edition.workspace = true +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } +log = { version = "0.4.20", default-features = false } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } + +# Bridge Dependencies +bp-messages = { path = "../../primitives/messages", default-features = false } +bp-runtime = { path = "../../primitives/runtime", default-features = false } +bp-xcm-bridge-hub = { path = "../../primitives/xcm-bridge-hub", default-features = false } +pallet-bridge-messages = { path = "../messages", default-features = false } +bridge-runtime-common = { path = "../../bin/runtime-common", default-features = false } + +# Substrate Dependencies +frame-support = { path = "../../../substrate/frame/support", default-features = false } +frame-system = { path = "../../../substrate/frame/system", default-features = false } +sp-core = { path = "../../../substrate/primitives/core", default-features = false } +sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } +sp-std = { path = "../../../substrate/primitives/std", default-features = false } + +# Polkadot Dependencies +xcm = { package = "staging-xcm", path = "../../../polkadot/xcm", default-features = false } +xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot/xcm/xcm-builder", default-features = false } +xcm-executor = { package = "staging-xcm-executor", path = "../../../polkadot/xcm/xcm-executor", default-features = false } + +[dev-dependencies] +bp-header-chain = { path = "../../primitives/header-chain" } +pallet-balances = { path = "../../../substrate/frame/balances" } +sp-io = { path = "../../../substrate/primitives/io" } + +[features] +default = ["std"] +std = [ + "bp-messages/std", + "bp-runtime/std", + "bp-xcm-bridge-hub/std", + "bridge-runtime-common/std", + "codec/std", + "frame-support/std", + "frame-system/std", + "log/std", + "pallet-bridge-messages/std", + "scale-info/std", + "sp-core/std", + "sp-runtime/std", + "sp-std/std", + "xcm-builder/std", + "xcm-executor/std", + "xcm/std", +] +runtime-benchmarks = [ + "bridge-runtime-common/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-bridge-messages/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", + "xcm-executor/runtime-benchmarks", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", + "pallet-balances/try-runtime", + "pallet-bridge-messages/try-runtime", + "sp-runtime/try-runtime", +] diff --git a/bridges/modules/xcm-bridge-hub/src/exporter.rs b/bridges/modules/xcm-bridge-hub/src/exporter.rs new file mode 100644 index 00000000000..445551d6934 --- /dev/null +++ b/bridges/modules/xcm-bridge-hub/src/exporter.rs @@ -0,0 +1,208 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! The code that allows to use the pallet (`pallet-xcm-bridge-hub`) as XCM message +//! exporter at the sending bridge hub. Internally, it just enqueues outbound blob +//! in the messages pallet queue. +//! +//! This code is executed at the source bridge hub. + +use crate::{Config, Pallet, LOG_TARGET}; + +use bp_messages::source_chain::MessagesBridge; +use bp_xcm_bridge_hub::XcmAsPlainPayload; +use bridge_runtime_common::messages_xcm_extension::{LocalXcmQueueManager, SenderAndLane}; +use pallet_bridge_messages::{Config as BridgeMessagesConfig, Pallet as BridgeMessagesPallet}; +use xcm::prelude::*; +use xcm_builder::{HaulBlob, HaulBlobError, HaulBlobExporter}; +use xcm_executor::traits::ExportXcm; + +/// An easy way to access `HaulBlobExporter`. +pub type PalletAsHaulBlobExporter = HaulBlobExporter< + DummyHaulBlob, + >::BridgedNetworkId, + >::MessageExportPrice, +>; +/// An easy way to access associated messages pallet. +type MessagesPallet = BridgeMessagesPallet>::BridgeMessagesPalletInstance>; + +impl, I: 'static> ExportXcm for Pallet +where + T: BridgeMessagesConfig< + >::BridgeMessagesPalletInstance, + OutboundPayload = XcmAsPlainPayload, + >, +{ + type Ticket = (SenderAndLane, XcmAsPlainPayload, XcmHash); + + fn validate( + network: NetworkId, + channel: u32, + universal_source: &mut Option, + destination: &mut Option, + message: &mut Option>, + ) -> Result<(Self::Ticket, MultiAssets), SendError> { + // Find supported lane_id. + let sender_and_lane = Self::lane_for( + universal_source.as_ref().ok_or(SendError::MissingArgument)?, + (&network, destination.as_ref().ok_or(SendError::MissingArgument)?), + ) + .ok_or(SendError::NotApplicable)?; + + // check if we are able to route the message. We use existing `HaulBlobExporter` for that. + // It will make all required changes and will encode message properly, so that the + // `DispatchBlob` at the bridged bridge hub will be able to decode it + let ((blob, id), price) = PalletAsHaulBlobExporter::::validate( + network, + channel, + universal_source, + destination, + message, + )?; + + Ok(((sender_and_lane, blob, id), price)) + } + + fn deliver( + (sender_and_lane, blob, id): (SenderAndLane, XcmAsPlainPayload, XcmHash), + ) -> Result { + let lane_id = sender_and_lane.lane; + let send_result = MessagesPallet::::send_message(lane_id, blob); + + match send_result { + Ok(artifacts) => { + log::info!( + target: LOG_TARGET, + "XCM message {:?} has been enqueued at bridge {:?} with nonce {}", + id, + lane_id, + artifacts.nonce, + ); + + // notify XCM queue manager about updated lane state + LocalXcmQueueManager::::on_bridge_message_enqueued( + &sender_and_lane, + artifacts.enqueued_messages, + ); + }, + Err(error) => { + log::debug!( + target: LOG_TARGET, + "XCM message {:?} has been dropped because of bridge error {:?} on bridge {:?}", + id, + error, + lane_id, + ); + return Err(SendError::Transport("BridgeSendError")) + }, + } + + Ok(id) + } +} + +/// Dummy implementation of the `HaulBlob` trait that is never called. +/// +/// We are using `HaulBlobExporter`, which requires `HaulBlob` implementation. It assumes that +/// there's a single channel between two bridge hubs - `HaulBlob` only accepts the blob and nothing +/// else. But bridge messages pallet may have a dedicated channel (lane) for every pair of bridged +/// chains. So we are using our own `ExportXcm` implementation, but to utilize `HaulBlobExporter` we +/// still need this `DummyHaulBlob`. +pub struct DummyHaulBlob; + +impl HaulBlob for DummyHaulBlob { + fn haul_blob(_blob: XcmAsPlainPayload) -> Result<(), HaulBlobError> { + Err(HaulBlobError::Transport("DummyHaulBlob")) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::mock::*; + use frame_support::assert_ok; + use xcm_executor::traits::export_xcm; + + fn universal_source() -> InteriorMultiLocation { + X2(GlobalConsensus(RelayNetwork::get()), Parachain(SIBLING_ASSET_HUB_ID)) + } + + fn universal_destination() -> InteriorMultiLocation { + BridgedDestination::get() + } + + #[test] + fn export_works() { + run_test(|| { + assert_ok!(export_xcm::( + BridgedRelayNetwork::get(), + 0, + universal_source(), + universal_destination(), + vec![Instruction::ClearOrigin].into(), + )); + }) + } + + #[test] + fn export_fails_if_argument_is_missing() { + run_test(|| { + assert_eq!( + XcmOverBridge::validate( + BridgedRelayNetwork::get(), + 0, + &mut None, + &mut Some(universal_destination()), + &mut Some(Vec::new().into()), + ), + Err(SendError::MissingArgument), + ); + + assert_eq!( + XcmOverBridge::validate( + BridgedRelayNetwork::get(), + 0, + &mut Some(universal_source()), + &mut None, + &mut Some(Vec::new().into()), + ), + Err(SendError::MissingArgument), + ); + }) + } + + #[test] + fn exporter_computes_correct_lane_id() { + run_test(|| { + let expected_lane_id = TEST_LANE_ID; + + assert_eq!( + XcmOverBridge::validate( + BridgedRelayNetwork::get(), + 0, + &mut Some(universal_source()), + &mut Some(universal_destination()), + &mut Some(Vec::new().into()), + ) + .unwrap() + .0 + .0 + .lane, + expected_lane_id, + ); + }) + } +} diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs new file mode 100644 index 00000000000..14439a4d8ff --- /dev/null +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -0,0 +1,96 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! Module that adds XCM support to bridge pallets. + +#![warn(missing_docs)] +#![cfg_attr(not(feature = "std"), no_std)] + +use bridge_runtime_common::messages_xcm_extension::XcmBlobHauler; +use pallet_bridge_messages::Config as BridgeMessagesConfig; +use xcm::prelude::*; + +pub use exporter::PalletAsHaulBlobExporter; +pub use pallet::*; + +mod exporter; +mod mock; + +/// The target that will be used when publishing logs related to this pallet. +pub const LOG_TARGET: &str = "runtime::bridge-xcm"; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use bridge_runtime_common::messages_xcm_extension::SenderAndLane; + use frame_support::pallet_prelude::*; + + #[pallet::config] + #[pallet::disable_frame_system_supertrait_check] + pub trait Config: + BridgeMessagesConfig + { + /// Runtime's universal location. + type UniversalLocation: Get; + // TODO: https://github.com/paritytech/parity-bridges-common/issues/1666 remove `ChainId` and + // replace it with the `NetworkId` - then we'll be able to use + // `T as pallet_bridge_messages::Config::BridgedChain::NetworkId` + /// Bridged network id. + #[pallet::constant] + type BridgedNetworkId: Get; + /// Associated messages pallet instance that bridges us with the + /// `BridgedNetworkId` consensus. + type BridgeMessagesPalletInstance: 'static; + + /// Price of single message export to the bridged consensus (`Self::BridgedNetworkId`). + type MessageExportPrice: Get; + + /// Get point-to-point links with bridged consensus (`Self::BridgedNetworkId`). + /// (this will be replaced with dynamic on-chain bridges - `Bridges V2`) + type Lanes: Get>; + /// Support for point-to-point links + /// (this will be replaced with dynamic on-chain bridges - `Bridges V2`) + type LanesSupport: XcmBlobHauler; + } + + #[pallet::pallet] + pub struct Pallet(PhantomData<(T, I)>); + + impl, I: 'static> Pallet { + /// Returns dedicated/configured lane identifier. + pub(crate) fn lane_for( + source: &InteriorMultiLocation, + dest: (&NetworkId, &InteriorMultiLocation), + ) -> Option { + let source = source.relative_to(&T::UniversalLocation::get()); + + // Check that we have configured a point-to-point lane for 'source' and `dest`. + T::Lanes::get() + .into_iter() + .find_map(|(lane_source, (lane_dest_network, lane_dest))| { + if lane_source.location == source && + &lane_dest_network == dest.0 && + &T::BridgedNetworkId::get() == dest.0 && + &lane_dest == dest.1 + { + Some(lane_source) + } else { + None + } + }) + } + } +} diff --git a/bridges/modules/xcm-bridge-hub/src/mock.rs b/bridges/modules/xcm-bridge-hub/src/mock.rs new file mode 100644 index 00000000000..7766aac1fb7 --- /dev/null +++ b/bridges/modules/xcm-bridge-hub/src/mock.rs @@ -0,0 +1,328 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +#![cfg(test)] + +use crate as pallet_xcm_bridge_hub; + +use bp_messages::{ + source_chain::LaneMessageVerifier, + target_chain::{DispatchMessage, MessageDispatch}, + LaneId, OutboundLaneData, VerificationError, +}; +use bp_runtime::{messages::MessageDispatchResult, Chain, UnderlyingChainProvider}; +use bridge_runtime_common::{ + messages::{ + source::TargetHeaderChainAdapter, target::SourceHeaderChainAdapter, + BridgedChainWithMessages, HashOf, MessageBridge, ThisChainWithMessages, + }, + messages_xcm_extension::{SenderAndLane, XcmBlobHauler}, +}; +use codec::Encode; +use frame_support::{derive_impl, parameter_types, traits::ConstU32, weights::RuntimeDbWeight}; +use sp_core::H256; +use sp_runtime::{ + testing::Header as SubstrateHeader, + traits::{BlakeTwo256, IdentityLookup}, + AccountId32, BuildStorage, +}; +use xcm::prelude::*; + +pub type AccountId = AccountId32; +pub type Balance = u64; + +type Block = frame_system::mocking::MockBlock; + +pub const SIBLING_ASSET_HUB_ID: u32 = 2001; +pub const THIS_BRIDGE_HUB_ID: u32 = 2002; +pub const BRIDGED_ASSET_HUB_ID: u32 = 1001; +pub const TEST_LANE_ID: LaneId = LaneId([0, 0, 0, 1]); + +frame_support::construct_runtime! { + pub enum TestRuntime { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Balances: pallet_balances::{Pallet, Event}, + Messages: pallet_bridge_messages::{Pallet, Call, Event}, + XcmOverBridge: pallet_xcm_bridge_hub::{Pallet}, + } +} + +parameter_types! { + pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { read: 1, write: 2 }; + pub const ExistentialDeposit: Balance = 1; +} + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for TestRuntime { + type AccountId = AccountId; + type AccountData = pallet_balances::AccountData; + type Block = Block; + type Lookup = IdentityLookup; +} + +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig as pallet_balances::DefaultConfig)] +impl pallet_balances::Config for TestRuntime { + type AccountStore = System; +} + +/// Lane message verifier that is used in tests. +#[derive(Debug, Default)] +pub struct TestLaneMessageVerifier; + +impl LaneMessageVerifier> for TestLaneMessageVerifier { + fn verify_message( + _lane: &LaneId, + _lane_outbound_data: &OutboundLaneData, + _payload: &Vec, + ) -> Result<(), VerificationError> { + Ok(()) + } +} + +parameter_types! { + pub const ActiveOutboundLanes: &'static [LaneId] = &[TEST_LANE_ID]; +} + +impl pallet_bridge_messages::Config for TestRuntime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = TestMessagesWeights; + + type BridgedChainId = (); + type ActiveOutboundLanes = ActiveOutboundLanes; + type MaxUnrewardedRelayerEntriesAtInboundLane = (); + type MaxUnconfirmedMessagesAtInboundLane = (); + type MaximalOutboundPayloadSize = ConstU32<2048>; + type OutboundPayload = Vec; + type InboundPayload = Vec; + type InboundRelayer = (); + type DeliveryPayments = (); + type TargetHeaderChain = TargetHeaderChainAdapter; + type LaneMessageVerifier = TestLaneMessageVerifier; + type DeliveryConfirmationPayments = (); + type OnMessagesDelivered = (); + type SourceHeaderChain = SourceHeaderChainAdapter; + type MessageDispatch = TestMessageDispatch; +} + +pub struct TestMessagesWeights; + +impl pallet_bridge_messages::WeightInfo for TestMessagesWeights { + fn receive_single_message_proof() -> Weight { + Weight::zero() + } + fn receive_single_message_proof_with_outbound_lane_state() -> Weight { + Weight::zero() + } + fn receive_delivery_proof_for_single_message() -> Weight { + Weight::zero() + } + fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { + Weight::zero() + } + fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { + Weight::zero() + } + + fn receive_two_messages_proof() -> Weight { + Weight::zero() + } + + fn receive_single_message_proof_1_kb() -> Weight { + Weight::zero() + } + + fn receive_single_message_proof_16_kb() -> Weight { + Weight::zero() + } + + fn receive_single_message_proof_with_dispatch(_: u32) -> Weight { + Weight::from_parts(1, 0) + } +} + +impl pallet_bridge_messages::WeightInfoExt for TestMessagesWeights { + fn expected_extra_storage_proof_size() -> u32 { + 0 + } + + fn receive_messages_proof_overhead_from_runtime() -> Weight { + Weight::zero() + } + + fn receive_messages_delivery_proof_overhead_from_runtime() -> Weight { + Weight::zero() + } +} + +parameter_types! { + pub const RelayNetwork: NetworkId = NetworkId::Kusama; + pub const BridgedRelayNetwork: NetworkId = NetworkId::Polkadot; + pub const NonBridgedRelayNetwork: NetworkId = NetworkId::Rococo; + pub const BridgeReserve: Balance = 100_000; + pub UniversalLocation: InteriorMultiLocation = X2( + GlobalConsensus(RelayNetwork::get()), + Parachain(THIS_BRIDGE_HUB_ID), + ); + pub const Penalty: Balance = 1_000; +} + +impl pallet_xcm_bridge_hub::Config for TestRuntime { + type UniversalLocation = UniversalLocation; + type BridgedNetworkId = BridgedRelayNetwork; + type BridgeMessagesPalletInstance = (); + + type MessageExportPrice = (); + type Lanes = TestLanes; + type LanesSupport = TestXcmBlobHauler; +} + +parameter_types! { + pub TestSenderAndLane: SenderAndLane = SenderAndLane { + location: MultiLocation::new(1, X1(Parachain(SIBLING_ASSET_HUB_ID))), + lane: TEST_LANE_ID, + }; + pub const BridgedDestination: InteriorMultiLocation = X1( + Parachain(BRIDGED_ASSET_HUB_ID) + ); + pub TestLanes: sp_std::vec::Vec<(SenderAndLane, (NetworkId, InteriorMultiLocation))> = sp_std::vec![ + (TestSenderAndLane::get(), (BridgedRelayNetwork::get(), BridgedDestination::get())) + ]; +} + +pub struct TestXcmBlobHauler; +impl XcmBlobHauler for TestXcmBlobHauler { + type Runtime = TestRuntime; + type MessagesInstance = (); + type ToSourceChainSender = (); + type CongestedMessage = (); + type UncongestedMessage = (); +} + +pub struct ThisChain; + +impl Chain for ThisChain { + type BlockNumber = u64; + type Hash = H256; + type Hasher = BlakeTwo256; + type Header = SubstrateHeader; + type AccountId = AccountId; + type Balance = Balance; + type Nonce = u64; + type Signature = sp_runtime::MultiSignature; + + fn max_extrinsic_size() -> u32 { + u32::MAX + } + + fn max_extrinsic_weight() -> Weight { + Weight::MAX + } +} + +pub struct BridgedChain; +pub type BridgedHeaderHash = H256; +pub type BridgedChainHeader = SubstrateHeader; + +impl Chain for BridgedChain { + type BlockNumber = u64; + type Hash = BridgedHeaderHash; + type Hasher = BlakeTwo256; + type Header = BridgedChainHeader; + type AccountId = AccountId; + type Balance = Balance; + type Nonce = u64; + type Signature = sp_runtime::MultiSignature; + + fn max_extrinsic_size() -> u32 { + 4096 + } + + fn max_extrinsic_weight() -> Weight { + Weight::MAX + } +} + +/// Test message dispatcher. +pub struct TestMessageDispatch; + +impl TestMessageDispatch { + pub fn deactivate(lane: LaneId) { + frame_support::storage::unhashed::put(&(b"inactive", lane).encode()[..], &false); + } +} + +impl MessageDispatch for TestMessageDispatch { + type DispatchPayload = Vec; + type DispatchLevelResult = (); + + fn is_active() -> bool { + frame_support::storage::unhashed::take::(&(b"inactive").encode()[..]) != Some(false) + } + + fn dispatch_weight(_message: &mut DispatchMessage) -> Weight { + Weight::zero() + } + + fn dispatch( + _: DispatchMessage, + ) -> MessageDispatchResult { + MessageDispatchResult { unspent_weight: Weight::zero(), dispatch_level_result: () } + } +} + +pub struct WrappedThisChain; +impl UnderlyingChainProvider for WrappedThisChain { + type Chain = ThisChain; +} +impl ThisChainWithMessages for WrappedThisChain { + type RuntimeOrigin = RuntimeOrigin; +} + +pub struct WrappedBridgedChain; +impl UnderlyingChainProvider for WrappedBridgedChain { + type Chain = BridgedChain; +} +impl BridgedChainWithMessages for WrappedBridgedChain {} + +pub struct BridgedHeaderChain; +impl bp_header_chain::HeaderChain for BridgedHeaderChain { + fn finalized_header_state_root( + _hash: HashOf, + ) -> Option> { + unreachable!() + } +} + +/// Bridge that is deployed on `ThisChain` and allows sending/receiving messages to/from +/// `BridgedChain`. +#[derive(Debug, PartialEq, Eq)] +pub struct OnThisChainBridge; + +impl MessageBridge for OnThisChainBridge { + const BRIDGED_MESSAGES_PALLET_NAME: &'static str = ""; + + type ThisChain = WrappedThisChain; + type BridgedChain = WrappedBridgedChain; + type BridgedHeaderChain = BridgedHeaderChain; +} + +/// Run pallet test. +pub fn run_test(test: impl FnOnce() -> T) -> T { + sp_io::TestExternalities::new( + frame_system::GenesisConfig::::default().build_storage().unwrap(), + ) + .execute_with(test) +} diff --git a/bridges/primitives/chain-kusama/src/lib.rs b/bridges/primitives/chain-kusama/src/lib.rs index d5748aa132c..5f089fbc589 100644 --- a/bridges/primitives/chain-kusama/src/lib.rs +++ b/bridges/primitives/chain-kusama/src/lib.rs @@ -52,8 +52,8 @@ impl ChainWithGrandpa for Kusama { const MAX_AUTHORITIES_COUNT: u32 = MAX_AUTHORITIES_COUNT; const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 = REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY; - const MAX_HEADER_SIZE: u32 = MAX_HEADER_SIZE; - const AVERAGE_HEADER_SIZE_IN_JUSTIFICATION: u32 = AVERAGE_HEADER_SIZE_IN_JUSTIFICATION; + const MAX_MANDATORY_HEADER_SIZE: u32 = MAX_MANDATORY_HEADER_SIZE; + const AVERAGE_HEADER_SIZE: u32 = AVERAGE_HEADER_SIZE; } // The SignedExtension used by Kusama. diff --git a/bridges/primitives/chain-polkadot-bulletin/src/lib.rs b/bridges/primitives/chain-polkadot-bulletin/src/lib.rs index fcc6e90eb1b..fe82c9644b6 100644 --- a/bridges/primitives/chain-polkadot-bulletin/src/lib.rs +++ b/bridges/primitives/chain-polkadot-bulletin/src/lib.rs @@ -42,8 +42,8 @@ use sp_runtime::{traits::DispatchInfoOf, transaction_validity::TransactionValidi // This chain reuses most of Polkadot primitives. pub use bp_polkadot_core::{ AccountAddress, AccountId, Balance, Block, BlockNumber, Hash, Hasher, Header, Nonce, Signature, - SignedBlock, UncheckedExtrinsic, AVERAGE_HEADER_SIZE_IN_JUSTIFICATION, - EXTRA_STORAGE_PROOF_SIZE, MAX_HEADER_SIZE, REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY, + SignedBlock, UncheckedExtrinsic, AVERAGE_HEADER_SIZE, EXTRA_STORAGE_PROOF_SIZE, + MAX_MANDATORY_HEADER_SIZE, REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY, }; /// Maximal number of GRANDPA authorities at Polkadot Bulletin chain. @@ -207,8 +207,8 @@ impl ChainWithGrandpa for PolkadotBulletin { const MAX_AUTHORITIES_COUNT: u32 = MAX_AUTHORITIES_COUNT; const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 = REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY; - const MAX_HEADER_SIZE: u32 = MAX_HEADER_SIZE; - const AVERAGE_HEADER_SIZE_IN_JUSTIFICATION: u32 = AVERAGE_HEADER_SIZE_IN_JUSTIFICATION; + const MAX_MANDATORY_HEADER_SIZE: u32 = MAX_MANDATORY_HEADER_SIZE; + const AVERAGE_HEADER_SIZE: u32 = AVERAGE_HEADER_SIZE; } decl_bridge_finality_runtime_apis!(polkadot_bulletin, grandpa); diff --git a/bridges/primitives/chain-polkadot/src/lib.rs b/bridges/primitives/chain-polkadot/src/lib.rs index 61c8ca927d8..9a5b8970acc 100644 --- a/bridges/primitives/chain-polkadot/src/lib.rs +++ b/bridges/primitives/chain-polkadot/src/lib.rs @@ -52,8 +52,8 @@ impl ChainWithGrandpa for Polkadot { const MAX_AUTHORITIES_COUNT: u32 = MAX_AUTHORITIES_COUNT; const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 = REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY; - const MAX_HEADER_SIZE: u32 = MAX_HEADER_SIZE; - const AVERAGE_HEADER_SIZE_IN_JUSTIFICATION: u32 = AVERAGE_HEADER_SIZE_IN_JUSTIFICATION; + const MAX_MANDATORY_HEADER_SIZE: u32 = MAX_MANDATORY_HEADER_SIZE; + const AVERAGE_HEADER_SIZE: u32 = AVERAGE_HEADER_SIZE; } /// The SignedExtension used by Polkadot. diff --git a/bridges/primitives/chain-rococo/src/lib.rs b/bridges/primitives/chain-rococo/src/lib.rs index 5436ad84646..7f3e762715f 100644 --- a/bridges/primitives/chain-rococo/src/lib.rs +++ b/bridges/primitives/chain-rococo/src/lib.rs @@ -52,8 +52,8 @@ impl ChainWithGrandpa for Rococo { const MAX_AUTHORITIES_COUNT: u32 = MAX_AUTHORITIES_COUNT; const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 = REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY; - const MAX_HEADER_SIZE: u32 = MAX_HEADER_SIZE; - const AVERAGE_HEADER_SIZE_IN_JUSTIFICATION: u32 = AVERAGE_HEADER_SIZE_IN_JUSTIFICATION; + const MAX_MANDATORY_HEADER_SIZE: u32 = MAX_MANDATORY_HEADER_SIZE; + const AVERAGE_HEADER_SIZE: u32 = AVERAGE_HEADER_SIZE; } parameter_types! { diff --git a/bridges/primitives/chain-westend/src/lib.rs b/bridges/primitives/chain-westend/src/lib.rs index 45c13d60060..7fa5e140d57 100644 --- a/bridges/primitives/chain-westend/src/lib.rs +++ b/bridges/primitives/chain-westend/src/lib.rs @@ -52,8 +52,8 @@ impl ChainWithGrandpa for Westend { const MAX_AUTHORITIES_COUNT: u32 = MAX_AUTHORITIES_COUNT; const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 = REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY; - const MAX_HEADER_SIZE: u32 = MAX_HEADER_SIZE; - const AVERAGE_HEADER_SIZE_IN_JUSTIFICATION: u32 = AVERAGE_HEADER_SIZE_IN_JUSTIFICATION; + const MAX_MANDATORY_HEADER_SIZE: u32 = MAX_MANDATORY_HEADER_SIZE; + const AVERAGE_HEADER_SIZE: u32 = AVERAGE_HEADER_SIZE; } parameter_types! { diff --git a/bridges/primitives/header-chain/src/justification/mod.rs b/bridges/primitives/header-chain/src/justification/mod.rs index 72a5f68918d..b32d8bdb5f1 100644 --- a/bridges/primitives/header-chain/src/justification/mod.rs +++ b/bridges/primitives/header-chain/src/justification/mod.rs @@ -82,8 +82,8 @@ impl GrandpaJustification { .saturating_add(BlockNumberOf::::max_encoded_len().saturated_into()) .saturating_add(HashOf::::max_encoded_len().saturated_into()); - let max_expected_votes_ancestries_size = C::REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY - .saturating_mul(C::AVERAGE_HEADER_SIZE_IN_JUSTIFICATION); + let max_expected_votes_ancestries_size = + C::REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY.saturating_mul(C::AVERAGE_HEADER_SIZE); // justification is round number (u64=8b), a signed GRANDPA commit and the // `votes_ancestries` vector diff --git a/bridges/primitives/header-chain/src/lib.rs b/bridges/primitives/header-chain/src/lib.rs index d2c7ec0759e..1459b1c1994 100644 --- a/bridges/primitives/header-chain/src/lib.rs +++ b/bridges/primitives/header-chain/src/lib.rs @@ -266,23 +266,28 @@ pub trait ChainWithGrandpa: Chain { /// to submitter. const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32; - /// Maximal size of the chain header. The header may be the header that enacts new GRANDPA - /// authorities set (so it has large digest inside). + /// Maximal size of the mandatory chain header. Mandatory header is the header that enacts new + /// GRANDPA authorities set (so it has large digest inside). /// /// This isn't a strict limit. The relay may submit larger headers and the pallet will accept /// the call. The limit is only used to compute maximal refund amount and doing calls which /// exceed the limit, may be costly to submitter. - const MAX_HEADER_SIZE: u32; + const MAX_MANDATORY_HEADER_SIZE: u32; - /// Average size of the chain header from justification ancestry. We don't expect to see there - /// headers that change GRANDPA authorities set (GRANDPA will probably be able to finalize at - /// least one additional header per session on non test chains), so this is average size of - /// headers that aren't changing the set. + /// Average size of the chain header. We don't expect to see there headers that change GRANDPA + /// authorities set (GRANDPA will probably be able to finalize at least one additional header + /// per session on non test chains), so this is average size of headers that aren't changing the + /// set. /// - /// This isn't a strict limit. The relay may submit justifications with larger headers in its - /// ancestry and the pallet will accept the call. The limit is only used to compute maximal - /// refund amount and doing calls which exceed the limit, may be costly to submitter. - const AVERAGE_HEADER_SIZE_IN_JUSTIFICATION: u32; + /// This isn't a strict limit. The relay may submit justifications with larger headers and the + /// pallet will accept the call. However, if the total size of all `submit_finality_proof` + /// arguments exceeds the maximal size, computed using this average size, relayer will only get + /// partial refund. + /// + /// We expect some headers on production chains that are above this size. But they are rare and + /// if rellayer cares about its profitability, we expect it'll select other headers for + /// submission. + const AVERAGE_HEADER_SIZE: u32; } impl ChainWithGrandpa for T @@ -295,7 +300,67 @@ where const MAX_AUTHORITIES_COUNT: u32 = ::MAX_AUTHORITIES_COUNT; const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 = ::REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY; - const MAX_HEADER_SIZE: u32 = ::MAX_HEADER_SIZE; - const AVERAGE_HEADER_SIZE_IN_JUSTIFICATION: u32 = - ::AVERAGE_HEADER_SIZE_IN_JUSTIFICATION; + const MAX_MANDATORY_HEADER_SIZE: u32 = + ::MAX_MANDATORY_HEADER_SIZE; + const AVERAGE_HEADER_SIZE: u32 = ::AVERAGE_HEADER_SIZE; +} + +/// Returns maximal expected size of `submit_finality_proof` call arguments. +pub fn max_expected_submit_finality_proof_arguments_size( + is_mandatory_finality_target: bool, + precommits: u32, +) -> u32 { + let max_expected_justification_size = + GrandpaJustification::>::max_reasonable_size::(precommits); + + // call arguments are header and justification + let max_expected_finality_target_size = if is_mandatory_finality_target { + C::MAX_MANDATORY_HEADER_SIZE + } else { + C::AVERAGE_HEADER_SIZE + }; + max_expected_finality_target_size.saturating_add(max_expected_justification_size) +} + +#[cfg(test)] +mod tests { + use super::*; + use frame_support::weights::Weight; + use sp_runtime::{testing::H256, traits::BlakeTwo256, MultiSignature}; + + struct TestChain; + + impl Chain for TestChain { + type BlockNumber = u32; + type Hash = H256; + type Hasher = BlakeTwo256; + type Header = sp_runtime::generic::Header; + type AccountId = u64; + type Balance = u64; + type Nonce = u64; + type Signature = MultiSignature; + + fn max_extrinsic_size() -> u32 { + 0 + } + fn max_extrinsic_weight() -> Weight { + Weight::zero() + } + } + + impl ChainWithGrandpa for TestChain { + const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = "Test"; + const MAX_AUTHORITIES_COUNT: u32 = 128; + const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 = 2; + const MAX_MANDATORY_HEADER_SIZE: u32 = 100_000; + const AVERAGE_HEADER_SIZE: u32 = 1_024; + } + + #[test] + fn max_expected_submit_finality_proof_arguments_size_respects_mandatory_argument() { + assert!( + max_expected_submit_finality_proof_arguments_size::(true, 100) > + max_expected_submit_finality_proof_arguments_size::(false, 100), + ); + } } diff --git a/bridges/primitives/polkadot-core/src/lib.rs b/bridges/primitives/polkadot-core/src/lib.rs index af39b5ab9ba..586cbf8cb9b 100644 --- a/bridges/primitives/polkadot-core/src/lib.rs +++ b/bridges/primitives/polkadot-core/src/lib.rs @@ -64,30 +64,28 @@ pub const MAX_AUTHORITIES_COUNT: u32 = 1_256; /// /// See [`bp-header-chain::ChainWithGrandpa`] for more details. /// -/// This value comes from recent (February, 2023) Kusama and Polkadot headers. There are no +/// This value comes from recent (December, 2023) Kusama and Polkadot headers. There are no /// justifications with any additional headers in votes ancestry, so reasonable headers may /// be set to zero. But we assume that there may be small GRANDPA lags, so we're leaving some /// reserve here. pub const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 = 2; -/// Approximate average header size in `votes_ancestries` field of justification on Polkadot-like +/// Average header size in `votes_ancestries` field of justification on Polkadot-like /// chains. /// /// See [`bp-header-chain::ChainWithGrandpa`] for more details. /// -/// This value comes from recent (February, 2023) Kusama headers. Average is `336` there, but some -/// non-mandatory headers has size `40kb` (they contain the BABE epoch descriptor with all -/// authorities - just like our mandatory header). Since we assume `2` headers in justification -/// votes ancestry, let's set average header to `40kb / 2`. -pub const AVERAGE_HEADER_SIZE_IN_JUSTIFICATION: u32 = 20 * 1024; +/// This value comes from recent (December, 2023) Kusama headers. Most of headers are `327` bytes +/// there, but let's have some reserve and make it 1024. +pub const AVERAGE_HEADER_SIZE: u32 = 1024; /// Approximate maximal header size on Polkadot-like chains. /// /// See [`bp-header-chain::ChainWithGrandpa`] for more details. /// -/// This value comes from recent (February, 2023) Kusama headers. Maximal header is a mandatory -/// header. In its SCALE-encoded form it is `80348` bytes. Let's have some reserve here. -pub const MAX_HEADER_SIZE: u32 = 90_000; +/// This value comes from recent (December, 2023) Kusama headers. Maximal header is a mandatory +/// header. In its SCALE-encoded form it is `113407` bytes. Let's have some reserve here. +pub const MAX_MANDATORY_HEADER_SIZE: u32 = 120 * 1024; /// Number of extra bytes (excluding size of storage value itself) of storage proof, built at /// Polkadot-like chain. This mostly depends on number of entries in the storage trie. diff --git a/bridges/primitives/xcm-bridge-hub/Cargo.toml b/bridges/primitives/xcm-bridge-hub/Cargo.toml new file mode 100644 index 00000000000..212b7b2642f --- /dev/null +++ b/bridges/primitives/xcm-bridge-hub/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "bp-xcm-bridge-hub" +description = "Primitives of the xcm-bridge-hub pallet." +version = "0.1.0" +authors.workspace = true +edition.workspace = true +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[dependencies] + +# Substrate Dependencies +sp-std = { path = "../../../substrate/primitives/std", default-features = false } + +[features] +default = ["std"] +std = ["sp-std/std"] diff --git a/bridges/primitives/xcm-bridge-hub/src/lib.rs b/bridges/primitives/xcm-bridge-hub/src/lib.rs new file mode 100644 index 00000000000..9745011c902 --- /dev/null +++ b/bridges/primitives/xcm-bridge-hub/src/lib.rs @@ -0,0 +1,24 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! Primitives of the xcm-bridge-hub pallet. + +#![warn(missing_docs)] +#![cfg_attr(not(feature = "std"), no_std)] + +/// Encoded XCM blob. We expect the bridge messages pallet to use this blob type for both inbound +/// and outbound payloads. +pub type XcmAsPlainPayload = sp_std::vec::Vec; diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs index 4e61f7ce0dd..b31a17034b9 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs @@ -16,7 +16,7 @@ use crate::*; #[test] -fn send_xcm_from_rococo_relay_to_westend_asset_hub() { +fn send_xcm_from_rococo_relay_to_westend_asset_hub_should_fail_on_not_applicable() { // Init tests variables // XcmPallet send arguments let sudo_origin = ::RuntimeOrigin::root(); @@ -53,7 +53,8 @@ fn send_xcm_from_rococo_relay_to_westend_asset_hub() { ] ); }); - // Receive XCM message in Bridge Hub source Parachain + // Receive XCM message in Bridge Hub source Parachain, it should fail, because we don't have + // opened bridge/lane. BridgeHubRococo::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; @@ -61,37 +62,7 @@ fn send_xcm_from_rococo_relay_to_westend_asset_hub() { BridgeHubRococo, vec![ RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { - success: true, - .. - }) => {}, - RuntimeEvent::BridgeWestendMessages(pallet_bridge_messages::Event::MessageAccepted { - lane_id: LaneId([0, 0, 0, 2]), - nonce: 1, - }) => {}, - ] - ); - }); - - // Westend Global Consensus - // Receive XCM message in Bridge Hub target Parachain - BridgeHubWestend::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - BridgeHubWestend, - vec![ - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, - ] - ); - }); - // Receive embedded XCM message within `ExportMessage` in Parachain destination - AssetHubWestend::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - AssetHubWestend, - vec![ - RuntimeEvent::MessageQueue(pallet_message_queue::Event::ProcessingFailed { + success: false, .. }) => {}, ] diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs index 4b21d758cd9..f5c2ac3677f 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs @@ -16,7 +16,7 @@ use crate::*; #[test] -fn send_xcm_from_westend_relay_to_rococo_asset_hub() { +fn send_xcm_from_westend_relay_to_rococo_asset_hub_should_fail_on_not_applicable() { // Init tests variables // XcmPallet send arguments let sudo_origin = ::RuntimeOrigin::root(); @@ -53,7 +53,8 @@ fn send_xcm_from_westend_relay_to_rococo_asset_hub() { ] ); }); - // Receive XCM message in Bridge Hub source Parachain + // Receive XCM message in Bridge Hub source Parachain, it should fail, because we don't have + // opened bridge/lane. BridgeHubWestend::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; @@ -61,37 +62,7 @@ fn send_xcm_from_westend_relay_to_rococo_asset_hub() { BridgeHubWestend, vec![ RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { - success: true, - .. - }) => {}, - RuntimeEvent::BridgeRococoMessages(pallet_bridge_messages::Event::MessageAccepted { - lane_id: LaneId([0, 0, 0, 2]), - nonce: 1, - }) => {}, - ] - ); - }); - - // Rococo Global Consensus - // Receive XCM message in Bridge Hub target Parachain - BridgeHubRococo::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - BridgeHubRococo, - vec![ - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, - ] - ); - }); - // Receive embedded XCM message within `ExportMessage` in Parachain destination - AssetHubRococo::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - assert_expected_events!( - AssetHubRococo, - vec![ - RuntimeEvent::MessageQueue(pallet_message_queue::Event::ProcessingFailed { + success: false, .. }) => {}, ] diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml index 08758aaf7bb..551615e155c 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -98,6 +98,7 @@ pallet-bridge-grandpa = { path = "../../../../../bridges/modules/grandpa", defau pallet-bridge-messages = { path = "../../../../../bridges/modules/messages", default-features = false } pallet-bridge-parachains = { path = "../../../../../bridges/modules/parachains", default-features = false } pallet-bridge-relayers = { path = "../../../../../bridges/modules/relayers", default-features = false } +pallet-xcm-bridge-hub = { path = "../../../../../bridges/modules/xcm-bridge-hub", default-features = false } bridge-runtime-common = { path = "../../../../../bridges/bin/runtime-common", default-features = false } [dev-dependencies] @@ -156,6 +157,7 @@ std = [ "pallet-transaction-payment/std", "pallet-utility/std", "pallet-xcm-benchmarks?/std", + "pallet-xcm-bridge-hub/std", "pallet-xcm/std", "parachain-info/std", "parachains-common/std", @@ -207,6 +209,7 @@ runtime-benchmarks = [ "pallet-timestamp/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", + "pallet-xcm-bridge-hub/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "parachains-common/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", @@ -239,6 +242,7 @@ try-runtime = [ "pallet-timestamp/try-runtime", "pallet-transaction-payment/try-runtime", "pallet-utility/try-runtime", + "pallet-xcm-bridge-hub/try-runtime", "pallet-xcm/try-runtime", "parachain-info/try-runtime", "polkadot-runtime-common/try-runtime", diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs index f3c1c9597b5..ec9b2646c88 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs @@ -18,8 +18,10 @@ use crate::{ bridge_common_config::{BridgeParachainWestendInstance, DeliveryRewardInBalance}, - weights, AccountId, BridgeWestendMessages, ParachainInfo, Runtime, RuntimeEvent, RuntimeOrigin, - XcmRouter, + weights, + xcm_config::UniversalLocation, + AccountId, BridgeWestendMessages, Runtime, RuntimeEvent, RuntimeOrigin, + XcmOverBridgeHubWestend, XcmRouter, }; use bp_messages::LaneId; use bridge_runtime_common::{ @@ -46,7 +48,7 @@ use xcm::{ latest::prelude::*, prelude::{InteriorMultiLocation, NetworkId}, }; -use xcm_builder::{BridgeBlobDispatcher, HaulBlobExporter}; +use xcm_builder::BridgeBlobDispatcher; parameter_types! { pub const MaxUnrewardedRelayerEntriesAtInboundLane: bp_messages::MessageNonce = @@ -55,23 +57,28 @@ parameter_types! { bp_bridge_hub_rococo::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; pub const BridgeHubWestendChainId: bp_runtime::ChainId = bp_runtime::BRIDGE_HUB_WESTEND_CHAIN_ID; pub BridgeRococoToWestendMessagesPalletInstance: InteriorMultiLocation = X1(PalletInstance(::index() as u8)); - pub BridgeHubRococoUniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(Rococo), Parachain(ParachainInfo::parachain_id().into())); pub WestendGlobalConsensusNetwork: NetworkId = NetworkId::Westend; - pub ActiveOutboundLanesToBridgeHubWestend: &'static [bp_messages::LaneId] = &[XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND]; - pub const AssetHubRococoToAssetHubWestendMessagesLane: bp_messages::LaneId = XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND; // see the `FEE_BOOST_PER_MESSAGE` constant to get the meaning of this value pub PriorityBoostPerMessage: u64 = 182_044_444_444_444; pub AssetHubRococoParaId: cumulus_primitives_core::ParaId = bp_asset_hub_rococo::ASSET_HUB_ROCOCO_PARACHAIN_ID.into(); pub AssetHubWestendParaId: cumulus_primitives_core::ParaId = bp_asset_hub_westend::ASSET_HUB_WESTEND_PARACHAIN_ID.into(); + // Lanes + pub ActiveOutboundLanesToBridgeHubWestend: &'static [bp_messages::LaneId] = &[XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND]; + pub const AssetHubRococoToAssetHubWestendMessagesLane: bp_messages::LaneId = XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND; pub FromAssetHubRococoToAssetHubWestendRoute: SenderAndLane = SenderAndLane::new( ParentThen(X1(Parachain(AssetHubRococoParaId::get().into()))).into(), XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, ); + pub ActiveLanes: sp_std::vec::Vec<(SenderAndLane, (NetworkId, InteriorMultiLocation))> = sp_std::vec![ + ( + FromAssetHubRococoToAssetHubWestendRoute::get(), + (WestendGlobalConsensusNetwork::get(), X1(Parachain(AssetHubWestendParaId::get().into()))) + ) + ]; pub CongestedMessage: Xcm<()> = build_congestion_message(true).into(); - pub UncongestedMessage: Xcm<()> = build_congestion_message(false).into(); } pub const XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND: LaneId = LaneId([0, 0, 0, 2]); @@ -103,23 +110,16 @@ pub type ToWestendBridgeHubMessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof; /// Dispatches received XCM messages from other bridge -type FromWestendMessageBlobDispatcher = BridgeBlobDispatcher< - XcmRouter, - BridgeHubRococoUniversalLocation, - BridgeRococoToWestendMessagesPalletInstance, ->; +type FromWestendMessageBlobDispatcher = + BridgeBlobDispatcher; /// Export XCM messages to be relayed to the other side -pub type ToBridgeHubWestendHaulBlobExporter = HaulBlobExporter< - XcmBlobHaulerAdapter, - WestendGlobalConsensusNetwork, - (), ->; +pub type ToBridgeHubWestendHaulBlobExporter = XcmOverBridgeHubWestend; + pub struct ToBridgeHubWestendXcmBlobHauler; impl XcmBlobHauler for ToBridgeHubWestendXcmBlobHauler { type Runtime = Runtime; type MessagesInstance = WithBridgeHubWestendMessagesInstance; - type SenderAndLane = FromAssetHubRococoToAssetHubWestendRoute; type ToSourceChainSender = XcmRouter; type CongestedMessage = CongestedMessage; @@ -127,7 +127,8 @@ impl XcmBlobHauler for ToBridgeHubWestendXcmBlobHauler { } /// On messages delivered callback. -type OnMessagesDeliveredFromWestend = XcmBlobHaulerAdapter; +type OnMessagesDeliveredFromWestend = + XcmBlobHaulerAdapter; /// Messaging Bridge configuration for BridgeHubRococo -> BridgeHubWestend pub struct WithBridgeHubWestendMessageBridge; @@ -229,6 +230,17 @@ impl pallet_bridge_messages::Config for Ru type OnMessagesDelivered = OnMessagesDeliveredFromWestend; } +/// Add support for the export and dispatch of XCM programs. +pub type XcmOverBridgeHubWestendInstance = pallet_xcm_bridge_hub::Instance1; +impl pallet_xcm_bridge_hub::Config for Runtime { + type UniversalLocation = UniversalLocation; + type BridgedNetworkId = WestendGlobalConsensusNetwork; + type BridgeMessagesPalletInstance = WithBridgeHubWestendMessagesInstance; + type MessageExportPrice = (); + type Lanes = ActiveLanes; + type LanesSupport = ToBridgeHubWestendXcmBlobHauler; +} + #[cfg(test)] mod tests { use super::*; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index 7dbf015de50..8bd5c196016 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -500,6 +500,8 @@ construct_runtime!( BridgeRelayers: pallet_bridge_relayers::{Pallet, Call, Storage, Event} = 47, + XcmOverBridgeHubWestend: pallet_xcm_bridge_hub::::{Pallet} = 52, + // Message Queue. Importantly, is registered last so that messages are processed after // the `on_initialize` hooks of bridging pallets. MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event} = 250, @@ -931,7 +933,13 @@ impl_runtime_apis! { fn export_message_origin_and_destination( ) -> Result<(MultiLocation, NetworkId, InteriorMultiLocation), BenchmarkError> { - Ok((TokenLocation::get(), NetworkId::Westend, X1(Parachain(100)))) + Ok( + ( + bridge_to_westend_config::FromAssetHubRococoToAssetHubWestendRoute::get().location, + NetworkId::Westend, + X1(Parachain(bridge_to_westend_config::AssetHubWestendParaId::get().into())) + ) + ) } fn alias_origin() -> Result<(MultiLocation, MultiLocation), BenchmarkError> { diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs index 9597d71f6b2..c1af369cdf8 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs @@ -191,7 +191,7 @@ mod bridge_hub_rococo_tests { _ => None, } }), - || ExportMessage { network: Westend, destination: X1(Parachain(1234)), xcm: Xcm(vec![]) }, + || ExportMessage { network: Westend, destination: X1(Parachain(bridge_to_westend_config::AssetHubWestendParaId::get().into())), xcm: Xcm(vec![]) }, XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, Some((TokenLocation::get(), ExistentialDeposit::get()).into()), // value should be >= than value generated by `can_calculate_weight_for_paid_export_message_with_reserve_transfer` diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml index c6ceb4b4c90..dd713987ffb 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml @@ -74,6 +74,7 @@ parachain-info = { package = "staging-parachain-info", path = "../../../pallets/ parachains-common = { path = "../../../common", default-features = false } # Bridges +bp-asset-hub-rococo = { path = "../../../../../bridges/primitives/chain-asset-hub-rococo", default-features = false } bp-asset-hub-westend = { path = "../../../../../bridges/primitives/chain-asset-hub-westend", default-features = false } bp-bridge-hub-rococo = { path = "../../../../../bridges/primitives/chain-bridge-hub-rococo", default-features = false } bp-bridge-hub-westend = { path = "../../../../../bridges/primitives/chain-bridge-hub-westend", default-features = false } @@ -89,6 +90,7 @@ pallet-bridge-grandpa = { path = "../../../../../bridges/modules/grandpa", defau pallet-bridge-messages = { path = "../../../../../bridges/modules/messages", default-features = false } pallet-bridge-parachains = { path = "../../../../../bridges/modules/parachains", default-features = false } pallet-bridge-relayers = { path = "../../../../../bridges/modules/relayers", default-features = false } +pallet-xcm-bridge-hub = { path = "../../../../../bridges/modules/xcm-bridge-hub", default-features = false } bridge-runtime-common = { path = "../../../../../bridges/bin/runtime-common", default-features = false } [dev-dependencies] @@ -100,6 +102,7 @@ sp-keyring = { path = "../../../../../substrate/primitives/keyring" } [features] default = ["std"] std = [ + "bp-asset-hub-rococo/std", "bp-asset-hub-westend/std", "bp-bridge-hub-rococo/std", "bp-bridge-hub-westend/std", @@ -144,6 +147,7 @@ std = [ "pallet-transaction-payment/std", "pallet-utility/std", "pallet-xcm-benchmarks?/std", + "pallet-xcm-bridge-hub/std", "pallet-xcm/std", "parachain-info/std", "parachains-common/std", @@ -195,6 +199,7 @@ runtime-benchmarks = [ "pallet-timestamp/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", + "pallet-xcm-bridge-hub/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "parachains-common/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", @@ -227,6 +232,7 @@ try-runtime = [ "pallet-timestamp/try-runtime", "pallet-transaction-payment/try-runtime", "pallet-utility/try-runtime", + "pallet-xcm-bridge-hub/try-runtime", "pallet-xcm/try-runtime", "parachain-info/try-runtime", "polkadot-runtime-common/try-runtime", diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs index 70ff43c09e3..3b773947b47 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs @@ -17,8 +17,9 @@ //! Bridge definitions used on BridgeHub with the Westend flavor. use crate::{ - bridge_common_config::DeliveryRewardInBalance, weights, AccountId, BridgeRococoMessages, - ParachainInfo, Runtime, RuntimeEvent, RuntimeOrigin, XcmRouter, + bridge_common_config::DeliveryRewardInBalance, weights, xcm_config::UniversalLocation, + AccountId, BridgeRococoMessages, Runtime, RuntimeEvent, RuntimeOrigin, XcmOverBridgeHubRococo, + XcmRouter, }; use bp_messages::LaneId; use bp_parachains::SingleParaStoredHeaderDataBuilder; @@ -48,7 +49,7 @@ use xcm::{ latest::prelude::*, prelude::{InteriorMultiLocation, NetworkId}, }; -use xcm_builder::{BridgeBlobDispatcher, HaulBlobExporter}; +use xcm_builder::BridgeBlobDispatcher; parameter_types! { pub const RelayChainHeadersToKeep: u32 = 1024; @@ -62,23 +63,29 @@ parameter_types! { pub const MaxUnconfirmedMessagesAtInboundLane: bp_messages::MessageNonce = bp_bridge_hub_westend::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; pub const BridgeHubRococoChainId: bp_runtime::ChainId = bp_runtime::BRIDGE_HUB_ROCOCO_CHAIN_ID; - pub BridgeHubWestendUniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(Westend), Parachain(ParachainInfo::parachain_id().into())); pub BridgeWestendToRococoMessagesPalletInstance: InteriorMultiLocation = X1(PalletInstance(::index() as u8)); pub RococoGlobalConsensusNetwork: NetworkId = NetworkId::Rococo; - pub ActiveOutboundLanesToBridgeHubRococo: &'static [bp_messages::LaneId] = &[XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO]; - pub const AssetHubWestendToAssetHubRococoMessagesLane: bp_messages::LaneId = XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO; // see the `FEE_BOOST_PER_MESSAGE` constant to get the meaning of this value pub PriorityBoostPerMessage: u64 = 182_044_444_444_444; pub AssetHubWestendParaId: cumulus_primitives_core::ParaId = bp_asset_hub_westend::ASSET_HUB_WESTEND_PARACHAIN_ID.into(); + pub AssetHubRococoParaId: cumulus_primitives_core::ParaId = bp_asset_hub_rococo::ASSET_HUB_ROCOCO_PARACHAIN_ID.into(); + // Lanes + pub ActiveOutboundLanesToBridgeHubRococo: &'static [bp_messages::LaneId] = &[XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO]; + pub const AssetHubWestendToAssetHubRococoMessagesLane: bp_messages::LaneId = XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO; pub FromAssetHubWestendToAssetHubRococoRoute: SenderAndLane = SenderAndLane::new( ParentThen(X1(Parachain(AssetHubWestendParaId::get().into()))).into(), XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, ); + pub ActiveLanes: sp_std::vec::Vec<(SenderAndLane, (NetworkId, InteriorMultiLocation))> = sp_std::vec![ + ( + FromAssetHubWestendToAssetHubRococoRoute::get(), + (RococoGlobalConsensusNetwork::get(), X1(Parachain(AssetHubRococoParaId::get().into()))) + ) + ]; pub CongestedMessage: Xcm<()> = build_congestion_message(true).into(); - pub UncongestedMessage: Xcm<()> = build_congestion_message(false).into(); } pub const XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO: LaneId = LaneId([0, 0, 0, 2]); @@ -110,23 +117,16 @@ pub type ToRococoBridgeHubMessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof; /// Dispatches received XCM messages from other bridge -type FromRococoMessageBlobDispatcher = BridgeBlobDispatcher< - XcmRouter, - BridgeHubWestendUniversalLocation, - BridgeWestendToRococoMessagesPalletInstance, ->; +type FromRococoMessageBlobDispatcher = + BridgeBlobDispatcher; /// Export XCM messages to be relayed to the other side -pub type ToBridgeHubRococoHaulBlobExporter = HaulBlobExporter< - XcmBlobHaulerAdapter, - RococoGlobalConsensusNetwork, - (), ->; +pub type ToBridgeHubRococoHaulBlobExporter = XcmOverBridgeHubRococo; + pub struct ToBridgeHubRococoXcmBlobHauler; impl XcmBlobHauler for ToBridgeHubRococoXcmBlobHauler { type Runtime = Runtime; type MessagesInstance = WithBridgeHubRococoMessagesInstance; - type SenderAndLane = FromAssetHubWestendToAssetHubRococoRoute; type ToSourceChainSender = XcmRouter; type CongestedMessage = CongestedMessage; @@ -134,7 +134,7 @@ impl XcmBlobHauler for ToBridgeHubRococoXcmBlobHauler { } /// On messages delivered callback. -type OnMessagesDelivered = XcmBlobHaulerAdapter; +type OnMessagesDelivered = XcmBlobHaulerAdapter; /// Messaging Bridge configuration for BridgeHubWestend -> BridgeHubRococo pub struct WithBridgeHubRococoMessageBridge; @@ -256,6 +256,17 @@ impl pallet_bridge_messages::Config for Run type OnMessagesDelivered = OnMessagesDelivered; } +/// Add support for the export and dispatch of XCM programs. +pub type XcmOverBridgeHubRococoInstance = pallet_xcm_bridge_hub::Instance1; +impl pallet_xcm_bridge_hub::Config for Runtime { + type UniversalLocation = UniversalLocation; + type BridgedNetworkId = RococoGlobalConsensusNetwork; + type BridgeMessagesPalletInstance = WithBridgeHubRococoMessagesInstance; + type MessageExportPrice = (); + type Lanes = ActiveLanes; + type LanesSupport = ToBridgeHubRococoXcmBlobHauler; +} + #[cfg(test)] mod tests { use super::*; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index e77184351ed..07e664d67be 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -488,6 +488,7 @@ construct_runtime!( BridgeRococoGrandpa: pallet_bridge_grandpa::::{Pallet, Call, Storage, Event, Config} = 42, BridgeRococoParachains: pallet_bridge_parachains::::{Pallet, Call, Storage, Event} = 43, BridgeRococoMessages: pallet_bridge_messages::::{Pallet, Call, Storage, Event, Config} = 44, + XcmOverBridgeHubRococo: pallet_xcm_bridge_hub::::{Pallet} = 45, // Message Queue. Importantly, is registered last so that messages are processed after // the `on_initialize` hooks of bridging pallets. @@ -921,7 +922,13 @@ impl_runtime_apis! { fn export_message_origin_and_destination( ) -> Result<(MultiLocation, NetworkId, InteriorMultiLocation), BenchmarkError> { - Ok((WestendLocation::get(), NetworkId::Rococo, X1(Parachain(100)))) + Ok( + ( + bridge_to_rococo_config::FromAssetHubWestendToAssetHubRococoRoute::get().location, + NetworkId::Rococo, + X1(Parachain(bridge_to_rococo_config::AssetHubRococoParaId::get().into())) + ) + ) } fn alias_origin() -> Result<(MultiLocation, MultiLocation), BenchmarkError> { diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs index 4d477e1413e..822dc2340d4 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs @@ -179,7 +179,7 @@ fn handle_export_message_from_system_parachain_add_to_outbound_queue_works() { _ => None, } }), - || ExportMessage { network: Rococo, destination: X1(Parachain(4321)), xcm: Xcm(vec![]) }, + || ExportMessage { network: Rococo, destination: X1(Parachain(bridge_to_rococo_config::AssetHubRococoParaId::get().into())), xcm: Xcm(vec![]) }, XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, Some((WestendLocation::get(), ExistentialDeposit::get()).into()), // value should be >= than value generated by `can_calculate_weight_for_paid_export_message_with_reserve_transfer` diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases.rs index 7a86d85c86f..fee95a38288 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases.rs @@ -1457,9 +1457,9 @@ pub mod test_data { ); // to compute proper cost of GRANDPA call, let's add some dummy bytes to header, so that the // `submit_finality_proof` call size would be close to maximal expected (and refundable) - let expected_bytes_in_grandpa_call = BridgedRelayChain::AVERAGE_HEADER_SIZE_IN_JUSTIFICATION + let expected_bytes_in_grandpa_call = BridgedRelayChain::AVERAGE_HEADER_SIZE .saturating_mul(BridgedRelayChain::REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY) - .saturating_add(BridgedRelayChain::MAX_HEADER_SIZE) + .saturating_add(BridgedRelayChain::MAX_MANDATORY_HEADER_SIZE) as usize; let extra_bytes_required = expected_bytes_in_grandpa_call.saturating_sub(relay_chain_header.encoded_size()); -- GitLab From 4df313fbc7abd64a93d3e8f07f4f9870094e8a94 Mon Sep 17 00:00:00 2001 From: Juan Girini Date: Wed, 6 Dec 2023 20:26:06 +0100 Subject: [PATCH 10/59] Improve polkadot sdk docs (#2631) Closes https://github.com/paritytech/polkadot-sdk-docs/issues/69 --- docs/sdk/Cargo.toml | 2 +- docs/sdk/src/guides/mod.rs | 2 +- docs/sdk/src/guides/your_first_pallet/mod.rs | 136 ++++++++++-------- .../src/reference_docs/fee_less_runtime.rs | 2 +- 4 files changed, 79 insertions(+), 63 deletions(-) diff --git a/docs/sdk/Cargo.toml b/docs/sdk/Cargo.toml index f5bfd80fd10..14b4747d558 100644 --- a/docs/sdk/Cargo.toml +++ b/docs/sdk/Cargo.toml @@ -22,7 +22,7 @@ pallet-default-config-example = { path = "../../substrate/frame/examples/default simple-mermaid = { git = "https://github.com/kianenigma/simple-mermaid.git", branch = "main" } docify = "0.2.6" -# Polkadot SDK deps, typically all should only be scope such that we can link to their doc item. +# Polkadot SDK deps, typically all should only be in scope such that we can link to their doc item. node-cli = { package = "staging-node-cli", path = "../../substrate/bin/node/cli" } kitchensink-runtime = { path = "../../substrate/bin/node/runtime" } chain-spec-builder = { package = "staging-chain-spec-builder", path = "../../substrate/bin/utils/chain-spec-builder" } diff --git a/docs/sdk/src/guides/mod.rs b/docs/sdk/src/guides/mod.rs index 68ca9317b90..3120f253310 100644 --- a/docs/sdk/src/guides/mod.rs +++ b/docs/sdk/src/guides/mod.rs @@ -1,7 +1,7 @@ //! # Polkadot SDK Docs Guides //! //! This crate contains a collection of guides that are foundational to the developers of -//! Polkadot SDK. They common user-journeys that are traversed in the Polkadot ecosystem. +//! Polkadot SDK. They are common user-journeys that are traversed in the Polkadot ecosystem. /// Write your first simple pallet, learning the most most basic features of FRAME along the way. pub mod your_first_pallet; diff --git a/docs/sdk/src/guides/your_first_pallet/mod.rs b/docs/sdk/src/guides/your_first_pallet/mod.rs index 855b390aba9..c886bc9af84 100644 --- a/docs/sdk/src/guides/your_first_pallet/mod.rs +++ b/docs/sdk/src/guides/your_first_pallet/mod.rs @@ -12,12 +12,11 @@ //! > This guide will build a currency pallet from scratch using only the lowest primitives of //! > FRAME, and is mainly intended for education, not *applicability*. For example, almost all //! > FRAME-based runtimes use various techniques to re-use a currency pallet instead of writing -//! > one. Further advance FRAME related topics are discussed in [`crate::reference_docs`]. +//! > one. Further advanced FRAME related topics are discussed in [`crate::reference_docs`]. //! //! ## Topics Covered //! -//! The following FRAME topics are covered in this guide. See the documentation of the -//! associated items to know more. +//! The following FRAME topics are covered in this guide: //! //! - [Storage](frame::pallet_macros::storage) //! - [Call](frame::pallet_macros::call) @@ -50,8 +49,10 @@ //! //! One should be a mapping from account-ids to a balance type, and one value that is the total //! issuance. -// -// For the rest of this guide, we will opt for a balance type of u128. +//! +//! > For the rest of this guide, we will opt for a balance type of `u128`. For the sake of +//! > simplicity, we are hardcoding this type. In a real pallet is best practice to define it as a +//! > generic bounded type in the `Config` trait, and then specify it in the implementation. #![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", Balance)] //! //! The definition of these two storage items, based on [`frame::pallet_macros::storage`] details, @@ -160,13 +161,12 @@ #![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", first_test)] //! //! In the first test, we simply assert that there is no total issuance, and no balance associated -//! with account `1`. Then, we mint some balance into `1`, and re-check. +//! with Alice's account. Then, we mint some balance into Alice's, and re-check. //! //! As noted above, the `T::AccountId` is now `u64`. Moreover, `Runtime` is replacing ``. //! This is why for example you see `Balances::::get(..)`. Finally, notice that the //! dispatchables are simply functions that can be called on top of the `Pallet` struct. -//! -//! TODO: hard to explain exactly `RuntimeOrigin::signed(1)` at this point. +// TODO: hard to explain exactly `RuntimeOrigin::signed(ALICE)` at this point. //! //! Congratulations! You have written your first pallet and tested it! Next, we learn a few optional //! steps to improve our pallet. @@ -186,8 +186,8 @@ #![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", StateBuilder)] //! //! This struct is meant to contain the same list of accounts and balances that we want to have at -//! the beginning of each block. We hardcoded this to `let accounts = vec![(1, 100), (2, 100)];` so -//! far. Then, if desired, we attach a default value for this struct. +//! the beginning of each block. We hardcoded this to `let accounts = vec![(ALICE, 100), (2, 100)];` +//! so far. Then, if desired, we attach a default value for this struct. #![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", default_state_builder)] //! //! Like any other builder pattern, we attach functions to the type to mutate its internal @@ -222,7 +222,7 @@ //! "success path" of a dispatchable, and one test for each "failure path", such as: #![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", transfer_from_non_existent_fails)] //! -//! We leave it up to you to write a test that triggers to `InsufficientBalance` error. +//! We leave it up to you to write a test that triggers the `InsufficientBalance` error. //! //! ### Event and Error //! @@ -230,21 +230,24 @@ //! Errors. First, let's understand what each is. //! //! - **Error**: The static string-based error scheme we used so far is good for readability, but it -//! has a few drawbacks. These string literals will bloat the final wasm blob, and are relatively -//! heavy to transmit and encode/decode. Moreover, it is easy to mistype them by one character. -//! FRAME errors are exactly a solution to maintain readability, whilst fixing the drawbacks -//! mentioned. In short, we use an enum to represent different variants of our error. These -//! variants are then mapped in an efficient way (using only `u8` indices) to -//! [`sp_runtime::DispatchError::Module`] Read more about this in [`frame::pallet_macros::error`]. -//! -//! - **Event**: Events are akin to the return type of dispatchables. They should represent what -//! happened at the end of a dispatch operation. Therefore, the convention is to use passive tense -//! for event names (eg. `SomethingHappened`). This allows other sub-systems or external parties -//! (eg. a light-node, a DApp) to listen to particular events happening, without needing to -//! re-execute the whole state transition function. -//! -//! TODO: both need to be improved a lot at the pallet-macro rust-doc level. Also my explanation -//! of event is probably not the best. +//! has a few drawbacks. The biggest problem with strings are that they are not type safe, e.g. a +//! match statement cannot be exhaustive. These string literals will bloat the final wasm blob, +//! and are relatively heavy to transmit and encode/decode. Moreover, it is easy to mistype them +//! by one character. FRAME errors are exactly a solution to maintain readability, whilst fixing +//! the drawbacks mentioned. In short, we use an enum to represent different variants of our +//! error. These variants are then mapped in an efficient way (using only `u8` indices) to +//! [`sp_runtime::DispatchError::Module`]. Read more about this in +//! [`frame::pallet_macros::error`]. +//! +//! - **Event**: Events are akin to the return type of dispatchables. They are mostly data blobs +//! emitted by the runtime to let outside world know what is happening inside the pallet. Since +//! otherwise, the outside world does not have an easy access to the state changes. They should +//! represent what happened at the end of a dispatch operation. Therefore, the convention is to +//! use passive tense for event names (eg. `SomethingHappened`). This allows other sub-systems or +//! external parties (eg. a light-node, a DApp) to listen to particular events happening, without +//! needing to re-execute the whole state transition function. +// TODO: both need to be improved a lot at the pallet-macro rust-doc level. Also my explanation +// of event is probably not the best. //! //! With the explanation out of the way, let's see how these components can be added. Both follow a //! fairly familiar syntax: normal Rust enums, with an extra `#[frame::event/error]` attribute @@ -413,6 +416,9 @@ pub mod pallet { pub(crate) mod tests { use crate::guides::your_first_pallet::pallet::*; use frame::testing_prelude::*; + const ALICE: u64 = 1; + const BOB: u64 = 2; + const CHARLIE: u64 = 3; #[docify::export] mod runtime { @@ -447,7 +453,7 @@ pub mod pallet { #[docify::export] fn new_test_state_basic() -> TestState { let mut state = TestState::new_empty(); - let accounts = vec![(1, 100), (2, 100)]; + let accounts = vec![(ALICE, 100), (BOB, 100)]; state.execute_with(|| { for (who, amount) in &accounts { Balances::::insert(who, amount); @@ -466,7 +472,7 @@ pub mod pallet { #[docify::export(default_state_builder)] impl Default for StateBuilder { fn default() -> Self { - Self { balances: vec![(1, 100), (2, 100)] } + Self { balances: vec![(ALICE, 100), (BOB, 100)] } } } @@ -509,15 +515,19 @@ pub mod pallet { #[test] fn first_test() { TestState::new_empty().execute_with(|| { - // We expect account 1 to have no funds. - assert_eq!(Balances::::get(&1), None); + // We expect Alice's account to have no funds. + assert_eq!(Balances::::get(&ALICE), None); assert_eq!(TotalIssuance::::get(), None); - // mint some funds into 1 - assert_ok!(Pallet::::mint_unsafe(RuntimeOrigin::signed(1), 1, 100)); + // mint some funds into Alice's account. + assert_ok!(Pallet::::mint_unsafe( + RuntimeOrigin::signed(ALICE), + ALICE, + 100 + )); // re-check the above - assert_eq!(Balances::::get(&1), Some(100)); + assert_eq!(Balances::::get(&ALICE), Some(100)); assert_eq!(TotalIssuance::::get(), Some(100)); }) } @@ -526,9 +536,9 @@ pub mod pallet { #[test] fn state_builder_works() { StateBuilder::default().build_and_execute(|| { - assert_eq!(Balances::::get(&1), Some(100)); - assert_eq!(Balances::::get(&2), Some(100)); - assert_eq!(Balances::::get(&3), None); + assert_eq!(Balances::::get(&ALICE), Some(100)); + assert_eq!(Balances::::get(&BOB), Some(100)); + assert_eq!(Balances::::get(&CHARLIE), None); assert_eq!(TotalIssuance::::get(), Some(200)); }); } @@ -536,8 +546,8 @@ pub mod pallet { #[docify::export] #[test] fn state_builder_add_balance() { - StateBuilder::default().add_balance(3, 42).build_and_execute(|| { - assert_eq!(Balances::::get(&3), Some(42)); + StateBuilder::default().add_balance(CHARLIE, 42).build_and_execute(|| { + assert_eq!(Balances::::get(&CHARLIE), Some(42)); assert_eq!(TotalIssuance::::get(), Some(242)); }) } @@ -546,10 +556,10 @@ pub mod pallet { #[should_panic] fn state_builder_duplicate_genesis_fails() { StateBuilder::default() - .add_balance(3, 42) - .add_balance(3, 43) + .add_balance(CHARLIE, 42) + .add_balance(CHARLIE, 43) .build_and_execute(|| { - assert_eq!(Balances::::get(&3), None); + assert_eq!(Balances::::get(&CHARLIE), None); assert_eq!(TotalIssuance::::get(), Some(242)); }) } @@ -559,17 +569,21 @@ pub mod pallet { fn mint_works() { StateBuilder::default().build_and_execute(|| { // given the initial state, when: - assert_ok!(Pallet::::mint_unsafe(RuntimeOrigin::signed(1), 2, 100)); + assert_ok!(Pallet::::mint_unsafe(RuntimeOrigin::signed(ALICE), BOB, 100)); // then: - assert_eq!(Balances::::get(&2), Some(200)); + assert_eq!(Balances::::get(&BOB), Some(200)); assert_eq!(TotalIssuance::::get(), Some(300)); // given: - assert_ok!(Pallet::::mint_unsafe(RuntimeOrigin::signed(1), 3, 100)); + assert_ok!(Pallet::::mint_unsafe( + RuntimeOrigin::signed(ALICE), + CHARLIE, + 100 + )); // then: - assert_eq!(Balances::::get(&3), Some(100)); + assert_eq!(Balances::::get(&CHARLIE), Some(100)); assert_eq!(TotalIssuance::::get(), Some(400)); }); } @@ -579,19 +593,19 @@ pub mod pallet { fn transfer_works() { StateBuilder::default().build_and_execute(|| { // given the the initial state, when: - assert_ok!(Pallet::::transfer(RuntimeOrigin::signed(1), 2, 50)); + assert_ok!(Pallet::::transfer(RuntimeOrigin::signed(ALICE), BOB, 50)); // then: - assert_eq!(Balances::::get(&1), Some(50)); - assert_eq!(Balances::::get(&2), Some(150)); + assert_eq!(Balances::::get(&ALICE), Some(50)); + assert_eq!(Balances::::get(&BOB), Some(150)); assert_eq!(TotalIssuance::::get(), Some(200)); // when: - assert_ok!(Pallet::::transfer(RuntimeOrigin::signed(2), 1, 50)); + assert_ok!(Pallet::::transfer(RuntimeOrigin::signed(BOB), ALICE, 50)); // then: - assert_eq!(Balances::::get(&1), Some(100)); - assert_eq!(Balances::::get(&2), Some(100)); + assert_eq!(Balances::::get(&ALICE), Some(100)); + assert_eq!(Balances::::get(&BOB), Some(100)); assert_eq!(TotalIssuance::::get(), Some(200)); }); } @@ -602,14 +616,14 @@ pub mod pallet { StateBuilder::default().build_and_execute(|| { // given the the initial state, when: assert_err!( - Pallet::::transfer(RuntimeOrigin::signed(3), 1, 10), + Pallet::::transfer(RuntimeOrigin::signed(CHARLIE), ALICE, 10), "NonExistentAccount" ); // then nothing has changed. - assert_eq!(Balances::::get(&1), Some(100)); - assert_eq!(Balances::::get(&2), Some(100)); - assert_eq!(Balances::::get(&3), None); + assert_eq!(Balances::::get(&ALICE), Some(100)); + assert_eq!(Balances::::get(&BOB), Some(100)); + assert_eq!(Balances::::get(&CHARLIE), None); assert_eq!(TotalIssuance::::get(), Some(200)); }); } @@ -685,6 +699,8 @@ pub mod pallet_v2 { pub mod tests { use super::{super::pallet::tests::StateBuilder, *}; use frame::testing_prelude::*; + const ALICE: u64 = 1; + const BOB: u64 = 2; #[docify::export] pub mod runtime_v2 { @@ -717,20 +733,20 @@ pub mod pallet_v2 { StateBuilder::default().build_and_execute(|| { // skip the genesis block, as events are not deposited there and we need them for // the final assertion. - System::set_block_number(1); + System::set_block_number(ALICE); // given the the initial state, when: - assert_ok!(Pallet::::transfer(RuntimeOrigin::signed(1), 2, 50)); + assert_ok!(Pallet::::transfer(RuntimeOrigin::signed(ALICE), BOB, 50)); // then: - assert_eq!(Balances::::get(&1), Some(50)); - assert_eq!(Balances::::get(&2), Some(150)); + assert_eq!(Balances::::get(&ALICE), Some(50)); + assert_eq!(Balances::::get(&BOB), Some(150)); assert_eq!(TotalIssuance::::get(), Some(200)); // now we can also check that an event has been deposited: assert_eq!( System::read_events_for_pallet::>(), - vec![Event::Transferred { from: 1, to: 2, amount: 50 }] + vec![Event::Transferred { from: ALICE, to: BOB, amount: 50 }] ); }); } diff --git a/docs/sdk/src/reference_docs/fee_less_runtime.rs b/docs/sdk/src/reference_docs/fee_less_runtime.rs index 43a761a6c52..1213c262825 100644 --- a/docs/sdk/src/reference_docs/fee_less_runtime.rs +++ b/docs/sdk/src/reference_docs/fee_less_runtime.rs @@ -9,4 +9,4 @@ //! and some kind of rate limiting (eg. any account gets 5 free tx per day). //! - The rule of thumb is that as long as the unsigned validate does one storage read, similar to //! nonce, it is fine. -//! - This could possibly be a good tutorial/template, rather than a reference doc. +//! - This could possibly be a good guide/template, rather than a reference doc. -- GitLab From 0b3d0677f89d28fb3c3e8d09ab3f8e538f90c404 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Thu, 7 Dec 2023 00:53:31 +0300 Subject: [PATCH 11/59] Added AllSiblingSystemParachains matcher to be used at a parachain level (#2422) As suggested in this thread: https://github.com/polkadot-fellows/runtimes/pull/87#discussion_r1400237122 We already have the `IsChildSystemParachain`, which may be used at relay chain, but it can't be used at a parachain level. So let's use `AllSiblingSystemParachains` for that. I was thinking about `AllSystemParachains`, but it may cause wrong impression that it can be used at a relay chain level. --------- Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> --- Cargo.lock | 2 + cumulus/parachains/common/src/xcm_config.rs | 42 +++++++++++++++++-- .../assets/asset-hub-rococo/src/xcm_config.rs | 25 +++-------- .../asset-hub-westend/src/xcm_config.rs | 24 +++-------- .../bridge-hub-rococo/src/xcm_config.rs | 25 ++++------- .../bridge-hub-westend/src/xcm_config.rs | 24 ++++------- .../collectives-westend/src/xcm_config.rs | 24 ++++------- .../contracts-rococo/src/xcm_config.rs | 25 ++++------- polkadot/runtime/rococo/constants/Cargo.toml | 2 + polkadot/runtime/rococo/constants/src/lib.rs | 10 ++--- polkadot/runtime/westend/constants/Cargo.toml | 2 + polkadot/runtime/westend/constants/src/lib.rs | 10 ++--- 12 files changed, 93 insertions(+), 122 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a37d24d50a3..13f89d645b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14544,6 +14544,7 @@ dependencies = [ "sp-runtime", "sp-weights", "staging-xcm", + "staging-xcm-builder", ] [[package]] @@ -20982,6 +20983,7 @@ dependencies = [ "sp-runtime", "sp-weights", "staging-xcm", + "staging-xcm-builder", ] [[package]] diff --git a/cumulus/parachains/common/src/xcm_config.rs b/cumulus/parachains/common/src/xcm_config.rs index 4b0215d672b..97dc47cb028 100644 --- a/cumulus/parachains/common/src/xcm_config.rs +++ b/cumulus/parachains/common/src/xcm_config.rs @@ -100,6 +100,25 @@ impl, Runtime: parachain_info::C } } +/// Contains all sibling system parachains, including the one where this matcher is used. +/// +/// This structure can only be used at a parachain level. In the Relay Chain, please use +/// the `xcm_builder::IsChildSystemParachain` matcher. +pub struct AllSiblingSystemParachains; + +impl Contains for AllSiblingSystemParachains { + fn contains(l: &MultiLocation) -> bool { + log::trace!(target: "xcm::contains", "AllSiblingSystemParachains location: {:?}", l); + match *l { + // System parachain + MultiLocation { parents: 1, interior: X1(Parachain(id)) } => + ParaId::from(id).is_system(), + // Everything else + _ => false, + } + } +} + /// Accepts an asset if it is a concrete asset from the system (Relay Chain or system parachain). pub struct ConcreteAssetFromSystem(PhantomData); impl> ContainsPair @@ -122,12 +141,14 @@ impl> ContainsPair #[cfg(test)] mod tests { - use frame_support::parameter_types; + use frame_support::{parameter_types, traits::Contains}; use super::{ - ConcreteAssetFromSystem, ContainsPair, GeneralIndex, Here, MultiAsset, MultiLocation, - PalletInstance, Parachain, Parent, + AllSiblingSystemParachains, ConcreteAssetFromSystem, ContainsPair, GeneralIndex, Here, + MultiAsset, MultiLocation, PalletInstance, Parachain, Parent, }; + use polkadot_primitives::LOWEST_PUBLIC_ID; + use xcm::latest::prelude::*; parameter_types! { pub const RelayLocation: MultiLocation = MultiLocation::parent(); @@ -180,4 +201,19 @@ mod tests { ); } } + + #[test] + fn all_sibling_system_parachains_works() { + // system parachain + assert!(AllSiblingSystemParachains::contains(&MultiLocation::new(1, X1(Parachain(1))))); + // non-system parachain + assert!(!AllSiblingSystemParachains::contains(&MultiLocation::new( + 1, + X1(Parachain(LOWEST_PUBLIC_ID.into())) + ))); + // when used at relay chain + assert!(!AllSiblingSystemParachains::contains(&MultiLocation::new(0, X1(Parachain(1))))); + // when used with non-parachain + assert!(!AllSiblingSystemParachains::contains(&MultiLocation::new(1, X1(OnlyChild)))); + } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index 4da0a2500a5..4b47aded28f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -32,14 +32,13 @@ use pallet_xcm::XcmPassthrough; use parachains_common::{ impls::ToStakingPot, xcm_config::{ - AssetFeeAsExistentialDepositMultiplier, ConcreteAssetFromSystem, - RelayOrOtherSystemParachains, + AllSiblingSystemParachains, AssetFeeAsExistentialDepositMultiplier, + ConcreteAssetFromSystem, RelayOrOtherSystemParachains, }, TREASURY_PALLET_ID, }; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::xcm_sender::ExponentialPrice; -use rococo_runtime_constants::system_parachain; use sp_runtime::traits::{AccountIdConversion, ConvertInto}; use xcm::latest::prelude::*; use xcm_builder::{ @@ -513,25 +512,13 @@ pub type ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger = ForeignAssetsInstance, >; -match_types! { - pub type SystemParachains: impl Contains = { - MultiLocation { - parents: 1, - interior: X1(Parachain( - system_parachain::ASSET_HUB_ID | - system_parachain::BRIDGE_HUB_ID | - system_parachain::CONTRACTS_ID | - system_parachain::ENCOINTER_ID - )), - } - }; -} - /// Locations that will not be charged fees in the executor, /// either execution or delivery. /// We only waive fees for system functions, which these locations represent. -pub type WaivedLocations = - (RelayOrOtherSystemParachains, Equals); +pub type WaivedLocations = ( + RelayOrOtherSystemParachains, + Equals, +); /// Cases where a remote origin is accepted as trusted Teleporter for a given asset: /// diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs index 4760e087e24..19fd9b0b928 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs @@ -32,15 +32,14 @@ use pallet_xcm::XcmPassthrough; use parachains_common::{ impls::ToStakingPot, xcm_config::{ - AssetFeeAsExistentialDepositMultiplier, ConcreteAssetFromSystem, - RelayOrOtherSystemParachains, + AllSiblingSystemParachains, AssetFeeAsExistentialDepositMultiplier, + ConcreteAssetFromSystem, RelayOrOtherSystemParachains, }, TREASURY_PALLET_ID, }; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::xcm_sender::ExponentialPrice; use sp_runtime::traits::{AccountIdConversion, ConvertInto}; -use westend_runtime_constants::system_parachain; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, @@ -520,24 +519,13 @@ pub type ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger = ForeignAssetsInstance, >; -match_types! { - pub type SystemParachains: impl Contains = { - MultiLocation { - parents: 1, - interior: X1(Parachain( - system_parachain::ASSET_HUB_ID | - system_parachain::COLLECTIVES_ID | - system_parachain::BRIDGE_HUB_ID - )), - } - }; -} - /// Locations that will not be charged fees in the executor, /// either execution or delivery. /// We only waive fees for system functions, which these locations represent. -pub type WaivedLocations = - (RelayOrOtherSystemParachains, Equals); +pub type WaivedLocations = ( + RelayOrOtherSystemParachains, + Equals, +); /// Cases where a remote origin is accepted as trusted Teleporter for a given asset: /// diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs index de7b5315c88..8092bd16120 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs @@ -33,12 +33,13 @@ use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; use parachains_common::{ impls::ToStakingPot, - xcm_config::{ConcreteAssetFromSystem, RelayOrOtherSystemParachains}, + xcm_config::{ + AllSiblingSystemParachains, ConcreteAssetFromSystem, RelayOrOtherSystemParachains, + }, TREASURY_PALLET_ID, }; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::xcm_sender::ExponentialPrice; -use rococo_runtime_constants::system_parachain; use sp_core::Get; use sp_runtime::traits::AccountIdConversion; use sp_std::marker::PhantomData; @@ -220,25 +221,13 @@ pub type Barrier = TrailingSetTopicAsId< >, >; -match_types! { - pub type SystemParachains: impl Contains = { - MultiLocation { - parents: 1, - interior: X1(Parachain( - system_parachain::ASSET_HUB_ID | - system_parachain::BRIDGE_HUB_ID | - system_parachain::CONTRACTS_ID | - system_parachain::ENCOINTER_ID - )), - } - }; -} - /// Locations that will not be charged fees in the executor, /// either execution or delivery. /// We only waive fees for system functions, which these locations represent. -pub type WaivedLocations = - (RelayOrOtherSystemParachains, Equals); +pub type WaivedLocations = ( + RelayOrOtherSystemParachains, + Equals, +); /// Cases where a remote origin is accepted as trusted Teleporter for a given asset: /// - NativeToken with the parent Relay Chain and sibling parachains. diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs index c89ee91c5e4..009b17a4675 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs @@ -28,13 +28,14 @@ use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; use parachains_common::{ impls::ToStakingPot, - xcm_config::{ConcreteAssetFromSystem, RelayOrOtherSystemParachains}, + xcm_config::{ + AllSiblingSystemParachains, ConcreteAssetFromSystem, RelayOrOtherSystemParachains, + }, TREASURY_PALLET_ID, }; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::xcm_sender::ExponentialPrice; use sp_runtime::traits::AccountIdConversion; -use westend_runtime_constants::system_parachain; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, @@ -209,24 +210,13 @@ pub type Barrier = TrailingSetTopicAsId< >, >; -match_types! { - pub type SystemParachains: impl Contains = { - MultiLocation { - parents: 1, - interior: X1(Parachain( - system_parachain::ASSET_HUB_ID | - system_parachain::BRIDGE_HUB_ID | - system_parachain::COLLECTIVES_ID - )), - } - }; -} - /// Locations that will not be charged fees in the executor, /// either execution or delivery. /// We only waive fees for system functions, which these locations represent. -pub type WaivedLocations = - (RelayOrOtherSystemParachains, Equals); +pub type WaivedLocations = ( + RelayOrOtherSystemParachains, + Equals, +); /// Cases where a remote origin is accepted as trusted Teleporter for a given asset: /// - NativeToken with the parent Relay Chain and sibling parachains. diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs index cefc099c96f..44d5d1daf32 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs @@ -27,11 +27,12 @@ use frame_system::EnsureRoot; use pallet_xcm::XcmPassthrough; use parachains_common::{ impls::ToStakingPot, - xcm_config::{ConcreteAssetFromSystem, RelayOrOtherSystemParachains}, + xcm_config::{ + AllSiblingSystemParachains, ConcreteAssetFromSystem, RelayOrOtherSystemParachains, + }, }; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::xcm_sender::ExponentialPrice; -use westend_runtime_constants::system_parachain; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, @@ -250,24 +251,13 @@ pub type Barrier = TrailingSetTopicAsId< >, >; -match_types! { - pub type SystemParachains: impl Contains = { - MultiLocation { - parents: 1, - interior: X1(Parachain( - system_parachain::ASSET_HUB_ID | - system_parachain::BRIDGE_HUB_ID | - system_parachain::COLLECTIVES_ID - )), - } - }; -} - /// Locations that will not be charged fees in the executor, /// either execution or delivery. /// We only waive fees for system functions, which these locations represent. -pub type WaivedLocations = - (RelayOrOtherSystemParachains, Equals); +pub type WaivedLocations = ( + RelayOrOtherSystemParachains, + Equals, +); /// Cases where a remote origin is accepted as trusted Teleporter for a given asset: /// - DOT with the parent Relay Chain and sibling parachains. diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs index 2ac93aed3f8..a11c477cc01 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs @@ -27,12 +27,13 @@ use frame_support::{ use frame_system::EnsureRoot; use pallet_xcm::{EnsureXcm, IsMajorityOfBody, XcmPassthrough}; use parachains_common::{ - xcm_config::{ConcreteAssetFromSystem, RelayOrOtherSystemParachains}, + xcm_config::{ + AllSiblingSystemParachains, ConcreteAssetFromSystem, RelayOrOtherSystemParachains, + }, TREASURY_PALLET_ID, }; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::xcm_sender::ExponentialPrice; -use rococo_runtime_constants::system_parachain; use sp_runtime::traits::AccountIdConversion; use xcm::latest::prelude::*; use xcm_builder::{ @@ -158,25 +159,13 @@ pub type Barrier = TrailingSetTopicAsId< >, >; -match_types! { - pub type SystemParachains: impl Contains = { - MultiLocation { - parents: 1, - interior: X1(Parachain( - system_parachain::ASSET_HUB_ID | - system_parachain::BRIDGE_HUB_ID | - system_parachain::CONTRACTS_ID | - system_parachain::ENCOINTER_ID - )), - } - }; -} - /// Locations that will not be charged fees in the executor, /// either execution or delivery. /// We only waive fees for system functions, which these locations represent. -pub type WaivedLocations = - (RelayOrOtherSystemParachains, Equals); +pub type WaivedLocations = ( + RelayOrOtherSystemParachains, + Equals, +); pub type TrustedTeleporter = ConcreteAssetFromSystem; diff --git a/polkadot/runtime/rococo/constants/Cargo.toml b/polkadot/runtime/rococo/constants/Cargo.toml index e052c89311f..a383ca65476 100644 --- a/polkadot/runtime/rococo/constants/Cargo.toml +++ b/polkadot/runtime/rococo/constants/Cargo.toml @@ -17,6 +17,7 @@ sp-weights = { path = "../../../../substrate/primitives/weights", default-featur sp-core = { path = "../../../../substrate/primitives/core", default-features = false } xcm = { package = "staging-xcm", path = "../../../xcm", default-features = false } +xcm-builder = { package = "staging-xcm-builder", path = "../../../xcm/xcm-builder", default-features = false } [features] default = ["std"] @@ -27,6 +28,7 @@ std = [ "sp-core/std", "sp-runtime/std", "sp-weights/std", + "xcm-builder/std", "xcm/std", ] diff --git a/polkadot/runtime/rococo/constants/src/lib.rs b/polkadot/runtime/rococo/constants/src/lib.rs index 2f641d60fc8..dd08b4fcab2 100644 --- a/polkadot/runtime/rococo/constants/src/lib.rs +++ b/polkadot/runtime/rococo/constants/src/lib.rs @@ -103,7 +103,8 @@ pub mod fee { /// System Parachains. pub mod system_parachain { - use xcm::latest::prelude::*; + use primitives::Id; + use xcm_builder::IsChildSystemParachain; /// Network's Asset Hub parachain ID. pub const ASSET_HUB_ID: u32 = 1000; @@ -114,11 +115,8 @@ pub mod system_parachain { /// BridgeHub parachain ID. pub const BRIDGE_HUB_ID: u32 = 1013; - frame_support::match_types! { - pub type SystemParachains: impl Contains = { - MultiLocation { parents: 0, interior: X1(Parachain(ASSET_HUB_ID | CONTRACTS_ID | ENCOINTER_ID | BRIDGE_HUB_ID)) } - }; - } + /// All system parachains of Rococo. + pub type SystemParachains = IsChildSystemParachain; } /// Rococo Treasury pallet instance. diff --git a/polkadot/runtime/westend/constants/Cargo.toml b/polkadot/runtime/westend/constants/Cargo.toml index 24f0da63b04..d2fa4158200 100644 --- a/polkadot/runtime/westend/constants/Cargo.toml +++ b/polkadot/runtime/westend/constants/Cargo.toml @@ -17,6 +17,7 @@ sp-weights = { path = "../../../../substrate/primitives/weights", default-featur sp-core = { path = "../../../../substrate/primitives/core", default-features = false } xcm = { package = "staging-xcm", path = "../../../xcm", default-features = false } +xcm-builder = { package = "staging-xcm-builder", path = "../../../xcm/xcm-builder", default-features = false } [features] default = ["std"] @@ -27,5 +28,6 @@ std = [ "sp-core/std", "sp-runtime/std", "sp-weights/std", + "xcm-builder/std", "xcm/std", ] diff --git a/polkadot/runtime/westend/constants/src/lib.rs b/polkadot/runtime/westend/constants/src/lib.rs index a06b3ba602a..de3969afb71 100644 --- a/polkadot/runtime/westend/constants/src/lib.rs +++ b/polkadot/runtime/westend/constants/src/lib.rs @@ -98,7 +98,8 @@ pub mod fee { /// System Parachains. pub mod system_parachain { - use xcm::latest::prelude::*; + use primitives::Id; + use xcm_builder::IsChildSystemParachain; /// Network's Asset Hub parachain ID. pub const ASSET_HUB_ID: u32 = 1000; @@ -107,11 +108,8 @@ pub mod system_parachain { /// BridgeHub parachain ID. pub const BRIDGE_HUB_ID: u32 = 1002; - frame_support::match_types! { - pub type SystemParachains: impl Contains = { - MultiLocation { parents: 0, interior: X1(Parachain(ASSET_HUB_ID | COLLECTIVES_ID | BRIDGE_HUB_ID ))} - }; - } + /// All system parachains of Westend. + pub type SystemParachains = IsChildSystemParachain; } /// Westend Treasury pallet instance. -- GitLab From 833478f262943d0490f44dec9938abaee7dd4aec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 6 Dec 2023 23:16:56 +0100 Subject: [PATCH 12/59] Relax approval requirements on CI files (#2564) - Remove the old Cumulus checks as these files do not exist anymore - Relax requirements on CI files to also give two core devs the right to change these files - Relax requirements on the review bot configuration itself as well. --- .github/review-bot.yml | 47 +++++++++++------------------------------- 1 file changed, 12 insertions(+), 35 deletions(-) diff --git a/.github/review-bot.yml b/.github/review-bot.yml index a5155949609..aa4ab8a69e0 100644 --- a/.github/review-bot.yml +++ b/.github/review-bot.yml @@ -1,5 +1,6 @@ rules: - name: CI files + countAuthor: true condition: include: - ^\.gitlab-ci\.yml @@ -8,24 +9,26 @@ rules: - ^\.gitlab/.* - ^\.config/nextest.toml - ^\.cargo/.* - exclude: + exclude: - ^\.gitlab/pipeline/zombienet.* - minApprovals: 2 - type: basic - teams: - - ci - - release-engineering + type: "or" + reviewers: + - minApprovals: 2 + teams: + - ci + - minApprovals: 2 + teams: + - core-devs - name: Audit rules type: basic condition: include: - - ^polkadot/runtime\/(kusama|polkadot|common)\/.* + - ^polkadot/runtime/common/.* - ^polkadot/primitives/src\/.+\.rs$ - ^substrate/primitives/.* - ^substrate/frame/.* exclude: - - ^polkadot/runtime\/(kusama|polkadot)\/src\/weights\/.+\.rs$ - ^substrate\/frame\/.+\.md$ minApprovals: 1 allowedToSkipRule: @@ -41,13 +44,8 @@ rules: - .* # excluding files from 'Runtime files' and 'CI files' rules exclude: - - ^polkadot/runtime/(kusama|polkadot)/src/[^/]+\.rs$ - - ^cumulus/parachains/runtimes/assets/(asset-hub-kusama|asset-hub-polkadot)/src/[^/]+\.rs$ - - ^cumulus/parachains/runtimes/bridge-hubs/(bridge-hub-kusama|bridge-hub-polkadot)/src/[^/]+\.rs$ - - ^cumulus/parachains/runtimes/collectives/collectives-polkadot/src/[^/]+\.rs$ - ^cumulus/parachains/common/src/[^/]+\.rs$ - ^substrate/frame/(?!.*(nfts/.*|uniques/.*|babe/.*|grandpa/.*|beefy|merkle-mountain-range/.*|contracts/.*|election|nomination-pools/.*|staking/.*|aura/.*)) - - ^polkadot/runtime/(kusama|polkadot)/src/[^/]+\.rs$ - ^\.gitlab-ci\.yml - ^docker/.* - ^\.github/.* @@ -59,24 +57,6 @@ rules: teams: - core-devs - # cumulus - - name: Runtime files cumulus - countAuthor: true - condition: - include: - - ^cumulus/parachains/runtimes/assets/(asset-hub-kusama|asset-hub-polkadot)/src/[^/]+\.rs$ - - ^cumulus/parachains/runtimes/bridge-hubs/(bridge-hub-kusama|bridge-hub-polkadot)/src/[^/]+\.rs$ - - ^cumulus/parachains/runtimes/collectives/collectives-polkadot/src/[^/]+\.rs$ - - ^cumulus/parachains/common/src/[^/]+\.rs$ - type: and-distinct - reviewers: - - minApprovals: 1 - teams: - - locks-review - - minApprovals: 1 - teams: - - polkadot-review - # if there are any changes in the bridges subtree (in case of backport changes back to bridges repo) - name: Bridges subtree files type: basic @@ -88,7 +68,6 @@ rules: - bridges-core # substrate - - name: FRAME coders substrate condition: include: @@ -104,6 +83,7 @@ rules: # Protection of THIS file - name: Review Bot + countAuthor: true condition: include: - review-bot\.yml @@ -115,9 +95,6 @@ rules: - minApprovals: 1 teams: - locks-review - - minApprovals: 1 - teams: - - ci preventReviewRequests: teams: -- GitLab From cd63276d31b0c6bcc9718fd0480ea0a9d79f18b2 Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Thu, 7 Dec 2023 09:57:43 +0100 Subject: [PATCH 13/59] [ci] Update rust to 1.74 (#2545) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cc https://github.com/paritytech/ci_cd/issues/900 --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Dónal Murray Co-authored-by: Bastian Köcher Co-authored-by: Oliver Tale-Yazdi Co-authored-by: command-bot <> --- .gitlab-ci.yml | 2 +- .../core/prospective-parachains/src/tests.rs | 8 +- .../bin/node/cli/tests/websocket_server.rs | 3 +- substrate/client/consensus/babe/src/tests.rs | 2 +- .../deprecated_where_block.stderr | 1 + ...umber_of_pallets_exceeds_tuple_size.stderr | 23 ++++- ...e_type_fails_when_type_not_in_scope.stderr | 6 +- .../call_argument_invalid_bound.stderr | 1 + .../call_argument_invalid_bound_2.stderr | 7 +- .../call_argument_invalid_bound_3.stderr | 1 + .../tests/pallet_ui/call_missing_index.stderr | 1 + .../call_weight_argument_has_suffix.stderr | 1 + .../call_weight_const_warning.stderr | 1 + .../call_weight_const_warning_twice.stderr | 1 + .../call_weight_inherited_invalid3.stderr | 1 + .../call_weight_unchecked_warning.stderr | 1 + .../pallet_ui/deprecated_store_attr.stderr | 1 + .../dev_mode_without_arg_call_index.stderr | 1 + ...ev_mode_without_arg_max_encoded_len.stderr | 12 ++- .../error_does_not_derive_pallet_error.stderr | 7 +- ...age_ensure_span_are_ok_on_wrong_gen.stderr | 84 +++++++++++++------ ...re_span_are_ok_on_wrong_gen_unnamed.stderr | 84 +++++++++++++------ .../pallet_ui/storage_info_unsatisfied.stderr | 11 ++- .../storage_info_unsatisfied_nmap.stderr | 11 ++- .../pallet_ui/store_trait_leak_private.stderr | 1 + .../ui/impl_incorrect_method_signature.stderr | 18 ++++ ...reference_in_impl_runtime_apis_call.stderr | 18 ++++ 27 files changed, 229 insertions(+), 79 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e8a91568ccf..53f723dd6c7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -21,7 +21,7 @@ workflow: - if: $CI_COMMIT_BRANCH variables: - CI_IMAGE: !reference [.ci-unified, variables, CI_IMAGE] + CI_IMAGE: "docker.io/paritytech/ci-unified:bullseye-1.74.0-2023-11-01-v20231204" # BUILDAH_IMAGE is defined in group variables BUILDAH_COMMAND: "buildah --storage-driver overlay2" RELENG_SCRIPTS_BRANCH: "master" diff --git a/polkadot/node/core/prospective-parachains/src/tests.rs b/polkadot/node/core/prospective-parachains/src/tests.rs index d2cd23fe95f..51a5ef622c0 100644 --- a/polkadot/node/core/prospective-parachains/src/tests.rs +++ b/polkadot/node/core/prospective-parachains/src/tests.rs @@ -101,11 +101,9 @@ fn test_harness>( let mut view = View::new(); let subsystem = async move { - loop { - match run_iteration(&mut context, &mut view, &Metrics(None)).await { - Ok(()) => break, - Err(e) => panic!("{:?}", e), - } + match run_iteration(&mut context, &mut view, &Metrics(None)).await { + Ok(()) => {}, + Err(e) => panic!("{:?}", e), } view diff --git a/substrate/bin/node/cli/tests/websocket_server.rs b/substrate/bin/node/cli/tests/websocket_server.rs index 432a4871cd3..b34fc82b8be 100644 --- a/substrate/bin/node/cli/tests/websocket_server.rs +++ b/substrate/bin/node/cli/tests/websocket_server.rs @@ -205,8 +205,7 @@ impl WsServer { Ok(soketto::Data::Text(len)) => String::from_utf8(buf[..len].to_vec()) .map(Message::Text) .map_err(|err| Box::new(err) as Box<_>), - Ok(soketto::Data::Binary(len)) => Ok(buf[..len].to_vec()) - .map(Message::Binary), + Ok(soketto::Data::Binary(len)) => Ok(Message::Binary(buf[..len].to_vec())), Err(err) => Err(Box::new(err) as Box<_>), }; Some((ret, (receiver, buf))) diff --git a/substrate/client/consensus/babe/src/tests.rs b/substrate/client/consensus/babe/src/tests.rs index e7096832eb3..38c9e1ff6ac 100644 --- a/substrate/client/consensus/babe/src/tests.rs +++ b/substrate/client/consensus/babe/src/tests.rs @@ -411,7 +411,7 @@ async fn run_one_test(mutator: impl Fn(&mut TestHeader, Stage) + Send + Sync + ' let mut net = net.lock(); net.poll(cx); for p in net.peers() { - for (h, e) in p.failed_verifications() { + if let Some((h, e)) = p.failed_verifications().into_iter().next() { panic!("Verification failed for {:?}: {}", h, e); } } diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr index a791c313b4a..b08efb3a842 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/deprecated_where_block.stderr @@ -17,6 +17,7 @@ error: use of deprecated constant `WhereSection::_w`: | |_^ | = note: `-D deprecated` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(deprecated)]` = note: this error originates in the macro `frame_support::match_and_insert` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Runtime: Config` is not satisfied diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.stderr index 7ed77e75da4..a8c1daf88da 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.stderr @@ -31,19 +31,34 @@ error[E0412]: cannot find type `RuntimeOrigin` in this scope --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:42:23 | 42 | type RuntimeOrigin = RuntimeOrigin; - | ^^^^^^^^^^^^^ help: you might have meant to use the associated type: `Self::RuntimeOrigin` + | ^^^^^^^^^^^^^ + | +help: you might have meant to use the associated type + | +42 | type RuntimeOrigin = Self::RuntimeOrigin; + | ++++++ error[E0412]: cannot find type `RuntimeCall` in this scope --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:44:21 | 44 | type RuntimeCall = RuntimeCall; - | ^^^^^^^^^^^ help: you might have meant to use the associated type: `Self::RuntimeCall` + | ^^^^^^^^^^^ + | +help: you might have meant to use the associated type + | +44 | type RuntimeCall = Self::RuntimeCall; + | ++++++ error[E0412]: cannot find type `RuntimeEvent` in this scope --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:50:22 | 50 | type RuntimeEvent = RuntimeEvent; - | ^^^^^^^^^^^^ help: you might have meant to use the associated type: `Self::RuntimeEvent` + | ^^^^^^^^^^^^ + | +help: you might have meant to use the associated type + | +50 | type RuntimeEvent = Self::RuntimeEvent; + | ++++++ error[E0412]: cannot find type `PalletInfo` in this scope --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:56:20 @@ -54,7 +69,7 @@ error[E0412]: cannot find type `PalletInfo` in this scope help: you might have meant to use the associated type | 56 | type PalletInfo = Self::PalletInfo; - | ~~~~~~~~~~~~~~~~ + | ++++++ help: consider importing one of these items | 18 + use frame_benchmarking::__private::traits::PalletInfo; diff --git a/substrate/frame/support/test/tests/derive_impl_ui/inject_runtime_type_fails_when_type_not_in_scope.stderr b/substrate/frame/support/test/tests/derive_impl_ui/inject_runtime_type_fails_when_type_not_in_scope.stderr index f3ac6b23281..58aae713f75 100644 --- a/substrate/frame/support/test/tests/derive_impl_ui/inject_runtime_type_fails_when_type_not_in_scope.stderr +++ b/substrate/frame/support/test/tests/derive_impl_ui/inject_runtime_type_fails_when_type_not_in_scope.stderr @@ -2,9 +2,13 @@ error[E0412]: cannot find type `RuntimeCall` in this scope --> tests/derive_impl_ui/inject_runtime_type_fails_when_type_not_in_scope.rs:30:10 | 30 | type RuntimeCall = (); - | ^^^^^^^^^^^ help: you might have meant to use the associated type: `Self::RuntimeCall` + | ^^^^^^^^^^^ ... 35 | #[derive_impl(Pallet)] // Injects type RuntimeCall = RuntimeCall; | ---------------------- in this macro invocation | = note: this error originates in the macro `Pallet` which comes from the expansion of the macro `frame_support::macro_magic::forward_tokens_verbatim` (in Nightly builds, run with -Z macro-backtrace for more info) +help: you might have meant to use the associated type + | +30 | type Self::RuntimeCall = (); + | ++++++ diff --git a/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr b/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr index 08ea7c0bec3..40f8f129830 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr @@ -10,6 +10,7 @@ error: use of deprecated constant `pallet::warnings::ConstantWeight_0::_w`: | ^ | = note: `-D deprecated` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(deprecated)]` error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` --> tests/pallet_ui/call_argument_invalid_bound.rs:38:36 diff --git a/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr b/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr index 80316fcd248..5744c636235 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr @@ -10,6 +10,7 @@ error: use of deprecated constant `pallet::warnings::ConstantWeight_0::_w`: | ^ | = note: `-D deprecated` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(deprecated)]` error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` --> tests/pallet_ui/call_argument_invalid_bound_2.rs:38:36 @@ -45,9 +46,9 @@ error[E0277]: the trait bound `::Bar: WrapperTypeEncode` is = note: required for `::Bar` to implement `Encode` error[E0277]: the trait bound `::Bar: WrapperTypeDecode` is not satisfied - --> tests/pallet_ui/call_argument_invalid_bound_2.rs:34:12 + --> tests/pallet_ui/call_argument_invalid_bound_2.rs:38:42 | -34 | #[pallet::call] - | ^^^^ the trait `WrapperTypeDecode` is not implemented for `::Bar` +38 | pub fn foo(origin: OriginFor, _bar: T::Bar) -> DispatchResultWithPostInfo { + | ^^^^^^ the trait `WrapperTypeDecode` is not implemented for `::Bar` | = note: required for `::Bar` to implement `Decode` diff --git a/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr b/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr index d45b74bad84..b58e4516bce 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr @@ -10,6 +10,7 @@ error: use of deprecated constant `pallet::warnings::ConstantWeight_0::_w`: | ^ | = note: `-D deprecated` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(deprecated)]` error[E0277]: `Bar` doesn't implement `std::fmt::Debug` --> tests/pallet_ui/call_argument_invalid_bound_3.rs:40:36 diff --git a/substrate/frame/support/test/tests/pallet_ui/call_missing_index.stderr b/substrate/frame/support/test/tests/pallet_ui/call_missing_index.stderr index 4d55ef79856..ba06285bdee 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_missing_index.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_missing_index.stderr @@ -11,6 +11,7 @@ error: use of deprecated constant `pallet::warnings::ImplicitCallIndex_0::_w`: | ^^^ | = note: `-D deprecated` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(deprecated)]` error: use of deprecated constant `pallet::warnings::ImplicitCallIndex_1::_w`: It is deprecated to use implicit call indices. diff --git a/substrate/frame/support/test/tests/pallet_ui/call_weight_argument_has_suffix.stderr b/substrate/frame/support/test/tests/pallet_ui/call_weight_argument_has_suffix.stderr index cf23a76f8ea..4b5abdcd0e6 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_weight_argument_has_suffix.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_weight_argument_has_suffix.stderr @@ -18,3 +18,4 @@ error: use of deprecated constant `pallet::warnings::ConstantWeight_0::_w`: | ^^^^^^^^^^^^^^^ | = note: `-D deprecated` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(deprecated)]` diff --git a/substrate/frame/support/test/tests/pallet_ui/call_weight_const_warning.stderr b/substrate/frame/support/test/tests/pallet_ui/call_weight_const_warning.stderr index ccd5a935773..d399df4d85b 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_weight_const_warning.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_weight_const_warning.stderr @@ -10,3 +10,4 @@ error: use of deprecated constant `pallet::warnings::ConstantWeight_0::_w`: | ^^^^^^^ | = note: `-D deprecated` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(deprecated)]` diff --git a/substrate/frame/support/test/tests/pallet_ui/call_weight_const_warning_twice.stderr b/substrate/frame/support/test/tests/pallet_ui/call_weight_const_warning_twice.stderr index aadb939b645..d7e4951e49f 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_weight_const_warning_twice.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_weight_const_warning_twice.stderr @@ -18,6 +18,7 @@ error: use of deprecated constant `pallet::warnings::ConstantWeight_0::_w`: | ^^^ | = note: `-D deprecated` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(deprecated)]` error: use of deprecated constant `pallet::warnings::ConstantWeight_1::_w`: It is deprecated to use hard-coded constant as call weight. diff --git a/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid3.stderr b/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid3.stderr index e8e6f2fe6df..339551d9811 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid3.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_weight_inherited_invalid3.stderr @@ -17,3 +17,4 @@ error: unused import: `frame_system::pallet_prelude::*` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D unused-imports` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(unused_imports)]` diff --git a/substrate/frame/support/test/tests/pallet_ui/call_weight_unchecked_warning.stderr b/substrate/frame/support/test/tests/pallet_ui/call_weight_unchecked_warning.stderr index 89fc1e0820f..33302a2a027 100644 --- a/substrate/frame/support/test/tests/pallet_ui/call_weight_unchecked_warning.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/call_weight_unchecked_warning.stderr @@ -10,3 +10,4 @@ error: use of deprecated constant `pallet::warnings::UncheckedWeightWitness_0::_ | ^^^^^^^ | = note: `-D deprecated` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(deprecated)]` diff --git a/substrate/frame/support/test/tests/pallet_ui/deprecated_store_attr.stderr b/substrate/frame/support/test/tests/pallet_ui/deprecated_store_attr.stderr index 942db0ab469..e227033d364 100644 --- a/substrate/frame/support/test/tests/pallet_ui/deprecated_store_attr.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/deprecated_store_attr.stderr @@ -7,3 +7,4 @@ error: use of deprecated struct `pallet::_::Store`: | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D deprecated` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(deprecated)]` diff --git a/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_call_index.stderr b/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_call_index.stderr index bcfe43d008f..01254584c62 100644 --- a/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_call_index.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_call_index.stderr @@ -11,6 +11,7 @@ error: use of deprecated constant `pallet::warnings::ImplicitCallIndex_0::_w`: | ^^^^^^^ | = note: `-D deprecated` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(deprecated)]` error: use of deprecated constant `pallet::warnings::ConstantWeight_0::_w`: It is deprecated to use hard-coded constant as call weight. diff --git a/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_max_encoded_len.stderr b/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_max_encoded_len.stderr index 531e8bdffeb..02ead305dd8 100644 --- a/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_max_encoded_len.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/dev_mode_without_arg_max_encoded_len.stderr @@ -11,6 +11,7 @@ error: use of deprecated constant `pallet::warnings::ImplicitCallIndex_0::_w`: | ^^^^^^^ | = note: `-D deprecated` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(deprecated)]` error: use of deprecated constant `pallet::warnings::ConstantWeight_0::_w`: It is deprecated to use hard-coded constant as call weight. @@ -26,8 +27,15 @@ error: use of deprecated constant `pallet::warnings::ConstantWeight_0::_w`: error[E0277]: the trait bound `Vec: MaxEncodedLen` is not satisfied --> tests/pallet_ui/dev_mode_without_arg_max_encoded_len.rs:28:12 | -28 | #[pallet::pallet] - | ^^^^^^ the trait `MaxEncodedLen` is not implemented for `Vec` +28 | #[pallet::pallet] + | _______________^ +29 | | pub struct Pallet(_); +30 | | +31 | | // Your Pallet's configuration trait, representing custom external types and interfaces. +... | +35 | | #[pallet::storage] +36 | | type MyStorage = StorageValue<_, Vec>; + | |__________________^ the trait `MaxEncodedLen` is not implemented for `Vec` | = help: the following other types implement trait `MaxEncodedLen`: bool diff --git a/substrate/frame/support/test/tests/pallet_ui/error_does_not_derive_pallet_error.stderr b/substrate/frame/support/test/tests/pallet_ui/error_does_not_derive_pallet_error.stderr index ea1d0ed99cd..9cefd2f4899 100644 --- a/substrate/frame/support/test/tests/pallet_ui/error_does_not_derive_pallet_error.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/error_does_not_derive_pallet_error.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `MyError: PalletError` is not satisfied - --> tests/pallet_ui/error_does_not_derive_pallet_error.rs:18:1 + --> tests/pallet_ui/error_does_not_derive_pallet_error.rs:28:15 | -18 | #[frame_support::pallet] - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `PalletError` is not implemented for `MyError` +28 | CustomError(crate::MyError), + | ^^^^^^^^^^^^^^ the trait `PalletError` is not implemented for `MyError` | = help: the following other types implement trait `PalletError`: bool @@ -14,4 +14,3 @@ error[E0277]: the trait bound `MyError: PalletError` is not satisfied u8 u16 and $N others - = note: this error originates in the derive macro `frame_support::PalletError` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr index b5d10827524..4229d1e8a54 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr @@ -1,8 +1,15 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:27:12 | -27 | #[pallet::without_storage_info] - | ^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` +27 | #[pallet::without_storage_info] + | _______________^ +28 | | pub struct Pallet(core::marker::PhantomData); +29 | | +30 | | #[pallet::hooks] +... | +38 | | #[pallet::storage] +39 | | type Foo = StorageValue; + | |____________^ the trait `WrapperTypeDecode` is not implemented for `Bar` | = help: the following other types implement trait `WrapperTypeDecode`: Box @@ -16,8 +23,15 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:27:12 | -27 | #[pallet::without_storage_info] - | ^^^^^^^^^^^^^^^^^^^^ the trait `EncodeLike` is not implemented for `Bar` +27 | #[pallet::without_storage_info] + | _______________^ +28 | | pub struct Pallet(core::marker::PhantomData); +29 | | +30 | | #[pallet::hooks] +... | +38 | | #[pallet::storage] +39 | | type Foo = StorageValue; + | |____________^ the trait `EncodeLike` is not implemented for `Bar` | = help: the following other types implement trait `EncodeLike`: @@ -36,8 +50,15 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:27:12 | -27 | #[pallet::without_storage_info] - | ^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` +27 | #[pallet::without_storage_info] + | _______________^ +28 | | pub struct Pallet(core::marker::PhantomData); +29 | | +30 | | #[pallet::hooks] +... | +38 | | #[pallet::storage] +39 | | type Foo = StorageValue; + | |____________^ the trait `WrapperTypeEncode` is not implemented for `Bar` | = help: the following other types implement trait `WrapperTypeEncode`: Box @@ -57,8 +78,10 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:38:12 | -38 | #[pallet::storage] - | ^^^^^^^ the trait `TypeInfo` is not implemented for `Bar` +38 | #[pallet::storage] + | _______________^ +39 | | type Foo = StorageValue; + | |____________^ the trait `TypeInfo` is not implemented for `Bar` | = help: the following other types implement trait `TypeInfo`: bool @@ -76,8 +99,10 @@ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:38:12 | -38 | #[pallet::storage] - | ^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` +38 | #[pallet::storage] + | _______________^ +39 | | type Foo = StorageValue; + | |____________^ the trait `WrapperTypeDecode` is not implemented for `Bar` | = help: the following other types implement trait `WrapperTypeDecode`: Box @@ -91,8 +116,10 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:38:12 | -38 | #[pallet::storage] - | ^^^^^^^ the trait `EncodeLike` is not implemented for `Bar` +38 | #[pallet::storage] + | _______________^ +39 | | type Foo = StorageValue; + | |____________^ the trait `EncodeLike` is not implemented for `Bar` | = help: the following other types implement trait `EncodeLike`: @@ -111,8 +138,10 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:38:12 | -38 | #[pallet::storage] - | ^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` +38 | #[pallet::storage] + | _______________^ +39 | | type Foo = StorageValue; + | |____________^ the trait `WrapperTypeEncode` is not implemented for `Bar` | = help: the following other types implement trait `WrapperTypeEncode`: Box @@ -130,10 +159,12 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageEntryMetadataBuilder` error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied - --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:18:1 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:38:12 | -18 | #[frame_support::pallet] - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` +38 | #[pallet::storage] + | _______________^ +39 | | type Foo = StorageValue; + | |____________^ the trait `WrapperTypeDecode` is not implemented for `Bar` | = help: the following other types implement trait `WrapperTypeDecode`: Box @@ -143,13 +174,14 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied = note: required for `Bar` to implement `Decode` = note: required for `Bar` to implement `FullCodec` = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `TryDecodeEntireStorage` - = note: this error originates in the attribute macro `frame_support::pallet` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied - --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:18:1 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:38:12 | -18 | #[frame_support::pallet] - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `EncodeLike` is not implemented for `Bar` +38 | #[pallet::storage] + | _______________^ +39 | | type Foo = StorageValue; + | |____________^ the trait `EncodeLike` is not implemented for `Bar` | = help: the following other types implement trait `EncodeLike`: @@ -164,13 +196,14 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied = note: required for `Bar` to implement `FullEncode` = note: required for `Bar` to implement `FullCodec` = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `TryDecodeEntireStorage` - = note: this error originates in the attribute macro `frame_support::pallet` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied - --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:18:1 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.rs:38:12 | -18 | #[frame_support::pallet] - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` +38 | #[pallet::storage] + | _______________^ +39 | | type Foo = StorageValue; + | |____________^ the trait `WrapperTypeEncode` is not implemented for `Bar` | = help: the following other types implement trait `WrapperTypeEncode`: Box @@ -186,4 +219,3 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied = note: required for `Bar` to implement `FullEncode` = note: required for `Bar` to implement `FullCodec` = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `TryDecodeEntireStorage` - = note: this error originates in the attribute macro `frame_support::pallet` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr index b58902590b8..855d289d0a1 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr @@ -1,8 +1,15 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:27:12 | -27 | #[pallet::without_storage_info] - | ^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` +27 | #[pallet::without_storage_info] + | _______________^ +28 | | pub struct Pallet(core::marker::PhantomData); +29 | | +30 | | #[pallet::hooks] +... | +38 | | #[pallet::storage] +39 | | type Foo = StorageValue<_, Bar>; + | |____________^ the trait `WrapperTypeDecode` is not implemented for `Bar` | = help: the following other types implement trait `WrapperTypeDecode`: Box @@ -16,8 +23,15 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:27:12 | -27 | #[pallet::without_storage_info] - | ^^^^^^^^^^^^^^^^^^^^ the trait `EncodeLike` is not implemented for `Bar` +27 | #[pallet::without_storage_info] + | _______________^ +28 | | pub struct Pallet(core::marker::PhantomData); +29 | | +30 | | #[pallet::hooks] +... | +38 | | #[pallet::storage] +39 | | type Foo = StorageValue<_, Bar>; + | |____________^ the trait `EncodeLike` is not implemented for `Bar` | = help: the following other types implement trait `EncodeLike`: @@ -36,8 +50,15 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:27:12 | -27 | #[pallet::without_storage_info] - | ^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` +27 | #[pallet::without_storage_info] + | _______________^ +28 | | pub struct Pallet(core::marker::PhantomData); +29 | | +30 | | #[pallet::hooks] +... | +38 | | #[pallet::storage] +39 | | type Foo = StorageValue<_, Bar>; + | |____________^ the trait `WrapperTypeEncode` is not implemented for `Bar` | = help: the following other types implement trait `WrapperTypeEncode`: Box @@ -57,8 +78,10 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:38:12 | -38 | #[pallet::storage] - | ^^^^^^^ the trait `TypeInfo` is not implemented for `Bar` +38 | #[pallet::storage] + | _______________^ +39 | | type Foo = StorageValue<_, Bar>; + | |____________^ the trait `TypeInfo` is not implemented for `Bar` | = help: the following other types implement trait `TypeInfo`: bool @@ -76,8 +99,10 @@ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:38:12 | -38 | #[pallet::storage] - | ^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` +38 | #[pallet::storage] + | _______________^ +39 | | type Foo = StorageValue<_, Bar>; + | |____________^ the trait `WrapperTypeDecode` is not implemented for `Bar` | = help: the following other types implement trait `WrapperTypeDecode`: Box @@ -91,8 +116,10 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:38:12 | -38 | #[pallet::storage] - | ^^^^^^^ the trait `EncodeLike` is not implemented for `Bar` +38 | #[pallet::storage] + | _______________^ +39 | | type Foo = StorageValue<_, Bar>; + | |____________^ the trait `EncodeLike` is not implemented for `Bar` | = help: the following other types implement trait `EncodeLike`: @@ -111,8 +138,10 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:38:12 | -38 | #[pallet::storage] - | ^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` +38 | #[pallet::storage] + | _______________^ +39 | | type Foo = StorageValue<_, Bar>; + | |____________^ the trait `WrapperTypeEncode` is not implemented for `Bar` | = help: the following other types implement trait `WrapperTypeEncode`: Box @@ -130,10 +159,12 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `StorageEntryMetadataBuilder` error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied - --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:18:1 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:38:12 | -18 | #[frame_support::pallet] - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeDecode` is not implemented for `Bar` +38 | #[pallet::storage] + | _______________^ +39 | | type Foo = StorageValue<_, Bar>; + | |____________^ the trait `WrapperTypeDecode` is not implemented for `Bar` | = help: the following other types implement trait `WrapperTypeDecode`: Box @@ -143,13 +174,14 @@ error[E0277]: the trait bound `Bar: WrapperTypeDecode` is not satisfied = note: required for `Bar` to implement `Decode` = note: required for `Bar` to implement `FullCodec` = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `TryDecodeEntireStorage` - = note: this error originates in the attribute macro `frame_support::pallet` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied - --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:18:1 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:38:12 | -18 | #[frame_support::pallet] - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `EncodeLike` is not implemented for `Bar` +38 | #[pallet::storage] + | _______________^ +39 | | type Foo = StorageValue<_, Bar>; + | |____________^ the trait `EncodeLike` is not implemented for `Bar` | = help: the following other types implement trait `EncodeLike`: @@ -164,13 +196,14 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied = note: required for `Bar` to implement `FullEncode` = note: required for `Bar` to implement `FullCodec` = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `TryDecodeEntireStorage` - = note: this error originates in the attribute macro `frame_support::pallet` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied - --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:18:1 + --> tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.rs:38:12 | -18 | #[frame_support::pallet] - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `Bar` +38 | #[pallet::storage] + | _______________^ +39 | | type Foo = StorageValue<_, Bar>; + | |____________^ the trait `WrapperTypeEncode` is not implemented for `Bar` | = help: the following other types implement trait `WrapperTypeEncode`: Box @@ -186,4 +219,3 @@ error[E0277]: the trait bound `Bar: WrapperTypeEncode` is not satisfied = note: required for `Bar` to implement `FullEncode` = note: required for `Bar` to implement `FullCodec` = note: required for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` to implement `TryDecodeEntireStorage` - = note: this error originates in the attribute macro `frame_support::pallet` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr index e04de98800e..504db21feeb 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr @@ -1,8 +1,15 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied --> tests/pallet_ui/storage_info_unsatisfied.rs:26:12 | -26 | #[pallet::pallet] - | ^^^^^^ the trait `MaxEncodedLen` is not implemented for `Bar` +26 | #[pallet::pallet] + | _______________^ +27 | | pub struct Pallet(core::marker::PhantomData); +28 | | +29 | | #[pallet::hooks] +... | +38 | | #[pallet::storage] +39 | | type Foo = StorageValue<_, Bar>; + | |____________^ the trait `MaxEncodedLen` is not implemented for `Bar` | = help: the following other types implement trait `MaxEncodedLen`: bool diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr index 31fe3b57338..6fd0b1959c8 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr @@ -1,8 +1,15 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied --> tests/pallet_ui/storage_info_unsatisfied_nmap.rs:29:12 | -29 | #[pallet::pallet] - | ^^^^^^ the trait `MaxEncodedLen` is not implemented for `Bar` +29 | #[pallet::pallet] + | _______________^ +30 | | pub struct Pallet(core::marker::PhantomData); +31 | | +32 | | #[pallet::hooks] +... | +41 | | #[pallet::storage] +42 | | type Foo = StorageNMap<_, Key, u32>; + | |____________^ the trait `MaxEncodedLen` is not implemented for `Bar` | = help: the following other types implement trait `MaxEncodedLen`: bool diff --git a/substrate/frame/support/test/tests/pallet_ui/store_trait_leak_private.stderr b/substrate/frame/support/test/tests/pallet_ui/store_trait_leak_private.stderr index 20144d825e8..ccb55122e81 100644 --- a/substrate/frame/support/test/tests/pallet_ui/store_trait_leak_private.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/store_trait_leak_private.stderr @@ -7,6 +7,7 @@ error: use of deprecated struct `pallet::_::Store`: | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D deprecated` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(deprecated)]` error[E0446]: private type `_GeneratedPrefixForStorageFoo` in public interface --> tests/pallet_ui/store_trait_leak_private.rs:28:37 diff --git a/substrate/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr b/substrate/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr index 4bd64c974f2..788d1807f3b 100644 --- a/substrate/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr +++ b/substrate/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr @@ -1,3 +1,21 @@ +error[E0603]: struct `RuntimeVersion` is private + --> tests/ui/impl_incorrect_method_signature.rs:37:27 + | +37 | fn version() -> sp_api::RuntimeVersion { + | ^^^^^^^^^^^^^^ private struct + | +note: the struct `RuntimeVersion` is defined here + --> $WORKSPACE/substrate/primitives/api/src/lib.rs + | + | use sp_version::RuntimeVersion; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider importing one of these items instead + | +37 | fn version() -> sp_api::__private::RuntimeVersion { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +37 | fn version() -> sp_version::RuntimeVersion { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + error[E0053]: method `test` has an incompatible type for trait --> tests/ui/impl_incorrect_method_signature.rs:33:17 | diff --git a/substrate/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr b/substrate/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr index 4c21a3afb9b..b4df7c06876 100644 --- a/substrate/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr +++ b/substrate/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr @@ -1,3 +1,21 @@ +error[E0603]: struct `RuntimeVersion` is private + --> tests/ui/type_reference_in_impl_runtime_apis_call.rs:39:27 + | +39 | fn version() -> sp_api::RuntimeVersion { + | ^^^^^^^^^^^^^^ private struct + | +note: the struct `RuntimeVersion` is defined here + --> $WORKSPACE/substrate/primitives/api/src/lib.rs + | + | use sp_version::RuntimeVersion; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider importing one of these items instead + | +39 | fn version() -> sp_api::__private::RuntimeVersion { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +39 | fn version() -> sp_version::RuntimeVersion { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + error[E0053]: method `test` has an incompatible type for trait --> tests/ui/type_reference_in_impl_runtime_apis_call.rs:33:17 | -- GitLab From 9f3c67b4ffbfb9502cdbcfcb64fcf705be118700 Mon Sep 17 00:00:00 2001 From: Nazar Mokrynskyi Date: Thu, 7 Dec 2023 13:07:12 +0200 Subject: [PATCH 14/59] Support querying peer reputation (#2392) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description Trivial change that resolves https://github.com/paritytech/polkadot-sdk/issues/2185. Since there was a mix of `who` and `peer_id` argument names nearby I changed them all to `peer_id`. # Checklist - [x] My PR includes a detailed description as outlined in the "Description" section above - [x] My PR follows the [labeling requirements](CONTRIBUTING.md#Process) of this project (at minimum one label for `T` required) - [x] I have made corresponding changes to the documentation (if applicable) - [ ] I have added tests that prove my fix is effective or that my feature works (if applicable) --------- Co-authored-by: Bastian Köcher --- .../grandpa/src/communication/tests.rs | 10 +++++--- substrate/client/network-gossip/src/bridge.rs | 8 +++++-- .../network-gossip/src/state_machine.rs | 10 +++++--- substrate/client/network/src/service.rs | 21 +++++++++-------- .../client/network/src/service/traits.rs | 23 +++++++++++-------- .../client/network/sync/src/service/mock.rs | 5 ++-- substrate/client/offchain/src/api.rs | 8 +++++-- substrate/client/offchain/src/lib.rs | 8 +++++-- 8 files changed, 60 insertions(+), 33 deletions(-) diff --git a/substrate/client/consensus/grandpa/src/communication/tests.rs b/substrate/client/consensus/grandpa/src/communication/tests.rs index b76b1af93da..fe24fb3cb20 100644 --- a/substrate/client/consensus/grandpa/src/communication/tests.rs +++ b/substrate/client/consensus/grandpa/src/communication/tests.rs @@ -75,11 +75,15 @@ impl NetworkPeers for TestNetwork { unimplemented!(); } - fn report_peer(&self, who: PeerId, cost_benefit: ReputationChange) { - let _ = self.sender.unbounded_send(Event::Report(who, cost_benefit)); + fn report_peer(&self, peer_id: PeerId, cost_benefit: ReputationChange) { + let _ = self.sender.unbounded_send(Event::Report(peer_id, cost_benefit)); } - fn disconnect_peer(&self, _who: PeerId, _protocol: ProtocolName) {} + fn peer_reputation(&self, _peer_id: &PeerId) -> i32 { + unimplemented!() + } + + fn disconnect_peer(&self, _peer_id: PeerId, _protocol: ProtocolName) {} fn accept_unreserved_peers(&self) { unimplemented!(); diff --git a/substrate/client/network-gossip/src/bridge.rs b/substrate/client/network-gossip/src/bridge.rs index c1bc414c3a3..1d6a4bdd0c0 100644 --- a/substrate/client/network-gossip/src/bridge.rs +++ b/substrate/client/network-gossip/src/bridge.rs @@ -394,9 +394,13 @@ mod tests { unimplemented!(); } - fn report_peer(&self, _who: PeerId, _cost_benefit: ReputationChange) {} + fn report_peer(&self, _peer_id: PeerId, _cost_benefit: ReputationChange) {} - fn disconnect_peer(&self, _who: PeerId, _protocol: ProtocolName) { + fn peer_reputation(&self, _peer_id: &PeerId) -> i32 { + unimplemented!() + } + + fn disconnect_peer(&self, _peer_id: PeerId, _protocol: ProtocolName) { unimplemented!(); } diff --git a/substrate/client/network-gossip/src/state_machine.rs b/substrate/client/network-gossip/src/state_machine.rs index 91b56b0f097..069d7cdba16 100644 --- a/substrate/client/network-gossip/src/state_machine.rs +++ b/substrate/client/network-gossip/src/state_machine.rs @@ -621,11 +621,15 @@ mod tests { unimplemented!(); } - fn report_peer(&self, who: PeerId, cost_benefit: ReputationChange) { - self.inner.lock().unwrap().peer_reports.push((who, cost_benefit)); + fn report_peer(&self, peer_id: PeerId, cost_benefit: ReputationChange) { + self.inner.lock().unwrap().peer_reports.push((peer_id, cost_benefit)); } - fn disconnect_peer(&self, _who: PeerId, _protocol: ProtocolName) { + fn peer_reputation(&self, _peer_id: &PeerId) -> i32 { + unimplemented!() + } + + fn disconnect_peer(&self, _peer_id: PeerId, _protocol: ProtocolName) { unimplemented!(); } diff --git a/substrate/client/network/src/service.rs b/substrate/client/network/src/service.rs index 43a3ab09115..06db23844d0 100644 --- a/substrate/client/network/src/service.rs +++ b/substrate/client/network/src/service.rs @@ -120,6 +120,8 @@ pub struct NetworkService { local_identity: Keypair, /// Bandwidth logging system. Can be queried to know the average bandwidth consumed. bandwidth: Arc, + /// Used to query and report reputation changes. + peer_store_handle: PeerStoreHandle, /// Channel that sends messages to the actual worker. to_worker: TracingUnboundedSender, /// Protocol name -> `SetId` mapping for notification protocols. The map never changes after @@ -130,8 +132,6 @@ pub struct NetworkService { protocol_handles: Vec, /// Shortcut to sync protocol handle (`protocol_handles[0]`). sync_protocol_handle: protocol_controller::ProtocolHandle, - /// Handle to `PeerStore`. - peer_store_handle: PeerStoreHandle, /// Marker to pin the `H` generic. Serves no purpose except to not break backwards /// compatibility. _marker: PhantomData, @@ -865,12 +865,18 @@ where .unbounded_send(ServiceToWorkerMsg::AddKnownAddress(peer_id, addr)); } - fn report_peer(&self, who: PeerId, cost_benefit: ReputationChange) { - let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::ReportPeer(who, cost_benefit)); + fn report_peer(&self, peer_id: PeerId, cost_benefit: ReputationChange) { + self.peer_store_handle.clone().report_peer(peer_id, cost_benefit); + } + + fn peer_reputation(&self, peer_id: &PeerId) -> i32 { + self.peer_store_handle.peer_reputation(peer_id) } - fn disconnect_peer(&self, who: PeerId, protocol: ProtocolName) { - let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::DisconnectPeer(who, protocol)); + fn disconnect_peer(&self, peer_id: PeerId, protocol: ProtocolName) { + let _ = self + .to_worker + .unbounded_send(ServiceToWorkerMsg::DisconnectPeer(peer_id, protocol)); } fn accept_unreserved_peers(&self) { @@ -1149,7 +1155,6 @@ enum ServiceToWorkerMsg { GetValue(KademliaKey), PutValue(KademliaKey, Vec), AddKnownAddress(PeerId, Multiaddr), - ReportPeer(PeerId, ReputationChange), EventStream(out_events::Sender), Request { target: PeerId, @@ -1277,8 +1282,6 @@ where self.network_service.behaviour_mut().put_value(key, value), ServiceToWorkerMsg::AddKnownAddress(peer_id, addr) => self.network_service.behaviour_mut().add_known_address(peer_id, addr), - ServiceToWorkerMsg::ReportPeer(peer_id, reputation_change) => - self.peer_store_handle.report_peer(peer_id, reputation_change), ServiceToWorkerMsg::EventStream(sender) => self.event_streams.push(sender), ServiceToWorkerMsg::Request { target, diff --git a/substrate/client/network/src/service/traits.rs b/substrate/client/network/src/service/traits.rs index f66e810be11..d4d4a05a86f 100644 --- a/substrate/client/network/src/service/traits.rs +++ b/substrate/client/network/src/service/traits.rs @@ -155,12 +155,15 @@ pub trait NetworkPeers { /// Report a given peer as either beneficial (+) or costly (-) according to the /// given scalar. - fn report_peer(&self, who: PeerId, cost_benefit: ReputationChange); + fn report_peer(&self, peer_id: PeerId, cost_benefit: ReputationChange); + + /// Get peer reputation. + fn peer_reputation(&self, peer_id: &PeerId) -> i32; /// Disconnect from a node as soon as possible. /// /// This triggers the same effects as if the connection had closed itself spontaneously. - fn disconnect_peer(&self, who: PeerId, protocol: ProtocolName); + fn disconnect_peer(&self, peer_id: PeerId, protocol: ProtocolName); /// Connect to unreserved peers and allow unreserved peers to connect for syncing purposes. fn accept_unreserved_peers(&self); @@ -254,16 +257,16 @@ where T::add_known_address(self, peer_id, addr) } - fn report_peer(&self, who: PeerId, cost_benefit: ReputationChange) { - // TODO: when we get rid of `Peerset`, we'll likely need to add some kind of async - // interface to `PeerStore`, otherwise we'll have trouble calling functions accepting - // `&mut self` via `Arc`. - // See https://github.com/paritytech/substrate/issues/14170. - T::report_peer(self, who, cost_benefit) + fn report_peer(&self, peer_id: PeerId, cost_benefit: ReputationChange) { + T::report_peer(self, peer_id, cost_benefit) + } + + fn peer_reputation(&self, peer_id: &PeerId) -> i32 { + T::peer_reputation(self, peer_id) } - fn disconnect_peer(&self, who: PeerId, protocol: ProtocolName) { - T::disconnect_peer(self, who, protocol) + fn disconnect_peer(&self, peer_id: PeerId, protocol: ProtocolName) { + T::disconnect_peer(self, peer_id, protocol) } fn accept_unreserved_peers(&self) { diff --git a/substrate/client/network/sync/src/service/mock.rs b/substrate/client/network/sync/src/service/mock.rs index 47986a71d01..6e307d86984 100644 --- a/substrate/client/network/sync/src/service/mock.rs +++ b/substrate/client/network/sync/src/service/mock.rs @@ -84,8 +84,9 @@ mockall::mock! { fn set_authorized_peers(&self, peers: HashSet); fn set_authorized_only(&self, reserved_only: bool); fn add_known_address(&self, peer_id: PeerId, addr: Multiaddr); - fn report_peer(&self, who: PeerId, cost_benefit: ReputationChange); - fn disconnect_peer(&self, who: PeerId, protocol: ProtocolName); + fn report_peer(&self, peer_id: PeerId, cost_benefit: ReputationChange); + fn peer_reputation(&self, peer_id: &PeerId) -> i32; + fn disconnect_peer(&self, peer_id: PeerId, protocol: ProtocolName); fn accept_unreserved_peers(&self); fn deny_unreserved_peers(&self); fn add_reserved_peer(&self, peer: MultiaddrWithPeerId) -> Result<(), String>; diff --git a/substrate/client/offchain/src/api.rs b/substrate/client/offchain/src/api.rs index 2901bab2f26..40f866b6d28 100644 --- a/substrate/client/offchain/src/api.rs +++ b/substrate/client/offchain/src/api.rs @@ -243,11 +243,15 @@ mod tests { unimplemented!(); } - fn report_peer(&self, _who: PeerId, _cost_benefit: ReputationChange) { + fn report_peer(&self, _peer_id: PeerId, _cost_benefit: ReputationChange) { unimplemented!(); } - fn disconnect_peer(&self, _who: PeerId, _protocol: ProtocolName) { + fn peer_reputation(&self, _peer_id: &PeerId) -> i32 { + unimplemented!() + } + + fn disconnect_peer(&self, _peer_id: PeerId, _protocol: ProtocolName) { unimplemented!(); } diff --git a/substrate/client/offchain/src/lib.rs b/substrate/client/offchain/src/lib.rs index 8bcfa66a5af..eb3436432f3 100644 --- a/substrate/client/offchain/src/lib.rs +++ b/substrate/client/offchain/src/lib.rs @@ -374,11 +374,15 @@ mod tests { unimplemented!(); } - fn report_peer(&self, _who: PeerId, _cost_benefit: ReputationChange) { + fn report_peer(&self, _peer_id: PeerId, _cost_benefit: ReputationChange) { unimplemented!(); } - fn disconnect_peer(&self, _who: PeerId, _protocol: ProtocolName) { + fn peer_reputation(&self, _peer_id: &PeerId) -> i32 { + unimplemented!() + } + + fn disconnect_peer(&self, _peer_id: PeerId, _protocol: ProtocolName) { unimplemented!(); } -- GitLab From 8f6b6322c21c1eff2d075cd2f2af77191652df6f Mon Sep 17 00:00:00 2001 From: Alexander Samusev <41779041+alvicsam@users.noreply.github.com> Date: Thu, 7 Dec 2023 12:19:07 +0100 Subject: [PATCH 15/59] [ci] Return CI_IMAGE variable (#2647) close https://github.com/paritytech/ci_cd/issues/900 --- .github/workflows/fmt-check.yml | 2 +- .gitlab-ci.yml | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/fmt-check.yml b/.github/workflows/fmt-check.yml index e4d39acabfd..99ac5120097 100644 --- a/.github/workflows/fmt-check.yml +++ b/.github/workflows/fmt-check.yml @@ -15,7 +15,7 @@ jobs: os: ["ubuntu-latest"] runs-on: ${{ matrix.os }} container: - image: paritytech/ci-unified:bullseye-1.73.0-2023-11-01-v20231025 + image: paritytech/ci-unified:bullseye-1.74.0-2023-11-01-v20231204 steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 53f723dd6c7..dc4b3cf162e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -21,7 +21,7 @@ workflow: - if: $CI_COMMIT_BRANCH variables: - CI_IMAGE: "docker.io/paritytech/ci-unified:bullseye-1.74.0-2023-11-01-v20231204" + CI_IMAGE: !reference [.ci-unified, variables, CI_IMAGE] # BUILDAH_IMAGE is defined in group variables BUILDAH_COMMAND: "buildah --storage-driver overlay2" RELENG_SCRIPTS_BRANCH: "master" @@ -116,7 +116,7 @@ default: tags: - linux-docker -# +# .forklift-cache: before_script: - 'curl --header "PRIVATE-TOKEN: $FL_CI_GROUP_TOKEN" -o forklift -L "${CI_API_V4_URL}/projects/676/packages/generic/forklift/${FL_FORKLIFT_VERSION}/forklift_${FL_FORKLIFT_VERSION}_linux_amd64"' @@ -124,19 +124,19 @@ default: - mkdir .forklift - cp $FL_FORKLIFT_CONFIG .forklift/config.toml - export FORKLIFT_PACKAGE_SUFFIX=${CI_JOB_NAME/ [0-9 \/]*} - - shopt -s expand_aliases + - shopt -s expand_aliases - export PATH=$PATH:$(pwd) - | if [ "$FORKLIFT_BYPASS" != "true" ]; then echo "FORKLIFT_BYPASS not set, creating alias cargo='forklift cargo'" alias cargo="forklift cargo" fi - - ls -al - - rm -f forklift.sock + - ls -al + - rm -f forklift.sock - forklift clean # - echo "FL_FORKLIFT_VERSION ${FL_FORKLIFT_VERSION}" - - echo "FORKLIFT_PACKAGE_SUFFIX $FORKLIFT_PACKAGE_SUFFIX" + - echo "FORKLIFT_PACKAGE_SUFFIX $FORKLIFT_PACKAGE_SUFFIX" .common-refs: rules: -- GitLab From f3073d8b33dc645da646962983f887505e1aef6e Mon Sep 17 00:00:00 2001 From: Egor_P Date: Thu, 7 Dec 2023 12:44:01 +0100 Subject: [PATCH 16/59] Fix failing rc-automation GHA (#2648) This PR adds missing `environment: release` parameter to the `rc-automation ` GHA --- .github/workflows/release-10_rc-automation.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release-10_rc-automation.yml b/.github/workflows/release-10_rc-automation.yml index f26f6b6e110..7231a8b7588 100644 --- a/.github/workflows/release-10_rc-automation.yml +++ b/.github/workflows/release-10_rc-automation.yml @@ -17,6 +17,7 @@ jobs: channel: - name: "RelEng: Polkadot Release Coordination" room: '!cqAmzdIcbOFwrdrubV:parity.io' + environment: release steps: - name: Checkout sources -- GitLab From 4d5832f7299a908c3e873ff71936ed3083fb362e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Dec 2023 14:46:20 +0100 Subject: [PATCH 17/59] Bump rand from 0.7.3 to 0.8.5 (#2645) Bumps [rand](https://github.com/rust-random/rand) from 0.7.3 to 0.8.5.
Changelog

Sourced from rand's changelog.

[0.8.5] - 2021-08-20

Fixes

  • Fix build on non-32/64-bit architectures (#1144)
  • Fix "min_const_gen" feature for no_std (#1173)
  • Check libc::pthread_atfork return value with panic on error (#1178)
  • More robust reseeding in case ReseedingRng is used from a fork handler (#1178)
  • Fix nightly: remove unused slice_partition_at_index feature (#1215)
  • Fix nightly + simd_support: update packed_simd (#1216)

Rngs

  • StdRng: Switch from HC128 to ChaCha12 on emscripten (#1142). We now use ChaCha12 on all platforms.

Documentation

  • Added docs about rand's use of const generics (#1150)
  • Better random chars example (#1157)

[0.8.4] - 2021-06-15

Additions

  • Use const-generics to support arrays of all sizes (#1104)
  • Implement Clone and Copy for Alphanumeric (#1126)
  • Add Distribution::map to derive a distribution using a closure (#1129)
  • Add Slice distribution (#1107)
  • Add DistString trait with impls for Standard and Alphanumeric (#1133)

Other

  • Reorder asserts in Uniform float distributions for easier debugging of non-finite arguments (#1094, #1108)
  • Add range overflow check in Uniform float distributions (#1108)
  • Deprecate rngs::adapter::ReadRng (#1130)

[0.8.3] - 2021-01-25

Fixes

  • Fix no-std + alloc build by gating choose_multiple_weighted on std (#1088)

[0.8.2] - 2021-01-12

Fixes

  • Fix panic in UniformInt::sample_single_inclusive and Rng::gen_range when providing a full integer range (eg 0..=MAX) (#1087)

[0.8.1] - 2020-12-31

Other

  • Enable all stable features in the playground (#1081)

[0.8.0] - 2020-12-18

Platform support

  • The minimum supported Rust version is now 1.36 (#1011)
  • getrandom updated to v0.2 (#1041)
  • Remove wasm-bindgen and stdweb feature flags. For details of WASM support,

... (truncated)

Commits
  • 937320c Update CHANGELOG for 0.8.5 (#1221)
  • 2924af6 Merge pull request #1183 from vks/fill-float-doc
  • dbbc1bf Merge pull request #1218 from Will-Low/master
  • 9f20df0 Making distributions comparable by deriving PartialEq. Tests included
  • a407bdf Merge pull request #1216 from rust-random/work5
  • d3ca11b Update to packed_simd_2 0.3.7
  • fa04c15 Merge pull request #1215 from Lantern-chat/master
  • 73f8ffd Remove unused slice_partition_at_index feature
  • 8f37250 Merge pull request #1208 from newpavlov/rand_distr/fix_no_std
  • 9ef737b update changelog
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=rand&package-manager=cargo&previous-version=0.7.3&new-version=0.8.5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 2 +- substrate/primitives/keystore/Cargo.toml | 2 +- substrate/utils/frame/benchmarking-cli/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 13f89d645b4..2e0de32bc6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17611,7 +17611,7 @@ version = "0.27.0" dependencies = [ "parity-scale-codec", "parking_lot 0.12.1", - "rand 0.7.3", + "rand 0.8.5", "rand_chacha 0.2.2", "sp-core", "sp-externalities 0.19.0", diff --git a/substrate/primitives/keystore/Cargo.toml b/substrate/primitives/keystore/Cargo.toml index 819b2c518a0..dcfb272c11a 100644 --- a/substrate/primitives/keystore/Cargo.toml +++ b/substrate/primitives/keystore/Cargo.toml @@ -20,7 +20,7 @@ sp-core = { path = "../core", default-features = false } sp-externalities = { path = "../externalities", default-features = false } [dev-dependencies] -rand = "0.7.2" +rand = "0.8.5" rand_chacha = "0.2.2" [features] diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml index b6eca132067..e88eb60ee63 100644 --- a/substrate/utils/frame/benchmarking-cli/Cargo.toml +++ b/substrate/utils/frame/benchmarking-cli/Cargo.toml @@ -24,7 +24,7 @@ itertools = "0.10.3" lazy_static = "1.4.0" linked-hash-map = "0.5.4" log = "0.4.17" -rand = { version = "0.8.4", features = ["small_rng"] } +rand = { version = "0.8.5", features = ["small_rng"] } rand_pcg = "0.3.1" serde = "1.0.193" serde_json = "1.0.108" -- GitLab From 26116cdb0234f71ab1aef3cbaaa2a80c0d47bb09 Mon Sep 17 00:00:00 2001 From: Anwesh Date: Thu, 7 Dec 2023 19:49:34 +0530 Subject: [PATCH 18/59] Improve inline comment for ClaimPermission extrinsic of nom pools (#2640) --- substrate/frame/nomination-pools/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs index f191126fbdd..c3fd6a98e88 100644 --- a/substrate/frame/nomination-pools/src/lib.rs +++ b/substrate/frame/nomination-pools/src/lib.rs @@ -460,7 +460,7 @@ pub enum ClaimPermission { PermissionlessCompound, /// Anyone can withdraw rewards on a pool member's behalf. PermissionlessWithdraw, - /// Anyone can withdraw and compound rewards on a member's behalf. + /// Anyone can withdraw and compound rewards on a pool member's behalf. PermissionlessAll, } -- GitLab From 1a4ab64bcb3d6626758431aa8784ad019730c4fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 7 Dec 2023 17:04:18 +0100 Subject: [PATCH 19/59] Fix recursive trait bounds (#2644) Closes: https://github.com/paritytech/polkadot-sdk/issues/2641 --- polkadot/runtime/rococo/src/lib.rs | 5 ++--- polkadot/runtime/westend/src/lib.rs | 7 +++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 26670cdcc23..572cdf1aade 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -276,8 +276,7 @@ impl pallet_babe::Config for Runtime { type WeightInfo = (); type MaxAuthorities = MaxAuthorities; type MaxNominators = ConstU32<0>; - type KeyOwnerProof = - >::Proof; + type KeyOwnerProof = sp_session::MembershipProof; type EquivocationReportSystem = pallet_babe::EquivocationReportSystem; } @@ -565,7 +564,7 @@ impl pallet_grandpa::Config for Runtime { type MaxAuthorities = MaxAuthorities; type MaxNominators = ConstU32<0>; type MaxSetIdSessionEntries = MaxSetIdSessionEntries; - type KeyOwnerProof = >::Proof; + type KeyOwnerProof = sp_session::MembershipProof; type EquivocationReportSystem = pallet_grandpa::EquivocationReportSystem; } diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 04723ef0d9b..25d4c1d2d6f 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -264,8 +264,7 @@ impl pallet_babe::Config for Runtime { type MaxAuthorities = MaxAuthorities; type MaxNominators = MaxNominators; - type KeyOwnerProof = - >::Proof; + type KeyOwnerProof = sp_session::MembershipProof; type EquivocationReportSystem = pallet_babe::EquivocationReportSystem; @@ -317,7 +316,7 @@ impl pallet_beefy::Config for Runtime { type MaxSetIdSessionEntries = BeefySetIdSessionEntries; type OnNewValidatorSet = BeefyMmrLeaf; type WeightInfo = (); - type KeyOwnerProof = >::Proof; + type KeyOwnerProof = sp_session::MembershipProof; type EquivocationReportSystem = pallet_beefy::EquivocationReportSystem; } @@ -801,7 +800,7 @@ impl pallet_grandpa::Config for Runtime { type MaxNominators = MaxNominators; type MaxSetIdSessionEntries = MaxSetIdSessionEntries; - type KeyOwnerProof = >::Proof; + type KeyOwnerProof = sp_session::MembershipProof; type EquivocationReportSystem = pallet_grandpa::EquivocationReportSystem; -- GitLab From 95c3ee10bc90cb0cb9729aa545b962e3c006ce42 Mon Sep 17 00:00:00 2001 From: dzmitry-lahoda Date: Thu, 7 Dec 2023 16:40:16 +0000 Subject: [PATCH 20/59] feat(xcm): support json schema (for CosmWasm VM support) (#1454) # Description - What does this PR do? Allows to generate JSON schema for subset of XCM in std builds - Why are these changes needed? To support XCM messages in CosmWasm contracts which require Schemars to generate contract clients - How were these changes implemented and what do they affect? We will use schema feature flag to build XCM pallet with JSON schema enabled # Checklist - [x] My PR includes a detailed description as outlined in the "Description" section above - [x] My PR follows the [labeling requirements](CONTRIBUTING.md#Process) of this project (at minimum one label for `T` required) - [x] I have made corresponding changes to the documentation (if applicable) - [x] I have added tests that prove my fix is effective or that my feature works (if applicable) - [x] If this PR alters any external APIs or interfaces used by Polkadot, the corresponding Polkadot PR is ready as well as the corresponding Cumulus PR (optional) --- Cargo.lock | 42 ++++++++++++++++++- polkadot/xcm/Cargo.toml | 4 +- polkadot/xcm/src/double_encoded.rs | 1 + polkadot/xcm/src/v2/mod.rs | 1 + polkadot/xcm/src/v3/junction.rs | 4 ++ polkadot/xcm/src/v3/junctions.rs | 1 + polkadot/xcm/src/v3/mod.rs | 10 +++++ polkadot/xcm/src/v3/multiasset.rs | 8 ++++ polkadot/xcm/src/v3/multilocation.rs | 1 + polkadot/xcm/src/v3/traits.rs | 1 + prdoc/pr_1454.prdoc | 10 +++++ substrate/primitives/weights/Cargo.toml | 5 +++ substrate/primitives/weights/src/weight_v2.rs | 1 + 13 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 prdoc/pr_1454.prdoc diff --git a/Cargo.lock b/Cargo.lock index 2e0de32bc6e..7f414cfff6f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1521,13 +1521,14 @@ dependencies = [ [[package]] name = "bounded-collections" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5b05133427c07c4776906f673ccf36c21b102c9829c641a5b56bd151d44fd6" +checksum = "ca548b6163b872067dc5eb82fd130c56881435e30367d2073594a3d9744120dd" dependencies = [ "log", "parity-scale-codec", "scale-info", + "schemars", "serde", ] @@ -16344,6 +16345,30 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "schemars" +version = "0.8.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "763f8cd0d4c71ed8389c90cb8100cba87e763bd01a8e614d4f0af97bcd50a161" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0f696e21e10fa546b7ffb1c9672c6de8fbc7a81acf59524386d8639bf12737" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 1.0.109", +] + [[package]] name = "schnellru" version = "0.2.1" @@ -16614,6 +16639,17 @@ dependencies = [ "syn 2.0.39", ] +[[package]] +name = "serde_derive_internals" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "serde_fmt" version = "1.0.3" @@ -18117,6 +18153,7 @@ dependencies = [ "bounded-collections", "parity-scale-codec", "scale-info", + "schemars", "serde", "smallvec", "sp-arithmetic", @@ -18353,6 +18390,7 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", + "schemars", "serde", "sp-io", "sp-weights", diff --git a/polkadot/xcm/Cargo.toml b/polkadot/xcm/Cargo.toml index 8fa0d128950..3d05957a3fe 100644 --- a/polkadot/xcm/Cargo.toml +++ b/polkadot/xcm/Cargo.toml @@ -7,7 +7,7 @@ edition.workspace = true license.workspace = true [dependencies] -bounded-collections = { version = "0.1.8", default-features = false, features = ["serde"] } +bounded-collections = { version = "0.1.9", default-features = false, features = ["serde"] } derivative = { version = "2.2.0", default-features = false, features = ["use_core"] } impl-trait-for-tuples = "0.2.2" log = { version = "0.4.17", default-features = false } @@ -15,6 +15,7 @@ parity-scale-codec = { version = "3.6.1", default-features = false, features = [ scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } sp-weights = { path = "../../substrate/primitives/weights", default-features = false, features = ["serde"] } serde = { version = "1.0.193", default-features = false, features = ["alloc", "derive"] } +schemars = { version = "0.8.13", default-features = true, optional = true } xcm-procedural = { path = "procedural" } environmental = { version = "1.1.4", default-features = false } @@ -35,3 +36,4 @@ std = [ "serde/std", "sp-weights/std", ] +json-schema = ["bounded-collections/json-schema", "dep:schemars", "sp-weights/json-schema"] diff --git a/polkadot/xcm/src/double_encoded.rs b/polkadot/xcm/src/double_encoded.rs index 875b811da3f..45856f657d1 100644 --- a/polkadot/xcm/src/double_encoded.rs +++ b/polkadot/xcm/src/double_encoded.rs @@ -25,6 +25,7 @@ use parity_scale_codec::{Decode, DecodeLimit, Encode}; #[codec(decode_bound())] #[scale_info(bounds(), skip_type_params(T))] #[scale_info(replace_segment("staging_xcm", "xcm"))] +#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] pub struct DoubleEncoded { encoded: Vec, #[codec(skip)] diff --git a/polkadot/xcm/src/v2/mod.rs b/polkadot/xcm/src/v2/mod.rs index 7f654ebfd9e..188b7f0b5c9 100644 --- a/polkadot/xcm/src/v2/mod.rs +++ b/polkadot/xcm/src/v2/mod.rs @@ -82,6 +82,7 @@ pub use traits::{Error, ExecuteXcm, GetWeight, Outcome, Result, SendError, SendR /// Basically just the XCM (more general) version of `ParachainDispatchOrigin`. #[derive(Copy, Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)] #[scale_info(replace_segment("staging_xcm", "xcm"))] +#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] pub enum OriginKind { /// Origin should just be the native dispatch origin representation for the sender in the /// local runtime framework. For Cumulus/Frame chains this is the `Parachain` or `Relay` origin diff --git a/polkadot/xcm/src/v3/junction.rs b/polkadot/xcm/src/v3/junction.rs index 5e6e4ab903b..6ae339db2ae 100644 --- a/polkadot/xcm/src/v3/junction.rs +++ b/polkadot/xcm/src/v3/junction.rs @@ -49,6 +49,7 @@ use serde::{Deserialize, Serialize}; Serialize, Deserialize, )] +#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] #[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum NetworkId { /// Network specified by the first 32 bytes of its genesis block. @@ -119,6 +120,7 @@ impl TryFrom for NetworkId { Serialize, Deserialize, )] +#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] #[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum BodyId { /// The only body in its context. @@ -190,6 +192,7 @@ impl TryFrom for BodyId { Serialize, Deserialize, )] +#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] #[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum BodyPart { /// The body's declaration, under whatever means it decides. @@ -266,6 +269,7 @@ impl TryFrom for BodyPart { Serialize, Deserialize, )] +#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] #[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum Junction { /// An indexed parachain belonging to and operated by the context. diff --git a/polkadot/xcm/src/v3/junctions.rs b/polkadot/xcm/src/v3/junctions.rs index d1cbc2dbed4..88da20cb1a1 100644 --- a/polkadot/xcm/src/v3/junctions.rs +++ b/polkadot/xcm/src/v3/junctions.rs @@ -44,6 +44,7 @@ pub(crate) const MAX_JUNCTIONS: usize = 8; serde::Serialize, serde::Deserialize, )] +#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] #[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum Junctions { /// The interpreting consensus system. diff --git a/polkadot/xcm/src/v3/mod.rs b/polkadot/xcm/src/v3/mod.rs index bbdd504ceb0..50b7a539122 100644 --- a/polkadot/xcm/src/v3/mod.rs +++ b/polkadot/xcm/src/v3/mod.rs @@ -69,6 +69,7 @@ pub type QueryId = u64; #[codec(encode_bound())] #[scale_info(bounds(), skip_type_params(Call))] #[scale_info(replace_segment("staging_xcm", "xcm"))] +#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] pub struct Xcm(pub Vec>); /// The maximal number of instructions in an XCM before decoding fails. @@ -232,15 +233,19 @@ pub mod prelude { } parameter_types! { + #[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] pub MaxPalletNameLen: u32 = 48; /// Maximum size of the encoded error code coming from a `Dispatch` result, used for /// `MaybeErrorCode`. This is not (yet) enforced, so it's just an indication of expectation. + #[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] pub MaxDispatchErrorLen: u32 = 128; + #[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] pub MaxPalletsInfo: u32 = 64; } #[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] #[scale_info(replace_segment("staging_xcm", "xcm"))] +#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] pub struct PalletInfo { #[codec(compact)] pub index: u32, @@ -272,6 +277,7 @@ impl PalletInfo { #[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] #[scale_info(replace_segment("staging_xcm", "xcm"))] +#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] pub enum MaybeErrorCode { Success, Error(BoundedVec), @@ -296,6 +302,7 @@ impl Default for MaybeErrorCode { /// Response data to a query. #[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)] #[scale_info(replace_segment("staging_xcm", "xcm"))] +#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] pub enum Response { /// No response. Serves as a neutral default. Null, @@ -320,6 +327,7 @@ impl Default for Response { /// Information regarding the composition of a query response. #[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)] #[scale_info(replace_segment("staging_xcm", "xcm"))] +#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] pub struct QueryResponseInfo { /// The destination to which the query response message should be send. pub destination: MultiLocation, @@ -333,6 +341,7 @@ pub struct QueryResponseInfo { /// An optional weight limit. #[derive(Clone, Eq, PartialEq, Encode, Decode, Debug, TypeInfo)] #[scale_info(replace_segment("staging_xcm", "xcm"))] +#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] pub enum WeightLimit { /// No weight limit imposed. Unlimited, @@ -417,6 +426,7 @@ impl XcmContext { #[codec(decode_bound())] #[scale_info(bounds(), skip_type_params(Call))] #[scale_info(replace_segment("staging_xcm", "xcm"))] +#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] pub enum Instruction { /// Withdraw asset(s) (`assets`) from the ownership of `origin` and place them into the Holding /// Register. diff --git a/polkadot/xcm/src/v3/multiasset.rs b/polkadot/xcm/src/v3/multiasset.rs index 454120a1a7b..c8801f5a461 100644 --- a/polkadot/xcm/src/v3/multiasset.rs +++ b/polkadot/xcm/src/v3/multiasset.rs @@ -47,6 +47,7 @@ use scale_info::TypeInfo; Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen, )] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] #[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum AssetInstance { /// Undefined - used if the non-fungible asset class has only one instance. @@ -243,6 +244,7 @@ impl TryFrom for u128 { /// instance. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] #[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum Fungibility { /// A fungible asset; we record a number of units, as a `u128` in the inner item. @@ -313,6 +315,7 @@ impl TryFrom for Fungibility { Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo, MaxEncodedLen, )] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] #[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum WildFungibility { /// The asset is fungible. @@ -337,6 +340,7 @@ impl TryFrom for WildFungibility { Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo, MaxEncodedLen, )] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] #[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum AssetId { /// A specific location identifying an asset. @@ -412,6 +416,7 @@ impl AssetId { /// Either an amount of a single fungible asset, or a single well-identified non-fungible asset. #[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] #[scale_info(replace_segment("staging_xcm", "xcm"))] pub struct MultiAsset { /// The overall asset identity (aka *class*, in the case of a non-fungible). @@ -510,6 +515,7 @@ impl TryFrom for MultiAsset { /// - The number of items should grow no larger than `MAX_ITEMS_IN_MULTIASSETS`. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, TypeInfo, Default)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] #[scale_info(replace_segment("staging_xcm", "xcm"))] pub struct MultiAssets(Vec); @@ -710,6 +716,7 @@ impl MultiAssets { /// A wildcard representing a set of assets. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] #[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum WildMultiAsset { /// All assets in Holding. @@ -823,6 +830,7 @@ impl, B: Into> From<(A, B)> for WildMultiAsset /// `MultiAsset` collection, defined either by a number of `MultiAssets` or a single wildcard. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] #[scale_info(replace_segment("staging_xcm", "xcm"))] pub enum MultiAssetFilter { /// Specify the filter as being everything contained by the given `MultiAssets` inner. diff --git a/polkadot/xcm/src/v3/multilocation.rs b/polkadot/xcm/src/v3/multilocation.rs index 89e25984443..9649b1b3207 100644 --- a/polkadot/xcm/src/v3/multilocation.rs +++ b/polkadot/xcm/src/v3/multilocation.rs @@ -66,6 +66,7 @@ use scale_info::TypeInfo; serde::Serialize, serde::Deserialize, )] +#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] pub struct MultiLocation { /// The number of parent junctions at the beginning of this `MultiLocation`. pub parents: u8, diff --git a/polkadot/xcm/src/v3/traits.rs b/polkadot/xcm/src/v3/traits.rs index 6054bf1456a..29bd40a6a2d 100644 --- a/polkadot/xcm/src/v3/traits.rs +++ b/polkadot/xcm/src/v3/traits.rs @@ -30,6 +30,7 @@ use super::*; /// they will retain the same index over time. #[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)] #[scale_info(replace_segment("staging_xcm", "xcm"))] +#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] pub enum Error { // Errors that happen due to instructions being executed. These alone are defined in the // XCM specification. diff --git a/prdoc/pr_1454.prdoc b/prdoc/pr_1454.prdoc new file mode 100644 index 00000000000..c96bfcde6cf --- /dev/null +++ b/prdoc/pr_1454.prdoc @@ -0,0 +1,10 @@ +title: Support XCM as part of Cosmos CosmWasm contract messages + +doc: + - audience: Runtime Dev + description: | + Made XCM JSON schema behind flag, bumped bounded-collection so to ensure it has that flag too. + +crates: + - name: staging-xcm + - name: sp-weights diff --git a/substrate/primitives/weights/Cargo.toml b/substrate/primitives/weights/Cargo.toml index 163b241276c..fb2e2ae8cb1 100644 --- a/substrate/primitives/weights/Cargo.toml +++ b/substrate/primitives/weights/Cargo.toml @@ -21,6 +21,7 @@ smallvec = "1.11.0" sp-arithmetic = { path = "../arithmetic", default-features = false } sp-debug-derive = { path = "../debug-derive", default-features = false } sp-std = { path = "../std", default-features = false } +schemars = { version = "0.8.3", default-features = false, optional = true } [features] default = ["std"] @@ -44,3 +45,7 @@ serde = [ "scale-info/serde", "sp-arithmetic/serde", ] + +json-schema = [ + "dep:schemars", +] diff --git a/substrate/primitives/weights/src/weight_v2.rs b/substrate/primitives/weights/src/weight_v2.rs index d692aaff8f5..3c10929f433 100644 --- a/substrate/primitives/weights/src/weight_v2.rs +++ b/substrate/primitives/weights/src/weight_v2.rs @@ -23,6 +23,7 @@ use super::*; #[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Eq, PartialEq, Copy, Clone, Debug, Default)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))] pub struct Weight { #[codec(compact)] /// The weight of computational time used based on some reference hardware. -- GitLab From 7e7fe9904744beb91ed4b13f2fac19cf10f8741f Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Thu, 7 Dec 2023 17:48:13 +0100 Subject: [PATCH 21/59] [FRAME] Make MQ pallet re-entrancy safe (#2356) Closes https://github.com/paritytech/polkadot-sdk/issues/2319 Changes: - Ensure that only `enqueue_message(s)` is callable from within the message processor. This prevents messed up storage that can currently happen when the pallet is called into recursively. - Use `H256` instead of `[u8; 32]` for clearer API. ## Details The re-entracy check is done with the `environmental` crate by adding a `with_service_mutex(f)` function that runs the closure exclusively. This works since the MQ pallet is not instantiable. --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Francisco Aguirre --- Cargo.lock | 1 + cumulus/pallets/xcmp-queue/src/tests.rs | 11 +- polkadot/runtime/parachains/src/ump_tests.rs | 8 +- substrate/frame/message-queue/Cargo.toml | 2 + .../frame/message-queue/src/benchmarking.rs | 7 +- .../message-queue/src/integration_test.rs | 82 ++++++- substrate/frame/message-queue/src/lib.rs | 227 ++++++++++++++---- substrate/frame/message-queue/src/mock.rs | 30 ++- .../frame/message-queue/src/mock_helpers.rs | 4 + substrate/frame/message-queue/src/tests.rs | 185 +++++++++++++- .../frame/support/src/traits/messages.rs | 2 + 11 files changed, 479 insertions(+), 80 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7f414cfff6f..d1735ec83af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10035,6 +10035,7 @@ dependencies = [ name = "pallet-message-queue" version = "7.0.0-dev" dependencies = [ + "environmental", "frame-benchmarking", "frame-support", "frame-system", diff --git a/cumulus/pallets/xcmp-queue/src/tests.rs b/cumulus/pallets/xcmp-queue/src/tests.rs index 50c2a057d42..8e8f6e852e1 100644 --- a/cumulus/pallets/xcmp-queue/src/tests.rs +++ b/cumulus/pallets/xcmp-queue/src/tests.rs @@ -22,8 +22,7 @@ use XcmpMessageFormat::*; use codec::Input; use cumulus_primitives_core::{ParaId, XcmpMessageHandler}; use frame_support::{ - assert_err, assert_noop, assert_ok, assert_storage_noop, hypothetically, - traits::{Footprint, Hooks}, + assert_err, assert_noop, assert_ok, assert_storage_noop, hypothetically, traits::Hooks, StorageNoopGuard, }; use mock::{new_test_ext, ParachainSystem, RuntimeOrigin as Origin, Test, XcmpQueue}; @@ -100,7 +99,7 @@ fn xcm_enqueueing_multiple_times_works() { } #[test] -#[cfg_attr(debug_assertions, should_panic = "Defensive failure")] +#[cfg_attr(debug_assertions, should_panic = "Could not enqueue XCMP messages.")] fn xcm_enqueueing_starts_dropping_on_overflow() { new_test_ext().execute_with(|| { let xcm = VersionedXcm::::from(Xcm::(vec![ClearOrigin])); @@ -112,12 +111,6 @@ fn xcm_enqueueing_starts_dropping_on_overflow() { repeat((1000.into(), 1, data.as_slice())).take(limit * 2), Weight::MAX, ); - assert_eq!(EnqueuedMessages::get().len(), limit); - // The drop threshold for pages is 48, the others numbers dont really matter: - assert_eq!( - ::XcmpQueue::footprint(1000.into()), - QueueFootprint { storage: Footprint { count: 256, size: 768 }, pages: 48 } - ); }) } diff --git a/polkadot/runtime/parachains/src/ump_tests.rs b/polkadot/runtime/parachains/src/ump_tests.rs index def60888205..426993ffa65 100644 --- a/polkadot/runtime/parachains/src/ump_tests.rs +++ b/polkadot/runtime/parachains/src/ump_tests.rs @@ -523,21 +523,21 @@ fn overweight_queue_works() { assert_last_events( [ pallet_message_queue::Event::::Processed { - id: hash_1, + id: hash_1.into(), origin: Ump(UmpQueueId::Para(para_a)), weight_used: Weight::from_parts(301, 301), success: true, } .into(), pallet_message_queue::Event::::OverweightEnqueued { - id: hash_2, + id: hash_2.into(), origin: Ump(UmpQueueId::Para(para_a)), page_index: 0, message_index: 1, } .into(), pallet_message_queue::Event::::OverweightEnqueued { - id: hash_3, + id: hash_3.into(), origin: Ump(UmpQueueId::Para(para_a)), page_index: 0, message_index: 2, @@ -565,7 +565,7 @@ fn overweight_queue_works() { )); assert_last_event( pallet_message_queue::Event::::Processed { - id: hash_3, + id: hash_3.into(), origin: Ump(UmpQueueId::Para(para_a)), weight_used: Weight::from_parts(501, 501), success: true, diff --git a/substrate/frame/message-queue/Cargo.toml b/substrate/frame/message-queue/Cargo.toml index 148848f2bf0..614e5885b4b 100644 --- a/substrate/frame/message-queue/Cargo.toml +++ b/substrate/frame/message-queue/Cargo.toml @@ -13,6 +13,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.193", optional = true, features = ["derive"] } log = { version = "0.4.17", default-features = false } +environmental = { version = "1.1.4", default-features = false } sp-core = { path = "../../primitives/core", default-features = false } sp-io = { path = "../../primitives/io", default-features = false } @@ -34,6 +35,7 @@ rand_distr = "0.4.3" default = ["std"] std = [ "codec/std", + "environmental/std", "frame-benchmarking?/std", "frame-support/std", "frame-system/std", diff --git a/substrate/frame/message-queue/src/benchmarking.rs b/substrate/frame/message-queue/src/benchmarking.rs index eedaaebeca9..7e99bc05858 100644 --- a/substrate/frame/message-queue/src/benchmarking.rs +++ b/substrate/frame/message-queue/src/benchmarking.rs @@ -25,6 +25,7 @@ use super::{mock_helpers::*, Pallet as MessageQueue, *}; use frame_benchmarking::v2::*; use frame_support::traits::Get; use frame_system::RawOrigin; +use sp_io::hashing::blake2_256; use sp_std::prelude::*; #[benchmarks( @@ -142,7 +143,7 @@ mod benchmarks { // Check that it was processed. assert_last_event::( Event::Processed { - id: sp_io::hashing::blake2_256(&msg), + id: blake2_256(&msg).into(), origin: 0.into(), weight_used: 1.into_weight(), success: true, @@ -227,7 +228,7 @@ mod benchmarks { assert_last_event::( Event::Processed { - id: sp_io::hashing::blake2_256(&((msgs - 1) as u32).encode()), + id: blake2_256(&((msgs - 1) as u32).encode()).into(), origin: 0.into(), weight_used: Weight::from_parts(1, 1), success: true, @@ -264,7 +265,7 @@ mod benchmarks { assert_last_event::( Event::Processed { - id: sp_io::hashing::blake2_256(&((msgs - 1) as u32).encode()), + id: blake2_256(&((msgs - 1) as u32).encode()).into(), origin: 0.into(), weight_used: Weight::from_parts(1, 1), success: true, diff --git a/substrate/frame/message-queue/src/integration_test.rs b/substrate/frame/message-queue/src/integration_test.rs index 53dc204ab9c..fee5d242135 100644 --- a/substrate/frame/message-queue/src/integration_test.rs +++ b/substrate/frame/message-queue/src/integration_test.rs @@ -29,8 +29,8 @@ use crate::{ mock::{ - build_and_execute, CountingMessageProcessor, IntoWeight, MockedWeightInfo, - NumMessagesProcessed, YieldingQueues, + build_and_execute, gen_seed, Callback, CountingMessageProcessor, IntoWeight, + MessagesProcessed, MockedWeightInfo, NumMessagesProcessed, YieldingQueues, }, mock_helpers::MessageOrigin, *, @@ -120,13 +120,13 @@ impl Config for Test { /// Processing all remaining 28639 messages /// ``` #[test] -#[ignore] // Only run in the CI. +#[ignore] // Only run in the CI, otherwise its too slow. fn stress_test_enqueue_and_service() { let blocks = 20; let max_queues = 10_000; let max_messages_per_queue = 10_000; let max_msg_len = MaxMessageLenOf::::get(); - let mut rng = StdRng::seed_from_u64(43); + let mut rng = StdRng::seed_from_u64(gen_seed()); build_and_execute::(|| { let mut msgs_remaining = 0; @@ -148,6 +148,74 @@ fn stress_test_enqueue_and_service() { }); } +/// Very similar to `stress_test_enqueue_and_service`, but enqueues messages while processing them. +#[test] +#[ignore] // Only run in the CI, otherwise its too slow. +fn stress_test_recursive() { + let blocks = 20; + let mut rng = StdRng::seed_from_u64(gen_seed()); + + // We need to use thread-locals since the callback cannot capture anything. + parameter_types! { + pub static TotalEnqueued: u32 = 0; + pub static Enqueued: u32 = 0; + pub static Called: u32 = 0; + } + + Called::take(); + Enqueued::take(); + TotalEnqueued::take(); + + Callback::set(Box::new(|_, _| { + let mut rng = StdRng::seed_from_u64(Enqueued::get() as u64); + let max_queues = 1_000; + let max_messages_per_queue = 1_000; + let max_msg_len = MaxMessageLenOf::::get(); + + // Instead of directly enqueueing, we enqueue inside a `service` call. + let enqueued = enqueue_messages(max_queues, max_messages_per_queue, max_msg_len, &mut rng); + TotalEnqueued::set(TotalEnqueued::get() + enqueued); + Enqueued::set(Enqueued::get() + enqueued); + Called::set(Called::get() + 1); + })); + + build_and_execute::(|| { + let mut msgs_remaining = 0; + for b in 0..blocks { + log::info!("Block #{}", b); + MessageQueue::enqueue_message( + BoundedSlice::defensive_truncate_from(format!("callback={b}").as_bytes()), + b.into(), + ); + + msgs_remaining += Enqueued::take() + 1; + // Pick a fraction of all messages currently in queue and process them. + let processed = rng.gen_range(1..=msgs_remaining); + log::info!("Processing {} of all messages {}", processed, msgs_remaining); + process_some_messages(processed); // This also advances the block. + msgs_remaining -= processed; + TotalEnqueued::set(TotalEnqueued::get() - processed + 1); + MessageQueue::do_try_state().unwrap(); + } + while Called::get() < blocks { + msgs_remaining += Enqueued::take(); + // Pick a fraction of all messages currently in queue and process them. + let processed = rng.gen_range(1..=msgs_remaining); + log::info!("Processing {} of all messages {}", processed, msgs_remaining); + process_some_messages(processed); // This also advances the block. + msgs_remaining -= processed; + TotalEnqueued::set(TotalEnqueued::get() - processed); + MessageQueue::do_try_state().unwrap(); + } + + let msgs_remaining = TotalEnqueued::take(); + log::info!("Processing all remaining {} messages", msgs_remaining); + process_all_messages(msgs_remaining); + assert_eq!(Called::get(), blocks); + post_conditions(); + }); +} + /// Simulates heavy usage of the suspension logic via `Yield`. /// /// # Example output @@ -164,14 +232,14 @@ fn stress_test_enqueue_and_service() { /// Processing all remaining 430 messages /// ``` #[test] -#[ignore] // Only run in the CI. +#[ignore] // Only run in the CI, otherwise its too slow. fn stress_test_queue_suspension() { let blocks = 20; let max_queues = 10_000; let max_messages_per_queue = 10_000; let (max_suspend_per_block, max_resume_per_block) = (100, 50); let max_msg_len = MaxMessageLenOf::::get(); - let mut rng = StdRng::seed_from_u64(43); + let mut rng = StdRng::seed_from_u64(gen_seed()); build_and_execute::(|| { let mut suspended = BTreeSet::::new(); @@ -300,6 +368,7 @@ fn process_all_messages(expected: u32) { assert_eq!(consumed, Weight::from_all(expected as u64)); assert_eq!(NumMessagesProcessed::take(), expected as usize); + MessagesProcessed::take(); } /// Returns the weight consumed by `MessageQueue::on_initialize()`. @@ -327,5 +396,6 @@ fn post_conditions() { assert!(ServiceHead::::get().is_none()); // This still works fine. assert_eq!(MessageQueue::service_queues(Weight::MAX), Weight::zero(), "Nothing left"); + MessageQueue::do_try_state().unwrap(); next_block(); } diff --git a/substrate/frame/message-queue/src/lib.rs b/substrate/frame/message-queue/src/lib.rs index 12d289478b3..07eb0041985 100644 --- a/substrate/frame/message-queue/src/lib.rs +++ b/substrate/frame/message-queue/src/lib.rs @@ -49,9 +49,21 @@ //! **Message Execution** //! //! Executing a message is offloaded to the [`Config::MessageProcessor`] which contains the actual -//! logic of how to handle the message since they are blobs. A message can be temporarily or -//! permanently overweight. The pallet will perpetually try to execute a temporarily overweight -//! message. A permanently overweight message is skipped and must be executed manually. +//! logic of how to handle the message since they are blobs. Storage changes are not rolled back on +//! error. +//! +//! A failed message can be temporarily or permanently overweight. The pallet will perpetually try +//! to execute a temporarily overweight message. A permanently overweight message is skipped and +//! must be executed manually. +//! +//! **Reentrancy** +//! +//! This pallet has two entry points for executing (possibly recursive) logic; +//! [`Pallet::service_queues`] and [`Pallet::execute_overweight`]. Both entry points are guarded by +//! the same mutex to error on reentrancy. The only functions that are explicitly **allowed** to be +//! called by a message processor are: [`Pallet::enqueue_message`] and +//! [`Pallet::enqueue_messages`]. All other functions are forbidden and error with +//! [`Error::RecursiveDisallowed`]. //! //! **Pagination** //! @@ -146,6 +158,7 @@ //! which is the default state for a message after being enqueued. //! - `knitting`/`unknitting`: The means of adding or removing a `Queue` from the `ReadyRing`. //! - `MEL`: The Max Encoded Length of a type, see [`codec::MaxEncodedLen`]. +//! - `Reentrance`: To enter an execution context again before it has completed. //! //! # Properties //! @@ -180,6 +193,7 @@ //! expensive. Currently this is archived by having one queue per para-chain/thread, which keeps the //! number of queues within `O(n)` and should be "good enough". +#![deny(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] mod benchmarking; @@ -194,8 +208,8 @@ use frame_support::{ defensive, pallet_prelude::*, traits::{ - DefensiveTruncateFrom, EnqueueMessage, ExecuteOverweightError, Footprint, ProcessMessage, - ProcessMessageError, QueueFootprint, QueuePausedQuery, ServiceQueues, + Defensive, DefensiveTruncateFrom, EnqueueMessage, ExecuteOverweightError, Footprint, + ProcessMessage, ProcessMessageError, QueueFootprint, QueuePausedQuery, ServiceQueues, }, BoundedSlice, CloneNoBound, DefaultNoBound, }; @@ -203,6 +217,7 @@ use frame_system::pallet_prelude::*; pub use pallet::*; use scale_info::TypeInfo; use sp_arithmetic::traits::{BaseArithmetic, Unsigned}; +use sp_core::{defer, H256}; use sp_runtime::{ traits::{One, Zero}, SaturatedConversion, Saturating, @@ -460,6 +475,10 @@ pub mod pallet { /// Processor for a message. /// + /// Storage changes are not rolled back on error. + /// + /// # Benchmarking + /// /// Must be set to [`mock_helpers::NoopMessageProcessor`] for benchmarking. /// Other message processors that consumes exactly (1, 1) weight for any give message will /// work as well. Otherwise the benchmarking will also measure the weight of the message @@ -516,18 +535,51 @@ pub mod pallet { #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { /// Message discarded due to an error in the `MessageProcessor` (usually a format error). - ProcessingFailed { id: [u8; 32], origin: MessageOriginOf, error: ProcessMessageError }, + ProcessingFailed { + /// The `blake2_256` hash of the message. + id: H256, + /// The queue of the message. + origin: MessageOriginOf, + /// The error that occurred. + /// + /// This error is pretty opaque. More fine-grained errors need to be emitted as events + /// by the `MessageProcessor`. + error: ProcessMessageError, + }, /// Message is processed. - Processed { id: [u8; 32], origin: MessageOriginOf, weight_used: Weight, success: bool }, + Processed { + /// The `blake2_256` hash of the message. + id: H256, + /// The queue of the message. + origin: MessageOriginOf, + /// How much weight was used to process the message. + weight_used: Weight, + /// Whether the message was processed. + /// + /// Note that this does not mean that the underlying `MessageProcessor` was internally + /// successful. It *solely* means that the MQ pallet will treat this as a success + /// condition and discard the message. Any internal error needs to be emitted as events + /// by the `MessageProcessor`. + success: bool, + }, /// Message placed in overweight queue. OverweightEnqueued { + /// The `blake2_256` hash of the message. id: [u8; 32], + /// The queue of the message. origin: MessageOriginOf, + /// The page of the message. page_index: PageIndex, + /// The index of the message within the page. message_index: T::Size, }, /// This page was reaped. - PageReaped { origin: MessageOriginOf, index: PageIndex }, + PageReaped { + /// The queue of the page. + origin: MessageOriginOf, + /// The index of the page. + index: PageIndex, + }, } #[pallet::error] @@ -554,6 +606,8 @@ pub mod pallet { /// /// This can change at any time and may resolve in the future by re-trying. QueuePaused, + /// Another call is in progress and needs to finish before this call can happen. + RecursiveDisallowed, } /// The index of the first and last (non-empty) pages. @@ -868,6 +922,21 @@ impl Pallet { page_index: PageIndex, index: T::Size, weight_limit: Weight, + ) -> Result> { + match with_service_mutex(|| { + Self::do_execute_overweight_inner(origin, page_index, index, weight_limit) + }) { + Err(()) => Err(Error::::RecursiveDisallowed), + Ok(x) => x, + } + } + + /// Same as `do_execute_overweight` but must be called while holding the `service_mutex`. + fn do_execute_overweight_inner( + origin: MessageOriginOf, + page_index: PageIndex, + index: T::Size, + weight_limit: Weight, ) -> Result> { let mut book_state = BookStateFor::::get(&origin); ensure!(!T::QueuePausedQuery::is_paused(&origin), Error::::QueuePaused); @@ -924,6 +993,14 @@ impl Pallet { /// Remove a stale page or one which has no more messages remaining to be processed. fn do_reap_page(origin: &MessageOriginOf, page_index: PageIndex) -> DispatchResult { + match with_service_mutex(|| Self::do_reap_page_inner(origin, page_index)) { + Err(()) => Err(Error::::RecursiveDisallowed.into()), + Ok(x) => x, + } + } + + /// Same as `do_reap_page` but must be called while holding the `service_mutex`. + fn do_reap_page_inner(origin: &MessageOriginOf, page_index: PageIndex) -> DispatchResult { let mut book_state = BookStateFor::::get(origin); // definitely not reapable if the page's index is no less than the `begin`ning of ready // pages. @@ -1112,6 +1189,7 @@ impl Pallet { weight: &mut WeightMeter, overweight_limit: Weight, ) -> ItemExecutionStatus { + use MessageExecutionStatus::*; // This ugly pre-checking is needed for the invariant // "we never bail if a page became complete". if page.is_complete() { @@ -1125,16 +1203,31 @@ impl Pallet { Some(m) => m, None => return ItemExecutionStatus::NoItem, }[..]; + let payload_len = payload.len() as u64; - use MessageExecutionStatus::*; - let is_processed = match Self::process_message_payload( + // Store these for the case that `process_message_payload` is recursive. + Pages::::insert(origin, page_index, &*page); + BookStateFor::::insert(origin, &*book_state); + + let res = Self::process_message_payload( origin.clone(), page_index, page.first_index, payload, weight, overweight_limit, - ) { + ); + + // And restore them afterwards to see the changes of a recursive call. + *book_state = BookStateFor::::get(origin); + if let Some(new_page) = Pages::::get(origin, page_index) { + *page = new_page; + } else { + defensive!("page must exist since we just inserted it and recursive calls are not allowed to remove anything"); + return ItemExecutionStatus::NoItem + }; + + let is_processed = match res { InsufficientWeight => return ItemExecutionStatus::Bailed, Unprocessable { permanent: false } => return ItemExecutionStatus::NoProgress, Processed | Unprocessable { permanent: true } => true, @@ -1143,7 +1236,7 @@ impl Pallet { if is_processed { book_state.message_count.saturating_dec(); - book_state.size.saturating_reduce(payload.len() as u64); + book_state.size.saturating_reduce(payload_len as u64); } page.skip_first(is_processed); ItemExecutionStatus::Executed(is_processed) @@ -1168,7 +1261,7 @@ impl Pallet { /// * `remaining_size` > 0 /// * `first` <= `last` /// * Every page can be decoded into peek_* functions - #[cfg(any(test, feature = "try-runtime"))] + #[cfg(any(test, feature = "try-runtime", feature = "std"))] pub fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> { // Checking memory corruption for BookStateFor ensure!( @@ -1181,13 +1274,17 @@ impl Pallet { "Memory Corruption in Pages" ); - // No state to check - if ServiceHead::::get().is_none() { - return Ok(()) + // Basic checks for each book + for book in BookStateFor::::iter_values() { + ensure!(book.end >= book.begin, "Invariant"); + ensure!(book.end < 1 << 30, "Likely overflow or corruption"); + ensure!(book.message_count < 1 << 30, "Likely overflow or corruption"); + ensure!(book.size < 1 << 30, "Likely overflow or corruption"); + ensure!(book.count < 1 << 30, "Likely overflow or corruption"); } //loop around this origin - let starting_origin = ServiceHead::::get().unwrap(); + let Some(starting_origin) = ServiceHead::::get() else { return Ok(()) }; while let Some(head) = Self::bump_service_head(&mut WeightMeter::new()) { ensure!( @@ -1220,7 +1317,7 @@ impl Pallet { for page_index in head_book_state.begin..head_book_state.end { let page = Pages::::get(&head, page_index).unwrap(); let remaining_messages = page.remaining; - let mut counted_remaining_messages = 0; + let mut counted_remaining_messages: u32 = 0; ensure!( remaining_messages > 0.into(), "These must be some messages that have not been processed yet!" @@ -1237,7 +1334,7 @@ impl Pallet { } ensure!( - remaining_messages == counted_remaining_messages.into(), + remaining_messages.into() == counted_remaining_messages, "Memory Corruption" ); } @@ -1312,10 +1409,9 @@ impl Pallet { meter: &mut WeightMeter, overweight_limit: Weight, ) -> MessageExecutionStatus { - let hash = sp_io::hashing::blake2_256(message); + let mut id = sp_io::hashing::blake2_256(message); use ProcessMessageError::*; let prev_consumed = meter.consumed(); - let mut id = hash; match T::MessageProcessor::process_message(message, origin.clone(), meter, &mut id) { Err(Overweight(w)) if w.any_gt(overweight_limit) => { @@ -1339,19 +1435,44 @@ impl Pallet { }, Err(error @ BadFormat | error @ Corrupt | error @ Unsupported) => { // Permanent error - drop - Self::deposit_event(Event::::ProcessingFailed { id, origin, error }); + Self::deposit_event(Event::::ProcessingFailed { id: id.into(), origin, error }); MessageExecutionStatus::Unprocessable { permanent: true } }, Ok(success) => { // Success let weight_used = meter.consumed().saturating_sub(prev_consumed); - Self::deposit_event(Event::::Processed { id, origin, weight_used, success }); + Self::deposit_event(Event::::Processed { + id: id.into(), + origin, + weight_used, + success, + }); MessageExecutionStatus::Processed }, } } } +/// Run a closure that errors on re-entrance. Meant to be used by anything that services queues. +pub(crate) fn with_service_mutex R, R>(f: F) -> Result { + // Holds the singelton token instance. + environmental::environmental!(token: Option<()>); + + token::using_once(&mut Some(()), || { + // The first `ok_or` should always be `Ok` since we are inside a `using_once`. + let hold = token::with(|t| t.take()).ok_or(()).defensive()?.ok_or(())?; + + // Put the token back when we're done. + defer! { + token::with(|t| { + *t = Some(hold); + }); + } + + Ok(f()) + }) +} + /// Provides a [`sp_core::Get`] to access the `MEL` of a [`codec::MaxEncodedLen`] type. pub struct MaxEncodedLenOf(sp_std::marker::PhantomData); impl Get for MaxEncodedLenOf { @@ -1407,35 +1528,40 @@ impl ServiceQueues for Pallet { Weight::zero() }); - let mut next = match Self::bump_service_head(&mut weight) { - Some(h) => h, - None => return weight.consumed(), - }; - // The last queue that did not make any progress. - // The loop aborts as soon as it arrives at this queue again without making any progress - // on other queues in between. - let mut last_no_progress = None; - - loop { - let (progressed, n) = Self::service_queue(next.clone(), &mut weight, max_weight); - next = match n { - Some(n) => - if !progressed { - if last_no_progress == Some(n.clone()) { - break - } - if last_no_progress.is_none() { - last_no_progress = Some(next.clone()) - } - n - } else { - last_no_progress = None; - n - }, - None => break, + match with_service_mutex(|| { + let mut next = match Self::bump_service_head(&mut weight) { + Some(h) => h, + None => return weight.consumed(), + }; + // The last queue that did not make any progress. + // The loop aborts as soon as it arrives at this queue again without making any progress + // on other queues in between. + let mut last_no_progress = None; + + loop { + let (progressed, n) = Self::service_queue(next.clone(), &mut weight, max_weight); + next = match n { + Some(n) => + if !progressed { + if last_no_progress == Some(n.clone()) { + break + } + if last_no_progress.is_none() { + last_no_progress = Some(next.clone()) + } + n + } else { + last_no_progress = None; + n + }, + None => break, + } } + weight.consumed() + }) { + Err(()) => weight.consumed(), + Ok(w) => w, } - weight.consumed() } /// Execute a single overweight message. @@ -1463,6 +1589,7 @@ impl ServiceQueues for Pallet { Error::::QueuePaused => ExecuteOverweightError::QueuePaused, Error::::NoPage | Error::::NoMessage | Error::::Queued => ExecuteOverweightError::NotFound, + Error::::RecursiveDisallowed => ExecuteOverweightError::RecursiveDisallowed, _ => ExecuteOverweightError::Other, }, ) diff --git a/substrate/frame/message-queue/src/mock.rs b/substrate/frame/message-queue/src/mock.rs index 97246900597..89c6e862510 100644 --- a/substrate/frame/message-queue/src/mock.rs +++ b/substrate/frame/message-queue/src/mock.rs @@ -108,7 +108,10 @@ impl MockedWeightInfo { impl crate::weights::WeightInfo for MockedWeightInfo { fn reap_page() -> Weight { - WeightForCall::get().get("reap_page").copied().unwrap_or_default() + WeightForCall::get() + .get("reap_page") + .copied() + .unwrap_or(DefaultWeightForCall::get()) } fn execute_overweight_page_updated() -> Weight { WeightForCall::get() @@ -207,6 +210,10 @@ impl ProcessMessage for RecordingMessageProcessor { let required = Weight::from_parts(weight, weight); if meter.try_consume(required).is_ok() { + if let Some(p) = message.strip_prefix(&b"callback="[..]) { + let s = String::from_utf8(p.to_vec()).expect("Need valid UTF8"); + Callback::get()(&origin, s.parse().expect("Expected an u32")); + } let mut m = MessagesProcessed::get(); m.push((message.to_vec(), origin)); MessagesProcessed::set(m); @@ -217,6 +224,10 @@ impl ProcessMessage for RecordingMessageProcessor { } } +parameter_types! { + pub static Callback: Box = Box::new(|_, _| {}); +} + /// Processed a mocked message. Messages that end with `badformat`, `corrupt`, `unsupported` or /// `yield` will fail with an error respectively. fn processing_message(msg: &[u8], origin: &MessageOrigin) -> Result<(), ProcessMessageError> { @@ -264,6 +275,10 @@ impl ProcessMessage for CountingMessageProcessor { let required = Weight::from_parts(1, 1); if meter.try_consume(required).is_ok() { + if let Some(p) = message.strip_prefix(&b"callback="[..]) { + let s = String::from_utf8(p.to_vec()).expect("Need valid UTF8"); + Callback::get()(&origin, s.parse().expect("Expected an u32")); + } NumMessagesProcessed::set(NumMessagesProcessed::get() + 1); Ok(true) } else { @@ -372,3 +387,16 @@ pub fn num_overweight_enqueued_events() -> u32 { pub fn fp(pages: u32, count: u64, size: u64) -> QueueFootprint { QueueFootprint { storage: Footprint { count, size }, pages } } + +/// A random seed that can be overwritten with `MQ_SEED`. +pub fn gen_seed() -> u64 { + use rand::Rng; + let seed = if let Ok(seed) = std::env::var("MQ_SEED") { + seed.parse().expect("Need valid u64 as MQ_SEED env variable") + } else { + rand::thread_rng().gen::() + }; + + println!("Using seed: {}", seed); + seed +} diff --git a/substrate/frame/message-queue/src/mock_helpers.rs b/substrate/frame/message-queue/src/mock_helpers.rs index f6109c127be..28395e27cdd 100644 --- a/substrate/frame/message-queue/src/mock_helpers.rs +++ b/substrate/frame/message-queue/src/mock_helpers.rs @@ -15,6 +15,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#![allow(missing_docs)] + //! Std setup helpers for testing and benchmarking. //! //! Cannot be put into mock.rs since benchmarks require no-std and mock.rs is std. @@ -88,10 +90,12 @@ pub fn page(msg: &[u8]) -> PageOf { PageOf::::from_message::(msg.try_into().unwrap()) } +/// Create a book with a single message of one byte. pub fn single_page_book() -> BookStateOf { BookState { begin: 0, end: 1, count: 1, message_count: 1, size: 1, ..Default::default() } } +/// Create an empty book. pub fn empty_book() -> BookStateOf { BookState { begin: 0, end: 1, count: 1, ..Default::default() } } diff --git a/substrate/frame/message-queue/src/tests.rs b/substrate/frame/message-queue/src/tests.rs index d94ad581ea0..9198e65e2f9 100644 --- a/substrate/frame/message-queue/src/tests.rs +++ b/substrate/frame/message-queue/src/tests.rs @@ -181,7 +181,7 @@ fn service_queues_failing_messages_works() { assert_eq!(MessageQueue::service_queues(1.into_weight()), 1.into_weight()); assert_last_event::( Event::ProcessingFailed { - id: blake2_256(b"badformat"), + id: blake2_256(b"badformat").into(), origin: MessageOrigin::Here, error: ProcessMessageError::BadFormat, } @@ -190,7 +190,7 @@ fn service_queues_failing_messages_works() { assert_eq!(MessageQueue::service_queues(1.into_weight()), 1.into_weight()); assert_last_event::( Event::ProcessingFailed { - id: blake2_256(b"corrupt"), + id: blake2_256(b"corrupt").into(), origin: MessageOrigin::Here, error: ProcessMessageError::Corrupt, } @@ -199,7 +199,7 @@ fn service_queues_failing_messages_works() { assert_eq!(MessageQueue::service_queues(1.into_weight()), 1.into_weight()); assert_last_event::( Event::ProcessingFailed { - id: blake2_256(b"unsupported"), + id: blake2_256(b"unsupported").into(), origin: MessageOrigin::Here, error: ProcessMessageError::Unsupported, } @@ -1264,7 +1264,7 @@ fn permanently_overweight_limit_is_valid_basic() { RuntimeEvent::MessageQueue(Event::Processed { origin: Here, weight_used: 200.into(), - id: blake2_256(m.as_bytes()), + id: blake2_256(m.as_bytes()).into(), success: true, }) ); @@ -1321,7 +1321,7 @@ fn permanently_overweight_limit_is_valid_fuzzy() { RuntimeEvent::MessageQueue(Event::Processed { origin: Here, weight_used: 200.into(), - id: blake2_256(m.as_bytes()), + id: blake2_256(m.as_bytes()).into(), success: true, }) ); @@ -1592,7 +1592,7 @@ fn execute_overweight_respects_suspension() { assert_last_event::( Event::Processed { - id: blake2_256(b"weight=5"), + id: blake2_256(b"weight=5").into(), origin, weight_used: 5.into_weight(), success: true, @@ -1619,7 +1619,7 @@ fn service_queue_suspension_ready_ring_works() { MessageQueue::service_queues(Weight::MAX); assert_last_event::( Event::Processed { - id: blake2_256(b"weight=5"), + id: blake2_256(b"weight=5").into(), origin, weight_used: 5.into_weight(), success: true, @@ -1662,3 +1662,174 @@ fn integrity_test_checks_service_weight() { } }); } + +/// Test for . +#[test] +fn regression_issue_2319() { + build_and_execute::(|| { + Callback::set(Box::new(|_, _| { + MessageQueue::enqueue_message(mock_helpers::msg("anothermessage"), There); + })); + + use MessageOrigin::*; + MessageQueue::enqueue_message(msg("callback=0"), Here); + + // while servicing queue Here, "anothermessage" of origin There is enqueued in + // "firstmessage"'s process_message + assert_eq!(MessageQueue::service_queues(1.into_weight()), 1.into_weight()); + assert_eq!(MessagesProcessed::take(), vec![(b"callback=0".to_vec(), Here)]); + + assert_eq!(MessageQueue::service_queues(1.into_weight()), 1.into_weight()); + // It used to fail here but got fixed. + assert_eq!(MessagesProcessed::take(), vec![(b"anothermessage".to_vec(), There)]); + }); +} + +/// Enqueueing a message from within `service_queues` works. +#[test] +fn recursive_enqueue_works() { + build_and_execute::(|| { + Callback::set(Box::new(|o, i| match i { + 0 => { + MessageQueue::enqueue_message(msg(&format!("callback={}", 1)), *o); + }, + 1 => { + for _ in 0..100 { + MessageQueue::enqueue_message(msg(&format!("callback={}", 2)), *o); + } + for i in 0..100 { + MessageQueue::enqueue_message(msg(&format!("callback={}", 3)), i.into()); + } + }, + 2 | 3 => { + MessageQueue::enqueue_message(msg(&format!("callback={}", 4)), *o); + }, + 4 => (), + _ => unreachable!(), + })); + + MessageQueue::enqueue_message(msg("callback=0"), MessageOrigin::Here); + + for _ in 0..402 { + assert_eq!(MessageQueue::service_queues(1.into_weight()), 1.into_weight()); + } + assert_eq!(MessageQueue::service_queues(Weight::MAX), Weight::zero()); + + assert_eq!(MessagesProcessed::take().len(), 402); + }); +} + +/// Calling `service_queues` from within `service_queues` is forbidden. +#[test] +fn recursive_service_is_forbidden() { + use MessageOrigin::*; + build_and_execute::(|| { + Callback::set(Box::new(|_, _| { + MessageQueue::enqueue_message(msg("m1"), There); + // This call will fail since it is recursive. But it will not mess up the state. + assert_storage_noop!(MessageQueue::service_queues(10.into_weight())); + MessageQueue::enqueue_message(msg("m2"), There); + })); + + for _ in 0..5 { + MessageQueue::enqueue_message(msg("callback=0"), Here); + MessageQueue::service_queues(3.into_weight()); + + // All three messages are correctly processed. + assert_eq!( + MessagesProcessed::take(), + vec![ + (b"callback=0".to_vec(), Here), + (b"m1".to_vec(), There), + (b"m2".to_vec(), There) + ] + ); + } + }); +} + +/// Calling `service_queues` from within `service_queues` is forbidden. +#[test] +fn recursive_overweight_while_service_is_forbidden() { + use MessageOrigin::*; + build_and_execute::(|| { + Callback::set(Box::new(|_, _| { + // Check that the message was permanently overweight. + assert_last_event::( + Event::OverweightEnqueued { + id: blake2_256(b"weight=10"), + origin: There, + message_index: 0, + page_index: 0, + } + .into(), + ); + // This call will fail since it is recursive. But it will not mess up the state. + assert_noop!( + ::execute_overweight( + 10.into_weight(), + (There, 0, 0) + ), + ExecuteOverweightError::RecursiveDisallowed + ); + })); + + MessageQueue::enqueue_message(msg("weight=10"), There); + MessageQueue::enqueue_message(msg("callback=0"), Here); + + // Mark it as permanently overweight. + MessageQueue::service_queues(5.into_weight()); + assert_ok!(::execute_overweight( + 10.into_weight(), + (There, 0, 0) + )); + }); +} + +/// Calling `reap_page` from within `service_queues` is forbidden. +#[test] +fn recursive_reap_page_is_forbidden() { + use MessageOrigin::*; + build_and_execute::(|| { + Callback::set(Box::new(|_, _| { + // This call will fail since it is recursive. But it will not mess up the state. + assert_noop!(MessageQueue::do_reap_page(&Here, 0), Error::::RecursiveDisallowed); + })); + + // Create 10 pages more than the stale limit. + let n = (MaxStale::get() + 10) as usize; + for _ in 0..n { + MessageQueue::enqueue_message(msg("weight=2"), Here); + } + + // Mark all pages as stale since their message is permanently overweight. + MessageQueue::service_queues(1.into_weight()); + assert_ok!(MessageQueue::do_reap_page(&Here, 0)); + + assert_last_event::(Event::PageReaped { origin: Here, index: 0 }.into()); + }); +} + +#[test] +fn with_service_mutex_works() { + let mut called = 0; + with_service_mutex(|| called = 1).unwrap(); + assert_eq!(called, 1); + + // The outer one is fine but the inner one errors. + with_service_mutex(|| with_service_mutex(|| unreachable!())) + .unwrap() + .unwrap_err(); + with_service_mutex(|| with_service_mutex(|| unreachable!()).unwrap_err()).unwrap(); + with_service_mutex(|| { + with_service_mutex(|| unreachable!()).unwrap_err(); + with_service_mutex(|| unreachable!()).unwrap_err(); + called = 2; + }) + .unwrap(); + assert_eq!(called, 2); + + // Still works. + with_service_mutex(|| called = 3).unwrap(); + assert_eq!(called, 3); +} diff --git a/substrate/frame/support/src/traits/messages.rs b/substrate/frame/support/src/traits/messages.rs index 58815b107c8..995ac4f7179 100644 --- a/substrate/frame/support/src/traits/messages.rs +++ b/substrate/frame/support/src/traits/messages.rs @@ -82,6 +82,8 @@ pub enum ExecuteOverweightError { QueuePaused, /// An unspecified error. Other, + /// Another call is currently ongoing and prevents this call from executing. + RecursiveDisallowed, } /// Can service queues and execute overweight messages. -- GitLab From 814b938d039b215d6f5109daafd68a3410189d52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=B3nal=20Murray?= Date: Thu, 7 Dec 2023 21:27:07 +0000 Subject: [PATCH 22/59] Remove `testnets-common` (#2620) `testnets-common` was introduced recently to start to separate testnet parachain configurations from those of Polkadot and Kusama. The `locks-review` and `polkadot-review` requirements are removed from `parachains-common` in https://github.com/paritytech/polkadot-sdk/pull/2564 and there are [plans](https://github.com/paritytech/polkadot-sdk/pull/2564#discussion_r1410882115) to move the Polkadot and Kusama contents of that package to the fellowship, `testnets-common` is no longer needed. This PR removes the crate and replaces uses of it in `collectives-westend`, the only place it is currently used. --- Cargo.lock | 14 -- Cargo.toml | 1 - cumulus/parachains/common/src/westend.rs | 29 +++- .../collectives-westend/Cargo.toml | 3 - .../collectives-westend/src/lib.rs | 10 +- cumulus/parachains/testnets-common/Cargo.toml | 44 ------ cumulus/parachains/testnets-common/src/lib.rs | 30 ---- .../parachains/testnets-common/src/rococo.rs | 119 --------------- .../parachains/testnets-common/src/westend.rs | 140 ------------------ .../parachains/testnets-common/src/wococo.rs | 17 --- 10 files changed, 30 insertions(+), 377 deletions(-) delete mode 100644 cumulus/parachains/testnets-common/Cargo.toml delete mode 100644 cumulus/parachains/testnets-common/src/lib.rs delete mode 100644 cumulus/parachains/testnets-common/src/rococo.rs delete mode 100644 cumulus/parachains/testnets-common/src/westend.rs delete mode 100644 cumulus/parachains/testnets-common/src/wococo.rs diff --git a/Cargo.lock b/Cargo.lock index d1735ec83af..c06bd4f1d3f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2668,7 +2668,6 @@ dependencies = [ "staging-xcm-builder", "staging-xcm-executor", "substrate-wasm-builder", - "testnets-common", "westend-runtime-constants", ] @@ -19182,19 +19181,6 @@ dependencies = [ "sp-weights", ] -[[package]] -name = "testnets-common" -version = "1.0.0" -dependencies = [ - "frame-support", - "polkadot-core-primitives", - "rococo-runtime-constants", - "smallvec", - "sp-runtime", - "substrate-wasm-builder", - "westend-runtime-constants", -] - [[package]] name = "textwrap" version = "0.16.0" diff --git a/Cargo.toml b/Cargo.toml index 85ba2c5bc93..e33b843eb1f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -95,7 +95,6 @@ members = [ "cumulus/parachains/runtimes/test-utils", "cumulus/parachains/runtimes/testing/penpal", "cumulus/parachains/runtimes/testing/rococo-parachain", - "cumulus/parachains/testnets-common", "cumulus/polkadot-parachain", "cumulus/primitives/aura", "cumulus/primitives/core", diff --git a/cumulus/parachains/common/src/westend.rs b/cumulus/parachains/common/src/westend.rs index 9d3e0bd1a0e..0ae21e23454 100644 --- a/cumulus/parachains/common/src/westend.rs +++ b/cumulus/parachains/common/src/westend.rs @@ -13,6 +13,24 @@ // See the License for the specific language governing permissions and // limitations under the License. +/// Universally recognized accounts. +pub mod account { + use frame_support::PalletId; + + /// Westend treasury pallet id, used to convert into AccountId - in Westend as a destination for + /// slashed funds. + pub const WESTEND_TREASURY_PALLET_ID: PalletId = PalletId(*b"py/trsry"); + /// Alliance pallet ID - used as a temporary place to deposit a slashed imbalance before the + /// teleport to the Treasury. + pub const ALLIANCE_PALLET_ID: PalletId = PalletId(*b"py/allia"); + /// Referenda pallet ID - used as a temporary place to deposit a slashed imbalance before the + /// teleport to the Treasury. + pub const REFERENDA_PALLET_ID: PalletId = PalletId(*b"py/refer"); + /// Ambassador Referenda pallet ID - used as a temporary place to deposit a slashed imbalance + /// before the teleport to the Treasury. + pub const AMBASSADOR_REFERENDA_PALLET_ID: PalletId = PalletId(*b"py/amref"); +} + pub mod currency { use polkadot_core_primitives::Balance; use westend_runtime_constants as constants; @@ -21,6 +39,7 @@ pub mod currency { pub const EXISTENTIAL_DEPOSIT: Balance = constants::currency::EXISTENTIAL_DEPOSIT / 10; pub const UNITS: Balance = constants::currency::UNITS; + pub const DOLLARS: Balance = UNITS; // 1_000_000_000_000 pub const CENTS: Balance = constants::currency::CENTS; pub const MILLICENTS: Balance = constants::currency::MILLICENTS; pub const GRAND: Balance = constants::currency::GRAND; @@ -44,7 +63,7 @@ pub mod fee { use smallvec::smallvec; pub use sp_runtime::Perbill; - /// The block saturation level. Fees will be updates based on this value. + /// The block saturation level. Fees will be updated based on this value. pub const TARGET_BLOCK_FULLNESS: Perbill = Perbill::from_percent(25); /// Handles converting a weight scalar to a fee value, based on the scale and granularity of the @@ -110,11 +129,11 @@ pub mod fee { /// Consensus-related. pub mod consensus { - /// Maximum number of blocks simultaneously accepted by the Runtime, not yet included - /// into the relay chain. + /// Maximum number of blocks simultaneously accepted by the Runtime, not yet included into the + /// relay chain. pub const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1; - /// How many parachain blocks are processed by the relay chain per parent. Limits the - /// number of blocks authored per slot. + /// How many parachain blocks are processed by the relay chain per parent. Limits the number of + /// blocks authored per slot. pub const BLOCK_PROCESSING_VELOCITY: u32 = 1; /// Relay chain slot duration, in milliseconds. pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000; diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml index 06f0a6239e3..94a5edc371f 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml @@ -77,7 +77,6 @@ pallet-collator-selection = { path = "../../../../pallets/collator-selection", d pallet-collective-content = { path = "../../../pallets/collective-content", default-features = false } parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } -testnets-common = { path = "../../../testnets-common", default-features = false } [build-dependencies] substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } @@ -118,7 +117,6 @@ runtime-benchmarks = [ "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", "sp-runtime/runtime-benchmarks", - "testnets-common/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", ] @@ -216,7 +214,6 @@ std = [ "sp-transaction-pool/std", "sp-version/std", "substrate-wasm-builder", - "testnets-common/std", "westend-runtime-constants/std", "xcm-builder/std", "xcm-executor/std", diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs index d6f8d32628e..3b8ce0a8704 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs @@ -81,12 +81,14 @@ use frame_system::{ }; pub use parachains_common as common; use parachains_common::{ - impls::DealWithFees, message_queue::*, AccountId, AuraId, Balance, BlockNumber, Hash, Header, - Nonce, Signature, AVERAGE_ON_INITIALIZE_RATIO, DAYS, HOURS, MAXIMUM_BLOCK_WEIGHT, MINUTES, - NORMAL_DISPATCH_RATIO, SLOT_DURATION, + impls::DealWithFees, + message_queue::*, + westend::{account::*, consensus::*, currency::*, fee::WeightToFee}, + AccountId, AuraId, Balance, BlockNumber, Hash, Header, Nonce, Signature, + AVERAGE_ON_INITIALIZE_RATIO, DAYS, HOURS, MAXIMUM_BLOCK_WEIGHT, MINUTES, NORMAL_DISPATCH_RATIO, + SLOT_DURATION, }; use sp_runtime::RuntimeDebug; -use testnets_common::westend::{account::*, consensus::*, currency::*, fee::WeightToFee}; use xcm_config::{GovernanceLocation, XcmOriginToTransactDispatchOrigin}; #[cfg(any(feature = "std", test))] diff --git a/cumulus/parachains/testnets-common/Cargo.toml b/cumulus/parachains/testnets-common/Cargo.toml deleted file mode 100644 index 87c570d10ea..00000000000 --- a/cumulus/parachains/testnets-common/Cargo.toml +++ /dev/null @@ -1,44 +0,0 @@ -[package] -name = "testnets-common" -version = "1.0.0" -authors.workspace = true -edition.workspace = true -description = "Logic and configuration specific to testnet parachain runtimes" -license = "Apache-2.0" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -smallvec = "1.11.0" - -# Substrate -frame-support = { path = "../../../substrate/frame/support", default-features = false } -sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } - -# Polkadot -rococo-runtime-constants = { path = "../../../polkadot/runtime/rococo/constants", default-features = false } -westend-runtime-constants = { path = "../../../polkadot/runtime/westend/constants", default-features = false } -polkadot-core-primitives = { path = "../../../polkadot/core-primitives", default-features = false } - -# Cumulus - -[dev-dependencies] - -[build-dependencies] -substrate-wasm-builder = { path = "../../../substrate/utils/wasm-builder" } - -[features] -default = ["std"] -std = [ - "frame-support/std", - "polkadot-core-primitives/std", - "rococo-runtime-constants/std", - "sp-runtime/std", - "westend-runtime-constants/std", -] - -runtime-benchmarks = [ - "frame-support/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", -] diff --git a/cumulus/parachains/testnets-common/src/lib.rs b/cumulus/parachains/testnets-common/src/lib.rs deleted file mode 100644 index 42d367bff27..00000000000 --- a/cumulus/parachains/testnets-common/src/lib.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (C) 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. - -#![cfg_attr(not(feature = "std"), no_std)] - -/// Since the parachains-common package is now published to crates.io, SP runtimes for testnets -/// will be adapted to use this package, and their config removed from the published common -/// package. Only the configs specific to rococo, westend and wococo will be moved here, and the -/// truly common logic will still be sourced from the parachains-common package. -/// -/// In practice this just means that instead of using e.g. `[parachains_common::westend::*]`, now -/// the westend configs will be in `[testnets_common::westend::*]`. -/// -/// TODO: edit all runtimes to remove the testnet configs as part of PR #1737 -/// -pub mod rococo; -pub mod westend; -pub mod wococo; diff --git a/cumulus/parachains/testnets-common/src/rococo.rs b/cumulus/parachains/testnets-common/src/rococo.rs deleted file mode 100644 index 6e31def4b55..00000000000 --- a/cumulus/parachains/testnets-common/src/rococo.rs +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (C) 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 currency { - use polkadot_core_primitives::Balance; - use rococo_runtime_constants as constants; - - /// The existential deposit. Set to 1/10 of its parent Relay Chain (v9010). - pub const EXISTENTIAL_DEPOSIT: Balance = constants::currency::EXISTENTIAL_DEPOSIT / 10; - - pub const UNITS: Balance = constants::currency::UNITS; - pub const CENTS: Balance = constants::currency::CENTS; - pub const MILLICENTS: Balance = constants::currency::MILLICENTS; - - pub const fn deposit(items: u32, bytes: u32) -> Balance { - // map to 1/100 of what the rococo relay chain charges - constants::currency::deposit(items, bytes) / 100 - } -} - -pub mod fee { - use frame_support::{ - pallet_prelude::Weight, - weights::{ - constants::ExtrinsicBaseWeight, FeePolynomial, WeightToFeeCoefficient, - WeightToFeeCoefficients, WeightToFeePolynomial, - }, - }; - use polkadot_core_primitives::Balance; - use smallvec::smallvec; - pub use sp_runtime::Perbill; - - /// The block saturation level. Fees will be updates based on this value. - pub const TARGET_BLOCK_FULLNESS: Perbill = Perbill::from_percent(25); - - /// Handles converting a weight scalar to a fee value, based on the scale and granularity of the - /// node's balance type. - /// - /// This should typically create a mapping between the following ranges: - /// - `[0, MAXIMUM_BLOCK_WEIGHT]` - /// - `[Balance::min, Balance::max]` - /// - /// Yet, it can be used for any other sort of change to weight-fee. Some examples being: - /// - Setting it to `0` will essentially disable the weight fee. - /// - Setting it to `1` will cause the literal `#[weight = x]` values to be charged. - pub struct WeightToFee; - impl frame_support::weights::WeightToFee for WeightToFee { - type Balance = Balance; - - fn weight_to_fee(weight: &Weight) -> Self::Balance { - let time_poly: FeePolynomial = RefTimeToFee::polynomial().into(); - let proof_poly: FeePolynomial = ProofSizeToFee::polynomial().into(); - - // Take the maximum instead of the sum to charge by the more scarce resource. - time_poly.eval(weight.ref_time()).max(proof_poly.eval(weight.proof_size())) - } - } - - /// Maps the reference time component of `Weight` to a fee. - pub struct RefTimeToFee; - impl WeightToFeePolynomial for RefTimeToFee { - type Balance = Balance; - fn polynomial() -> WeightToFeeCoefficients { - // In Rococo, extrinsic base weight (smallest non-zero weight) is mapped to 1/10 CENT: - // The standard system parachain configuration is 1/10 of that, as in 1/100 CENT. - let p = super::currency::CENTS; - let q = 100 * Balance::from(ExtrinsicBaseWeight::get().ref_time()); - - smallvec![WeightToFeeCoefficient { - degree: 1, - negative: false, - coeff_frac: Perbill::from_rational(p % q, q), - coeff_integer: p / q, - }] - } - } - - /// Maps the proof size component of `Weight` to a fee. - pub struct ProofSizeToFee; - impl WeightToFeePolynomial for ProofSizeToFee { - type Balance = Balance; - fn polynomial() -> WeightToFeeCoefficients { - // Map 10kb proof to 1 CENT. - let p = super::currency::CENTS; - let q = 10_000; - - smallvec![WeightToFeeCoefficient { - degree: 1, - negative: false, - coeff_frac: Perbill::from_rational(p % q, q), - coeff_integer: p / q, - }] - } - } -} - -/// Consensus-related. -pub mod consensus { - /// Maximum number of blocks simultaneously accepted by the Runtime, not yet included - /// into the relay chain. - pub const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1; - /// How many parachain blocks are processed by the relay chain per parent. Limits the - /// number of blocks authored per slot. - pub const BLOCK_PROCESSING_VELOCITY: u32 = 1; - /// Relay chain slot duration, in milliseconds. - pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000; -} diff --git a/cumulus/parachains/testnets-common/src/westend.rs b/cumulus/parachains/testnets-common/src/westend.rs deleted file mode 100644 index 0ae21e23454..00000000000 --- a/cumulus/parachains/testnets-common/src/westend.rs +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright (C) 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. - -/// Universally recognized accounts. -pub mod account { - use frame_support::PalletId; - - /// Westend treasury pallet id, used to convert into AccountId - in Westend as a destination for - /// slashed funds. - pub const WESTEND_TREASURY_PALLET_ID: PalletId = PalletId(*b"py/trsry"); - /// Alliance pallet ID - used as a temporary place to deposit a slashed imbalance before the - /// teleport to the Treasury. - pub const ALLIANCE_PALLET_ID: PalletId = PalletId(*b"py/allia"); - /// Referenda pallet ID - used as a temporary place to deposit a slashed imbalance before the - /// teleport to the Treasury. - pub const REFERENDA_PALLET_ID: PalletId = PalletId(*b"py/refer"); - /// Ambassador Referenda pallet ID - used as a temporary place to deposit a slashed imbalance - /// before the teleport to the Treasury. - pub const AMBASSADOR_REFERENDA_PALLET_ID: PalletId = PalletId(*b"py/amref"); -} - -pub mod currency { - use polkadot_core_primitives::Balance; - use westend_runtime_constants as constants; - - /// The existential deposit. Set to 1/10 of its parent Relay Chain. - pub const EXISTENTIAL_DEPOSIT: Balance = constants::currency::EXISTENTIAL_DEPOSIT / 10; - - pub const UNITS: Balance = constants::currency::UNITS; - pub const DOLLARS: Balance = UNITS; // 1_000_000_000_000 - pub const CENTS: Balance = constants::currency::CENTS; - pub const MILLICENTS: Balance = constants::currency::MILLICENTS; - pub const GRAND: Balance = constants::currency::GRAND; - - pub const fn deposit(items: u32, bytes: u32) -> Balance { - // 1/100 of Westend testnet - constants::currency::deposit(items, bytes) / 100 - } -} - -/// Fee-related. -pub mod fee { - use frame_support::{ - pallet_prelude::Weight, - weights::{ - constants::ExtrinsicBaseWeight, FeePolynomial, WeightToFeeCoefficient, - WeightToFeeCoefficients, WeightToFeePolynomial, - }, - }; - use polkadot_core_primitives::Balance; - use smallvec::smallvec; - pub use sp_runtime::Perbill; - - /// The block saturation level. Fees will be updated based on this value. - pub const TARGET_BLOCK_FULLNESS: Perbill = Perbill::from_percent(25); - - /// Handles converting a weight scalar to a fee value, based on the scale and granularity of the - /// node's balance type. - /// - /// This should typically create a mapping between the following ranges: - /// - [0, MAXIMUM_BLOCK_WEIGHT] - /// - [Balance::min, Balance::max] - /// - /// Yet, it can be used for any other sort of change to weight-fee. Some examples being: - /// - Setting it to `0` will essentially disable the weight fee. - /// - Setting it to `1` will cause the literal `#[weight = x]` values to be charged. - pub struct WeightToFee; - impl frame_support::weights::WeightToFee for WeightToFee { - type Balance = Balance; - - fn weight_to_fee(weight: &Weight) -> Self::Balance { - let time_poly: FeePolynomial = RefTimeToFee::polynomial().into(); - let proof_poly: FeePolynomial = ProofSizeToFee::polynomial().into(); - - // Take the maximum instead of the sum to charge by the more scarce resource. - time_poly.eval(weight.ref_time()).max(proof_poly.eval(weight.proof_size())) - } - } - - /// Maps the reference time component of `Weight` to a fee. - pub struct RefTimeToFee; - impl WeightToFeePolynomial for RefTimeToFee { - type Balance = Balance; - fn polynomial() -> WeightToFeeCoefficients { - // In Westend, extrinsic base weight (smallest non-zero weight) is mapped to 1/10 CENT: - // The standard system parachain configuration is 1/10 of that, as in 1/100 CENT. - let p = super::currency::CENTS; - let q = 100 * Balance::from(ExtrinsicBaseWeight::get().ref_time()); - - smallvec![WeightToFeeCoefficient { - degree: 1, - negative: false, - coeff_frac: Perbill::from_rational(p % q, q), - coeff_integer: p / q, - }] - } - } - - /// Maps the proof size component of `Weight` to a fee. - pub struct ProofSizeToFee; - impl WeightToFeePolynomial for ProofSizeToFee { - type Balance = Balance; - fn polynomial() -> WeightToFeeCoefficients { - // Map 10kb proof to 1 CENT. - let p = super::currency::CENTS; - let q = 10_000; - - smallvec![WeightToFeeCoefficient { - degree: 1, - negative: false, - coeff_frac: Perbill::from_rational(p % q, q), - coeff_integer: p / q, - }] - } - } -} - -/// Consensus-related. -pub mod consensus { - /// Maximum number of blocks simultaneously accepted by the Runtime, not yet included into the - /// relay chain. - pub const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1; - /// How many parachain blocks are processed by the relay chain per parent. Limits the number of - /// blocks authored per slot. - pub const BLOCK_PROCESSING_VELOCITY: u32 = 1; - /// Relay chain slot duration, in milliseconds. - pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000; -} diff --git a/cumulus/parachains/testnets-common/src/wococo.rs b/cumulus/parachains/testnets-common/src/wococo.rs deleted file mode 100644 index 5cd6121135a..00000000000 --- a/cumulus/parachains/testnets-common/src/wococo.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (C) 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. - -// re-export rococo -pub use crate::rococo::{consensus, currency, fee}; -- GitLab From fde5d8fe6c89d23ea8de885bdf743cc93e8c5a00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 8 Dec 2023 01:45:14 +0100 Subject: [PATCH 23/59] pallet-broker: Small improvements to the origin checks (#2656) The permissionless calls do not need to ensure that the `origin` is signed. Anyone can execute these calls. --- prdoc/pr_2656.prdoc | 10 ++++++++++ substrate/frame/broker/src/lib.rs | 20 ++++++++------------ substrate/frame/broker/src/mock.rs | 29 ++--------------------------- 3 files changed, 20 insertions(+), 39 deletions(-) create mode 100644 prdoc/pr_2656.prdoc diff --git a/prdoc/pr_2656.prdoc b/prdoc/pr_2656.prdoc new file mode 100644 index 00000000000..563218dbde6 --- /dev/null +++ b/prdoc/pr_2656.prdoc @@ -0,0 +1,10 @@ +title: "pallet-broker: Small improvements to the origin checks" + +doc: + - audience: Runtime User + description: | + Change the permissionless calls `drop_region`, `drop_contribution`, `drop_history` and + `drop_renewal` to allow any kind of origin. + +crates: + - name: "pallet-broker" diff --git a/substrate/frame/broker/src/lib.rs b/substrate/frame/broker/src/lib.rs index 4abd041f5f3..42895512ec0 100644 --- a/substrate/frame/broker/src/lib.rs +++ b/substrate/frame/broker/src/lib.rs @@ -716,55 +716,51 @@ pub mod pallet { /// Drop an expired Region from the chain. /// - /// - `origin`: Must be a Signed origin. + /// - `origin`: Can be any kind of origin. /// - `region_id`: The Region which has expired. #[pallet::call_index(14)] pub fn drop_region( - origin: OriginFor, + _origin: OriginFor, region_id: RegionId, ) -> DispatchResultWithPostInfo { - let _ = ensure_signed(origin)?; Self::do_drop_region(region_id)?; Ok(Pays::No.into()) } /// Drop an expired Instantaneous Pool Contribution record from the chain. /// - /// - `origin`: Must be a Signed origin. + /// - `origin`: Can be any kind of origin. /// - `region_id`: The Region identifying the Pool Contribution which has expired. #[pallet::call_index(15)] pub fn drop_contribution( - origin: OriginFor, + _origin: OriginFor, region_id: RegionId, ) -> DispatchResultWithPostInfo { - let _ = ensure_signed(origin)?; Self::do_drop_contribution(region_id)?; Ok(Pays::No.into()) } /// Drop an expired Instantaneous Pool History record from the chain. /// - /// - `origin`: Must be a Signed origin. + /// - `origin`: Can be any kind of origin. /// - `region_id`: The time of the Pool History record which has expired. #[pallet::call_index(16)] - pub fn drop_history(origin: OriginFor, when: Timeslice) -> DispatchResultWithPostInfo { - let _ = ensure_signed(origin)?; + pub fn drop_history(_origin: OriginFor, when: Timeslice) -> DispatchResultWithPostInfo { Self::do_drop_history(when)?; Ok(Pays::No.into()) } /// Drop an expired Allowed Renewal record from the chain. /// - /// - `origin`: Must be a Signed origin of the account which owns the Region `region_id`. + /// - `origin`: Can be any kind of origin. /// - `core`: The core to which the expired renewal refers. /// - `when`: The timeslice to which the expired renewal refers. This must have passed. #[pallet::call_index(17)] pub fn drop_renewal( - origin: OriginFor, + _origin: OriginFor, core: CoreIndex, when: Timeslice, ) -> DispatchResultWithPostInfo { - let _ = ensure_signed(origin)?; Self::do_drop_renewal(core, when)?; Ok(Pays::No.into()) } diff --git a/substrate/frame/broker/src/mock.rs b/substrate/frame/broker/src/mock.rs index 8b8cfa55abc..d8bea484909 100644 --- a/substrate/frame/broker/src/mock.rs +++ b/substrate/frame/broker/src/mock.rs @@ -29,11 +29,8 @@ use frame_support::{ }; use frame_system::{EnsureRoot, EnsureSignedBy}; use sp_arithmetic::Perbill; -use sp_core::{ConstU16, ConstU32, ConstU64, H256}; -use sp_runtime::{ - traits::{BlakeTwo256, Identity, IdentityLookup}, - BuildStorage, Saturating, -}; +use sp_core::{ConstU32, ConstU64}; +use sp_runtime::{traits::Identity, BuildStorage, Saturating}; use sp_std::collections::btree_map::BTreeMap; type Block = frame_system::mocking::MockBlock; @@ -49,29 +46,7 @@ frame_support::construct_runtime!( #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = ConstU16<42>; - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; } #[derive(Debug, Clone, Eq, PartialEq)] -- GitLab From 34c991e2cf117250ebb14802365b5ba9167f9307 Mon Sep 17 00:00:00 2001 From: cheme Date: Fri, 8 Dec 2023 06:28:04 +0100 Subject: [PATCH 24/59] Remove hashbrown from trie cache. (#2632) Using hashmap instead (hashset do not expose entry), to get the default random hasher her. --- Cargo.lock | 1 - substrate/primitives/trie/Cargo.toml | 2 -- .../primitives/trie/src/cache/shared_cache.rs | 26 ++++++++++++------- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c06bd4f1d3f..945698059ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18073,7 +18073,6 @@ dependencies = [ "array-bytes 6.1.0", "criterion 0.4.0", "hash-db", - "hashbrown 0.13.2", "lazy_static", "memory-db", "nohash-hasher", diff --git a/substrate/primitives/trie/Cargo.toml b/substrate/primitives/trie/Cargo.toml index 1b1e40c9458..5da1594e5d4 100644 --- a/substrate/primitives/trie/Cargo.toml +++ b/substrate/primitives/trie/Cargo.toml @@ -20,7 +20,6 @@ harness = false [dependencies] ahash = { version = "0.8.2", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -hashbrown = { version = "0.13.2", optional = true } hash-db = { version = "0.16.0", default-features = false } lazy_static = { version = "1.4.0", optional = true } memory-db = { version = "0.32.0", default-features = false } @@ -50,7 +49,6 @@ std = [ "ahash", "codec/std", "hash-db/std", - "hashbrown", "lazy_static", "memory-db/std", "nohash-hasher", diff --git a/substrate/primitives/trie/src/cache/shared_cache.rs b/substrate/primitives/trie/src/cache/shared_cache.rs index 01ac41a1e47..e3ba94a2af7 100644 --- a/substrate/primitives/trie/src/cache/shared_cache.rs +++ b/substrate/primitives/trie/src/cache/shared_cache.rs @@ -19,11 +19,11 @@ ///! that combines both caches and is exported to the outside. use super::{CacheSize, NodeCached}; use hash_db::Hasher; -use hashbrown::{hash_set::Entry as SetEntry, HashSet}; use nohash_hasher::BuildNoHashHasher; use parking_lot::{Mutex, RwLock, RwLockWriteGuard}; use schnellru::LruMap; use std::{ + collections::{hash_map::Entry as SetEntry, HashMap}, hash::{BuildHasher, Hasher as _}, sync::Arc, }; @@ -148,7 +148,7 @@ pub struct SharedValueCacheLimiter { heap_size: usize, /// A set with all of the keys deduplicated to save on memory. - known_storage_keys: HashSet>, + known_storage_keys: HashMap, (), ahash::RandomState>, /// A counter with the number of elements that got evicted from the cache. /// @@ -189,10 +189,10 @@ where } self.heap_size += new_item_heap_size; - entry.insert(); + entry.insert(()); }, SetEntry::Occupied(entry) => { - key.storage_key = entry.get().clone(); + key.storage_key = entry.key().clone(); }, } @@ -491,7 +491,7 @@ impl> SharedValueCache { max_inline_size, max_heap_size, heap_size: 0, - known_storage_keys: Default::default(), + known_storage_keys: HashMap::with_hasher(RANDOM_STATE.clone()), items_evicted: 0, max_items_evicted: 0, // Will be set during `update`. }, @@ -778,7 +778,9 @@ mod tests { assert_eq!(1, cache.lru.limiter_mut().known_storage_keys.len()); assert_eq!( 3, // Two instances inside the cache + one extra in `known_storage_keys`. - Arc::strong_count(cache.lru.limiter_mut().known_storage_keys.get(&key[..]).unwrap()) + Arc::strong_count( + cache.lru.limiter_mut().known_storage_keys.get_key_value(&key[..]).unwrap().0 + ) ); assert_eq!(key.len(), cache.lru.limiter().heap_size); assert_eq!(cache.lru.len(), 2); @@ -792,7 +794,9 @@ mod tests { assert_eq!(1, cache.lru.limiter_mut().known_storage_keys.len()); assert_eq!( 3, - Arc::strong_count(cache.lru.limiter_mut().known_storage_keys.get(&key[..]).unwrap()) + Arc::strong_count( + cache.lru.limiter_mut().known_storage_keys.get_key_value(&key[..]).unwrap().0 + ) ); assert_eq!(key.len(), cache.lru.limiter().heap_size); assert_eq!(cache.lru.len(), 2); @@ -812,7 +816,9 @@ mod tests { assert_eq!(1, cache.lru.limiter_mut().known_storage_keys.len()); assert_eq!( 3, - Arc::strong_count(cache.lru.limiter_mut().known_storage_keys.get(&key[..]).unwrap()) + Arc::strong_count( + cache.lru.limiter_mut().known_storage_keys.get_key_value(&key[..]).unwrap().0 + ) ); assert_eq!(key.len(), cache.lru.limiter().heap_size); assert_eq!(cache.lru.len(), 2); @@ -833,7 +839,7 @@ mod tests { assert_eq!(cache.lru.limiter().items_evicted, 2); assert_eq!(10, cache.lru.len()); assert_eq!(10, cache.lru.limiter_mut().known_storage_keys.len()); - assert!(cache.lru.limiter_mut().known_storage_keys.get(&key[..]).is_none()); + assert!(cache.lru.limiter_mut().known_storage_keys.get_key_value(&key[..]).is_none()); assert_eq!(key.len() * 10, cache.lru.limiter().heap_size); assert_eq!(cache.lru.len(), 10); assert!(cache.lru.limiter().heap_size <= cache.lru.limiter().max_heap_size); @@ -854,6 +860,6 @@ mod tests { vec![], ); - assert!(cache.lru.limiter_mut().known_storage_keys.get(&key[..]).is_none()); + assert!(cache.lru.limiter_mut().known_storage_keys.get_key_value(&key[..]).is_none()); } } -- GitLab From ac3f14d23ba0f4d7e92d70c2fe6b202ccdcb3a62 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Fri, 8 Dec 2023 00:40:26 -0500 Subject: [PATCH 25/59] Tasks: general system for recognizing and executing service work (#1343) `polkadot-sdk` version of original tasks PR located here: https://github.com/paritytech/substrate/pull/14329 Fixes #206 ## Status - [x] Generic `Task` trait - [x] `RuntimeTask` aggregated enum, compatible with `construct_runtime!` - [x] Casting between `Task` and `RuntimeTask` without needing `dyn` or `Box` - [x] Tasks Example pallet - [x] Runtime tests for Tasks example pallet - [x] Parsing for task-related macros - [x] Retrofit parsing to make macros optional - [x] Expansion for task-related macros - [x] Adds support for args in tasks - [x] Retrofit tasks example pallet to use macros instead of manual syntax - [x] Weights - [x] Cleanup - [x] UI tests - [x] Docs ## Target Syntax Adapted from https://github.com/paritytech/polkadot-sdk/issues/206#issue-1865172283 ```rust // NOTE: this enum is optional and is auto-generated by the other macros if not present #[pallet::task] pub enum Task { AddNumberIntoTotal { i: u32, } } /// Some running total. #[pallet::storage] pub(super) type Total, I: 'static = ()> = StorageValue<_, (u32, u32), ValueQuery>; /// Numbers to be added into the total. #[pallet::storage] pub(super) type Numbers, I: 'static = ()> = StorageMap<_, Twox64Concat, u32, u32, OptionQuery>; #[pallet::tasks_experimental] impl, I: 'static> Pallet { /// Add a pair of numbers into the totals and remove them. #[pallet::task_list(Numbers::::iter_keys())] #[pallet::task_condition(|i| Numbers::::contains_key(i))] #[pallet::task_index(0)] pub fn add_number_into_total(i: u32) -> DispatchResult { let v = Numbers::::take(i).ok_or(Error::::NotFound)?; Total::::mutate(|(total_keys, total_values)| { *total_keys += i; *total_values += v; }); Ok(()) } } ``` --------- Co-authored-by: Nikhil Gupta <17176722+gupnik@users.noreply.github.com> Co-authored-by: kianenigma Co-authored-by: Nikhil Gupta <> Co-authored-by: Gavin Wood Co-authored-by: Oliver Tale-Yazdi Co-authored-by: gupnik --- Cargo.lock | 19 + Cargo.toml | 1 + .../pallets/collator-selection/src/mock.rs | 3 +- .../pallets/template/src/mock.rs | 3 +- prdoc/pr_1343.prdoc | 29 + substrate/bin/node/runtime/Cargo.toml | 4 + substrate/bin/node/runtime/src/lib.rs | 7 + substrate/frame/examples/Cargo.toml | 3 + .../frame/examples/default-config/src/lib.rs | 5 + .../frame/examples/kitchensink/Cargo.toml | 1 + substrate/frame/examples/src/lib.rs | 2 + substrate/frame/examples/tasks/Cargo.toml | 52 + .../frame/examples/tasks/src/benchmarking.rs | 42 + substrate/frame/examples/tasks/src/lib.rs | 78 ++ substrate/frame/examples/tasks/src/mock.rs | 43 + substrate/frame/examples/tasks/src/tests.rs | 127 +++ substrate/frame/examples/tasks/src/weights.rs | 84 ++ substrate/frame/scheduler/src/mock.rs | 4 +- substrate/frame/support/procedural/Cargo.toml | 3 + .../src/construct_runtime/expand/mod.rs | 2 + .../src/construct_runtime/expand/task.rs | 131 +++ .../procedural/src/construct_runtime/mod.rs | 3 + .../procedural/src/construct_runtime/parse.rs | 8 +- substrate/frame/support/procedural/src/lib.rs | 58 +- .../procedural/src/pallet/expand/mod.rs | 3 + .../procedural/src/pallet/expand/tasks.rs | 267 +++++ .../src/pallet/expand/tt_default_parts.rs | 4 +- .../procedural/src/pallet/parse/call.rs | 3 +- .../procedural/src/pallet/parse/composite.rs | 9 +- .../procedural/src/pallet/parse/mod.rs | 159 ++- .../procedural/src/pallet/parse/tasks.rs | 968 ++++++++++++++++++ .../procedural/src/pallet/parse/tests/mod.rs | 264 +++++ .../src/pallet/parse/tests/tasks.rs | 240 +++++ substrate/frame/support/src/dispatch.rs | 2 + substrate/frame/support/src/lib.rs | 57 +- .../support/src/storage/generator/mod.rs | 2 + substrate/frame/support/src/tests/mod.rs | 57 +- substrate/frame/support/src/tests/tasks.rs | 62 ++ substrate/frame/support/src/traits.rs | 3 + substrate/frame/support/src/traits/tasks.rs | 87 ++ .../support/test/compile_pass/src/lib.rs | 3 +- substrate/frame/support/test/src/lib.rs | 2 + .../generics_in_invalid_module.stderr | 2 +- .../invalid_module_details_keyword.stderr | 2 +- .../invalid_module_entry.stderr | 2 +- ...umber_of_pallets_exceeds_tuple_size.stderr | 8 + .../inject_runtime_type_invalid.stderr | 2 +- .../test/tests/pallet_outer_enums_explicit.rs | 2 + .../test/tests/pallet_outer_enums_implicit.rs | 2 + ...mposite_enum_unsupported_identifier.stderr | 2 +- .../test/tests/pallet_ui/pass/task_valid.rs | 43 + .../task_can_only_be_attached_to_impl.rs | 34 + .../task_can_only_be_attached_to_impl.stderr | 5 + .../pallet_ui/task_condition_invalid_arg.rs | 42 + .../task_condition_invalid_arg.stderr | 22 + .../tests/pallet_ui/task_invalid_condition.rs | 42 + .../pallet_ui/task_invalid_condition.stderr | 27 + .../tests/pallet_ui/task_invalid_index.rs | 39 + .../tests/pallet_ui/task_invalid_index.stderr | 5 + .../test/tests/pallet_ui/task_invalid_list.rs | 42 + .../tests/pallet_ui/task_invalid_list.stderr | 19 + .../tests/pallet_ui/task_invalid_weight.rs | 42 + .../pallet_ui/task_invalid_weight.stderr | 27 + .../tests/pallet_ui/task_missing_condition.rs | 39 + .../pallet_ui/task_missing_condition.stderr | 5 + .../tests/pallet_ui/task_missing_index.rs | 38 + .../tests/pallet_ui/task_missing_index.stderr | 5 + .../test/tests/pallet_ui/task_missing_list.rs | 40 + .../tests/pallet_ui/task_missing_list.stderr | 5 + .../tests/pallet_ui/task_missing_weight.rs | 41 + .../pallet_ui/task_missing_weight.stderr | 5 + substrate/frame/system/src/lib.rs | 40 + substrate/frame/system/src/mock.rs | 3 +- substrate/test-utils/runtime/src/lib.rs | 3 +- substrate/utils/frame/rpc/support/src/lib.rs | 1 + 75 files changed, 3516 insertions(+), 24 deletions(-) create mode 100644 prdoc/pr_1343.prdoc create mode 100644 substrate/frame/examples/tasks/Cargo.toml create mode 100644 substrate/frame/examples/tasks/src/benchmarking.rs create mode 100644 substrate/frame/examples/tasks/src/lib.rs create mode 100644 substrate/frame/examples/tasks/src/mock.rs create mode 100644 substrate/frame/examples/tasks/src/tests.rs create mode 100644 substrate/frame/examples/tasks/src/weights.rs create mode 100644 substrate/frame/support/procedural/src/construct_runtime/expand/task.rs create mode 100644 substrate/frame/support/procedural/src/pallet/expand/tasks.rs create mode 100644 substrate/frame/support/procedural/src/pallet/parse/tasks.rs create mode 100644 substrate/frame/support/procedural/src/pallet/parse/tests/mod.rs create mode 100644 substrate/frame/support/procedural/src/pallet/parse/tests/tasks.rs create mode 100644 substrate/frame/support/src/tests/tasks.rs create mode 100644 substrate/frame/support/src/traits/tasks.rs create mode 100644 substrate/frame/support/test/tests/pallet_ui/pass/task_valid.rs create mode 100644 substrate/frame/support/test/tests/pallet_ui/task_can_only_be_attached_to_impl.rs create mode 100644 substrate/frame/support/test/tests/pallet_ui/task_can_only_be_attached_to_impl.stderr create mode 100644 substrate/frame/support/test/tests/pallet_ui/task_condition_invalid_arg.rs create mode 100644 substrate/frame/support/test/tests/pallet_ui/task_condition_invalid_arg.stderr create mode 100644 substrate/frame/support/test/tests/pallet_ui/task_invalid_condition.rs create mode 100644 substrate/frame/support/test/tests/pallet_ui/task_invalid_condition.stderr create mode 100644 substrate/frame/support/test/tests/pallet_ui/task_invalid_index.rs create mode 100644 substrate/frame/support/test/tests/pallet_ui/task_invalid_index.stderr create mode 100644 substrate/frame/support/test/tests/pallet_ui/task_invalid_list.rs create mode 100644 substrate/frame/support/test/tests/pallet_ui/task_invalid_list.stderr create mode 100644 substrate/frame/support/test/tests/pallet_ui/task_invalid_weight.rs create mode 100644 substrate/frame/support/test/tests/pallet_ui/task_invalid_weight.stderr create mode 100644 substrate/frame/support/test/tests/pallet_ui/task_missing_condition.rs create mode 100644 substrate/frame/support/test/tests/pallet_ui/task_missing_condition.stderr create mode 100644 substrate/frame/support/test/tests/pallet_ui/task_missing_index.rs create mode 100644 substrate/frame/support/test/tests/pallet_ui/task_missing_index.stderr create mode 100644 substrate/frame/support/test/tests/pallet_ui/task_missing_list.rs create mode 100644 substrate/frame/support/test/tests/pallet_ui/task_missing_list.stderr create mode 100644 substrate/frame/support/test/tests/pallet_ui/task_missing_weight.rs create mode 100644 substrate/frame/support/test/tests/pallet_ui/task_missing_weight.stderr diff --git a/Cargo.lock b/Cargo.lock index 945698059ec..5184a8137a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5505,6 +5505,7 @@ dependencies = [ "proc-macro-warning", "proc-macro2", "quote", + "regex", "sp-core-hashing", "syn 2.0.39", ] @@ -6879,6 +6880,7 @@ dependencies = [ "pallet-election-provider-multi-phase", "pallet-election-provider-support-benchmarking", "pallet-elections-phragmen", + "pallet-example-tasks", "pallet-fast-unstake", "pallet-glutton", "pallet-grandpa", @@ -9842,6 +9844,22 @@ dependencies = [ "sp-std 8.0.0", ] +[[package]] +name = "pallet-example-tasks" +version = "1.0.0-dev" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 8.0.0", +] + [[package]] name = "pallet-examples" version = "4.0.0-dev" @@ -9853,6 +9871,7 @@ dependencies = [ "pallet-example-kitchensink", "pallet-example-offchain-worker", "pallet-example-split", + "pallet-example-tasks", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index e33b843eb1f..26d48ba0ced 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -308,6 +308,7 @@ members = [ "substrate/frame/examples/kitchensink", "substrate/frame/examples/offchain-worker", "substrate/frame/examples/split", + "substrate/frame/examples/tasks", "substrate/frame/executive", "substrate/frame/fast-unstake", "substrate/frame/glutton", diff --git a/cumulus/pallets/collator-selection/src/mock.rs b/cumulus/pallets/collator-selection/src/mock.rs index 46143674bb3..ab9ad5ec11a 100644 --- a/cumulus/pallets/collator-selection/src/mock.rs +++ b/cumulus/pallets/collator-selection/src/mock.rs @@ -16,7 +16,7 @@ use super::*; use crate as collator_selection; use frame_support::{ - ord_parameter_types, parameter_types, + derive_impl, ord_parameter_types, parameter_types, traits::{ConstBool, ConstU32, ConstU64, FindAuthor, ValidatorRegistration}, PalletId, }; @@ -50,6 +50,7 @@ parameter_types! { pub const SS58Prefix: u8 = 42; } +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); diff --git a/cumulus/parachain-template/pallets/template/src/mock.rs b/cumulus/parachain-template/pallets/template/src/mock.rs index 8fae1019f42..411a16b116c 100644 --- a/cumulus/parachain-template/pallets/template/src/mock.rs +++ b/cumulus/parachain-template/pallets/template/src/mock.rs @@ -1,4 +1,4 @@ -use frame_support::{parameter_types, traits::Everything}; +use frame_support::{derive_impl, parameter_types, traits::Everything}; use frame_system as system; use sp_core::H256; use sp_runtime::{ @@ -22,6 +22,7 @@ parameter_types! { pub const SS58Prefix: u8 = 42; } +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl system::Config for Test { type BaseCallFilter = Everything; type BlockWeights = (); diff --git a/prdoc/pr_1343.prdoc b/prdoc/pr_1343.prdoc new file mode 100644 index 00000000000..84168230e0a --- /dev/null +++ b/prdoc/pr_1343.prdoc @@ -0,0 +1,29 @@ +title: Tasks API - A general system for recognizing and executing service work + +doc: + - audience: Runtime Dev + description: | + The Tasks API allows you to define some service work that can be recognized by a script or an off-chain worker. + Such a script can then create and submit all such work items at any given time. + `#[pallet:tasks_experimental]` provides a convenient way to define such work items. It can be attached to an + `impl` block inside a pallet, whose functions can then be annotated by the following attributes: + 1. `#[pallet::task_list]`: Define an iterator over the available work items for a task + 2. `#[pallet::task_condition]`: Define the conditions for a given work item to be valid + 3. `#[pallet::task_weight]`: Define the weight of a given work item + 4. `#[pallet::task_index]`: Define the index of a given work item + Each such function becomes a variant of the autogenerated enum `Task` for this pallet. + All such enums are aggregated into a `RuntimeTask` by `construct_runtime`. + An example pallet that uses the Tasks API is available at `substrate/frame/example/tasks`. + +migrations: + db: [] + + runtime: [] + +crates: + - name: frame-system + - name: frame-support + - name: frame-support-procedural + - name: pallet-example-tasks + +host_functions: [] diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index e53646c0ef4..8ea2988bee0 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -80,6 +80,7 @@ pallet-democracy = { path = "../../../frame/democracy", default-features = false pallet-election-provider-multi-phase = { path = "../../../frame/election-provider-multi-phase", default-features = false } pallet-election-provider-support-benchmarking = { path = "../../../frame/election-provider-support/benchmarking", default-features = false, optional = true } pallet-elections-phragmen = { path = "../../../frame/elections-phragmen", default-features = false } +pallet-example-tasks = { path = "../../../frame/examples/tasks", default-features = false } pallet-fast-unstake = { path = "../../../frame/fast-unstake", default-features = false } pallet-nis = { path = "../../../frame/nis", default-features = false } pallet-grandpa = { path = "../../../frame/grandpa", default-features = false } @@ -177,6 +178,7 @@ std = [ "pallet-election-provider-multi-phase/std", "pallet-election-provider-support-benchmarking?/std", "pallet-elections-phragmen/std", + "pallet-example-tasks/std", "pallet-fast-unstake/std", "pallet-glutton/std", "pallet-grandpa/std", @@ -279,6 +281,7 @@ runtime-benchmarks = [ "pallet-election-provider-multi-phase/runtime-benchmarks", "pallet-election-provider-support-benchmarking/runtime-benchmarks", "pallet-elections-phragmen/runtime-benchmarks", + "pallet-example-tasks/runtime-benchmarks", "pallet-fast-unstake/runtime-benchmarks", "pallet-glutton/runtime-benchmarks", "pallet-grandpa/runtime-benchmarks", @@ -353,6 +356,7 @@ try-runtime = [ "pallet-democracy/try-runtime", "pallet-election-provider-multi-phase/try-runtime", "pallet-elections-phragmen/try-runtime", + "pallet-example-tasks/try-runtime", "pallet-fast-unstake/try-runtime", "pallet-glutton/try-runtime", "pallet-grandpa/try-runtime", diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 1f4f22f224a..eded60adfd7 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -304,6 +304,11 @@ impl frame_system::Config for Runtime { impl pallet_insecure_randomness_collective_flip::Config for Runtime {} +impl pallet_example_tasks::Config for Runtime { + type RuntimeTask = RuntimeTask; + type WeightInfo = pallet_example_tasks::weights::SubstrateWeight; +} + impl pallet_utility::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; @@ -2135,6 +2140,7 @@ construct_runtime!( SafeMode: pallet_safe_mode, Statement: pallet_statement, Broker: pallet_broker, + TasksExample: pallet_example_tasks, Mixnet: pallet_mixnet, SkipFeelessPayment: pallet_skip_feeless_payment, } @@ -2227,6 +2233,7 @@ mod benches { [pallet_conviction_voting, ConvictionVoting] [pallet_contracts, Contracts] [pallet_core_fellowship, CoreFellowship] + [tasks_example, TasksExample] [pallet_democracy, Democracy] [pallet_asset_conversion, AssetConversion] [pallet_election_provider_multi_phase, ElectionProviderMultiPhase] diff --git a/substrate/frame/examples/Cargo.toml b/substrate/frame/examples/Cargo.toml index 779baa432fc..b272a15dd63 100644 --- a/substrate/frame/examples/Cargo.toml +++ b/substrate/frame/examples/Cargo.toml @@ -20,6 +20,7 @@ pallet-example-frame-crate = { path = "frame-crate", default-features = false } pallet-example-kitchensink = { path = "kitchensink", default-features = false } pallet-example-offchain-worker = { path = "offchain-worker", default-features = false } pallet-example-split = { path = "split", default-features = false } +pallet-example-tasks = { path = "tasks", default-features = false } [features] default = ["std"] @@ -31,6 +32,7 @@ std = [ "pallet-example-kitchensink/std", "pallet-example-offchain-worker/std", "pallet-example-split/std", + "pallet-example-tasks/std", ] try-runtime = [ "pallet-default-config-example/try-runtime", @@ -39,4 +41,5 @@ try-runtime = [ "pallet-example-kitchensink/try-runtime", "pallet-example-offchain-worker/try-runtime", "pallet-example-split/try-runtime", + "pallet-example-tasks/try-runtime", ] diff --git a/substrate/frame/examples/default-config/src/lib.rs b/substrate/frame/examples/default-config/src/lib.rs index 8a1f6f9d6a8..f1611bca2ce 100644 --- a/substrate/frame/examples/default-config/src/lib.rs +++ b/substrate/frame/examples/default-config/src/lib.rs @@ -47,6 +47,10 @@ pub mod pallet { #[pallet::no_default] // optional. `RuntimeEvent` is automatically excluded as well. type RuntimeEvent: From> + IsType<::RuntimeEvent>; + /// The overarching task type. + #[pallet::no_default] + type RuntimeTask: Task; + /// An input parameter to this pallet. This value can have a default, because it is not /// reliant on `frame_system::Config` or the overarching runtime in any way. type WithDefaultValue: Get; @@ -193,6 +197,7 @@ pub mod tests { impl pallet_default_config_example::Config for Runtime { // These two both cannot have defaults. type RuntimeEvent = RuntimeEvent; + type RuntimeTask = RuntimeTask; type HasNoDefault = frame_support::traits::ConstU32<1>; type CannotHaveDefault = SomeCall; diff --git a/substrate/frame/examples/kitchensink/Cargo.toml b/substrate/frame/examples/kitchensink/Cargo.toml index e63e1192458..3b3b7a3761a 100644 --- a/substrate/frame/examples/kitchensink/Cargo.toml +++ b/substrate/frame/examples/kitchensink/Cargo.toml @@ -7,6 +7,7 @@ license = "MIT-0" homepage = "https://substrate.io" repository.workspace = true description = "FRAME example kitchensink pallet" +publish = false [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/examples/src/lib.rs b/substrate/frame/examples/src/lib.rs index 8d65639f835..f38bbe52dc1 100644 --- a/substrate/frame/examples/src/lib.rs +++ b/substrate/frame/examples/src/lib.rs @@ -43,4 +43,6 @@ //! - [`pallet_example_frame_crate`]: Example pallet showcasing how one can be //! built using only the `frame` umbrella crate. //! +//! - [`pallet_example_tasks`]: This pallet demonstrates the use of `Tasks` to execute service work. +//! //! **Tip**: Use `cargo doc --package --open` to view each pallet's documentation. diff --git a/substrate/frame/examples/tasks/Cargo.toml b/substrate/frame/examples/tasks/Cargo.toml new file mode 100644 index 00000000000..e26e822e40f --- /dev/null +++ b/substrate/frame/examples/tasks/Cargo.toml @@ -0,0 +1,52 @@ +[package] +name = "pallet-example-tasks" +version = "1.0.0-dev" +authors.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true +description = "Pallet to demonstrate the usage of Tasks to recongnize and execute service work" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +log = { version = "0.4.17", default-features = false } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } + +frame-support = { path = "../../support", default-features = false } +frame-system = { path = "../../system", default-features = false } + +sp-io = { path = "../../../primitives/io", default-features = false } +sp-runtime = { path = "../../../primitives/runtime", default-features = false } +sp-std = { path = "../../../primitives/std", default-features = false } +sp-core = { version = "21.0.0", default-features = false, path = "../../../primitives/core" } + +frame-benchmarking = { path = "../../benchmarking", default-features = false, optional = true } + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-benchmarking?/std", + "frame-support/std", + "frame-system/std", + "log/std", + "scale-info/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", +] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", + "sp-runtime/try-runtime", +] diff --git a/substrate/frame/examples/tasks/src/benchmarking.rs b/substrate/frame/examples/tasks/src/benchmarking.rs new file mode 100644 index 00000000000..81f7d3d3b21 --- /dev/null +++ b/substrate/frame/examples/tasks/src/benchmarking.rs @@ -0,0 +1,42 @@ +// This file is part of Substrate. + +// Copyright (C) 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. + +//! Benchmarking for `pallet-example-tasks`. + +#![cfg(feature = "runtime-benchmarks")] + +use crate::*; +use frame_benchmarking::v2::*; + +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn add_number_into_total() { + Numbers::::insert(0, 1); + + #[block] + { + Task::::add_number_into_total(0).unwrap(); + } + + assert_eq!(Numbers::::get(0), None); + } + + impl_benchmark_test_suite!(Pallet, crate::tests::new_test_ext(), crate::mock::Runtime); +} diff --git a/substrate/frame/examples/tasks/src/lib.rs b/substrate/frame/examples/tasks/src/lib.rs new file mode 100644 index 00000000000..c65d8095bcf --- /dev/null +++ b/substrate/frame/examples/tasks/src/lib.rs @@ -0,0 +1,78 @@ +// This file is part of Substrate. + +// Copyright (C) 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. + +//! This pallet demonstrates the use of the `pallet::task` api for service work. +#![cfg_attr(not(feature = "std"), no_std)] + +use frame_support::dispatch::DispatchResult; +// Re-export pallet items so that they can be accessed from the crate namespace. +pub use pallet::*; + +pub mod mock; +pub mod tests; + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; + +pub mod weights; +pub use weights::*; + +#[frame_support::pallet(dev_mode)] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + + #[pallet::error] + pub enum Error { + /// The referenced task was not found. + NotFound, + } + + #[pallet::tasks_experimental] + impl Pallet { + /// Add a pair of numbers into the totals and remove them. + #[pallet::task_list(Numbers::::iter_keys())] + #[pallet::task_condition(|i| Numbers::::contains_key(i))] + #[pallet::task_weight(T::WeightInfo::add_number_into_total())] + #[pallet::task_index(0)] + pub fn add_number_into_total(i: u32) -> DispatchResult { + let v = Numbers::::take(i).ok_or(Error::::NotFound)?; + Total::::mutate(|(total_keys, total_values)| { + *total_keys += i; + *total_values += v; + }); + Ok(()) + } + } + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeTask: frame_support::traits::Task; + type WeightInfo: WeightInfo; + } + + #[pallet::pallet] + pub struct Pallet(_); + + /// Some running total. + #[pallet::storage] + pub type Total = StorageValue<_, (u32, u32), ValueQuery>; + + /// Numbers to be added into the total. + #[pallet::storage] + pub type Numbers = StorageMap<_, Twox64Concat, u32, u32, OptionQuery>; +} diff --git a/substrate/frame/examples/tasks/src/mock.rs b/substrate/frame/examples/tasks/src/mock.rs new file mode 100644 index 00000000000..e0fbec3eb76 --- /dev/null +++ b/substrate/frame/examples/tasks/src/mock.rs @@ -0,0 +1,43 @@ +// This file is part of Substrate. + +// Copyright (C) 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. + +//! Mock runtime for `tasks-example` tests. +#![cfg(test)] + +use crate::{self as tasks_example}; +use frame_support::derive_impl; + +pub type AccountId = u32; +pub type Balance = u32; + +type Block = frame_system::mocking::MockBlock; +frame_support::construct_runtime!( + pub struct Runtime { + System: frame_system, + TasksExample: tasks_example, + } +); + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for Runtime { + type Block = Block; +} + +impl tasks_example::Config for Runtime { + type RuntimeTask = RuntimeTask; + type WeightInfo = (); +} diff --git a/substrate/frame/examples/tasks/src/tests.rs b/substrate/frame/examples/tasks/src/tests.rs new file mode 100644 index 00000000000..6b255491091 --- /dev/null +++ b/substrate/frame/examples/tasks/src/tests.rs @@ -0,0 +1,127 @@ +// This file is part of Substrate. + +// Copyright (C) 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 `pallet-example-tasks`. +#![cfg(test)] + +use crate::{mock::*, Numbers, Total}; +use frame_support::{assert_noop, assert_ok, traits::Task}; +use sp_runtime::BuildStorage; + +// This function basically just builds a genesis storage key/value store according to +// our desired mockup. +pub fn new_test_ext() -> sp_io::TestExternalities { + let t = RuntimeGenesisConfig { + // We use default for brevity, but you can configure as desired if needed. + system: Default::default(), + } + .build_storage() + .unwrap(); + t.into() +} + +#[test] +fn task_enumerate_works() { + new_test_ext().execute_with(|| { + Numbers::::insert(0, 1); + assert_eq!(crate::pallet::Task::::iter().collect::>().len(), 1); + }); +} + +#[test] +fn runtime_task_enumerate_works_via_frame_system_config() { + new_test_ext().execute_with(|| { + Numbers::::insert(0, 1); + Numbers::::insert(1, 4); + assert_eq!( + ::RuntimeTask::iter().collect::>().len(), + 2 + ); + }); +} + +#[test] +fn runtime_task_enumerate_works_via_pallet_config() { + new_test_ext().execute_with(|| { + Numbers::::insert(1, 4); + assert_eq!( + ::RuntimeTask::iter() + .collect::>() + .len(), + 1 + ); + }); +} + +#[test] +fn task_index_works_at_pallet_level() { + new_test_ext().execute_with(|| { + assert_eq!(crate::pallet::Task::::AddNumberIntoTotal { i: 2u32 }.task_index(), 0); + }); +} + +#[test] +fn task_index_works_at_runtime_level() { + new_test_ext().execute_with(|| { + assert_eq!( + ::RuntimeTask::TasksExample(crate::pallet::Task::< + Runtime, + >::AddNumberIntoTotal { + i: 1u32 + }) + .task_index(), + 0 + ); + }); +} + +#[test] +fn task_execution_works() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + Numbers::::insert(0, 1); + Numbers::::insert(1, 4); + + let task = + ::RuntimeTask::TasksExample(crate::pallet::Task::< + Runtime, + >::AddNumberIntoTotal { + i: 1u32, + }); + assert_ok!(System::do_task(RuntimeOrigin::signed(1), task.clone(),)); + assert_eq!(Numbers::::get(0), Some(1)); + assert_eq!(Numbers::::get(1), None); + assert_eq!(Total::::get(), (1, 4)); + System::assert_last_event(frame_system::Event::::TaskCompleted { task }.into()); + }); +} + +#[test] +fn task_execution_fails_for_invalid_task() { + new_test_ext().execute_with(|| { + Numbers::::insert(1, 4); + assert_noop!( + System::do_task( + RuntimeOrigin::signed(1), + ::RuntimeTask::TasksExample( + crate::pallet::Task::::AddNumberIntoTotal { i: 0u32 } + ), + ), + frame_system::Error::::InvalidTask + ); + }); +} diff --git a/substrate/frame/examples/tasks/src/weights.rs b/substrate/frame/examples/tasks/src/weights.rs new file mode 100644 index 00000000000..793af6e9622 --- /dev/null +++ b/substrate/frame/examples/tasks/src/weights.rs @@ -0,0 +1,84 @@ +// This file is part of Substrate. + +// Copyright (C) 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. + +//! Autogenerated weights for `pallet_example_tasks` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-06-02, STEPS: `20`, REPEAT: `10`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `MacBook.local`, CPU: `` +//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/node-template +// benchmark +// pallet +// --chain +// dev +// --pallet +// pallet_example_tasks +// --extrinsic +// * +// --steps +// 20 +// --repeat +// 10 +// --output +// frame/examples/tasks/src/weights.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use core::marker::PhantomData; + +/// Weight functions needed for pallet_template. +pub trait WeightInfo { + fn add_number_into_total() -> Weight; +} + +/// Weight functions for `pallet_example_kitchensink`. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: Kitchensink OtherFoo (r:0 w:1) + /// Proof Skipped: Kitchensink OtherFoo (max_values: Some(1), max_size: None, mode: Measured) + fn add_number_into_total() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_000_000 picoseconds. + Weight::from_parts(1_000_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} + +impl WeightInfo for () { + /// Storage: Kitchensink OtherFoo (r:0 w:1) + /// Proof Skipped: Kitchensink OtherFoo (max_values: Some(1), max_size: None, mode: Measured) + fn add_number_into_total() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_000_000 picoseconds. + Weight::from_parts(1_000_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(RocksDbWeight::get().writes(1)) + } +} diff --git a/substrate/frame/scheduler/src/mock.rs b/substrate/frame/scheduler/src/mock.rs index b6eb1d044fa..4edcfa0a7bf 100644 --- a/substrate/frame/scheduler/src/mock.rs +++ b/substrate/frame/scheduler/src/mock.rs @@ -21,7 +21,7 @@ use super::*; use crate as scheduler; use frame_support::{ - ord_parameter_types, parameter_types, + derive_impl, ord_parameter_types, parameter_types, traits::{ ConstU32, ConstU64, Contains, EitherOfDiverse, EqualPrivilegeOnly, OnFinalize, OnInitialize, }, @@ -118,6 +118,8 @@ parameter_types! { Weight::from_parts(2_000_000_000_000, u64::MAX), ); } + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl system::Config for Test { type BaseCallFilter = BaseFilter; type BlockWeights = BlockWeights; diff --git a/substrate/frame/support/procedural/Cargo.toml b/substrate/frame/support/procedural/Cargo.toml index f1d8a7d4ca9..7c207b230f3 100644 --- a/substrate/frame/support/procedural/Cargo.toml +++ b/substrate/frame/support/procedural/Cargo.toml @@ -28,6 +28,9 @@ proc-macro-warning = { version = "1.0.0", default-features = false } expander = "2.0.0" sp-core-hashing = { path = "../../../primitives/core/hashing" } +[dev-dependencies] +regex = "1" + [features] default = ["std"] std = [] diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/mod.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/mod.rs index a0fc6b8130b..88f9a3c6e33 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/expand/mod.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/mod.rs @@ -26,6 +26,7 @@ mod metadata; mod origin; mod outer_enums; mod slash_reason; +mod task; mod unsigned; pub use call::expand_outer_dispatch; @@ -38,4 +39,5 @@ pub use metadata::expand_runtime_metadata; pub use origin::expand_outer_origin; pub use outer_enums::{expand_outer_enum, OuterEnumType}; pub use slash_reason::expand_outer_slash_reason; +pub use task::expand_outer_task; pub use unsigned::expand_outer_validate_unsigned; diff --git a/substrate/frame/support/procedural/src/construct_runtime/expand/task.rs b/substrate/frame/support/procedural/src/construct_runtime/expand/task.rs new file mode 100644 index 00000000000..bd952202bbb --- /dev/null +++ b/substrate/frame/support/procedural/src/construct_runtime/expand/task.rs @@ -0,0 +1,131 @@ +// This file is part of Substrate. + +// Copyright (C) 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::construct_runtime::Pallet; +use proc_macro2::{Ident, TokenStream as TokenStream2}; +use quote::quote; + +/// Expands aggregate `RuntimeTask` enum. +pub fn expand_outer_task( + runtime_name: &Ident, + pallet_decls: &[Pallet], + scrate: &TokenStream2, +) -> TokenStream2 { + let mut from_impls = Vec::new(); + let mut task_variants = Vec::new(); + let mut variant_names = Vec::new(); + let mut task_paths = Vec::new(); + for decl in pallet_decls { + if decl.find_part("Task").is_none() { + continue; + } + + let variant_name = &decl.name; + let path = &decl.path; + let index = decl.index; + + from_impls.push(quote! { + impl From<#path::Task<#runtime_name>> for RuntimeTask { + fn from(hr: #path::Task<#runtime_name>) -> Self { + RuntimeTask::#variant_name(hr) + } + } + + impl TryInto<#path::Task<#runtime_name>> for RuntimeTask { + type Error = (); + + fn try_into(self) -> Result<#path::Task<#runtime_name>, Self::Error> { + match self { + RuntimeTask::#variant_name(hr) => Ok(hr), + _ => Err(()), + } + } + } + }); + + task_variants.push(quote! { + #[codec(index = #index)] + #variant_name(#path::Task<#runtime_name>), + }); + + variant_names.push(quote!(#variant_name)); + + task_paths.push(quote!(#path::Task)); + } + + let prelude = quote!(#scrate::traits::tasks::__private); + + const INCOMPLETE_MATCH_QED: &'static str = + "cannot have an instantiated RuntimeTask without some Task variant in the runtime. QED"; + + let output = quote! { + /// An aggregation of all `Task` enums across all pallets included in the current runtime. + #[derive( + Clone, Eq, PartialEq, + #scrate::__private::codec::Encode, + #scrate::__private::codec::Decode, + #scrate::__private::scale_info::TypeInfo, + #scrate::__private::RuntimeDebug, + )] + pub enum RuntimeTask { + #( #task_variants )* + } + + #[automatically_derived] + impl #scrate::traits::Task for RuntimeTask { + type Enumeration = #prelude::IntoIter; + + fn is_valid(&self) -> bool { + match self { + #(RuntimeTask::#variant_names(val) => val.is_valid(),)* + _ => unreachable!(#INCOMPLETE_MATCH_QED), + } + } + + fn run(&self) -> Result<(), #scrate::traits::tasks::__private::DispatchError> { + match self { + #(RuntimeTask::#variant_names(val) => val.run(),)* + _ => unreachable!(#INCOMPLETE_MATCH_QED), + } + } + + fn weight(&self) -> #scrate::pallet_prelude::Weight { + match self { + #(RuntimeTask::#variant_names(val) => val.weight(),)* + _ => unreachable!(#INCOMPLETE_MATCH_QED), + } + } + + fn task_index(&self) -> u32 { + match self { + #(RuntimeTask::#variant_names(val) => val.task_index(),)* + _ => unreachable!(#INCOMPLETE_MATCH_QED), + } + } + + fn iter() -> Self::Enumeration { + let mut all_tasks = Vec::new(); + #(all_tasks.extend(#task_paths::iter().map(RuntimeTask::from).collect::>());)* + all_tasks.into_iter() + } + } + + #( #from_impls )* + }; + + output +} diff --git a/substrate/frame/support/procedural/src/construct_runtime/mod.rs b/substrate/frame/support/procedural/src/construct_runtime/mod.rs index 010143574ed..7a9c4d89a74 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/mod.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/mod.rs @@ -386,6 +386,7 @@ fn construct_runtime_final_expansion( let pallet_to_index = decl_pallet_runtime_setup(&name, &pallets, &scrate); let dispatch = expand::expand_outer_dispatch(&name, system_pallet, &pallets, &scrate); + let tasks = expand::expand_outer_task(&name, &pallets, &scrate); let metadata = expand::expand_runtime_metadata( &name, &pallets, @@ -475,6 +476,8 @@ fn construct_runtime_final_expansion( #dispatch + #tasks + #metadata #outer_config diff --git a/substrate/frame/support/procedural/src/construct_runtime/parse.rs b/substrate/frame/support/procedural/src/construct_runtime/parse.rs index 9b08e164697..88f3f14dc86 100644 --- a/substrate/frame/support/procedural/src/construct_runtime/parse.rs +++ b/substrate/frame/support/procedural/src/construct_runtime/parse.rs @@ -42,6 +42,7 @@ mod keyword { syn::custom_keyword!(ValidateUnsigned); syn::custom_keyword!(FreezeReason); syn::custom_keyword!(HoldReason); + syn::custom_keyword!(Task); syn::custom_keyword!(LockId); syn::custom_keyword!(SlashReason); syn::custom_keyword!(exclude_parts); @@ -404,6 +405,7 @@ pub enum PalletPartKeyword { ValidateUnsigned(keyword::ValidateUnsigned), FreezeReason(keyword::FreezeReason), HoldReason(keyword::HoldReason), + Task(keyword::Task), LockId(keyword::LockId), SlashReason(keyword::SlashReason), } @@ -434,6 +436,8 @@ impl Parse for PalletPartKeyword { Ok(Self::FreezeReason(input.parse()?)) } else if lookahead.peek(keyword::HoldReason) { Ok(Self::HoldReason(input.parse()?)) + } else if lookahead.peek(keyword::Task) { + Ok(Self::Task(input.parse()?)) } else if lookahead.peek(keyword::LockId) { Ok(Self::LockId(input.parse()?)) } else if lookahead.peek(keyword::SlashReason) { @@ -459,6 +463,7 @@ impl PalletPartKeyword { Self::ValidateUnsigned(_) => "ValidateUnsigned", Self::FreezeReason(_) => "FreezeReason", Self::HoldReason(_) => "HoldReason", + Self::Task(_) => "Task", Self::LockId(_) => "LockId", Self::SlashReason(_) => "SlashReason", } @@ -471,7 +476,7 @@ impl PalletPartKeyword { /// Returns the names of all pallet parts that allow to have a generic argument. fn all_generic_arg() -> &'static [&'static str] { - &["Event", "Error", "Origin", "Config"] + &["Event", "Error", "Origin", "Config", "Task"] } } @@ -489,6 +494,7 @@ impl ToTokens for PalletPartKeyword { Self::ValidateUnsigned(inner) => inner.to_tokens(tokens), Self::FreezeReason(inner) => inner.to_tokens(tokens), Self::HoldReason(inner) => inner.to_tokens(tokens), + Self::Task(inner) => inner.to_tokens(tokens), Self::LockId(inner) => inner.to_tokens(tokens), Self::SlashReason(inner) => inner.to_tokens(tokens), } diff --git a/substrate/frame/support/procedural/src/lib.rs b/substrate/frame/support/procedural/src/lib.rs index 682b135fa14..349b6ee6599 100644 --- a/substrate/frame/support/procedural/src/lib.rs +++ b/substrate/frame/support/procedural/src/lib.rs @@ -646,7 +646,6 @@ pub fn storage_alias(attributes: TokenStream, input: TokenStream) -> TokenStream /// ``` /// /// where `TestDefaultConfig` was defined and registered as follows: -/// /// ```ignore /// pub struct TestDefaultConfig; /// @@ -673,7 +672,6 @@ pub fn storage_alias(attributes: TokenStream, input: TokenStream) -> TokenStream /// ``` /// /// The above call to `derive_impl` would expand to roughly the following: -/// /// ```ignore /// impl frame_system::Config for Test { /// use frame_system::config_preludes::TestDefaultConfig; @@ -881,6 +879,7 @@ pub fn inject_runtime_type(_: TokenStream, tokens: TokenStream) -> TokenStream { let item = syn::parse_macro_input!(item as TraitItemType); if item.ident != "RuntimeCall" && item.ident != "RuntimeEvent" && + item.ident != "RuntimeTask" && item.ident != "RuntimeOrigin" && item.ident != "RuntimeHoldReason" && item.ident != "RuntimeFreezeReason" && @@ -888,10 +887,11 @@ pub fn inject_runtime_type(_: TokenStream, tokens: TokenStream) -> TokenStream { { return syn::Error::new_spanned( item, - "`#[inject_runtime_type]` can only be attached to `RuntimeCall`, `RuntimeEvent`, `RuntimeOrigin` or `PalletInfo`", + "`#[inject_runtime_type]` can only be attached to `RuntimeCall`, `RuntimeEvent`, \ + `RuntimeTask`, `RuntimeOrigin` or `PalletInfo`", ) .to_compile_error() - .into(); + .into() } tokens } @@ -1518,6 +1518,56 @@ pub fn composite_enum(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } +/// +/// --- +/// +/// **Rust-Analyzer users**: See the documentation of the Rust item in +/// `frame_support::pallet_macros::tasks_experimental`. +#[proc_macro_attribute] +pub fn tasks_experimental(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// +/// --- +/// +/// **Rust-Analyzer users**: See the documentation of the Rust item in +/// `frame_support::pallet_macros::task_list`. +#[proc_macro_attribute] +pub fn task_list(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// +/// --- +/// +/// **Rust-Analyzer users**: See the documentation of the Rust item in +/// `frame_support::pallet_macros::task_condition`. +#[proc_macro_attribute] +pub fn task_condition(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// +/// --- +/// +/// **Rust-Analyzer users**: See the documentation of the Rust item in +/// `frame_support::pallet_macros::task_weight`. +#[proc_macro_attribute] +pub fn task_weight(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// +/// --- +/// +/// **Rust-Analyzer users**: See the documentation of the Rust item in +/// `frame_support::pallet_macros::task_index`. +#[proc_macro_attribute] +pub fn task_index(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + /// Can be attached to a module. Doing so will declare that module as importable into a pallet /// via [`#[import_section]`](`macro@import_section`). /// diff --git a/substrate/frame/support/procedural/src/pallet/expand/mod.rs b/substrate/frame/support/procedural/src/pallet/expand/mod.rs index 6f32e569751..db242df781b 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/mod.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/mod.rs @@ -31,6 +31,7 @@ mod origin; mod pallet_struct; mod storage; mod store_trait; +mod tasks; mod tt_default_parts; mod type_value; mod validate_unsigned; @@ -60,6 +61,7 @@ pub fn expand(mut def: Def) -> proc_macro2::TokenStream { let pallet_struct = pallet_struct::expand_pallet_struct(&mut def); let config = config::expand_config(&mut def); let call = call::expand_call(&mut def); + let tasks = tasks::expand_tasks(&mut def); let error = error::expand_error(&mut def); let event = event::expand_event(&mut def); let storages = storage::expand_storages(&mut def); @@ -100,6 +102,7 @@ storage item. Otherwise, all storage items are listed among [*Type Definitions*] #pallet_struct #config #call + #tasks #error #event #storages diff --git a/substrate/frame/support/procedural/src/pallet/expand/tasks.rs b/substrate/frame/support/procedural/src/pallet/expand/tasks.rs new file mode 100644 index 00000000000..6697e5c822a --- /dev/null +++ b/substrate/frame/support/procedural/src/pallet/expand/tasks.rs @@ -0,0 +1,267 @@ +//! Contains logic for expanding task-related items. + +// This file is part of Substrate. + +// Copyright (C) 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. + +//! Home of the expansion code for the Tasks API + +use crate::pallet::{parse::tasks::*, Def}; +use derive_syn_parse::Parse; +use inflector::Inflector; +use proc_macro2::TokenStream as TokenStream2; +use quote::{format_ident, quote, ToTokens}; +use syn::{parse_quote, spanned::Spanned, ItemEnum, ItemImpl}; + +impl TaskEnumDef { + /// Since we optionally allow users to manually specify a `#[pallet::task_enum]`, in the + /// event they _don't_ specify one (which is actually the most common behavior) we have to + /// generate one based on the existing [`TasksDef`]. This method performs that generation. + pub fn generate( + tasks: &TasksDef, + type_decl_bounded_generics: TokenStream2, + type_use_generics: TokenStream2, + ) -> Self { + let variants = if tasks.tasks_attr.is_some() { + tasks + .tasks + .iter() + .map(|task| { + let ident = &task.item.sig.ident; + let ident = + format_ident!("{}", ident.to_string().to_class_case(), span = ident.span()); + + let args = task.item.sig.inputs.iter().collect::>(); + + if args.is_empty() { + quote!(#ident) + } else { + quote!(#ident { + #(#args),* + }) + } + }) + .collect::>() + } else { + Vec::new() + }; + let mut task_enum_def: TaskEnumDef = parse_quote! { + /// Auto-generated enum that encapsulates all tasks defined by this pallet. + /// + /// Conceptually similar to the [`Call`] enum, but for tasks. This is only + /// generated if there are tasks present in this pallet. + #[pallet::task_enum] + pub enum Task<#type_decl_bounded_generics> { + #( + #variants, + )* + } + }; + task_enum_def.type_use_generics = type_use_generics; + task_enum_def + } +} + +impl ToTokens for TaskEnumDef { + fn to_tokens(&self, tokens: &mut TokenStream2) { + let item_enum = &self.item_enum; + let ident = &item_enum.ident; + let vis = &item_enum.vis; + let attrs = &item_enum.attrs; + let generics = &item_enum.generics; + let variants = &item_enum.variants; + let scrate = &self.scrate; + let type_use_generics = &self.type_use_generics; + if self.attr.is_some() { + // `item_enum` is short-hand / generated enum + tokens.extend(quote! { + #(#attrs)* + #[derive( + #scrate::CloneNoBound, + #scrate::EqNoBound, + #scrate::PartialEqNoBound, + #scrate::pallet_prelude::Encode, + #scrate::pallet_prelude::Decode, + #scrate::pallet_prelude::TypeInfo, + )] + #[codec(encode_bound())] + #[codec(decode_bound())] + #[scale_info(skip_type_params(#type_use_generics))] + #vis enum #ident #generics { + #variants + #[doc(hidden)] + #[codec(skip)] + __Ignore(core::marker::PhantomData, #scrate::Never), + } + + impl core::fmt::Debug for #ident<#type_use_generics> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct(stringify!(#ident)).field("value", self).finish() + } + } + }); + } else { + // `item_enum` is a manually specified enum (no attribute) + tokens.extend(item_enum.to_token_stream()); + } + } +} + +/// Represents an already-expanded [`TasksDef`]. +#[derive(Parse)] +pub struct ExpandedTasksDef { + pub task_item_impl: ItemImpl, + pub task_trait_impl: ItemImpl, +} + +impl ToTokens for TasksDef { + fn to_tokens(&self, tokens: &mut TokenStream2) { + let scrate = &self.scrate; + let enum_ident = syn::Ident::new("Task", self.enum_ident.span()); + let enum_arguments = &self.enum_arguments; + let enum_use = quote!(#enum_ident #enum_arguments); + + let task_fn_idents = self + .tasks + .iter() + .map(|task| { + format_ident!( + "{}", + &task.item.sig.ident.to_string().to_class_case(), + span = task.item.sig.ident.span() + ) + }) + .collect::>(); + let task_indices = self.tasks.iter().map(|task| &task.index_attr.meta.index); + let task_conditions = self.tasks.iter().map(|task| &task.condition_attr.meta.expr); + let task_weights = self.tasks.iter().map(|task| &task.weight_attr.meta.expr); + let task_iters = self.tasks.iter().map(|task| &task.list_attr.meta.expr); + + let task_fn_impls = self.tasks.iter().map(|task| { + let mut task_fn_impl = task.item.clone(); + task_fn_impl.attrs = vec![]; + task_fn_impl + }); + + let task_fn_names = self.tasks.iter().map(|task| &task.item.sig.ident); + let task_arg_names = self.tasks.iter().map(|task| &task.arg_names).collect::>(); + + let sp_std = quote!(#scrate::__private::sp_std); + let impl_generics = &self.item_impl.generics; + tokens.extend(quote! { + impl #impl_generics #enum_use + { + #(#task_fn_impls)* + } + + impl #impl_generics #scrate::traits::Task for #enum_use + { + type Enumeration = #sp_std::vec::IntoIter<#enum_use>; + + fn iter() -> Self::Enumeration { + let mut all_tasks = #sp_std::vec![]; + #(all_tasks + .extend(#task_iters.map(|(#(#task_arg_names),*)| #enum_ident::#task_fn_idents { #(#task_arg_names: #task_arg_names.clone()),* }) + .collect::<#sp_std::vec::Vec<_>>()); + )* + all_tasks.into_iter() + } + + fn task_index(&self) -> u32 { + match self.clone() { + #(#enum_ident::#task_fn_idents { .. } => #task_indices,)* + Task::__Ignore(_, _) => unreachable!(), + } + } + + fn is_valid(&self) -> bool { + match self.clone() { + #(#enum_ident::#task_fn_idents { #(#task_arg_names),* } => (#task_conditions)(#(#task_arg_names),* ),)* + Task::__Ignore(_, _) => unreachable!(), + } + } + + fn run(&self) -> Result<(), #scrate::pallet_prelude::DispatchError> { + match self.clone() { + #(#enum_ident::#task_fn_idents { #(#task_arg_names),* } => { + <#enum_use>::#task_fn_names(#( #task_arg_names, )* ) + },)* + Task::__Ignore(_, _) => unreachable!(), + } + } + + #[allow(unused_variables)] + fn weight(&self) -> #scrate::pallet_prelude::Weight { + match self.clone() { + #(#enum_ident::#task_fn_idents { #(#task_arg_names),* } => #task_weights,)* + Task::__Ignore(_, _) => unreachable!(), + } + } + } + }); + } +} + +/// Expands the [`TasksDef`] in the enclosing [`Def`], if present, and returns its tokens. +/// +/// This modifies the underlying [`Def`] in addition to returning any tokens that were added. +pub fn expand_tasks_impl(def: &mut Def) -> TokenStream2 { + let Some(tasks) = &mut def.tasks else { return quote!() }; + let ExpandedTasksDef { task_item_impl, task_trait_impl } = parse_quote!(#tasks); + quote! { + #task_item_impl + #task_trait_impl + } +} + +/// Represents a fully-expanded [`TaskEnumDef`]. +#[derive(Parse)] +pub struct ExpandedTaskEnum { + pub item_enum: ItemEnum, + pub debug_impl: ItemImpl, +} + +/// Modifies a [`Def`] to expand the underlying [`TaskEnumDef`] if present, and also returns +/// its tokens. A blank [`TokenStream2`] is returned if no [`TaskEnumDef`] has been generated +/// or defined. +pub fn expand_task_enum(def: &mut Def) -> TokenStream2 { + let Some(task_enum) = &mut def.task_enum else { return quote!() }; + let ExpandedTaskEnum { item_enum, debug_impl } = parse_quote!(#task_enum); + quote! { + #item_enum + #debug_impl + } +} + +/// Modifies a [`Def`] to expand the underlying [`TasksDef`] and also generate a +/// [`TaskEnumDef`] if applicable. The tokens for these items are returned if they are created. +pub fn expand_tasks(def: &mut Def) -> TokenStream2 { + if let Some(tasks_def) = &def.tasks { + if def.task_enum.is_none() { + def.task_enum = Some(TaskEnumDef::generate( + &tasks_def, + def.type_decl_bounded_generics(tasks_def.item_impl.span()), + def.type_use_generics(tasks_def.item_impl.span()), + )); + } + } + let tasks_extra_output = expand_tasks_impl(def); + let task_enum_extra_output = expand_task_enum(def); + quote! { + #tasks_extra_output + #task_enum_extra_output + } +} diff --git a/substrate/frame/support/procedural/src/pallet/expand/tt_default_parts.rs b/substrate/frame/support/procedural/src/pallet/expand/tt_default_parts.rs index c9a776ee247..7cc1415dfdd 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/tt_default_parts.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/tt_default_parts.rs @@ -31,6 +31,8 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream { let call_part = def.call.as_ref().map(|_| quote::quote!(Call,)); + let task_part = def.task_enum.as_ref().map(|_| quote::quote!(Task,)); + let storage_part = (!def.storages.is_empty()).then(|| quote::quote!(Storage,)); let event_part = def.event.as_ref().map(|event| { @@ -99,7 +101,7 @@ pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream { tokens = [{ expanded::{ Pallet, #call_part #storage_part #event_part #error_part #origin_part #config_part - #inherent_part #validate_unsigned_part #freeze_reason_part + #inherent_part #validate_unsigned_part #freeze_reason_part #task_part #hold_reason_part #lock_id_part #slash_reason_part } }] diff --git a/substrate/frame/support/procedural/src/pallet/parse/call.rs b/substrate/frame/support/procedural/src/pallet/parse/call.rs index f78f2baa9d1..58e14365e76 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/call.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/call.rs @@ -286,8 +286,7 @@ impl CallDef { if weight_attrs.is_empty() && dev_mode { // inject a default O(1) weight when dev mode is enabled and no weight has // been specified on the call - let empty_weight: syn::Expr = syn::parse(quote::quote!(0).into()) - .expect("we are parsing a quoted string; qed"); + let empty_weight: syn::Expr = syn::parse_quote!(0); weight_attrs.push(FunctionAttr::Weight(empty_weight)); } diff --git a/substrate/frame/support/procedural/src/pallet/parse/composite.rs b/substrate/frame/support/procedural/src/pallet/parse/composite.rs index 6e6ea6a795c..fa5f47dfdfa 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/composite.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/composite.rs @@ -26,11 +26,14 @@ pub mod keyword { syn::custom_keyword!(HoldReason); syn::custom_keyword!(LockId); syn::custom_keyword!(SlashReason); + syn::custom_keyword!(Task); + pub enum CompositeKeyword { FreezeReason(FreezeReason), HoldReason(HoldReason), LockId(LockId), SlashReason(SlashReason), + Task(Task), } impl ToTokens for CompositeKeyword { @@ -41,6 +44,7 @@ pub mod keyword { HoldReason(inner) => inner.to_tokens(tokens), LockId(inner) => inner.to_tokens(tokens), SlashReason(inner) => inner.to_tokens(tokens), + Task(inner) => inner.to_tokens(tokens), } } } @@ -56,6 +60,8 @@ pub mod keyword { Ok(Self::LockId(input.parse()?)) } else if lookahead.peek(SlashReason) { Ok(Self::SlashReason(input.parse()?)) + } else if lookahead.peek(Task) { + Ok(Self::Task(input.parse()?)) } else { Err(lookahead.error()) } @@ -71,6 +77,7 @@ pub mod keyword { match self { FreezeReason(_) => "FreezeReason", HoldReason(_) => "HoldReason", + Task(_) => "Task", LockId(_) => "LockId", SlashReason(_) => "SlashReason", } @@ -80,7 +87,7 @@ pub mod keyword { } pub struct CompositeDef { - /// The index of the HoldReason item in the pallet module. + /// The index of the CompositeDef item in the pallet module. pub index: usize, /// The composite keyword used (contains span). pub composite_keyword: keyword::CompositeKeyword, diff --git a/substrate/frame/support/procedural/src/pallet/parse/mod.rs b/substrate/frame/support/procedural/src/pallet/parse/mod.rs index 83a881751ef..e1efdbcc202 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/mod.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/mod.rs @@ -33,11 +33,16 @@ pub mod inherent; pub mod origin; pub mod pallet_struct; pub mod storage; +pub mod tasks; pub mod type_value; pub mod validate_unsigned; +#[cfg(test)] +pub mod tests; + use composite::{keyword::CompositeKeyword, CompositeDef}; use frame_support_procedural_tools::generate_access_from_frame_or_crate; +use quote::ToTokens; use syn::spanned::Spanned; /// Parsed definition of a pallet. @@ -49,6 +54,8 @@ pub struct Def { pub pallet_struct: pallet_struct::PalletStructDef, pub hooks: Option, pub call: Option, + pub tasks: Option, + pub task_enum: Option, pub storages: Vec, pub error: Option, pub event: Option, @@ -84,6 +91,8 @@ impl Def { let mut pallet_struct = None; let mut hooks = None; let mut call = None; + let mut tasks = None; + let mut task_enum = None; let mut error = None; let mut event = None; let mut origin = None; @@ -118,6 +127,32 @@ impl Def { }, Some(PalletAttr::RuntimeCall(cw, span)) if call.is_none() => call = Some(call::CallDef::try_from(span, index, item, dev_mode, cw)?), + Some(PalletAttr::Tasks(_)) if tasks.is_none() => { + let item_tokens = item.to_token_stream(); + // `TasksDef::parse` needs to know if attr was provided so we artificially + // re-insert it here + tasks = Some(syn::parse2::(quote::quote! { + #[pallet::tasks_experimental] + #item_tokens + })?); + + // replace item with a no-op because it will be handled by the expansion of tasks + *item = syn::Item::Verbatim(quote::quote!()); + } + Some(PalletAttr::TaskCondition(span)) => return Err(syn::Error::new( + span, + "`#[pallet::task_condition]` can only be used on items within an `impl` statement." + )), + Some(PalletAttr::TaskIndex(span)) => return Err(syn::Error::new( + span, + "`#[pallet::task_index]` can only be used on items within an `impl` statement." + )), + Some(PalletAttr::TaskList(span)) => return Err(syn::Error::new( + span, + "`#[pallet::task_list]` can only be used on items within an `impl` statement." + )), + Some(PalletAttr::RuntimeTask(_)) if task_enum.is_none() => + task_enum = Some(syn::parse2::(item.to_token_stream())?), Some(PalletAttr::Error(span)) if error.is_none() => error = Some(error::ErrorDef::try_from(span, index, item)?), Some(PalletAttr::RuntimeEvent(span)) if event.is_none() => @@ -190,6 +225,8 @@ impl Def { return Err(syn::Error::new(item_span, msg)) } + Self::resolve_tasks(&item_span, &mut tasks, &mut task_enum, items)?; + let def = Def { item, config: config @@ -198,6 +235,8 @@ impl Def { .ok_or_else(|| syn::Error::new(item_span, "Missing `#[pallet::pallet]`"))?, hooks, call, + tasks, + task_enum, extra_constants, genesis_config, genesis_build, @@ -220,6 +259,99 @@ impl Def { Ok(def) } + /// Performs extra logic checks necessary for the `#[pallet::tasks_experimental]` feature. + fn resolve_tasks( + item_span: &proc_macro2::Span, + tasks: &mut Option, + task_enum: &mut Option, + items: &mut Vec, + ) -> syn::Result<()> { + // fallback for manual (without macros) definition of tasks impl + Self::resolve_manual_tasks_impl(tasks, task_enum, items)?; + + // fallback for manual (without macros) definition of task enum + Self::resolve_manual_task_enum(tasks, task_enum, items)?; + + // ensure that if `task_enum` is specified, `tasks` is also specified + match (&task_enum, &tasks) { + (Some(_), None) => + return Err(syn::Error::new( + *item_span, + "Missing `#[pallet::tasks_experimental]` impl", + )), + (None, Some(tasks)) => + if tasks.tasks_attr.is_none() { + return Err(syn::Error::new( + tasks.item_impl.impl_token.span(), + "A `#[pallet::tasks_experimental]` attribute must be attached to your `Task` impl if the \ + task enum has been omitted", + )) + } else { + }, + _ => (), + } + + Ok(()) + } + + /// Tries to locate task enum based on the tasks impl target if attribute is not specified + /// but impl is present. If one is found, `task_enum` is set appropriately. + fn resolve_manual_task_enum( + tasks: &Option, + task_enum: &mut Option, + items: &mut Vec, + ) -> syn::Result<()> { + let (None, Some(tasks)) = (&task_enum, &tasks) else { return Ok(()) }; + let syn::Type::Path(type_path) = &*tasks.item_impl.self_ty else { return Ok(()) }; + let type_path = type_path.path.segments.iter().collect::>(); + let (Some(seg), None) = (type_path.get(0), type_path.get(1)) else { return Ok(()) }; + let mut result = None; + for item in items { + let syn::Item::Enum(item_enum) = item else { continue }; + if item_enum.ident == seg.ident { + result = Some(syn::parse2::(item_enum.to_token_stream())?); + // replace item with a no-op because it will be handled by the expansion of + // `task_enum`. We use a no-op instead of simply removing it from the vec + // so that any indices collected by `Def::try_from` remain accurate + *item = syn::Item::Verbatim(quote::quote!()); + break + } + } + *task_enum = result; + Ok(()) + } + + /// Tries to locate a manual tasks impl (an impl impling a trait whose last path segment is + /// `Task`) in the event that one has not been found already via the attribute macro + pub fn resolve_manual_tasks_impl( + tasks: &mut Option, + task_enum: &Option, + items: &Vec, + ) -> syn::Result<()> { + let None = tasks else { return Ok(()) }; + let mut result = None; + for item in items { + let syn::Item::Impl(item_impl) = item else { continue }; + let Some((_, path, _)) = &item_impl.trait_ else { continue }; + let Some(trait_last_seg) = path.segments.last() else { continue }; + let syn::Type::Path(target_path) = &*item_impl.self_ty else { continue }; + let target_path = target_path.path.segments.iter().collect::>(); + let (Some(target_ident), None) = (target_path.get(0), target_path.get(1)) else { + continue + }; + let matches_task_enum = match task_enum { + Some(task_enum) => task_enum.item_enum.ident == target_ident.ident, + None => true, + }; + if trait_last_seg.ident == "Task" && matches_task_enum { + result = Some(syn::parse2::(item_impl.to_token_stream())?); + break + } + } + *tasks = result; + Ok(()) + } + /// Check that usage of trait `Event` is consistent with the definition, i.e. it is declared /// and trait defines type RuntimeEvent, or not declared and no trait associated type. fn check_event_usage(&self) -> syn::Result<()> { @@ -408,6 +540,11 @@ impl GenericKind { mod keyword { syn::custom_keyword!(origin); syn::custom_keyword!(call); + syn::custom_keyword!(tasks_experimental); + syn::custom_keyword!(task_enum); + syn::custom_keyword!(task_list); + syn::custom_keyword!(task_condition); + syn::custom_keyword!(task_index); syn::custom_keyword!(weight); syn::custom_keyword!(event); syn::custom_keyword!(config); @@ -472,6 +609,11 @@ enum PalletAttr { /// instead of the zero weight. So to say: it works together with `dev_mode`. RuntimeCall(Option, proc_macro2::Span), Error(proc_macro2::Span), + Tasks(proc_macro2::Span), + TaskList(proc_macro2::Span), + TaskCondition(proc_macro2::Span), + TaskIndex(proc_macro2::Span), + RuntimeTask(proc_macro2::Span), RuntimeEvent(proc_macro2::Span), RuntimeOrigin(proc_macro2::Span), Inherent(proc_macro2::Span), @@ -490,8 +632,13 @@ impl PalletAttr { Self::Config(span, _) => *span, Self::Pallet(span) => *span, Self::Hooks(span) => *span, - Self::RuntimeCall(_, span) => *span, + Self::Tasks(span) => *span, + Self::TaskCondition(span) => *span, + Self::TaskIndex(span) => *span, + Self::TaskList(span) => *span, Self::Error(span) => *span, + Self::RuntimeTask(span) => *span, + Self::RuntimeCall(_, span) => *span, Self::RuntimeEvent(span) => *span, Self::RuntimeOrigin(span) => *span, Self::Inherent(span) => *span, @@ -535,6 +682,16 @@ impl syn::parse::Parse for PalletAttr { false => Some(InheritedCallWeightAttr::parse(&content)?), }; Ok(PalletAttr::RuntimeCall(attr, span)) + } else if lookahead.peek(keyword::tasks_experimental) { + Ok(PalletAttr::Tasks(content.parse::()?.span())) + } else if lookahead.peek(keyword::task_enum) { + Ok(PalletAttr::RuntimeTask(content.parse::()?.span())) + } else if lookahead.peek(keyword::task_condition) { + Ok(PalletAttr::TaskCondition(content.parse::()?.span())) + } else if lookahead.peek(keyword::task_index) { + Ok(PalletAttr::TaskIndex(content.parse::()?.span())) + } else if lookahead.peek(keyword::task_list) { + Ok(PalletAttr::TaskList(content.parse::()?.span())) } else if lookahead.peek(keyword::error) { Ok(PalletAttr::Error(content.parse::()?.span())) } else if lookahead.peek(keyword::event) { diff --git a/substrate/frame/support/procedural/src/pallet/parse/tasks.rs b/substrate/frame/support/procedural/src/pallet/parse/tasks.rs new file mode 100644 index 00000000000..6405bb415a6 --- /dev/null +++ b/substrate/frame/support/procedural/src/pallet/parse/tasks.rs @@ -0,0 +1,968 @@ +// This file is part of Substrate. + +// Copyright (C) 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. + +//! Home of the parsing code for the Tasks API + +use std::collections::HashSet; + +#[cfg(test)] +use crate::assert_parse_error_matches; + +#[cfg(test)] +use crate::pallet::parse::tests::simulate_manifest_dir; + +use derive_syn_parse::Parse; +use frame_support_procedural_tools::generate_access_from_frame_or_crate; +use proc_macro2::TokenStream as TokenStream2; +use quote::{quote, ToTokens}; +use syn::{ + parse::ParseStream, + parse2, + spanned::Spanned, + token::{Bracket, Paren, PathSep, Pound}, + Attribute, Error, Expr, Ident, ImplItem, ImplItemFn, ItemEnum, ItemImpl, LitInt, Path, + PathArguments, Result, TypePath, +}; + +pub mod keywords { + use syn::custom_keyword; + + custom_keyword!(tasks_experimental); + custom_keyword!(task_enum); + custom_keyword!(task_list); + custom_keyword!(task_condition); + custom_keyword!(task_index); + custom_keyword!(task_weight); + custom_keyword!(pallet); +} + +/// Represents the `#[pallet::tasks_experimental]` attribute and its attached item. Also includes +/// metadata about the linked [`TaskEnumDef`] if applicable. +#[derive(Clone, Debug)] +pub struct TasksDef { + pub tasks_attr: Option, + pub tasks: Vec, + pub item_impl: ItemImpl, + /// Path to `frame_support` + pub scrate: Path, + pub enum_ident: Ident, + pub enum_arguments: PathArguments, +} + +impl syn::parse::Parse for TasksDef { + fn parse(input: ParseStream) -> Result { + let item_impl: ItemImpl = input.parse()?; + let (tasks_attrs, normal_attrs) = partition_tasks_attrs(&item_impl); + let tasks_attr = match tasks_attrs.first() { + Some(attr) => Some(parse2::(attr.to_token_stream())?), + None => None, + }; + if let Some(extra_tasks_attr) = tasks_attrs.get(1) { + return Err(Error::new( + extra_tasks_attr.span(), + "unexpected extra `#[pallet::tasks_experimental]` attribute", + )) + } + let tasks: Vec = if tasks_attr.is_some() { + item_impl + .items + .clone() + .into_iter() + .filter(|impl_item| matches!(impl_item, ImplItem::Fn(_))) + .map(|item| parse2::(item.to_token_stream())) + .collect::>()? + } else { + Vec::new() + }; + let mut task_indices = HashSet::::new(); + for task in tasks.iter() { + let task_index = &task.index_attr.meta.index; + if !task_indices.insert(task_index.clone()) { + return Err(Error::new( + task_index.span(), + format!("duplicate task index `{}`", task_index), + )) + } + } + let mut item_impl = item_impl; + item_impl.attrs = normal_attrs; + + // we require the path on the impl to be a TypePath + let enum_path = parse2::(item_impl.self_ty.to_token_stream())?; + let segments = enum_path.path.segments.iter().collect::>(); + let (Some(last_seg), None) = (segments.get(0), segments.get(1)) else { + return Err(Error::new( + enum_path.span(), + "if specified manually, the task enum must be defined locally in this \ + pallet and cannot be a re-export", + )) + }; + let enum_ident = last_seg.ident.clone(); + let enum_arguments = last_seg.arguments.clone(); + + // We do this here because it would be improper to do something fallible like this at + // the expansion phase. Fallible stuff should happen during parsing. + let scrate = generate_access_from_frame_or_crate("frame-support")?; + + Ok(TasksDef { tasks_attr, item_impl, tasks, scrate, enum_ident, enum_arguments }) + } +} + +/// Parsing for a `#[pallet::tasks_experimental]` attr. +pub type PalletTasksAttr = PalletTaskAttr; + +/// Parsing for any of the attributes that can be used within a `#[pallet::tasks_experimental]` +/// [`ItemImpl`]. +pub type TaskAttr = PalletTaskAttr; + +/// Parsing for a `#[pallet::task_index]` attr. +pub type TaskIndexAttr = PalletTaskAttr; + +/// Parsing for a `#[pallet::task_condition]` attr. +pub type TaskConditionAttr = PalletTaskAttr; + +/// Parsing for a `#[pallet::task_list]` attr. +pub type TaskListAttr = PalletTaskAttr; + +/// Parsing for a `#[pallet::task_weight]` attr. +pub type TaskWeightAttr = PalletTaskAttr; + +/// Parsing for a `#[pallet:task_enum]` attr. +pub type PalletTaskEnumAttr = PalletTaskAttr; + +/// Parsing for a manually-specified (or auto-generated) task enum, optionally including the +/// attached `#[pallet::task_enum]` attribute. +#[derive(Clone, Debug)] +pub struct TaskEnumDef { + pub attr: Option, + pub item_enum: ItemEnum, + pub scrate: Path, + pub type_use_generics: TokenStream2, +} + +impl syn::parse::Parse for TaskEnumDef { + fn parse(input: ParseStream) -> Result { + let mut item_enum = input.parse::()?; + let attr = extract_pallet_attr(&mut item_enum)?; + let attr = match attr { + Some(attr) => Some(parse2(attr)?), + None => None, + }; + + // We do this here because it would be improper to do something fallible like this at + // the expansion phase. Fallible stuff should happen during parsing. + let scrate = generate_access_from_frame_or_crate("frame-support")?; + + let type_use_generics = quote!(T); + + Ok(TaskEnumDef { attr, item_enum, scrate, type_use_generics }) + } +} + +/// Represents an individual tasks within a [`TasksDef`]. +#[derive(Debug, Clone)] +pub struct TaskDef { + pub index_attr: TaskIndexAttr, + pub condition_attr: TaskConditionAttr, + pub list_attr: TaskListAttr, + pub weight_attr: TaskWeightAttr, + pub normal_attrs: Vec, + pub item: ImplItemFn, + pub arg_names: Vec, +} + +impl syn::parse::Parse for TaskDef { + fn parse(input: ParseStream) -> Result { + let item = input.parse::()?; + // we only want to activate TaskAttrType parsing errors for tasks-related attributes, + // so we filter them here + let (task_attrs, normal_attrs) = partition_task_attrs(&item); + + let task_attrs: Vec = task_attrs + .into_iter() + .map(|attr| parse2(attr.to_token_stream())) + .collect::>()?; + + let Some(index_attr) = task_attrs + .iter() + .find(|attr| matches!(attr.meta, TaskAttrMeta::TaskIndex(_))) + .cloned() + else { + return Err(Error::new( + item.sig.ident.span(), + "missing `#[pallet::task_index(..)]` attribute", + )) + }; + + let Some(condition_attr) = task_attrs + .iter() + .find(|attr| matches!(attr.meta, TaskAttrMeta::TaskCondition(_))) + .cloned() + else { + return Err(Error::new( + item.sig.ident.span(), + "missing `#[pallet::task_condition(..)]` attribute", + )) + }; + + let Some(list_attr) = task_attrs + .iter() + .find(|attr| matches!(attr.meta, TaskAttrMeta::TaskList(_))) + .cloned() + else { + return Err(Error::new( + item.sig.ident.span(), + "missing `#[pallet::task_list(..)]` attribute", + )) + }; + + let Some(weight_attr) = task_attrs + .iter() + .find(|attr| matches!(attr.meta, TaskAttrMeta::TaskWeight(_))) + .cloned() + else { + return Err(Error::new( + item.sig.ident.span(), + "missing `#[pallet::task_weight(..)]` attribute", + )) + }; + + if let Some(duplicate) = task_attrs + .iter() + .filter(|attr| matches!(attr.meta, TaskAttrMeta::TaskCondition(_))) + .collect::>() + .get(1) + { + return Err(Error::new( + duplicate.span(), + "unexpected extra `#[pallet::task_condition(..)]` attribute", + )) + } + + if let Some(duplicate) = task_attrs + .iter() + .filter(|attr| matches!(attr.meta, TaskAttrMeta::TaskList(_))) + .collect::>() + .get(1) + { + return Err(Error::new( + duplicate.span(), + "unexpected extra `#[pallet::task_list(..)]` attribute", + )) + } + + if let Some(duplicate) = task_attrs + .iter() + .filter(|attr| matches!(attr.meta, TaskAttrMeta::TaskIndex(_))) + .collect::>() + .get(1) + { + return Err(Error::new( + duplicate.span(), + "unexpected extra `#[pallet::task_index(..)]` attribute", + )) + } + + let mut arg_names = vec![]; + for input in item.sig.inputs.iter() { + match input { + syn::FnArg::Typed(pat_type) => match &*pat_type.pat { + syn::Pat::Ident(ident) => arg_names.push(ident.ident.clone()), + _ => return Err(Error::new(input.span(), "unexpected pattern type")), + }, + _ => return Err(Error::new(input.span(), "unexpected function argument type")), + } + } + + let index_attr = index_attr.try_into().expect("we check the type above; QED"); + let condition_attr = condition_attr.try_into().expect("we check the type above; QED"); + let list_attr = list_attr.try_into().expect("we check the type above; QED"); + let weight_attr = weight_attr.try_into().expect("we check the type above; QED"); + + Ok(TaskDef { + index_attr, + condition_attr, + list_attr, + weight_attr, + normal_attrs, + item, + arg_names, + }) + } +} + +/// The contents of a [`TasksDef`]-related attribute. +#[derive(Parse, Debug, Clone)] +pub enum TaskAttrMeta { + #[peek(keywords::task_list, name = "#[pallet::task_list(..)]")] + TaskList(TaskListAttrMeta), + #[peek(keywords::task_index, name = "#[pallet::task_index(..)")] + TaskIndex(TaskIndexAttrMeta), + #[peek(keywords::task_condition, name = "#[pallet::task_condition(..)")] + TaskCondition(TaskConditionAttrMeta), + #[peek(keywords::task_weight, name = "#[pallet::task_weight(..)")] + TaskWeight(TaskWeightAttrMeta), +} + +/// The contents of a `#[pallet::task_list]` attribute. +#[derive(Parse, Debug, Clone)] +pub struct TaskListAttrMeta { + pub task_list: keywords::task_list, + #[paren] + _paren: Paren, + #[inside(_paren)] + pub expr: Expr, +} + +/// The contents of a `#[pallet::task_index]` attribute. +#[derive(Parse, Debug, Clone)] +pub struct TaskIndexAttrMeta { + pub task_index: keywords::task_index, + #[paren] + _paren: Paren, + #[inside(_paren)] + pub index: LitInt, +} + +/// The contents of a `#[pallet::task_condition]` attribute. +#[derive(Parse, Debug, Clone)] +pub struct TaskConditionAttrMeta { + pub task_condition: keywords::task_condition, + #[paren] + _paren: Paren, + #[inside(_paren)] + pub expr: Expr, +} + +/// The contents of a `#[pallet::task_weight]` attribute. +#[derive(Parse, Debug, Clone)] +pub struct TaskWeightAttrMeta { + pub task_weight: keywords::task_weight, + #[paren] + _paren: Paren, + #[inside(_paren)] + pub expr: Expr, +} + +/// The contents of a `#[pallet::task]` attribute. +#[derive(Parse, Debug, Clone)] +pub struct PalletTaskAttr { + pub pound: Pound, + #[bracket] + _bracket: Bracket, + #[inside(_bracket)] + pub pallet: keywords::pallet, + #[inside(_bracket)] + pub colons: PathSep, + #[inside(_bracket)] + pub meta: T, +} + +impl ToTokens for TaskListAttrMeta { + fn to_tokens(&self, tokens: &mut TokenStream2) { + let task_list = self.task_list; + let expr = &self.expr; + tokens.extend(quote!(#task_list(#expr))); + } +} + +impl ToTokens for TaskConditionAttrMeta { + fn to_tokens(&self, tokens: &mut TokenStream2) { + let task_condition = self.task_condition; + let expr = &self.expr; + tokens.extend(quote!(#task_condition(#expr))); + } +} + +impl ToTokens for TaskWeightAttrMeta { + fn to_tokens(&self, tokens: &mut TokenStream2) { + let task_weight = self.task_weight; + let expr = &self.expr; + tokens.extend(quote!(#task_weight(#expr))); + } +} + +impl ToTokens for TaskIndexAttrMeta { + fn to_tokens(&self, tokens: &mut TokenStream2) { + let task_index = self.task_index; + let index = &self.index; + tokens.extend(quote!(#task_index(#index))) + } +} + +impl ToTokens for TaskAttrMeta { + fn to_tokens(&self, tokens: &mut TokenStream2) { + match self { + TaskAttrMeta::TaskList(list) => tokens.extend(list.to_token_stream()), + TaskAttrMeta::TaskIndex(index) => tokens.extend(index.to_token_stream()), + TaskAttrMeta::TaskCondition(condition) => tokens.extend(condition.to_token_stream()), + TaskAttrMeta::TaskWeight(weight) => tokens.extend(weight.to_token_stream()), + } + } +} + +impl ToTokens for PalletTaskAttr { + fn to_tokens(&self, tokens: &mut TokenStream2) { + let pound = self.pound; + let pallet = self.pallet; + let colons = self.colons; + let meta = &self.meta; + tokens.extend(quote!(#pound[#pallet #colons #meta])); + } +} + +impl TryFrom> for TaskIndexAttr { + type Error = syn::Error; + + fn try_from(value: PalletTaskAttr) -> Result { + let pound = value.pound; + let pallet = value.pallet; + let colons = value.colons; + match value.meta { + TaskAttrMeta::TaskIndex(meta) => parse2(quote!(#pound[#pallet #colons #meta])), + _ => + return Err(Error::new( + value.span(), + format!("`{:?}` cannot be converted to a `TaskIndexAttr`", value.meta), + )), + } + } +} + +impl TryFrom> for TaskConditionAttr { + type Error = syn::Error; + + fn try_from(value: PalletTaskAttr) -> Result { + let pound = value.pound; + let pallet = value.pallet; + let colons = value.colons; + match value.meta { + TaskAttrMeta::TaskCondition(meta) => parse2(quote!(#pound[#pallet #colons #meta])), + _ => + return Err(Error::new( + value.span(), + format!("`{:?}` cannot be converted to a `TaskConditionAttr`", value.meta), + )), + } + } +} + +impl TryFrom> for TaskWeightAttr { + type Error = syn::Error; + + fn try_from(value: PalletTaskAttr) -> Result { + let pound = value.pound; + let pallet = value.pallet; + let colons = value.colons; + match value.meta { + TaskAttrMeta::TaskWeight(meta) => parse2(quote!(#pound[#pallet #colons #meta])), + _ => + return Err(Error::new( + value.span(), + format!("`{:?}` cannot be converted to a `TaskWeightAttr`", value.meta), + )), + } + } +} + +impl TryFrom> for TaskListAttr { + type Error = syn::Error; + + fn try_from(value: PalletTaskAttr) -> Result { + let pound = value.pound; + let pallet = value.pallet; + let colons = value.colons; + match value.meta { + TaskAttrMeta::TaskList(meta) => parse2(quote!(#pound[#pallet #colons #meta])), + _ => + return Err(Error::new( + value.span(), + format!("`{:?}` cannot be converted to a `TaskListAttr`", value.meta), + )), + } + } +} + +fn extract_pallet_attr(item_enum: &mut ItemEnum) -> Result> { + let mut duplicate = None; + let mut attr = None; + item_enum.attrs = item_enum + .attrs + .iter() + .filter(|found_attr| { + let segs = found_attr + .path() + .segments + .iter() + .map(|seg| seg.ident.clone()) + .collect::>(); + let (Some(seg1), Some(_), None) = (segs.get(0), segs.get(1), segs.get(2)) else { + return true + }; + if seg1 != "pallet" { + return true + } + if attr.is_some() { + duplicate = Some(found_attr.span()); + } + attr = Some(found_attr.to_token_stream()); + false + }) + .cloned() + .collect(); + if let Some(span) = duplicate { + return Err(Error::new(span, "only one `#[pallet::_]` attribute is supported on this item")) + } + Ok(attr) +} + +fn partition_tasks_attrs(item_impl: &ItemImpl) -> (Vec, Vec) { + item_impl.attrs.clone().into_iter().partition(|attr| { + let mut path_segs = attr.path().segments.iter(); + let (Some(prefix), Some(suffix), None) = + (path_segs.next(), path_segs.next(), path_segs.next()) + else { + return false + }; + prefix.ident == "pallet" && suffix.ident == "tasks_experimental" + }) +} + +fn partition_task_attrs(item: &ImplItemFn) -> (Vec, Vec) { + item.attrs.clone().into_iter().partition(|attr| { + let mut path_segs = attr.path().segments.iter(); + let (Some(prefix), Some(suffix)) = (path_segs.next(), path_segs.next()) else { + return false + }; + // N.B: the `PartialEq` impl between `Ident` and `&str` is more efficient than + // parsing and makes no stack or heap allocations + prefix.ident == "pallet" && + (suffix.ident == "tasks_experimental" || + suffix.ident == "task_list" || + suffix.ident == "task_condition" || + suffix.ident == "task_weight" || + suffix.ident == "task_index") + }) +} + +#[test] +fn test_parse_task_list_() { + parse2::(quote!(#[pallet::task_list(Something::iter())])).unwrap(); + parse2::(quote!(#[pallet::task_list(Numbers::::iter_keys())])).unwrap(); + parse2::(quote!(#[pallet::task_list(iter())])).unwrap(); + assert_parse_error_matches!( + parse2::(quote!(#[pallet::task_list()])), + "expected an expression" + ); + assert_parse_error_matches!( + parse2::(quote!(#[pallet::task_list])), + "expected parentheses" + ); +} + +#[test] +fn test_parse_task_index() { + parse2::(quote!(#[pallet::task_index(3)])).unwrap(); + parse2::(quote!(#[pallet::task_index(0)])).unwrap(); + parse2::(quote!(#[pallet::task_index(17)])).unwrap(); + assert_parse_error_matches!( + parse2::(quote!(#[pallet::task_index])), + "expected parentheses" + ); + assert_parse_error_matches!( + parse2::(quote!(#[pallet::task_index("hey")])), + "expected integer literal" + ); + assert_parse_error_matches!( + parse2::(quote!(#[pallet::task_index(0.3)])), + "expected integer literal" + ); +} + +#[test] +fn test_parse_task_condition() { + parse2::(quote!(#[pallet::task_condition(|x| x.is_some())])).unwrap(); + parse2::(quote!(#[pallet::task_condition(|_x| some_expr())])).unwrap(); + parse2::(quote!(#[pallet::task_condition(|| some_expr())])).unwrap(); + parse2::(quote!(#[pallet::task_condition(some_expr())])).unwrap(); +} + +#[test] +fn test_parse_tasks_attr() { + parse2::(quote!(#[pallet::tasks_experimental])).unwrap(); + assert_parse_error_matches!( + parse2::(quote!(#[pallet::taskss])), + "expected `tasks_experimental`" + ); + assert_parse_error_matches!( + parse2::(quote!(#[pallet::tasks_])), + "expected `tasks_experimental`" + ); + assert_parse_error_matches!( + parse2::(quote!(#[pal::tasks])), + "expected `pallet`" + ); + assert_parse_error_matches!( + parse2::(quote!(#[pallet::tasks_experimental()])), + "unexpected token" + ); +} + +#[test] +fn test_parse_tasks_def_basic() { + simulate_manifest_dir("../../examples/basic", || { + let parsed = parse2::(quote! { + #[pallet::tasks_experimental] + impl, I: 'static> Pallet { + /// Add a pair of numbers into the totals and remove them. + #[pallet::task_list(Numbers::::iter_keys())] + #[pallet::task_condition(|i| Numbers::::contains_key(i))] + #[pallet::task_index(0)] + #[pallet::task_weight(0)] + pub fn add_number_into_total(i: u32) -> DispatchResult { + let v = Numbers::::take(i).ok_or(Error::::NotFound)?; + Total::::mutate(|(total_keys, total_values)| { + *total_keys += i; + *total_values += v; + }); + Ok(()) + } + } + }) + .unwrap(); + assert_eq!(parsed.tasks.len(), 1); + }); +} + +#[test] +fn test_parse_tasks_def_basic_increment_decrement() { + simulate_manifest_dir("../../examples/basic", || { + let parsed = parse2::(quote! { + #[pallet::tasks_experimental] + impl, I: 'static> Pallet { + /// Get the value and check if it can be incremented + #[pallet::task_index(0)] + #[pallet::task_condition(|| { + let value = Value::::get().unwrap(); + value < 255 + })] + #[pallet::task_list(Vec::>::new())] + #[pallet::task_weight(0)] + fn increment() -> DispatchResult { + let value = Value::::get().unwrap_or_default(); + if value >= 255 { + Err(Error::::ValueOverflow.into()) + } else { + let new_val = value.checked_add(1).ok_or(Error::::ValueOverflow)?; + Value::::put(new_val); + Pallet::::deposit_event(Event::Incremented { new_val }); + Ok(()) + } + } + + // Get the value and check if it can be decremented + #[pallet::task_index(1)] + #[pallet::task_condition(|| { + let value = Value::::get().unwrap(); + value > 0 + })] + #[pallet::task_list(Vec::>::new())] + #[pallet::task_weight(0)] + fn decrement() -> DispatchResult { + let value = Value::::get().unwrap_or_default(); + if value == 0 { + Err(Error::::ValueUnderflow.into()) + } else { + let new_val = value.checked_sub(1).ok_or(Error::::ValueUnderflow)?; + Value::::put(new_val); + Pallet::::deposit_event(Event::Decremented { new_val }); + Ok(()) + } + } + } + }) + .unwrap(); + assert_eq!(parsed.tasks.len(), 2); + }); +} + +#[test] +fn test_parse_tasks_def_duplicate_index() { + simulate_manifest_dir("../../examples/basic", || { + assert_parse_error_matches!( + parse2::(quote! { + #[pallet::tasks_experimental] + impl, I: 'static> Pallet { + #[pallet::task_list(Something::iter())] + #[pallet::task_condition(|i| i % 2 == 0)] + #[pallet::task_index(0)] + #[pallet::task_weight(0)] + pub fn foo(i: u32) -> DispatchResult { + Ok(()) + } + + #[pallet::task_list(Numbers::::iter_keys())] + #[pallet::task_condition(|i| Numbers::::contains_key(i))] + #[pallet::task_index(0)] + #[pallet::task_weight(0)] + pub fn bar(i: u32) -> DispatchResult { + Ok(()) + } + } + }), + "duplicate task index `0`" + ); + }); +} + +#[test] +fn test_parse_tasks_def_missing_task_list() { + simulate_manifest_dir("../../examples/basic", || { + assert_parse_error_matches!( + parse2::(quote! { + #[pallet::tasks_experimental] + impl, I: 'static> Pallet { + #[pallet::task_condition(|i| i % 2 == 0)] + #[pallet::task_index(0)] + pub fn foo(i: u32) -> DispatchResult { + Ok(()) + } + } + }), + r"missing `#\[pallet::task_list\(\.\.\)\]`" + ); + }); +} + +#[test] +fn test_parse_tasks_def_missing_task_condition() { + simulate_manifest_dir("../../examples/basic", || { + assert_parse_error_matches!( + parse2::(quote! { + #[pallet::tasks_experimental] + impl, I: 'static> Pallet { + #[pallet::task_list(Something::iter())] + #[pallet::task_index(0)] + pub fn foo(i: u32) -> DispatchResult { + Ok(()) + } + } + }), + r"missing `#\[pallet::task_condition\(\.\.\)\]`" + ); + }); +} + +#[test] +fn test_parse_tasks_def_missing_task_index() { + simulate_manifest_dir("../../examples/basic", || { + assert_parse_error_matches!( + parse2::(quote! { + #[pallet::tasks_experimental] + impl, I: 'static> Pallet { + #[pallet::task_condition(|i| i % 2 == 0)] + #[pallet::task_list(Something::iter())] + pub fn foo(i: u32) -> DispatchResult { + Ok(()) + } + } + }), + r"missing `#\[pallet::task_index\(\.\.\)\]`" + ); + }); +} + +#[test] +fn test_parse_tasks_def_missing_task_weight() { + simulate_manifest_dir("../../examples/basic", || { + assert_parse_error_matches!( + parse2::(quote! { + #[pallet::tasks_experimental] + impl, I: 'static> Pallet { + #[pallet::task_condition(|i| i % 2 == 0)] + #[pallet::task_list(Something::iter())] + #[pallet::task_index(0)] + pub fn foo(i: u32) -> DispatchResult { + Ok(()) + } + } + }), + r"missing `#\[pallet::task_weight\(\.\.\)\]`" + ); + }); +} + +#[test] +fn test_parse_tasks_def_unexpected_extra_task_list_attr() { + simulate_manifest_dir("../../examples/basic", || { + assert_parse_error_matches!( + parse2::(quote! { + #[pallet::tasks_experimental] + impl, I: 'static> Pallet { + #[pallet::task_condition(|i| i % 2 == 0)] + #[pallet::task_index(0)] + #[pallet::task_weight(0)] + #[pallet::task_list(Something::iter())] + #[pallet::task_list(SomethingElse::iter())] + pub fn foo(i: u32) -> DispatchResult { + Ok(()) + } + } + }), + r"unexpected extra `#\[pallet::task_list\(\.\.\)\]`" + ); + }); +} + +#[test] +fn test_parse_tasks_def_unexpected_extra_task_condition_attr() { + simulate_manifest_dir("../../examples/basic", || { + assert_parse_error_matches!( + parse2::(quote! { + #[pallet::tasks_experimental] + impl, I: 'static> Pallet { + #[pallet::task_condition(|i| i % 2 == 0)] + #[pallet::task_condition(|i| i % 4 == 0)] + #[pallet::task_index(0)] + #[pallet::task_list(Something::iter())] + #[pallet::task_weight(0)] + pub fn foo(i: u32) -> DispatchResult { + Ok(()) + } + } + }), + r"unexpected extra `#\[pallet::task_condition\(\.\.\)\]`" + ); + }); +} + +#[test] +fn test_parse_tasks_def_unexpected_extra_task_index_attr() { + simulate_manifest_dir("../../examples/basic", || { + assert_parse_error_matches!( + parse2::(quote! { + #[pallet::tasks_experimental] + impl, I: 'static> Pallet { + #[pallet::task_condition(|i| i % 2 == 0)] + #[pallet::task_index(0)] + #[pallet::task_index(0)] + #[pallet::task_list(Something::iter())] + #[pallet::task_weight(0)] + pub fn foo(i: u32) -> DispatchResult { + Ok(()) + } + } + }), + r"unexpected extra `#\[pallet::task_index\(\.\.\)\]`" + ); + }); +} + +#[test] +fn test_parse_tasks_def_extra_tasks_attribute() { + simulate_manifest_dir("../../examples/basic", || { + assert_parse_error_matches!( + parse2::(quote! { + #[pallet::tasks_experimental] + #[pallet::tasks_experimental] + impl, I: 'static> Pallet {} + }), + r"unexpected extra `#\[pallet::tasks_experimental\]` attribute" + ); + }); +} + +#[test] +fn test_parse_task_enum_def_basic() { + simulate_manifest_dir("../../examples/basic", || { + parse2::(quote! { + #[pallet::task_enum] + pub enum Task { + Increment, + Decrement, + } + }) + .unwrap(); + }); +} + +#[test] +fn test_parse_task_enum_def_non_task_name() { + simulate_manifest_dir("../../examples/basic", || { + parse2::(quote! { + #[pallet::task_enum] + pub enum Something { + Foo + } + }) + .unwrap(); + }); +} + +#[test] +fn test_parse_task_enum_def_missing_attr_allowed() { + simulate_manifest_dir("../../examples/basic", || { + parse2::(quote! { + pub enum Task { + Increment, + Decrement, + } + }) + .unwrap(); + }); +} + +#[test] +fn test_parse_task_enum_def_missing_attr_alternate_name_allowed() { + simulate_manifest_dir("../../examples/basic", || { + parse2::(quote! { + pub enum Foo { + Red, + } + }) + .unwrap(); + }); +} + +#[test] +fn test_parse_task_enum_def_wrong_attr() { + simulate_manifest_dir("../../examples/basic", || { + assert_parse_error_matches!( + parse2::(quote! { + #[pallet::something] + pub enum Task { + Increment, + Decrement, + } + }), + "expected `task_enum`" + ); + }); +} + +#[test] +fn test_parse_task_enum_def_wrong_item() { + simulate_manifest_dir("../../examples/basic", || { + assert_parse_error_matches!( + parse2::(quote! { + #[pallet::task_enum] + pub struct Something; + }), + "expected `enum`" + ); + }); +} diff --git a/substrate/frame/support/procedural/src/pallet/parse/tests/mod.rs b/substrate/frame/support/procedural/src/pallet/parse/tests/mod.rs new file mode 100644 index 00000000000..a3661f3076d --- /dev/null +++ b/substrate/frame/support/procedural/src/pallet/parse/tests/mod.rs @@ -0,0 +1,264 @@ +// This file is part of Substrate. + +// Copyright (C) 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 std::{panic, sync::Mutex}; +use syn::parse_quote; + +#[doc(hidden)] +pub mod __private { + pub use regex; +} + +/// Allows you to assert that the input expression resolves to an error whose string +/// representation matches the specified regex literal. +/// +/// ## Example: +/// +/// ``` +/// use super::tasks::*; +/// +/// assert_parse_error_matches!( +/// parse2::(quote! { +/// #[pallet::task_enum] +/// pub struct Something; +/// }), +/// "expected `enum`" +/// ); +/// ``` +/// +/// More complex regular expressions are also possible (anything that could pass as a regex for +/// use with the [`regex`] crate.): +/// +/// ```ignore +/// assert_parse_error_matches!( +/// parse2::(quote! { +/// #[pallet::tasks_experimental] +/// impl, I: 'static> Pallet { +/// #[pallet::task_condition(|i| i % 2 == 0)] +/// #[pallet::task_index(0)] +/// pub fn foo(i: u32) -> DispatchResult { +/// Ok(()) +/// } +/// } +/// }), +/// r"missing `#\[pallet::task_list\(\.\.\)\]`" +/// ); +/// ``` +/// +/// Although this is primarily intended to be used with parsing errors, this macro is general +/// enough that it will work with any error with a reasonable [`core::fmt::Display`] impl. +#[macro_export] +macro_rules! assert_parse_error_matches { + ($expr:expr, $reg:literal) => { + match $expr { + Ok(_) => panic!("Expected an `Error(..)`, but got Ok(..)"), + Err(e) => { + let error_message = e.to_string(); + let re = $crate::pallet::parse::tests::__private::regex::Regex::new($reg) + .expect("Invalid regex pattern"); + assert!( + re.is_match(&error_message), + "Error message \"{}\" does not match the pattern \"{}\"", + error_message, + $reg + ); + }, + } + }; +} + +/// Allows you to assert that an entire pallet parses successfully. A custom syntax is used for +/// specifying arguments so please pay attention to the docs below. +/// +/// The general syntax is: +/// +/// ```ignore +/// assert_pallet_parses! { +/// #[manifest_dir("../../examples/basic")] +/// #[frame_support::pallet] +/// pub mod pallet { +/// #[pallet::config] +/// pub trait Config: frame_system::Config {} +/// +/// #[pallet::pallet] +/// pub struct Pallet(_); +/// } +/// }; +/// ``` +/// +/// The `#[manifest_dir(..)]` attribute _must_ be specified as the _first_ attribute on the +/// pallet module, and should reference the relative (to your current directory) path of a +/// directory containing containing the `Cargo.toml` of a valid pallet. Typically you will only +/// ever need to use the `examples/basic` pallet, but sometimes it might be advantageous to +/// specify a different one that has additional dependencies. +/// +/// The reason this must be specified is that our underlying parsing of pallets depends on +/// reaching out into the file system to look for particular `Cargo.toml` dependencies via the +/// [`generate_access_from_frame_or_crate`] method, so to simulate this properly in a proc +/// macro crate, we need to temporarily convince this function that we are running from the +/// directory of a valid pallet. +#[macro_export] +macro_rules! assert_pallet_parses { + ( + #[manifest_dir($manifest_dir:literal)] + $($tokens:tt)* + ) => { + { + let mut pallet: Option<$crate::pallet::parse::Def> = None; + $crate::pallet::parse::tests::simulate_manifest_dir($manifest_dir, core::panic::AssertUnwindSafe(|| { + pallet = Some($crate::pallet::parse::Def::try_from(syn::parse_quote! { + $($tokens)* + }, false).unwrap()); + })); + pallet.unwrap() + } + } +} + +/// Similar to [`assert_pallet_parses`], except this instead expects the pallet not to parse, +/// and allows you to specify a regex matching the expected parse error. +/// +/// This is identical syntactically to [`assert_pallet_parses`] in every way except there is a +/// second attribute that must be specified immediately after `#[manifest_dir(..)]` which is +/// `#[error_regex(..)]` which should contain a string/regex literal designed to match what you +/// consider to be the correct parsing error we should see when we try to parse this particular +/// pallet. +/// +/// ## Example: +/// +/// ``` +/// assert_pallet_parse_error! { +/// #[manifest_dir("../../examples/basic")] +/// #[error_regex("Missing `\\#\\[pallet::pallet\\]`")] +/// #[frame_support::pallet] +/// pub mod pallet { +/// #[pallet::config] +/// pub trait Config: frame_system::Config {} +/// } +/// } +/// ``` +#[macro_export] +macro_rules! assert_pallet_parse_error { + ( + #[manifest_dir($manifest_dir:literal)] + #[error_regex($reg:literal)] + $($tokens:tt)* + ) => { + $crate::pallet::parse::tests::simulate_manifest_dir($manifest_dir, || { + $crate::assert_parse_error_matches!( + $crate::pallet::parse::Def::try_from( + parse_quote! { + $($tokens)* + }, + false + ), + $reg + ); + }); + } +} + +/// Safely runs the specified `closure` while simulating an alternative `CARGO_MANIFEST_DIR`, +/// restoring `CARGO_MANIFEST_DIR` to its original value upon completion regardless of whether +/// the closure panics. +/// +/// This is useful in tests of `Def::try_from` and other pallet-related methods that internally +/// make use of [`generate_access_from_frame_or_crate`], which is sensitive to entries in the +/// "current" `Cargo.toml` files. +/// +/// This function uses a [`Mutex`] to avoid a race condition created when multiple tests try to +/// modify and then restore the `CARGO_MANIFEST_DIR` ENV var in an overlapping way. +pub fn simulate_manifest_dir, F: FnOnce() + std::panic::UnwindSafe>( + path: P, + closure: F, +) { + use std::{env::*, path::*}; + + /// Ensures that only one thread can modify/restore the `CARGO_MANIFEST_DIR` ENV var at a time, + /// avoiding a race condition because `cargo test` runs tests in parallel. + /// + /// Although this forces all tests that use [`simulate_manifest_dir`] to run sequentially with + /// respect to each other, this is still several orders of magnitude faster than using UI + /// tests, even if they are run in parallel. + static MANIFEST_DIR_LOCK: Mutex<()> = Mutex::new(()); + + // avoid race condition when swapping out `CARGO_MANIFEST_DIR` + let guard = MANIFEST_DIR_LOCK.lock().unwrap(); + + // obtain the current/original `CARGO_MANIFEST_DIR` + let orig = PathBuf::from( + var("CARGO_MANIFEST_DIR").expect("failed to read ENV var `CARGO_MANIFEST_DIR`"), + ); + + // set `CARGO_MANIFEST_DIR` to the provided path, relative to current working dir + set_var("CARGO_MANIFEST_DIR", orig.join(path.as_ref())); + + // safely run closure catching any panics + let result = panic::catch_unwind(closure); + + // restore original `CARGO_MANIFEST_DIR` before unwinding + set_var("CARGO_MANIFEST_DIR", &orig); + + // unlock the mutex so we don't poison it if there is a panic + drop(guard); + + // unwind any panics originally encountered when running closure + result.unwrap(); +} + +mod tasks; + +#[test] +fn test_parse_minimal_pallet() { + assert_pallet_parses! { + #[manifest_dir("../../examples/basic")] + #[frame_support::pallet] + pub mod pallet { + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + } + }; +} + +#[test] +fn test_parse_pallet_missing_pallet() { + assert_pallet_parse_error! { + #[manifest_dir("../../examples/basic")] + #[error_regex("Missing `\\#\\[pallet::pallet\\]`")] + #[frame_support::pallet] + pub mod pallet { + #[pallet::config] + pub trait Config: frame_system::Config {} + } + } +} + +#[test] +fn test_parse_pallet_missing_config() { + assert_pallet_parse_error! { + #[manifest_dir("../../examples/basic")] + #[error_regex("Missing `\\#\\[pallet::config\\]`")] + #[frame_support::pallet] + pub mod pallet { + #[pallet::pallet] + pub struct Pallet(_); + } + } +} diff --git a/substrate/frame/support/procedural/src/pallet/parse/tests/tasks.rs b/substrate/frame/support/procedural/src/pallet/parse/tests/tasks.rs new file mode 100644 index 00000000000..9f143628404 --- /dev/null +++ b/substrate/frame/support/procedural/src/pallet/parse/tests/tasks.rs @@ -0,0 +1,240 @@ +// This file is part of Substrate. + +// Copyright (C) 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 syn::parse_quote; + +#[test] +fn test_parse_pallet_with_task_enum_missing_impl() { + assert_pallet_parse_error! { + #[manifest_dir("../../examples/basic")] + #[error_regex("Missing `\\#\\[pallet::tasks_experimental\\]` impl")] + #[frame_support::pallet] + pub mod pallet { + #[pallet::task_enum] + pub enum Task { + Something, + } + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + } + } +} + +#[test] +fn test_parse_pallet_with_task_enum_wrong_attribute() { + assert_pallet_parse_error! { + #[manifest_dir("../../examples/basic")] + #[error_regex("expected one of")] + #[frame_support::pallet] + pub mod pallet { + #[pallet::wrong_attribute] + pub enum Task { + Something, + } + + #[pallet::task_list] + impl frame_support::traits::Task for Task + where + T: TypeInfo, + {} + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + } + } +} + +#[test] +fn test_parse_pallet_missing_task_enum() { + assert_pallet_parses! { + #[manifest_dir("../../examples/basic")] + #[frame_support::pallet] + pub mod pallet { + #[pallet::tasks_experimental] + #[cfg(test)] // aha, this means it's being eaten + impl frame_support::traits::Task for Task + where + T: TypeInfo, + {} + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + } + }; +} + +#[test] +fn test_parse_pallet_task_list_in_wrong_place() { + assert_pallet_parse_error! { + #[manifest_dir("../../examples/basic")] + #[error_regex("can only be used on items within an `impl` statement.")] + #[frame_support::pallet] + pub mod pallet { + pub enum MyCustomTaskEnum { + Something, + } + + #[pallet::task_list] + pub fn something() { + println!("hey"); + } + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + } + } +} + +#[test] +fn test_parse_pallet_manual_tasks_impl_without_manual_tasks_enum() { + assert_pallet_parse_error! { + #[manifest_dir("../../examples/basic")] + #[error_regex(".*attribute must be attached to your.*")] + #[frame_support::pallet] + pub mod pallet { + + impl frame_support::traits::Task for Task + where + T: TypeInfo, + { + type Enumeration = sp_std::vec::IntoIter>; + + fn iter() -> Self::Enumeration { + sp_std::vec![Task::increment, Task::decrement].into_iter() + } + } + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + } + } +} + +#[test] +fn test_parse_pallet_manual_task_enum_non_manual_impl() { + assert_pallet_parses! { + #[manifest_dir("../../examples/basic")] + #[frame_support::pallet] + pub mod pallet { + pub enum MyCustomTaskEnum { + Something, + } + + #[pallet::tasks_experimental] + impl frame_support::traits::Task for MyCustomTaskEnum + where + T: TypeInfo, + {} + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + } + }; +} + +#[test] +fn test_parse_pallet_non_manual_task_enum_manual_impl() { + assert_pallet_parses! { + #[manifest_dir("../../examples/basic")] + #[frame_support::pallet] + pub mod pallet { + #[pallet::task_enum] + pub enum MyCustomTaskEnum { + Something, + } + + impl frame_support::traits::Task for MyCustomTaskEnum + where + T: TypeInfo, + {} + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + } + }; +} + +#[test] +fn test_parse_pallet_manual_task_enum_manual_impl() { + assert_pallet_parses! { + #[manifest_dir("../../examples/basic")] + #[frame_support::pallet] + pub mod pallet { + pub enum MyCustomTaskEnum { + Something, + } + + impl frame_support::traits::Task for MyCustomTaskEnum + where + T: TypeInfo, + {} + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + } + }; +} + +#[test] +fn test_parse_pallet_manual_task_enum_mismatch_ident() { + assert_pallet_parses! { + #[manifest_dir("../../examples/basic")] + #[frame_support::pallet] + pub mod pallet { + pub enum WrongIdent { + Something, + } + + #[pallet::tasks_experimental] + impl frame_support::traits::Task for MyCustomTaskEnum + where + T: TypeInfo, + {} + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + } + }; +} diff --git a/substrate/frame/support/src/dispatch.rs b/substrate/frame/support/src/dispatch.rs index c81dba12766..449b6f23165 100644 --- a/substrate/frame/support/src/dispatch.rs +++ b/substrate/frame/support/src/dispatch.rs @@ -695,6 +695,7 @@ mod weight_tests { type BaseCallFilter: crate::traits::Contains; type RuntimeOrigin; type RuntimeCall; + type RuntimeTask; type PalletInfo: crate::traits::PalletInfo; type DbWeight: Get; } @@ -791,6 +792,7 @@ mod weight_tests { type BaseCallFilter = crate::traits::Everything; type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; + type RuntimeTask = RuntimeTask; type DbWeight = DbWeight; type PalletInfo = PalletInfo; } diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index fd348f62b4f..af1f99be103 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -849,7 +849,7 @@ pub mod pallet_prelude { }, traits::{ BuildGenesisConfig, ConstU32, EnsureOrigin, Get, GetDefault, GetStorageVersion, Hooks, - IsType, PalletInfoAccess, StorageInfoTrait, StorageVersion, TypedGet, + IsType, PalletInfoAccess, StorageInfoTrait, StorageVersion, Task, TypedGet, }, Blake2_128, Blake2_128Concat, Blake2_256, CloneNoBound, DebugNoBound, EqNoBound, Identity, PartialEqNoBound, RuntimeDebugNoBound, Twox128, Twox256, Twox64Concat, @@ -2674,6 +2674,61 @@ pub mod pallet_macros { /// } /// ``` pub use frame_support_procedural::storage; + /// This attribute is attached to a function inside an `impl` block annoated with + /// [`pallet::tasks_experimental`](`tasks_experimental`) to define the conditions for a + /// given work item to be valid. + /// + /// It takes a closure as input, which is then used to define the condition. The closure + /// should have the same signature as the function it is attached to, except that it should + /// return a `bool` instead. + pub use frame_support_procedural::task_condition; + /// This attribute is attached to a function inside an `impl` block annoated with + /// [`pallet::tasks_experimental`](`tasks_experimental`) to define the index of a given + /// work item. + /// + /// It takes an integer literal as input, which is then used to define the index. This + /// index should be unique for each function in the `impl` block. + pub use frame_support_procedural::task_index; + /// This attribute is attached to a function inside an `impl` block annoated with + /// [`pallet::tasks_experimental`](`tasks_experimental`) to define an iterator over the + /// available work items for a task. + /// + /// It takes an iterator as input that yields a tuple with same types as the function + /// arguments. + pub use frame_support_procedural::task_list; + /// This attribute is attached to a function inside an `impl` block annoated with + /// [`pallet::tasks_experimental`](`tasks_experimental`) define the weight of a given work + /// item. + /// + /// It takes a closure as input, which should return a `Weight` value. + pub use frame_support_procedural::task_weight; + /// Allows you to define some service work that can be recognized by a script or an + /// off-chain worker. Such a script can then create and submit all such work items at any + /// given time. + /// + /// These work items are defined as instances of the [`Task`](frame_support::traits::Task) + /// trait. [`pallet:tasks_experimental`](`tasks_experimental`) when attached to an `impl` + /// block inside a pallet, will generate an enum `Task` whose variants are mapped to + /// functions inside this `impl` block. + /// + /// Each such function must have the following set of attributes: + /// + /// * [`pallet::task_list`](`task_list`) + /// * [`pallet::task_condition`](`task_condition`) + /// * [`pallet::task_weight`](`task_weight`) + /// * [`pallet::task_index`](`task_index`) + /// + /// All of such Tasks are then aggregated into a `RuntimeTask` by + /// [`construct_runtime`](frame_support::construct_runtime). + /// + /// Finally, the `RuntimeTask` can then used by a script or off-chain worker to create and + /// submit such tasks via an extrinsic defined in `frame_system` called `do_task`. + /// + /// ## Example + #[doc = docify::embed!("src/tests/tasks.rs", tasks_example)] + /// Now, this can be executed as follows: + #[doc = docify::embed!("src/tests/tasks.rs", tasks_work)] + pub use frame_support_procedural::tasks_experimental; } #[deprecated(note = "Will be removed after July 2023; Use `sp_runtime::traits` directly instead.")] diff --git a/substrate/frame/support/src/storage/generator/mod.rs b/substrate/frame/support/src/storage/generator/mod.rs index 2b2abdc2e83..dd6d622852d 100644 --- a/substrate/frame/support/src/storage/generator/mod.rs +++ b/substrate/frame/support/src/storage/generator/mod.rs @@ -63,6 +63,7 @@ mod tests { type BaseCallFilter: crate::traits::Contains; type RuntimeOrigin; type RuntimeCall; + type RuntimeTask; type PalletInfo: crate::traits::PalletInfo; type DbWeight: Get; } @@ -129,6 +130,7 @@ mod tests { type BaseCallFilter = crate::traits::Everything; type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; + type RuntimeTask = RuntimeTask; type PalletInfo = PalletInfo; type DbWeight = (); } diff --git a/substrate/frame/support/src/tests/mod.rs b/substrate/frame/support/src/tests/mod.rs index 3690159c599..c6a0b6cde77 100644 --- a/substrate/frame/support/src/tests/mod.rs +++ b/substrate/frame/support/src/tests/mod.rs @@ -16,6 +16,7 @@ // limitations under the License. use super::*; +use frame_support_procedural::import_section; use sp_io::{MultiRemovalResults, TestExternalities}; use sp_metadata_ir::{ PalletStorageMetadataIR, StorageEntryMetadataIR, StorageEntryModifierIR, StorageEntryTypeIR, @@ -27,13 +28,15 @@ pub use self::frame_system::{pallet_prelude::*, Config, Pallet}; mod inject_runtime_type; mod storage_alias; +mod tasks; +#[import_section(tasks::tasks_example)] #[pallet] pub mod frame_system { #[allow(unused)] use super::{frame_system, frame_system::pallet_prelude::*}; pub use crate::dispatch::RawOrigin; - use crate::pallet_prelude::*; + use crate::{pallet_prelude::*, traits::tasks::Task as TaskTrait}; pub mod config_preludes { use super::{inject_runtime_type, DefaultConfig}; @@ -49,6 +52,8 @@ pub mod frame_system { type RuntimeCall = (); #[inject_runtime_type] type PalletInfo = (); + #[inject_runtime_type] + type RuntimeTask = (); type DbWeight = (); } } @@ -69,6 +74,8 @@ pub mod frame_system { #[pallet::no_default_bounds] type RuntimeCall; #[pallet::no_default_bounds] + type RuntimeTask: crate::traits::tasks::Task; + #[pallet::no_default_bounds] type PalletInfo: crate::traits::PalletInfo; type DbWeight: Get; } @@ -77,13 +84,33 @@ pub mod frame_system { pub enum Error { /// Required by construct_runtime CallFiltered, + /// Used in tasks example. + NotFound, + /// The specified [`Task`] is not valid. + InvalidTask, + /// The specified [`Task`] failed during execution. + FailedTask, } #[pallet::origin] pub type Origin = RawOrigin<::AccountId>; #[pallet::call] - impl Pallet {} + impl Pallet { + #[pallet::call_index(0)] + #[pallet::weight(task.weight())] + pub fn do_task(_origin: OriginFor, task: T::RuntimeTask) -> DispatchResultWithPostInfo { + if !task.is_valid() { + return Err(Error::::InvalidTask.into()) + } + + if let Err(_err) = task.run() { + return Err(Error::::FailedTask.into()) + } + + Ok(().into()) + } + } #[pallet::storage] pub type Data = StorageMap<_, Twox64Concat, u32, u64, ValueQuery>; @@ -169,6 +196,14 @@ pub mod frame_system { } } + /// Some running total. + #[pallet::storage] + pub type Total = StorageValue<_, (u32, u32), ValueQuery>; + + /// Numbers to be added into the total. + #[pallet::storage] + pub type Numbers = StorageMap<_, Twox64Concat, u32, u32, OptionQuery>; + pub mod pallet_prelude { pub type OriginFor = ::RuntimeOrigin; @@ -622,6 +657,24 @@ fn expected_metadata() -> PalletStorageMetadataIR { default: vec![0], docs: vec![], }, + StorageEntryMetadataIR { + name: "Total", + modifier: StorageEntryModifierIR::Default, + ty: StorageEntryTypeIR::Plain(scale_info::meta_type::<(u32, u32)>()), + default: vec![0, 0, 0, 0, 0, 0, 0, 0], + docs: vec![" Some running total."], + }, + StorageEntryMetadataIR { + name: "Numbers", + modifier: StorageEntryModifierIR::Optional, + ty: StorageEntryTypeIR::Map { + hashers: vec![StorageHasherIR::Twox64Concat], + key: scale_info::meta_type::(), + value: scale_info::meta_type::(), + }, + default: vec![0], + docs: vec![" Numbers to be added into the total."], + }, ], } } diff --git a/substrate/frame/support/src/tests/tasks.rs b/substrate/frame/support/src/tests/tasks.rs new file mode 100644 index 00000000000..2774c130075 --- /dev/null +++ b/substrate/frame/support/src/tests/tasks.rs @@ -0,0 +1,62 @@ +// This file is part of Substrate. + +// Copyright (C) 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::{ + assert_ok, + tests::{ + frame_system::{Numbers, Total}, + new_test_ext, Runtime, RuntimeOrigin, RuntimeTask, System, + }, +}; +use frame_support_procedural::pallet_section; + +#[pallet_section] +mod tasks_example { + #[docify::export(tasks_example)] + #[pallet::tasks_experimental] + impl Pallet { + /// Add a pair of numbers into the totals and remove them. + #[pallet::task_list(Numbers::::iter_keys())] + #[pallet::task_condition(|i| Numbers::::contains_key(i))] + #[pallet::task_weight(0.into())] + #[pallet::task_index(0)] + pub fn add_number_into_total(i: u32) -> DispatchResult { + let v = Numbers::::take(i).ok_or(Error::::NotFound)?; + Total::::mutate(|(total_keys, total_values)| { + *total_keys += i; + *total_values += v; + }); + Ok(()) + } + } +} + +#[docify::export] +#[test] +fn tasks_work() { + new_test_ext().execute_with(|| { + Numbers::::insert(0, 1); + + let task = RuntimeTask::System(super::frame_system::Task::::AddNumberIntoTotal { + i: 0u32, + }); + + assert_ok!(System::do_task(RuntimeOrigin::signed(1), task.clone(),)); + assert_eq!(Numbers::::get(0), None); + assert_eq!(Total::::get(), (0, 1)); + }); +} diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs index 6362e750d2a..9afd9c16130 100644 --- a/substrate/frame/support/src/traits.rs +++ b/substrate/frame/support/src/traits.rs @@ -123,6 +123,9 @@ pub use safe_mode::{SafeMode, SafeModeError, SafeModeNotify}; mod tx_pause; pub use tx_pause::{TransactionPause, TransactionPauseError}; +pub mod tasks; +pub use tasks::Task; + #[cfg(feature = "try-runtime")] mod try_runtime; #[cfg(feature = "try-runtime")] diff --git a/substrate/frame/support/src/traits/tasks.rs b/substrate/frame/support/src/traits/tasks.rs new file mode 100644 index 00000000000..24f3430cf50 --- /dev/null +++ b/substrate/frame/support/src/traits/tasks.rs @@ -0,0 +1,87 @@ +// This file is part of Substrate. + +// Copyright (C) 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. + +//! Contains the [`Task`] trait, which defines a general-purpose way for defining and executing +//! service work, and supporting types. + +use codec::FullCodec; +use scale_info::TypeInfo; +use sp_runtime::DispatchError; +use sp_std::{fmt::Debug, iter::Iterator, vec, vec::IntoIter}; +use sp_weights::Weight; + +/// Contain's re-exports of all the supporting types for the [`Task`] trait. Used in the macro +/// expansion of `RuntimeTask`. +#[doc(hidden)] +pub mod __private { + pub use codec::FullCodec; + pub use scale_info::TypeInfo; + pub use sp_runtime::DispatchError; + pub use sp_std::{fmt::Debug, iter::Iterator, vec, vec::IntoIter}; + pub use sp_weights::Weight; +} + +/// A general-purpose trait which defines a type of service work (i.e., work to performed by an +/// off-chain worker) including methods for enumerating, validating, indexing, and running +/// tasks of this type. +pub trait Task: Sized + FullCodec + TypeInfo + Clone + Debug + PartialEq + Eq { + /// An [`Iterator`] over tasks of this type used as the return type for `enumerate`. + type Enumeration: Iterator; + + /// Inspects the pallet's state and enumerates tasks of this type. + fn iter() -> Self::Enumeration; + + /// Checks if a particular instance of this `Task` variant is a valid piece of work. + fn is_valid(&self) -> bool; + + /// Performs the work for this particular `Task` variant. + fn run(&self) -> Result<(), DispatchError>; + + /// Returns the weight of executing this `Task`. + fn weight(&self) -> Weight; + + /// A unique value representing this `Task` within the current pallet. Analogous to + /// `call_index`, but for tasks.' + /// + /// This value should be unique within the current pallet and can overlap with task indices + /// in other pallets. + fn task_index(&self) -> u32; +} + +impl Task for () { + type Enumeration = IntoIter; + + fn iter() -> Self::Enumeration { + vec![].into_iter() + } + + fn is_valid(&self) -> bool { + true + } + + fn run(&self) -> Result<(), DispatchError> { + Ok(()) + } + + fn weight(&self) -> Weight { + Weight::default() + } + + fn task_index(&self) -> u32 { + 0 + } +} diff --git a/substrate/frame/support/test/compile_pass/src/lib.rs b/substrate/frame/support/test/compile_pass/src/lib.rs index 6ea37fb27e7..b304dfcb282 100644 --- a/substrate/frame/support/test/compile_pass/src/lib.rs +++ b/substrate/frame/support/test/compile_pass/src/lib.rs @@ -22,7 +22,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use renamed_frame_support::{ - construct_runtime, parameter_types, + construct_runtime, derive_impl, parameter_types, traits::{ConstU16, ConstU32, ConstU64, Everything}, }; use sp_core::{sr25519, H256}; @@ -51,6 +51,7 @@ parameter_types! { pub const Version: RuntimeVersion = VERSION; } +#[derive_impl(renamed_frame_system::config_preludes::TestDefaultConfig as renamed_frame_system::DefaultConfig)] impl renamed_frame_system::Config for Runtime { type BaseCallFilter = Everything; type BlockWeights = (); diff --git a/substrate/frame/support/test/src/lib.rs b/substrate/frame/support/test/src/lib.rs index 6b38d42d33d..a8a72337503 100644 --- a/substrate/frame/support/test/src/lib.rs +++ b/substrate/frame/support/test/src/lib.rs @@ -50,6 +50,8 @@ pub mod pallet { + From>; /// The runtime call type. type RuntimeCall; + /// Contains an aggregation of all tasks in this runtime. + type RuntimeTask; /// The runtime event type. type RuntimeEvent: Parameter + Member diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/generics_in_invalid_module.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/generics_in_invalid_module.stderr index bf53f43b9ba..8458de97f6d 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/generics_in_invalid_module.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/generics_in_invalid_module.stderr @@ -1,4 +1,4 @@ -error: `Call` is not allowed to have generics. Only the following pallets are allowed to have generics: `Event`, `Error`, `Origin`, `Config`. +error: `Call` is not allowed to have generics. Only the following pallets are allowed to have generics: `Event`, `Error`, `Origin`, `Config`, `Task`. --> tests/construct_runtime_ui/generics_in_invalid_module.rs:24:36 | 24 | Balance: balances::::{Call, Origin}, diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_details_keyword.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_details_keyword.stderr index ad631de204e..feb61793151 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_details_keyword.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_details_keyword.stderr @@ -1,4 +1,4 @@ -error: expected one of: `Pallet`, `Call`, `Storage`, `Event`, `Error`, `Config`, `Origin`, `Inherent`, `ValidateUnsigned`, `FreezeReason`, `HoldReason`, `LockId`, `SlashReason` +error: expected one of: `Pallet`, `Call`, `Storage`, `Event`, `Error`, `Config`, `Origin`, `Inherent`, `ValidateUnsigned`, `FreezeReason`, `HoldReason`, `Task`, `LockId`, `SlashReason` --> tests/construct_runtime_ui/invalid_module_details_keyword.rs:23:20 | 23 | system: System::{enum}, diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_entry.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_entry.stderr index b5b89a5a270..97943dfc176 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_entry.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/invalid_module_entry.stderr @@ -1,4 +1,4 @@ -error: expected one of: `Pallet`, `Call`, `Storage`, `Event`, `Error`, `Config`, `Origin`, `Inherent`, `ValidateUnsigned`, `FreezeReason`, `HoldReason`, `LockId`, `SlashReason` +error: expected one of: `Pallet`, `Call`, `Storage`, `Event`, `Error`, `Config`, `Origin`, `Inherent`, `ValidateUnsigned`, `FreezeReason`, `HoldReason`, `Task`, `LockId`, `SlashReason` --> tests/construct_runtime_ui/invalid_module_entry.rs:24:23 | 24 | Balance: balances::{Unexpected}, diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.stderr index a8c1daf88da..6838b7f4c0a 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.stderr @@ -76,3 +76,11 @@ help: consider importing one of these items | 18 + use frame_support::traits::PalletInfo; | + +error[E0412]: cannot find type `RuntimeTask` in this scope + --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:39:1 + | +39 | #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you might have meant to use the associated type: `Self::RuntimeTask` + | + = note: this error originates in the macro `frame_system::config_preludes::TestDefaultConfig` which comes from the expansion of the macro `frame_support::macro_magic::forward_tokens_verbatim` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/substrate/frame/support/test/tests/derive_impl_ui/inject_runtime_type_invalid.stderr b/substrate/frame/support/test/tests/derive_impl_ui/inject_runtime_type_invalid.stderr index 501aad0419f..cda20288984 100644 --- a/substrate/frame/support/test/tests/derive_impl_ui/inject_runtime_type_invalid.stderr +++ b/substrate/frame/support/test/tests/derive_impl_ui/inject_runtime_type_invalid.stderr @@ -1,4 +1,4 @@ -error: `#[inject_runtime_type]` can only be attached to `RuntimeCall`, `RuntimeEvent`, `RuntimeOrigin` or `PalletInfo` +error: `#[inject_runtime_type]` can only be attached to `RuntimeCall`, `RuntimeEvent`, `RuntimeTask`, `RuntimeOrigin` or `PalletInfo` --> tests/derive_impl_ui/inject_runtime_type_invalid.rs:32:5 | 32 | type RuntimeInfo = (); diff --git a/substrate/frame/support/test/tests/pallet_outer_enums_explicit.rs b/substrate/frame/support/test/tests/pallet_outer_enums_explicit.rs index a8250f8b153..6246ad93d67 100644 --- a/substrate/frame/support/test/tests/pallet_outer_enums_explicit.rs +++ b/substrate/frame/support/test/tests/pallet_outer_enums_explicit.rs @@ -90,6 +90,8 @@ fn module_error_outer_enum_expand_explicit() { frame_system::Error::NonDefaultComposite => (), frame_system::Error::NonZeroRefCount => (), frame_system::Error::CallFiltered => (), + frame_system::Error::InvalidTask => (), + frame_system::Error::FailedTask => (), frame_system::Error::__Ignore(_, _) => (), }, diff --git a/substrate/frame/support/test/tests/pallet_outer_enums_implicit.rs b/substrate/frame/support/test/tests/pallet_outer_enums_implicit.rs index 191f095f5d7..26023dfa7b7 100644 --- a/substrate/frame/support/test/tests/pallet_outer_enums_implicit.rs +++ b/substrate/frame/support/test/tests/pallet_outer_enums_implicit.rs @@ -90,6 +90,8 @@ fn module_error_outer_enum_expand_implicit() { frame_system::Error::NonDefaultComposite => (), frame_system::Error::NonZeroRefCount => (), frame_system::Error::CallFiltered => (), + frame_system::Error::InvalidTask => (), + frame_system::Error::FailedTask => (), frame_system::Error::__Ignore(_, _) => (), }, diff --git a/substrate/frame/support/test/tests/pallet_ui/composite_enum_unsupported_identifier.stderr b/substrate/frame/support/test/tests/pallet_ui/composite_enum_unsupported_identifier.stderr index cdc8f623142..8de9c8990b0 100644 --- a/substrate/frame/support/test/tests/pallet_ui/composite_enum_unsupported_identifier.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/composite_enum_unsupported_identifier.stderr @@ -1,4 +1,4 @@ -error: expected one of: `FreezeReason`, `HoldReason`, `LockId`, `SlashReason` +error: expected one of: `FreezeReason`, `HoldReason`, `LockId`, `SlashReason`, `Task` --> tests/pallet_ui/composite_enum_unsupported_identifier.rs:27:11 | 27 | pub enum HoldReasons {} diff --git a/substrate/frame/support/test/tests/pallet_ui/pass/task_valid.rs b/substrate/frame/support/test/tests/pallet_ui/pass/task_valid.rs new file mode 100644 index 00000000000..234e220f49d --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/pass/task_valid.rs @@ -0,0 +1,43 @@ +// This file is part of Substrate. + +// Copyright (C) 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. + +#[frame_support::pallet(dev_mode)] +mod pallet { + use frame_support::{ensure, pallet_prelude::DispatchResult}; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::tasks_experimental] + impl Pallet { + #[pallet::task_index(0)] + #[pallet::task_condition(|i, j| i == 0u32 && j == 2u64)] + #[pallet::task_list(vec![(0u32, 2u64), (2u32, 4u64)].iter())] + #[pallet::task_weight(0.into())] + fn foo(i: u32, j: u64) -> DispatchResult { + ensure!(i == 0, "i must be 0"); + ensure!(j == 2, "j must be 2"); + Ok(()) + } + } +} + +fn main() { +} diff --git a/substrate/frame/support/test/tests/pallet_ui/task_can_only_be_attached_to_impl.rs b/substrate/frame/support/test/tests/pallet_ui/task_can_only_be_attached_to_impl.rs new file mode 100644 index 00000000000..95f5655af19 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/task_can_only_be_attached_to_impl.rs @@ -0,0 +1,34 @@ +// This file is part of Substrate. + +// Copyright (C) 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. + +#[frame_support::pallet(dev_mode)] +mod pallet { + use frame_support::pallet_prelude::DispatchResult; + use frame_system::pallet_prelude::OriginFor; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::tasks_experimental] + pub struct Task; +} + +fn main() { +} diff --git a/substrate/frame/support/test/tests/pallet_ui/task_can_only_be_attached_to_impl.stderr b/substrate/frame/support/test/tests/pallet_ui/task_can_only_be_attached_to_impl.stderr new file mode 100644 index 00000000000..eaa8e718840 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/task_can_only_be_attached_to_impl.stderr @@ -0,0 +1,5 @@ +error: expected `impl` + --> tests/pallet_ui/task_can_only_be_attached_to_impl.rs:30:5 + | +30 | pub struct Task; + | ^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/task_condition_invalid_arg.rs b/substrate/frame/support/test/tests/pallet_ui/task_condition_invalid_arg.rs new file mode 100644 index 00000000000..1db96869155 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/task_condition_invalid_arg.rs @@ -0,0 +1,42 @@ +// This file is part of Substrate. + +// Copyright (C) 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. + +#[frame_support::pallet(dev_mode)] +mod pallet { + use frame_support::pallet_prelude::DispatchResult; + use frame_system::pallet_prelude::OriginFor; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::tasks_experimental] + impl Pallet { + #[pallet::task_index(0)] + #[pallet::task_condition(|flag: bool| flag)] + #[pallet::task_list(vec![1, 2].iter())] + #[pallet::task_weight(0.into())] + fn foo(_i: u32) -> DispatchResult { + Ok(()) + } + } +} + +fn main() { +} diff --git a/substrate/frame/support/test/tests/pallet_ui/task_condition_invalid_arg.stderr b/substrate/frame/support/test/tests/pallet_ui/task_condition_invalid_arg.stderr new file mode 100644 index 00000000000..ef259656688 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/task_condition_invalid_arg.stderr @@ -0,0 +1,22 @@ +error: unused import: `frame_system::pallet_prelude::OriginFor` + --> tests/pallet_ui/task_condition_invalid_arg.rs:21:6 + | +21 | use frame_system::pallet_prelude::OriginFor; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D unused-imports` implied by `-D warnings` + +error[E0308]: mismatched types + --> tests/pallet_ui/task_condition_invalid_arg.rs:35:10 + | +32 | #[pallet::task_condition(|flag: bool| flag)] + | ----------------- arguments to this function are incorrect +... +35 | fn foo(_i: u32) -> DispatchResult { + | ^^ expected `bool`, found `u32` + | +note: closure parameter defined here + --> tests/pallet_ui/task_condition_invalid_arg.rs:32:29 + | +32 | #[pallet::task_condition(|flag: bool| flag)] + | ^^^^^^^^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/task_invalid_condition.rs b/substrate/frame/support/test/tests/pallet_ui/task_invalid_condition.rs new file mode 100644 index 00000000000..6875bc13b8f --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/task_invalid_condition.rs @@ -0,0 +1,42 @@ +// This file is part of Substrate. + +// Copyright (C) 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. + +#[frame_support::pallet(dev_mode)] +mod pallet { + use frame_support::pallet_prelude::DispatchResult; + use frame_system::pallet_prelude::OriginFor; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::tasks_experimental] + impl Pallet { + #[pallet::task_index(0)] + #[pallet::task_condition(0)] + #[pallet::task_list(vec![1, 2].iter())] + #[pallet::task_weight(0.into())] + fn foo() -> DispatchResult { + Ok(()) + } + } +} + +fn main() { +} diff --git a/substrate/frame/support/test/tests/pallet_ui/task_invalid_condition.stderr b/substrate/frame/support/test/tests/pallet_ui/task_invalid_condition.stderr new file mode 100644 index 00000000000..ff57017b3fd --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/task_invalid_condition.stderr @@ -0,0 +1,27 @@ +error: unused import: `frame_system::pallet_prelude::OriginFor` + --> tests/pallet_ui/task_invalid_condition.rs:21:6 + | +21 | use frame_system::pallet_prelude::OriginFor; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D unused-imports` implied by `-D warnings` + +error[E0308]: mismatched types + --> tests/pallet_ui/task_invalid_condition.rs:18:1 + | +18 | #[frame_support::pallet(dev_mode)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected integer, found `()` + | expected due to this + | + = note: this error originates in the attribute macro `frame_support::pallet` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0618]: expected function, found `{integer}` + --> tests/pallet_ui/task_invalid_condition.rs:32:28 + | +18 | #[frame_support::pallet(dev_mode)] + | ---------------------------------- call expression requires function +... +32 | #[pallet::task_condition(0)] + | ^ diff --git a/substrate/frame/support/test/tests/pallet_ui/task_invalid_index.rs b/substrate/frame/support/test/tests/pallet_ui/task_invalid_index.rs new file mode 100644 index 00000000000..2a4b40523a6 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/task_invalid_index.rs @@ -0,0 +1,39 @@ +// This file is part of Substrate. + +// Copyright (C) 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. + +#[frame_support::pallet(dev_mode)] +mod pallet { + use frame_support::pallet_prelude::DispatchResult; + use frame_system::pallet_prelude::OriginFor; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::tasks_experimental] + impl Pallet { + #[pallet::task_index("0")] + fn foo() -> DispatchResult { + Ok(()) + } + } +} + +fn main() { +} diff --git a/substrate/frame/support/test/tests/pallet_ui/task_invalid_index.stderr b/substrate/frame/support/test/tests/pallet_ui/task_invalid_index.stderr new file mode 100644 index 00000000000..d33600455bf --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/task_invalid_index.stderr @@ -0,0 +1,5 @@ +error: expected integer literal + --> tests/pallet_ui/task_invalid_index.rs:31:24 + | +31 | #[pallet::task_index("0")] + | ^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/task_invalid_list.rs b/substrate/frame/support/test/tests/pallet_ui/task_invalid_list.rs new file mode 100644 index 00000000000..bb6438aaf10 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/task_invalid_list.rs @@ -0,0 +1,42 @@ +// This file is part of Substrate. + +// Copyright (C) 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. + +#[frame_support::pallet(dev_mode)] +mod pallet { + use frame_support::pallet_prelude::DispatchResult; + use frame_system::pallet_prelude::OriginFor; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::tasks_experimental] + impl Pallet { + #[pallet::task_index(0)] + #[pallet::task_condition(|| true)] + #[pallet::task_list(0)] + #[pallet::task_weight(0.into())] + fn foo() -> DispatchResult { + Ok(()) + } + } +} + +fn main() { +} diff --git a/substrate/frame/support/test/tests/pallet_ui/task_invalid_list.stderr b/substrate/frame/support/test/tests/pallet_ui/task_invalid_list.stderr new file mode 100644 index 00000000000..8dda0c3a1aa --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/task_invalid_list.stderr @@ -0,0 +1,19 @@ +error: unused import: `frame_system::pallet_prelude::OriginFor` + --> tests/pallet_ui/task_invalid_list.rs:21:6 + | +21 | use frame_system::pallet_prelude::OriginFor; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D unused-imports` implied by `-D warnings` + +error[E0689]: can't call method `map` on ambiguous numeric type `{integer}` + --> tests/pallet_ui/task_invalid_list.rs:18:1 + | +18 | #[frame_support::pallet(dev_mode)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the attribute macro `frame_support::pallet` (in Nightly builds, run with -Z macro-backtrace for more info) +help: you must specify a concrete type for this numeric value, like `i32` + | +33 | #[pallet::task_list(0_i32)] + | ~~~~~ diff --git a/substrate/frame/support/test/tests/pallet_ui/task_invalid_weight.rs b/substrate/frame/support/test/tests/pallet_ui/task_invalid_weight.rs new file mode 100644 index 00000000000..a0c4040347a --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/task_invalid_weight.rs @@ -0,0 +1,42 @@ +// This file is part of Substrate. + +// Copyright (C) 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. + +#[frame_support::pallet(dev_mode)] +mod pallet { + use frame_support::pallet_prelude::DispatchResult; + use frame_system::pallet_prelude::OriginFor; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::tasks_experimental] + impl Pallet { + #[pallet::task_index(0)] + #[pallet::task_condition(|| true)] + #[pallet::task_list(vec![1, 2].iter())] + #[pallet::task_weight("0")] + fn foo() -> DispatchResult { + Ok(()) + } + } +} + +fn main() { +} diff --git a/substrate/frame/support/test/tests/pallet_ui/task_invalid_weight.stderr b/substrate/frame/support/test/tests/pallet_ui/task_invalid_weight.stderr new file mode 100644 index 00000000000..3537bb59028 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/task_invalid_weight.stderr @@ -0,0 +1,27 @@ +error: unused import: `frame_system::pallet_prelude::OriginFor` + --> tests/pallet_ui/task_invalid_weight.rs:21:6 + | +21 | use frame_system::pallet_prelude::OriginFor; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D unused-imports` implied by `-D warnings` + +error[E0308]: mismatched types + --> tests/pallet_ui/task_invalid_weight.rs:18:1 + | +18 | #[frame_support::pallet(dev_mode)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected integer, found `()` + | expected due to this + | + = note: this error originates in the attribute macro `frame_support::pallet` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> tests/pallet_ui/task_invalid_weight.rs:34:25 + | +18 | #[frame_support::pallet(dev_mode)] + | ---------------------------------- expected `Weight` because of return type +... +34 | #[pallet::task_weight("0")] + | ^^^ expected `Weight`, found `&str` diff --git a/substrate/frame/support/test/tests/pallet_ui/task_missing_condition.rs b/substrate/frame/support/test/tests/pallet_ui/task_missing_condition.rs new file mode 100644 index 00000000000..6ca6e37a5bd --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/task_missing_condition.rs @@ -0,0 +1,39 @@ +// This file is part of Substrate. + +// Copyright (C) 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. + +#[frame_support::pallet(dev_mode)] +mod pallet { + use frame_support::pallet_prelude::DispatchResult; + use frame_system::pallet_prelude::OriginFor; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::tasks_experimental] + impl Pallet { + #[pallet::task_index(0)] + fn foo() -> DispatchResult { + Ok(()) + } + } +} + +fn main() { +} diff --git a/substrate/frame/support/test/tests/pallet_ui/task_missing_condition.stderr b/substrate/frame/support/test/tests/pallet_ui/task_missing_condition.stderr new file mode 100644 index 00000000000..c709ec7eac9 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/task_missing_condition.stderr @@ -0,0 +1,5 @@ +error: missing `#[pallet::task_condition(..)]` attribute + --> tests/pallet_ui/task_missing_condition.rs:32:6 + | +32 | fn foo() -> DispatchResult { + | ^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/task_missing_index.rs b/substrate/frame/support/test/tests/pallet_ui/task_missing_index.rs new file mode 100644 index 00000000000..ed98d229f18 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/task_missing_index.rs @@ -0,0 +1,38 @@ +// This file is part of Substrate. + +// Copyright (C) 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. + +#[frame_support::pallet(dev_mode)] +mod pallet { + use frame_support::pallet_prelude::DispatchResult; + use frame_system::pallet_prelude::OriginFor; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::tasks_experimental] + impl Pallet { + fn foo() -> DispatchResult { + Ok(()) + } + } +} + +fn main() { +} diff --git a/substrate/frame/support/test/tests/pallet_ui/task_missing_index.stderr b/substrate/frame/support/test/tests/pallet_ui/task_missing_index.stderr new file mode 100644 index 00000000000..ba3c9d132b8 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/task_missing_index.stderr @@ -0,0 +1,5 @@ +error: missing `#[pallet::task_index(..)]` attribute + --> tests/pallet_ui/task_missing_index.rs:31:6 + | +31 | fn foo() -> DispatchResult { + | ^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/task_missing_list.rs b/substrate/frame/support/test/tests/pallet_ui/task_missing_list.rs new file mode 100644 index 00000000000..427efe12763 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/task_missing_list.rs @@ -0,0 +1,40 @@ +// This file is part of Substrate. + +// Copyright (C) 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. + +#[frame_support::pallet(dev_mode)] +mod pallet { + use frame_support::pallet_prelude::DispatchResult; + use frame_system::pallet_prelude::OriginFor; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::tasks_experimental] + impl Pallet { + #[pallet::task_index(0)] + #[pallet::task_condition(|| true)] + fn foo() -> DispatchResult { + Ok(()) + } + } +} + +fn main() { +} diff --git a/substrate/frame/support/test/tests/pallet_ui/task_missing_list.stderr b/substrate/frame/support/test/tests/pallet_ui/task_missing_list.stderr new file mode 100644 index 00000000000..f4ae26a75ad --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/task_missing_list.stderr @@ -0,0 +1,5 @@ +error: missing `#[pallet::task_list(..)]` attribute + --> tests/pallet_ui/task_missing_list.rs:33:6 + | +33 | fn foo() -> DispatchResult { + | ^^^ diff --git a/substrate/frame/support/test/tests/pallet_ui/task_missing_weight.rs b/substrate/frame/support/test/tests/pallet_ui/task_missing_weight.rs new file mode 100644 index 00000000000..704be1f1e0b --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/task_missing_weight.rs @@ -0,0 +1,41 @@ +// This file is part of Substrate. + +// Copyright (C) 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. + +#[frame_support::pallet(dev_mode)] +mod pallet { + use frame_support::pallet_prelude::DispatchResult; + use frame_system::pallet_prelude::OriginFor; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(core::marker::PhantomData); + + #[pallet::tasks_experimental] + impl Pallet { + #[pallet::task_index(0)] + #[pallet::task_condition(|| true)] + #[pallet::task_list(vec![1, 2].iter())] + fn foo() -> DispatchResult { + Ok(()) + } + } +} + +fn main() { +} diff --git a/substrate/frame/support/test/tests/pallet_ui/task_missing_weight.stderr b/substrate/frame/support/test/tests/pallet_ui/task_missing_weight.stderr new file mode 100644 index 00000000000..de7b2eb1720 --- /dev/null +++ b/substrate/frame/support/test/tests/pallet_ui/task_missing_weight.stderr @@ -0,0 +1,5 @@ +error: missing `#[pallet::task_weight(..)]` attribute + --> tests/pallet_ui/task_missing_weight.rs:34:6 + | +34 | fn foo() -> DispatchResult { + | ^^^ diff --git a/substrate/frame/system/src/lib.rs b/substrate/frame/system/src/lib.rs index 640cb133213..6624bb43a80 100644 --- a/substrate/frame/system/src/lib.rs +++ b/substrate/frame/system/src/lib.rs @@ -241,6 +241,8 @@ pub mod pallet { type RuntimeCall = (); #[inject_runtime_type] type PalletInfo = (); + #[inject_runtime_type] + type RuntimeTask = (); type BaseCallFilter = frame_support::traits::Everything; type BlockHashCount = frame_support::traits::ConstU64<10>; type OnSetCode = (); @@ -323,6 +325,8 @@ pub mod pallet { /// Converts a module to the index of the module, injected by `construct_runtime!`. #[inject_runtime_type] + type RuntimeTask = (); + #[inject_runtime_type] type PalletInfo = (); /// The basic call filter to use in dispatchable. Supports everything as the default. @@ -400,6 +404,10 @@ pub mod pallet { + Debug + From>; + /// The aggregated `RuntimeTask` type. + #[pallet::no_default_bounds] + type RuntimeTask: Task; + /// This stores the number of previous transactions associated with a sender account. type Nonce: Parameter + Member @@ -628,6 +636,28 @@ pub mod pallet { Self::deposit_event(Event::Remarked { sender: who, hash }); Ok(().into()) } + + #[pallet::call_index(8)] + #[pallet::weight(task.weight())] + pub fn do_task(origin: OriginFor, task: T::RuntimeTask) -> DispatchResultWithPostInfo { + ensure_signed(origin)?; + + if !task.is_valid() { + return Err(Error::::InvalidTask.into()) + } + + Self::deposit_event(Event::TaskStarted { task: task.clone() }); + if let Err(err) = task.run() { + Self::deposit_event(Event::TaskFailed { task, err }); + return Err(Error::::FailedTask.into()) + } + + // Emit a success event, if your design includes events for this pallet. + Self::deposit_event(Event::TaskCompleted { task }); + + // Return success. + Ok(().into()) + } } /// Event for the System pallet. @@ -645,6 +675,12 @@ pub mod pallet { KilledAccount { account: T::AccountId }, /// On on-chain remark happened. Remarked { sender: T::AccountId, hash: T::Hash }, + /// A [`Task`] has started executing + TaskStarted { task: T::RuntimeTask }, + /// A [`Task`] has finished executing. + TaskCompleted { task: T::RuntimeTask }, + /// A [`Task`] failed during execution. + TaskFailed { task: T::RuntimeTask, err: DispatchError }, } /// Error for the System pallet @@ -666,6 +702,10 @@ pub mod pallet { NonZeroRefCount, /// The origin filter prevent the call to be dispatched. CallFiltered, + /// The specified [`Task`] is not valid. + InvalidTask, + /// The specified [`Task`] failed during execution. + FailedTask, } /// Exposed trait-generic origin type. diff --git a/substrate/frame/system/src/mock.rs b/substrate/frame/system/src/mock.rs index c016ea9e1cd..e33ac2f56c8 100644 --- a/substrate/frame/system/src/mock.rs +++ b/substrate/frame/system/src/mock.rs @@ -17,7 +17,7 @@ use crate::{self as frame_system, *}; use frame_support::{ - parameter_types, + derive_impl, parameter_types, traits::{ConstU32, ConstU64}, }; use sp_core::H256; @@ -85,6 +85,7 @@ impl OnKilledAccount for RecordKilled { } } +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = RuntimeBlockWeights; diff --git a/substrate/test-utils/runtime/src/lib.rs b/substrate/test-utils/runtime/src/lib.rs index 1a4e9fd0466..16ab467772f 100644 --- a/substrate/test-utils/runtime/src/lib.rs +++ b/substrate/test-utils/runtime/src/lib.rs @@ -27,7 +27,7 @@ pub mod substrate_test_pallet; use codec::{Decode, Encode}; use frame_support::{ - construct_runtime, + construct_runtime, derive_impl, dispatch::DispatchClass, genesis_builder_helper::{build_config, create_default_config}, parameter_types, @@ -342,6 +342,7 @@ parameter_types! { .build_or_panic(); } +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::pallet::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = RuntimeBlockWeights; diff --git a/substrate/utils/frame/rpc/support/src/lib.rs b/substrate/utils/frame/rpc/support/src/lib.rs index b91ae436127..bb5098293c2 100644 --- a/substrate/utils/frame/rpc/support/src/lib.rs +++ b/substrate/utils/frame/rpc/support/src/lib.rs @@ -63,6 +63,7 @@ use sp_storage::{StorageData, StorageKey}; /// # type Lookup = IdentityLookup; /// # type Block = frame_system::mocking::MockBlock; /// # type RuntimeEvent = RuntimeEvent; +/// # type RuntimeTask = RuntimeTask; /// # type BlockHashCount = (); /// # type DbWeight = (); /// # type Version = (); -- GitLab From f5edd4f4da5d2c46fca23fe36d619e22d8839b67 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Fri, 8 Dec 2023 09:47:48 +0100 Subject: [PATCH 26/59] Bump ark-scale version to 0.0.12 (#2652) As per title. Fix in ark-scale `TypeInfo` implementation --- Cargo.lock | 40 +++++++++++++------ substrate/primitives/core/Cargo.toml | 2 +- .../primitives/crypto/ec-utils/Cargo.toml | 2 +- 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5184a8137a3..1dd20a12849 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -541,10 +541,24 @@ dependencies = [ "scale-info", ] +[[package]] +name = "ark-scale" +version = "0.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f69c00b3b529be29528a6f2fd5fa7b1790f8bed81b9cdca17e326538545a179" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", + "parity-scale-codec", + "scale-info", +] + [[package]] name = "ark-secret-scalar" version = "0.0.2" -source = "git+https://github.com/w3f/ring-vrf?rev=2019248#2019248785389b3246d55b1c3b0e9bdef4454cb7" +source = "git+https://github.com/w3f/ring-vrf?rev=e9782f9#e9782f938629c90f3adb3fff2358bc8d1386af3e" dependencies = [ "ark-ec", "ark-ff", @@ -593,7 +607,7 @@ dependencies = [ [[package]] name = "ark-transcript" version = "0.0.2" -source = "git+https://github.com/w3f/ring-vrf?rev=2019248#2019248785389b3246d55b1c3b0e9bdef4454cb7" +source = "git+https://github.com/w3f/ring-vrf?rev=e9782f9#e9782f938629c90f3adb3fff2358bc8d1386af3e" dependencies = [ "ark-ff", "ark-serialize", @@ -1223,7 +1237,7 @@ dependencies = [ [[package]] name = "bandersnatch_vrfs" version = "0.0.4" -source = "git+https://github.com/w3f/ring-vrf?rev=2019248#2019248785389b3246d55b1c3b0e9bdef4454cb7" +source = "git+https://github.com/w3f/ring-vrf?rev=e9782f9#e9782f938629c90f3adb3fff2358bc8d1386af3e" dependencies = [ "ark-bls12-381", "ark-ec", @@ -1346,8 +1360,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f" dependencies = [ "bitcoin_hashes", - "rand 0.8.5", - "rand_core 0.6.4", + "rand 0.7.3", + "rand_core 0.5.1", "serde", "unicode-normalization", ] @@ -2725,7 +2739,7 @@ dependencies = [ [[package]] name = "common" version = "0.1.0" -source = "git+https://github.com/w3f/ring-proof#61e7b528bc0170d6bf541be32440d569b784425d" +source = "git+https://github.com/w3f/ring-proof#b273d33f9981e2bb3375ab45faeb537f7ee35224" dependencies = [ "ark-ec", "ark-ff", @@ -4496,11 +4510,11 @@ checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632" [[package]] name = "dleq_vrf" version = "0.0.2" -source = "git+https://github.com/w3f/ring-vrf?rev=2019248#2019248785389b3246d55b1c3b0e9bdef4454cb7" +source = "git+https://github.com/w3f/ring-vrf?rev=e9782f9#e9782f938629c90f3adb3fff2358bc8d1386af3e" dependencies = [ "ark-ec", "ark-ff", - "ark-scale", + "ark-scale 0.0.12", "ark-secret-scalar", "ark-serialize", "ark-std", @@ -5081,7 +5095,7 @@ dependencies = [ [[package]] name = "fflonk" version = "0.1.0" -source = "git+https://github.com/w3f/fflonk#1beb0585e1c8488956fac7f05da061f9b41e8948" +source = "git+https://github.com/w3f/fflonk#1e854f35e9a65d08b11a86291405cdc95baa0a35" dependencies = [ "ark-ec", "ark-ff", @@ -14316,7 +14330,7 @@ dependencies = [ [[package]] name = "ring" version = "0.1.0" -source = "git+https://github.com/w3f/ring-proof#61e7b528bc0170d6bf541be32440d569b784425d" +source = "git+https://github.com/w3f/ring-proof#b273d33f9981e2bb3375ab45faeb537f7ee35224" dependencies = [ "ark-ec", "ark-ff", @@ -17529,7 +17543,7 @@ dependencies = [ "ark-ed-on-bls12-377-ext", "ark-ed-on-bls12-381-bandersnatch", "ark-ed-on-bls12-381-bandersnatch-ext", - "ark-scale", + "ark-scale 0.0.12", "sp-runtime-interface 17.0.0", "sp-std 8.0.0", ] @@ -17550,7 +17564,7 @@ dependencies = [ "ark-ed-on-bls12-377-ext", "ark-ed-on-bls12-381-bandersnatch", "ark-ed-on-bls12-381-bandersnatch-ext", - "ark-scale", + "ark-scale 0.0.11", "sp-runtime-interface 17.0.0 (git+https://github.com/paritytech/polkadot-sdk)", "sp-std 8.0.0 (git+https://github.com/paritytech/polkadot-sdk)", ] @@ -19929,7 +19943,7 @@ checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if", "digest 0.10.7", - "rand 0.8.5", + "rand 0.7.3", "static_assertions", ] diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index 331d762e0d7..a7c4b49fcb8 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -56,7 +56,7 @@ sp-runtime-interface = { path = "../runtime-interface", default-features = false # bls crypto w3f-bls = { version = "0.1.3", default-features = false, optional = true } # bandersnatch crypto -bandersnatch_vrfs = { git = "https://github.com/w3f/ring-vrf", rev = "2019248", default-features = false, features = ["substrate-curves"], optional = true } +bandersnatch_vrfs = { git = "https://github.com/w3f/ring-vrf", rev = "e9782f9", default-features = false, features = ["substrate-curves"], optional = true } [dev-dependencies] criterion = "0.4.0" diff --git a/substrate/primitives/crypto/ec-utils/Cargo.toml b/substrate/primitives/crypto/ec-utils/Cargo.toml index 548328fec3c..7519fa5fc68 100644 --- a/substrate/primitives/crypto/ec-utils/Cargo.toml +++ b/substrate/primitives/crypto/ec-utils/Cargo.toml @@ -23,7 +23,7 @@ ark-ed-on-bls12-381-bandersnatch-ext = { version = "0.4.1", default-features = f ark-ed-on-bls12-381-bandersnatch = { version = "0.4.0", default-features = false, optional = true } ark-ed-on-bls12-377-ext = { version = "0.4.1", default-features = false, optional = true } ark-ed-on-bls12-377 = { version = "0.4.0", default-features = false, optional = true } -ark-scale = { version = "0.0.11", default-features = false, features = ["hazmat"], optional = true } +ark-scale = { version = "0.0.12", default-features = false, features = ["hazmat"], optional = true } sp-runtime-interface = { path = "../../runtime-interface", default-features = false, optional = true } sp-std = { path = "../../std", default-features = false, optional = true } -- GitLab From 1bdfb29587800a00aad62acb7222b77b6c2701e7 Mon Sep 17 00:00:00 2001 From: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com> Date: Fri, 8 Dec 2023 12:26:13 +0200 Subject: [PATCH 27/59] [NTFs] Emit CollectionMaxSupplySet on collection create (#2626) Closes #2293 if the max_supply is set during the collection creation, we emit the `CollectionMaxSupplySet` event --- .../src/features/create_delete_collection.rs | 6 ++++ substrate/frame/nfts/src/tests.rs | 28 ++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/substrate/frame/nfts/src/features/create_delete_collection.rs b/substrate/frame/nfts/src/features/create_delete_collection.rs index e343ad18e50..f03df7fdd4f 100644 --- a/substrate/frame/nfts/src/features/create_delete_collection.rs +++ b/substrate/frame/nfts/src/features/create_delete_collection.rs @@ -66,7 +66,13 @@ impl, I: 'static> Pallet { CollectionConfigOf::::insert(&collection, config); CollectionAccount::::insert(&owner, &collection, ()); + Self::deposit_event(event); + + if let Some(max_supply) = config.max_supply { + Self::deposit_event(Event::CollectionMaxSupplySet { collection, max_supply }); + } + Ok(()) } diff --git a/substrate/frame/nfts/src/tests.rs b/substrate/frame/nfts/src/tests.rs index aeebf51b7c7..0c32aea2be0 100644 --- a/substrate/frame/nfts/src/tests.rs +++ b/substrate/frame/nfts/src/tests.rs @@ -2191,6 +2191,10 @@ fn max_supply_should_work() { default_collection_config() )); assert_eq!(CollectionConfigOf::::get(collection_id).unwrap().max_supply, None); + assert!(!events().contains(&Event::::CollectionMaxSupplySet { + collection: collection_id, + max_supply, + })); assert_ok!(Nfts::set_collection_max_supply( RuntimeOrigin::signed(user_id.clone()), @@ -2242,9 +2246,31 @@ fn max_supply_should_work() { None )); assert_noop!( - Nfts::mint(RuntimeOrigin::signed(user_id.clone()), collection_id, 2, user_id, None), + Nfts::mint( + RuntimeOrigin::signed(user_id.clone()), + collection_id, + 2, + user_id.clone(), + None + ), Error::::MaxSupplyReached ); + + // validate the event gets emitted when we set the max supply on collection create + let collection_id = 1; + assert_ok!(Nfts::force_create( + RuntimeOrigin::root(), + user_id.clone(), + CollectionConfig { max_supply: Some(max_supply), ..default_collection_config() } + )); + assert_eq!( + CollectionConfigOf::::get(collection_id).unwrap().max_supply, + Some(max_supply) + ); + assert!(events().contains(&Event::::CollectionMaxSupplySet { + collection: collection_id, + max_supply, + })); }); } -- GitLab From da40d97a2311640fe3f0da486f2ebf4cb840f40f Mon Sep 17 00:00:00 2001 From: Muharem Date: Fri, 8 Dec 2023 14:02:09 +0100 Subject: [PATCH 28/59] Westend: Fellowship Treasury (#2532) Treasury Pallet Instance for the Fellowship in Westend Collectives. In this update, we present a Treasury Pallet Instance that is under the control of the Fellowship body, with oversight from the Root and Treasurer origins. Here's how it is governed: - the Root origin have the authority to reject or approve spend proposals, with no amount limit for approvals. - the Treasurer origin have the authority to reject or approve spend proposals, with approval limits of up to 10,000,000 DOT. - Voice of all Fellows ranked at 3 or above can reject or approve spend proposals, with a maximum approval limit of 10,000 DOT. - Voice of Fellows ranked at 4 or above can also reject or approve spend proposals, with a maximum approval limit of 10,000,000 DOT. Additionally, we introduce the Asset Rate Pallet Instance to establish conversion rates from asset A to B. This is used to determine if a proposed spend amount involving a non-native asset is permissible by the commanding origin. The rates can be set up by the Root, Treasurer origins, or Voice of all Fellows. --------- Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Co-authored-by: joepetrowski --- Cargo.lock | 19 ++ Cargo.toml | 1 + cumulus/parachains/common/src/polkadot.rs | 2 + cumulus/parachains/common/src/westend.rs | 2 + .../collectives-westend/Cargo.toml | 25 ++ .../collectives-westend/src/genesis.rs | 67 ++++++ .../collectives-westend/src/lib.rs | 51 +++++ .../networks/westend-system/Cargo.toml | 1 + .../networks/westend-system/src/lib.rs | 4 + .../tests/assets/asset-hub-westend/Cargo.toml | 1 + .../tests/assets/asset-hub-westend/src/lib.rs | 7 +- .../src/tests/fellowship_treasury.rs | 131 +++++++++++ .../assets/asset-hub-westend/src/tests/mod.rs | 1 + .../asset-hub-westend/src/xcm_config.rs | 16 ++ .../collectives-westend/Cargo.toml | 8 + .../collectives-westend/src/fellowship/mod.rs | 128 ++++++++++- .../collectives-westend/src/lib.rs | 27 ++- .../collectives-westend/src/weights/mod.rs | 2 + .../src/weights/pallet_asset_rate.rs | 85 +++++++ .../src/weights/pallet_treasury.rs | 214 ++++++++++++++++++ .../collectives-westend/src/xcm_config.rs | 6 +- polkadot/runtime/common/src/impls.rs | 21 +- polkadot/runtime/westend/constants/src/lib.rs | 1 + polkadot/runtime/westend/src/xcm_config.rs | 13 +- prdoc/pr_2532.prdoc | 11 + substrate/frame/treasury/src/benchmarking.rs | 10 +- 26 files changed, 827 insertions(+), 27 deletions(-) create mode 100644 cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/Cargo.toml create mode 100644 cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/src/genesis.rs create mode 100644 cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/src/lib.rs create mode 100644 cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/fellowship_treasury.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_asset_rate.rs create mode 100644 cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_treasury.rs create mode 100644 prdoc/pr_2532.prdoc diff --git a/Cargo.lock b/Cargo.lock index 1dd20a12849..ee815868957 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -885,6 +885,7 @@ dependencies = [ "asset-test-utils", "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", + "cumulus-pallet-xcmp-queue", "emulated-integration-tests-common", "frame-support", "frame-system", @@ -2613,6 +2614,21 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "collectives-westend-emulated-chain" +version = "0.0.0" +dependencies = [ + "collectives-westend-runtime", + "cumulus-primitives-core", + "emulated-integration-tests-common", + "frame-support", + "parachains-common", + "serde_json", + "sp-core", + "sp-runtime", + "westend-emulated-chain", +] + [[package]] name = "collectives-westend-runtime" version = "1.0.0" @@ -2634,6 +2650,7 @@ dependencies = [ "hex-literal", "log", "pallet-alliance", + "pallet-asset-rate", "pallet-aura", "pallet-authorship", "pallet-balances", @@ -2653,6 +2670,7 @@ dependencies = [ "pallet-timestamp", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", + "pallet-treasury", "pallet-utility", "pallet-xcm", "parachains-common", @@ -21049,6 +21067,7 @@ version = "0.0.0" dependencies = [ "asset-hub-westend-emulated-chain", "bridge-hub-westend-emulated-chain", + "collectives-westend-emulated-chain", "emulated-integration-tests-common", "penpal-emulated-chain", "westend-emulated-chain", diff --git a/Cargo.toml b/Cargo.toml index 26d48ba0ced..1c791b6118f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -66,6 +66,7 @@ members = [ "cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend", "cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo", "cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend", + "cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend", "cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal", "cumulus/parachains/integration-tests/emulated/chains/relays/rococo", "cumulus/parachains/integration-tests/emulated/chains/relays/westend", diff --git a/cumulus/parachains/common/src/polkadot.rs b/cumulus/parachains/common/src/polkadot.rs index 744108bce2e..ca413830342 100644 --- a/cumulus/parachains/common/src/polkadot.rs +++ b/cumulus/parachains/common/src/polkadot.rs @@ -31,6 +31,8 @@ pub mod account { /// It is used as a temporarily place to deposit a slashed imbalance /// before the teleport to the Treasury. pub const AMBASSADOR_REFERENDA_PALLET_ID: PalletId = PalletId(*b"py/amref"); + /// Fellowship treasury pallet ID + pub const FELLOWSHIP_TREASURY_PALLET_ID: PalletId = PalletId(*b"py/feltr"); } /// Consensus-related. diff --git a/cumulus/parachains/common/src/westend.rs b/cumulus/parachains/common/src/westend.rs index 0ae21e23454..2bd4d18a15e 100644 --- a/cumulus/parachains/common/src/westend.rs +++ b/cumulus/parachains/common/src/westend.rs @@ -29,6 +29,8 @@ pub mod account { /// Ambassador Referenda pallet ID - used as a temporary place to deposit a slashed imbalance /// before the teleport to the Treasury. pub const AMBASSADOR_REFERENDA_PALLET_ID: PalletId = PalletId(*b"py/amref"); + /// Fellowship treasury pallet ID. + pub const FELLOWSHIP_TREASURY_PALLET_ID: PalletId = PalletId(*b"py/feltr"); } pub mod currency { diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/Cargo.toml new file mode 100644 index 00000000000..5dcf139bdb7 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "collectives-westend-emulated-chain" +version = "0.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +description = "Collectives Westend emulated chain" +publish = false + +[dependencies] +serde_json = "1.0.104" + +# Substrate +sp-core = { path = "../../../../../../../../substrate/primitives/core", default-features = false } +sp-runtime = { path = "../../../../../../../../substrate/primitives/runtime", default-features = false } +frame-support = { path = "../../../../../../../../substrate/frame/support", default-features = false } + +# Polakadot +parachains-common = { path = "../../../../../../../parachains/common" } + +# Cumulus +cumulus-primitives-core = { path = "../../../../../../../primitives/core", default-features = false } +emulated-integration-tests-common = { path = "../../../../common", default-features = false } +collectives-westend-runtime = { path = "../../../../../../runtimes/collectives/collectives-westend" } +westend-emulated-chain = { path = "../../../relays/westend" } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/src/genesis.rs new file mode 100644 index 00000000000..d79ef55072a --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/src/genesis.rs @@ -0,0 +1,67 @@ +// Copyright (C) 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 +use sp_core::storage::Storage; + +// Cumulus +use emulated_integration_tests_common::{ + accounts, build_genesis_storage, collators, SAFE_XCM_VERSION, +}; +use parachains_common::Balance; + +pub const PARA_ID: u32 = 1001; +pub const ED: Balance = parachains_common::westend::currency::EXISTENTIAL_DEPOSIT; + +pub fn genesis() -> Storage { + let genesis_config = collectives_westend_runtime::RuntimeGenesisConfig { + system: collectives_westend_runtime::SystemConfig::default(), + balances: collectives_westend_runtime::BalancesConfig { + balances: accounts::init_balances().iter().cloned().map(|k| (k, ED * 4096)).collect(), + }, + parachain_info: collectives_westend_runtime::ParachainInfoConfig { + parachain_id: PARA_ID.into(), + ..Default::default() + }, + collator_selection: collectives_westend_runtime::CollatorSelectionConfig { + invulnerables: collators::invulnerables().iter().cloned().map(|(acc, _)| acc).collect(), + candidacy_bond: ED * 16, + ..Default::default() + }, + session: collectives_westend_runtime::SessionConfig { + keys: collators::invulnerables() + .into_iter() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + collectives_westend_runtime::SessionKeys { aura }, // session keys + ) + }) + .collect(), + }, + polkadot_xcm: collectives_westend_runtime::PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + ..Default::default() + }, + ..Default::default() + }; + + build_genesis_storage( + &genesis_config, + collectives_westend_runtime::WASM_BINARY + .expect("WASM binary was not built, please build it!"), + ) +} diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/src/lib.rs new file mode 100644 index 00000000000..5d553b6f103 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/src/lib.rs @@ -0,0 +1,51 @@ +// Copyright (C) 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 genesis; + +// Substrate +use frame_support::traits::OnInitialize; + +// Cumulus +use emulated_integration_tests_common::{ + impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, + impls::Parachain, xcm_emulator::decl_test_parachains, +}; + +// CollectivesWestend Parachain declaration +decl_test_parachains! { + pub struct CollectivesWestend { + genesis = genesis::genesis(), + on_init = { + collectives_westend_runtime::AuraExt::on_initialize(1); + }, + runtime = collectives_westend_runtime, + core = { + XcmpMessageHandler: collectives_westend_runtime::XcmpQueue, + LocationToAccountId: collectives_westend_runtime::xcm_config::LocationToAccountId, + ParachainInfo: collectives_westend_runtime::ParachainInfo, + }, + pallets = { + PolkadotXcm: collectives_westend_runtime::PolkadotXcm, + Balances: collectives_westend_runtime::Balances, + FellowshipTreasury: collectives_westend_runtime::FellowshipTreasury, + AssetRate: collectives_westend_runtime::AssetRate, + } + }, +} + +// AssetHubWestend implementation +impl_accounts_helpers_for_parachain!(CollectivesWestend); +impl_assert_events_helpers_for_parachain!(CollectivesWestend); diff --git a/cumulus/parachains/integration-tests/emulated/networks/westend-system/Cargo.toml b/cumulus/parachains/integration-tests/emulated/networks/westend-system/Cargo.toml index a4360076d6b..634111bc381 100644 --- a/cumulus/parachains/integration-tests/emulated/networks/westend-system/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/networks/westend-system/Cargo.toml @@ -13,4 +13,5 @@ emulated-integration-tests-common = { path = "../../common", default-features = westend-emulated-chain = { path = "../../chains/relays/westend", default-features = false } asset-hub-westend-emulated-chain = { path = "../../chains/parachains/assets/asset-hub-westend" } bridge-hub-westend-emulated-chain = { path = "../../chains/parachains/bridges/bridge-hub-westend" } +collectives-westend-emulated-chain = { path = "../../chains/parachains/collectives/collectives-westend" } penpal-emulated-chain = { path = "../../chains/parachains/testing/penpal" } diff --git a/cumulus/parachains/integration-tests/emulated/networks/westend-system/src/lib.rs b/cumulus/parachains/integration-tests/emulated/networks/westend-system/src/lib.rs index 667b44a6986..26cd5c7e860 100644 --- a/cumulus/parachains/integration-tests/emulated/networks/westend-system/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/networks/westend-system/src/lib.rs @@ -15,11 +15,13 @@ pub use asset_hub_westend_emulated_chain; pub use bridge_hub_westend_emulated_chain; +pub use collectives_westend_emulated_chain; pub use penpal_emulated_chain; pub use westend_emulated_chain; use asset_hub_westend_emulated_chain::AssetHubWestend; use bridge_hub_westend_emulated_chain::BridgeHubWestend; +use collectives_westend_emulated_chain::CollectivesWestend; use penpal_emulated_chain::{PenpalA, PenpalB}; use westend_emulated_chain::Westend; @@ -35,6 +37,7 @@ decl_test_networks! { parachains = vec![ AssetHubWestend, BridgeHubWestend, + CollectivesWestend, PenpalA, PenpalB, ], @@ -46,6 +49,7 @@ decl_test_sender_receiver_accounts_parameter_types! { WestendRelay { sender: ALICE, receiver: BOB }, AssetHubWestendPara { sender: ALICE, receiver: BOB }, BridgeHubWestendPara { sender: ALICE, receiver: BOB }, + CollectivesWestendPara { sender: ALICE, receiver: BOB }, PenpalAPara { sender: ALICE, receiver: BOB }, PenpalBPara { sender: ALICE, receiver: BOB } } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml index cdaa65f02cb..a0861b49955 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml @@ -36,6 +36,7 @@ parachains-common = { path = "../../../../../../parachains/common" } asset-hub-westend-runtime = { path = "../../../../../runtimes/assets/asset-hub-westend" } asset-test-utils = { path = "../../../../../runtimes/assets/test-utils" } cumulus-pallet-dmp-queue = { default-features = false, path = "../../../../../../pallets/dmp-queue" } +cumulus-pallet-xcmp-queue = { default-features = false, path = "../../../../../../pallets/xcmp-queue" } cumulus-pallet-parachain-system = { default-features = false, path = "../../../../../../pallets/parachain-system" } emulated-integration-tests-common = { path = "../../../common", default-features = false } westend-system-emulated-network = { path = "../../../networks/westend-system" } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs index e2c03d2f8f0..e9c7a59faaf 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/lib.rs @@ -47,11 +47,16 @@ pub use westend_system_emulated_network::{ asset_hub_westend_emulated_chain::{ genesis::ED as ASSET_HUB_WESTEND_ED, AssetHubWestendParaPallet as AssetHubWestendPallet, }, + collectives_westend_emulated_chain::{ + genesis::ED as COLLECTIVES_WESTEND_ED, + CollectivesWestendParaPallet as CollectivesWestendPallet, + }, penpal_emulated_chain::PenpalBParaPallet as PenpalBPallet, westend_emulated_chain::{genesis::ED as WESTEND_ED, WestendRelayPallet as WestendPallet}, AssetHubWestendPara as AssetHubWestend, AssetHubWestendParaReceiver as AssetHubWestendReceiver, AssetHubWestendParaSender as AssetHubWestendSender, BridgeHubWestendPara as BridgeHubWestend, - BridgeHubWestendParaReceiver as BridgeHubWestendReceiver, PenpalBPara as PenpalB, + BridgeHubWestendParaReceiver as BridgeHubWestendReceiver, + CollectivesWestendPara as CollectivesWestend, PenpalBPara as PenpalB, PenpalBParaReceiver as PenpalBReceiver, PenpalBParaSender as PenpalBSender, WestendRelay as Westend, WestendRelayReceiver as WestendReceiver, WestendRelaySender as WestendSender, diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/fellowship_treasury.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/fellowship_treasury.rs new file mode 100644 index 00000000000..d7de0a451f2 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/fellowship_treasury.rs @@ -0,0 +1,131 @@ +// Copyright (C) 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 emulated_integration_tests_common::accounts::{ALICE, BOB}; +use frame_support::traits::fungibles::{Create, Inspect, Mutate}; +use polkadot_runtime_common::impls::VersionedLocatableAsset; +use xcm_executor::traits::ConvertLocation; + +#[test] +fn create_and_claim_treasury_spend() { + const ASSET_ID: u32 = 1984; + const SPEND_AMOUNT: u128 = 1_000_000; + // treasury location from a sibling parachain. + let treasury_location: MultiLocation = MultiLocation::new( + 1, + X2(Parachain(CollectivesWestend::para_id().into()), PalletInstance(65)), + ); + // treasury account on a sibling parachain. + let treasury_account = + asset_hub_westend_runtime::xcm_config::LocationToAccountId::convert_location( + &treasury_location, + ) + .unwrap(); + let asset_hub_location = MultiLocation::new(1, Parachain(AssetHubWestend::para_id().into())); + let root = ::RuntimeOrigin::root(); + // asset kind to be spent from the treasury. + let asset_kind = VersionedLocatableAsset::V3 { + location: asset_hub_location, + asset_id: AssetId::Concrete((PalletInstance(50), GeneralIndex(ASSET_ID.into())).into()), + }; + // treasury spend beneficiary. + let alice: AccountId = Westend::account_id_of(ALICE); + let bob: AccountId = CollectivesWestend::account_id_of(BOB); + let bob_signed = ::RuntimeOrigin::signed(bob.clone()); + + AssetHubWestend::execute_with(|| { + type Assets = ::Assets; + + // create an asset class and mint some assets to the treasury account. + assert_ok!(>::create( + ASSET_ID, + treasury_account.clone(), + true, + SPEND_AMOUNT / 2 + )); + assert_ok!(>::mint_into(ASSET_ID, &treasury_account, SPEND_AMOUNT * 4)); + // beneficiary has zero balance. + assert_eq!(>::balance(ASSET_ID, &alice,), 0u128,); + }); + + CollectivesWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + type FellowshipTreasury = + ::FellowshipTreasury; + type AssetRate = ::AssetRate; + + // create a conversion rate from `asset_kind` to the native currency. + assert_ok!(AssetRate::create(root.clone(), Box::new(asset_kind.clone()), 2.into())); + + // create and approve a treasury spend. + assert_ok!(FellowshipTreasury::spend( + root, + Box::new(asset_kind), + SPEND_AMOUNT, + Box::new(MultiLocation::new(0, Into::<[u8; 32]>::into(alice.clone())).into()), + None, + )); + // claim the spend. + assert_ok!(FellowshipTreasury::payout(bob_signed.clone(), 0)); + + assert_expected_events!( + CollectivesWestend, + vec![ + RuntimeEvent::FellowshipTreasury(pallet_treasury::Event::Paid { .. }) => {}, + ] + ); + }); + + AssetHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + type Assets = ::Assets; + + // assert events triggered by xcm pay program + // 1. treasury asset transferred to spend beneficiary + // 2. response to the Fellowship treasury pallet instance sent back + // 3. XCM program completed + assert_expected_events!( + AssetHubWestend, + vec![ + RuntimeEvent::Assets(pallet_assets::Event::Transferred { asset_id: id, from, to, amount }) => { + id: id == &ASSET_ID, + from: from == &treasury_account, + to: to == &alice, + amount: amount == &SPEND_AMOUNT, + }, + RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, + RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { success: true ,.. }) => {}, + ] + ); + // beneficiary received the assets from the treasury. + assert_eq!(>::balance(ASSET_ID, &alice,), SPEND_AMOUNT,); + }); + + CollectivesWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + type FellowshipTreasury = + ::FellowshipTreasury; + + // check the payment status to ensure the response from the AssetHub was received. + assert_ok!(FellowshipTreasury::check_status(bob_signed, 0)); + assert_expected_events!( + CollectivesWestend, + vec![ + RuntimeEvent::FellowshipTreasury(pallet_treasury::Event::SpendProcessed { .. }) => {}, + ] + ); + }); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs index d2127b63048..ee720c24480 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/mod.rs @@ -13,6 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +mod fellowship_treasury; mod reserve_transfer; mod send; mod set_xcm_versions; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs index 19fd9b0b928..946ab9696f7 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs @@ -239,6 +239,18 @@ match_types! { MultiLocation { parents: 1, interior: Here } | MultiLocation { parents: 1, interior: X1(Plurality { .. }) } }; + pub type FellowshipEntities: impl Contains = { + // Fellowship Plurality + MultiLocation { parents: 1, interior: X2(Parachain(1001), Plurality { id: BodyId::Technical, ..}) } | + // Fellowship Salary Pallet + MultiLocation { parents: 1, interior: X2(Parachain(1001), PalletInstance(64)) } | + // Fellowship Treasury Pallet + MultiLocation { parents: 1, interior: X2(Parachain(1001), PalletInstance(65)) } + }; + pub type AmbassadorEntities: impl Contains = { + // Ambassador Salary Pallet + MultiLocation { parents: 1, interior: X2(Parachain(1001), PalletInstance(74)) } + }; } /// A call filter for the XCM Transact instruction. This is a temporary measure until we properly @@ -487,6 +499,8 @@ pub type Barrier = TrailingSetTopicAsId< ParentOrParentsPlurality, Equals, Equals, + FellowshipEntities, + AmbassadorEntities, )>, // Subscriptions for version tracking are OK. AllowSubscriptionsFrom, @@ -525,6 +539,8 @@ pub type ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger = pub type WaivedLocations = ( RelayOrOtherSystemParachains, Equals, + FellowshipEntities, + AmbassadorEntities, ); /// Cases where a remote origin is accepted as trusted Teleporter for a given asset: diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml index 94a5edc371f..433e55c6ea9 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml @@ -21,6 +21,7 @@ frame-system = { path = "../../../../../substrate/frame/system", default-feature frame-system-benchmarking = { path = "../../../../../substrate/frame/system/benchmarking", default-features = false, optional = true } frame-system-rpc-runtime-api = { path = "../../../../../substrate/frame/system/rpc/runtime-api", default-features = false } frame-try-runtime = { path = "../../../../../substrate/frame/try-runtime", default-features = false, optional = true } +pallet-asset-rate = { path = "../../../../../substrate/frame/asset-rate", default-features = false } pallet-alliance = { path = "../../../../../substrate/frame/alliance", default-features = false } pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false } pallet-authorship = { path = "../../../../../substrate/frame/authorship", default-features = false } @@ -34,6 +35,7 @@ pallet-session = { path = "../../../../../substrate/frame/session", default-feat pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false } pallet-transaction-payment = { path = "../../../../../substrate/frame/transaction-payment", default-features = false } pallet-transaction-payment-rpc-runtime-api = { path = "../../../../../substrate/frame/transaction-payment/rpc/runtime-api", default-features = false } +pallet-treasury = { path = "../../../../../substrate/frame/treasury", default-features = false } pallet-utility = { path = "../../../../../substrate/frame/utility", default-features = false } pallet-referenda = { path = "../../../../../substrate/frame/referenda", default-features = false } pallet-ranked-collective = { path = "../../../../../substrate/frame/ranked-collective", default-features = false } @@ -97,6 +99,7 @@ runtime-benchmarks = [ "frame-system-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-alliance/runtime-benchmarks", + "pallet-asset-rate/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-collator-selection/runtime-benchmarks", "pallet-collective-content/runtime-benchmarks", @@ -111,6 +114,7 @@ runtime-benchmarks = [ "pallet-salary/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-treasury/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "parachains-common/runtime-benchmarks", @@ -130,6 +134,7 @@ try-runtime = [ "frame-system/try-runtime", "frame-try-runtime/try-runtime", "pallet-alliance/try-runtime", + "pallet-asset-rate/try-runtime", "pallet-aura/try-runtime", "pallet-authorship/try-runtime", "pallet-balances/try-runtime", @@ -148,6 +153,7 @@ try-runtime = [ "pallet-session/try-runtime", "pallet-timestamp/try-runtime", "pallet-transaction-payment/try-runtime", + "pallet-treasury/try-runtime", "pallet-utility/try-runtime", "pallet-xcm/try-runtime", "parachain-info/try-runtime", @@ -172,6 +178,7 @@ std = [ "frame-try-runtime?/std", "log/std", "pallet-alliance/std", + "pallet-asset-rate/std", "pallet-aura/std", "pallet-authorship/std", "pallet-balances/std", @@ -191,6 +198,7 @@ std = [ "pallet-timestamp/std", "pallet-transaction-payment-rpc-runtime-api/std", "pallet-transaction-payment/std", + "pallet-treasury/std", "pallet-utility/std", "pallet-xcm/std", "parachain-info/std", diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/mod.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/mod.rs index b7412705dde..3fd108c0a5c 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/mod.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/fellowship/mod.rs @@ -21,28 +21,41 @@ mod tracks; use crate::{ impls::ToParentTreasury, weights, - xcm_config::{FellowshipAdminBodyId, UsdtAssetHub}, - AccountId, Balance, Balances, FellowshipReferenda, GovernanceLocation, Preimage, Runtime, - RuntimeCall, RuntimeEvent, RuntimeOrigin, Scheduler, WestendTreasuryAccount, DAYS, + xcm_config::{FellowshipAdminBodyId, TreasurerBodyId, UsdtAssetHub}, + AccountId, AssetRate, Balance, Balances, FellowshipReferenda, GovernanceLocation, Preimage, + Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, Scheduler, WestendTreasuryAccount, DAYS, }; use frame_support::{ parameter_types, - traits::{EitherOf, EitherOfDiverse, MapSuccess, OriginTrait, TryWithMorphedArg}, + traits::{ + EitherOf, EitherOfDiverse, MapSuccess, NeverEnsureOrigin, OriginTrait, TryWithMorphedArg, + }, + PalletId, }; -use frame_system::EnsureRootWithSuccess; +use frame_system::{EnsureRoot, EnsureRootWithSuccess}; pub use origins::{ pallet_origins as pallet_fellowship_origins, Architects, EnsureCanPromoteTo, EnsureCanRetainAt, EnsureFellowship, Fellows, Masters, Members, ToVoice, }; use pallet_ranked_collective::EnsureOfRank; use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; -use parachains_common::{polkadot::account, HOURS}; +use parachains_common::westend::{account, currency::GRAND}; +use polkadot_runtime_common::impls::{ + LocatableAssetConverter, VersionedLocatableAsset, VersionedMultiLocationConverter, +}; +use sp_arithmetic::Permill; use sp_core::{ConstU128, ConstU32}; -use sp_runtime::traits::{AccountIdConversion, ConstU16, ConvertToValue, Replace, TakeFirst}; +use sp_runtime::traits::{ + AccountIdConversion, ConstU16, ConvertToValue, IdentityLookup, Replace, TakeFirst, +}; +use westend_runtime_constants::time::HOURS; +use xcm::prelude::*; use xcm_builder::{AliasesIntoAccountId32, PayOverXcm}; #[cfg(feature = "runtime-benchmarks")] use crate::impls::benchmarks::{OpenHrmpChannel, PayWithEnsure}; +#[cfg(feature = "runtime-benchmarks")] +use parachains_common::westend::currency::DOLLARS; /// The Fellowship members' ranks. pub mod ranks { @@ -191,8 +204,6 @@ impl pallet_core_fellowship::Config for Runtime { pub type FellowshipSalaryInstance = pallet_salary::Instance1; -use xcm::prelude::*; - parameter_types! { // The interior location on AssetHub for the paying account. This is the Fellowship Salary // pallet instance (which sits at index 64). This sovereign account will need funding. @@ -236,3 +247,102 @@ impl pallet_salary::Config for Runtime { // Total monthly salary budget. type Budget = ConstU128<{ 100_000 * USDT_UNITS }>; } + +parameter_types! { + pub const FellowshipTreasuryPalletId: PalletId = account::FELLOWSHIP_TREASURY_PALLET_ID; + pub const HundredPercent: Permill = Permill::from_percent(100); + pub const Burn: Permill = Permill::from_percent(0); + pub const MaxBalance: Balance = Balance::max_value(); + // The asset's interior location for the paying account. This is the Fellowship Treasury + // pallet instance (which sits at index 65). + pub FellowshipTreasuryInteriorLocation: InteriorMultiLocation = PalletInstance(65).into(); +} + +#[cfg(feature = "runtime-benchmarks")] +parameter_types! { + // Benchmark bond. Needed to make `propose_spend` work. + pub const TenPercent: Permill = Permill::from_percent(10); + // Benchmark minimum. Needed to make `propose_spend` work. + pub const BenchmarkProposalBondMinimum: Balance = 1 * DOLLARS; + // Benchmark maximum. Needed to make `propose_spend` work. + pub const BenchmarkProposalBondMaximum: Balance = 10 * DOLLARS; +} + +/// [`PayOverXcm`] setup to pay the Fellowship Treasury. +pub type FellowshipTreasuryPaymaster = PayOverXcm< + FellowshipTreasuryInteriorLocation, + crate::xcm_config::XcmRouter, + crate::PolkadotXcm, + ConstU32<{ 6 * HOURS }>, + VersionedMultiLocation, + VersionedLocatableAsset, + LocatableAssetConverter, + VersionedMultiLocationConverter, +>; + +pub type FellowshipTreasuryInstance = pallet_treasury::Instance1; + +impl pallet_treasury::Config for Runtime { + // The creation of proposals via the treasury pallet is deprecated and should not be utilized. + // Instead, public or fellowship referenda should be used to propose and command the treasury + // spend or spend_local dispatchables. The parameters below have been configured accordingly to + // discourage its use. + // TODO: replace with `NeverEnsure` once polkadot-sdk 1.5 is released. + type ApproveOrigin = NeverEnsureOrigin<()>; + type OnSlash = (); + #[cfg(not(feature = "runtime-benchmarks"))] + type ProposalBond = HundredPercent; + #[cfg(not(feature = "runtime-benchmarks"))] + type ProposalBondMinimum = MaxBalance; + #[cfg(not(feature = "runtime-benchmarks"))] + type ProposalBondMaximum = MaxBalance; + + #[cfg(feature = "runtime-benchmarks")] + type ProposalBond = TenPercent; + #[cfg(feature = "runtime-benchmarks")] + type ProposalBondMinimum = BenchmarkProposalBondMinimum; + #[cfg(feature = "runtime-benchmarks")] + type ProposalBondMaximum = BenchmarkProposalBondMaximum; + // end. + + type WeightInfo = weights::pallet_treasury::WeightInfo; + type PalletId = FellowshipTreasuryPalletId; + type Currency = Balances; + type RejectOrigin = EitherOfDiverse< + EnsureRoot, + EitherOfDiverse>, Fellows>, + >; + type RuntimeEvent = RuntimeEvent; + type SpendPeriod = ConstU32<{ 7 * DAYS }>; + type Burn = Burn; + type BurnDestination = (); + type SpendFunds = (); + type MaxApprovals = ConstU32<100>; + type SpendOrigin = EitherOf< + EitherOf< + EnsureRootWithSuccess, + MapSuccess< + EnsureXcm>, + Replace>, + >, + >, + EitherOf< + MapSuccess>>, + MapSuccess>>, + >, + >; + type AssetKind = VersionedLocatableAsset; + type Beneficiary = VersionedMultiLocation; + type BeneficiaryLookup = IdentityLookup; + #[cfg(not(feature = "runtime-benchmarks"))] + type Paymaster = FellowshipTreasuryPaymaster; + #[cfg(feature = "runtime-benchmarks")] + type Paymaster = PayWithEnsure>>; + type BalanceConverter = AssetRate; + type PayoutPeriod = ConstU32<{ 30 * DAYS }>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = polkadot_runtime_common::impls::benchmarks::TreasuryArguments< + sp_core::ConstU8<1>, + ConstU32<1000>, + >; +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs index 3b8ce0a8704..9135405155b 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs @@ -89,14 +89,16 @@ use parachains_common::{ SLOT_DURATION, }; use sp_runtime::RuntimeDebug; -use xcm_config::{GovernanceLocation, XcmOriginToTransactDispatchOrigin}; +use xcm_config::{GovernanceLocation, TreasurerBodyId, XcmOriginToTransactDispatchOrigin}; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; // Polkadot imports use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; -use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; +use polkadot_runtime_common::{ + impls::VersionedLocatableAsset, BlockHashCount, SlowAdjustingFeeUpdate, +}; use xcm::latest::{prelude::*, BodyId}; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; @@ -325,6 +327,7 @@ impl InstanceFilter for ProxyType { RuntimeCall::FellowshipReferenda { .. } | RuntimeCall::FellowshipCore { .. } | RuntimeCall::FellowshipSalary { .. } | + RuntimeCall::FellowshipTreasury { .. } | RuntimeCall::Utility { .. } | RuntimeCall::Multisig { .. } ), @@ -613,6 +616,21 @@ impl pallet_preimage::Config for Runtime { >; } +impl pallet_asset_rate::Config for Runtime { + type WeightInfo = weights::pallet_asset_rate::WeightInfo; + type RuntimeEvent = RuntimeEvent; + type CreateOrigin = EitherOfDiverse< + EnsureRoot, + EitherOfDiverse>, Fellows>, + >; + type RemoveOrigin = Self::CreateOrigin; + type UpdateOrigin = Self::CreateOrigin; + type Currency = Balances; + type AssetKind = VersionedLocatableAsset; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = polkadot_runtime_common::impls::benchmarks::AssetRateArguments; +} + // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( pub enum Runtime @@ -648,6 +666,7 @@ construct_runtime!( Proxy: pallet_proxy::{Pallet, Call, Storage, Event} = 42, Preimage: pallet_preimage::{Pallet, Call, Storage, Event, HoldReason} = 43, Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event} = 44, + AssetRate: pallet_asset_rate::{Pallet, Call, Storage, Event} = 45, // The main stage. @@ -665,6 +684,8 @@ construct_runtime!( FellowshipCore: pallet_core_fellowship::::{Pallet, Call, Storage, Event} = 63, // pub type FellowshipSalaryInstance = pallet_salary::Instance1; FellowshipSalary: pallet_salary::::{Pallet, Call, Storage, Event} = 64, + // pub type FellowshipTreasuryInstance = pallet_treasury::Instance1; + FellowshipTreasury: pallet_treasury::::{Pallet, Call, Storage, Event} = 65, // Ambassador Program. AmbassadorCollective: pallet_ranked_collective::::{Pallet, Call, Storage, Event} = 70, @@ -744,6 +765,8 @@ mod benches { [pallet_collective_content, AmbassadorContent] [pallet_core_fellowship, AmbassadorCore] [pallet_salary, AmbassadorSalary] + [pallet_treasury, FellowshipTreasury] + [pallet_asset_rate, AssetRate] ); } diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/mod.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/mod.rs index d49a2905e7f..77f76342a2e 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/mod.rs @@ -19,6 +19,7 @@ pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; pub mod pallet_alliance; +pub mod pallet_asset_rate; pub mod pallet_balances; pub mod pallet_collator_selection; pub mod pallet_collective; @@ -38,6 +39,7 @@ pub mod pallet_salary_fellowship_salary; pub mod pallet_scheduler; pub mod pallet_session; pub mod pallet_timestamp; +pub mod pallet_treasury; pub mod pallet_utility; pub mod pallet_xcm; pub mod paritydb_weights; diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_asset_rate.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_asset_rate.rs new file mode 100644 index 00000000000..51b0580f857 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_asset_rate.rs @@ -0,0 +1,85 @@ +// Copyright Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +//! Autogenerated weights for `pallet_asset_rate` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-11-28, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `cob`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/debug/polkadot-parachain +// benchmark +// pallet +// --chain=collectives-westend-dev +// --steps=2 +// --repeat=2 +// --pallet=pallet-asset-rate +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_asset_rate`. +pub struct WeightInfo(PhantomData); +impl pallet_asset_rate::WeightInfo for WeightInfo { + /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) + /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(1238), added: 3713, mode: `MaxEncodedLen`) + fn create() -> Weight { + // Proof Size summary in bytes: + // Measured: `6` + // Estimated: `4703` + // Minimum execution time: 102_000_000 picoseconds. + Weight::from_parts(112_000_000, 0) + .saturating_add(Weight::from_parts(0, 4703)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) + /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(1238), added: 3713, mode: `MaxEncodedLen`) + fn update() -> Weight { + // Proof Size summary in bytes: + // Measured: `74` + // Estimated: `4703` + // Minimum execution time: 101_000_000 picoseconds. + Weight::from_parts(105_000_000, 0) + .saturating_add(Weight::from_parts(0, 4703)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) + /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(1238), added: 3713, mode: `MaxEncodedLen`) + fn remove() -> Weight { + // Proof Size summary in bytes: + // Measured: `74` + // Estimated: `4703` + // Minimum execution time: 112_000_000 picoseconds. + Weight::from_parts(116_000_000, 0) + .saturating_add(Weight::from_parts(0, 4703)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_treasury.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_treasury.rs new file mode 100644 index 00000000000..58540e646d8 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_treasury.rs @@ -0,0 +1,214 @@ +// Copyright Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +//! Autogenerated weights for `pallet_treasury` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-11-28, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `cob`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/debug/polkadot-parachain +// benchmark +// pallet +// --chain=collectives-westend-dev +// --steps=2 +// --repeat=2 +// --pallet=pallet-treasury +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_treasury`. +pub struct WeightInfo(PhantomData); +impl pallet_treasury::WeightInfo for WeightInfo { + /// Storage: `FellowshipTreasury::ProposalCount` (r:1 w:1) + /// Proof: `FellowshipTreasury::ProposalCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `FellowshipTreasury::Approvals` (r:1 w:1) + /// Proof: `FellowshipTreasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + /// Storage: `FellowshipTreasury::Proposals` (r:0 w:1) + /// Proof: `FellowshipTreasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + fn spend_local() -> Weight { + // Proof Size summary in bytes: + // Measured: `42` + // Estimated: `1887` + // Minimum execution time: 117_000_000 picoseconds. + Weight::from_parts(126_000_000, 0) + .saturating_add(Weight::from_parts(0, 1887)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `FellowshipTreasury::ProposalCount` (r:1 w:1) + /// Proof: `FellowshipTreasury::ProposalCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `FellowshipTreasury::Proposals` (r:0 w:1) + /// Proof: `FellowshipTreasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + fn propose_spend() -> Weight { + // Proof Size summary in bytes: + // Measured: `143` + // Estimated: `1489` + // Minimum execution time: 264_000_000 picoseconds. + Weight::from_parts(277_000_000, 0) + .saturating_add(Weight::from_parts(0, 1489)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `FellowshipTreasury::Proposals` (r:1 w:1) + /// Proof: `FellowshipTreasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn reject_proposal() -> Weight { + // Proof Size summary in bytes: + // Measured: `301` + // Estimated: `3593` + // Minimum execution time: 289_000_000 picoseconds. + Weight::from_parts(312_000_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// The range of component `p` is `[0, 99]`. + fn approve_proposal(_p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 0_000 picoseconds. + Weight::from_parts(0, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `FellowshipTreasury::Approvals` (r:1 w:1) + /// Proof: `FellowshipTreasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + fn remove_approval() -> Weight { + // Proof Size summary in bytes: + // Measured: `127` + // Estimated: `1887` + // Minimum execution time: 62_000_000 picoseconds. + Weight::from_parts(65_000_000, 0) + .saturating_add(Weight::from_parts(0, 1887)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `System::Account` (r:199 w:199) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `FellowshipTreasury::Deactivated` (r:1 w:1) + /// Proof: `FellowshipTreasury::Deactivated` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `Balances::InactiveIssuance` (r:1 w:1) + /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `FellowshipTreasury::Approvals` (r:1 w:1) + /// Proof: `FellowshipTreasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + /// Storage: `FellowshipTreasury::Proposals` (r:99 w:99) + /// Proof: `FellowshipTreasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// The range of component `p` is `[0, 99]`. + fn on_initialize_proposals(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `145 + p * (250 ±0)` + // Estimated: `256707 + p * (5206 ±0)` + // Minimum execution time: 218_000_000 picoseconds. + Weight::from_parts(221_000_000, 0) + .saturating_add(Weight::from_parts(0, 256707)) + // Standard Error: 154_515 + .saturating_add(Weight::from_parts(399_232_323, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(p.into()))) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(p.into()))) + .saturating_add(Weight::from_parts(0, 5206).saturating_mul(p.into())) + } + /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:0) + /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(1238), added: 3713, mode: `MaxEncodedLen`) + /// Storage: `FellowshipTreasury::SpendCount` (r:1 w:1) + /// Proof: `FellowshipTreasury::SpendCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `FellowshipTreasury::Spends` (r:0 w:1) + /// Proof: `FellowshipTreasury::Spends` (`max_values`: None, `max_size`: Some(1853), added: 4328, mode: `MaxEncodedLen`) + fn spend() -> Weight { + // Proof Size summary in bytes: + // Measured: `118` + // Estimated: `4703` + // Minimum execution time: 163_000_000 picoseconds. + Weight::from_parts(171_000_000, 0) + .saturating_add(Weight::from_parts(0, 4703)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `FellowshipTreasury::Spends` (r:1 w:1) + /// Proof: `FellowshipTreasury::Spends` (`max_values`: None, `max_size`: Some(1853), added: 4328, mode: `MaxEncodedLen`) + /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) + /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::QueryCounter` (r:1 w:1) + /// Proof: `PolkadotXcm::QueryCounter` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) + /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) + /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::OutboundXcmpMessages` (r:0 w:1) + /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `PolkadotXcm::Queries` (r:0 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn payout() -> Weight { + // Proof Size summary in bytes: + // Measured: `629` + // Estimated: `5318` + // Minimum execution time: 472_000_000 picoseconds. + Weight::from_parts(492_000_000, 0) + .saturating_add(Weight::from_parts(0, 5318)) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(6)) + } + /// Storage: `FellowshipTreasury::Spends` (r:1 w:1) + /// Proof: `FellowshipTreasury::Spends` (`max_values`: None, `max_size`: Some(1853), added: 4328, mode: `MaxEncodedLen`) + /// Storage: `PolkadotXcm::Queries` (r:1 w:1) + /// Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn check_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `383` + // Estimated: `5318` + // Minimum execution time: 211_000_000 picoseconds. + Weight::from_parts(215_000_000, 0) + .saturating_add(Weight::from_parts(0, 5318)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `FellowshipTreasury::Spends` (r:1 w:1) + /// Proof: `FellowshipTreasury::Spends` (`max_values`: None, `max_size`: Some(1853), added: 4328, mode: `MaxEncodedLen`) + fn void_spend() -> Weight { + // Proof Size summary in bytes: + // Measured: `179` + // Estimated: `5318` + // Minimum execution time: 124_000_000 picoseconds. + Weight::from_parts(126_000_000, 0) + .saturating_add(Weight::from_parts(0, 5318)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs index 44d5d1daf32..9b5b709ab82 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs @@ -33,6 +33,7 @@ use parachains_common::{ }; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::xcm_sender::ExponentialPrice; +use westend_runtime_constants::xcm as xcm_constants; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses, @@ -46,8 +47,6 @@ use xcm_builder::{ }; use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; -const FELLOWSHIP_ADMIN_INDEX: u32 = 1; - parameter_types! { pub const WndLocation: MultiLocation = MultiLocation::parent(); pub const RelayNetwork: Option = Some(NetworkId::Westend); @@ -57,7 +56,8 @@ parameter_types! { pub RelayTreasuryLocation: MultiLocation = (Parent, PalletInstance(westend_runtime_constants::TREASURY_PALLET_ID)).into(); pub CheckingAccount: AccountId = PolkadotXcm::check_account(); pub const GovernanceLocation: MultiLocation = MultiLocation::parent(); - pub const FellowshipAdminBodyId: BodyId = BodyId::Index(FELLOWSHIP_ADMIN_INDEX); + pub const FellowshipAdminBodyId: BodyId = BodyId::Index(xcm_constants::body::FELLOWSHIP_ADMIN_INDEX); + pub const TreasurerBodyId: BodyId = BodyId::Index(xcm_constants::body::TREASURER_INDEX); pub AssetHub: MultiLocation = (Parent, Parachain(1000)).into(); pub AssetHubUsdtId: AssetId = (PalletInstance(50), GeneralIndex(1984)).into(); pub UsdtAssetHub: LocatableAssetId = LocatableAssetId { diff --git a/polkadot/runtime/common/src/impls.rs b/polkadot/runtime/common/src/impls.rs index 60e631a03ee..d71c626cd98 100644 --- a/polkadot/runtime/common/src/impls.rs +++ b/polkadot/runtime/common/src/impls.rs @@ -149,8 +149,11 @@ impl TryConvert<&VersionedMultiLocation, xcm::latest::MultiLocation> #[cfg(feature = "runtime-benchmarks")] pub mod benchmarks { use super::VersionedLocatableAsset; + use core::marker::PhantomData; + use frame_support::traits::Get; use pallet_asset_rate::AssetKindFactory; use pallet_treasury::ArgumentsFactory as TreasuryArgumentsFactory; + use sp_core::{ConstU32, ConstU8}; use xcm::prelude::*; /// Provides a factory method for the [`VersionedLocatableAsset`]. @@ -172,12 +175,22 @@ pub mod benchmarks { /// Provide factory methods for the [`VersionedLocatableAsset`] and the `Beneficiary` of the /// [`VersionedMultiLocation`]. The location of the asset is determined as a Parachain with an /// ID equal to the passed seed. - pub struct TreasuryArguments; - impl TreasuryArgumentsFactory - for TreasuryArguments + pub struct TreasuryArguments, ParaId = ConstU32<0>>( + PhantomData<(Parents, ParaId)>, + ); + impl, ParaId: Get> + TreasuryArgumentsFactory + for TreasuryArguments { fn create_asset_kind(seed: u32) -> VersionedLocatableAsset { - AssetRateArguments::create_asset_kind(seed) + VersionedLocatableAsset::V3 { + location: xcm::v3::MultiLocation::new(Parents::get(), X1(Parachain(ParaId::get()))), + asset_id: xcm::v3::MultiLocation::new( + 0, + X2(PalletInstance(seed.try_into().unwrap()), GeneralIndex(seed.into())), + ) + .into(), + } } fn create_beneficiary(seed: [u8; 32]) -> VersionedMultiLocation { VersionedMultiLocation::V3(xcm::v3::MultiLocation::new( diff --git a/polkadot/runtime/westend/constants/src/lib.rs b/polkadot/runtime/westend/constants/src/lib.rs index de3969afb71..c2bce3a1791 100644 --- a/polkadot/runtime/westend/constants/src/lib.rs +++ b/polkadot/runtime/westend/constants/src/lib.rs @@ -124,6 +124,7 @@ pub mod xcm { const ROOT_INDEX: u32 = 0; // The bodies corresponding to the Polkadot OpenGov Origins. pub const FELLOWSHIP_ADMIN_INDEX: u32 = 1; + pub const TREASURER_INDEX: u32 = 2; } } diff --git a/polkadot/runtime/westend/src/xcm_config.rs b/polkadot/runtime/westend/src/xcm_config.rs index 9ab6470f6da..d846b982e9a 100644 --- a/polkadot/runtime/westend/src/xcm_config.rs +++ b/polkadot/runtime/westend/src/xcm_config.rs @@ -21,7 +21,7 @@ use super::{ GeneralAdmin, ParaId, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, StakingAdmin, TransactionByteFee, Treasury, WeightToFee, XcmPallet, }; - +use crate::governance::pallet_custom_origins::Treasurer; use frame_support::{ match_types, parameter_types, traits::{Everything, Nothing}, @@ -34,7 +34,9 @@ use runtime_common::{ }; use sp_core::ConstU32; use westend_runtime_constants::{ - currency::CENTS, system_parachain::*, xcm::body::FELLOWSHIP_ADMIN_INDEX, + currency::CENTS, + system_parachain::*, + xcm::body::{FELLOWSHIP_ADMIN_INDEX, TREASURER_INDEX}, }; use xcm::latest::prelude::*; use xcm_builder::{ @@ -198,6 +200,8 @@ parameter_types! { pub const StakingAdminBodyId: BodyId = BodyId::Defense; // FellowshipAdmin pluralistic body. pub const FellowshipAdminBodyId: BodyId = BodyId::Index(FELLOWSHIP_ADMIN_INDEX); + // `Treasurer` pluralistic body. + pub const TreasurerBodyId: BodyId = BodyId::Index(TREASURER_INDEX); } /// Type to convert the `GeneralAdmin` origin to a Plurality `MultiLocation` value. @@ -220,6 +224,9 @@ pub type StakingAdminToPlurality = pub type FellowshipAdminToPlurality = OriginToPluralityVoice; +/// Type to convert the `Treasurer` origin to a Plurality `MultiLocation` value. +pub type TreasurerToPlurality = OriginToPluralityVoice; + /// Type to convert a pallet `Origin` type value into a `MultiLocation` value which represents an /// interior location of this chain for a destination chain. pub type LocalPalletOriginToLocation = ( @@ -229,6 +236,8 @@ pub type LocalPalletOriginToLocation = ( StakingAdminToPlurality, // FellowshipAdmin origin to be used in XCM as a corresponding Plurality `MultiLocation` value. FellowshipAdminToPlurality, + // `Treasurer` origin to be used in XCM as a corresponding Plurality `MultiLocation` value. + TreasurerToPlurality, ); impl pallet_xcm::Config for Runtime { diff --git a/prdoc/pr_2532.prdoc b/prdoc/pr_2532.prdoc new file mode 100644 index 00000000000..d0df0ee4aca --- /dev/null +++ b/prdoc/pr_2532.prdoc @@ -0,0 +1,11 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Westend Fellowship Treasury + +doc: + - audience: Runtime User + description: | + Treasury Pallet Instance for the Fellowship in Westend Collectives. + +crates: [ ] diff --git a/substrate/frame/treasury/src/benchmarking.rs b/substrate/frame/treasury/src/benchmarking.rs index 61fe29dafca..0b9999e37fb 100644 --- a/substrate/frame/treasury/src/benchmarking.rs +++ b/substrate/frame/treasury/src/benchmarking.rs @@ -78,8 +78,7 @@ fn create_approved_proposals, I: 'static>(n: u32) -> Result<(), &'s #[allow(deprecated)] Treasury::::propose_spend(RawOrigin::Signed(caller).into(), value, lookup)?; let proposal_id = >::get() - 1; - #[allow(deprecated)] - Treasury::::approve_proposal(RawOrigin::Root.into(), proposal_id)?; + Approvals::::try_append(proposal_id).unwrap(); } ensure!(>::get().len() == n as usize, "Not all approved"); Ok(()) @@ -163,6 +162,8 @@ mod benchmarks { fn approve_proposal( p: Linear<0, { T::MaxApprovals::get() - 1 }>, ) -> Result<(), BenchmarkError> { + let approve_origin = + T::ApproveOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; create_approved_proposals::(p)?; let (caller, value, beneficiary_lookup) = setup_proposal::(SEED); #[allow(deprecated)] @@ -172,8 +173,6 @@ mod benchmarks { beneficiary_lookup, )?; let proposal_id = Treasury::::proposal_count() - 1; - let approve_origin = - T::ApproveOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; #[extrinsic_call] _(approve_origin as T::RuntimeOrigin, proposal_id); @@ -191,8 +190,7 @@ mod benchmarks { beneficiary_lookup, )?; let proposal_id = Treasury::::proposal_count() - 1; - #[allow(deprecated)] - Treasury::::approve_proposal(RawOrigin::Root.into(), proposal_id)?; + Approvals::::try_append(proposal_id).unwrap(); let reject_origin = T::RejectOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?; -- GitLab From f6ae145813b2e213b39f09f713d3ccbdd9376f6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Fri, 8 Dec 2023 16:10:58 +0100 Subject: [PATCH 29/59] Update proc-macro-crate (#2660) --- Cargo.lock | 52 ++++++++----------- .../parachain-system/proc-macro/Cargo.toml | 2 +- polkadot/node/gum/proc-macro/Cargo.toml | 2 +- substrate/client/chain-spec/derive/Cargo.toml | 2 +- .../client/tracing/proc-macro/Cargo.toml | 2 +- substrate/frame/contracts/fixtures/Cargo.toml | 2 +- .../solution-type/Cargo.toml | 2 +- .../frame/staking/reward-curve/Cargo.toml | 2 +- .../frame/support/procedural/tools/Cargo.toml | 2 +- .../primitives/api/proc-macro/Cargo.toml | 2 +- .../runtime-interface/proc-macro/Cargo.toml | 2 +- 11 files changed, 31 insertions(+), 41 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ee815868957..11e4de35e45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3646,7 +3646,7 @@ dependencies = [ name = "cumulus-pallet-parachain-system-proc-macro" version = "0.1.0" dependencies = [ - "proc-macro-crate 2.0.0", + "proc-macro-crate 2.0.1", "proc-macro2", "quote", "syn 2.0.39", @@ -5381,7 +5381,7 @@ dependencies = [ "frame-election-provider-support", "frame-support", "parity-scale-codec", - "proc-macro-crate 2.0.0", + "proc-macro-crate 2.0.1", "proc-macro2", "quote", "scale-info", @@ -5547,7 +5547,7 @@ name = "frame-support-procedural-tools" version = "4.0.0-dev" dependencies = [ "frame-support-procedural-tools-derive", - "proc-macro-crate 2.0.0", + "proc-macro-crate 2.0.1", "proc-macro2", "quote", "syn 2.0.39", @@ -9564,7 +9564,7 @@ dependencies = [ "parity-wasm", "sp-runtime", "tempfile", - "toml 0.8.8", + "toml 0.8.2", "twox-hash", "wat", ] @@ -10773,7 +10773,7 @@ dependencies = [ name = "pallet-staking-reward-curve" version = "4.0.0-dev" dependencies = [ - "proc-macro-crate 2.0.0", + "proc-macro-crate 2.0.1", "proc-macro2", "quote", "sp-runtime", @@ -13676,11 +13676,12 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" +checksum = "97dc5fea232fc28d2f597b37c4876b348a40e33f3b02cc975c8d006d78d94b1a" dependencies = [ - "toml_edit 0.20.7", + "toml_datetime", + "toml_edit 0.20.2", ] [[package]] @@ -15035,7 +15036,7 @@ dependencies = [ name = "sc-chain-spec-derive" version = "4.0.0-dev" dependencies = [ - "proc-macro-crate 2.0.0", + "proc-macro-crate 2.0.1", "proc-macro2", "quote", "syn 2.0.39", @@ -16291,7 +16292,7 @@ dependencies = [ name = "sc-tracing-proc-macro" version = "4.0.0-dev" dependencies = [ - "proc-macro-crate 2.0.0", + "proc-macro-crate 2.0.1", "proc-macro2", "quote", "syn 2.0.39", @@ -17205,7 +17206,7 @@ dependencies = [ "assert_matches", "blake2 0.10.6", "expander 2.0.0", - "proc-macro-crate 2.0.0", + "proc-macro-crate 2.0.1", "proc-macro2", "quote", "syn 2.0.39", @@ -17882,7 +17883,7 @@ version = "11.0.0" dependencies = [ "Inflector", "expander 2.0.0", - "proc-macro-crate 2.0.0", + "proc-macro-crate 2.0.1", "proc-macro2", "quote", "syn 2.0.39", @@ -19545,21 +19546,21 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.8" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" +checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.21.0", + "toml_edit 0.20.2", ] [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" dependencies = [ "serde", ] @@ -19579,20 +19580,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.20.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" -dependencies = [ - "indexmap 2.0.0", - "toml_datetime", - "winnow", -] - -[[package]] -name = "toml_edit" -version = "0.21.0" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ "indexmap 2.0.0", "serde", @@ -19702,7 +19692,7 @@ version = "1.0.0" dependencies = [ "assert_matches", "expander 2.0.0", - "proc-macro-crate 2.0.0", + "proc-macro-crate 2.0.1", "proc-macro2", "quote", "syn 2.0.39", diff --git a/cumulus/pallets/parachain-system/proc-macro/Cargo.toml b/cumulus/pallets/parachain-system/proc-macro/Cargo.toml index a0f18237c79..ffe44c32902 100644 --- a/cumulus/pallets/parachain-system/proc-macro/Cargo.toml +++ b/cumulus/pallets/parachain-system/proc-macro/Cargo.toml @@ -13,7 +13,7 @@ proc-macro = true syn = "2.0.39" proc-macro2 = "1.0.64" quote = "1.0.33" -proc-macro-crate = "2.0.0" +proc-macro-crate = "2.0.1" [features] default = ["std"] diff --git a/polkadot/node/gum/proc-macro/Cargo.toml b/polkadot/node/gum/proc-macro/Cargo.toml index 731798cc01e..055eafa1b9c 100644 --- a/polkadot/node/gum/proc-macro/Cargo.toml +++ b/polkadot/node/gum/proc-macro/Cargo.toml @@ -16,7 +16,7 @@ proc-macro = true syn = { version = "2.0.39", features = ["extra-traits", "full"] } quote = "1.0.28" proc-macro2 = "1.0.56" -proc-macro-crate = "2.0.0" +proc-macro-crate = "2.0.1" expander = "2.0.0" [dev-dependencies] diff --git a/substrate/client/chain-spec/derive/Cargo.toml b/substrate/client/chain-spec/derive/Cargo.toml index 4dea856b03f..36ad67ce1c5 100644 --- a/substrate/client/chain-spec/derive/Cargo.toml +++ b/substrate/client/chain-spec/derive/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -proc-macro-crate = "2.0.0" +proc-macro-crate = "2.0.1" proc-macro2 = "1.0.56" quote = "1.0.28" syn = "2.0.39" diff --git a/substrate/client/tracing/proc-macro/Cargo.toml b/substrate/client/tracing/proc-macro/Cargo.toml index 1d5d638c49b..673ef50aead 100644 --- a/substrate/client/tracing/proc-macro/Cargo.toml +++ b/substrate/client/tracing/proc-macro/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -proc-macro-crate = "2.0.0" +proc-macro-crate = "2.0.1" proc-macro2 = "1.0.56" quote = { version = "1.0.28", features = ["proc-macro"] } syn = { version = "2.0.39", features = ["extra-traits", "full", "parsing", "proc-macro"] } diff --git a/substrate/frame/contracts/fixtures/Cargo.toml b/substrate/frame/contracts/fixtures/Cargo.toml index 2e95354ddc9..1c247bf22c0 100644 --- a/substrate/frame/contracts/fixtures/Cargo.toml +++ b/substrate/frame/contracts/fixtures/Cargo.toml @@ -16,7 +16,7 @@ anyhow = "1.0.0" [build-dependencies] parity-wasm = "0.45.0" tempfile = "3.8.1" -toml = "0.8.8" +toml = "0.8.2" twox-hash = "1.6.3" anyhow = "1.0.0" cfg-if = { version = "1.0", default-features = false } diff --git a/substrate/frame/election-provider-support/solution-type/Cargo.toml b/substrate/frame/election-provider-support/solution-type/Cargo.toml index 5bf84daf52d..2e95163fc26 100644 --- a/substrate/frame/election-provider-support/solution-type/Cargo.toml +++ b/substrate/frame/election-provider-support/solution-type/Cargo.toml @@ -18,7 +18,7 @@ proc-macro = true syn = { version = "2.0.39", features = ["full", "visit"] } quote = "1.0.28" proc-macro2 = "1.0.56" -proc-macro-crate = "2.0.0" +proc-macro-crate = "2.0.1" [dev-dependencies] parity-scale-codec = "3.6.1" diff --git a/substrate/frame/staking/reward-curve/Cargo.toml b/substrate/frame/staking/reward-curve/Cargo.toml index d3a1f439cf9..1e5717e4075 100644 --- a/substrate/frame/staking/reward-curve/Cargo.toml +++ b/substrate/frame/staking/reward-curve/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -proc-macro-crate = "2.0.0" +proc-macro-crate = "2.0.1" proc-macro2 = "1.0.56" quote = "1.0.28" syn = { version = "2.0.39", features = ["full", "visit"] } diff --git a/substrate/frame/support/procedural/tools/Cargo.toml b/substrate/frame/support/procedural/tools/Cargo.toml index bc5cc7fdda5..0b04d64a4bc 100644 --- a/substrate/frame/support/procedural/tools/Cargo.toml +++ b/substrate/frame/support/procedural/tools/Cargo.toml @@ -12,7 +12,7 @@ description = "Proc macro helpers for procedural macros" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -proc-macro-crate = "2.0.0" +proc-macro-crate = "2.0.1" proc-macro2 = "1.0.56" quote = "1.0.28" syn = { version = "2.0.39", features = ["extra-traits", "full", "visit"] } diff --git a/substrate/primitives/api/proc-macro/Cargo.toml b/substrate/primitives/api/proc-macro/Cargo.toml index 46d05c78b4a..487b2cd9b84 100644 --- a/substrate/primitives/api/proc-macro/Cargo.toml +++ b/substrate/primitives/api/proc-macro/Cargo.toml @@ -20,7 +20,7 @@ quote = "1.0.28" syn = { version = "2.0.39", features = ["extra-traits", "fold", "full", "visit"] } proc-macro2 = "1.0.56" blake2 = { version = "0.10.4", default-features = false } -proc-macro-crate = "2.0.0" +proc-macro-crate = "2.0.1" expander = "2.0.0" Inflector = "0.11.4" diff --git a/substrate/primitives/runtime-interface/proc-macro/Cargo.toml b/substrate/primitives/runtime-interface/proc-macro/Cargo.toml index efabaee3aeb..8179e88546c 100644 --- a/substrate/primitives/runtime-interface/proc-macro/Cargo.toml +++ b/substrate/primitives/runtime-interface/proc-macro/Cargo.toml @@ -17,7 +17,7 @@ proc-macro = true [dependencies] Inflector = "0.11.4" -proc-macro-crate = "2.0.0" +proc-macro-crate = "2.0.1" proc-macro2 = "1.0.56" quote = "1.0.28" expander = "2.0.0" -- GitLab From e5dc8ed8f5a137298a8c4f9ead509ea13682d7e6 Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe <49718502+alexggh@users.noreply.github.com> Date: Sun, 10 Dec 2023 23:22:00 +0200 Subject: [PATCH 30/59] [ci] fix test-frame-ui job (#2672) The test frame ui started failing consistently on latest master [1]. I assume it was because of a race between https://github.com/paritytech/polkadot-sdk/pull/1343 which introduced this warning and a PR that updated our tooling version, hence the warnings don't match perfectly, so regenerated them with `TRYBUILD=overwrite` as the test suggests. [1] https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/4666766 --------- Signed-off-by: Alexandru Gheorghe --- .../number_of_pallets_exceeds_tuple_size.stderr | 7 ++++++- .../test/tests/pallet_ui/task_condition_invalid_arg.stderr | 1 + .../test/tests/pallet_ui/task_invalid_condition.stderr | 1 + .../support/test/tests/pallet_ui/task_invalid_list.stderr | 1 + .../test/tests/pallet_ui/task_invalid_weight.stderr | 1 + 5 files changed, 10 insertions(+), 1 deletion(-) diff --git a/substrate/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.stderr b/substrate/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.stderr index 6838b7f4c0a..3b6329c650f 100644 --- a/substrate/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.stderr +++ b/substrate/frame/support/test/tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.stderr @@ -81,6 +81,11 @@ error[E0412]: cannot find type `RuntimeTask` in this scope --> tests/construct_runtime_ui/number_of_pallets_exceeds_tuple_size.rs:39:1 | 39 | #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you might have meant to use the associated type: `Self::RuntimeTask` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the macro `frame_system::config_preludes::TestDefaultConfig` which comes from the expansion of the macro `frame_support::macro_magic::forward_tokens_verbatim` (in Nightly builds, run with -Z macro-backtrace for more info) +help: you might have meant to use the associated type + --> $WORKSPACE/substrate/frame/system/src/lib.rs + | + | type Self::RuntimeTask = (); + | ++++++ diff --git a/substrate/frame/support/test/tests/pallet_ui/task_condition_invalid_arg.stderr b/substrate/frame/support/test/tests/pallet_ui/task_condition_invalid_arg.stderr index ef259656688..9c7bad8119f 100644 --- a/substrate/frame/support/test/tests/pallet_ui/task_condition_invalid_arg.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/task_condition_invalid_arg.stderr @@ -5,6 +5,7 @@ error: unused import: `frame_system::pallet_prelude::OriginFor` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D unused-imports` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(unused_imports)]` error[E0308]: mismatched types --> tests/pallet_ui/task_condition_invalid_arg.rs:35:10 diff --git a/substrate/frame/support/test/tests/pallet_ui/task_invalid_condition.stderr b/substrate/frame/support/test/tests/pallet_ui/task_invalid_condition.stderr index ff57017b3fd..05c0ba5eecf 100644 --- a/substrate/frame/support/test/tests/pallet_ui/task_invalid_condition.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/task_invalid_condition.stderr @@ -5,6 +5,7 @@ error: unused import: `frame_system::pallet_prelude::OriginFor` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D unused-imports` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(unused_imports)]` error[E0308]: mismatched types --> tests/pallet_ui/task_invalid_condition.rs:18:1 diff --git a/substrate/frame/support/test/tests/pallet_ui/task_invalid_list.stderr b/substrate/frame/support/test/tests/pallet_ui/task_invalid_list.stderr index 8dda0c3a1aa..536d02610cb 100644 --- a/substrate/frame/support/test/tests/pallet_ui/task_invalid_list.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/task_invalid_list.stderr @@ -5,6 +5,7 @@ error: unused import: `frame_system::pallet_prelude::OriginFor` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D unused-imports` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(unused_imports)]` error[E0689]: can't call method `map` on ambiguous numeric type `{integer}` --> tests/pallet_ui/task_invalid_list.rs:18:1 diff --git a/substrate/frame/support/test/tests/pallet_ui/task_invalid_weight.stderr b/substrate/frame/support/test/tests/pallet_ui/task_invalid_weight.stderr index 3537bb59028..24e925a0699 100644 --- a/substrate/frame/support/test/tests/pallet_ui/task_invalid_weight.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/task_invalid_weight.stderr @@ -5,6 +5,7 @@ error: unused import: `frame_system::pallet_prelude::OriginFor` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D unused-imports` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(unused_imports)]` error[E0308]: mismatched types --> tests/pallet_ui/task_invalid_weight.rs:18:1 -- GitLab From 6cedb0c78d33d64596e5beabf5f09bf81f36953c Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Mon, 11 Dec 2023 12:07:01 +0200 Subject: [PATCH 31/59] pallet-xcm: fix test benchmarks (#2679) For some reason original PR passed CI - when it shouldn't have. Fix `pallet-xcm` test benchmarks. --- polkadot/xcm/pallet-xcm/src/mock.rs | 30 +++++++++++-------- .../pallet-xcm/src/tests/assets_transfer.rs | 29 +++++++++++++----- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index 9a734d0f276..e7f5870c914 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -589,10 +589,23 @@ impl super::benchmarking::Config for Test { let asset_amount = 10u128; let fee_amount = 2u128; + let existential_deposit = ExistentialDeposit::get(); + let caller = frame_benchmarking::whitelisted_caller(); + + // Give some multiple of the existential deposit + let balance = asset_amount + existential_deposit * 1000; + let _ = >::make_free_balance_be( + &caller, balance, + ); // create sufficient foreign asset USDT let usdt_initial_local_amount = fee_amount * 10; - let (usdt_chain, _, usdt_id_multilocation) = - set_up_foreign_asset(USDT_PARA_ID, None, usdt_initial_local_amount, true); + let (usdt_chain, _, usdt_id_multilocation) = set_up_foreign_asset( + USDT_PARA_ID, + None, + caller.clone(), + usdt_initial_local_amount, + true, + ); // native assets transfer destination is USDT chain (teleport trust only for USDT) let dest = usdt_chain; @@ -602,20 +615,13 @@ impl super::benchmarking::Config for Test { // native asset to transfer (not used for fees) - local reserve (MultiLocation::here(), asset_amount).into(), ); - - let existential_deposit = ExistentialDeposit::get(); - let caller = frame_benchmarking::whitelisted_caller(); - // Give some multiple of the existential deposit - let balance = asset_amount + existential_deposit * 1000; - let _ = >::make_free_balance_be( - &caller, balance, - ); - // verify initial balance + // verify initial balances assert_eq!(Balances::free_balance(&caller), balance); + assert_eq!(Assets::balance(usdt_id_multilocation, &caller), usdt_initial_local_amount); // verify transferred successfully let verify = Box::new(move || { - // verify balance after transfer, decreased by transferred amount + // verify balances after transfer, decreased by transferred amounts assert_eq!(Balances::free_balance(&caller), balance - asset_amount); assert_eq!( Assets::balance(usdt_id_multilocation, &caller), diff --git a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs index fb0bef26ebd..6893bae2b6c 100644 --- a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs @@ -244,6 +244,7 @@ fn reserve_transfer_assets_with_paid_router_works() { pub(crate) fn set_up_foreign_asset( reserve_para_id: u32, inner_junction: Option, + benficiary: AccountId, initial_amount: u128, is_sufficient: bool, ) -> (MultiLocation, AccountId, MultiLocation) { @@ -271,7 +272,7 @@ pub(crate) fn set_up_foreign_asset( assert_ok!(Assets::mint( RuntimeOrigin::signed(BOB), foreign_asset_id_multilocation, - ALICE, + benficiary, initial_amount )); @@ -440,6 +441,7 @@ fn destination_asset_reserve_and_local_fee_reserve_call( set_up_foreign_asset( FOREIGN_ASSET_RESERVE_PARA_ID, Some(FOREIGN_ASSET_INNER_JUNCTION), + ALICE, foreign_initial_amount, false, ); @@ -595,6 +597,7 @@ fn remote_asset_reserve_and_local_fee_reserve_call_disallowed( let (_, _, foreign_asset_id_multilocation) = set_up_foreign_asset( FOREIGN_ASSET_RESERVE_PARA_ID, Some(FOREIGN_ASSET_INNER_JUNCTION), + ALICE, foreign_initial_amount, false, ); @@ -712,6 +715,7 @@ fn local_asset_reserve_and_destination_fee_reserve_call( set_up_foreign_asset( USDC_RESERVE_PARA_ID, Some(USDC_INNER_JUNCTION), + ALICE, usdc_initial_local_amount, true, ); @@ -870,6 +874,7 @@ fn destination_asset_reserve_and_destination_fee_reserve_call( set_up_foreign_asset( FOREIGN_ASSET_RESERVE_PARA_ID, Some(FOREIGN_ASSET_INNER_JUNCTION), + ALICE, foreign_initial_amount, true, ); @@ -1013,6 +1018,7 @@ fn remote_asset_reserve_and_destination_fee_reserve_call_disallowed( let (usdc_chain, _, usdc_id_multilocation) = set_up_foreign_asset( USDC_RESERVE_PARA_ID, Some(USDC_INNER_JUNCTION), + ALICE, usdc_initial_local_amount, true, ); @@ -1022,6 +1028,7 @@ fn remote_asset_reserve_and_destination_fee_reserve_call_disallowed( let (_, _, foreign_asset_id_multilocation) = set_up_foreign_asset( FOREIGN_ASSET_RESERVE_PARA_ID, Some(FOREIGN_ASSET_INNER_JUNCTION), + ALICE, foreign_initial_amount, false, ); @@ -1135,6 +1142,7 @@ fn local_asset_reserve_and_remote_fee_reserve_call_disallowed( let (_, usdc_chain_sovereign_account, usdc_id_multilocation) = set_up_foreign_asset( USDC_RESERVE_PARA_ID, Some(USDC_INNER_JUNCTION), + ALICE, usdc_initial_local_amount, true, ); @@ -1244,6 +1252,7 @@ fn destination_asset_reserve_and_remote_fee_reserve_call_disallowed( let (_, usdc_chain_sovereign_account, usdc_id_multilocation) = set_up_foreign_asset( USDC_RESERVE_PARA_ID, Some(USDC_INNER_JUNCTION), + ALICE, usdc_initial_local_amount, true, ); @@ -1254,6 +1263,7 @@ fn destination_asset_reserve_and_remote_fee_reserve_call_disallowed( set_up_foreign_asset( FOREIGN_ASSET_RESERVE_PARA_ID, Some(FOREIGN_ASSET_INNER_JUNCTION), + ALICE, foreign_initial_amount, false, ); @@ -1383,6 +1393,7 @@ fn remote_asset_reserve_and_remote_fee_reserve_call( set_up_foreign_asset( USDC_RESERVE_PARA_ID, Some(USDC_INNER_JUNCTION), + ALICE, usdc_initial_local_amount, true, ); @@ -1526,7 +1537,7 @@ fn local_asset_reserve_and_teleported_fee_call( // create sufficient foreign asset USDT let usdt_initial_local_amount = 42; let (usdt_chain, usdt_chain_sovereign_account, usdt_id_multilocation) = - set_up_foreign_asset(USDT_PARA_ID, None, usdt_initial_local_amount, true); + set_up_foreign_asset(USDT_PARA_ID, None, ALICE, usdt_initial_local_amount, true); // native assets transfer destination is USDT chain (teleport trust only for USDT) let dest = usdt_chain; @@ -1675,7 +1686,7 @@ fn destination_asset_reserve_and_teleported_fee_call( // create sufficient foreign asset USDT let usdt_initial_local_amount = 42; let (_, usdt_chain_sovereign_account, usdt_id_multilocation) = - set_up_foreign_asset(USDT_PARA_ID, None, usdt_initial_local_amount, true); + set_up_foreign_asset(USDT_PARA_ID, None, ALICE, usdt_initial_local_amount, true); // create non-sufficient foreign asset BLA let foreign_initial_amount = 142; @@ -1683,6 +1694,7 @@ fn destination_asset_reserve_and_teleported_fee_call( set_up_foreign_asset( FOREIGN_ASSET_RESERVE_PARA_ID, Some(FOREIGN_ASSET_INNER_JUNCTION), + ALICE, foreign_initial_amount, false, ); @@ -1845,13 +1857,14 @@ fn remote_asset_reserve_and_teleported_fee_reserve_call_disallowed( // create sufficient foreign asset USDT let usdt_initial_local_amount = 42; let (usdt_chain, usdt_chain_sovereign_account, usdt_id_multilocation) = - set_up_foreign_asset(USDT_PARA_ID, None, usdt_initial_local_amount, true); + set_up_foreign_asset(USDT_PARA_ID, None, ALICE, usdt_initial_local_amount, true); // create non-sufficient foreign asset BLA let foreign_initial_amount = 142; let (_, reserve_sovereign_account, foreign_asset_id_multilocation) = set_up_foreign_asset( FOREIGN_ASSET_RESERVE_PARA_ID, Some(FOREIGN_ASSET_INNER_JUNCTION), + ALICE, foreign_initial_amount, false, ); @@ -1952,7 +1965,7 @@ fn reserve_transfer_assets_with_teleportable_asset_disallowed() { // create sufficient foreign asset USDT let usdt_initial_local_amount = 42; let (usdt_chain, usdt_chain_sovereign_account, usdt_id_multilocation) = - set_up_foreign_asset(USDT_PARA_ID, None, usdt_initial_local_amount, true); + set_up_foreign_asset(USDT_PARA_ID, None, ALICE, usdt_initial_local_amount, true); // transfer destination is USDT chain (foreign asset needs to go through its reserve chain) let dest = usdt_chain; @@ -2037,6 +2050,7 @@ fn intermediary_error_reverts_side_effects() { let (_, usdc_chain_sovereign_account, usdc_id_multilocation) = set_up_foreign_asset( USDC_RESERVE_PARA_ID, Some(USDC_INNER_JUNCTION), + ALICE, usdc_initial_local_amount, true, ); @@ -2106,7 +2120,7 @@ fn teleport_asset_using_local_fee_reserve_call( // create non-sufficient foreign asset USDT let usdt_initial_local_amount = 42; let (usdt_chain, usdt_chain_sovereign_account, usdt_id_multilocation) = - set_up_foreign_asset(USDT_PARA_ID, None, usdt_initial_local_amount, false); + set_up_foreign_asset(USDT_PARA_ID, None, ALICE, usdt_initial_local_amount, false); // transfer destination is reserve location (no teleport trust) let dest = usdt_chain; @@ -2258,6 +2272,7 @@ fn teleported_asset_using_destination_reserve_fee_call( set_up_foreign_asset( FOREIGN_ASSET_RESERVE_PARA_ID, Some(FOREIGN_ASSET_INNER_JUNCTION), + ALICE, foreign_initial_amount, true, ); @@ -2265,7 +2280,7 @@ fn teleported_asset_using_destination_reserve_fee_call( // create non-sufficient foreign asset USDT let usdt_initial_local_amount = 42; let (_, usdt_chain_sovereign_account, usdt_id_multilocation) = - set_up_foreign_asset(USDT_PARA_ID, None, usdt_initial_local_amount, false); + set_up_foreign_asset(USDT_PARA_ID, None, ALICE, usdt_initial_local_amount, false); // transfer destination is BLA reserve location let dest = reserve_location; -- GitLab From 84c932cd8ace8e389f753608e7a796f77ccdb00d Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe <49718502+alexggh@users.noreply.github.com> Date: Mon, 11 Dec 2023 12:49:11 +0200 Subject: [PATCH 32/59] Add feature flag to enable v2 assignments (#2444) Scaffold everything, so that we can enable v2 assignments via a node feature bit, once all nodes have upgraded to the new protocol. Implements: https://github.com/paritytech/polkadot-sdk/issues/628 --------- Signed-off-by: Alexandru Gheorghe --- .../node/core/approval-voting/src/criteria.rs | 4 +- .../node/core/approval-voting/src/import.rs | 339 ++++++++++-------- .../node/core/approval-voting/src/tests.rs | 14 +- .../core/dispute-coordinator/src/tests.rs | 43 ++- .../src/pov_requester/mod.rs | 10 +- .../src/requester/tests.rs | 8 +- .../src/tests/state.rs | 7 +- .../src/collator_side/tests/mod.rs | 12 +- .../dispute-distribution/src/tests/mod.rs | 22 +- .../src/legacy_v1/tests.rs | 57 ++- .../node/subsystem-util/src/runtime/mod.rs | 27 +- polkadot/primitives/src/vstaging/mod.rs | 16 + 12 files changed, 393 insertions(+), 166 deletions(-) diff --git a/polkadot/node/core/approval-voting/src/criteria.rs b/polkadot/node/core/approval-voting/src/criteria.rs index acad1c66a43..b6ad1971ef6 100644 --- a/polkadot/node/core/approval-voting/src/criteria.rs +++ b/polkadot/node/core/approval-voting/src/criteria.rs @@ -261,6 +261,7 @@ pub(crate) trait AssignmentCriteria { relay_vrf_story: RelayVRFStory, config: &Config, leaving_cores: Vec<(CandidateHash, CoreIndex, GroupIndex)>, + enable_v2_assignments: bool, ) -> HashMap; fn check_assignment_cert( @@ -284,8 +285,9 @@ impl AssignmentCriteria for RealAssignmentCriteria { relay_vrf_story: RelayVRFStory, config: &Config, leaving_cores: Vec<(CandidateHash, CoreIndex, GroupIndex)>, + enable_v2_assignments: bool, ) -> HashMap { - compute_assignments(keystore, relay_vrf_story, config, leaving_cores, false) + compute_assignments(keystore, relay_vrf_story, config, leaving_cores, enable_v2_assignments) } fn check_assignment_cert( diff --git a/polkadot/node/core/approval-voting/src/import.rs b/polkadot/node/core/approval-voting/src/import.rs index d7667e8e405..a64685326cf 100644 --- a/polkadot/node/core/approval-voting/src/import.rs +++ b/polkadot/node/core/approval-voting/src/import.rs @@ -45,8 +45,8 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_util::{determine_new_blocks, runtime::RuntimeInfo}; use polkadot_primitives::{ - BlockNumber, CandidateEvent, CandidateHash, CandidateReceipt, ConsensusLog, CoreIndex, - GroupIndex, Hash, Header, SessionIndex, + vstaging::node_features, BlockNumber, CandidateEvent, CandidateHash, CandidateReceipt, + ConsensusLog, CoreIndex, GroupIndex, Hash, Header, SessionIndex, }; use sc_keystore::LocalKeystore; use sp_consensus_slots::Slot; @@ -60,7 +60,7 @@ use super::approval_db::v2; use crate::{ backend::{Backend, OverlayedBackend}, criteria::{AssignmentCriteria, OurAssignment}, - get_session_info, + get_extended_session_info, get_session_info, persisted_entries::CandidateEntry, time::{slot_number_to_tick, Tick}, }; @@ -214,10 +214,21 @@ async fn imported_block_info( } }; + let extended_session_info = + get_extended_session_info(env.runtime_info, ctx.sender(), block_hash, session_index).await; + let enable_v2_assignments = extended_session_info.map_or(false, |extended_session_info| { + *extended_session_info + .node_features + .get(node_features::FeatureIndex::EnableAssignmentsV2 as usize) + .as_deref() + .unwrap_or(&false) + }); + let session_info = get_session_info(env.runtime_info, ctx.sender(), block_hash, session_index) .await .ok_or(ImportedBlockInfoError::SessionInfoUnavailable)?; + gum::debug!(target: LOG_TARGET, ?enable_v2_assignments, "V2 assignments"); let (assignments, slot, relay_vrf_story) = { let unsafe_vrf = approval_types::v1::babe_unsafe_vrf_info(&block_header); @@ -239,6 +250,7 @@ async fn imported_block_info( .iter() .map(|(c_hash, _, core, group)| (*c_hash, *core, *group)) .collect(), + enable_v2_assignments, ); (assignments, slot, relay_vrf) @@ -603,6 +615,7 @@ pub(crate) mod tests { use polkadot_node_subsystem_test_helpers::make_subsystem_context; use polkadot_node_subsystem_util::database::Database; use polkadot_primitives::{ + vstaging::{node_features::FeatureIndex, NodeFeatures}, ExecutorParams, Id as ParaId, IndexedVec, SessionInfo, ValidatorId, ValidatorIndex, }; pub(crate) use sp_consensus_babe::{ @@ -639,7 +652,7 @@ pub(crate) mod tests { keystore: Arc::new(LocalKeystore::in_memory()), slot_duration_millis: 6_000, clock: Box::new(MockClock::default()), - assignment_criteria: Box::new(MockAssignmentCriteria), + assignment_criteria: Box::new(MockAssignmentCriteria::default()), spans: HashMap::new(), } } @@ -654,7 +667,10 @@ pub(crate) mod tests { ) } - struct MockAssignmentCriteria; + #[derive(Default)] + struct MockAssignmentCriteria { + enable_v2: bool, + } impl AssignmentCriteria for MockAssignmentCriteria { fn compute_assignments( @@ -667,7 +683,9 @@ pub(crate) mod tests { polkadot_primitives::CoreIndex, polkadot_primitives::GroupIndex, )>, + enable_assignments_v2: bool, ) -> HashMap { + assert_eq!(enable_assignments_v2, self.enable_v2); HashMap::new() } @@ -711,154 +729,164 @@ pub(crate) mod tests { #[test] fn imported_block_info_is_good() { - let pool = TaskExecutor::new(); - let (mut ctx, mut handle) = - make_subsystem_context::(pool.clone()); - - let session = 5; - let session_info = dummy_session_info(session); - - let slot = Slot::from(10); - - let header = Header { - digest: { - let mut d = Digest::default(); - let vrf_signature = garbage_vrf_signature(); - d.push(DigestItem::babe_pre_digest(PreDigest::SecondaryVRF( - SecondaryVRFPreDigest { authority_index: 0, slot, vrf_signature }, - ))); - - d - }, - extrinsics_root: Default::default(), - number: 5, - state_root: Default::default(), - parent_hash: Default::default(), - }; - - let hash = header.hash(); - let make_candidate = |para_id| { - let mut r = dummy_candidate_receipt(dummy_hash()); - r.descriptor.para_id = para_id; - r.descriptor.relay_parent = hash; - r - }; - let candidates = vec![ - (make_candidate(1.into()), CoreIndex(0), GroupIndex(2)), - (make_candidate(2.into()), CoreIndex(1), GroupIndex(3)), - ]; + for enable_v2 in [false, true] { + let pool = TaskExecutor::new(); + let (mut ctx, mut handle) = + make_subsystem_context::(pool.clone()); + + let session = 5; + let session_info = dummy_session_info(session); + + let slot = Slot::from(10); + let header = Header { + digest: { + let mut d = Digest::default(); + let vrf_signature = garbage_vrf_signature(); + d.push(DigestItem::babe_pre_digest(PreDigest::SecondaryVRF( + SecondaryVRFPreDigest { authority_index: 0, slot, vrf_signature }, + ))); + + d + }, + extrinsics_root: Default::default(), + number: 5, + state_root: Default::default(), + parent_hash: Default::default(), + }; - let inclusion_events = candidates - .iter() - .cloned() - .map(|(r, c, g)| CandidateEvent::CandidateIncluded(r, Vec::new().into(), c, g)) - .collect::>(); + let hash = header.hash(); + let make_candidate = |para_id| { + let mut r = dummy_candidate_receipt(dummy_hash()); + r.descriptor.para_id = para_id; + r.descriptor.relay_parent = hash; + r + }; + let candidates = vec![ + (make_candidate(1.into()), CoreIndex(0), GroupIndex(2)), + (make_candidate(2.into()), CoreIndex(1), GroupIndex(3)), + ]; - let test_fut = { - let included_candidates = candidates + let inclusion_events = candidates .iter() - .map(|(r, c, g)| (r.hash(), r.clone(), *c, *g)) + .cloned() + .map(|(r, c, g)| CandidateEvent::CandidateIncluded(r, Vec::new().into(), c, g)) .collect::>(); - let mut runtime_info = RuntimeInfo::new_with_config(RuntimeInfoConfig { - keystore: None, - session_cache_lru_size: DISPUTE_WINDOW.get(), - }); + let test_fut = { + let included_candidates = candidates + .iter() + .map(|(r, c, g)| (r.hash(), r.clone(), *c, *g)) + .collect::>(); + + let mut runtime_info = RuntimeInfo::new_with_config(RuntimeInfoConfig { + keystore: None, + session_cache_lru_size: DISPUTE_WINDOW.get(), + }); + + let header = header.clone(); + Box::pin(async move { + let env = ImportedBlockInfoEnv { + runtime_info: &mut runtime_info, + assignment_criteria: &MockAssignmentCriteria { enable_v2 }, + keystore: &LocalKeystore::in_memory(), + }; - let header = header.clone(); - Box::pin(async move { - let env = ImportedBlockInfoEnv { - runtime_info: &mut runtime_info, - assignment_criteria: &MockAssignmentCriteria, - keystore: &LocalKeystore::in_memory(), - }; + let info = + imported_block_info(&mut ctx, env, hash, &header, &Some(4)).await.unwrap(); - let info = - imported_block_info(&mut ctx, env, hash, &header, &Some(4)).await.unwrap(); + assert_eq!(info.included_candidates, included_candidates); + assert_eq!(info.session_index, session); + assert!(info.assignments.is_empty()); + assert_eq!(info.n_validators, 0); + assert_eq!(info.slot, slot); + assert!(info.force_approve.is_none()); + }) + }; - assert_eq!(info.included_candidates, included_candidates); - assert_eq!(info.session_index, session); - assert!(info.assignments.is_empty()); - assert_eq!(info.n_validators, 0); - assert_eq!(info.slot, slot); - assert!(info.force_approve.is_none()); - }) - }; + let aux_fut = Box::pin(async move { + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + h, + RuntimeApiRequest::CandidateEvents(c_tx), + )) => { + assert_eq!(h, hash); + let _ = c_tx.send(Ok(inclusion_events)); + } + ); - let aux_fut = Box::pin(async move { - assert_matches!( - handle.recv().await, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - h, - RuntimeApiRequest::CandidateEvents(c_tx), - )) => { - assert_eq!(h, hash); - let _ = c_tx.send(Ok(inclusion_events)); - } - ); + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + h, + RuntimeApiRequest::SessionIndexForChild(c_tx), + )) => { + assert_eq!(h, header.parent_hash); + let _ = c_tx.send(Ok(session)); + } + ); - assert_matches!( - handle.recv().await, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - h, - RuntimeApiRequest::SessionIndexForChild(c_tx), - )) => { - assert_eq!(h, header.parent_hash); - let _ = c_tx.send(Ok(session)); - } - ); + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + h, + RuntimeApiRequest::CurrentBabeEpoch(c_tx), + )) => { + assert_eq!(h, hash); + let _ = c_tx.send(Ok(BabeEpoch { + epoch_index: session as _, + start_slot: Slot::from(0), + duration: 200, + authorities: vec![(Sr25519Keyring::Alice.public().into(), 1)], + randomness: [0u8; 32], + config: BabeEpochConfiguration { + c: (1, 4), + allowed_slots: AllowedSlots::PrimarySlots, + }, + })); + } + ); - assert_matches!( - handle.recv().await, - AllMessages::RuntimeApi(RuntimeApiMessage::Request( - h, - RuntimeApiRequest::CurrentBabeEpoch(c_tx), - )) => { - assert_eq!(h, hash); - let _ = c_tx.send(Ok(BabeEpoch { - epoch_index: session as _, - start_slot: Slot::from(0), - duration: 200, - authorities: vec![(Sr25519Keyring::Alice.public().into(), 1)], - randomness: [0u8; 32], - config: BabeEpochConfiguration { - c: (1, 4), - allowed_slots: AllowedSlots::PrimarySlots, - }, - })); - } - ); + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request( + req_block_hash, + RuntimeApiRequest::SessionInfo(idx, si_tx), + ) + ) => { + assert_eq!(session, idx); + assert_eq!(req_block_hash, hash); + si_tx.send(Ok(Some(session_info.clone()))).unwrap(); + } + ); - assert_matches!( - handle.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request( - req_block_hash, - RuntimeApiRequest::SessionInfo(idx, si_tx), - ) - ) => { - assert_eq!(session, idx); - assert_eq!(req_block_hash, hash); - si_tx.send(Ok(Some(session_info.clone()))).unwrap(); - } - ); + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request( + req_block_hash, + RuntimeApiRequest::SessionExecutorParams(idx, si_tx), + ) + ) => { + assert_eq!(session, idx); + assert_eq!(req_block_hash, hash); + si_tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); + } + ); - assert_matches!( - handle.recv().await, - AllMessages::RuntimeApi( - RuntimeApiMessage::Request( - req_block_hash, - RuntimeApiRequest::SessionExecutorParams(idx, si_tx), - ) - ) => { - assert_eq!(session, idx); - assert_eq!(req_block_hash, hash); - si_tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); - } - ); - }); + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::NodeFeatures(_, si_tx), ) + ) => { + si_tx.send(Ok(NodeFeatures::repeat(enable_v2, FeatureIndex::EnableAssignmentsV2 as usize + 1))).unwrap(); + } + ); + }); - futures::executor::block_on(futures::future::join(test_fut, aux_fut)); + futures::executor::block_on(futures::future::join(test_fut, aux_fut)); + } } #[test] @@ -906,7 +934,7 @@ pub(crate) mod tests { Box::pin(async move { let env = ImportedBlockInfoEnv { runtime_info: &mut runtime_info, - assignment_criteria: &MockAssignmentCriteria, + assignment_criteria: &MockAssignmentCriteria::default(), keystore: &LocalKeystore::in_memory(), }; @@ -987,6 +1015,15 @@ pub(crate) mod tests { si_tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); } ); + + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::NodeFeatures(_, si_tx), ) + ) => { + si_tx.send(Ok(NodeFeatures::EMPTY)).unwrap(); + } + ); }); futures::executor::block_on(futures::future::join(test_fut, aux_fut)); @@ -1036,7 +1073,7 @@ pub(crate) mod tests { Box::pin(async move { let env = ImportedBlockInfoEnv { runtime_info: &mut runtime_info, - assignment_criteria: &MockAssignmentCriteria, + assignment_criteria: &MockAssignmentCriteria::default(), keystore: &LocalKeystore::in_memory(), }; @@ -1134,7 +1171,7 @@ pub(crate) mod tests { Box::pin(async move { let env = ImportedBlockInfoEnv { runtime_info: &mut runtime_info, - assignment_criteria: &MockAssignmentCriteria, + assignment_criteria: &MockAssignmentCriteria::default(), keystore: &LocalKeystore::in_memory(), }; @@ -1221,6 +1258,15 @@ pub(crate) mod tests { si_tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); } ); + + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::NodeFeatures(_, si_tx), ) + ) => { + si_tx.send(Ok(NodeFeatures::EMPTY)).unwrap(); + } + ); }); futures::executor::block_on(futures::future::join(test_fut, aux_fut)); @@ -1438,6 +1484,15 @@ pub(crate) mod tests { } ); + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::NodeFeatures(_, si_tx), ) + ) => { + si_tx.send(Ok(NodeFeatures::EMPTY)).unwrap(); + } + ); + assert_matches!( handle.recv().await, AllMessages::ApprovalDistribution(ApprovalDistributionMessage::NewBlocks( diff --git a/polkadot/node/core/approval-voting/src/tests.rs b/polkadot/node/core/approval-voting/src/tests.rs index e1ec194cb54..cdfc170cd2b 100644 --- a/polkadot/node/core/approval-voting/src/tests.rs +++ b/polkadot/node/core/approval-voting/src/tests.rs @@ -37,8 +37,8 @@ use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_node_subsystem_util::TimeoutExt; use polkadot_overseer::HeadSupportsParachains; use polkadot_primitives::{ - CandidateCommitments, CandidateEvent, CoreIndex, GroupIndex, Header, Id as ParaId, IndexedVec, - ValidationCode, ValidatorSignature, + vstaging::NodeFeatures, CandidateCommitments, CandidateEvent, CoreIndex, GroupIndex, Header, + Id as ParaId, IndexedVec, ValidationCode, ValidatorSignature, }; use std::time::Duration; @@ -243,6 +243,7 @@ where polkadot_primitives::CoreIndex, polkadot_primitives::GroupIndex, )>, + _enable_assignments_v2: bool, ) -> HashMap { self.0() } @@ -1003,6 +1004,15 @@ async fn import_block( si_tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); } ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::NodeFeatures(_, si_tx), ) + ) => { + si_tx.send(Ok(NodeFeatures::EMPTY)).unwrap(); + } + ); } assert_matches!( diff --git a/polkadot/node/core/dispute-coordinator/src/tests.rs b/polkadot/node/core/dispute-coordinator/src/tests.rs index 9254c2a851c..6912bbf67e1 100644 --- a/polkadot/node/core/dispute-coordinator/src/tests.rs +++ b/polkadot/node/core/dispute-coordinator/src/tests.rs @@ -61,10 +61,11 @@ use polkadot_node_subsystem_test_helpers::{ make_buffered_subsystem_context, mock::new_leaf, TestSubsystemContextHandle, }; use polkadot_primitives::{ - ApprovalVote, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, - CandidateReceipt, CoreIndex, DisputeStatement, ExecutorParams, GroupIndex, Hash, HeadData, - Header, IndexedVec, MultiDisputeStatementSet, ScrapedOnChainVotes, SessionIndex, SessionInfo, - SigningContext, ValidDisputeStatementKind, ValidatorId, ValidatorIndex, ValidatorSignature, + vstaging::NodeFeatures, ApprovalVote, BlockNumber, CandidateCommitments, CandidateEvent, + CandidateHash, CandidateReceipt, CoreIndex, DisputeStatement, ExecutorParams, GroupIndex, Hash, + HeadData, Header, IndexedVec, MultiDisputeStatementSet, ScrapedOnChainVotes, SessionIndex, + SessionInfo, SigningContext, ValidDisputeStatementKind, ValidatorId, ValidatorIndex, + ValidatorSignature, }; use crate::{ @@ -352,6 +353,15 @@ impl TestState { let _ = tx.send(Ok(Some(ExecutorParams::default()))); } ); + + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::NodeFeatures(_, si_tx), ) + ) => { + si_tx.send(Ok(NodeFeatures::EMPTY)).unwrap(); + } + ); } } @@ -3492,6 +3502,14 @@ fn session_info_is_requested_only_once() { let _ = tx.send(Ok(Some(ExecutorParams::default()))); } ); + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::NodeFeatures(_, si_tx), ) + ) => { + si_tx.send(Ok(NodeFeatures::EMPTY)).unwrap(); + } + ); test_state }) }); @@ -3552,6 +3570,15 @@ fn session_info_big_jump_works() { let _ = tx.send(Ok(Some(ExecutorParams::default()))); } ); + + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::NodeFeatures(_, si_tx), ) + ) => { + si_tx.send(Ok(NodeFeatures::EMPTY)).unwrap(); + } + ); } test_state }) @@ -3612,6 +3639,14 @@ fn session_info_small_jump_works() { let _ = tx.send(Ok(Some(ExecutorParams::default()))); } ); + assert_matches!( + virtual_overseer.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::NodeFeatures(_, si_tx), ) + ) => { + si_tx.send(Ok(NodeFeatures::EMPTY)).unwrap(); + } + ); } test_state }) diff --git a/polkadot/node/network/availability-distribution/src/pov_requester/mod.rs b/polkadot/node/network/availability-distribution/src/pov_requester/mod.rs index 12a97a1fb5a..6f9ef9f6a9f 100644 --- a/polkadot/node/network/availability-distribution/src/pov_requester/mod.rs +++ b/polkadot/node/network/availability-distribution/src/pov_requester/mod.rs @@ -146,7 +146,9 @@ mod tests { AllMessages, AvailabilityDistributionMessage, RuntimeApiMessage, RuntimeApiRequest, }; use polkadot_node_subsystem_test_helpers as test_helpers; - use polkadot_primitives::{CandidateHash, ExecutorParams, Hash, ValidatorIndex}; + use polkadot_primitives::{ + vstaging::NodeFeatures, CandidateHash, ExecutorParams, Hash, ValidatorIndex, + }; use test_helpers::mock::make_ferdie_keystore; use super::*; @@ -214,6 +216,12 @@ mod tests { )) => { tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); }, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _, + RuntimeApiRequest::NodeFeatures(_, si_tx), + )) => { + si_tx.send(Ok(NodeFeatures::EMPTY)).unwrap(); + }, AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendRequests( mut reqs, _, diff --git a/polkadot/node/network/availability-distribution/src/requester/tests.rs b/polkadot/node/network/availability-distribution/src/requester/tests.rs index c4252b4e439..2f5d900b037 100644 --- a/polkadot/node/network/availability-distribution/src/requester/tests.rs +++ b/polkadot/node/network/availability-distribution/src/requester/tests.rs @@ -25,8 +25,8 @@ use polkadot_node_primitives::{BlockData, ErasureChunk, PoV}; use polkadot_node_subsystem_test_helpers::mock::new_leaf; use polkadot_node_subsystem_util::runtime::RuntimeInfo; use polkadot_primitives::{ - BlockNumber, CoreState, ExecutorParams, GroupIndex, Hash, Id as ParaId, ScheduledCore, - SessionIndex, SessionInfo, + vstaging::NodeFeatures, BlockNumber, CoreState, ExecutorParams, GroupIndex, Hash, Id as ParaId, + ScheduledCore, SessionIndex, SessionInfo, }; use sp_core::traits::SpawnNamed; @@ -125,6 +125,10 @@ fn spawn_virtual_overseer( tx.send(Ok(Some(ExecutorParams::default()))) .expect("Receiver should be alive."); }, + RuntimeApiRequest::NodeFeatures(_, tx) => { + tx.send(Ok(NodeFeatures::EMPTY)) + .expect("Receiver should be alive."); + }, RuntimeApiRequest::AvailabilityCores(tx) => { let para_id = ParaId::from(1_u32); let maybe_block_position = diff --git a/polkadot/node/network/availability-distribution/src/tests/state.rs b/polkadot/node/network/availability-distribution/src/tests/state.rs index 101d917c0db..e95c1c3a27c 100644 --- a/polkadot/node/network/availability-distribution/src/tests/state.rs +++ b/polkadot/node/network/availability-distribution/src/tests/state.rs @@ -46,8 +46,8 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_primitives::{ - CandidateHash, CoreState, ExecutorParams, GroupIndex, Hash, Id as ParaId, ScheduledCore, - SessionInfo, ValidatorIndex, + vstaging::NodeFeatures, CandidateHash, CoreState, ExecutorParams, GroupIndex, Hash, + Id as ParaId, ScheduledCore, SessionInfo, ValidatorIndex, }; use test_helpers::mock::{make_ferdie_keystore, new_leaf}; @@ -264,6 +264,9 @@ impl TestState { tx.send(Ok(Some(ExecutorParams::default()))) .expect("Receiver should be alive."); }, + RuntimeApiRequest::NodeFeatures(_, si_tx) => { + si_tx.send(Ok(NodeFeatures::EMPTY)).expect("Receiver should be alive."); + }, RuntimeApiRequest::AvailabilityCores(tx) => { gum::trace!(target: LOG_TARGET, cores= ?self.cores[&hash], hash = ?hash, "Sending out cores for hash"); tx.send(Ok(self.cores[&hash].clone())) diff --git a/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs b/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs index 7dd2287dab6..1b1194c7270 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs @@ -45,8 +45,9 @@ use polkadot_node_subsystem::{ use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_node_subsystem_util::{reputation::add_reputation, TimeoutExt}; use polkadot_primitives::{ - AuthorityDiscoveryId, CollatorPair, ExecutorParams, GroupIndex, GroupRotationInfo, IndexedVec, - ScheduledCore, SessionIndex, SessionInfo, ValidatorId, ValidatorIndex, + vstaging::NodeFeatures, AuthorityDiscoveryId, CollatorPair, ExecutorParams, GroupIndex, + GroupRotationInfo, IndexedVec, ScheduledCore, SessionIndex, SessionInfo, ValidatorId, + ValidatorIndex, }; use polkadot_primitives_test_helpers::TestCandidateBuilder; use test_helpers::mock::new_leaf; @@ -406,7 +407,12 @@ async fn distribute_collation_with_receipt( tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); }, - + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _, + RuntimeApiRequest::NodeFeatures(_, si_tx), + )) => { + si_tx.send(Ok(NodeFeatures::EMPTY)).unwrap(); + }, AllMessages::RuntimeApi(RuntimeApiMessage::Request( _relay_parent, RuntimeApiRequest::ValidatorGroups(tx), diff --git a/polkadot/node/network/dispute-distribution/src/tests/mod.rs b/polkadot/node/network/dispute-distribution/src/tests/mod.rs index 96f045cbf76..a3520bf35f8 100644 --- a/polkadot/node/network/dispute-distribution/src/tests/mod.rs +++ b/polkadot/node/network/dispute-distribution/src/tests/mod.rs @@ -57,8 +57,8 @@ use polkadot_node_subsystem_test_helpers::{ subsystem_test_harness, TestSubsystemContextHandle, }; use polkadot_primitives::{ - AuthorityDiscoveryId, CandidateHash, CandidateReceipt, ExecutorParams, Hash, SessionIndex, - SessionInfo, + vstaging::NodeFeatures, AuthorityDiscoveryId, CandidateHash, CandidateReceipt, ExecutorParams, + Hash, SessionIndex, SessionInfo, }; use self::mock::{ @@ -646,6 +646,16 @@ async fn nested_network_dispute_request<'a, F, O>( }, unexpected => panic!("Unexpected message {:?}", unexpected), } + + match handle.recv().await { + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _, + RuntimeApiRequest::NodeFeatures(_, si_tx), + )) => { + si_tx.send(Ok(NodeFeatures::EMPTY)).unwrap(); + }, + unexpected => panic!("Unexpected message {:?}", unexpected), + } } // Import should get initiated: @@ -773,6 +783,14 @@ async fn activate_leaf( tx.send(Ok(Some(ExecutorParams::default()))).expect("Receiver should stay alive."); } ); + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::NodeFeatures(_, si_tx), ) + ) => { + si_tx.send(Ok(NodeFeatures::EMPTY)).unwrap(); + } + ); } assert_matches!( diff --git a/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs b/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs index ca3038f9b3f..8ac9895ec5a 100644 --- a/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs +++ b/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs @@ -43,8 +43,8 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_test_helpers::mock::{make_ferdie_keystore, new_leaf}; use polkadot_primitives::{ - ExecutorParams, GroupIndex, Hash, HeadData, Id as ParaId, IndexedVec, SessionInfo, - ValidationCode, + vstaging::NodeFeatures, ExecutorParams, GroupIndex, Hash, HeadData, Id as ParaId, IndexedVec, + SessionInfo, ValidationCode, }; use polkadot_primitives_test_helpers::{ dummy_committed_candidate_receipt, dummy_hash, AlwaysZeroRng, @@ -834,6 +834,15 @@ fn receiving_from_one_sends_to_another_and_to_candidate_backing() { } ); + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::NodeFeatures(_, si_tx), ) + ) => { + si_tx.send(Ok(NodeFeatures::EMPTY)).unwrap(); + } + ); + // notify of peers and view handle .send(FromOrchestra::Communication { @@ -1074,6 +1083,15 @@ fn receiving_large_statement_from_one_sends_to_another_and_to_candidate_backing( } ); + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::NodeFeatures(_, si_tx), ) + ) => { + si_tx.send(Ok(NodeFeatures::EMPTY)).unwrap(); + } + ); + // notify of peers and view handle .send(FromOrchestra::Communication { @@ -1604,6 +1622,15 @@ fn delay_reputation_changes() { } ); + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::NodeFeatures(_, si_tx), ) + ) => { + si_tx.send(Ok(NodeFeatures::EMPTY)).unwrap(); + } + ); + // notify of peers and view handle .send(FromOrchestra::Communication { @@ -2084,6 +2111,15 @@ fn share_prioritizes_backing_group() { } ); + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::NodeFeatures(_, si_tx), ) + ) => { + si_tx.send(Ok(NodeFeatures::EMPTY)).unwrap(); + } + ); + // notify of dummy peers and view for (peer, pair) in dummy_peers.clone().into_iter().zip(dummy_pairs) { handle @@ -2406,6 +2442,15 @@ fn peer_cant_flood_with_large_statements() { } ); + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::NodeFeatures(_, si_tx), ) + ) => { + si_tx.send(Ok(NodeFeatures::EMPTY)).unwrap(); + } + ); + // notify of peers and view handle .send(FromOrchestra::Communication { @@ -2631,6 +2676,14 @@ fn handle_multiple_seconded_statements() { } ); + assert_matches!( + handle.recv().await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::NodeFeatures(_, si_tx), ) + ) => { + si_tx.send(Ok(NodeFeatures::EMPTY)).unwrap(); + } + ); // notify of peers and view for peer in all_peers.iter() { handle diff --git a/polkadot/node/subsystem-util/src/runtime/mod.rs b/polkadot/node/subsystem-util/src/runtime/mod.rs index aada7a5d77a..0e44423b4e3 100644 --- a/polkadot/node/subsystem-util/src/runtime/mod.rs +++ b/polkadot/node/subsystem-util/src/runtime/mod.rs @@ -30,10 +30,12 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_types::UnpinHandle; use polkadot_primitives::{ - slashing, vstaging::NodeFeatures, AsyncBackingParams, CandidateEvent, CandidateHash, CoreState, - EncodeAs, ExecutorParams, GroupIndex, GroupRotationInfo, Hash, IndexedVec, OccupiedCore, - ScrapedOnChainVotes, SessionIndex, SessionInfo, Signed, SigningContext, UncheckedSigned, - ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, LEGACY_MIN_BACKING_VOTES, + slashing, + vstaging::{node_features::FeatureIndex, NodeFeatures}, + AsyncBackingParams, CandidateEvent, CandidateHash, CoreState, EncodeAs, ExecutorParams, + GroupIndex, GroupRotationInfo, Hash, IndexedVec, OccupiedCore, ScrapedOnChainVotes, + SessionIndex, SessionInfo, Signed, SigningContext, UncheckedSigned, ValidationCode, + ValidationCodeHash, ValidatorId, ValidatorIndex, LEGACY_MIN_BACKING_VOTES, }; use crate::{ @@ -92,6 +94,8 @@ pub struct ExtendedSessionInfo { pub validator_info: ValidatorInfo, /// Session executor parameters pub executor_params: ExecutorParams, + /// Node features + pub node_features: NodeFeatures, } /// Information about ourselves, in case we are an `Authority`. @@ -202,7 +206,20 @@ impl RuntimeInfo { let validator_info = self.get_validator_info(&session_info)?; - let full_info = ExtendedSessionInfo { session_info, validator_info, executor_params }; + let node_features = request_node_features(parent, session_index, sender) + .await? + .unwrap_or(NodeFeatures::EMPTY); + let last_set_index = node_features.iter_ones().last().unwrap_or_default(); + if last_set_index >= FeatureIndex::FirstUnassigned as usize { + gum::warn!(target: LOG_TARGET, "Runtime requires feature bit {} that node doesn't support, please upgrade node version", last_set_index); + } + + let full_info = ExtendedSessionInfo { + session_info, + validator_info, + executor_params, + node_features, + }; self.session_info_cache.insert(session_index, full_info); } diff --git a/polkadot/primitives/src/vstaging/mod.rs b/polkadot/primitives/src/vstaging/mod.rs index 083e0f42d56..1639dc15e21 100644 --- a/polkadot/primitives/src/vstaging/mod.rs +++ b/polkadot/primitives/src/vstaging/mod.rs @@ -22,3 +22,19 @@ use bitvec::vec::BitVec; /// Bit indices in the `HostConfiguration.node_features` that correspond to different node features. pub type NodeFeatures = BitVec; + +/// Module containing feature-specific bit indices into the `NodeFeatures` bitvec. +pub mod node_features { + /// A feature index used to indentify a bit into the node_features array stored + /// in the HostConfiguration. + #[repr(u8)] + pub enum FeatureIndex { + /// Tells if tranch0 assignments could be sent in a single certificate. + /// Reserved for: `` + EnableAssignmentsV2 = 0, + /// First unassigned feature bit. + /// Every time a new feature flag is assigned it should take this value. + /// and this should be incremented. + FirstUnassigned = 1, + } +} -- GitLab From 1e878780a54791c627bf6eae210b77e1bd5f098f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 11:49:28 +0100 Subject: [PATCH 33/59] Bump num-traits from 0.2.16 to 0.2.17 (#2674) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [num-traits](https://github.com/rust-num/num-traits) from 0.2.16 to 0.2.17.
Changelog

Sourced from num-traits's changelog.

Release 0.2.17 (2023-10-07)

Contributors: @​robamu

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=num-traits&package-manager=cargo&previous-version=0.2.16&new-version=0.2.17)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 10 +++++----- substrate/client/consensus/babe/Cargo.toml | 2 +- substrate/primitives/arithmetic/Cargo.toml | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 11e4de35e45..baaa561bb80 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1361,8 +1361,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f" dependencies = [ "bitcoin_hashes", - "rand 0.7.3", - "rand_core 0.5.1", + "rand 0.8.5", + "rand_core 0.6.4", "serde", "unicode-normalization", ] @@ -8797,9 +8797,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", "libm", @@ -19951,7 +19951,7 @@ checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if", "digest 0.10.7", - "rand 0.7.3", + "rand 0.8.5", "static_assertions", ] diff --git a/substrate/client/consensus/babe/Cargo.toml b/substrate/client/consensus/babe/Cargo.toml index c8cff0981b3..6008a5a99f8 100644 --- a/substrate/client/consensus/babe/Cargo.toml +++ b/substrate/client/consensus/babe/Cargo.toml @@ -20,7 +20,7 @@ futures = "0.3.21" log = "0.4.17" num-bigint = "0.4.3" num-rational = "0.4.1" -num-traits = "0.2.8" +num-traits = "0.2.17" parking_lot = "0.12.1" thiserror = "1.0" fork-tree = { path = "../../../utils/fork-tree" } diff --git a/substrate/primitives/arithmetic/Cargo.toml b/substrate/primitives/arithmetic/Cargo.toml index 8634dabe854..ecd3d9585bc 100644 --- a/substrate/primitives/arithmetic/Cargo.toml +++ b/substrate/primitives/arithmetic/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "max-encoded-len", ] } integer-sqrt = "0.1.2" -num-traits = { version = "0.2.8", default-features = false } +num-traits = { version = "0.2.17", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { version = "1.0.193", default-features = false, features = ["alloc", "derive"], optional = true } static_assertions = "1.1.0" -- GitLab From f6548aee31153df576d31820d23bbefca2a5eee4 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Mon, 11 Dec 2023 15:21:20 +0100 Subject: [PATCH 34/59] `keyring`: remove `lazy_static` public keys hash maps (#2387) The `lazy_static` package does not work well in `no-std`: it requires `spin_no_std` feature, which also will propagate into `std` if enabled. This is not what we want. This PR removes public/private key hash-maps and replaces them with simple static byte arrays. `&T` versions of `AsRef/Deref/From` traits implementation were removed. Little const helper for converting hex strings into array during compile time was also added. (somewhat similar to _hex_literal_). --------- Co-authored-by: command-bot <> Co-authored-by: Koute --- Cargo.lock | 1 - .../primitives/core/src/const_hex2array.rs | 162 ++++++++++++++++++ substrate/primitives/core/src/lib.rs | 1 + substrate/primitives/keyring/Cargo.toml | 1 - .../primitives/keyring/src/bandersnatch.rs | 69 +++----- substrate/primitives/keyring/src/ed25519.rs | 78 ++++----- substrate/primitives/keyring/src/sr25519.rs | 76 ++++---- 7 files changed, 266 insertions(+), 122 deletions(-) create mode 100644 substrate/primitives/core/src/const_hex2array.rs diff --git a/Cargo.lock b/Cargo.lock index baaa561bb80..a55223b4bcd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17687,7 +17687,6 @@ dependencies = [ name = "sp-keyring" version = "24.0.0" dependencies = [ - "lazy_static", "sp-core", "sp-runtime", "strum", diff --git a/substrate/primitives/core/src/const_hex2array.rs b/substrate/primitives/core/src/const_hex2array.rs new file mode 100644 index 00000000000..cd6071028e6 --- /dev/null +++ b/substrate/primitives/core/src/const_hex2array.rs @@ -0,0 +1,162 @@ +// This file is part of Substrate. + +// Copyright (C) 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. + +//! Provides a const function for converting a hex string to a `u8` array at compile time, when used +//! in the proper context. + +/// Provides a const array from given string literal. +/// +/// Valid characters are `[0-9a-fA-F]`, and the hex string should not start +/// with the `0x` prefix. +#[macro_export] +macro_rules! hex2array { + ($input:expr) => {{ + const BYTES: [u8; $input.len() / 2] = $crate::const_hex2array::private_hex2array($input); + BYTES + }}; +} + +/// Generates array from (static) string literal. +/// +/// Valid characters are `[0-9a-fA-F]`, and the hex string should not start +/// with the `0x` prefix. +/// +/// # Panics +/// +/// The function will panic at compile time when used in a const context if: +/// - The given hex string has an invalid length. +/// - It contains invalid characters. +/// +/// The function will panic at runtime when used in a non-const context if the above conditions are +/// met. +#[doc(hidden)] +pub const fn private_hex2array(hex: &str) -> [u8; N] { + const fn c2b(c: u8) -> u8 { + match c as char { + '0'..='9' => c - b'0', + 'a'..='f' => c - (b'a' - 10), + 'A'..='F' => c - (b'A' - 10), + _ => panic!("hex string contains invalid character"), + } + } + let mut output = [0; N]; + let mut i = 0; + if hex.len() != 2 * N { + panic!("hex string length is not valid"); + } + while i < N { + output[i] = 16 * c2b(hex.as_bytes()[2 * i]) + c2b(hex.as_bytes()[2 * i + 1]); + i += 1; + } + output +} + +#[cfg(test)] +mod testh2b { + use super::private_hex2array; + + #[test] + fn t00() { + const T0: [u8; 0] = private_hex2array(""); + const EMPTY: [u8; 0] = []; + assert_eq!(T0, EMPTY); + } + + macro_rules! test_byte { + ($a:expr, $b:expr) => {{ + const X: [u8; 1] = private_hex2array($a); + assert_eq!(X, [$b]); + }}; + } + + #[test] + fn t01() { + test_byte!("00", 0); + test_byte!("01", 1); + test_byte!("02", 2); + test_byte!("03", 3); + test_byte!("04", 4); + test_byte!("05", 5); + test_byte!("06", 6); + test_byte!("07", 7); + test_byte!("08", 8); + test_byte!("09", 9); + test_byte!("0a", 10); + test_byte!("0A", 10); + test_byte!("0b", 11); + test_byte!("0B", 11); + test_byte!("0c", 12); + test_byte!("0C", 12); + test_byte!("0d", 13); + test_byte!("0D", 13); + test_byte!("0e", 14); + test_byte!("0E", 14); + test_byte!("0f", 15); + test_byte!("0F", 15); + } + + #[test] + fn t02() { + const T0: [u8; 2] = private_hex2array("0a10"); + assert_eq!(T0, [10, 16]); + const T1: [u8; 2] = private_hex2array("4545"); + assert_eq!(T1, [69, 69]); + } + + #[test] + fn t02m() { + assert_eq!(hex2array!("0a10"), [10, 16]); + assert_eq!(hex2array!("4545"), [69, 69]); + assert_eq!( + hex2array!("000102030405060708090a0b0c0d0e0f"), + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] + ); + } + + #[test] + fn t16() { + const T16: [u8; 16] = private_hex2array("000102030405060708090a0b0c0d0e0f"); + + assert_eq!(T16, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]); + } + + #[test] + fn t33() { + const T33: [u8; 33] = + private_hex2array("9c8af77d3a4e3f6f076853922985b9e6724fc9675329087f47aff1ceaaae772180"); + + assert_eq!( + T33, + [ + 156, 138, 247, 125, 58, 78, 63, 111, 7, 104, 83, 146, 41, 133, 185, 230, 114, 79, + 201, 103, 83, 41, 8, 127, 71, 175, 241, 206, 170, 174, 119, 33, 128 + ] + ); + } + + #[test] + #[should_panic = "hex string length is not valid"] + fn t_panic_incorrect_length2() { + let _ = private_hex2array::<2>("454"); + } + + #[test] + #[should_panic = "hex string contains invalid character"] + fn t_panic_invalid_character() { + let _ = private_hex2array::<2>("45ag"); + } +} diff --git a/substrate/primitives/core/src/lib.rs b/substrate/primitives/core/src/lib.rs index 4873d1a2112..c7232563cb7 100644 --- a/substrate/primitives/core/src/lib.rs +++ b/substrate/primitives/core/src/lib.rs @@ -51,6 +51,7 @@ pub mod hashing; #[cfg(feature = "full_crypto")] pub use hashing::{blake2_128, blake2_256, keccak_256, twox_128, twox_256, twox_64}; +pub mod const_hex2array; pub mod crypto; pub mod hexdisplay; pub use paste; diff --git a/substrate/primitives/keyring/Cargo.toml b/substrate/primitives/keyring/Cargo.toml index a504cda756e..5b58a4f97ca 100644 --- a/substrate/primitives/keyring/Cargo.toml +++ b/substrate/primitives/keyring/Cargo.toml @@ -14,7 +14,6 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -lazy_static = "1.4.0" strum = { version = "0.24.1", features = ["derive"], default-features = false } sp-core = { path = "../core" } sp-runtime = { path = "../runtime" } diff --git a/substrate/primitives/keyring/src/bandersnatch.rs b/substrate/primitives/keyring/src/bandersnatch.rs index 8de6786a6fb..eb60f856327 100644 --- a/substrate/primitives/keyring/src/bandersnatch.rs +++ b/substrate/primitives/keyring/src/bandersnatch.rs @@ -21,12 +21,9 @@ pub use sp_core::bandersnatch; use sp_core::{ bandersnatch::{Pair, Public, Signature}, crypto::UncheckedFrom, - ByteArray, Pair as PairT, + hex2array, ByteArray, Pair as PairT, }; -use lazy_static::lazy_static; -use std::{collections::HashMap, ops::Deref, sync::Mutex}; - /// Set of test accounts. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum::Display, strum::EnumIter)] pub enum Keyring { @@ -74,7 +71,7 @@ impl Keyring { } pub fn public(self) -> Public { - self.pair().public() + Public::from(self) } pub fn to_seed(self) -> String { @@ -129,20 +126,9 @@ impl std::str::FromStr for Keyring { } } -lazy_static! { - static ref PRIVATE_KEYS: Mutex> = - Mutex::new(Keyring::iter().map(|who| (who, who.pair())).collect()); - static ref PUBLIC_KEYS: HashMap = PRIVATE_KEYS - .lock() - .unwrap() - .iter() - .map(|(&who, pair)| (who, pair.public())) - .collect(); -} - impl From for Public { fn from(k: Keyring) -> Self { - *(*PUBLIC_KEYS).get(&k).unwrap() + Public::unchecked_from(<[u8; PUBLIC_RAW_LEN]>::from(k)) } } @@ -154,32 +140,24 @@ impl From for Pair { impl From for [u8; PUBLIC_RAW_LEN] { fn from(k: Keyring) -> Self { - *(*PUBLIC_KEYS).get(&k).unwrap().as_ref() - } -} - -impl From for &'static [u8; PUBLIC_RAW_LEN] { - fn from(k: Keyring) -> Self { - PUBLIC_KEYS.get(&k).unwrap().as_ref() - } -} - -impl AsRef<[u8; PUBLIC_RAW_LEN]> for Keyring { - fn as_ref(&self) -> &[u8; PUBLIC_RAW_LEN] { - PUBLIC_KEYS.get(self).unwrap().as_ref() - } -} - -impl AsRef for Keyring { - fn as_ref(&self) -> &Public { - PUBLIC_KEYS.get(self).unwrap() - } -} - -impl Deref for Keyring { - type Target = [u8; PUBLIC_RAW_LEN]; - fn deref(&self) -> &[u8; PUBLIC_RAW_LEN] { - PUBLIC_KEYS.get(self).unwrap().as_ref() + match k { + Keyring::Alice => + hex2array!("9c8af77d3a4e3f6f076853922985b9e6724fc9675329087f47aff1ceaaae772180"), + Keyring::Bob => + hex2array!("1abfbb76dc8374a1a6d93d59a5c81f07c18835f4681a6258aa0f514d363bff4780"), + Keyring::Charlie => + hex2array!("0f4a9990aca3d39a7cd8bf187e2e81a9ea6f9cedb2db405f2fffff384c5dd02680"), + Keyring::Dave => + hex2array!("bd7a87d4dfa89926a408b5acbed554ae3b053fa3532531053295cbabf07d337000"), + Keyring::Eve => + hex2array!("f992d5b8eac8fc004d521bee6edc1174cfa7fae3a1baec8262511ee351f9f85e00"), + Keyring::Ferdie => + hex2array!("1ce2613e89bc5c8e358aad884099cfb576a61176f2f9968cd0d486a04457245180"), + Keyring::One => + hex2array!("a29e03ac273e521274d8e501a6242abd2ab393d7e197221a9113bdf8e2e5b34d00"), + Keyring::Two => + hex2array!("f968d47e819ddb18a9d0f2ebd16501680b1a3f07ee375c6f81310e5f99a04f4d00"), + } } } @@ -206,4 +184,9 @@ mod tests { &Keyring::Bob.public(), )); } + #[test] + fn verify_static_public_keys() { + assert!(Keyring::iter() + .all(|k| { k.pair().public().as_ref() == <[u8; PUBLIC_RAW_LEN]>::from(k) })); + } } diff --git a/substrate/primitives/keyring/src/ed25519.rs b/substrate/primitives/keyring/src/ed25519.rs index 3060bfb1ad9..ade42b29494 100644 --- a/substrate/primitives/keyring/src/ed25519.rs +++ b/substrate/primitives/keyring/src/ed25519.rs @@ -17,14 +17,12 @@ //! Support code for the runtime. A set of test accounts. -use lazy_static::lazy_static; pub use sp_core::ed25519; use sp_core::{ ed25519::{Pair, Public, Signature}, - ByteArray, Pair as PairT, H256, + hex2array, ByteArray, Pair as PairT, H256, }; use sp_runtime::AccountId32; -use std::{collections::HashMap, ops::Deref}; /// Set of test accounts. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum::Display, strum::EnumIter)] @@ -93,7 +91,7 @@ impl Keyring { } pub fn public(self) -> Public { - self.pair().public() + Public::from(self) } pub fn to_seed(self) -> String { @@ -128,16 +126,9 @@ impl From for sp_runtime::MultiSigner { } } -lazy_static! { - static ref PRIVATE_KEYS: HashMap = - Keyring::iter().map(|i| (i, i.pair())).collect(); - static ref PUBLIC_KEYS: HashMap = - PRIVATE_KEYS.iter().map(|(&name, pair)| (name, pair.public())).collect(); -} - impl From for Public { fn from(k: Keyring) -> Self { - *(*PUBLIC_KEYS).get(&k).unwrap() + Public::from_raw(k.into()) } } @@ -155,38 +146,42 @@ impl From for Pair { impl From for [u8; 32] { fn from(k: Keyring) -> Self { - *(*PUBLIC_KEYS).get(&k).unwrap().as_array_ref() + match k { + Keyring::Alice => + hex2array!("88dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0ee"), + Keyring::Bob => + hex2array!("d17c2d7823ebf260fd138f2d7e27d114c0145d968b5ff5006125f2414fadae69"), + Keyring::Charlie => + hex2array!("439660b36c6c03afafca027b910b4fecf99801834c62a5e6006f27d978de234f"), + Keyring::Dave => + hex2array!("5e639b43e0052c47447dac87d6fd2b6ec50bdd4d0f614e4299c665249bbd09d9"), + Keyring::Eve => + hex2array!("1dfe3e22cc0d45c70779c1095f7489a8ef3cf52d62fbd8c2fa38c9f1723502b5"), + Keyring::Ferdie => + hex2array!("568cb4a574c6d178feb39c27dfc8b3f789e5f5423e19c71633c748b9acf086b5"), + Keyring::AliceStash => + hex2array!("451781cd0c5504504f69ceec484cc66e4c22a2b6a9d20fb1a426d91ad074a2a8"), + Keyring::BobStash => + hex2array!("292684abbb28def63807c5f6e84e9e8689769eb37b1ab130d79dbfbf1b9a0d44"), + Keyring::CharlieStash => + hex2array!("dd6a6118b6c11c9c9e5a4f34ed3d545e2c74190f90365c60c230fa82e9423bb9"), + Keyring::DaveStash => + hex2array!("1d0432d75331ab299065bee79cdb1bdc2497c597a3087b4d955c67e3c000c1e2"), + Keyring::EveStash => + hex2array!("c833bdd2e1a7a18acc1c11f8596e2e697bb9b42d6b6051e474091a1d43a294d7"), + Keyring::FerdieStash => + hex2array!("199d749dbf4b8135cb1f3c8fd697a390fc0679881a8a110c1d06375b3b62cd09"), + Keyring::One => + hex2array!("16f97016bbea8f7b45ae6757b49efc1080accc175d8f018f9ba719b60b0815e4"), + Keyring::Two => + hex2array!("5079bcd20fd97d7d2f752c4607012600b401950260a91821f73e692071c82bf5"), + } } } impl From for H256 { fn from(k: Keyring) -> Self { - (*PUBLIC_KEYS).get(&k).unwrap().as_array_ref().into() - } -} - -impl From for &'static [u8; 32] { - fn from(k: Keyring) -> Self { - (*PUBLIC_KEYS).get(&k).unwrap().as_array_ref() - } -} - -impl AsRef<[u8; 32]> for Keyring { - fn as_ref(&self) -> &[u8; 32] { - (*PUBLIC_KEYS).get(self).unwrap().as_array_ref() - } -} - -impl AsRef for Keyring { - fn as_ref(&self) -> &Public { - (*PUBLIC_KEYS).get(self).unwrap() - } -} - -impl Deref for Keyring { - type Target = [u8; 32]; - fn deref(&self) -> &[u8; 32] { - (*PUBLIC_KEYS).get(self).unwrap().as_array_ref() + k.into() } } @@ -213,4 +208,9 @@ mod tests { &Keyring::Bob.public(), )); } + + #[test] + fn verify_static_public_keys() { + assert!(Keyring::iter().all(|k| { k.pair().public().as_ref() == <[u8; 32]>::from(k) })); + } } diff --git a/substrate/primitives/keyring/src/sr25519.rs b/substrate/primitives/keyring/src/sr25519.rs index 914a66b4d83..1c2a2526efb 100644 --- a/substrate/primitives/keyring/src/sr25519.rs +++ b/substrate/primitives/keyring/src/sr25519.rs @@ -17,14 +17,13 @@ //! Support code for the runtime. A set of test accounts. -use lazy_static::lazy_static; pub use sp_core::sr25519; use sp_core::{ + hex2array, sr25519::{Pair, Public, Signature}, ByteArray, Pair as PairT, H256, }; use sp_runtime::AccountId32; -use std::{collections::HashMap, ops::Deref}; /// Set of test accounts. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum::Display, strum::EnumIter)] @@ -93,7 +92,7 @@ impl Keyring { } pub fn public(self) -> Public { - self.pair().public() + Public::from(self) } pub fn to_seed(self) -> String { @@ -165,13 +164,6 @@ impl std::str::FromStr for Keyring { } } -lazy_static! { - static ref PRIVATE_KEYS: HashMap = - Keyring::iter().map(|i| (i, i.pair())).collect(); - static ref PUBLIC_KEYS: HashMap = - PRIVATE_KEYS.iter().map(|(&name, pair)| (name, pair.public())).collect(); -} - impl From for AccountId32 { fn from(k: Keyring) -> Self { k.to_account_id() @@ -180,7 +172,7 @@ impl From for AccountId32 { impl From for Public { fn from(k: Keyring) -> Self { - *(*PUBLIC_KEYS).get(&k).unwrap() + Public::from_raw(k.into()) } } @@ -192,38 +184,42 @@ impl From for Pair { impl From for [u8; 32] { fn from(k: Keyring) -> Self { - *(*PUBLIC_KEYS).get(&k).unwrap().as_array_ref() + match k { + Keyring::Alice => + hex2array!("d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"), + Keyring::Bob => + hex2array!("8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48"), + Keyring::Charlie => + hex2array!("90b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22"), + Keyring::Dave => + hex2array!("306721211d5404bd9da88e0204360a1a9ab8b87c66c1bc2fcdd37f3c2222cc20"), + Keyring::Eve => + hex2array!("e659a7a1628cdd93febc04a4e0646ea20e9f5f0ce097d9a05290d4a9e054df4e"), + Keyring::Ferdie => + hex2array!("1cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c"), + Keyring::AliceStash => + hex2array!("be5ddb1579b72e84524fc29e78609e3caf42e85aa118ebfe0b0ad404b5bdd25f"), + Keyring::BobStash => + hex2array!("fe65717dad0447d715f660a0a58411de509b42e6efb8375f562f58a554d5860e"), + Keyring::CharlieStash => + hex2array!("1e07379407fecc4b89eb7dbd287c2c781cfb1907a96947a3eb18e4f8e7198625"), + Keyring::DaveStash => + hex2array!("e860f1b1c7227f7c22602f53f15af80747814dffd839719731ee3bba6edc126c"), + Keyring::EveStash => + hex2array!("8ac59e11963af19174d0b94d5d78041c233f55d2e19324665bafdfb62925af2d"), + Keyring::FerdieStash => + hex2array!("101191192fc877c24d725b337120fa3edc63d227bbc92705db1e2cb65f56981a"), + Keyring::One => + hex2array!("ac859f8a216eeb1b320b4c76d118da3d7407fa523484d0a980126d3b4d0d220a"), + Keyring::Two => + hex2array!("1254f7017f0b8347ce7ab14f96d818802e7e9e0c0d1b7c9acb3c726b080e7a03"), + } } } impl From for H256 { fn from(k: Keyring) -> Self { - (*PUBLIC_KEYS).get(&k).unwrap().as_array_ref().into() - } -} - -impl From for &'static [u8; 32] { - fn from(k: Keyring) -> Self { - (*PUBLIC_KEYS).get(&k).unwrap().as_array_ref() - } -} - -impl AsRef<[u8; 32]> for Keyring { - fn as_ref(&self) -> &[u8; 32] { - (*PUBLIC_KEYS).get(self).unwrap().as_array_ref() - } -} - -impl AsRef for Keyring { - fn as_ref(&self) -> &Public { - (*PUBLIC_KEYS).get(self).unwrap() - } -} - -impl Deref for Keyring { - type Target = [u8; 32]; - fn deref(&self) -> &[u8; 32] { - (*PUBLIC_KEYS).get(self).unwrap().as_array_ref() + k.into() } } @@ -250,4 +246,8 @@ mod tests { &Keyring::Bob.public(), )); } + #[test] + fn verify_static_public_keys() { + assert!(Keyring::iter().all(|k| { k.pair().public().as_ref() == <[u8; 32]>::from(k) })); + } } -- GitLab From 7b416d84ff97588e00e069a7850ca33c9fe734e6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 17:26:09 +0100 Subject: [PATCH 35/59] Bump the known_good_semver group with 2 updates (#2675) Bumps the known_good_semver group with 2 updates: [clap](https://github.com/clap-rs/clap) and [syn](https://github.com/dtolnay/syn). Updates `clap` from 4.4.10 to 4.4.11
Release notes

Sourced from clap's releases.

v4.4.11

[4.4.11] - 2023-12-04

Features

  • Add Command::mut_group
Changelog

Sourced from clap's changelog.

[4.4.11] - 2023-12-04

Features

  • Add Command::mut_group
Commits

Updates `syn` from 2.0.39 to 2.0.40
Release notes

Sourced from syn's releases.

2.0.40

Commits
  • cf7f40a Release 2.0.40
  • 1ce8ccf Merge pull request #1538 from dtolnay/testinvisible
  • d06bff8 Add test for parsing Delimiter::None in expressions
  • 9ec66d4 Merge pull request #1545 from dtolnay/groupedlet
  • 384621a Fix None-delimited let expression in stmt position
  • 5325b6d Add test of let expr surrounded in None-delimited group
  • 0ddfc27 Merge pull request #1544 from dtolnay/nonedelimloop
  • 9c99b3f Fix stmt boundary after None-delimited group containing loop
  • 2781584 Add test of None-delimited group containing loop in match arm
  • d332928 Simplify token stream construction in Delimiter::None tests
  • Additional commits viewable in compare view

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 166 +++++++++--------- cumulus/client/cli/Cargo.toml | 2 +- .../parachain-system/proc-macro/Cargo.toml | 2 +- cumulus/parachain-template/node/Cargo.toml | 2 +- cumulus/polkadot-parachain/Cargo.toml | 2 +- cumulus/test/service/Cargo.toml | 2 +- polkadot/cli/Cargo.toml | 2 +- polkadot/node/gum/proc-macro/Cargo.toml | 2 +- polkadot/node/malus/Cargo.toml | 2 +- .../test-parachains/adder/collator/Cargo.toml | 2 +- .../undying/collator/Cargo.toml | 2 +- polkadot/utils/generate-bags/Cargo.toml | 2 +- .../remote-ext-tests/bags-list/Cargo.toml | 2 +- polkadot/xcm/procedural/Cargo.toml | 2 +- substrate/bin/minimal/node/Cargo.toml | 2 +- substrate/bin/node-template/node/Cargo.toml | 2 +- substrate/bin/node/bench/Cargo.toml | 2 +- substrate/bin/node/cli/Cargo.toml | 4 +- substrate/bin/node/inspect/Cargo.toml | 2 +- .../bin/utils/chain-spec-builder/Cargo.toml | 2 +- substrate/bin/utils/subkey/Cargo.toml | 2 +- substrate/client/chain-spec/derive/Cargo.toml | 2 +- substrate/client/cli/Cargo.toml | 2 +- substrate/client/storage-monitor/Cargo.toml | 2 +- .../client/tracing/proc-macro/Cargo.toml | 2 +- .../frame/contracts/proc-macro/Cargo.toml | 2 +- .../solution-type/Cargo.toml | 2 +- .../solution-type/fuzzer/Cargo.toml | 2 +- .../frame/staking/reward-curve/Cargo.toml | 2 +- substrate/frame/support/procedural/Cargo.toml | 2 +- .../frame/support/procedural/tools/Cargo.toml | 2 +- .../procedural/tools/derive/Cargo.toml | 2 +- .../primitives/api/proc-macro/Cargo.toml | 2 +- .../core/hashing/proc-macro/Cargo.toml | 2 +- substrate/primitives/debug-derive/Cargo.toml | 2 +- .../npos-elections/fuzzer/Cargo.toml | 2 +- .../runtime-interface/proc-macro/Cargo.toml | 2 +- .../primitives/version/proc-macro/Cargo.toml | 2 +- .../ci/node-template-release/Cargo.toml | 2 +- .../utils/frame/benchmarking-cli/Cargo.toml | 2 +- .../frame/frame-utilities-cli/Cargo.toml | 2 +- .../generate-bags/node-runtime/Cargo.toml | 2 +- .../utils/frame/try-runtime/cli/Cargo.toml | 2 +- 43 files changed, 126 insertions(+), 126 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a55223b4bcd..05e6063cff9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1158,7 +1158,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -1175,7 +1175,7 @@ checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -1351,7 +1351,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -2522,9 +2522,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.10" +version = "4.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fffed7514f420abec6d183b1d3acfd9099c79c3a10a06ade4f8203f1411272" +checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2" dependencies = [ "clap_builder", "clap_derive 4.4.7", @@ -2532,9 +2532,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.9" +version = "4.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63361bae7eef3771745f02d8d892bec2fee5f6e34af316ba556e7f97a7069ff1" +checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb" dependencies = [ "anstream", "anstyle", @@ -2549,7 +2549,7 @@ version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "586a385f7ef2f8b4d86bddaa0c094794e7ccbfe5ffef1f434fe928143fc783a5" dependencies = [ - "clap 4.4.10", + "clap 4.4.11", ] [[package]] @@ -2574,7 +2574,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -3141,7 +3141,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.4.10", + "clap 4.4.11", "criterion-plot", "futures", "is-terminal", @@ -3316,7 +3316,7 @@ dependencies = [ name = "cumulus-client-cli" version = "0.1.0" dependencies = [ - "clap 4.4.10", + "clap 4.4.11", "parity-scale-codec", "sc-chain-spec", "sc-cli", @@ -3649,7 +3649,7 @@ dependencies = [ "proc-macro-crate 2.0.1", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -4037,7 +4037,7 @@ name = "cumulus-test-service" version = "0.1.0" dependencies = [ "async-trait", - "clap 4.4.10", + "clap 4.4.11", "criterion 0.5.1", "cumulus-client-cli", "cumulus-client-consensus-common", @@ -4160,7 +4160,7 @@ checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -4200,7 +4200,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -4217,7 +4217,7 @@ checksum = "50c49547d73ba8dcfd4ad7325d64c6d5391ff4224d498fc39a6f3f49825a530d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -4516,7 +4516,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -4577,7 +4577,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.39", + "syn 2.0.40", "termcolor", "toml 0.7.6", "walkdir", @@ -4833,7 +4833,7 @@ checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -4844,7 +4844,7 @@ checksum = "c2ad8cef1d801a4686bfd8919f0b30eac4c8e48968c437a6405ded4fb5272d2b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -4999,7 +4999,7 @@ dependencies = [ "fs-err", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -5320,7 +5320,7 @@ dependencies = [ "Inflector", "array-bytes 6.1.0", "chrono", - "clap 4.4.10", + "clap 4.4.11", "comfy-table", "frame-benchmarking", "frame-support", @@ -5386,7 +5386,7 @@ dependencies = [ "quote", "scale-info", "sp-arithmetic", - "syn 2.0.39", + "syn 2.0.40", "trybuild", ] @@ -5412,7 +5412,7 @@ dependencies = [ name = "frame-election-solution-type-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.4.10", + "clap 4.4.11", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-support", @@ -5539,7 +5539,7 @@ dependencies = [ "quote", "regex", "sp-core-hashing", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -5550,7 +5550,7 @@ dependencies = [ "proc-macro-crate 2.0.1", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -5559,7 +5559,7 @@ version = "3.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -5792,7 +5792,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -7797,7 +7797,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -7811,7 +7811,7 @@ dependencies = [ "macro_magic_core_macros", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -7822,7 +7822,7 @@ checksum = "9ea73aa640dc01d62a590d48c0c3521ed739d53b27f919b25c3551e233481654" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -7833,7 +7833,7 @@ checksum = "ef9d79ae96aaba821963320eb2b6e34d17df1e5a83d8a1985c29cc5be59577b3" dependencies = [ "macro_magic_core", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -8002,7 +8002,7 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" name = "minimal-node" version = "4.0.0-dev" dependencies = [ - "clap 4.4.10", + "clap 4.4.11", "frame", "futures", "futures-timer", @@ -8476,7 +8476,7 @@ name = "node-bench" version = "0.9.0-dev" dependencies = [ "array-bytes 6.1.0", - "clap 4.4.10", + "clap 4.4.11", "derive_more", "fs_extra", "futures", @@ -8551,7 +8551,7 @@ dependencies = [ name = "node-runtime-generate-bags" version = "3.0.0" dependencies = [ - "clap 4.4.10", + "clap 4.4.11", "generate-bags", "kitchensink-runtime", ] @@ -8560,7 +8560,7 @@ dependencies = [ name = "node-template" version = "4.0.0-dev" dependencies = [ - "clap 4.4.10", + "clap 4.4.11", "frame-benchmarking", "frame-benchmarking-cli", "frame-system", @@ -8604,7 +8604,7 @@ dependencies = [ name = "node-template-release" version = "3.0.0" dependencies = [ - "clap 4.4.10", + "clap 4.4.11", "flate2", "fs_extra", "glob", @@ -9617,7 +9617,7 @@ version = "4.0.0-dev" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -10777,7 +10777,7 @@ dependencies = [ "proc-macro2", "quote", "sp-runtime", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -11183,7 +11183,7 @@ dependencies = [ name = "parachain-template-node" version = "0.1.0" dependencies = [ - "clap 4.4.10", + "clap 4.4.11", "color-print", "cumulus-client-cli", "cumulus-client-collator", @@ -11671,7 +11671,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -11712,7 +11712,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -11934,7 +11934,7 @@ name = "polkadot-cli" version = "1.1.0" dependencies = [ "cfg-if", - "clap 4.4.10", + "clap 4.4.11", "frame-benchmarking-cli", "futures", "log", @@ -12773,7 +12773,7 @@ dependencies = [ "async-trait", "bridge-hub-rococo-runtime", "bridge-hub-westend-runtime", - "clap 4.4.10", + "clap 4.4.11", "collectives-westend-runtime", "color-print", "contracts-rococo-runtime", @@ -13305,7 +13305,7 @@ version = "1.0.0" dependencies = [ "assert_matches", "async-trait", - "clap 4.4.10", + "clap 4.4.11", "color-eyre", "futures", "futures-timer", @@ -13452,7 +13452,7 @@ dependencies = [ name = "polkadot-voter-bags" version = "1.0.0" dependencies = [ - "clap 4.4.10", + "clap 4.4.11", "generate-bags", "sp-io", "westend-runtime", @@ -13630,7 +13630,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62" dependencies = [ "proc-macro2", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -13722,7 +13722,7 @@ checksum = "9b698b0b09d40e9b7c1a47b132d66a8b54bcd20583d9b6d06e4535e383b4405c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -13794,7 +13794,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -14196,7 +14196,7 @@ checksum = "7f7473c2cfcf90008193dd0e3e16599455cb601a9fce322b5bb55de799664925" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -14265,7 +14265,7 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" name = "remote-ext-tests-bags-list" version = "1.0.0" dependencies = [ - "clap 4.4.10", + "clap 4.4.11", "frame-system", "log", "pallet-bags-list-remote-tests", @@ -15039,7 +15039,7 @@ dependencies = [ "proc-macro-crate 2.0.1", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -15049,7 +15049,7 @@ dependencies = [ "array-bytes 6.1.0", "bip39", "chrono", - "clap 4.4.10", + "clap 4.4.11", "fdlimit", "futures", "futures-timer", @@ -16193,7 +16193,7 @@ dependencies = [ name = "sc-storage-monitor" version = "0.1.0" dependencies = [ - "clap 4.4.10", + "clap 4.4.11", "fs4", "log", "sc-client-db", @@ -16295,7 +16295,7 @@ dependencies = [ "proc-macro-crate 2.0.1", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -16688,7 +16688,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -16765,7 +16765,7 @@ checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -17209,7 +17209,7 @@ dependencies = [ "proc-macro-crate 2.0.1", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -17544,7 +17544,7 @@ version = "9.0.0" dependencies = [ "quote", "sp-core-hashing", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -17602,7 +17602,7 @@ version = "8.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -17612,7 +17612,7 @@ source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf5 dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -17771,7 +17771,7 @@ dependencies = [ name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.4.10", + "clap 4.4.11", "honggfuzz", "rand 0.8.5", "sp-npos-elections", @@ -17885,7 +17885,7 @@ dependencies = [ "proc-macro-crate 2.0.1", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -17897,7 +17897,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -18168,7 +18168,7 @@ dependencies = [ "proc-macro2", "quote", "sp-version", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -18279,7 +18279,7 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" name = "staging-chain-spec-builder" version = "2.0.0" dependencies = [ - "clap 4.4.10", + "clap 4.4.11", "log", "sc-chain-spec", "serde_json", @@ -18292,7 +18292,7 @@ version = "3.0.0-dev" dependencies = [ "array-bytes 6.1.0", "assert_cmd", - "clap 4.4.10", + "clap 4.4.11", "clap_complete", "criterion 0.4.0", "frame-benchmarking", @@ -18397,7 +18397,7 @@ dependencies = [ name = "staging-node-inspect" version = "0.9.0-dev" dependencies = [ - "clap 4.4.10", + "clap 4.4.11", "parity-scale-codec", "sc-cli", "sc-client-api", @@ -18620,7 +18620,7 @@ dependencies = [ name = "subkey" version = "3.0.0" dependencies = [ - "clap 4.4.10", + "clap 4.4.11", "sc-cli", ] @@ -18662,7 +18662,7 @@ dependencies = [ name = "substrate-frame-cli" version = "4.0.0-dev" dependencies = [ - "clap 4.4.10", + "clap 4.4.11", "frame-support", "frame-system", "sc-cli", @@ -19017,9 +19017,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "13fa70a4ee923979ffb522cacce59d34421ebdea5625e1073c4326ef9d2dd42e" dependencies = [ "proc-macro2", "quote", @@ -19137,7 +19137,7 @@ dependencies = [ name = "test-parachain-adder-collator" version = "1.0.0" dependencies = [ - "clap 4.4.10", + "clap 4.4.11", "futures", "futures-timer", "log", @@ -19185,7 +19185,7 @@ dependencies = [ name = "test-parachain-undying-collator" version = "1.0.0" dependencies = [ - "clap 4.4.10", + "clap 4.4.11", "futures", "futures-timer", "log", @@ -19274,7 +19274,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -19446,7 +19446,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -19652,7 +19652,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -19694,7 +19694,7 @@ dependencies = [ "proc-macro-crate 2.0.1", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] @@ -19847,7 +19847,7 @@ version = "0.10.0-dev" dependencies = [ "assert_cmd", "async-trait", - "clap 4.4.10", + "clap 4.4.11", "frame-remote-externalities", "frame-try-runtime", "hex", @@ -20249,7 +20249,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", "wasm-bindgen-shared", ] @@ -20283,7 +20283,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -21463,7 +21463,7 @@ dependencies = [ "proc-macro2", "quote", "staging-xcm", - "syn 2.0.39", + "syn 2.0.40", "trybuild", ] @@ -21583,7 +21583,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.40", ] [[package]] diff --git a/cumulus/client/cli/Cargo.toml b/cumulus/client/cli/Cargo.toml index 35945bf4052..c1b27673c40 100644 --- a/cumulus/client/cli/Cargo.toml +++ b/cumulus/client/cli/Cargo.toml @@ -7,7 +7,7 @@ description = "Parachain node CLI utilities." license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] -clap = { version = "4.4.10", features = ["derive"] } +clap = { version = "4.4.11", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } url = "2.4.0" diff --git a/cumulus/pallets/parachain-system/proc-macro/Cargo.toml b/cumulus/pallets/parachain-system/proc-macro/Cargo.toml index ffe44c32902..fe960f716de 100644 --- a/cumulus/pallets/parachain-system/proc-macro/Cargo.toml +++ b/cumulus/pallets/parachain-system/proc-macro/Cargo.toml @@ -10,7 +10,7 @@ license = "Apache-2.0" proc-macro = true [dependencies] -syn = "2.0.39" +syn = "2.0.40" proc-macro2 = "1.0.64" quote = "1.0.33" proc-macro-crate = "2.0.1" diff --git a/cumulus/parachain-template/node/Cargo.toml b/cumulus/parachain-template/node/Cargo.toml index 19ee334cf95..a83b4e21ac5 100644 --- a/cumulus/parachain-template/node/Cargo.toml +++ b/cumulus/parachain-template/node/Cargo.toml @@ -11,7 +11,7 @@ build = "build.rs" publish = false [dependencies] -clap = { version = "4.4.10", features = ["derive"] } +clap = { version = "4.4.11", features = ["derive"] } log = "0.4.20" codec = { package = "parity-scale-codec", version = "3.0.0" } serde = { version = "1.0.193", features = ["derive"] } diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index 67ebc244adf..fed076132a4 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -13,7 +13,7 @@ path = "src/main.rs" [dependencies] async-trait = "0.1.73" -clap = { version = "4.4.10", features = ["derive"] } +clap = { version = "4.4.11", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.28" hex-literal = "0.4.1" diff --git a/cumulus/test/service/Cargo.toml b/cumulus/test/service/Cargo.toml index 271c450539b..cc25c80d4bf 100644 --- a/cumulus/test/service/Cargo.toml +++ b/cumulus/test/service/Cargo.toml @@ -11,7 +11,7 @@ path = "src/main.rs" [dependencies] async-trait = "0.1.73" -clap = { version = "4.4.10", features = ["derive"] } +clap = { version = "4.4.11", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } criterion = { version = "0.5.1", features = ["async_tokio"] } jsonrpsee = { version = "0.16.2", features = ["server"] } diff --git a/polkadot/cli/Cargo.toml b/polkadot/cli/Cargo.toml index 72b2a18f36b..77f73ead2ed 100644 --- a/polkadot/cli/Cargo.toml +++ b/polkadot/cli/Cargo.toml @@ -16,7 +16,7 @@ crate-type = ["cdylib", "rlib"] [dependencies] cfg-if = "1.0" -clap = { version = "4.4.10", features = ["derive"], optional = true } +clap = { version = "4.4.11", features = ["derive"], optional = true } log = "0.4.17" thiserror = "1.0.48" futures = "0.3.21" diff --git a/polkadot/node/gum/proc-macro/Cargo.toml b/polkadot/node/gum/proc-macro/Cargo.toml index 055eafa1b9c..e260cf1f929 100644 --- a/polkadot/node/gum/proc-macro/Cargo.toml +++ b/polkadot/node/gum/proc-macro/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -syn = { version = "2.0.39", features = ["extra-traits", "full"] } +syn = { version = "2.0.40", features = ["extra-traits", "full"] } quote = "1.0.28" proc-macro2 = "1.0.56" proc-macro-crate = "2.0.1" diff --git a/polkadot/node/malus/Cargo.toml b/polkadot/node/malus/Cargo.toml index 1958bcf4620..2955bfbee18 100644 --- a/polkadot/node/malus/Cargo.toml +++ b/polkadot/node/malus/Cargo.toml @@ -40,7 +40,7 @@ assert_matches = "1.5" async-trait = "0.1.57" sp-keystore = { path = "../../../substrate/primitives/keystore" } sp-core = { path = "../../../substrate/primitives/core" } -clap = { version = "4.4.10", features = ["derive"] } +clap = { version = "4.4.11", features = ["derive"] } futures = "0.3.21" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../gum" } diff --git a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml index eeb367f8aee..8a018e330ba 100644 --- a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml @@ -13,7 +13,7 @@ path = "src/main.rs" [dependencies] parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } -clap = { version = "4.4.10", features = ["derive"] } +clap = { version = "4.4.11", features = ["derive"] } futures = "0.3.21" futures-timer = "3.0.2" log = "0.4.17" diff --git a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml index 0de349eac01..8e4022a718f 100644 --- a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml @@ -13,7 +13,7 @@ path = "src/main.rs" [dependencies] parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } -clap = { version = "4.4.10", features = ["derive"] } +clap = { version = "4.4.11", features = ["derive"] } futures = "0.3.21" futures-timer = "3.0.2" log = "0.4.17" diff --git a/polkadot/utils/generate-bags/Cargo.toml b/polkadot/utils/generate-bags/Cargo.toml index 1cd7b057c87..361c6af71bc 100644 --- a/polkadot/utils/generate-bags/Cargo.toml +++ b/polkadot/utils/generate-bags/Cargo.toml @@ -7,7 +7,7 @@ license.workspace = true description = "CLI to generate voter bags for Polkadot runtimes" [dependencies] -clap = { version = "4.4.10", features = ["derive"] } +clap = { version = "4.4.11", features = ["derive"] } generate-bags = { path = "../../../substrate/utils/frame/generate-bags" } sp-io = { path = "../../../substrate/primitives/io" } diff --git a/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml b/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml index 7f0c49f0c26..4a75142d00c 100644 --- a/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml +++ b/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml @@ -15,6 +15,6 @@ sp-tracing = { path = "../../../../substrate/primitives/tracing" } frame-system = { path = "../../../../substrate/frame/system" } sp-core = { path = "../../../../substrate/primitives/core" } -clap = { version = "4.4.10", features = ["derive"] } +clap = { version = "4.4.11", features = ["derive"] } log = "0.4.17" tokio = { version = "1.24.2", features = ["macros"] } diff --git a/polkadot/xcm/procedural/Cargo.toml b/polkadot/xcm/procedural/Cargo.toml index b42f69d4438..bb67bf0d1b0 100644 --- a/polkadot/xcm/procedural/Cargo.toml +++ b/polkadot/xcm/procedural/Cargo.toml @@ -13,7 +13,7 @@ proc-macro = true [dependencies] proc-macro2 = "1.0.56" quote = "1.0.28" -syn = "2.0.39" +syn = "2.0.40" Inflector = "0.11.4" [dev-dependencies] diff --git a/substrate/bin/minimal/node/Cargo.toml b/substrate/bin/minimal/node/Cargo.toml index d8c8c7740b0..4358009057a 100644 --- a/substrate/bin/minimal/node/Cargo.toml +++ b/substrate/bin/minimal/node/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] name = "minimal-node" [dependencies] -clap = { version = "4.4.10", features = ["derive"] } +clap = { version = "4.4.11", features = ["derive"] } futures = { version = "0.3.21", features = ["thread-pool"] } futures-timer = "3.0.1" jsonrpsee = { version = "0.16.2", features = ["server"] } diff --git a/substrate/bin/node-template/node/Cargo.toml b/substrate/bin/node-template/node/Cargo.toml index a76aaf2a631..1541ffec27f 100644 --- a/substrate/bin/node-template/node/Cargo.toml +++ b/substrate/bin/node-template/node/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] name = "node-template" [dependencies] -clap = { version = "4.4.10", features = ["derive"] } +clap = { version = "4.4.11", features = ["derive"] } futures = { version = "0.3.21", features = ["thread-pool"] } serde_json = "1.0.108" diff --git a/substrate/bin/node/bench/Cargo.toml b/substrate/bin/node/bench/Cargo.toml index 903eb4de7e6..1d9ce149d4f 100644 --- a/substrate/bin/node/bench/Cargo.toml +++ b/substrate/bin/node/bench/Cargo.toml @@ -13,7 +13,7 @@ publish = false [dependencies] array-bytes = "6.1" -clap = { version = "4.4.10", features = ["derive"] } +clap = { version = "4.4.11", features = ["derive"] } log = "0.4.17" node-primitives = { path = "../primitives" } node-testing = { path = "../testing" } diff --git a/substrate/bin/node/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml index e511633ff50..307aae1189e 100644 --- a/substrate/bin/node/cli/Cargo.toml +++ b/substrate/bin/node/cli/Cargo.toml @@ -38,7 +38,7 @@ crate-type = ["cdylib", "rlib"] [dependencies] # third-party dependencies array-bytes = "6.1" -clap = { version = "4.4.10", features = ["derive"], optional = true } +clap = { version = "4.4.11", features = ["derive"], optional = true } codec = { package = "parity-scale-codec", version = "3.6.1" } serde = { version = "1.0.193", features = ["derive"] } jsonrpsee = { version = "0.16.2", features = ["server"] } @@ -157,7 +157,7 @@ sp-trie = { path = "../../../primitives/trie" } sp-state-machine = { path = "../../../primitives/state-machine" } [build-dependencies] -clap = { version = "4.4.10", optional = true } +clap = { version = "4.4.11", optional = true } clap_complete = { version = "4.0.2", optional = true } node-inspect = { package = "staging-node-inspect", path = "../inspect", optional = true } frame-benchmarking-cli = { path = "../../../utils/frame/benchmarking-cli", optional = true } diff --git a/substrate/bin/node/inspect/Cargo.toml b/substrate/bin/node/inspect/Cargo.toml index cdf4b1ff146..0457fd54cab 100644 --- a/substrate/bin/node/inspect/Cargo.toml +++ b/substrate/bin/node/inspect/Cargo.toml @@ -12,7 +12,7 @@ repository.workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "4.4.10", features = ["derive"] } +clap = { version = "4.4.11", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.6.1" } thiserror = "1.0" sc-cli = { path = "../../../client/cli" } diff --git a/substrate/bin/utils/chain-spec-builder/Cargo.toml b/substrate/bin/utils/chain-spec-builder/Cargo.toml index bfa2951cf00..110c1b6ce02 100644 --- a/substrate/bin/utils/chain-spec-builder/Cargo.toml +++ b/substrate/bin/utils/chain-spec-builder/Cargo.toml @@ -20,7 +20,7 @@ name = "chain-spec-builder" crate-type = ["rlib"] [dependencies] -clap = { version = "4.4.10", features = ["derive"] } +clap = { version = "4.4.11", features = ["derive"] } log = "0.4.17" sc-chain-spec = { path = "../../../client/chain-spec" } serde_json = "1.0.108" diff --git a/substrate/bin/utils/subkey/Cargo.toml b/substrate/bin/utils/subkey/Cargo.toml index 1769afd865b..37eba299cb2 100644 --- a/substrate/bin/utils/subkey/Cargo.toml +++ b/substrate/bin/utils/subkey/Cargo.toml @@ -17,5 +17,5 @@ path = "src/main.rs" name = "subkey" [dependencies] -clap = { version = "4.4.10", features = ["derive"] } +clap = { version = "4.4.11", features = ["derive"] } sc-cli = { path = "../../../client/cli" } diff --git a/substrate/client/chain-spec/derive/Cargo.toml b/substrate/client/chain-spec/derive/Cargo.toml index 36ad67ce1c5..0fbe1074d27 100644 --- a/substrate/client/chain-spec/derive/Cargo.toml +++ b/substrate/client/chain-spec/derive/Cargo.toml @@ -18,4 +18,4 @@ proc-macro = true proc-macro-crate = "2.0.1" proc-macro2 = "1.0.56" quote = "1.0.28" -syn = "2.0.39" +syn = "2.0.40" diff --git a/substrate/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index d75eac1ac98..1f3e8f44f82 100644 --- a/substrate/client/cli/Cargo.toml +++ b/substrate/client/cli/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] array-bytes = "6.1" chrono = "0.4.27" -clap = { version = "4.4.10", features = ["derive", "string", "wrap_help"] } +clap = { version = "4.4.11", features = ["derive", "string", "wrap_help"] } fdlimit = "0.3.0" futures = "0.3.21" itertools = "0.10.3" diff --git a/substrate/client/storage-monitor/Cargo.toml b/substrate/client/storage-monitor/Cargo.toml index c0eb9d94b92..f7c62f44af4 100644 --- a/substrate/client/storage-monitor/Cargo.toml +++ b/substrate/client/storage-monitor/Cargo.toml @@ -9,7 +9,7 @@ description = "Storage monitor service for substrate" homepage = "https://substrate.io" [dependencies] -clap = { version = "4.4.10", features = ["derive", "string"] } +clap = { version = "4.4.11", features = ["derive", "string"] } log = "0.4.17" fs4 = "0.7.0" sc-client-db = { path = "../db", default-features = false } diff --git a/substrate/client/tracing/proc-macro/Cargo.toml b/substrate/client/tracing/proc-macro/Cargo.toml index 673ef50aead..509e87174da 100644 --- a/substrate/client/tracing/proc-macro/Cargo.toml +++ b/substrate/client/tracing/proc-macro/Cargo.toml @@ -18,4 +18,4 @@ proc-macro = true proc-macro-crate = "2.0.1" proc-macro2 = "1.0.56" quote = { version = "1.0.28", features = ["proc-macro"] } -syn = { version = "2.0.39", features = ["extra-traits", "full", "parsing", "proc-macro"] } +syn = { version = "2.0.40", features = ["extra-traits", "full", "parsing", "proc-macro"] } diff --git a/substrate/frame/contracts/proc-macro/Cargo.toml b/substrate/frame/contracts/proc-macro/Cargo.toml index 8aa6e6679cd..f05df18954c 100644 --- a/substrate/frame/contracts/proc-macro/Cargo.toml +++ b/substrate/frame/contracts/proc-macro/Cargo.toml @@ -17,7 +17,7 @@ proc-macro = true [dependencies] proc-macro2 = "1.0.56" quote = "1.0.28" -syn = { version = "2.0.39", features = ["full"] } +syn = { version = "2.0.40", features = ["full"] } [dev-dependencies] diff --git a/substrate/frame/election-provider-support/solution-type/Cargo.toml b/substrate/frame/election-provider-support/solution-type/Cargo.toml index 2e95163fc26..f81b366a5ec 100644 --- a/substrate/frame/election-provider-support/solution-type/Cargo.toml +++ b/substrate/frame/election-provider-support/solution-type/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -syn = { version = "2.0.39", features = ["full", "visit"] } +syn = { version = "2.0.40", features = ["full", "visit"] } quote = "1.0.28" proc-macro2 = "1.0.56" proc-macro-crate = "2.0.1" diff --git a/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml b/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml index 144ed8b18c5..1f0261571a5 100644 --- a/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml +++ b/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml @@ -13,7 +13,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "4.4.10", features = ["derive"] } +clap = { version = "4.4.11", features = ["derive"] } honggfuzz = "0.5" rand = { version = "0.8", features = ["small_rng", "std"] } diff --git a/substrate/frame/staking/reward-curve/Cargo.toml b/substrate/frame/staking/reward-curve/Cargo.toml index 1e5717e4075..136cdd7d1b0 100644 --- a/substrate/frame/staking/reward-curve/Cargo.toml +++ b/substrate/frame/staking/reward-curve/Cargo.toml @@ -18,7 +18,7 @@ proc-macro = true proc-macro-crate = "2.0.1" proc-macro2 = "1.0.56" quote = "1.0.28" -syn = { version = "2.0.39", features = ["full", "visit"] } +syn = { version = "2.0.40", features = ["full", "visit"] } [dev-dependencies] sp-runtime = { path = "../../../primitives/runtime" } diff --git a/substrate/frame/support/procedural/Cargo.toml b/substrate/frame/support/procedural/Cargo.toml index 7c207b230f3..769cb9f1cfb 100644 --- a/substrate/frame/support/procedural/Cargo.toml +++ b/substrate/frame/support/procedural/Cargo.toml @@ -21,7 +21,7 @@ cfg-expr = "0.15.5" itertools = "0.10.3" proc-macro2 = "1.0.56" quote = "1.0.28" -syn = { version = "2.0.39", features = ["full"] } +syn = { version = "2.0.40", features = ["full"] } frame-support-procedural-tools = { path = "tools" } macro_magic = { version = "0.5.0", features = ["proc_support"] } proc-macro-warning = { version = "1.0.0", default-features = false } diff --git a/substrate/frame/support/procedural/tools/Cargo.toml b/substrate/frame/support/procedural/tools/Cargo.toml index 0b04d64a4bc..9be7a029ef9 100644 --- a/substrate/frame/support/procedural/tools/Cargo.toml +++ b/substrate/frame/support/procedural/tools/Cargo.toml @@ -15,5 +15,5 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro-crate = "2.0.1" proc-macro2 = "1.0.56" quote = "1.0.28" -syn = { version = "2.0.39", features = ["extra-traits", "full", "visit"] } +syn = { version = "2.0.40", features = ["extra-traits", "full", "visit"] } frame-support-procedural-tools-derive = { path = "derive" } diff --git a/substrate/frame/support/procedural/tools/derive/Cargo.toml b/substrate/frame/support/procedural/tools/derive/Cargo.toml index 6040449df65..dc2774cb177 100644 --- a/substrate/frame/support/procedural/tools/derive/Cargo.toml +++ b/substrate/frame/support/procedural/tools/derive/Cargo.toml @@ -17,4 +17,4 @@ proc-macro = true [dependencies] proc-macro2 = "1.0.56" quote = { version = "1.0.28", features = ["proc-macro"] } -syn = { version = "2.0.39", features = ["extra-traits", "full", "parsing", "proc-macro"] } +syn = { version = "2.0.40", features = ["extra-traits", "full", "parsing", "proc-macro"] } diff --git a/substrate/primitives/api/proc-macro/Cargo.toml b/substrate/primitives/api/proc-macro/Cargo.toml index 487b2cd9b84..c66a7c65d11 100644 --- a/substrate/primitives/api/proc-macro/Cargo.toml +++ b/substrate/primitives/api/proc-macro/Cargo.toml @@ -17,7 +17,7 @@ proc-macro = true [dependencies] quote = "1.0.28" -syn = { version = "2.0.39", features = ["extra-traits", "fold", "full", "visit"] } +syn = { version = "2.0.40", features = ["extra-traits", "fold", "full", "visit"] } proc-macro2 = "1.0.56" blake2 = { version = "0.10.4", default-features = false } proc-macro-crate = "2.0.1" diff --git a/substrate/primitives/core/hashing/proc-macro/Cargo.toml b/substrate/primitives/core/hashing/proc-macro/Cargo.toml index a5e5956e94f..a16bec5a2a1 100644 --- a/substrate/primitives/core/hashing/proc-macro/Cargo.toml +++ b/substrate/primitives/core/hashing/proc-macro/Cargo.toml @@ -17,5 +17,5 @@ proc-macro = true [dependencies] quote = "1.0.28" -syn = { version = "2.0.39", features = ["full", "parsing"] } +syn = { version = "2.0.40", features = ["full", "parsing"] } sp-core-hashing = { path = "..", default-features = false } diff --git a/substrate/primitives/debug-derive/Cargo.toml b/substrate/primitives/debug-derive/Cargo.toml index 1f739c256d0..0662cd309ed 100644 --- a/substrate/primitives/debug-derive/Cargo.toml +++ b/substrate/primitives/debug-derive/Cargo.toml @@ -18,7 +18,7 @@ proc-macro = true [dependencies] quote = "1.0.28" -syn = "2.0.39" +syn = "2.0.40" proc-macro2 = "1.0.56" [features] diff --git a/substrate/primitives/npos-elections/fuzzer/Cargo.toml b/substrate/primitives/npos-elections/fuzzer/Cargo.toml index bd1fa856813..591ef412363 100644 --- a/substrate/primitives/npos-elections/fuzzer/Cargo.toml +++ b/substrate/primitives/npos-elections/fuzzer/Cargo.toml @@ -14,7 +14,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "4.4.10", features = ["derive"] } +clap = { version = "4.4.11", features = ["derive"] } honggfuzz = "0.5" rand = { version = "0.8", features = ["small_rng", "std"] } sp-npos-elections = { path = ".." } diff --git a/substrate/primitives/runtime-interface/proc-macro/Cargo.toml b/substrate/primitives/runtime-interface/proc-macro/Cargo.toml index 8179e88546c..f94f568c913 100644 --- a/substrate/primitives/runtime-interface/proc-macro/Cargo.toml +++ b/substrate/primitives/runtime-interface/proc-macro/Cargo.toml @@ -21,4 +21,4 @@ proc-macro-crate = "2.0.1" proc-macro2 = "1.0.56" quote = "1.0.28" expander = "2.0.0" -syn = { version = "2.0.39", features = ["extra-traits", "fold", "full", "visit"] } +syn = { version = "2.0.40", features = ["extra-traits", "fold", "full", "visit"] } diff --git a/substrate/primitives/version/proc-macro/Cargo.toml b/substrate/primitives/version/proc-macro/Cargo.toml index 715316b842d..05a3dcb2e27 100644 --- a/substrate/primitives/version/proc-macro/Cargo.toml +++ b/substrate/primitives/version/proc-macro/Cargo.toml @@ -19,7 +19,7 @@ proc-macro = true codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } proc-macro2 = "1.0.56" quote = "1.0.28" -syn = { version = "2.0.39", features = ["extra-traits", "fold", "full", "visit"] } +syn = { version = "2.0.40", features = ["extra-traits", "fold", "full", "visit"] } [dev-dependencies] sp-version = { path = ".." } diff --git a/substrate/scripts/ci/node-template-release/Cargo.toml b/substrate/scripts/ci/node-template-release/Cargo.toml index 59c53e952b9..beb0e0852de 100644 --- a/substrate/scripts/ci/node-template-release/Cargo.toml +++ b/substrate/scripts/ci/node-template-release/Cargo.toml @@ -11,7 +11,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "4.4.10", features = ["derive"] } +clap = { version = "4.4.11", features = ["derive"] } flate2 = "1.0" fs_extra = "1.3" glob = "0.3" diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml index e88eb60ee63..8fb2c731520 100644 --- a/substrate/utils/frame/benchmarking-cli/Cargo.toml +++ b/substrate/utils/frame/benchmarking-cli/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] array-bytes = "6.1" chrono = "0.4" -clap = { version = "4.4.10", features = ["derive"] } +clap = { version = "4.4.11", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.6.1" } comfy-table = { version = "7.0.1", default-features = false } handlebars = "4.2.2" diff --git a/substrate/utils/frame/frame-utilities-cli/Cargo.toml b/substrate/utils/frame/frame-utilities-cli/Cargo.toml index 6e33ed88e0a..5dc974cf89b 100644 --- a/substrate/utils/frame/frame-utilities-cli/Cargo.toml +++ b/substrate/utils/frame/frame-utilities-cli/Cargo.toml @@ -11,7 +11,7 @@ documentation = "https://docs.rs/substrate-frame-cli" readme = "README.md" [dependencies] -clap = { version = "4.4.10", features = ["derive"] } +clap = { version = "4.4.11", features = ["derive"] } frame-support = { path = "../../../frame/support" } frame-system = { path = "../../../frame/system" } sc-cli = { path = "../../../client/cli" } diff --git a/substrate/utils/frame/generate-bags/node-runtime/Cargo.toml b/substrate/utils/frame/generate-bags/node-runtime/Cargo.toml index a2ee3883786..8dfc78c63ca 100644 --- a/substrate/utils/frame/generate-bags/node-runtime/Cargo.toml +++ b/substrate/utils/frame/generate-bags/node-runtime/Cargo.toml @@ -14,4 +14,4 @@ kitchensink-runtime = { path = "../../../../bin/node/runtime" } generate-bags = { path = ".." } # third-party -clap = { version = "4.4.10", features = ["derive"] } +clap = { version = "4.4.11", features = ["derive"] } diff --git a/substrate/utils/frame/try-runtime/cli/Cargo.toml b/substrate/utils/frame/try-runtime/cli/Cargo.toml index 31e95a8be41..3745198db31 100644 --- a/substrate/utils/frame/try-runtime/cli/Cargo.toml +++ b/substrate/utils/frame/try-runtime/cli/Cargo.toml @@ -35,7 +35,7 @@ frame-try-runtime = { path = "../../../../frame/try-runtime", optional = true } substrate-rpc-client = { path = "../../rpc/client" } async-trait = "0.1.57" -clap = { version = "4.4.10", features = ["derive"] } +clap = { version = "4.4.11", features = ["derive"] } hex = { version = "0.4.3", default-features = false } log = "0.4.17" parity-scale-codec = "3.6.1" -- GitLab From 50b7b6f39999c825276454fe9bd4ba6e34fc4dd4 Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Tue, 12 Dec 2023 00:47:24 +0800 Subject: [PATCH 36/59] fix comment of exit_runtime (#2616) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Köcher --- .../primitives/state-machine/src/overlayed_changes/changeset.rs | 2 +- substrate/primitives/state-machine/src/overlayed_changes/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/primitives/state-machine/src/overlayed_changes/changeset.rs b/substrate/primitives/state-machine/src/overlayed_changes/changeset.rs index 8f2d02fd684..59589dbbb37 100644 --- a/substrate/primitives/state-machine/src/overlayed_changes/changeset.rs +++ b/substrate/primitives/state-machine/src/overlayed_changes/changeset.rs @@ -298,7 +298,7 @@ impl OverlayedMap { /// Call this when control returns from the runtime. /// - /// This commits all dangling transaction left open by the runtime. + /// This rollbacks all dangling transaction left open by the runtime. /// Calling this while already outside the runtime will return an error. pub fn exit_runtime(&mut self) -> Result<(), NotInRuntime> { if let ExecutionMode::Client = self.execution_mode { diff --git a/substrate/primitives/state-machine/src/overlayed_changes/mod.rs b/substrate/primitives/state-machine/src/overlayed_changes/mod.rs index 28cfecf1dbd..9525c2c9dfe 100644 --- a/substrate/primitives/state-machine/src/overlayed_changes/mod.rs +++ b/substrate/primitives/state-machine/src/overlayed_changes/mod.rs @@ -498,7 +498,7 @@ impl OverlayedChanges { /// Call this when control returns from the runtime. /// - /// This commits all dangling transaction left open by the runtime. + /// This rollbacks all dangling transaction left open by the runtime. /// Calling this while outside the runtime will return an error. pub fn exit_runtime(&mut self) -> Result<(), NotInRuntime> { self.top.exit_runtime()?; -- GitLab From c2d45e7e474c94e77b57c0aefe181fa8708d7965 Mon Sep 17 00:00:00 2001 From: Gabriel Facco de Arruda Date: Mon, 11 Dec 2023 20:12:15 -0300 Subject: [PATCH 37/59] pallet-vesting: Configurable block number provider (#2403) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR makes the block number provider configurable through the Config trait in pallet-vesting, this gives parachains the option to use the relay chain block number provider from ParachainSystem. --------- Co-authored-by: Bastian Köcher --- polkadot/runtime/common/src/claims.rs | 1 + polkadot/runtime/common/src/purchase.rs | 1 + polkadot/runtime/rococo/src/lib.rs | 1 + polkadot/runtime/test-runtime/src/lib.rs | 1 + polkadot/runtime/westend/src/lib.rs | 1 + prdoc/pr_2403.prdoc | 9 +++++++++ substrate/bin/node/runtime/src/lib.rs | 1 + substrate/frame/system/src/lib.rs | 5 +++++ substrate/frame/vesting/src/benchmarking.rs | 8 ++++---- substrate/frame/vesting/src/lib.rs | 13 ++++++++----- substrate/frame/vesting/src/mock.rs | 1 + 11 files changed, 33 insertions(+), 9 deletions(-) create mode 100644 prdoc/pr_2403.prdoc diff --git a/polkadot/runtime/common/src/claims.rs b/polkadot/runtime/common/src/claims.rs index 4f04a79be55..e05c0fe5c4c 100644 --- a/polkadot/runtime/common/src/claims.rs +++ b/polkadot/runtime/common/src/claims.rs @@ -801,6 +801,7 @@ mod tests { type MinVestedTransfer = MinVestedTransfer; type WeightInfo = (); type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons; + type BlockNumberProvider = System; const MAX_VESTING_SCHEDULES: u32 = 28; } diff --git a/polkadot/runtime/common/src/purchase.rs b/polkadot/runtime/common/src/purchase.rs index 06b0a0a0211..f43f16b838c 100644 --- a/polkadot/runtime/common/src/purchase.rs +++ b/polkadot/runtime/common/src/purchase.rs @@ -573,6 +573,7 @@ mod tests { type MinVestedTransfer = MinVestedTransfer; type WeightInfo = (); type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons; + type BlockNumberProvider = System; const MAX_VESTING_SCHEDULES: u32 = 28; } diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 572cdf1aade..26cc6d95449 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -744,6 +744,7 @@ impl pallet_vesting::Config for Runtime { type MinVestedTransfer = MinVestedTransfer; type WeightInfo = weights::pallet_vesting::WeightInfo; type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons; + type BlockNumberProvider = System; const MAX_VESTING_SCHEDULES: u32 = 28; } diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index 81b9b63f75b..351a1393fa0 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -463,6 +463,7 @@ impl pallet_vesting::Config for Runtime { type MinVestedTransfer = MinVestedTransfer; type WeightInfo = (); type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons; + type BlockNumberProvider = System; const MAX_VESTING_SCHEDULES: u32 = 28; } diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 25d4c1d2d6f..11f267a327b 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -948,6 +948,7 @@ impl pallet_vesting::Config for Runtime { type MinVestedTransfer = MinVestedTransfer; type WeightInfo = weights::pallet_vesting::WeightInfo; type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons; + type BlockNumberProvider = System; const MAX_VESTING_SCHEDULES: u32 = 28; } diff --git a/prdoc/pr_2403.prdoc b/prdoc/pr_2403.prdoc new file mode 100644 index 00000000000..f1c4d3ecbaf --- /dev/null +++ b/prdoc/pr_2403.prdoc @@ -0,0 +1,9 @@ +title: Configurable block number provider in pallet-vesting + +doc: + - audience: Runtime Dev + description: | + Adds `BlockNumberProvider` type to pallet-vesting Config trait, allowing for custom providers instead of hardcoding frame-system. + This is particularly useful for parachains wanting to use `cumulus_pallet_parachain_system::RelaychainDataProvider` with `pallet-vesting`. + +crates: [ ] diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index eded60adfd7..b8c638ef155 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -1552,6 +1552,7 @@ impl pallet_vesting::Config for Runtime { type MinVestedTransfer = MinVestedTransfer; type WeightInfo = pallet_vesting::weights::SubstrateWeight; type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons; + type BlockNumberProvider = System; // `VestingInfo` encode length is 36bytes. 28 schedules gets encoded as 1009 bytes, which is the // highest number of schedules that encodes less than 2^10. const MAX_VESTING_SCHEDULES: u32 = 28; diff --git a/substrate/frame/system/src/lib.rs b/substrate/frame/system/src/lib.rs index 6624bb43a80..3697e36f3fc 100644 --- a/substrate/frame/system/src/lib.rs +++ b/substrate/frame/system/src/lib.rs @@ -1919,6 +1919,11 @@ impl BlockNumberProvider for Pallet { fn current_block_number() -> Self::BlockNumber { Pallet::::block_number() } + + #[cfg(feature = "runtime-benchmarks")] + fn set_block_number(n: BlockNumberFor) { + Self::set_block_number(n) + } } /// Implement StoredMap for a simple single-item, provide-when-not-default system. This works fine diff --git a/substrate/frame/vesting/src/benchmarking.rs b/substrate/frame/vesting/src/benchmarking.rs index 34aa04607ad..311590873d9 100644 --- a/substrate/frame/vesting/src/benchmarking.rs +++ b/substrate/frame/vesting/src/benchmarking.rs @@ -55,7 +55,7 @@ fn add_vesting_schedules( let source_lookup = T::Lookup::unlookup(source.clone()); T::Currency::make_free_balance_be(&source, BalanceOf::::max_value()); - System::::set_block_number(BlockNumberFor::::zero()); + T::BlockNumberProvider::set_block_number(BlockNumberFor::::zero()); let mut total_locked: BalanceOf = Zero::zero(); for _ in 0..n { @@ -116,7 +116,7 @@ benchmarks! { add_vesting_schedules::(caller_lookup, s)?; // At block 21, everything is unlocked. - System::::set_block_number(21u32.into()); + T::BlockNumberProvider::set_block_number(21u32.into()); assert_eq!( Vesting::::vesting_balance(&caller), Some(BalanceOf::::zero()), @@ -173,7 +173,7 @@ benchmarks! { add_locks::(&other, l as u8); add_vesting_schedules::(other_lookup.clone(), s)?; // At block 21 everything is unlocked. - System::::set_block_number(21u32.into()); + T::BlockNumberProvider::set_block_number(21u32.into()); assert_eq!( Vesting::::vesting_balance(&other), @@ -335,7 +335,7 @@ benchmarks! { let total_transferred = add_vesting_schedules::(caller_lookup, s)?; // Go to about half way through all the schedules duration. (They all start at 1, and have a duration of 20 or 21). - System::::set_block_number(11u32.into()); + T::BlockNumberProvider::set_block_number(11u32.into()); // We expect half the original locked balance (+ any remainder that vests on the last block). let expected_balance = total_transferred / 2u32.into(); assert_eq!( diff --git a/substrate/frame/vesting/src/lib.rs b/substrate/frame/vesting/src/lib.rs index dbad7926a30..4101caded41 100644 --- a/substrate/frame/vesting/src/lib.rs +++ b/substrate/frame/vesting/src/lib.rs @@ -71,8 +71,8 @@ use frame_system::pallet_prelude::BlockNumberFor; use scale_info::TypeInfo; use sp_runtime::{ traits::{ - AtLeast32BitUnsigned, Bounded, Convert, MaybeSerializeDeserialize, One, Saturating, - StaticLookup, Zero, + AtLeast32BitUnsigned, BlockNumberProvider, Bounded, Convert, MaybeSerializeDeserialize, + One, Saturating, StaticLookup, Zero, }, DispatchError, RuntimeDebug, }; @@ -176,6 +176,9 @@ pub mod pallet { /// the unvested amount. type UnvestedFundsAllowedWithdrawReasons: Get; + /// Provider for the block number. + type BlockNumberProvider: BlockNumberProvider>; + /// Maximum number of vesting schedules an account may have at a given moment. const MAX_VESTING_SCHEDULES: u32; } @@ -565,7 +568,7 @@ impl Pallet { schedules: Vec, BlockNumberFor>>, action: VestingAction, ) -> (Vec, BlockNumberFor>>, BalanceOf) { - let now = >::block_number(); + let now = T::BlockNumberProvider::current_block_number(); let mut total_locked_now: BalanceOf = Zero::zero(); let filtered_schedules = action @@ -649,7 +652,7 @@ impl Pallet { let (mut schedules, mut locked_now) = Self::report_schedule_updates(schedules.to_vec(), action); - let now = >::block_number(); + let now = T::BlockNumberProvider::current_block_number(); if let Some(new_schedule) = Self::merge_vesting_info(now, schedule1, schedule2) { // Merging created a new schedule so we: // 1) need to add it to the accounts vesting schedule collection, @@ -685,7 +688,7 @@ where /// Get the amount that is currently being vested and cannot be transferred out of this account. fn vesting_balance(who: &T::AccountId) -> Option> { if let Some(v) = Self::vesting(who) { - let now = >::block_number(); + let now = T::BlockNumberProvider::current_block_number(); let total_locked_now = v.iter().fold(Zero::zero(), |total, schedule| { schedule.locked_at::(now).saturating_add(total) }); diff --git a/substrate/frame/vesting/src/mock.rs b/substrate/frame/vesting/src/mock.rs index 67444b8d125..3af4a9c962d 100644 --- a/substrate/frame/vesting/src/mock.rs +++ b/substrate/frame/vesting/src/mock.rs @@ -96,6 +96,7 @@ impl Config for Test { type MinVestedTransfer = MinVestedTransfer; type WeightInfo = (); type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons; + type BlockNumberProvider = System; } pub struct ExtBuilder { -- GitLab From 048a9c2744ca83ef6faeadd2cd19466295d52b9d Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Tue, 12 Dec 2023 13:23:02 +0700 Subject: [PATCH 38/59] Staking: Add `deprecate_controller_batch` AdminOrigin call (#2589) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Partially Addresses #2500 Adds a `deprecate_controller_batch` call to the staking pallet that is callable by `Root` and `StakingAdmin`. To be used for controller account deprecation and removed thereafter. Adds `MaxControllersDeprecationBatch` pallet constant that defines max possible deprecations per call. - [x] Add `deprecate_controller_batch` call, and `MaxControllersInDeprecationBatch` constant. - [x] Add tests, benchmark, weights. Tests that weight is only consumed if unique pair. - [x] Adds `StakingAdmin` origin to staking's `AdminOrigin` type in westend runtime. - [x] Determined that worst case 5,900 deprecations does fit into `maxBlock` `proofSize` and `refTime` in both normal and operational thresholds, meaning we can deprecate all controllers for each network in one call. ## Block Weights By querying `consts.system.blockWeights` we can see that the `deprecate_controller_batch` weights fit within the `normal` threshold on Polkadot. #### `controller_deprecation_batch` where i = 5900: #### Ref time: 69,933,325,300 #### Proof size: 21,040,390 ### Polkadot ``` // consts.query.blockWeights maxBlock: { refTime: 2,000,000,000,000 proofSize: 18,446,744,073,709,551,615 } normal: { maxExtrinsic: { refTime: 1,479,873,955,000 proofSize: 13,650,590,614,545,068,195 } maxTotal: { refTime: 1,500,000,000,000 proofSize: 13,835,058,055,282,163,711 } } ``` ### Kusama ``` // consts.query.blockWeights maxBlock: { refTime: 2,000,000,000,000 proofSize: 18,446,744,073,709,551,615 } normal: { maxExtrinsic: { refTime: 1,479,875,294,000 proofSize: 13,650,590,614,545,068,195 } maxTotal: { refTime: 1,500,000,000,000 proofSize: 13,835,058,055,282,163,711 } } ``` --------- Co-authored-by: command-bot <> Co-authored-by: Gonçalo Pestana --- polkadot/runtime/test-runtime/src/lib.rs | 1 + polkadot/runtime/westend/src/lib.rs | 4 +- .../westend/src/weights/pallet_staking.rs | 214 ++++----- substrate/bin/node/runtime/src/lib.rs | 2 + substrate/frame/babe/src/mock.rs | 1 + substrate/frame/beefy/src/mock.rs | 1 + .../test-staking-e2e/src/mock.rs | 1 + substrate/frame/fast-unstake/src/mock.rs | 1 + substrate/frame/grandpa/src/mock.rs | 1 + .../nomination-pools/benchmarking/src/mock.rs | 1 + .../nomination-pools/test-staking/src/mock.rs | 1 + .../frame/offences/benchmarking/src/mock.rs | 1 + substrate/frame/root-offences/src/mock.rs | 1 + .../frame/session/benchmarking/src/mock.rs | 1 + substrate/frame/staking/src/benchmarking.rs | 34 ++ substrate/frame/staking/src/mock.rs | 2 + substrate/frame/staking/src/pallet/mod.rs | 56 ++- substrate/frame/staking/src/tests.rs | 179 +++++++- substrate/frame/staking/src/weights.rs | 407 ++++++++++-------- 19 files changed, 624 insertions(+), 285 deletions(-) diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index 351a1393fa0..cd9590796ae 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -356,6 +356,7 @@ impl pallet_staking::Config for Runtime { type TargetList = pallet_staking::UseValidatorsMap; type NominationsQuota = pallet_staking::FixedNominationsQuota; type MaxUnlockingChunks = frame_support::traits::ConstU32<32>; + type MaxControllersInDeprecationBatch = ConstU32<5900>; type HistoryDepth = frame_support::traits::ConstU32<84>; type BenchmarkingConfig = runtime_common::StakingBenchmarkingConfig; type EventListeners = (); diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 11f267a327b..827a4953ec3 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -672,6 +672,7 @@ parameter_types! { pub const MaxNominators: u32 = 64; pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17); pub const MaxNominations: u32 = ::LIMIT as u32; + pub const MaxControllersInDeprecationBatch: u32 = 751; } impl pallet_staking::Config for Runtime { @@ -686,7 +687,7 @@ impl pallet_staking::Config for Runtime { type SessionsPerEra = SessionsPerEra; type BondingDuration = BondingDuration; type SlashDeferDuration = SlashDeferDuration; - type AdminOrigin = EnsureRoot; + type AdminOrigin = EitherOf, StakingAdmin>; type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type MaxExposurePageSize = MaxExposurePageSize; @@ -699,6 +700,7 @@ impl pallet_staking::Config for Runtime { type NominationsQuota = pallet_staking::FixedNominationsQuota<{ MaxNominations::get() }>; type MaxUnlockingChunks = frame_support::traits::ConstU32<32>; type HistoryDepth = frame_support::traits::ConstU32<84>; + type MaxControllersInDeprecationBatch = MaxControllersInDeprecationBatch; type BenchmarkingConfig = runtime_common::StakingBenchmarkingConfig; type EventListeners = NominationPools; type WeightInfo = weights::pallet_staking::WeightInfo; diff --git a/polkadot/runtime/westend/src/weights/pallet_staking.rs b/polkadot/runtime/westend/src/weights/pallet_staking.rs index 87b603621e8..1ecd44747ef 100644 --- a/polkadot/runtime/westend/src/weights/pallet_staking.rs +++ b/polkadot/runtime/westend/src/weights/pallet_staking.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_staking` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-12-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-itmxxexx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -62,8 +62,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `894` // Estimated: `4764` - // Minimum execution time: 38_052_000 picoseconds. - Weight::from_parts(39_303_000, 0) + // Minimum execution time: 38_316_000 picoseconds. + Weight::from_parts(40_022_000, 0) .saturating_add(Weight::from_parts(0, 4764)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(4)) @@ -84,8 +84,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1921` // Estimated: `8877` - // Minimum execution time: 81_690_000 picoseconds. - Weight::from_parts(83_889_000, 0) + // Minimum execution time: 81_027_000 picoseconds. + Weight::from_parts(83_964_000, 0) .saturating_add(Weight::from_parts(0, 8877)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(7)) @@ -112,8 +112,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `2128` // Estimated: `8877` - // Minimum execution time: 84_409_000 picoseconds. - Weight::from_parts(87_330_000, 0) + // Minimum execution time: 85_585_000 picoseconds. + Weight::from_parts(87_256_000, 0) .saturating_add(Weight::from_parts(0, 8877)) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(7)) @@ -133,11 +133,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1075` // Estimated: `4764` - // Minimum execution time: 39_770_000 picoseconds. - Weight::from_parts(40_828_632, 0) + // Minimum execution time: 39_520_000 picoseconds. + Weight::from_parts(41_551_548, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 824 - .saturating_add(Weight::from_parts(51_107, 0).saturating_mul(s.into())) + // Standard Error: 1_094 + .saturating_add(Weight::from_parts(50_426, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -174,11 +174,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `2127 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 82_500_000 picoseconds. - Weight::from_parts(90_099_121, 0) + // Minimum execution time: 82_915_000 picoseconds. + Weight::from_parts(89_597_160, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 3_280 - .saturating_add(Weight::from_parts(1_273_212, 0).saturating_mul(s.into())) + // Standard Error: 3_146 + .saturating_add(Weight::from_parts(1_228_061, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13)) .saturating_add(T::DbWeight::get().writes(11)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -210,8 +210,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1301` // Estimated: `4556` - // Minimum execution time: 48_236_000 picoseconds. - Weight::from_parts(49_518_000, 0) + // Minimum execution time: 48_070_000 picoseconds. + Weight::from_parts(49_226_000, 0) .saturating_add(Weight::from_parts(0, 4556)) .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(5)) @@ -225,11 +225,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1243 + k * (569 ±0)` // Estimated: `4556 + k * (3033 ±0)` - // Minimum execution time: 28_280_000 picoseconds. - Weight::from_parts(29_182_740, 0) + // Minimum execution time: 29_140_000 picoseconds. + Weight::from_parts(30_225_579, 0) .saturating_add(Weight::from_parts(0, 4556)) - // Standard Error: 6_102 - .saturating_add(Weight::from_parts(6_412_107, 0).saturating_mul(k.into())) + // Standard Error: 5_394 + .saturating_add(Weight::from_parts(6_401_367, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -262,11 +262,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1797 + n * (102 ±0)` // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 59_846_000 picoseconds. - Weight::from_parts(58_029_857, 0) + // Minimum execution time: 59_287_000 picoseconds. + Weight::from_parts(58_285_052, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 15_967 - .saturating_add(Weight::from_parts(3_898_764, 0).saturating_mul(n.into())) + // Standard Error: 14_556 + .saturating_add(Weight::from_parts(3_863_008, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(6)) @@ -290,8 +290,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1581` // Estimated: `6248` - // Minimum execution time: 51_223_000 picoseconds. - Weight::from_parts(52_310_000, 0) + // Minimum execution time: 51_035_000 picoseconds. + Weight::from_parts(52_163_000, 0) .saturating_add(Weight::from_parts(0, 6248)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(6)) @@ -306,8 +306,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `865` // Estimated: `4556` - // Minimum execution time: 15_762_000 picoseconds. - Weight::from_parts(16_381_000, 0) + // Minimum execution time: 15_809_000 picoseconds. + Weight::from_parts(16_451_000, 0) .saturating_add(Weight::from_parts(0, 4556)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -322,8 +322,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `932` // Estimated: `4556` - // Minimum execution time: 21_904_000 picoseconds. - Weight::from_parts(22_373_000, 0) + // Minimum execution time: 21_695_000 picoseconds. + Weight::from_parts(22_351_000, 0) .saturating_add(Weight::from_parts(0, 4556)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -336,8 +336,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `865` // Estimated: `4556` - // Minimum execution time: 18_869_000 picoseconds. - Weight::from_parts(19_422_000, 0) + // Minimum execution time: 18_548_000 picoseconds. + Weight::from_parts(19_205_000, 0) .saturating_add(Weight::from_parts(0, 4556)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(3)) @@ -348,8 +348,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_205_000 picoseconds. - Weight::from_parts(2_320_000, 0) + // Minimum execution time: 2_193_000 picoseconds. + Weight::from_parts(2_408_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -359,8 +359,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_179_000 picoseconds. - Weight::from_parts(7_843_000, 0) + // Minimum execution time: 7_475_000 picoseconds. + Weight::from_parts(7_874_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -370,8 +370,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_206_000 picoseconds. - Weight::from_parts(7_829_000, 0) + // Minimum execution time: 7_393_000 picoseconds. + Weight::from_parts(7_643_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -381,8 +381,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_414_000 picoseconds. - Weight::from_parts(7_770_000, 0) + // Minimum execution time: 7_474_000 picoseconds. + Weight::from_parts(7_814_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -393,13 +393,33 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_256_000 picoseconds. - Weight::from_parts(2_645_840, 0) + // Minimum execution time: 2_358_000 picoseconds. + Weight::from_parts(2_589_423, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 37 - .saturating_add(Weight::from_parts(10_207, 0).saturating_mul(v.into())) + // Standard Error: 81 + .saturating_add(Weight::from_parts(13_612, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `Staking::Ledger` (r:751 w:1502) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Payee` (r:751 w:0) + /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:0 w:751) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// The range of component `i` is `[0, 751]`. + fn deprecate_controller_batch(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `668 + i * (148 ±0)` + // Estimated: `990 + i * (3566 ±0)` + // Minimum execution time: 1_934_000 picoseconds. + Weight::from_parts(2_070_000, 0) + .saturating_add(Weight::from_parts(0, 990)) + // Standard Error: 19_129 + .saturating_add(Weight::from_parts(13_231_580, 0).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(i.into()))) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(i.into()))) + .saturating_add(Weight::from_parts(0, 3566).saturating_mul(i.into())) + } /// Storage: `Staking::SlashingSpans` (r:1 w:1) /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Staking::Bonded` (r:1 w:1) @@ -433,11 +453,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `2127 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 81_032_000 picoseconds. - Weight::from_parts(88_297_596, 0) + // Minimum execution time: 80_290_000 picoseconds. + Weight::from_parts(87_901_664, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 3_070 - .saturating_add(Weight::from_parts(1_207_207, 0).saturating_mul(s.into())) + // Standard Error: 2_960 + .saturating_add(Weight::from_parts(1_195_050, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13)) .saturating_add(T::DbWeight::get().writes(12)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -450,11 +470,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `66639` // Estimated: `70104` - // Minimum execution time: 131_456_000 picoseconds. - Weight::from_parts(935_254_517, 0) + // Minimum execution time: 132_682_000 picoseconds. + Weight::from_parts(932_504_297, 0) .saturating_add(Weight::from_parts(0, 70104)) - // Standard Error: 57_806 - .saturating_add(Weight::from_parts(4_823_189, 0).saturating_mul(s.into())) + // Standard Error: 57_593 + .saturating_add(Weight::from_parts(4_829_705, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -490,12 +510,12 @@ impl pallet_staking::WeightInfo for WeightInfo { fn payout_stakers_alive_staked(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `8249 + n * (396 ±0)` - // Estimated: `10779 + n * (3774 ±0)` - // Minimum execution time: 129_233_000 picoseconds. - Weight::from_parts(165_096_042, 0) + // Estimated: `10779 + n * (3774 ±3)` + // Minimum execution time: 129_091_000 picoseconds. + Weight::from_parts(166_186_167, 0) .saturating_add(Weight::from_parts(0, 10779)) - // Standard Error: 29_598 - .saturating_add(Weight::from_parts(40_716_425, 0).saturating_mul(n.into())) + // Standard Error: 36_242 + .saturating_add(Weight::from_parts(40_467_481, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(14)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(4)) @@ -519,11 +539,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1922 + l * (5 ±0)` // Estimated: `8877` - // Minimum execution time: 77_223_000 picoseconds. - Weight::from_parts(80_026_259, 0) + // Minimum execution time: 77_461_000 picoseconds. + Weight::from_parts(80_118_021, 0) .saturating_add(Weight::from_parts(0, 8877)) - // Standard Error: 4_493 - .saturating_add(Weight::from_parts(52_909, 0).saturating_mul(l.into())) + // Standard Error: 4_343 + .saturating_add(Weight::from_parts(59_113, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(7)) } @@ -558,11 +578,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `2127 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 89_871_000 picoseconds. - Weight::from_parts(92_313_331, 0) + // Minimum execution time: 89_366_000 picoseconds. + Weight::from_parts(91_964_557, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 3_321 - .saturating_add(Weight::from_parts(1_243_347, 0).saturating_mul(s.into())) + // Standard Error: 2_799 + .saturating_add(Weight::from_parts(1_206_123, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(11)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -607,14 +627,14 @@ impl pallet_staking::WeightInfo for WeightInfo { fn new_era(v: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + n * (716 ±0) + v * (3594 ±0)` - // Estimated: `456136 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 518_819_000 picoseconds. - Weight::from_parts(522_108_000, 0) + // Estimated: `456136 + n * (3566 ±4) + v * (3566 ±40)` + // Minimum execution time: 520_430_000 picoseconds. + Weight::from_parts(527_125_000, 0) .saturating_add(Weight::from_parts(0, 456136)) - // Standard Error: 1_987_848 - .saturating_add(Weight::from_parts(64_855_377, 0).saturating_mul(v.into())) - // Standard Error: 198_078 - .saturating_add(Weight::from_parts(18_343_485, 0).saturating_mul(n.into())) + // Standard Error: 1_974_092 + .saturating_add(Weight::from_parts(64_885_491, 0).saturating_mul(v.into())) + // Standard Error: 196_707 + .saturating_add(Weight::from_parts(18_100_326, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(184)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -645,13 +665,13 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `3108 + n * (907 ±0) + v * (391 ±0)` // Estimated: `456136 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 34_976_277_000 picoseconds. - Weight::from_parts(35_245_501_000, 0) + // Minimum execution time: 33_917_323_000 picoseconds. + Weight::from_parts(34_173_565_000, 0) .saturating_add(Weight::from_parts(0, 456136)) - // Standard Error: 386_461 - .saturating_add(Weight::from_parts(5_145_210, 0).saturating_mul(v.into())) - // Standard Error: 386_461 - .saturating_add(Weight::from_parts(3_762_623, 0).saturating_mul(n.into())) + // Standard Error: 367_135 + .saturating_add(Weight::from_parts(4_696_840, 0).saturating_mul(v.into())) + // Standard Error: 367_135 + .saturating_add(Weight::from_parts(3_889_075, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(179)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -668,11 +688,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `946 + v * (50 ±0)` // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_577_411_000 picoseconds. - Weight::from_parts(86_073_486, 0) + // Minimum execution time: 2_447_197_000 picoseconds. + Weight::from_parts(13_003_614, 0) .saturating_add(Weight::from_parts(0, 3510)) - // Standard Error: 8_363 - .saturating_add(Weight::from_parts(5_074_828, 0).saturating_mul(v.into())) + // Standard Error: 9_738 + .saturating_add(Weight::from_parts(4_953_442, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) @@ -693,8 +713,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_539_000 picoseconds. - Weight::from_parts(3_903_000, 0) + // Minimum execution time: 3_714_000 picoseconds. + Weight::from_parts(3_956_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(6)) } @@ -714,11 +734,13 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_244_000 picoseconds. - Weight::from_parts(3_450_000, 0) + // Minimum execution time: 3_361_000 picoseconds. + Weight::from_parts(3_632_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(6)) } + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) @@ -741,12 +763,12 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill_other() -> Weight { // Proof Size summary in bytes: - // Measured: `1704` + // Measured: `1870` // Estimated: `6248` - // Minimum execution time: 62_606_000 picoseconds. - Weight::from_parts(64_678_000, 0) + // Minimum execution time: 65_329_000 picoseconds. + Weight::from_parts(67_247_000, 0) .saturating_add(Weight::from_parts(0, 6248)) - .saturating_add(T::DbWeight::get().reads(11)) + .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(6)) } /// Storage: `Staking::MinCommission` (r:1 w:0) @@ -757,8 +779,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `658` // Estimated: `3510` - // Minimum execution time: 11_490_000 picoseconds. - Weight::from_parts(11_867_000, 0) + // Minimum execution time: 11_760_000 picoseconds. + Weight::from_parts(12_095_000, 0) .saturating_add(Weight::from_parts(0, 3510)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -769,8 +791,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_125_000 picoseconds. - Weight::from_parts(2_337_000, 0) + // Minimum execution time: 2_256_000 picoseconds. + Weight::from_parts(2_378_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index b8c638ef155..4d0b253413a 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -632,6 +632,7 @@ parameter_types! { pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; pub const MaxNominators: u32 = 64; pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17); + pub const MaxControllersInDeprecationBatch: u32 = 5900; pub OffchainRepeat: BlockNumber = 5; pub HistoryDepth: u32 = 84; } @@ -674,6 +675,7 @@ impl pallet_staking::Config for Runtime { // This a placeholder, to be introduced in the next PR as an instance of bags-list type TargetList = pallet_staking::UseValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; + type MaxControllersInDeprecationBatch = MaxControllersInDeprecationBatch; type HistoryDepth = HistoryDepth; type EventListeners = NominationPools; type WeightInfo = pallet_staking::weights::SubstrateWeight; diff --git a/substrate/frame/babe/src/mock.rs b/substrate/frame/babe/src/mock.rs index 0003c6f9f11..72abbc805db 100644 --- a/substrate/frame/babe/src/mock.rs +++ b/substrate/frame/babe/src/mock.rs @@ -183,6 +183,7 @@ impl pallet_staking::Config for Test { type TargetList = pallet_staking::UseValidatorsMap; type NominationsQuota = FixedNominationsQuota<16>; type MaxUnlockingChunks = ConstU32<32>; + type MaxControllersInDeprecationBatch = ConstU32<100>; type HistoryDepth = ConstU32<84>; type EventListeners = (); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; diff --git a/substrate/frame/beefy/src/mock.rs b/substrate/frame/beefy/src/mock.rs index 53d523cf724..8dc30614c33 100644 --- a/substrate/frame/beefy/src/mock.rs +++ b/substrate/frame/beefy/src/mock.rs @@ -201,6 +201,7 @@ impl pallet_staking::Config for Test { type TargetList = pallet_staking::UseValidatorsMap; type NominationsQuota = pallet_staking::FixedNominationsQuota<16>; type MaxUnlockingChunks = ConstU32<32>; + type MaxControllersInDeprecationBatch = ConstU32<100>; type HistoryDepth = ConstU32<84>; type EventListeners = (); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs index 751ffc07aa5..ecb2ae435b8 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs @@ -276,6 +276,7 @@ impl pallet_staking::Config for Runtime { type NominationsQuota = pallet_staking::FixedNominationsQuota; type TargetList = pallet_staking::UseValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; + type MaxControllersInDeprecationBatch = ConstU32<100>; type HistoryDepth = HistoryDepth; type EventListeners = (); type WeightInfo = pallet_staking::weights::SubstrateWeight; diff --git a/substrate/frame/fast-unstake/src/mock.rs b/substrate/frame/fast-unstake/src/mock.rs index 09a08f222b6..f9326919fd3 100644 --- a/substrate/frame/fast-unstake/src/mock.rs +++ b/substrate/frame/fast-unstake/src/mock.rs @@ -142,6 +142,7 @@ impl pallet_staking::Config for Runtime { type TargetList = pallet_staking::UseValidatorsMap; type NominationsQuota = pallet_staking::FixedNominationsQuota<16>; type MaxUnlockingChunks = ConstU32<32>; + type MaxControllersInDeprecationBatch = ConstU32<100>; type EventListeners = (); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); diff --git a/substrate/frame/grandpa/src/mock.rs b/substrate/frame/grandpa/src/mock.rs index 4766d5c3780..f1f51e0b118 100644 --- a/substrate/frame/grandpa/src/mock.rs +++ b/substrate/frame/grandpa/src/mock.rs @@ -206,6 +206,7 @@ impl pallet_staking::Config for Test { type TargetList = pallet_staking::UseValidatorsMap; type NominationsQuota = pallet_staking::FixedNominationsQuota<16>; type MaxUnlockingChunks = ConstU32<32>; + type MaxControllersInDeprecationBatch = ConstU32<100>; type HistoryDepth = ConstU32<84>; type EventListeners = (); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; diff --git a/substrate/frame/nomination-pools/benchmarking/src/mock.rs b/substrate/frame/nomination-pools/benchmarking/src/mock.rs index 095df219dc8..c58a66f6163 100644 --- a/substrate/frame/nomination-pools/benchmarking/src/mock.rs +++ b/substrate/frame/nomination-pools/benchmarking/src/mock.rs @@ -119,6 +119,7 @@ impl pallet_staking::Config for Runtime { type VoterList = VoterList; type TargetList = pallet_staking::UseValidatorsMap; type NominationsQuota = pallet_staking::FixedNominationsQuota<16>; + type MaxControllersInDeprecationBatch = ConstU32<100>; type MaxUnlockingChunks = ConstU32<32>; type HistoryDepth = ConstU32<84>; type EventListeners = Pools; diff --git a/substrate/frame/nomination-pools/test-staking/src/mock.rs b/substrate/frame/nomination-pools/test-staking/src/mock.rs index ee24b53db06..491cd619161 100644 --- a/substrate/frame/nomination-pools/test-staking/src/mock.rs +++ b/substrate/frame/nomination-pools/test-staking/src/mock.rs @@ -134,6 +134,7 @@ impl pallet_staking::Config for Runtime { type TargetList = pallet_staking::UseValidatorsMap; type NominationsQuota = pallet_staking::FixedNominationsQuota<16>; type MaxUnlockingChunks = ConstU32<32>; + type MaxControllersInDeprecationBatch = ConstU32<100>; type HistoryDepth = ConstU32<84>; type EventListeners = Pools; type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; diff --git a/substrate/frame/offences/benchmarking/src/mock.rs b/substrate/frame/offences/benchmarking/src/mock.rs index 62ce1990112..1d642b9b498 100644 --- a/substrate/frame/offences/benchmarking/src/mock.rs +++ b/substrate/frame/offences/benchmarking/src/mock.rs @@ -185,6 +185,7 @@ impl pallet_staking::Config for Test { type TargetList = pallet_staking::UseValidatorsMap; type NominationsQuota = pallet_staking::FixedNominationsQuota<16>; type MaxUnlockingChunks = ConstU32<32>; + type MaxControllersInDeprecationBatch = ConstU32<100>; type HistoryDepth = ConstU32<84>; type EventListeners = (); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; diff --git a/substrate/frame/root-offences/src/mock.rs b/substrate/frame/root-offences/src/mock.rs index 5e04e9abc13..c0c83dd08d2 100644 --- a/substrate/frame/root-offences/src/mock.rs +++ b/substrate/frame/root-offences/src/mock.rs @@ -188,6 +188,7 @@ impl pallet_staking::Config for Test { type NominationsQuota = pallet_staking::FixedNominationsQuota<16>; type MaxUnlockingChunks = ConstU32<32>; type HistoryDepth = ConstU32<84>; + type MaxControllersInDeprecationBatch = ConstU32<100>; type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; type EventListeners = (); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; diff --git a/substrate/frame/session/benchmarking/src/mock.rs b/substrate/frame/session/benchmarking/src/mock.rs index 5c00d4bb491..e1744fa43ab 100644 --- a/substrate/frame/session/benchmarking/src/mock.rs +++ b/substrate/frame/session/benchmarking/src/mock.rs @@ -179,6 +179,7 @@ impl pallet_staking::Config for Test { type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; type MaxUnlockingChunks = ConstU32<32>; + type MaxControllersInDeprecationBatch = ConstU32<100>; type HistoryDepth = ConstU32<84>; type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; type TargetList = pallet_staking::UseValidatorsMap; diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index c0c6a838aa5..abb78b7e304 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -25,6 +25,7 @@ use codec::Decode; use frame_election_provider_support::{bounds::DataProviderBounds, SortedListProvider}; use frame_support::{ pallet_prelude::*, + storage::bounded_vec::BoundedVec, traits::{Currency, Get, Imbalance, UnfilteredDispatchable}, }; use sp_runtime::{ @@ -525,6 +526,39 @@ benchmarks! { assert_eq!(Invulnerables::::get().len(), v as usize); } + deprecate_controller_batch { + // We pass a dynamic number of controllers to the benchmark, up to + // `MaxControllersInDeprecationBatch`. + let i in 0 .. T::MaxControllersInDeprecationBatch::get(); + + let mut controllers: Vec<_> = vec![]; + let mut stashes: Vec<_> = vec![]; + for n in 0..i as u32 { + let (stash, controller) = create_unique_stash_controller::( + n, + 100, + RewardDestination::Staked, + false + )?; + controllers.push(controller); + stashes.push(stash); + } + let bounded_controllers: BoundedVec<_, T::MaxControllersInDeprecationBatch> = + BoundedVec::try_from(controllers.clone()).unwrap(); + }: _(RawOrigin::Root, bounded_controllers) + verify { + for n in 0..i as u32 { + let stash = &stashes[n as usize]; + let controller = &controllers[n as usize]; + // Ledger no longer keyed by controller. + assert_eq!(Ledger::::get(controller), None); + // Bonded now maps to the stash. + assert_eq!(Bonded::::get(stash), Some(stash.clone())); + // Ledger is now keyed by stash. + assert_eq!(Ledger::::get(stash).unwrap().stash, *stash); + } + } + force_unstake { // Slashing Spans let s in 0 .. MAX_SPANS; diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 90b0ee0260d..5332dbfdd5b 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -122,6 +122,7 @@ parameter_types! { pub static SlashDeferDuration: EraIndex = 0; pub static Period: BlockNumber = 5; pub static Offset: BlockNumber = 0; + pub static MaxControllersInDeprecationBatch: u32 = 5900; } #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] @@ -316,6 +317,7 @@ impl crate::pallet::pallet::Config for Test { type NominationsQuota = WeightedNominationsQuota<16>; type MaxUnlockingChunks = MaxUnlockingChunks; type HistoryDepth = HistoryDepth; + type MaxControllersInDeprecationBatch = MaxControllersInDeprecationBatch; type EventListeners = EventListenerMock; type BenchmarkingConfig = TestBenchmarkingConfig; type WeightInfo = (); diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index ce80f22c2bb..b914545a76b 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -269,6 +269,9 @@ pub mod pallet { #[pallet::constant] type MaxUnlockingChunks: Get; + /// The maximum amount of controller accounts that can be deprecated in one call. + type MaxControllersInDeprecationBatch: Get; + /// Something that listens to staking updates and performs actions based on the data it /// receives. /// @@ -1323,7 +1326,7 @@ pub mod pallet { pub fn set_controller(origin: OriginFor) -> DispatchResult { let stash = ensure_signed(origin)?; - // the bonded map and ledger are mutated directly as this extrinsic is related to a + // The bonded map and ledger are mutated directly as this extrinsic is related to a // (temporary) passive migration. Self::ledger(StakingAccount::Stash(stash.clone())).map(|ledger| { let controller = ledger.controller() @@ -1331,10 +1334,9 @@ pub mod pallet { .ok_or(Error::::NotController)?; if controller == stash { - // stash is already its own controller. + // Stash is already its own controller. return Err(Error::::AlreadyPaired.into()) } - // update bond and ledger. >::remove(controller); >::insert(&stash, &stash); >::insert(&stash, ledger); @@ -1920,6 +1922,54 @@ pub mod pallet { Ok(Pays::No.into()) } + + /// Updates a batch of controller accounts to their corresponding stash account if they are + /// not the same. Ignores any controller accounts that do not exist, and does not operate if + /// the stash and controller are already the same. + /// + /// Effects will be felt instantly (as soon as this function is completed successfully). + /// + /// The dispatch origin must be `T::AdminOrigin`. + #[pallet::call_index(28)] + #[pallet::weight(T::WeightInfo::deprecate_controller_batch(controllers.len() as u32))] + pub fn deprecate_controller_batch( + origin: OriginFor, + controllers: BoundedVec, + ) -> DispatchResultWithPostInfo { + T::AdminOrigin::ensure_origin(origin)?; + + // Ignore controllers that do not exist or are already the same as stash. + let filtered_batch_with_ledger: Vec<_> = controllers + .iter() + .filter_map(|controller| { + let ledger = Self::ledger(StakingAccount::Controller(controller.clone())); + ledger.ok().map_or(None, |ledger| { + // If the controller `RewardDestination` is still the deprecated + // `Controller` variant, skip deprecating this account. + let payee_deprecated = Payee::::get(&ledger.stash) == { + #[allow(deprecated)] + RewardDestination::Controller + }; + + if ledger.stash != *controller && !payee_deprecated { + Some((controller.clone(), ledger)) + } else { + None + } + }) + }) + .collect(); + + // Update unique pairs. + for (controller, ledger) in filtered_batch_with_ledger { + let stash = ledger.stash.clone(); + + >::insert(&stash, &stash); + >::remove(controller); + >::insert(stash, ledger); + } + Ok(Some(T::WeightInfo::deprecate_controller_batch(controllers.len() as u32)).into()) + } } } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 7d967609f52..0e9be70ee7d 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -6206,7 +6206,7 @@ fn proportional_ledger_slash_works() { #[test] fn reducing_max_unlocking_chunks_abrupt() { // Concern is on validators only - // By Default 11, 10 are stash and ctrl and 21,20 + // By Default 11, 10 are stash and ctlr and 21,20 ExtBuilder::default().build_and_execute(|| { // given a staker at era=10 and MaxUnlockChunks set to 2 MaxUnlockingChunks::set(2); @@ -6867,4 +6867,181 @@ mod ledger { assert_eq!(Payee::::get(&21), RewardDestination::Stash); }) } + + #[test] + fn deprecate_controller_batch_works_full_weight() { + ExtBuilder::default().build_and_execute(|| { + // Given: + + let start = 1001; + let mut controllers: Vec<_> = vec![]; + for n in start..(start + MaxControllersInDeprecationBatch::get()).into() { + let ctlr: u64 = n.into(); + let stash: u64 = (n + 10000).into(); + + Ledger::::insert( + ctlr, + StakingLedger { + controller: None, + total: (10 + ctlr).into(), + active: (10 + ctlr).into(), + ..StakingLedger::default_from(stash) + }, + ); + Bonded::::insert(stash, ctlr); + Payee::::insert(stash, RewardDestination::Staked); + + controllers.push(ctlr); + } + + // When: + + let bounded_controllers: BoundedVec< + _, + ::MaxControllersInDeprecationBatch, + > = BoundedVec::try_from(controllers).unwrap(); + + // Only `AdminOrigin` can sign. + assert_noop!( + Staking::deprecate_controller_batch( + RuntimeOrigin::signed(2), + bounded_controllers.clone() + ), + BadOrigin + ); + + let result = + Staking::deprecate_controller_batch(RuntimeOrigin::root(), bounded_controllers); + assert_ok!(result); + assert_eq!( + result.unwrap().actual_weight.unwrap(), + ::WeightInfo::deprecate_controller_batch( + ::MaxControllersInDeprecationBatch::get() + ) + ); + + // Then: + + for n in start..(start + MaxControllersInDeprecationBatch::get()).into() { + let ctlr: u64 = n.into(); + let stash: u64 = (n + 10000).into(); + + // Ledger no longer keyed by controller. + assert_eq!(Ledger::::get(ctlr), None); + // Bonded now maps to the stash. + assert_eq!(Bonded::::get(stash), Some(stash)); + + // Ledger is now keyed by stash. + let ledger_updated = Ledger::::get(stash).unwrap(); + assert_eq!(ledger_updated.stash, stash); + + // Check `active` and `total` values match the original ledger set by controller. + assert_eq!(ledger_updated.active, (10 + ctlr).into()); + assert_eq!(ledger_updated.total, (10 + ctlr).into()); + } + }) + } + + #[test] + fn deprecate_controller_batch_works_half_weight() { + ExtBuilder::default().build_and_execute(|| { + // Given: + + let start = 1001; + let mut controllers: Vec<_> = vec![]; + for n in start..(start + MaxControllersInDeprecationBatch::get()).into() { + let ctlr: u64 = n.into(); + + // Only half of entries are unique pairs. + let stash: u64 = if n % 2 == 0 { (n + 10000).into() } else { ctlr }; + + Ledger::::insert( + ctlr, + StakingLedger { controller: None, ..StakingLedger::default_from(stash) }, + ); + Bonded::::insert(stash, ctlr); + Payee::::insert(stash, RewardDestination::Staked); + + controllers.push(ctlr); + } + + // When: + let bounded_controllers: BoundedVec< + _, + ::MaxControllersInDeprecationBatch, + > = BoundedVec::try_from(controllers.clone()).unwrap(); + + let result = + Staking::deprecate_controller_batch(RuntimeOrigin::root(), bounded_controllers); + assert_ok!(result); + assert_eq!( + result.unwrap().actual_weight.unwrap(), + ::WeightInfo::deprecate_controller_batch(controllers.len() as u32) + ); + + // Then: + + for n in start..(start + MaxControllersInDeprecationBatch::get()).into() { + let unique_pair = n % 2 == 0; + let ctlr: u64 = n.into(); + let stash: u64 = if unique_pair { (n + 10000).into() } else { ctlr }; + + // Side effect of migration for unique pair. + if unique_pair { + assert_eq!(Ledger::::get(ctlr), None); + } + // Bonded maps to the stash. + assert_eq!(Bonded::::get(stash), Some(stash)); + + // Ledger is keyed by stash. + let ledger_updated = Ledger::::get(stash).unwrap(); + assert_eq!(ledger_updated.stash, stash); + } + }) + } + + #[test] + fn deprecate_controller_batch_skips_unmigrated_controller_payees() { + ExtBuilder::default().build_and_execute(|| { + // Given: + + let stash: u64 = 1000; + let ctlr: u64 = 1001; + + Ledger::::insert( + ctlr, + StakingLedger { controller: None, ..StakingLedger::default_from(stash) }, + ); + Bonded::::insert(stash, ctlr); + #[allow(deprecated)] + Payee::::insert(stash, RewardDestination::Controller); + + // When: + + let bounded_controllers: BoundedVec< + _, + ::MaxControllersInDeprecationBatch, + > = BoundedVec::try_from(vec![ctlr]).unwrap(); + + let result = + Staking::deprecate_controller_batch(RuntimeOrigin::root(), bounded_controllers); + assert_ok!(result); + assert_eq!( + result.unwrap().actual_weight.unwrap(), + ::WeightInfo::deprecate_controller_batch(1 as u32) + ); + + // Then: + + // Esure deprecation did not happen. + assert_eq!(Ledger::::get(ctlr).is_some(), true); + + // Bonded still keyed by controller. + assert_eq!(Bonded::::get(stash), Some(ctlr)); + + // Ledger is still keyed by controller. + let ledger_updated = Ledger::::get(ctlr).unwrap(); + assert_eq!(ledger_updated.stash, stash); + }) + } } diff --git a/substrate/frame/staking/src/weights.rs b/substrate/frame/staking/src/weights.rs index ae00509eaa8..7c9a0500164 100644 --- a/substrate/frame/staking/src/weights.rs +++ b/substrate/frame/staking/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_staking` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-12-10, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-itmxxexx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -66,6 +66,7 @@ pub trait WeightInfo { fn force_new_era() -> Weight; fn force_new_era_always() -> Weight; fn set_invulnerables(v: u32, ) -> Weight; + fn deprecate_controller_batch(i: u32, ) -> Weight; fn force_unstake(s: u32, ) -> Weight; fn cancel_deferred_slash(s: u32, ) -> Weight; fn payout_stakers_alive_staked(n: u32, ) -> Weight; @@ -98,8 +99,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `927` // Estimated: `4764` - // Minimum execution time: 42_895_000 picoseconds. - Weight::from_parts(44_924_000, 4764) + // Minimum execution time: 42_491_000 picoseconds. + Weight::from_parts(44_026_000, 4764) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -119,8 +120,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1990` // Estimated: `8877` - // Minimum execution time: 87_734_000 picoseconds. - Weight::from_parts(90_762_000, 8877) + // Minimum execution time: 88_756_000 picoseconds. + Weight::from_parts(91_000_000, 8877) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -146,8 +147,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2195` // Estimated: `8877` - // Minimum execution time: 90_914_000 picoseconds. - Weight::from_parts(94_156_000, 8877) + // Minimum execution time: 91_331_000 picoseconds. + Weight::from_parts(94_781_000, 8877) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -166,10 +167,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1115` // Estimated: `4764` - // Minimum execution time: 43_141_000 picoseconds. - Weight::from_parts(45_081_969, 4764) - // Standard Error: 1_010 - .saturating_add(Weight::from_parts(39_539, 0).saturating_mul(s.into())) + // Minimum execution time: 42_495_000 picoseconds. + Weight::from_parts(44_189_470, 4764) + // Standard Error: 1_389 + .saturating_add(Weight::from_parts(47_484, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -206,10 +207,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 87_743_000 picoseconds. - Weight::from_parts(96_983_484, 6248) - // Standard Error: 4_271 - .saturating_add(Weight::from_parts(1_382_993, 0).saturating_mul(s.into())) + // Minimum execution time: 89_004_000 picoseconds. + Weight::from_parts(96_677_570, 6248) + // Standard Error: 4_635 + .saturating_add(Weight::from_parts(1_387_718, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().writes(11_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -241,8 +242,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1372` // Estimated: `4556` - // Minimum execution time: 51_888_000 picoseconds. - Weight::from_parts(54_353_000, 4556) + // Minimum execution time: 51_532_000 picoseconds. + Weight::from_parts(53_308_000, 4556) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -255,10 +256,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1280 + k * (569 ±0)` // Estimated: `4556 + k * (3033 ±0)` - // Minimum execution time: 28_944_000 picoseconds. - Weight::from_parts(31_116_533, 4556) - // Standard Error: 11_848 - .saturating_add(Weight::from_parts(6_422_601, 0).saturating_mul(k.into())) + // Minimum execution time: 28_955_000 picoseconds. + Weight::from_parts(29_609_869, 4556) + // Standard Error: 6_793 + .saturating_add(Weight::from_parts(6_412_124, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -291,10 +292,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1866 + n * (102 ±0)` // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 63_921_000 picoseconds. - Weight::from_parts(62_662_863, 6248) - // Standard Error: 15_071 - .saturating_add(Weight::from_parts(3_950_084, 0).saturating_mul(n.into())) + // Minimum execution time: 64_080_000 picoseconds. + Weight::from_parts(61_985_382, 6248) + // Standard Error: 13_320 + .saturating_add(Weight::from_parts(4_030_513, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) @@ -318,8 +319,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1650` // Estimated: `6248` - // Minimum execution time: 54_605_000 picoseconds. - Weight::from_parts(56_406_000, 6248) + // Minimum execution time: 54_194_000 picoseconds. + Weight::from_parts(55_578_000, 6248) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -333,8 +334,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `902` // Estimated: `4556` - // Minimum execution time: 16_826_000 picoseconds. - Weight::from_parts(17_326_000, 4556) + // Minimum execution time: 16_597_000 picoseconds. + Weight::from_parts(16_980_000, 4556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -348,8 +349,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `969` // Estimated: `4556` - // Minimum execution time: 20_831_000 picoseconds. - Weight::from_parts(21_615_000, 4556) + // Minimum execution time: 20_626_000 picoseconds. + Weight::from_parts(21_242_000, 4556) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -361,8 +362,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `902` // Estimated: `4556` - // Minimum execution time: 20_190_000 picoseconds. - Weight::from_parts(20_993_000, 4556) + // Minimum execution time: 19_972_000 picoseconds. + Weight::from_parts(20_470_000, 4556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -372,8 +373,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_603_000 picoseconds. - Weight::from_parts(2_747_000, 0) + // Minimum execution time: 2_571_000 picoseconds. + Weight::from_parts(2_720_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -382,8 +383,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_070_000 picoseconds. - Weight::from_parts(8_745_000, 0) + // Minimum execution time: 8_056_000 picoseconds. + Weight::from_parts(8_413_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -392,8 +393,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_999_000 picoseconds. - Weight::from_parts(8_624_000, 0) + // Minimum execution time: 8_162_000 picoseconds. + Weight::from_parts(8_497_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -402,8 +403,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_131_000 picoseconds. - Weight::from_parts(8_467_000, 0) + // Minimum execution time: 8_320_000 picoseconds. + Weight::from_parts(8_564_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::Invulnerables` (r:0 w:1) @@ -413,12 +414,31 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_731_000 picoseconds. - Weight::from_parts(3_298_421, 0) - // Standard Error: 31 - .saturating_add(Weight::from_parts(10_075, 0).saturating_mul(v.into())) + // Minimum execution time: 2_470_000 picoseconds. + Weight::from_parts(3_110_242, 0) + // Standard Error: 63 + .saturating_add(Weight::from_parts(11_786, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(1_u64)) } + /// Storage: `Staking::Ledger` (r:5900 w:11800) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Payee` (r:5900 w:0) + /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:0 w:5900) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// The range of component `i` is `[0, 5900]`. + fn deprecate_controller_batch(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1356 + i * (151 ±0)` + // Estimated: `990 + i * (3566 ±0)` + // Minimum execution time: 2_101_000 picoseconds. + Weight::from_parts(2_238_000, 990) + // Standard Error: 56_753 + .saturating_add(Weight::from_parts(18_404_902, 0).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(i.into()))) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(i.into()))) + .saturating_add(Weight::from_parts(0, 3566).saturating_mul(i.into())) + } /// Storage: `Staking::SlashingSpans` (r:1 w:1) /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Staking::Bonded` (r:1 w:1) @@ -452,10 +472,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 86_305_000 picoseconds. - Weight::from_parts(94_494_401, 6248) - // Standard Error: 3_602 - .saturating_add(Weight::from_parts(1_339_477, 0).saturating_mul(s.into())) + // Minimum execution time: 86_765_000 picoseconds. + Weight::from_parts(95_173_565, 6248) + // Standard Error: 4_596 + .saturating_add(Weight::from_parts(1_354_849, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().writes(12_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -468,10 +488,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `66672` // Estimated: `70137` - // Minimum execution time: 100_007_000 picoseconds. - Weight::from_parts(894_033_025, 70137) - // Standard Error: 57_584 - .saturating_add(Weight::from_parts(4_870_504, 0).saturating_mul(s.into())) + // Minimum execution time: 104_490_000 picoseconds. + Weight::from_parts(1_162_956_951, 70137) + // Standard Error: 76_760 + .saturating_add(Weight::from_parts(6_485_569, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -508,10 +528,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `33297 + n * (377 ±0)` // Estimated: `30944 + n * (3774 ±0)` - // Minimum execution time: 142_575_000 picoseconds. - Weight::from_parts(196_320_577, 30944) - // Standard Error: 29_330 - .saturating_add(Weight::from_parts(45_325_062, 0).saturating_mul(n.into())) + // Minimum execution time: 144_790_000 picoseconds. + Weight::from_parts(36_764_791, 30944) + // Standard Error: 89_592 + .saturating_add(Weight::from_parts(49_620_105, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(14_u64)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) @@ -535,10 +555,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1991 + l * (7 ±0)` // Estimated: `8877` - // Minimum execution time: 81_113_000 picoseconds. - Weight::from_parts(84_470_927, 8877) - // Standard Error: 5_588 - .saturating_add(Weight::from_parts(97_606, 0).saturating_mul(l.into())) + // Minimum execution time: 81_768_000 picoseconds. + Weight::from_parts(85_332_982, 8877) + // Standard Error: 5_380 + .saturating_add(Weight::from_parts(70_298, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -573,10 +593,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 94_810_000 picoseconds. - Weight::from_parts(99_292_156, 6248) - // Standard Error: 3_677 - .saturating_add(Weight::from_parts(1_345_598, 0).saturating_mul(s.into())) + // Minimum execution time: 96_123_000 picoseconds. + Weight::from_parts(100_278_672, 6248) + // Standard Error: 3_487 + .saturating_add(Weight::from_parts(1_326_503, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(11_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -621,13 +641,13 @@ impl WeightInfo for SubstrateWeight { fn new_era(v: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + n * (720 ±0) + v * (3598 ±0)` - // Estimated: `512390 + n * (3566 ±4) + v * (3566 ±40)` - // Minimum execution time: 583_230_000 picoseconds. - Weight::from_parts(585_794_000, 512390) - // Standard Error: 1_984_644 - .saturating_add(Weight::from_parts(65_914_551, 0).saturating_mul(v.into())) - // Standard Error: 197_758 - .saturating_add(Weight::from_parts(18_105_424, 0).saturating_mul(n.into())) + // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` + // Minimum execution time: 572_893_000 picoseconds. + Weight::from_parts(578_010_000, 512390) + // Standard Error: 2_094_268 + .saturating_add(Weight::from_parts(68_419_710, 0).saturating_mul(v.into())) + // Standard Error: 208_682 + .saturating_add(Weight::from_parts(18_826_175, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(206_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -658,12 +678,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3175 + n * (911 ±0) + v * (395 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 33_312_958_000 picoseconds. - Weight::from_parts(4_949_866_209, 512390) - // Standard Error: 402_931 - .saturating_add(Weight::from_parts(16_448_367, 0).saturating_mul(v.into())) - // Standard Error: 402_931 - .saturating_add(Weight::from_parts(25_361_503, 0).saturating_mul(n.into())) + // Minimum execution time: 33_836_205_000 picoseconds. + Weight::from_parts(34_210_443_000, 512390) + // Standard Error: 441_692 + .saturating_add(Weight::from_parts(6_122_533, 0).saturating_mul(v.into())) + // Standard Error: 441_692 + .saturating_add(Weight::from_parts(4_418_264, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(201_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -680,10 +700,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `979 + v * (50 ±0)` // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_474_646_000 picoseconds. - Weight::from_parts(2_512_113_000, 3510) - // Standard Error: 33_996 - .saturating_add(Weight::from_parts(1_992_173, 0).saturating_mul(v.into())) + // Minimum execution time: 2_454_689_000 picoseconds. + Weight::from_parts(161_771_064, 3510) + // Standard Error: 31_022 + .saturating_add(Weight::from_parts(4_820_158, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) @@ -704,8 +724,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_466_000 picoseconds. - Weight::from_parts(5_861_000, 0) + // Minimum execution time: 5_073_000 picoseconds. + Weight::from_parts(5_452_000, 0) .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: `Staking::MinCommission` (r:0 w:1) @@ -724,8 +744,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_780_000 picoseconds. - Weight::from_parts(4_998_000, 0) + // Minimum execution time: 4_465_000 picoseconds. + Weight::from_parts(4_832_000, 0) .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: `Staking::Bonded` (r:1 w:0) @@ -754,8 +774,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1939` // Estimated: `6248` - // Minimum execution time: 71_261_000 picoseconds. - Weight::from_parts(72_778_000, 6248) + // Minimum execution time: 71_239_000 picoseconds. + Weight::from_parts(74_649_000, 6248) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -767,8 +787,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `691` // Estimated: `3510` - // Minimum execution time: 12_497_000 picoseconds. - Weight::from_parts(13_049_000, 3510) + // Minimum execution time: 12_525_000 picoseconds. + Weight::from_parts(13_126_000, 3510) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -778,8 +798,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_044_000 picoseconds. - Weight::from_parts(3_278_000, 0) + // Minimum execution time: 2_918_000 picoseconds. + Weight::from_parts(3_176_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } } @@ -800,8 +820,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `927` // Estimated: `4764` - // Minimum execution time: 42_895_000 picoseconds. - Weight::from_parts(44_924_000, 4764) + // Minimum execution time: 42_491_000 picoseconds. + Weight::from_parts(44_026_000, 4764) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -821,8 +841,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1990` // Estimated: `8877` - // Minimum execution time: 87_734_000 picoseconds. - Weight::from_parts(90_762_000, 8877) + // Minimum execution time: 88_756_000 picoseconds. + Weight::from_parts(91_000_000, 8877) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -848,8 +868,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2195` // Estimated: `8877` - // Minimum execution time: 90_914_000 picoseconds. - Weight::from_parts(94_156_000, 8877) + // Minimum execution time: 91_331_000 picoseconds. + Weight::from_parts(94_781_000, 8877) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -868,10 +888,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1115` // Estimated: `4764` - // Minimum execution time: 43_141_000 picoseconds. - Weight::from_parts(45_081_969, 4764) - // Standard Error: 1_010 - .saturating_add(Weight::from_parts(39_539, 0).saturating_mul(s.into())) + // Minimum execution time: 42_495_000 picoseconds. + Weight::from_parts(44_189_470, 4764) + // Standard Error: 1_389 + .saturating_add(Weight::from_parts(47_484, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -908,10 +928,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 87_743_000 picoseconds. - Weight::from_parts(96_983_484, 6248) - // Standard Error: 4_271 - .saturating_add(Weight::from_parts(1_382_993, 0).saturating_mul(s.into())) + // Minimum execution time: 89_004_000 picoseconds. + Weight::from_parts(96_677_570, 6248) + // Standard Error: 4_635 + .saturating_add(Weight::from_parts(1_387_718, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().writes(11_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -943,8 +963,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1372` // Estimated: `4556` - // Minimum execution time: 51_888_000 picoseconds. - Weight::from_parts(54_353_000, 4556) + // Minimum execution time: 51_532_000 picoseconds. + Weight::from_parts(53_308_000, 4556) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -957,10 +977,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1280 + k * (569 ±0)` // Estimated: `4556 + k * (3033 ±0)` - // Minimum execution time: 28_944_000 picoseconds. - Weight::from_parts(31_116_533, 4556) - // Standard Error: 11_848 - .saturating_add(Weight::from_parts(6_422_601, 0).saturating_mul(k.into())) + // Minimum execution time: 28_955_000 picoseconds. + Weight::from_parts(29_609_869, 4556) + // Standard Error: 6_793 + .saturating_add(Weight::from_parts(6_412_124, 0).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -993,10 +1013,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1866 + n * (102 ±0)` // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 63_921_000 picoseconds. - Weight::from_parts(62_662_863, 6248) - // Standard Error: 15_071 - .saturating_add(Weight::from_parts(3_950_084, 0).saturating_mul(n.into())) + // Minimum execution time: 64_080_000 picoseconds. + Weight::from_parts(61_985_382, 6248) + // Standard Error: 13_320 + .saturating_add(Weight::from_parts(4_030_513, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) @@ -1020,8 +1040,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1650` // Estimated: `6248` - // Minimum execution time: 54_605_000 picoseconds. - Weight::from_parts(56_406_000, 6248) + // Minimum execution time: 54_194_000 picoseconds. + Weight::from_parts(55_578_000, 6248) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -1035,8 +1055,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `902` // Estimated: `4556` - // Minimum execution time: 16_826_000 picoseconds. - Weight::from_parts(17_326_000, 4556) + // Minimum execution time: 16_597_000 picoseconds. + Weight::from_parts(16_980_000, 4556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1050,8 +1070,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `969` // Estimated: `4556` - // Minimum execution time: 20_831_000 picoseconds. - Weight::from_parts(21_615_000, 4556) + // Minimum execution time: 20_626_000 picoseconds. + Weight::from_parts(21_242_000, 4556) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1063,8 +1083,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `902` // Estimated: `4556` - // Minimum execution time: 20_190_000 picoseconds. - Weight::from_parts(20_993_000, 4556) + // Minimum execution time: 19_972_000 picoseconds. + Weight::from_parts(20_470_000, 4556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1074,8 +1094,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_603_000 picoseconds. - Weight::from_parts(2_747_000, 0) + // Minimum execution time: 2_571_000 picoseconds. + Weight::from_parts(2_720_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1084,8 +1104,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_070_000 picoseconds. - Weight::from_parts(8_745_000, 0) + // Minimum execution time: 8_056_000 picoseconds. + Weight::from_parts(8_413_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1094,8 +1114,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_999_000 picoseconds. - Weight::from_parts(8_624_000, 0) + // Minimum execution time: 8_162_000 picoseconds. + Weight::from_parts(8_497_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1104,8 +1124,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_131_000 picoseconds. - Weight::from_parts(8_467_000, 0) + // Minimum execution time: 8_320_000 picoseconds. + Weight::from_parts(8_564_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::Invulnerables` (r:0 w:1) @@ -1115,12 +1135,31 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_731_000 picoseconds. - Weight::from_parts(3_298_421, 0) - // Standard Error: 31 - .saturating_add(Weight::from_parts(10_075, 0).saturating_mul(v.into())) + // Minimum execution time: 2_470_000 picoseconds. + Weight::from_parts(3_110_242, 0) + // Standard Error: 63 + .saturating_add(Weight::from_parts(11_786, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().writes(1_u64)) } + /// Storage: `Staking::Ledger` (r:5900 w:11800) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Payee` (r:5900 w:0) + /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:0 w:5900) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// The range of component `i` is `[0, 5900]`. + fn deprecate_controller_batch(i: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1356 + i * (151 ±0)` + // Estimated: `990 + i * (3566 ±0)` + // Minimum execution time: 2_101_000 picoseconds. + Weight::from_parts(2_238_000, 990) + // Standard Error: 56_753 + .saturating_add(Weight::from_parts(18_404_902, 0).saturating_mul(i.into())) + .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(i.into()))) + .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(i.into()))) + .saturating_add(Weight::from_parts(0, 3566).saturating_mul(i.into())) + } /// Storage: `Staking::SlashingSpans` (r:1 w:1) /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Staking::Bonded` (r:1 w:1) @@ -1154,10 +1193,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 86_305_000 picoseconds. - Weight::from_parts(94_494_401, 6248) - // Standard Error: 3_602 - .saturating_add(Weight::from_parts(1_339_477, 0).saturating_mul(s.into())) + // Minimum execution time: 86_765_000 picoseconds. + Weight::from_parts(95_173_565, 6248) + // Standard Error: 4_596 + .saturating_add(Weight::from_parts(1_354_849, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().writes(12_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -1170,10 +1209,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `66672` // Estimated: `70137` - // Minimum execution time: 100_007_000 picoseconds. - Weight::from_parts(894_033_025, 70137) - // Standard Error: 57_584 - .saturating_add(Weight::from_parts(4_870_504, 0).saturating_mul(s.into())) + // Minimum execution time: 104_490_000 picoseconds. + Weight::from_parts(1_162_956_951, 70137) + // Standard Error: 76_760 + .saturating_add(Weight::from_parts(6_485_569, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1210,10 +1249,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `33297 + n * (377 ±0)` // Estimated: `30944 + n * (3774 ±0)` - // Minimum execution time: 142_575_000 picoseconds. - Weight::from_parts(196_320_577, 30944) - // Standard Error: 29_330 - .saturating_add(Weight::from_parts(45_325_062, 0).saturating_mul(n.into())) + // Minimum execution time: 144_790_000 picoseconds. + Weight::from_parts(36_764_791, 30944) + // Standard Error: 89_592 + .saturating_add(Weight::from_parts(49_620_105, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(14_u64)) .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) @@ -1237,10 +1276,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1991 + l * (7 ±0)` // Estimated: `8877` - // Minimum execution time: 81_113_000 picoseconds. - Weight::from_parts(84_470_927, 8877) - // Standard Error: 5_588 - .saturating_add(Weight::from_parts(97_606, 0).saturating_mul(l.into())) + // Minimum execution time: 81_768_000 picoseconds. + Weight::from_parts(85_332_982, 8877) + // Standard Error: 5_380 + .saturating_add(Weight::from_parts(70_298, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -1275,10 +1314,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 94_810_000 picoseconds. - Weight::from_parts(99_292_156, 6248) - // Standard Error: 3_677 - .saturating_add(Weight::from_parts(1_345_598, 0).saturating_mul(s.into())) + // Minimum execution time: 96_123_000 picoseconds. + Weight::from_parts(100_278_672, 6248) + // Standard Error: 3_487 + .saturating_add(Weight::from_parts(1_326_503, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(11_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -1323,13 +1362,13 @@ impl WeightInfo for () { fn new_era(v: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + n * (720 ±0) + v * (3598 ±0)` - // Estimated: `512390 + n * (3566 ±4) + v * (3566 ±40)` - // Minimum execution time: 583_230_000 picoseconds. - Weight::from_parts(585_794_000, 512390) - // Standard Error: 1_984_644 - .saturating_add(Weight::from_parts(65_914_551, 0).saturating_mul(v.into())) - // Standard Error: 197_758 - .saturating_add(Weight::from_parts(18_105_424, 0).saturating_mul(n.into())) + // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` + // Minimum execution time: 572_893_000 picoseconds. + Weight::from_parts(578_010_000, 512390) + // Standard Error: 2_094_268 + .saturating_add(Weight::from_parts(68_419_710, 0).saturating_mul(v.into())) + // Standard Error: 208_682 + .saturating_add(Weight::from_parts(18_826_175, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(206_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -1360,12 +1399,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3175 + n * (911 ±0) + v * (395 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 33_312_958_000 picoseconds. - Weight::from_parts(4_949_866_209, 512390) - // Standard Error: 402_931 - .saturating_add(Weight::from_parts(16_448_367, 0).saturating_mul(v.into())) - // Standard Error: 402_931 - .saturating_add(Weight::from_parts(25_361_503, 0).saturating_mul(n.into())) + // Minimum execution time: 33_836_205_000 picoseconds. + Weight::from_parts(34_210_443_000, 512390) + // Standard Error: 441_692 + .saturating_add(Weight::from_parts(6_122_533, 0).saturating_mul(v.into())) + // Standard Error: 441_692 + .saturating_add(Weight::from_parts(4_418_264, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(201_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -1382,10 +1421,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `979 + v * (50 ±0)` // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_474_646_000 picoseconds. - Weight::from_parts(2_512_113_000, 3510) - // Standard Error: 33_996 - .saturating_add(Weight::from_parts(1_992_173, 0).saturating_mul(v.into())) + // Minimum execution time: 2_454_689_000 picoseconds. + Weight::from_parts(161_771_064, 3510) + // Standard Error: 31_022 + .saturating_add(Weight::from_parts(4_820_158, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) @@ -1406,8 +1445,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_466_000 picoseconds. - Weight::from_parts(5_861_000, 0) + // Minimum execution time: 5_073_000 picoseconds. + Weight::from_parts(5_452_000, 0) .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: `Staking::MinCommission` (r:0 w:1) @@ -1426,8 +1465,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_780_000 picoseconds. - Weight::from_parts(4_998_000, 0) + // Minimum execution time: 4_465_000 picoseconds. + Weight::from_parts(4_832_000, 0) .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: `Staking::Bonded` (r:1 w:0) @@ -1456,8 +1495,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1939` // Estimated: `6248` - // Minimum execution time: 71_261_000 picoseconds. - Weight::from_parts(72_778_000, 6248) + // Minimum execution time: 71_239_000 picoseconds. + Weight::from_parts(74_649_000, 6248) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -1469,8 +1508,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `691` // Estimated: `3510` - // Minimum execution time: 12_497_000 picoseconds. - Weight::from_parts(13_049_000, 3510) + // Minimum execution time: 12_525_000 picoseconds. + Weight::from_parts(13_126_000, 3510) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1480,8 +1519,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_044_000 picoseconds. - Weight::from_parts(3_278_000, 0) + // Minimum execution time: 2_918_000 picoseconds. + Weight::from_parts(3_176_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } } -- GitLab From bbc2d870b78987d197238450589f15eabe00d821 Mon Sep 17 00:00:00 2001 From: Chevdor Date: Tue, 12 Dec 2023 11:04:01 +0100 Subject: [PATCH 39/59] Upgrade srtool GHA to v0.9.1 (#2655) Upgrade to [srtool-actions v0.9.1](https://github.com/chevdor/srtool-actions/releases/tag/v0.9.1) to fix issue introduced in https://github.com/paritytech/polkadot-sdk/pull/2217 --- .github/workflows/build-and-attach-release-runtimes.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-attach-release-runtimes.yml b/.github/workflows/build-and-attach-release-runtimes.yml index 8e0a5ba04b4..a480784aea3 100644 --- a/.github/workflows/build-and-attach-release-runtimes.yml +++ b/.github/workflows/build-and-attach-release-runtimes.yml @@ -23,7 +23,7 @@ jobs: - { name: glutton-westend, package: glutton-westend-runtime, path: cumulus/parachains/runtimes/glutton/glutton-westend } build_config: # Release build has logging disabled and no dev features - - { type: on-chain-release, opts: --features on-chain-release-build } + - { type: on-chain-release, opts: --features on-chain-release-build } # Debug build has logging enabled and developer features - { type: dev-debug-build, opts: --features try-runtime } @@ -35,7 +35,7 @@ jobs: - name: Build ${{ matrix.runtime.name }} ${{ matrix.build_config.type }} id: srtool_build - uses: chevdor/srtool-actions@v0.9.0 + uses: chevdor/srtool-actions@v0.9.1 env: BUILD_OPTS: ${{ matrix.build_config.opts }} with: -- GitLab From 2aaa9af3746b0cf671de9dc98fe2465c7ef59be2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Dec 2023 11:26:44 +0100 Subject: [PATCH 40/59] Bump names from 0.13.0 to 0.14.0 (#2686) Bumps [names](https://github.com/fnichol/names) from 0.13.0 to 0.14.0.
Release notes

Sourced from names's releases.

Release 0.14.0

0.14.0 - 2022-06-28

Changed

  • upgrade to regex 1.5.6
Changelog

Sourced from names's changelog.

[0.14.0] - 2022-06-28

Changed

  • upgrade to regex 1.5.6
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=names&package-manager=cargo&previous-version=0.13.0&new-version=0.14.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 19 +++++-------------- substrate/client/cli/Cargo.toml | 2 +- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 05e6063cff9..72fa4a8e2bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1361,8 +1361,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f" dependencies = [ "bitcoin_hashes", - "rand 0.8.5", - "rand_core 0.6.4", + "rand 0.7.3", + "rand_core 0.5.1", "serde", "unicode-normalization", ] @@ -8337,15 +8337,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "names" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7d66043b25d4a6cccb23619d10c19c25304b355a7dccd4a8e11423dd2382146" -dependencies = [ - "rand 0.8.5", -] - [[package]] name = "names" version = "0.14.0" @@ -13882,7 +13873,7 @@ dependencies = [ "libc", "libflate", "log", - "names 0.14.0", + "names", "prost", "reqwest", "thiserror", @@ -15056,7 +15047,7 @@ dependencies = [ "itertools 0.10.5", "libp2p-identity", "log", - "names 0.13.0", + "names", "parity-scale-codec", "rand 0.8.5", "regex", @@ -19950,7 +19941,7 @@ checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if", "digest 0.10.7", - "rand 0.8.5", + "rand 0.7.3", "static_assertions", ] diff --git a/substrate/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index 1f3e8f44f82..de303975031 100644 --- a/substrate/client/cli/Cargo.toml +++ b/substrate/client/cli/Cargo.toml @@ -21,7 +21,7 @@ futures = "0.3.21" itertools = "0.10.3" libp2p-identity = { version = "0.1.3", features = ["ed25519", "peerid"] } log = "0.4.17" -names = { version = "0.13.0", default-features = false } +names = { version = "0.14.0", default-features = false } parity-scale-codec = "3.6.1" rand = "0.8.5" regex = "1.6.0" -- GitLab From ef62acfbcfefbbed5bcf934447578c9e9ef07eec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 12 Dec 2023 12:37:52 +0100 Subject: [PATCH 41/59] pallet-uniques: Move migration over to `VersionedMigration` (#2687) --- prdoc/pr_2687.prdoc | 18 +++++++ substrate/frame/uniques/src/migration.rs | 65 ++++++++++++------------ 2 files changed, 51 insertions(+), 32 deletions(-) create mode 100644 prdoc/pr_2687.prdoc diff --git a/prdoc/pr_2687.prdoc b/prdoc/pr_2687.prdoc new file mode 100644 index 00000000000..90e635d8052 --- /dev/null +++ b/prdoc/pr_2687.prdoc @@ -0,0 +1,18 @@ +title: "pallet-uniques: Move migration over to `VersionedMigration`" + +doc: + - audience: Runtime Dev + description: | + Moves the migration over to `VersionedMigration`. Thus, if you had + used `migrate_to_v1` before in a custom `OnRuntimeUpgrade` implementation + you can now directly use the `MigrateV0ToV1`. + +migrations: + runtime: + - reference: MigrateV0ToV1 + description: | + Migrate the pallet storage from `0` to `1` by initializing + the `CollectionAccount` storage entry from all collections. + +crates: + - name: "pallet-uniques" diff --git a/substrate/frame/uniques/src/migration.rs b/substrate/frame/uniques/src/migration.rs index 6c92b753b4a..6b2bbf375e7 100644 --- a/substrate/frame/uniques/src/migration.rs +++ b/substrate/frame/uniques/src/migration.rs @@ -17,38 +17,39 @@ //! Various pieces of common functionality. use super::*; -use frame_support::traits::{Get, GetStorageVersion, PalletInfoAccess, StorageVersion}; - -/// Migrate the pallet storage to v1. -pub fn migrate_to_v1, I: 'static, P: GetStorageVersion + PalletInfoAccess>( -) -> frame_support::weights::Weight { - let on_chain_storage_version =

::on_chain_storage_version(); - log::info!( - target: LOG_TARGET, - "Running migration storage v1 for uniques with storage version {:?}", - on_chain_storage_version, - ); - - if on_chain_storage_version < 1 { - let mut count = 0; - for (collection, detail) in Collection::::iter() { - CollectionAccount::::insert(&detail.owner, &collection, ()); - count += 1; +use frame_support::traits::{Get, OnRuntimeUpgrade}; +use sp_std::marker::PhantomData; + +mod v1 { + use super::*; + + /// Actual implementation of the storage migration. + pub struct MigrateToV1Impl(PhantomData<(T, I)>); + + impl, I: 'static> OnRuntimeUpgrade for MigrateToV1Impl { + fn on_runtime_upgrade() -> frame_support::weights::Weight { + let mut count = 0; + for (collection, detail) in Collection::::iter() { + CollectionAccount::::insert(&detail.owner, &collection, ()); + count += 1; + } + + log::info!( + target: LOG_TARGET, + "Storage migration v1 for uniques finished.", + ); + + // calculate and return migration weights + T::DbWeight::get().reads_writes(count as u64 + 1, count as u64 + 1) } - StorageVersion::new(1).put::

(); - log::info!( - target: LOG_TARGET, - "Running migration storage v1 for uniques with storage version {:?} was complete", - on_chain_storage_version, - ); - // calculate and return migration weights - T::DbWeight::get().reads_writes(count as u64 + 1, count as u64 + 1) - } else { - log::warn!( - target: LOG_TARGET, - "Attempted to apply migration to v1 but failed because storage version is {:?}", - on_chain_storage_version, - ); - T::DbWeight::get().reads(1) } } + +/// Migrate the pallet storage from `0` to `1`. +pub type MigrateV0ToV1 = frame_support::migrations::VersionedMigration< + 0, + 1, + v1::MigrateToV1Impl, + Pallet, + ::DbWeight, +>; -- GitLab From 6b5995ffd162d88df1e3baeaafe05869d1a7d966 Mon Sep 17 00:00:00 2001 From: Juan Girini Date: Tue, 12 Dec 2023 14:24:27 +0100 Subject: [PATCH 42/59] Add a deprecation section to the Contributing notes (#2248) A brief explanation of the Deprecation Checklist is added to the Contributing notes with a link to it --- docs/contributor/CONTRIBUTING.md | 6 ++++++ docs/contributor/DEPRECATION_CHECKLIST.md | 6 ++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/contributor/CONTRIBUTING.md b/docs/contributor/CONTRIBUTING.md index 3350d134414..96dc86e9780 100644 --- a/docs/contributor/CONTRIBUTING.md +++ b/docs/contributor/CONTRIBUTING.md @@ -152,3 +152,9 @@ We use [zepter](https://github.com/ggwpez/zepter) to enforce features are propag If you're member of **paritytech** org - you can use command-bot to run various of common commands in CI: Start with comment in PR: `bot help` to see the list of available commands. + + +## Deprecating code + +When deprecating and removing code you need to be mindful of how this could impact downstream developers. In order to +mitigate this impact, it is recommended to adhere to the steps outlined in the [Deprecation Checklist](./DEPRECATION_CHECKLIST.md). diff --git a/docs/contributor/DEPRECATION_CHECKLIST.md b/docs/contributor/DEPRECATION_CHECKLIST.md index ffb99e1ec3f..687c0a7cd7d 100644 --- a/docs/contributor/DEPRECATION_CHECKLIST.md +++ b/docs/contributor/DEPRECATION_CHECKLIST.md @@ -1,9 +1,7 @@ # Deprecation Checklist -This deprecation checklist makes sense while we don’t use [SemVer](https://semver.org/). -After that, this document will most likely change. -As deprecation and removal of existing code can happen on any release, we need to be mindful that external builders -could be impacted by the changes we make. +Polkadot SDK is under constant development and improvement, thus deprecation and removal of existing code happen often. +When creating a breaking change we need to be mindful that external builders could be impacted by this. The deprecation checklist tries to mitigate this impact, while still keeping the developer experience, the DevEx, as smooth as possible. -- GitLab From 42a3afba945c88b8e1364c710565299116958dea Mon Sep 17 00:00:00 2001 From: Chevdor Date: Tue, 12 Dec 2023 15:29:56 +0100 Subject: [PATCH 43/59] Changelogs local generation (#1411) This PR introduces a script and some templates to use the prdoc involved in a release and build: - the changelog - a simple draft of audience documentation Since the prdoc presence was enforced in the middle of the version 1.5.0, not all PRs did come with a `prdoc` file. This PR creates all the missing `prdoc` files with some minimum content allowing to properly generate the changelog. The generated content is **not** suitable for the audience documentation. The audience documentation will be possible with the next version, when all PR come with a proper `prdoc`. ## Assumptions - the prdoc files for release `vX.Y.Z` have been moved under `prdoc/X.Y.Z` - the changelog requires for now for the prdoc files to contain author + topic. Thos fields are optional. The build script can be called as: ``` VERSION=X.Y.Z ./scripts/release/build-changelogs.sh ``` Related: - #1408 --------- Co-authored-by: EgorPopelyaev --- Cargo.lock | 4 +- .../assets/asset-hub-rococo/src/lib.rs | 4 +- .../assets/asset-hub-westend/src/lib.rs | 2 +- .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 2 +- .../bridge-hubs/bridge-hub-westend/src/lib.rs | 2 +- .../collectives-westend/src/lib.rs | 2 +- .../contracts/contracts-rococo/src/lib.rs | 2 +- .../glutton/glutton-westend/src/lib.rs | 2 +- .../testing/rococo-parachain/src/lib.rs | 2 +- cumulus/polkadot-parachain/Cargo.toml | 2 +- polkadot/Cargo.toml | 2 +- polkadot/node/primitives/src/lib.rs | 2 +- polkadot/runtime/rococo/src/lib.rs | 2 +- polkadot/runtime/westend/src/lib.rs | 2 +- prdoc/{ => 1.3.0}/pr_1234.prdoc | 0 prdoc/{ => 1.3.0}/pr_1255.prdoc | 0 prdoc/{ => 1.3.0}/pr_1818.prdoc | 0 prdoc/{ => 1.3.0}/pr_1873.prdoc | 0 prdoc/{ => 1.3.0}/pr_1913.prdoc | 0 prdoc/{ => 1.3.0}/pr_1921.prdoc | 0 prdoc/1.3.0/readme.md | 2 + prdoc/{ => 1.4.0}/pr_1178.prdoc | 0 prdoc/{ => 1.4.0}/pr_1246.prdoc | 0 prdoc/{ => 1.4.0}/pr_1256.prdoc | 0 prdoc/{ => 1.4.0}/pr_1805.prdoc | 0 prdoc/{ => 1.4.0}/pr_1926.prdoc | 0 prdoc/{ => 1.4.0}/pr_2086.prdoc | 0 prdoc/{ => 1.4.0}/pr_2107.prdoc | 0 prdoc/{ => 1.4.0}/pr_2165.prdoc | 0 prdoc/1.4.0/readme.md | 2 + prdoc/1.5.0/pr_1370_special.prdoc | 9 ++++ .../pr_1408_prodc-introduction.prdoc | 3 ++ prdoc/1.5.0/pr_1497_special.prdoc | 9 ++++ prdoc/1.5.0/pr_1918_special.prdoc | 9 ++++ .../pr_1946_prdoc_new_schema.prdoc | 3 ++ prdoc/1.5.0/pr_1985_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2001_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2058_special.prdoc | 9 ++++ prdoc/{ => 1.5.0}/pr_2142.prdoc | 3 ++ prdoc/1.5.0/pr_2167_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2174_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2182_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2184_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2221_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2250_special.prdoc | 9 ++++ prdoc/{ => 1.5.0}/pr_2253.prdoc | 3 ++ prdoc/1.5.0/pr_2265_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2300_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2351_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2354_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2361_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2368_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2369_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2377_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2378_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2380_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2381_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2385_special.prdoc | 9 ++++ prdoc/{ => 1.5.0}/pr_2388.prdoc | 8 ++- prdoc/1.5.0/pr_2397_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2406_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2411_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2413_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2426_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2435_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2442_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2446_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2450_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2455_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2457_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2459_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2461_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2462_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2463_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2474_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2483_special.prdoc | 9 ++++ prdoc/{ => 1.5.0}/pr_2486.prdoc | 3 ++ prdoc/1.5.0/pr_2487_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2501_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2509_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2515_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2516_special.prdoc | 9 ++++ prdoc/1.5.0/pr_2521_special.prdoc | 10 ++++ prdoc/1.5.0/pr_2526_special.prdoc | 10 ++++ prdoc/1.5.0/pr_2552_special.prdoc | 10 ++++ prdoc/1.5.0/pr_2555_special.prdoc | 10 ++++ prdoc/1.5.0/pr_2572_special.prdoc | 10 ++++ prdoc/1.5.0/pr_2579_special.prdoc | 10 ++++ prdoc/1.5.0/pr_2581_special.prdoc | 10 ++++ prdoc/1.5.0/pr_2591.prdoc | 12 +++++ prdoc/1.5.0/pr_2602_special.prdoc | 10 ++++ prdoc/1.5.0/pr_2625_special.prdoc | 10 ++++ prdoc/1.5.0/readme.md | 2 + prdoc/pr_2591.prdoc | 9 ---- prdoc/schema_user.json | 10 ++++ scripts/release/build-changelogs.sh | 54 +++++++++++++++++++ scripts/release/templates/audience.md.tera | 13 +++++ scripts/release/templates/changelog.md.tera | 7 +++ 98 files changed, 643 insertions(+), 27 deletions(-) rename prdoc/{ => 1.3.0}/pr_1234.prdoc (100%) rename prdoc/{ => 1.3.0}/pr_1255.prdoc (100%) rename prdoc/{ => 1.3.0}/pr_1818.prdoc (100%) rename prdoc/{ => 1.3.0}/pr_1873.prdoc (100%) rename prdoc/{ => 1.3.0}/pr_1913.prdoc (100%) rename prdoc/{ => 1.3.0}/pr_1921.prdoc (100%) create mode 100644 prdoc/1.3.0/readme.md rename prdoc/{ => 1.4.0}/pr_1178.prdoc (100%) rename prdoc/{ => 1.4.0}/pr_1246.prdoc (100%) rename prdoc/{ => 1.4.0}/pr_1256.prdoc (100%) rename prdoc/{ => 1.4.0}/pr_1805.prdoc (100%) rename prdoc/{ => 1.4.0}/pr_1926.prdoc (100%) rename prdoc/{ => 1.4.0}/pr_2086.prdoc (100%) rename prdoc/{ => 1.4.0}/pr_2107.prdoc (100%) rename prdoc/{ => 1.4.0}/pr_2165.prdoc (100%) create mode 100644 prdoc/1.4.0/readme.md create mode 100644 prdoc/1.5.0/pr_1370_special.prdoc rename prdoc/{ => 1.5.0}/pr_1408_prodc-introduction.prdoc (89%) create mode 100644 prdoc/1.5.0/pr_1497_special.prdoc create mode 100644 prdoc/1.5.0/pr_1918_special.prdoc rename prdoc/{ => 1.5.0}/pr_1946_prdoc_new_schema.prdoc (90%) create mode 100644 prdoc/1.5.0/pr_1985_special.prdoc create mode 100644 prdoc/1.5.0/pr_2001_special.prdoc create mode 100644 prdoc/1.5.0/pr_2058_special.prdoc rename prdoc/{ => 1.5.0}/pr_2142.prdoc (93%) create mode 100644 prdoc/1.5.0/pr_2167_special.prdoc create mode 100644 prdoc/1.5.0/pr_2174_special.prdoc create mode 100644 prdoc/1.5.0/pr_2182_special.prdoc create mode 100644 prdoc/1.5.0/pr_2184_special.prdoc create mode 100644 prdoc/1.5.0/pr_2221_special.prdoc create mode 100644 prdoc/1.5.0/pr_2250_special.prdoc rename prdoc/{ => 1.5.0}/pr_2253.prdoc (95%) create mode 100644 prdoc/1.5.0/pr_2265_special.prdoc create mode 100644 prdoc/1.5.0/pr_2300_special.prdoc create mode 100644 prdoc/1.5.0/pr_2351_special.prdoc create mode 100644 prdoc/1.5.0/pr_2354_special.prdoc create mode 100644 prdoc/1.5.0/pr_2361_special.prdoc create mode 100644 prdoc/1.5.0/pr_2368_special.prdoc create mode 100644 prdoc/1.5.0/pr_2369_special.prdoc create mode 100644 prdoc/1.5.0/pr_2377_special.prdoc create mode 100644 prdoc/1.5.0/pr_2378_special.prdoc create mode 100644 prdoc/1.5.0/pr_2380_special.prdoc create mode 100644 prdoc/1.5.0/pr_2381_special.prdoc create mode 100644 prdoc/1.5.0/pr_2385_special.prdoc rename prdoc/{ => 1.5.0}/pr_2388.prdoc (91%) create mode 100644 prdoc/1.5.0/pr_2397_special.prdoc create mode 100644 prdoc/1.5.0/pr_2406_special.prdoc create mode 100644 prdoc/1.5.0/pr_2411_special.prdoc create mode 100644 prdoc/1.5.0/pr_2413_special.prdoc create mode 100644 prdoc/1.5.0/pr_2426_special.prdoc create mode 100644 prdoc/1.5.0/pr_2435_special.prdoc create mode 100644 prdoc/1.5.0/pr_2442_special.prdoc create mode 100644 prdoc/1.5.0/pr_2446_special.prdoc create mode 100644 prdoc/1.5.0/pr_2450_special.prdoc create mode 100644 prdoc/1.5.0/pr_2455_special.prdoc create mode 100644 prdoc/1.5.0/pr_2457_special.prdoc create mode 100644 prdoc/1.5.0/pr_2459_special.prdoc create mode 100644 prdoc/1.5.0/pr_2461_special.prdoc create mode 100644 prdoc/1.5.0/pr_2462_special.prdoc create mode 100644 prdoc/1.5.0/pr_2463_special.prdoc create mode 100644 prdoc/1.5.0/pr_2474_special.prdoc create mode 100644 prdoc/1.5.0/pr_2483_special.prdoc rename prdoc/{ => 1.5.0}/pr_2486.prdoc (95%) create mode 100644 prdoc/1.5.0/pr_2487_special.prdoc create mode 100644 prdoc/1.5.0/pr_2501_special.prdoc create mode 100644 prdoc/1.5.0/pr_2509_special.prdoc create mode 100644 prdoc/1.5.0/pr_2515_special.prdoc create mode 100644 prdoc/1.5.0/pr_2516_special.prdoc create mode 100644 prdoc/1.5.0/pr_2521_special.prdoc create mode 100644 prdoc/1.5.0/pr_2526_special.prdoc create mode 100644 prdoc/1.5.0/pr_2552_special.prdoc create mode 100644 prdoc/1.5.0/pr_2555_special.prdoc create mode 100644 prdoc/1.5.0/pr_2572_special.prdoc create mode 100644 prdoc/1.5.0/pr_2579_special.prdoc create mode 100644 prdoc/1.5.0/pr_2581_special.prdoc create mode 100644 prdoc/1.5.0/pr_2591.prdoc create mode 100644 prdoc/1.5.0/pr_2602_special.prdoc create mode 100644 prdoc/1.5.0/pr_2625_special.prdoc create mode 100644 prdoc/1.5.0/readme.md delete mode 100644 prdoc/pr_2591.prdoc create mode 100755 scripts/release/build-changelogs.sh create mode 100644 scripts/release/templates/audience.md.tera create mode 100644 scripts/release/templates/changelog.md.tera diff --git a/Cargo.lock b/Cargo.lock index 72fa4a8e2bc..e62e7f900c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11786,7 +11786,7 @@ dependencies = [ [[package]] name = "polkadot" -version = "1.1.0" +version = "1.5.0" dependencies = [ "assert_cmd", "color-eyre", @@ -12756,7 +12756,7 @@ dependencies = [ [[package]] name = "polkadot-parachain-bin" -version = "1.1.0" +version = "1.5.0" dependencies = [ "assert_cmd", "asset-hub-rococo-runtime", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index 86000a20b5b..a4a42aa9e88 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -112,7 +112,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("statemine"), impl_name: create_runtime_str!("statemine"), authoring_version: 1, - spec_version: 1_004_000, + spec_version: 1_005_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 13, @@ -125,7 +125,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("statemine"), impl_name: create_runtime_str!("statemine"), authoring_version: 1, - spec_version: 1_004_000, + spec_version: 1_005_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 13, diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 6709a20b275..7443de54cb6 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -109,7 +109,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("westmint"), impl_name: create_runtime_str!("westmint"), authoring_version: 1, - spec_version: 1_004_000, + spec_version: 1_005_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 13, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index 8bd5c196016..1bb2faeb2fc 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -171,7 +171,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("bridge-hub-rococo"), impl_name: create_runtime_str!("bridge-hub-rococo"), authoring_version: 1, - spec_version: 1_004_000, + spec_version: 1_005_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 3, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index 07e664d67be..6157aa90a5a 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -172,7 +172,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("bridge-hub-westend"), impl_name: create_runtime_str!("bridge-hub-westend"), authoring_version: 1, - spec_version: 1_004_000, + spec_version: 1_005_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 3, diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs index 9135405155b..9074323fe31 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs @@ -114,7 +114,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("collectives-westend"), impl_name: create_runtime_str!("collectives-westend"), authoring_version: 1, - spec_version: 1_004_000, + spec_version: 1_005_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 5, diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index 4ab3014cace..79b6b6be299 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -133,7 +133,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("contracts-rococo"), impl_name: create_runtime_str!("contracts-rococo"), authoring_version: 1, - spec_version: 1_004_000, + spec_version: 1_005_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 6, diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs index c9dc5131644..2c51791c074 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs @@ -99,7 +99,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("glutton-westend"), impl_name: create_runtime_str!("glutton-westend"), authoring_version: 1, - spec_version: 1_004_000, + spec_version: 1_005_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs index 9d2ba98a67c..4967ca86854 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs @@ -106,7 +106,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("test-parachain"), impl_name: create_runtime_str!("test-parachain"), authoring_version: 1, - spec_version: 1_004_000, + spec_version: 1_005_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 6, diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index fed076132a4..860c420d45b 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-parachain-bin" -version = "1.1.0" +version = "1.5.0" authors.workspace = true build = "build.rs" edition.workspace = true diff --git a/polkadot/Cargo.toml b/polkadot/Cargo.toml index c0227823c6b..6896d3c4b22 100644 --- a/polkadot/Cargo.toml +++ b/polkadot/Cargo.toml @@ -18,7 +18,7 @@ rust-version = "1.64.0" readme = "README.md" authors.workspace = true edition.workspace = true -version = "1.1.0" +version = "1.5.0" default-run = "polkadot" [dependencies] diff --git a/polkadot/node/primitives/src/lib.rs b/polkadot/node/primitives/src/lib.rs index be62145b999..6ac6b82c223 100644 --- a/polkadot/node/primitives/src/lib.rs +++ b/polkadot/node/primitives/src/lib.rs @@ -58,7 +58,7 @@ pub use disputes::{ /// relatively rare. /// /// The associated worker binaries should use the same version as the node that spawns them. -pub const NODE_VERSION: &'static str = "1.1.0"; +pub const NODE_VERSION: &'static str = "1.5.0"; // For a 16-ary Merkle Prefix Trie, we can expect at most 16 32-byte hashes per node // plus some overhead: diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 26cc6d95449..1e40f14f492 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -149,7 +149,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("rococo"), impl_name: create_runtime_str!("parity-rococo-v2.0"), authoring_version: 0, - spec_version: 1_004_000, + spec_version: 1_005_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 22, diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 827a4953ec3..0a70a493b29 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -145,7 +145,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("westend"), impl_name: create_runtime_str!("parity-westend"), authoring_version: 2, - spec_version: 1_004_000, + spec_version: 1_005_000, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 22, diff --git a/prdoc/pr_1234.prdoc b/prdoc/1.3.0/pr_1234.prdoc similarity index 100% rename from prdoc/pr_1234.prdoc rename to prdoc/1.3.0/pr_1234.prdoc diff --git a/prdoc/pr_1255.prdoc b/prdoc/1.3.0/pr_1255.prdoc similarity index 100% rename from prdoc/pr_1255.prdoc rename to prdoc/1.3.0/pr_1255.prdoc diff --git a/prdoc/pr_1818.prdoc b/prdoc/1.3.0/pr_1818.prdoc similarity index 100% rename from prdoc/pr_1818.prdoc rename to prdoc/1.3.0/pr_1818.prdoc diff --git a/prdoc/pr_1873.prdoc b/prdoc/1.3.0/pr_1873.prdoc similarity index 100% rename from prdoc/pr_1873.prdoc rename to prdoc/1.3.0/pr_1873.prdoc diff --git a/prdoc/pr_1913.prdoc b/prdoc/1.3.0/pr_1913.prdoc similarity index 100% rename from prdoc/pr_1913.prdoc rename to prdoc/1.3.0/pr_1913.prdoc diff --git a/prdoc/pr_1921.prdoc b/prdoc/1.3.0/pr_1921.prdoc similarity index 100% rename from prdoc/pr_1921.prdoc rename to prdoc/1.3.0/pr_1921.prdoc diff --git a/prdoc/1.3.0/readme.md b/prdoc/1.3.0/readme.md new file mode 100644 index 00000000000..3d74fa34247 --- /dev/null +++ b/prdoc/1.3.0/readme.md @@ -0,0 +1,2 @@ +Version 1.3.0 does not support `prddoc` yet. +Some prdoc files are provided but the list is NOT complete. diff --git a/prdoc/pr_1178.prdoc b/prdoc/1.4.0/pr_1178.prdoc similarity index 100% rename from prdoc/pr_1178.prdoc rename to prdoc/1.4.0/pr_1178.prdoc diff --git a/prdoc/pr_1246.prdoc b/prdoc/1.4.0/pr_1246.prdoc similarity index 100% rename from prdoc/pr_1246.prdoc rename to prdoc/1.4.0/pr_1246.prdoc diff --git a/prdoc/pr_1256.prdoc b/prdoc/1.4.0/pr_1256.prdoc similarity index 100% rename from prdoc/pr_1256.prdoc rename to prdoc/1.4.0/pr_1256.prdoc diff --git a/prdoc/pr_1805.prdoc b/prdoc/1.4.0/pr_1805.prdoc similarity index 100% rename from prdoc/pr_1805.prdoc rename to prdoc/1.4.0/pr_1805.prdoc diff --git a/prdoc/pr_1926.prdoc b/prdoc/1.4.0/pr_1926.prdoc similarity index 100% rename from prdoc/pr_1926.prdoc rename to prdoc/1.4.0/pr_1926.prdoc diff --git a/prdoc/pr_2086.prdoc b/prdoc/1.4.0/pr_2086.prdoc similarity index 100% rename from prdoc/pr_2086.prdoc rename to prdoc/1.4.0/pr_2086.prdoc diff --git a/prdoc/pr_2107.prdoc b/prdoc/1.4.0/pr_2107.prdoc similarity index 100% rename from prdoc/pr_2107.prdoc rename to prdoc/1.4.0/pr_2107.prdoc diff --git a/prdoc/pr_2165.prdoc b/prdoc/1.4.0/pr_2165.prdoc similarity index 100% rename from prdoc/pr_2165.prdoc rename to prdoc/1.4.0/pr_2165.prdoc diff --git a/prdoc/1.4.0/readme.md b/prdoc/1.4.0/readme.md new file mode 100644 index 00000000000..e1a1055d918 --- /dev/null +++ b/prdoc/1.4.0/readme.md @@ -0,0 +1,2 @@ +Version 1.4.0 does not support `prddoc` yet. +Some prdoc files are provided but the list is NOT complete. diff --git a/prdoc/1.5.0/pr_1370_special.prdoc b/prdoc/1.5.0/pr_1370_special.prdoc new file mode 100644 index 00000000000..692a6e03170 --- /dev/null +++ b/prdoc/1.5.0/pr_1370_special.prdoc @@ -0,0 +1,9 @@ +title: Rework the event system of `sc-network` +author: altonen +topic: Node + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/pr_1408_prodc-introduction.prdoc b/prdoc/1.5.0/pr_1408_prodc-introduction.prdoc similarity index 89% rename from prdoc/pr_1408_prodc-introduction.prdoc rename to prdoc/1.5.0/pr_1408_prodc-introduction.prdoc index 85b4661b127..46f56068e27 100644 --- a/prdoc/pr_1408_prodc-introduction.prdoc +++ b/prdoc/1.5.0/pr_1408_prodc-introduction.prdoc @@ -1,6 +1,9 @@ # This PR does not need a prdoc but it is provided in order to test title: PRdoc check +author: chevdor +topic: documentation + doc: - audience: Node Dev description: | diff --git a/prdoc/1.5.0/pr_1497_special.prdoc b/prdoc/1.5.0/pr_1497_special.prdoc new file mode 100644 index 00000000000..3d603548260 --- /dev/null +++ b/prdoc/1.5.0/pr_1497_special.prdoc @@ -0,0 +1,9 @@ +title: Update tick collator for async backing +author: Sophia-Gold +topic: Tests + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_1918_special.prdoc b/prdoc/1.5.0/pr_1918_special.prdoc new file mode 100644 index 00000000000..9220ee970bc --- /dev/null +++ b/prdoc/1.5.0/pr_1918_special.prdoc @@ -0,0 +1,9 @@ +title: Preserve artifact cache unless stale +author: eagr +topic: Node + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/pr_1946_prdoc_new_schema.prdoc b/prdoc/1.5.0/pr_1946_prdoc_new_schema.prdoc similarity index 90% rename from prdoc/pr_1946_prdoc_new_schema.prdoc rename to prdoc/1.5.0/pr_1946_prdoc_new_schema.prdoc index c0632177738..fae063f6b1e 100644 --- a/prdoc/pr_1946_prdoc_new_schema.prdoc +++ b/prdoc/1.5.0/pr_1946_prdoc_new_schema.prdoc @@ -3,6 +3,9 @@ title: New PRDoc Schema +author: chevdor +topic: documentation + doc: - audience: Node Dev description: &desc | diff --git a/prdoc/1.5.0/pr_1985_special.prdoc b/prdoc/1.5.0/pr_1985_special.prdoc new file mode 100644 index 00000000000..c4305d6bb29 --- /dev/null +++ b/prdoc/1.5.0/pr_1985_special.prdoc @@ -0,0 +1,9 @@ +title: Enable parallel key scraping +author: eagr +topic: Node + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2001_special.prdoc b/prdoc/1.5.0/pr_2001_special.prdoc new file mode 100644 index 00000000000..366b5fddb8b --- /dev/null +++ b/prdoc/1.5.0/pr_2001_special.prdoc @@ -0,0 +1,9 @@ +title: "cumulus-consensus-common: block import: `delayed_best_block` flag added" +author: michalkucharczyk +topic: Node + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2058_special.prdoc b/prdoc/1.5.0/pr_2058_special.prdoc new file mode 100644 index 00000000000..6e3c83b09fa --- /dev/null +++ b/prdoc/1.5.0/pr_2058_special.prdoc @@ -0,0 +1,9 @@ +title: "PVF: Add test instructions" +author: mrcnski +topic: Node + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/pr_2142.prdoc b/prdoc/1.5.0/pr_2142.prdoc similarity index 93% rename from prdoc/pr_2142.prdoc rename to prdoc/1.5.0/pr_2142.prdoc index 1d379411346..9cd1b23906d 100644 --- a/prdoc/pr_2142.prdoc +++ b/prdoc/1.5.0/pr_2142.prdoc @@ -1,5 +1,8 @@ title: Cleanup XCMP `QueueConfigData` +author: serban300 +topic: runtime + doc: - audience: Runtime Dev description: Removes obsolete fields from the `QueueConfigData` structure. For the remaining fields, if they use the old defaults, we replace them with the new defaults. diff --git a/prdoc/1.5.0/pr_2167_special.prdoc b/prdoc/1.5.0/pr_2167_special.prdoc new file mode 100644 index 00000000000..7bbde7002a2 --- /dev/null +++ b/prdoc/1.5.0/pr_2167_special.prdoc @@ -0,0 +1,9 @@ +title: "add pallet nomination-pools versioned migration to kitchensink" +author: brunopgalvao +topic: Tests + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2174_special.prdoc b/prdoc/1.5.0/pr_2174_special.prdoc new file mode 100644 index 00000000000..f23d2803e96 --- /dev/null +++ b/prdoc/1.5.0/pr_2174_special.prdoc @@ -0,0 +1,9 @@ +title: "chain-spec-builder: cleanup" +author: michalkucharczyk +topic: Node + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2182_special.prdoc b/prdoc/1.5.0/pr_2182_special.prdoc new file mode 100644 index 00000000000..ad57bf64916 --- /dev/null +++ b/prdoc/1.5.0/pr_2182_special.prdoc @@ -0,0 +1,9 @@ +title: "remove retry from backers on failed candidate validation" +author: Jpserrat +topic: Node + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2184_special.prdoc b/prdoc/1.5.0/pr_2184_special.prdoc new file mode 100644 index 00000000000..b838bf41ba1 --- /dev/null +++ b/prdoc/1.5.0/pr_2184_special.prdoc @@ -0,0 +1,9 @@ +title: Zombienet tests - disputes on finalized blocks +author: Overkillus +topic: Tests + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2221_special.prdoc b/prdoc/1.5.0/pr_2221_special.prdoc new file mode 100644 index 00000000000..dbd8c4a1fc1 --- /dev/null +++ b/prdoc/1.5.0/pr_2221_special.prdoc @@ -0,0 +1,9 @@ +title: "PVF worker: switch on seccomp networking restrictions" +author: mrcnski +topic: Node + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2250_special.prdoc b/prdoc/1.5.0/pr_2250_special.prdoc new file mode 100644 index 00000000000..d3f87b81b92 --- /dev/null +++ b/prdoc/1.5.0/pr_2250_special.prdoc @@ -0,0 +1,9 @@ +title: "crypto: `lazy_static` removed, light parser for address URI added" +author: michalkucharczyk +topic: Node + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/pr_2253.prdoc b/prdoc/1.5.0/pr_2253.prdoc similarity index 95% rename from prdoc/pr_2253.prdoc rename to prdoc/1.5.0/pr_2253.prdoc index 8a6dac754d1..3f69bc2461e 100644 --- a/prdoc/pr_2253.prdoc +++ b/prdoc/1.5.0/pr_2253.prdoc @@ -3,6 +3,9 @@ title: Different builder pattern constructors for XCM +author: franciscoaguirre +topic: runtime + doc: - audience: Runtime Dev description: | diff --git a/prdoc/1.5.0/pr_2265_special.prdoc b/prdoc/1.5.0/pr_2265_special.prdoc new file mode 100644 index 00000000000..336adec03ab --- /dev/null +++ b/prdoc/1.5.0/pr_2265_special.prdoc @@ -0,0 +1,9 @@ +title: Remove im-online pallet from Rococo and Westend +author: s0me0ne-unkn0wn +topic: Pallets + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2300_special.prdoc b/prdoc/1.5.0/pr_2300_special.prdoc new file mode 100644 index 00000000000..407f0766325 --- /dev/null +++ b/prdoc/1.5.0/pr_2300_special.prdoc @@ -0,0 +1,9 @@ +title: '[testnet] Remove Wococo stuff from BridgeHubRococo/AssetHubRococo' +author: bkontur  +topic: Bridges + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2351_special.prdoc b/prdoc/1.5.0/pr_2351_special.prdoc new file mode 100644 index 00000000000..16f9e5d15a7 --- /dev/null +++ b/prdoc/1.5.0/pr_2351_special.prdoc @@ -0,0 +1,9 @@ +title: "frame-system: Add last_runtime_upgrade_spec_version" +author: bkchr +topic: Frame + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2354_special.prdoc b/prdoc/1.5.0/pr_2354_special.prdoc new file mode 100644 index 00000000000..5fbedef0361 --- /dev/null +++ b/prdoc/1.5.0/pr_2354_special.prdoc @@ -0,0 +1,9 @@ +title: "Fix Typo: `PalletXcmExtrinsicsBenchmark`" +author: joepetrowski +topic: Benchmarks + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2361_special.prdoc b/prdoc/1.5.0/pr_2361_special.prdoc new file mode 100644 index 00000000000..d44b87287c4 --- /dev/null +++ b/prdoc/1.5.0/pr_2361_special.prdoc @@ -0,0 +1,9 @@ +title: "[ci] Enable zombienet jobs in PRs" +author: alvicsam +topic: Tests + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2368_special.prdoc b/prdoc/1.5.0/pr_2368_special.prdoc new file mode 100644 index 00000000000..e8ebcb38d30 --- /dev/null +++ b/prdoc/1.5.0/pr_2368_special.prdoc @@ -0,0 +1,9 @@ +title: "implementers-guide: update github link" +author: ordian +topic: Documentation + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2369_special.prdoc b/prdoc/1.5.0/pr_2369_special.prdoc new file mode 100644 index 00000000000..ebcc533712d --- /dev/null +++ b/prdoc/1.5.0/pr_2369_special.prdoc @@ -0,0 +1,9 @@ +title: "[NPoS] Check if staker is exposed in paged exposure storage entries" +author: Ank4n +topic: Pallets + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2377_special.prdoc b/prdoc/1.5.0/pr_2377_special.prdoc new file mode 100644 index 00000000000..2985db6f3f8 --- /dev/null +++ b/prdoc/1.5.0/pr_2377_special.prdoc @@ -0,0 +1,9 @@ +title: "fix typo" +author: cuteolaf +topic: Documentation + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2378_special.prdoc b/prdoc/1.5.0/pr_2378_special.prdoc new file mode 100644 index 00000000000..bdc96500094 --- /dev/null +++ b/prdoc/1.5.0/pr_2378_special.prdoc @@ -0,0 +1,9 @@ +title: "Beefy: small fixes" +author: serban300 +topic: Bridges + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2380_special.prdoc b/prdoc/1.5.0/pr_2380_special.prdoc new file mode 100644 index 00000000000..058be28bf5d --- /dev/null +++ b/prdoc/1.5.0/pr_2380_special.prdoc @@ -0,0 +1,9 @@ +title: Deprecate `RewardDestination::Controller` +author: rossbulat +topic: XCM + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2381_special.prdoc b/prdoc/1.5.0/pr_2381_special.prdoc new file mode 100644 index 00000000000..eb4020424d7 --- /dev/null +++ b/prdoc/1.5.0/pr_2381_special.prdoc @@ -0,0 +1,9 @@ +title: Make collator RPC mode non-experimental +author: skunert +topic: Cumulus + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2385_special.prdoc b/prdoc/1.5.0/pr_2385_special.prdoc new file mode 100644 index 00000000000..a5239d30652 --- /dev/null +++ b/prdoc/1.5.0/pr_2385_special.prdoc @@ -0,0 +1,9 @@ +title: "Relax `force_default_xcm_version` for testnet system parachains" +author: bkontur +topic: Cumulus + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/pr_2388.prdoc b/prdoc/1.5.0/pr_2388.prdoc similarity index 91% rename from prdoc/pr_2388.prdoc rename to prdoc/1.5.0/pr_2388.prdoc index fa560197aff..8f79097b8f6 100644 --- a/prdoc/pr_2388.prdoc +++ b/prdoc/1.5.0/pr_2388.prdoc @@ -3,8 +3,11 @@ title: Add new flexible `pallet_xcm::transfer_assets()` call/extrinsic +author: acatangiu +topic: runtime + doc: - - audience: Builder + - audience: Runtime Dev description: | For complex combinations of asset transfers where assets and fees may have different reserves or different reserve/teleport trust configurations, users can use the newly added `transfer_assets()` @@ -21,6 +24,7 @@ migrations: runtime: [] -crates: pallet-xcm +crates: + - name: pallet-xcm host_functions: [] diff --git a/prdoc/1.5.0/pr_2397_special.prdoc b/prdoc/1.5.0/pr_2397_special.prdoc new file mode 100644 index 00000000000..5f07b269b1e --- /dev/null +++ b/prdoc/1.5.0/pr_2397_special.prdoc @@ -0,0 +1,9 @@ +title: "Pools: Add `MaxUnbonding` to metadata" +author: rossbulat +topic: Pallets + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2406_special.prdoc b/prdoc/1.5.0/pr_2406_special.prdoc new file mode 100644 index 00000000000..3fdb7ad8cf2 --- /dev/null +++ b/prdoc/1.5.0/pr_2406_special.prdoc @@ -0,0 +1,9 @@ +title: Refactor ValidationError +author: eagr +topic: Node + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2411_special.prdoc b/prdoc/1.5.0/pr_2411_special.prdoc new file mode 100644 index 00000000000..0bc01e66903 --- /dev/null +++ b/prdoc/1.5.0/pr_2411_special.prdoc @@ -0,0 +1,9 @@ +title: "polkadot-node-subsystems: `ChainApiBackend` added + polkadot-debug image version fixed" +author: michalkucharczyk +topic: Tests + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2413_special.prdoc b/prdoc/1.5.0/pr_2413_special.prdoc new file mode 100644 index 00000000000..38083ba845b --- /dev/null +++ b/prdoc/1.5.0/pr_2413_special.prdoc @@ -0,0 +1,9 @@ +title: "Update documentation for `SafeMode` and `TxPause` Pallets" +author: wilwade +topic: Documentation + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2426_special.prdoc b/prdoc/1.5.0/pr_2426_special.prdoc new file mode 100644 index 00000000000..a0f5ab8ac5b --- /dev/null +++ b/prdoc/1.5.0/pr_2426_special.prdoc @@ -0,0 +1,9 @@ +title: "PVF: Fix unshare `no such file or directory` error" +author: mrcnski +topic: Node + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2435_special.prdoc b/prdoc/1.5.0/pr_2435_special.prdoc new file mode 100644 index 00000000000..b2bb7a2b815 --- /dev/null +++ b/prdoc/1.5.0/pr_2435_special.prdoc @@ -0,0 +1,9 @@ +title: "pallet-staking: Converts all math operations to safe" +author: gpestanaar +topic: Pallets + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2442_special.prdoc b/prdoc/1.5.0/pr_2442_special.prdoc new file mode 100644 index 00000000000..52e672e765f --- /dev/null +++ b/prdoc/1.5.0/pr_2442_special.prdoc @@ -0,0 +1,9 @@ +title: "Fixes cumulus README instructions" +author: gpestana +topic: Documentation + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2446_special.prdoc b/prdoc/1.5.0/pr_2446_special.prdoc new file mode 100644 index 00000000000..9fec1ad139c --- /dev/null +++ b/prdoc/1.5.0/pr_2446_special.prdoc @@ -0,0 +1,9 @@ +title: "sp-api: Move macro related re-exports to `__private`" +author: bkchr +topic: Runtime API + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2450_special.prdoc b/prdoc/1.5.0/pr_2450_special.prdoc new file mode 100644 index 00000000000..343e71fbf6d --- /dev/null +++ b/prdoc/1.5.0/pr_2450_special.prdoc @@ -0,0 +1,9 @@ +title: Adapt test worker to profile flag +author: eagr +topic: Node + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2455_special.prdoc b/prdoc/1.5.0/pr_2455_special.prdoc new file mode 100644 index 00000000000..928b8467807 --- /dev/null +++ b/prdoc/1.5.0/pr_2455_special.prdoc @@ -0,0 +1,9 @@ +title: "Remove `RuntimeApi` dependency on system parachain runtime code" +author: seadanda +topic: "System Parachains" + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2457_special.prdoc b/prdoc/1.5.0/pr_2457_special.prdoc new file mode 100644 index 00000000000..ca6401206f4 --- /dev/null +++ b/prdoc/1.5.0/pr_2457_special.prdoc @@ -0,0 +1,9 @@ +title: "polkadot-parachain: one chain-spec for all" +author: michalkucharczyk +topic: "System Parachains" + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2459_special.prdoc b/prdoc/1.5.0/pr_2459_special.prdoc new file mode 100644 index 00000000000..125f390f4ac --- /dev/null +++ b/prdoc/1.5.0/pr_2459_special.prdoc @@ -0,0 +1,9 @@ +title: '[NPoS] Use `EraInfo` to manipulate exposure in fast-unstake tests' +author: Ank4n +topic: Pallets,Tests + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2461_special.prdoc b/prdoc/1.5.0/pr_2461_special.prdoc new file mode 100644 index 00000000000..60a46714ca4 --- /dev/null +++ b/prdoc/1.5.0/pr_2461_special.prdoc @@ -0,0 +1,9 @@ +title: "PVF: remove audit log access" +author: mrcnski +topic: Node + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2462_special.prdoc b/prdoc/1.5.0/pr_2462_special.prdoc new file mode 100644 index 00000000000..ae1f1486327 --- /dev/null +++ b/prdoc/1.5.0/pr_2462_special.prdoc @@ -0,0 +1,9 @@ +title: "relay-chain-consensus: set a fork_choice" +author: michalkucharczyk +topic: Node + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2463_special.prdoc b/prdoc/1.5.0/pr_2463_special.prdoc new file mode 100644 index 00000000000..0f35d50036f --- /dev/null +++ b/prdoc/1.5.0/pr_2463_special.prdoc @@ -0,0 +1,9 @@ +title: Add `on-chain-release-build` feature for Collectives Westend +author: liamaharon +topic: System Parachains + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2474_special.prdoc b/prdoc/1.5.0/pr_2474_special.prdoc new file mode 100644 index 00000000000..42d67b5efa6 --- /dev/null +++ b/prdoc/1.5.0/pr_2474_special.prdoc @@ -0,0 +1,9 @@ +title: "Pools: Add ability to configure commission claiming permissions" +author: rossbulat +topic: Pallets + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2483_special.prdoc b/prdoc/1.5.0/pr_2483_special.prdoc new file mode 100644 index 00000000000..21fb045cae8 --- /dev/null +++ b/prdoc/1.5.0/pr_2483_special.prdoc @@ -0,0 +1,9 @@ +title: Remove `dmp-queue`` pallet from Rococo Asset Hub and Bridge Hub +author: liamaharon +topic: Frame + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/pr_2486.prdoc b/prdoc/1.5.0/pr_2486.prdoc similarity index 95% rename from prdoc/pr_2486.prdoc rename to prdoc/1.5.0/pr_2486.prdoc index 0d50a7279d1..c716f71c34e 100644 --- a/prdoc/pr_2486.prdoc +++ b/prdoc/1.5.0/pr_2486.prdoc @@ -1,5 +1,8 @@ title: "PVF: Add Secure Validator Mode" +author: mrcnski +topic: node + doc: - audience: Node Operator description: | diff --git a/prdoc/1.5.0/pr_2487_special.prdoc b/prdoc/1.5.0/pr_2487_special.prdoc new file mode 100644 index 00000000000..3d6a2e11e26 --- /dev/null +++ b/prdoc/1.5.0/pr_2487_special.prdoc @@ -0,0 +1,9 @@ +title: "Do not pollute global base path with export genesis/wasm" +author: bkchr +topic: Cumulus + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2501_special.prdoc b/prdoc/1.5.0/pr_2501_special.prdoc new file mode 100644 index 00000000000..125b9452c98 --- /dev/null +++ b/prdoc/1.5.0/pr_2501_special.prdoc @@ -0,0 +1,9 @@ +title: "Staking: `chill_other` takes stash instead of controller" +author: rossbulat +topic: Pallets + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2509_special.prdoc b/prdoc/1.5.0/pr_2509_special.prdoc new file mode 100644 index 00000000000..03ebfd80c96 --- /dev/null +++ b/prdoc/1.5.0/pr_2509_special.prdoc @@ -0,0 +1,9 @@ +title: "Breaking: Remove long deprecated `AllPalletsWithoutSystemReversed`" +author: skunert +topic: Frame + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2515_special.prdoc b/prdoc/1.5.0/pr_2515_special.prdoc new file mode 100644 index 00000000000..4664058f86c --- /dev/null +++ b/prdoc/1.5.0/pr_2515_special.prdoc @@ -0,0 +1,9 @@ +title: Set `frame_system::LastRuntimeUpgrade` after running `try-runtime migrations` +author: liamaharon +topic: Frame + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2516_special.prdoc b/prdoc/1.5.0/pr_2516_special.prdoc new file mode 100644 index 00000000000..5d452b63e59 --- /dev/null +++ b/prdoc/1.5.0/pr_2516_special.prdoc @@ -0,0 +1,9 @@ +title: Remove `dmp_queue pallet` from Westend SP runtimes +author: liamaharon +topic: Frame + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2521_special.prdoc b/prdoc/1.5.0/pr_2521_special.prdoc new file mode 100644 index 00000000000..3b70150619e --- /dev/null +++ b/prdoc/1.5.0/pr_2521_special.prdoc @@ -0,0 +1,10 @@ +title: 'substrate-node: `NativeElseWasmExecutor` is no longer used' + +author: michalkucharczyk +topic: node + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2526_special.prdoc b/prdoc/1.5.0/pr_2526_special.prdoc new file mode 100644 index 00000000000..6008d7bfa9d --- /dev/null +++ b/prdoc/1.5.0/pr_2526_special.prdoc @@ -0,0 +1,10 @@ +title: Remove `pov-recovery` race condition/Improve zombienet test + +author: skunert +topic: testing + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2552_special.prdoc b/prdoc/1.5.0/pr_2552_special.prdoc new file mode 100644 index 00000000000..9f0140c8142 --- /dev/null +++ b/prdoc/1.5.0/pr_2552_special.prdoc @@ -0,0 +1,10 @@ +title: Withdraw Assets Before Checking Out in OnReapIdentity impl + +author: joepetrowski +topic: xcm + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2555_special.prdoc b/prdoc/1.5.0/pr_2555_special.prdoc new file mode 100644 index 00000000000..f817810f433 --- /dev/null +++ b/prdoc/1.5.0/pr_2555_special.prdoc @@ -0,0 +1,10 @@ +title: Remove dependency on rand's SliceRandom shuffle implementation in `gossip-support` + +author: rphmeier +topic: node + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2572_special.prdoc b/prdoc/1.5.0/pr_2572_special.prdoc new file mode 100644 index 00000000000..9d4c285798c --- /dev/null +++ b/prdoc/1.5.0/pr_2572_special.prdoc @@ -0,0 +1,10 @@ +title: Add missing glossary to ref docs + +author: juangirini +topic: documentation + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2579_special.prdoc b/prdoc/1.5.0/pr_2579_special.prdoc new file mode 100644 index 00000000000..2992c92a8c5 --- /dev/null +++ b/prdoc/1.5.0/pr_2579_special.prdoc @@ -0,0 +1,10 @@ +title: "impl guide: update PVF host page; add diagrams" + +author: mrcnsk +topic: documentation + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2581_special.prdoc b/prdoc/1.5.0/pr_2581_special.prdoc new file mode 100644 index 00000000000..ebe5855b401 --- /dev/null +++ b/prdoc/1.5.0/pr_2581_special.prdoc @@ -0,0 +1,10 @@ +title: 'Bandersnatch: `ring-context` generic over domain size' + +author: davxy +topic: node + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2591.prdoc b/prdoc/1.5.0/pr_2591.prdoc new file mode 100644 index 00000000000..f827e70af8b --- /dev/null +++ b/prdoc/1.5.0/pr_2591.prdoc @@ -0,0 +1,12 @@ +title: Ensure to cleanup state in `remove_member` + +author: bkchr +topic: runtime + +doc: + - audience: Runtime Dev + description: | + Cleans up the state properly if a member of a ranked collective is removed. + +crates: + - name: pallet-ranked-collective diff --git a/prdoc/1.5.0/pr_2602_special.prdoc b/prdoc/1.5.0/pr_2602_special.prdoc new file mode 100644 index 00000000000..56896348b4f --- /dev/null +++ b/prdoc/1.5.0/pr_2602_special.prdoc @@ -0,0 +1,10 @@ +title: 'Bridges subtree update' + +author: bkontur +topic: bridges + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/pr_2625_special.prdoc b/prdoc/1.5.0/pr_2625_special.prdoc new file mode 100644 index 00000000000..21803d93dca --- /dev/null +++ b/prdoc/1.5.0/pr_2625_special.prdoc @@ -0,0 +1,10 @@ +title: Bridges update subtree + +author: bkontur +topic: bridges + +doc: + - audience: Runtime Dev + description: n/a + +crates: [] diff --git a/prdoc/1.5.0/readme.md b/prdoc/1.5.0/readme.md new file mode 100644 index 00000000000..14b6d603314 --- /dev/null +++ b/prdoc/1.5.0/readme.md @@ -0,0 +1,2 @@ +Version 1.5.0 does not fully support `prddoc` yet. +While the list is complete, not all prdoc files have a valid or accurate content. diff --git a/prdoc/pr_2591.prdoc b/prdoc/pr_2591.prdoc deleted file mode 100644 index fe967cb6785..00000000000 --- a/prdoc/pr_2591.prdoc +++ /dev/null @@ -1,9 +0,0 @@ -title: Ensure to cleanup state in remove_member - -doc: - - audience: Runtime Dev - description: | - Cleanes up the state properly if a member of a ranked collective is removed. - -crates: - - name: pallet-ranked-collective diff --git a/prdoc/schema_user.json b/prdoc/schema_user.json index 60ff28d3626..82215d51866 100644 --- a/prdoc/schema_user.json +++ b/prdoc/schema_user.json @@ -17,6 +17,16 @@ "type": "string", "description": "Title for the PR. This is what will show up in the release notes.\nif needed, you may provide a different title override for each audience in the `doc` property." }, + "author": { + "title": "Author handle", + "type": "string", + "description": "Author handle" + }, + "topic": { + "title": "Topic", + "type": "string", + "description": "Topic" + }, "doc": { "type": "array", diff --git a/scripts/release/build-changelogs.sh b/scripts/release/build-changelogs.sh new file mode 100755 index 00000000000..a9275f45a50 --- /dev/null +++ b/scripts/release/build-changelogs.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash + +export PRODUCT=polkadot +export VERSION=${VERSION:-1.5.0} + +PROJECT_ROOT=`git rev-parse --show-toplevel` +echo $PROJECT_ROOT + +TMP=$(mktemp -d) +TEMPLATE_AUDIENCE="${PROJECT_ROOT}/scripts/release/templates/audience.md.tera" +TEMPLATE_CHANGELOG="${PROJECT_ROOT}/scripts/release/templates/changelog.md.tera" + +DATA_JSON="${TMP}/data.json" +CONTEXT_JSON="${TMP}/context.json" +echo -e "TEMPLATE_AUDIENCE: \t$TEMPLATE_AUDIENCE" +echo -e "DATA_JSON: \t\t$DATA_JSON" +echo -e "CONTEXT_JSON: \t\t$CONTEXT_JSON" + +# Create output folder +OUTPUT="${TMP}/changelogs/$PRODUCT/$VERSION" +echo -e "OUTPUT: \t\t$OUTPUT" +mkdir -p $OUTPUT + +prdoc load -d "$PROJECT_ROOT/prdoc/$VERSION" --json > $DATA_JSON +# ls -al $DATA_JSON + +cat $DATA_JSON | jq ' { "prdoc" : .}' > $CONTEXT_JSON +# ls -al $CONTEXT_JSON + +# Fetch the list of valid audiences +SCHEMA_URL=https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json +SCHEMA=$(curl -s $SCHEMA_URL | sed 's|^//.*||') +AUDIENCE_ARRAY=$(echo -E $SCHEMA | jq -r '."$defs".audience.oneOf[] | .const') + +readarray -t audiences < <(echo "$AUDIENCE_ARRAY") +declare -p audiences + + +# Generate a changelog +echo "Generating changelog..." +tera -t "${TEMPLATE_CHANGELOG}" --env --env-key env "${CONTEXT_JSON}" > "$OUTPUT/changelog.md" +echo "Changelog ready in $OUTPUT/changelog.md" + +# Generate a release notes doc per audience +for audience in "${audiences[@]}"; do + audience_id="$(tr [A-Z] [a-z] <<< "$audience")" + audience_id="$(tr ' ' '_' <<< "$audience_id")" + echo "Processing audience: $audience ($audience_id)" + export TARGET_AUDIENCE=$audience + tera -t "${TEMPLATE_AUDIENCE}" --env --env-key env "${CONTEXT_JSON}" > "$OUTPUT/relnote_${audience_id}.md" +done + +# Show the files +tree -s -h -c $OUTPUT/ diff --git a/scripts/release/templates/audience.md.tera b/scripts/release/templates/audience.md.tera new file mode 100644 index 00000000000..dc507053dd5 --- /dev/null +++ b/scripts/release/templates/audience.md.tera @@ -0,0 +1,13 @@ +## Release {{ env.PRODUCT }} {{ env.VERSION }} + +Changelog for `{{ env.TARGET_AUDIENCE }}`. + +{% for file in prdoc -%} +#### PR #{{file.doc_filename.number}}: {{ file.content.title }} +{% for doc_item in file.content.doc %} +{%- if doc_item.audience == env.TARGET_AUDIENCE %} +{{ doc_item.description }} +{% endif -%} + +{%- endfor %} +{%- endfor %} diff --git a/scripts/release/templates/changelog.md.tera b/scripts/release/templates/changelog.md.tera new file mode 100644 index 00000000000..aaba761e8e4 --- /dev/null +++ b/scripts/release/templates/changelog.md.tera @@ -0,0 +1,7 @@ +## Changelog for `{{ env.PRODUCT | capitalize }} v{{ env.VERSION }}` + +{% for file in prdoc | sort(attribute="doc_filename.number") -%} +{%- set author= file.content.author | default(value="n/a") -%} +{%- set topic= file.content.topic | default(value="n/a") -%} +- #{{file.doc_filename.number}}: {{ file.content.title }} (@{{ author }}) [{{ topic | capitalize }}] +{% endfor -%} -- GitLab From 575b8f8d15c860f31cc0d5aeb680bbc1025c374a Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Tue, 12 Dec 2023 16:04:26 +0100 Subject: [PATCH 44/59] Ensure xcm versions over bridge (on sending chains) (#2481) ## Summary This pull request proposes a solution for improved control of the versioned XCM flow over the bridge (across different consensus chains) and resolves the situation where the sending chain/consensus has already migrated to a higher XCM version than the receiving chain/consensus. ## Problem/Motivation The current flow over the bridge involves a transfer from AssetHubRococo (AHR) to BridgeHubRococo (BHR) to BridgeHubWestend (BHW) and finally to AssetHubWestend (AHW), beginning with a reserve-backed transfer on AHR. In this process: 1. AHR sends XCM `ExportMessage` through `XcmpQueue`, incorporating XCM version checks using the `WrapVersion` feature, influenced by `pallet_xcm::SupportedVersion` (managed by `pallet_xcm::force_xcm_version` or version discovery). 2. BHR handles the `ExportMessage` instruction, utilizing the latest XCM version. The `HaulBlobExporter` converts the inner XCM to [`VersionedXcm::from`](https://github.com/paritytech/polkadot-sdk/blob/63ac2471aa0210f0ac9903bdd7d8f9351f9a635f/polkadot/xcm/xcm-builder/src/universal_exports.rs#L465-L467), also using the latest XCM version. However, challenges arise: - Incompatibility when BHW uses a different version than BHR. For instance, if BHR migrates to **XCMv4** while BHW remains on **XCMv3**, BHR's `VersionedXcm::from` uses `VersionedXcm::V4` variant, causing encoding issues for BHW. ``` /// Just a simulation of possible error, which could happen on BHW /// (this code is based on actual master without XCMv4) let encoded = hex_literal::hex!("0400"); println!("{:?}", VersionedXcm::<()>::decode(&mut &encoded[..])); Err(Error { cause: None, desc: "Could not decode `VersionedXcm`, variant doesn't exist" }) ``` - Similar compatibility issues exist between AHR and AHW. ## Solution This pull request introduces the following solutions: 1. **New trait `CheckVersion`** - added to the `xcm` module and exposing `pallet_xcm::SupportedVersion`. This enhancement allows checking the actual XCM version for desired destinations outside of the `pallet_xcm` module. 2. **Version Check in `HaulBlobExporter`** uses `CheckVersion` to check known/configured destination versions, ensuring compatibility. For example, in the scenario mentioned, BHR can store the version `3` for BHW. If BHR is on XCMv4, it will attempt to downgrade the message to version `3` instead of using the latest version `4`. 3. **Version Check in `pallet-xcm-bridge-hub-router`** - this check ensures compatibility with the real destination's XCM version, preventing the unnecessary sending of messages to the local bridge hub if versions are incompatible. These additions aim to improve the control and compatibility of XCM flows over the bridge and addressing issues related to version mismatches. ## Possible alternative solution _(More investigation is needed, and at the very least, it should extend to XCMv4/5. If this proves to be a viable option, I can open an RFC for XCM.)._ Add the `XcmVersion` attribute to the `ExportMessage` so that the sending chain can determine, based on what is stored in `pallet_xcm::SupportedVersion`, the version the destination is using. This way, we may not need to handle the version in `HaulBlobExporter`. ``` ExportMessage { network: NetworkId, destination: InteriorMultiLocation, xcm: Xcm<()> destination_xcm_version: Version, // <- new attritbute }, ``` ``` pub trait ExportXcm { fn validate( network: NetworkId, channel: u32, universal_source: &mut Option, destination: &mut Option, message: &mut Option>, destination_xcm_version: Version, , // <- new attritbute ) -> SendResult; ``` ## Future Directions This PR does not fix version discovery over bridge, further investigation will be conducted here: https://github.com/paritytech/polkadot-sdk/issues/2417. ## TODO - [x] `pallet_xcm` mock for tests uses hard-coded XCM version `2` - change to 3 or lastest? - [x] fix `pallet-xcm-bridge-hub-router` - [x] fix HaulBlobExporter with version determination [here](https://github.com/paritytech/polkadot-sdk/blob/2183669d05f9b510f979a0cc3c7847707bacba2e/polkadot/xcm/xcm-builder/src/universal_exports.rs#L465) - [x] add unit-tests to the runtimes - [x] run benchmarks for `ExportMessage` - [x] extend local run scripts about `force_xcm_version(dest, version)` - [ ] when merged, prepare governance calls for Rococo/Westend - [ ] add PRDoc Part of: https://github.com/paritytech/parity-bridges-common/issues/2719 --------- Co-authored-by: command-bot <> --- Cargo.lock | 2 + .../src/messages_xcm_extension.rs | 22 ++ .../xcm-bridge-hub-router/src/benchmarking.rs | 12 +- .../modules/xcm-bridge-hub-router/src/lib.rs | 96 +++++---- .../modules/xcm-bridge-hub-router/src/mock.rs | 20 +- .../modules/xcm-bridge-hub/src/exporter.rs | 3 +- bridges/modules/xcm-bridge-hub/src/lib.rs | 28 ++- bridges/modules/xcm-bridge-hub/src/mock.rs | 8 +- .../assets/asset-hub-rococo/src/lib.rs | 5 +- .../assets/asset-hub-westend/src/lib.rs | 5 +- .../bridges/bridge-hub-rococo/src/lib.rs | 3 +- .../bridges/bridge-hub-westend/src/lib.rs | 3 +- .../emulated/common/src/impls.rs | 55 ++++- .../bridges/bridge-hub-rococo/Cargo.toml | 1 + .../bridges/bridge-hub-rococo/src/lib.rs | 4 +- .../src/tests/asset_transfers.rs | 70 +------ .../bridge-hub-rococo/src/tests/mod.rs | 96 +++++++++ .../bridge-hub-rococo/src/tests/send_xcm.rs | 122 ++++++++++- .../bridges/bridge-hub-westend/Cargo.toml | 1 + .../bridges/bridge-hub-westend/src/lib.rs | 4 +- .../src/tests/asset_transfers.rs | 70 +------ .../bridge-hub-westend/src/tests/mod.rs | 96 +++++++++ .../bridge-hub-westend/src/tests/send_xcm.rs | 122 ++++++++++- .../assets/asset-hub-rococo/src/lib.rs | 22 +- .../weights/pallet_xcm_bridge_hub_router.rs | 32 +-- .../assets/asset-hub-rococo/tests/tests.rs | 9 +- .../assets/asset-hub-westend/src/lib.rs | 20 +- .../weights/pallet_xcm_bridge_hub_router.rs | 46 ++-- .../assets/asset-hub-westend/tests/tests.rs | 12 +- .../src/bridge_to_westend_config.rs | 21 +- .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 17 +- .../xcm/pallet_xcm_benchmarks_generic.rs | 136 ++++++------ .../bridge-hub-rococo/tests/tests.rs | 14 +- .../src/bridge_to_rococo_config.rs | 21 +- .../bridge-hubs/bridge-hub-westend/src/lib.rs | 15 ++ .../xcm/pallet_xcm_benchmarks_generic.rs | 196 +++++++++--------- .../bridge-hub-westend/tests/tests.rs | 15 +- .../bridge-hubs/test-utils/src/test_cases.rs | 60 ++++-- .../parachains/runtimes/test-utils/src/lib.rs | 2 +- cumulus/scripts/bridges_common.sh | 14 +- cumulus/scripts/bridges_rococo_westend.sh | 33 +++ .../generate_hex_encoded_call/index.js | 10 +- polkadot/xcm/pallet-xcm/src/lib.rs | 8 +- polkadot/xcm/pallet-xcm/src/mock.rs | 13 +- polkadot/xcm/pallet-xcm/src/tests/mod.rs | 73 ++++++- polkadot/xcm/src/lib.rs | 20 +- .../src/tests/bridging/local_para_para.rs | 9 +- .../src/tests/bridging/local_relay_relay.rs | 9 +- .../xcm/xcm-builder/src/tests/bridging/mod.rs | 1 + .../tests/bridging/paid_remote_relay_relay.rs | 3 +- .../src/tests/bridging/remote_para_para.rs | 3 +- .../bridging/remote_para_para_via_relay.rs | 3 +- .../src/tests/bridging/remote_relay_relay.rs | 3 +- .../xcm/xcm-builder/src/universal_exports.rs | 68 ++++-- prdoc/pr_2481.prdoc | 13 ++ 55 files changed, 1279 insertions(+), 490 deletions(-) create mode 100644 prdoc/pr_2481.prdoc diff --git a/Cargo.lock b/Cargo.lock index e62e7f900c5..ba8cccca1ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1883,6 +1883,7 @@ dependencies = [ "parachains-common", "parity-scale-codec", "rococo-westend-system-emulated-network", + "sp-runtime", "staging-xcm", "staging-xcm-executor", ] @@ -2048,6 +2049,7 @@ dependencies = [ "parachains-common", "parity-scale-codec", "rococo-westend-system-emulated-network", + "sp-runtime", "staging-xcm", "staging-xcm-executor", ] diff --git a/bridges/bin/runtime-common/src/messages_xcm_extension.rs b/bridges/bin/runtime-common/src/messages_xcm_extension.rs index 0159ede6481..53c0579c4cd 100644 --- a/bridges/bin/runtime-common/src/messages_xcm_extension.rs +++ b/bridges/bin/runtime-common/src/messages_xcm_extension.rs @@ -309,6 +309,28 @@ impl LocalXcmQueueManager { } } +/// Adapter for the implementation of `GetVersion`, which attempts to find the minimal +/// configured XCM version between the destination `dest` and the bridge hub location provided as +/// `Get`. +pub struct XcmVersionOfDestAndRemoteBridge( + sp_std::marker::PhantomData<(Version, RemoteBridge)>, +); +impl> GetVersion + for XcmVersionOfDestAndRemoteBridge +{ + fn get_version_for(dest: &MultiLocation) -> Option { + let dest_version = Version::get_version_for(dest); + let bridge_hub_version = Version::get_version_for(&RemoteBridge::get()); + + match (dest_version, bridge_hub_version) { + (Some(dv), Some(bhv)) => Some(sp_std::cmp::min(dv, bhv)), + (Some(dv), None) => Some(dv), + (None, Some(bhv)) => Some(bhv), + (None, None) => None, + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs b/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs index c4d1e3971e7..922e4bf94ba 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs @@ -21,7 +21,7 @@ use crate::{Bridge, Call}; use bp_xcm_bridge_hub_router::{BridgeState, MINIMAL_DELIVERY_FEE_FACTOR}; -use frame_benchmarking::benchmarks_instance_pallet; +use frame_benchmarking::{benchmarks_instance_pallet, BenchmarkError}; use frame_support::traits::{EnsureOrigin, Get, Hooks, UnfilteredDispatchable}; use sp_runtime::traits::Zero; use xcm::prelude::*; @@ -37,11 +37,11 @@ pub trait Config: crate::Config { /// Returns destination which is valid for this router instance. /// (Needs to pass `T::Bridges`) /// Make sure that `SendXcm` will pass. - fn ensure_bridged_target_destination() -> MultiLocation { - MultiLocation::new( + fn ensure_bridged_target_destination() -> Result { + Ok(MultiLocation::new( Self::UniversalLocation::get().len() as u8, X1(GlobalConsensus(Self::BridgedNetworkId::get().unwrap())), - ) + )) } } @@ -61,7 +61,7 @@ benchmarks_instance_pallet! { delivery_fee_factor: MINIMAL_DELIVERY_FEE_FACTOR + MINIMAL_DELIVERY_FEE_FACTOR, }); - let _ = T::ensure_bridged_target_destination(); + let _ = T::ensure_bridged_target_destination()?; T::make_congested(); }: { crate::Pallet::::on_initialize(Zero::zero()) @@ -81,7 +81,7 @@ benchmarks_instance_pallet! { } send_message { - let dest = T::ensure_bridged_target_destination(); + let dest = T::ensure_bridged_target_destination()?; let xcm = sp_std::vec![].into(); // make local queue congested, because it means additional db write diff --git a/bridges/modules/xcm-bridge-hub-router/src/lib.rs b/bridges/modules/xcm-bridge-hub-router/src/lib.rs index cf51ef82412..229628aedcb 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/lib.rs @@ -89,6 +89,8 @@ pub mod pallet { /// **possible fee**. Allows to externalize better control over allowed **bridged /// networks/locations**. type Bridges: ExporterFor; + /// Checks the XCM version for the destination. + type DestinationVersion: GetVersion; /// Origin of the sibling bridge hub that is allowed to report bridge status. type BridgeHubOrigin: EnsureOrigin; @@ -319,12 +321,13 @@ impl, I: 'static> SendXcm for Pallet { dest: &mut Option, xcm: &mut Option>, ) -> SendResult { - // we won't have an access to `dest` and `xcm` in the `delvier` method, so precompute + // `dest` and `xcm` are required here + let dest_ref = dest.as_ref().ok_or(SendError::MissingArgument)?; + let xcm_ref = xcm.as_ref().ok_or(SendError::MissingArgument)?; + + // we won't have an access to `dest` and `xcm` in the `deliver` method, so precompute // everything required here - let message_size = xcm - .as_ref() - .map(|xcm| xcm.encoded_size() as _) - .ok_or(SendError::MissingArgument)?; + let message_size = xcm_ref.encoded_size() as _; // bridge doesn't support oversized/overweight messages now. So it is better to drop such // messages here than at the bridge hub. Let's check the message size. @@ -332,6 +335,18 @@ impl, I: 'static> SendXcm for Pallet { return Err(SendError::ExceedsMaxMessageSize) } + // We need to ensure that the known `dest`'s XCM version can comprehend the current `xcm` + // program. This may seem like an additional, unnecessary check, but it is not. A similar + // check is probably performed by the `ViaBridgeHubExporter`, which attempts to send a + // versioned message to the sibling bridge hub. However, the local bridge hub may have a + // higher XCM version than the remote `dest`. Once again, it is better to discard such + // messages here than at the bridge hub (e.g., to avoid losing funds). + let destination_version = T::DestinationVersion::get_version_for(dest_ref) + .ok_or(SendError::DestinationUnsupported)?; + let _ = VersionedXcm::from(xcm_ref.clone()) + .into_version(destination_version) + .map_err(|()| SendError::DestinationUnsupported)?; + // just use exporter to validate destination and insert instructions to pay message fee // at the sibling/child bridge hub // @@ -358,6 +373,7 @@ impl, I: 'static> SendXcm for Pallet { #[cfg(test)] mod tests { use super::*; + use frame_support::assert_ok; use mock::*; use frame_support::traits::Hooks; @@ -451,6 +467,19 @@ mod tests { }); } + #[test] + fn destination_unsupported_if_wrap_version_fails() { + run_test(|| { + assert_eq!( + send_xcm::( + UnknownXcmVersionLocation::get(), + vec![ClearOrigin].into(), + ), + Err(SendError::DestinationUnsupported), + ); + }); + } + #[test] fn returns_proper_delivery_price() { run_test(|| { @@ -488,17 +517,14 @@ mod tests { fn sent_message_doesnt_increase_factor_if_xcm_channel_is_uncongested() { run_test(|| { let old_bridge = XcmBridgeHubRouter::bridge(); - assert_eq!( - send_xcm::( - MultiLocation::new( - 2, - X2(GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)) - ), - vec![ClearOrigin].into(), - ) - .map(drop), - Ok(()), - ); + assert_ok!(send_xcm::( + MultiLocation::new( + 2, + X2(GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)) + ), + vec![ClearOrigin].into(), + ) + .map(drop)); assert!(TestToBridgeHubSender::is_message_sent()); assert_eq!(old_bridge, XcmBridgeHubRouter::bridge()); @@ -511,17 +537,14 @@ mod tests { TestWithBridgeHubChannel::make_congested(); let old_bridge = XcmBridgeHubRouter::bridge(); - assert_eq!( - send_xcm::( - MultiLocation::new( - 2, - X2(GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)) - ), - vec![ClearOrigin].into(), - ) - .map(drop), - Ok(()), - ); + assert_ok!(send_xcm::( + MultiLocation::new( + 2, + X2(GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)) + ), + vec![ClearOrigin].into(), + ) + .map(drop)); assert!(TestToBridgeHubSender::is_message_sent()); assert!( @@ -536,17 +559,14 @@ mod tests { Bridge::::put(congested_bridge(MINIMAL_DELIVERY_FEE_FACTOR)); let old_bridge = XcmBridgeHubRouter::bridge(); - assert_eq!( - send_xcm::( - MultiLocation::new( - 2, - X2(GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)) - ), - vec![ClearOrigin].into(), - ) - .map(drop), - Ok(()), - ); + assert_ok!(send_xcm::( + MultiLocation::new( + 2, + X2(GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)) + ), + vec![ClearOrigin].into(), + ) + .map(drop)); assert!(TestToBridgeHubSender::is_message_sent()); assert!( diff --git a/bridges/modules/xcm-bridge-hub-router/src/mock.rs b/bridges/modules/xcm-bridge-hub-router/src/mock.rs index 2d173ebc045..9079f4b9c4c 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/mock.rs @@ -19,7 +19,10 @@ use crate as pallet_xcm_bridge_hub_router; use bp_xcm_bridge_hub_router::XcmChannelStatusProvider; -use frame_support::{construct_runtime, derive_impl, parameter_types}; +use frame_support::{ + construct_runtime, derive_impl, parameter_types, + traits::{Contains, Equals}, +}; use frame_system::EnsureRoot; use sp_runtime::{traits::ConstU128, BuildStorage}; use xcm::prelude::*; @@ -58,6 +61,7 @@ parameter_types! { Some((BridgeFeeAsset::get(), BASE_FEE).into()) ) ]; + pub UnknownXcmVersionLocation: MultiLocation = MultiLocation::new(2, X2(GlobalConsensus(BridgedNetworkId::get()), Parachain(9999))); } #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] @@ -71,6 +75,8 @@ impl pallet_xcm_bridge_hub_router::Config<()> for TestRuntime { type UniversalLocation = UniversalLocation; type BridgedNetworkId = BridgedNetworkId; type Bridges = NetworkExportTable; + type DestinationVersion = + LatestOrNoneForLocationVersionChecker>; type BridgeHubOrigin = EnsureRoot; type ToBridgeHubSender = TestToBridgeHubSender; @@ -80,6 +86,18 @@ impl pallet_xcm_bridge_hub_router::Config<()> for TestRuntime { type FeeAsset = BridgeFeeAsset; } +pub struct LatestOrNoneForLocationVersionChecker(sp_std::marker::PhantomData); +impl> GetVersion + for LatestOrNoneForLocationVersionChecker +{ + fn get_version_for(dest: &MultiLocation) -> Option { + if Location::contains(dest) { + return None + } + Some(XCM_VERSION) + } +} + pub struct TestToBridgeHubSender; impl TestToBridgeHubSender { diff --git a/bridges/modules/xcm-bridge-hub/src/exporter.rs b/bridges/modules/xcm-bridge-hub/src/exporter.rs index 445551d6934..5318b222c54 100644 --- a/bridges/modules/xcm-bridge-hub/src/exporter.rs +++ b/bridges/modules/xcm-bridge-hub/src/exporter.rs @@ -33,7 +33,8 @@ use xcm_executor::traits::ExportXcm; /// An easy way to access `HaulBlobExporter`. pub type PalletAsHaulBlobExporter = HaulBlobExporter< DummyHaulBlob, - >::BridgedNetworkId, + >::BridgedNetwork, + >::DestinationVersion, >::MessageExportPrice, >; /// An easy way to access associated messages pallet. diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index 14439a4d8ff..44f6903b018 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -37,6 +37,7 @@ pub mod pallet { use super::*; use bridge_runtime_common::messages_xcm_extension::SenderAndLane; use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::BlockNumberFor; #[pallet::config] #[pallet::disable_frame_system_supertrait_check] @@ -48,15 +49,17 @@ pub mod pallet { // TODO: https://github.com/paritytech/parity-bridges-common/issues/1666 remove `ChainId` and // replace it with the `NetworkId` - then we'll be able to use // `T as pallet_bridge_messages::Config::BridgedChain::NetworkId` - /// Bridged network id. + /// Bridged network as relative location of bridged `GlobalConsensus`. #[pallet::constant] - type BridgedNetworkId: Get; + type BridgedNetwork: Get; /// Associated messages pallet instance that bridges us with the /// `BridgedNetworkId` consensus. type BridgeMessagesPalletInstance: 'static; /// Price of single message export to the bridged consensus (`Self::BridgedNetworkId`). type MessageExportPrice: Get; + /// Checks the XCM version for the destination. + type DestinationVersion: GetVersion; /// Get point-to-point links with bridged consensus (`Self::BridgedNetworkId`). /// (this will be replaced with dynamic on-chain bridges - `Bridges V2`) @@ -69,6 +72,17 @@ pub mod pallet { #[pallet::pallet] pub struct Pallet(PhantomData<(T, I)>); + #[pallet::hooks] + impl, I: 'static> Hooks> for Pallet { + fn integrity_test() { + assert!( + Self::bridged_network_id().is_some(), + "Configured `T::BridgedNetwork`: {:?} does not contain `GlobalConsensus` junction with `NetworkId`", + T::BridgedNetwork::get() + ) + } + } + impl, I: 'static> Pallet { /// Returns dedicated/configured lane identifier. pub(crate) fn lane_for( @@ -83,7 +97,7 @@ pub mod pallet { .find_map(|(lane_source, (lane_dest_network, lane_dest))| { if lane_source.location == source && &lane_dest_network == dest.0 && - &T::BridgedNetworkId::get() == dest.0 && + Self::bridged_network_id().as_ref() == Some(dest.0) && &lane_dest == dest.1 { Some(lane_source) @@ -92,5 +106,13 @@ pub mod pallet { } }) } + + /// Returns some `NetworkId` if contains `GlobalConsensus` junction. + fn bridged_network_id() -> Option { + match T::BridgedNetwork::get().take_first_interior() { + Some(GlobalConsensus(network)) => Some(network), + _ => None, + } + } } } diff --git a/bridges/modules/xcm-bridge-hub/src/mock.rs b/bridges/modules/xcm-bridge-hub/src/mock.rs index 7766aac1fb7..8edd4b1f7aa 100644 --- a/bridges/modules/xcm-bridge-hub/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub/src/mock.rs @@ -170,6 +170,10 @@ impl pallet_bridge_messages::WeightInfoExt for TestMessagesWeights { parameter_types! { pub const RelayNetwork: NetworkId = NetworkId::Kusama; pub const BridgedRelayNetwork: NetworkId = NetworkId::Polkadot; + pub const BridgedRelayNetworkLocation: MultiLocation = MultiLocation { + parents: 1, + interior: X1(GlobalConsensus(BridgedRelayNetwork::get())) + }; pub const NonBridgedRelayNetwork: NetworkId = NetworkId::Rococo; pub const BridgeReserve: Balance = 100_000; pub UniversalLocation: InteriorMultiLocation = X2( @@ -181,10 +185,12 @@ parameter_types! { impl pallet_xcm_bridge_hub::Config for TestRuntime { type UniversalLocation = UniversalLocation; - type BridgedNetworkId = BridgedRelayNetwork; + type BridgedNetwork = BridgedRelayNetworkLocation; type BridgeMessagesPalletInstance = (); type MessageExportPrice = (); + type DestinationVersion = AlwaysLatest; + type Lanes = TestLanes; type LanesSupport = TestXcmBlobHauler; } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs index 877edceae32..05454a2e573 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/lib.rs @@ -21,8 +21,8 @@ use frame_support::traits::OnInitialize; // Cumulus use emulated_integration_tests_common::{ impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - impl_assets_helpers_for_parachain, impl_foreign_assets_helpers_for_parachain, impls::Parachain, - xcm_emulator::decl_test_parachains, + impl_assets_helpers_for_parachain, impl_foreign_assets_helpers_for_parachain, + impl_xcm_helpers_for_parachain, impls::Parachain, xcm_emulator::decl_test_parachains, }; use rococo_emulated_chain::Rococo; @@ -55,3 +55,4 @@ impl_accounts_helpers_for_parachain!(AssetHubRococo); impl_assert_events_helpers_for_parachain!(AssetHubRococo); impl_assets_helpers_for_parachain!(AssetHubRococo, Rococo); impl_foreign_assets_helpers_for_parachain!(AssetHubRococo, Rococo); +impl_xcm_helpers_for_parachain!(AssetHubRococo); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs index 1c017c63c6f..56382fad564 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/src/lib.rs @@ -21,8 +21,8 @@ use frame_support::traits::OnInitialize; // Cumulus use emulated_integration_tests_common::{ impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - impl_assets_helpers_for_parachain, impl_foreign_assets_helpers_for_parachain, impls::Parachain, - xcm_emulator::decl_test_parachains, + impl_assets_helpers_for_parachain, impl_foreign_assets_helpers_for_parachain, + impl_xcm_helpers_for_parachain, impls::Parachain, xcm_emulator::decl_test_parachains, }; use westend_emulated_chain::Westend; @@ -55,3 +55,4 @@ impl_accounts_helpers_for_parachain!(AssetHubWestend); impl_assert_events_helpers_for_parachain!(AssetHubWestend); impl_assets_helpers_for_parachain!(AssetHubWestend, Westend); impl_foreign_assets_helpers_for_parachain!(AssetHubWestend, Westend); +impl_xcm_helpers_for_parachain!(AssetHubWestend); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs index 8e5b29e6561..8162823dfce 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs @@ -21,7 +21,7 @@ use frame_support::traits::OnInitialize; // Cumulus use emulated_integration_tests_common::{ impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - impls::Parachain, xcm_emulator::decl_test_parachains, + impl_xcm_helpers_for_parachain, impls::Parachain, xcm_emulator::decl_test_parachains, }; // BridgeHubRococo Parachain declaration @@ -47,3 +47,4 @@ decl_test_parachains! { // BridgeHubRococo implementation impl_accounts_helpers_for_parachain!(BridgeHubRococo); impl_assert_events_helpers_for_parachain!(BridgeHubRococo); +impl_xcm_helpers_for_parachain!(BridgeHubRococo); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs index a774f31b0fb..c996b8045e7 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/src/lib.rs @@ -21,7 +21,7 @@ use frame_support::traits::OnInitialize; // Cumulus use emulated_integration_tests_common::{ impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, - impls::Parachain, xcm_emulator::decl_test_parachains, + impl_xcm_helpers_for_parachain, impls::Parachain, xcm_emulator::decl_test_parachains, }; // BridgeHubWestend Parachain declaration @@ -47,3 +47,4 @@ decl_test_parachains! { // BridgeHubWestend implementation impl_accounts_helpers_for_parachain!(BridgeHubWestend); impl_assert_events_helpers_for_parachain!(BridgeHubWestend); +impl_xcm_helpers_for_parachain!(BridgeHubWestend); diff --git a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs index 768784ac067..42b5847d17c 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs @@ -38,7 +38,7 @@ pub use polkadot_runtime_parachains::{ inclusion::{AggregateMessageOrigin, UmpQueueId}, }; pub use xcm::{ - prelude::{MultiLocation, OriginKind, Outcome, VersionedXcm}, + prelude::{MultiLocation, OriginKind, Outcome, VersionedXcm, XcmVersion}, v3::Error, DoubleEncoded, }; @@ -173,10 +173,14 @@ macro_rules! impl_accounts_helpers_for_relay_chain { pub fn fund_accounts(accounts: Vec<($crate::impls::AccountId, $crate::impls::Balance)>) { ::execute_with(|| { for account in accounts { + let who = account.0; + let actual = ]>::Balances::free_balance(&who); + let actual = actual.saturating_add(]>::Balances::reserved_balance(&who)); + $crate::impls::assert_ok!(]>::Balances::force_set_balance( ::RuntimeOrigin::root(), - account.0.into(), - account.1, + who.into(), + actual.saturating_add(account.1), )); } }); @@ -386,15 +390,26 @@ macro_rules! impl_accounts_helpers_for_parachain { pub fn fund_accounts(accounts: Vec<($crate::impls::AccountId, $crate::impls::Balance)>) { ::execute_with(|| { for account in accounts { + let who = account.0; + let actual = ]>::Balances::free_balance(&who); + let actual = actual.saturating_add(]>::Balances::reserved_balance(&who)); + $crate::impls::assert_ok!(]>::Balances::force_set_balance( ::RuntimeOrigin::root(), - account.0.into(), - account.1, + who.into(), + actual.saturating_add(account.1), )); } }); } + /// Fund a sovereign account of sibling para. + pub fn fund_para_sovereign(sibling_para_id: $crate::impls::ParaId, balance: $crate::impls::Balance) { + let sibling_location = Self::sibling_location_of(sibling_para_id); + let sovereign_account = Self::sovereign_account_id_of(sibling_location); + Self::fund_accounts(vec![(sovereign_account.into(), balance)]) + } + /// Return local sovereign account of `para_id` on other `network_id` pub fn sovereign_account_of_parachain_on_other_global_consensus( network_id: $crate::impls::NetworkId, @@ -790,3 +805,33 @@ macro_rules! impl_foreign_assets_helpers_for_parachain { } }; } + +#[macro_export] +macro_rules! impl_xcm_helpers_for_parachain { + ( $chain:ident ) => { + $crate::impls::paste::paste! { + impl $chain { + /// Set XCM version for destination. + pub fn force_xcm_version(dest: $crate::impls::MultiLocation, version: $crate::impls::XcmVersion) { + ::execute_with(|| { + $crate::impls::assert_ok!(]>::PolkadotXcm::force_xcm_version( + ::RuntimeOrigin::root(), + $crate::impls::bx!(dest), + version, + )); + }); + } + + /// Set default/safe XCM version for runtime. + pub fn force_default_xcm_version(version: Option<$crate::impls::XcmVersion>) { + ::execute_with(|| { + $crate::impls::assert_ok!(]>::PolkadotXcm::force_default_xcm_version( + ::RuntimeOrigin::root(), + version, + )); + }); + } + } + } + } +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml index 826b55507ed..4f33505f9a7 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml @@ -15,6 +15,7 @@ frame-support = { path = "../../../../../../../substrate/frame/support", default pallet-assets = { path = "../../../../../../../substrate/frame/assets", default-features = false } pallet-balances = { path = "../../../../../../../substrate/frame/balances", default-features = false } pallet-message-queue = { path = "../../../../../../../substrate/frame/message-queue" } +sp-runtime = { path = "../../../../../../../substrate/primitives/runtime", default-features = false } # Polkadot xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false } diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs index 53665437887..4ae2c6cc902 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs @@ -14,10 +14,12 @@ // limitations under the License. // Substrate -pub use frame_support::assert_ok; +pub use frame_support::{assert_err, assert_ok, pallet_prelude::DispatchResult}; +pub use sp_runtime::DispatchError; // Polkadot pub use xcm::{ + latest::ParentThen, prelude::{AccountId32 as AccountId32Junction, *}, v3::{ Error, diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs index c55613f2826..5a2111a9be9 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/asset_transfers.rs @@ -13,70 +13,22 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::*; +use crate::tests::*; fn send_asset_from_asset_hub_rococo_to_asset_hub_westend(id: MultiLocation, amount: u128) { - let signed_origin = - ::RuntimeOrigin::signed(AssetHubRococoSender::get().into()); - let asset_hub_westend_para_id = AssetHubWestend::para_id().into(); - let destination = MultiLocation { - parents: 2, - interior: X2(GlobalConsensus(NetworkId::Westend), Parachain(asset_hub_westend_para_id)), - }; - let beneficiary_id = AssetHubWestendReceiver::get(); - let beneficiary: MultiLocation = - AccountId32Junction { network: None, id: beneficiary_id.into() }.into(); - let assets: MultiAssets = (id, amount).into(); - let fee_asset_item = 0; + let destination = asset_hub_westend_location(); // fund the AHR's SA on BHR for paying bridge transport fees - let ahr_as_seen_by_bhr = BridgeHubRococo::sibling_location_of(AssetHubRococo::para_id()); - let sov_ahr_on_bhr = BridgeHubRococo::sovereign_account_id_of(ahr_as_seen_by_bhr); - BridgeHubRococo::fund_accounts(vec![(sov_ahr_on_bhr.into(), 10_000_000_000_000u128)]); - - AssetHubRococo::execute_with(|| { - assert_ok!( - ::PolkadotXcm::limited_reserve_transfer_assets( - signed_origin, - bx!(destination.into()), - bx!(beneficiary.into()), - bx!(assets.into()), - fee_asset_item, - WeightLimit::Unlimited, - ) - ); - }); + BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id(), 10_000_000_000_000u128); - BridgeHubRococo::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - BridgeHubRococo, - vec![ - // pay for bridge fees - RuntimeEvent::Balances(pallet_balances::Event::Withdraw { .. }) => {}, - // message exported - RuntimeEvent::BridgeWestendMessages( - pallet_bridge_messages::Event::MessageAccepted { .. } - ) => {}, - // message processed successfully - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); - }); - BridgeHubWestend::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - BridgeHubWestend, - vec![ - // message dispatched successfully - RuntimeEvent::XcmpQueue( - cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. } - ) => {}, - ] - ); - }); + // set XCM versions + AssetHubRococo::force_xcm_version(destination, XCM_VERSION); + BridgeHubRococo::force_xcm_version(bridge_hub_westend_location(), XCM_VERSION); + + // send message over bridge + assert_ok!(send_asset_from_asset_hub_rococo(destination, (id, amount))); + assert_bridge_hub_rococo_message_accepted(true); + assert_bridge_hub_westend_message_received(); } #[test] diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs index 4e2ef1434fd..d102dd2e5d6 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/mod.rs @@ -13,6 +13,102 @@ // See the License for the specific language governing permissions and // limitations under the License. +use crate::*; + mod asset_transfers; mod send_xcm; mod teleport; + +pub(crate) fn asset_hub_westend_location() -> MultiLocation { + MultiLocation { + parents: 2, + interior: X2( + GlobalConsensus(NetworkId::Westend), + Parachain(AssetHubWestend::para_id().into()), + ), + } +} + +pub(crate) fn bridge_hub_westend_location() -> MultiLocation { + MultiLocation { + parents: 2, + interior: X2( + GlobalConsensus(NetworkId::Westend), + Parachain(BridgeHubWestend::para_id().into()), + ), + } +} + +pub(crate) fn send_asset_from_asset_hub_rococo( + destination: MultiLocation, + (id, amount): (MultiLocation, u128), +) -> DispatchResult { + let signed_origin = + ::RuntimeOrigin::signed(AssetHubRococoSender::get().into()); + + let beneficiary: MultiLocation = + AccountId32Junction { network: None, id: AssetHubWestendReceiver::get().into() }.into(); + + let assets: MultiAssets = (id, amount).into(); + let fee_asset_item = 0; + + AssetHubRococo::execute_with(|| { + ::PolkadotXcm::limited_reserve_transfer_assets( + signed_origin, + bx!(destination.into()), + bx!(beneficiary.into()), + bx!(assets.into()), + fee_asset_item, + WeightLimit::Unlimited, + ) + }) +} + +pub(crate) fn assert_bridge_hub_rococo_message_accepted(expected_processed: bool) { + BridgeHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + if expected_processed { + assert_expected_events!( + BridgeHubRococo, + vec![ + // pay for bridge fees + RuntimeEvent::Balances(pallet_balances::Event::Withdraw { .. }) => {}, + // message exported + RuntimeEvent::BridgeWestendMessages( + pallet_bridge_messages::Event::MessageAccepted { .. } + ) => {}, + // message processed successfully + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); + } else { + assert_expected_events!( + BridgeHubRococo, + vec![ + RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { + success: false, + .. + }) => {}, + ] + ); + } + }); +} + +pub(crate) fn assert_bridge_hub_westend_message_received() { + BridgeHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + BridgeHubWestend, + vec![ + // message sent to destination + RuntimeEvent::XcmpQueue( + cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. } + ) => {}, + ] + ); + }) +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs index b31a17034b9..a3a7d96a14a 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/send_xcm.rs @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::*; +use crate::tests::*; #[test] fn send_xcm_from_rococo_relay_to_westend_asset_hub_should_fail_on_not_applicable() { @@ -55,17 +55,123 @@ fn send_xcm_from_rococo_relay_to_westend_asset_hub_should_fail_on_not_applicable }); // Receive XCM message in Bridge Hub source Parachain, it should fail, because we don't have // opened bridge/lane. - BridgeHubRococo::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; + assert_bridge_hub_rococo_message_accepted(false); +} + +#[test] +fn send_xcm_through_opened_lane_with_different_xcm_version_on_hops_works() { + // Initially set only default version on all runtimes + AssetHubRococo::force_default_xcm_version(Some(xcm::v2::prelude::XCM_VERSION)); + BridgeHubRococo::force_default_xcm_version(Some(xcm::v2::prelude::XCM_VERSION)); + BridgeHubWestend::force_default_xcm_version(Some(xcm::v2::prelude::XCM_VERSION)); + AssetHubWestend::force_default_xcm_version(Some(xcm::v2::prelude::XCM_VERSION)); + + // prepare data + let destination = asset_hub_westend_location(); + let native_token = MultiLocation::parent(); + let amount = ASSET_HUB_ROCOCO_ED * 1_000; + + // fund the AHR's SA on BHR for paying bridge transport fees + BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id(), 10_000_000_000_000u128); + // fund sender + AssetHubRococo::fund_accounts(vec![(AssetHubRococoSender::get().into(), amount * 10)]); + + // send XCM from AssetHubRococo - fails - destination version not known + assert_err!( + send_asset_from_asset_hub_rococo(destination, (native_token, amount)), + DispatchError::Module(sp_runtime::ModuleError { + index: 31, + error: [1, 0, 0, 0], + message: Some("SendFailure") + }) + ); + + // set destination version + AssetHubRococo::force_xcm_version(destination, xcm::v3::prelude::XCM_VERSION); + + // TODO: remove this block, when removing `xcm:v2` + { + // send XCM from AssetHubRococo - fails - AssetHubRococo is set to the default/safe `2` + // version, which does not have the `ExportMessage` instruction. If the default `2` is + // changed to `3`, then this assert can go away" + assert_err!( + send_asset_from_asset_hub_rococo(destination, (native_token, amount)), + DispatchError::Module(sp_runtime::ModuleError { + index: 31, + error: [1, 0, 0, 0], + message: Some("SendFailure") + }) + ); + // set exact version for BridgeHubWestend to `2` without `ExportMessage` instruction + AssetHubRococo::force_xcm_version( + ParentThen(Parachain(BridgeHubRococo::para_id().into()).into()).into(), + xcm::v2::prelude::XCM_VERSION, + ); + // send XCM from AssetHubRococo - fails - `ExportMessage` is not in `2` + assert_err!( + send_asset_from_asset_hub_rococo(destination, (native_token, amount)), + DispatchError::Module(sp_runtime::ModuleError { + index: 31, + error: [1, 0, 0, 0], + message: Some("SendFailure") + }) + ); + } + + // set version with `ExportMessage` for BridgeHubRococo + AssetHubRococo::force_xcm_version( + ParentThen(Parachain(BridgeHubRococo::para_id().into()).into()).into(), + xcm::v3::prelude::XCM_VERSION, + ); + // send XCM from AssetHubRococo - ok + assert_ok!(send_asset_from_asset_hub_rococo(destination, (native_token, amount))); + + // `ExportMessage` on local BridgeHub - fails - remote BridgeHub version not known + assert_bridge_hub_rococo_message_accepted(false); + + // set version for remote BridgeHub on BridgeHubRococo + BridgeHubRococo::force_xcm_version( + bridge_hub_westend_location(), + xcm::v3::prelude::XCM_VERSION, + ); + // set version for AssetHubWestend on BridgeHubWestend + BridgeHubWestend::force_xcm_version( + ParentThen(Parachain(AssetHubWestend::para_id().into()).into()).into(), + xcm::v3::prelude::XCM_VERSION, + ); + + // send XCM from AssetHubRococo - ok + assert_ok!(send_asset_from_asset_hub_rococo(destination, (native_token, amount))); + assert_bridge_hub_rococo_message_accepted(true); + assert_bridge_hub_westend_message_received(); + // message delivered and processed at destination + AssetHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; assert_expected_events!( - BridgeHubRococo, + AssetHubWestend, vec![ - RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { - success: false, - .. - }) => {}, + // message processed with failure, but for this scenario it is ok, important is that was delivered + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: false, .. } + ) => {}, ] ); }); + + // TODO: remove this block, when removing `xcm:v2` + { + // set `2` version for remote BridgeHub on BridgeHubRococo, which does not have + // `UniversalOrigin` and `DescendOrigin` + BridgeHubRococo::force_xcm_version( + bridge_hub_westend_location(), + xcm::v2::prelude::XCM_VERSION, + ); + + // send XCM from AssetHubRococo - ok + assert_ok!(send_asset_from_asset_hub_rococo(destination, (native_token, amount))); + // message is not accepted on the local BridgeHub (`DestinationUnsupported`) because we + // cannot add `UniversalOrigin` and `DescendOrigin` + assert_bridge_hub_rococo_message_accepted(false); + } } diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml index cb53d7fc0e1..00cf54b6541 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml @@ -15,6 +15,7 @@ frame-support = { path = "../../../../../../../substrate/frame/support", default pallet-assets = { path = "../../../../../../../substrate/frame/assets", default-features = false } pallet-balances = { path = "../../../../../../../substrate/frame/balances", default-features = false } pallet-message-queue = { path = "../../../../../../../substrate/frame/message-queue" } +sp-runtime = { path = "../../../../../../../substrate/primitives/runtime", default-features = false } # Polkadot xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false } diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs index 04746aa8670..90a11d38f77 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/lib.rs @@ -14,10 +14,12 @@ // limitations under the License. // Substrate -pub use frame_support::assert_ok; +pub use frame_support::{assert_err, assert_ok, pallet_prelude::DispatchResult}; +pub use sp_runtime::DispatchError; // Polkadot pub use xcm::{ + latest::ParentThen, prelude::{AccountId32 as AccountId32Junction, *}, v3::{ Error, diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs index f90514f80c3..21f4b4ee235 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/asset_transfers.rs @@ -12,70 +12,22 @@ // 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::tests::*; fn send_asset_from_asset_hub_westend_to_asset_hub_rococo(id: MultiLocation, amount: u128) { - let signed_origin = - ::RuntimeOrigin::signed(AssetHubWestendSender::get().into()); - let asset_hub_rococo_para_id = AssetHubRococo::para_id().into(); - let destination = MultiLocation { - parents: 2, - interior: X2(GlobalConsensus(NetworkId::Rococo), Parachain(asset_hub_rococo_para_id)), - }; - let beneficiary_id = AssetHubRococoReceiver::get(); - let beneficiary: MultiLocation = - AccountId32Junction { network: None, id: beneficiary_id.into() }.into(); - let assets: MultiAssets = (id, amount).into(); - let fee_asset_item = 0; + let destination = asset_hub_rococo_location(); // fund the AHW's SA on BHW for paying bridge transport fees - let ahw_as_seen_by_bhw = BridgeHubWestend::sibling_location_of(AssetHubWestend::para_id()); - let sov_ahw_on_bhw = BridgeHubWestend::sovereign_account_id_of(ahw_as_seen_by_bhw); - BridgeHubWestend::fund_accounts(vec![(sov_ahw_on_bhw.into(), 10_000_000_000_000u128)]); - - AssetHubWestend::execute_with(|| { - assert_ok!( - ::PolkadotXcm::limited_reserve_transfer_assets( - signed_origin, - bx!(destination.into()), - bx!(beneficiary.into()), - bx!(assets.into()), - fee_asset_item, - WeightLimit::Unlimited, - ) - ); - }); + BridgeHubWestend::fund_para_sovereign(AssetHubWestend::para_id(), 10_000_000_000_000u128); - BridgeHubWestend::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - BridgeHubWestend, - vec![ - // pay for bridge fees - RuntimeEvent::Balances(pallet_balances::Event::Withdraw { .. }) => {}, - // message exported - RuntimeEvent::BridgeRococoMessages( - pallet_bridge_messages::Event::MessageAccepted { .. } - ) => {}, - // message processed successfully - RuntimeEvent::MessageQueue( - pallet_message_queue::Event::Processed { success: true, .. } - ) => {}, - ] - ); - }); - BridgeHubRococo::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - assert_expected_events!( - BridgeHubRococo, - vec![ - // message dispatched successfully - RuntimeEvent::XcmpQueue( - cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. } - ) => {}, - ] - ); - }); + // set XCM versions + AssetHubWestend::force_xcm_version(destination, XCM_VERSION); + BridgeHubWestend::force_xcm_version(bridge_hub_rococo_location(), XCM_VERSION); + + // send message over bridge + assert_ok!(send_asset_from_asset_hub_westend(destination, (id, amount))); + assert_bridge_hub_westend_message_accepted(true); + assert_bridge_hub_rococo_message_received(); } #[test] diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs index 4e2ef1434fd..ec2e68fc889 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/mod.rs @@ -13,6 +13,102 @@ // See the License for the specific language governing permissions and // limitations under the License. +use crate::*; + mod asset_transfers; mod send_xcm; mod teleport; + +pub(crate) fn asset_hub_rococo_location() -> MultiLocation { + MultiLocation { + parents: 2, + interior: X2( + GlobalConsensus(NetworkId::Rococo), + Parachain(AssetHubRococo::para_id().into()), + ), + } +} + +pub(crate) fn bridge_hub_rococo_location() -> MultiLocation { + MultiLocation { + parents: 2, + interior: X2( + GlobalConsensus(NetworkId::Rococo), + Parachain(BridgeHubRococo::para_id().into()), + ), + } +} + +pub(crate) fn send_asset_from_asset_hub_westend( + destination: MultiLocation, + (id, amount): (MultiLocation, u128), +) -> DispatchResult { + let signed_origin = + ::RuntimeOrigin::signed(AssetHubWestendSender::get().into()); + + let beneficiary: MultiLocation = + AccountId32Junction { network: None, id: AssetHubRococoReceiver::get().into() }.into(); + + let assets: MultiAssets = (id, amount).into(); + let fee_asset_item = 0; + + AssetHubWestend::execute_with(|| { + ::PolkadotXcm::limited_reserve_transfer_assets( + signed_origin, + bx!(destination.into()), + bx!(beneficiary.into()), + bx!(assets.into()), + fee_asset_item, + WeightLimit::Unlimited, + ) + }) +} + +pub(crate) fn assert_bridge_hub_westend_message_accepted(expected_processed: bool) { + BridgeHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + if expected_processed { + assert_expected_events!( + BridgeHubWestend, + vec![ + // pay for bridge fees + RuntimeEvent::Balances(pallet_balances::Event::Withdraw { .. }) => {}, + // message exported + RuntimeEvent::BridgeRococoMessages( + pallet_bridge_messages::Event::MessageAccepted { .. } + ) => {}, + // message processed successfully + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); + } else { + assert_expected_events!( + BridgeHubWestend, + vec![ + RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { + success: false, + .. + }) => {}, + ] + ); + } + }); +} + +pub(crate) fn assert_bridge_hub_rococo_message_received() { + BridgeHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + assert_expected_events!( + BridgeHubRococo, + vec![ + // message sent to destination + RuntimeEvent::XcmpQueue( + cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. } + ) => {}, + ] + ); + }) +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs index f5c2ac3677f..0773cbb0599 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::*; +use crate::tests::*; #[test] fn send_xcm_from_westend_relay_to_rococo_asset_hub_should_fail_on_not_applicable() { @@ -55,17 +55,123 @@ fn send_xcm_from_westend_relay_to_rococo_asset_hub_should_fail_on_not_applicable }); // Receive XCM message in Bridge Hub source Parachain, it should fail, because we don't have // opened bridge/lane. - BridgeHubWestend::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; + assert_bridge_hub_westend_message_accepted(false); +} + +#[test] +fn send_xcm_through_opened_lane_with_different_xcm_version_on_hops_works() { + // Initially set only default version on all runtimes + AssetHubRococo::force_default_xcm_version(Some(xcm::v2::prelude::XCM_VERSION)); + BridgeHubRococo::force_default_xcm_version(Some(xcm::v2::prelude::XCM_VERSION)); + BridgeHubWestend::force_default_xcm_version(Some(xcm::v2::prelude::XCM_VERSION)); + AssetHubWestend::force_default_xcm_version(Some(xcm::v2::prelude::XCM_VERSION)); + + // prepare data + let destination = asset_hub_rococo_location(); + let native_token = MultiLocation::parent(); + let amount = ASSET_HUB_WESTEND_ED * 1_000; + + // fund the AHR's SA on BHR for paying bridge transport fees + BridgeHubWestend::fund_para_sovereign(AssetHubWestend::para_id(), 10_000_000_000_000u128); + // fund sender + AssetHubWestend::fund_accounts(vec![(AssetHubWestendSender::get().into(), amount * 10)]); + + // send XCM from AssetHubWestend - fails - destination version not known + assert_err!( + send_asset_from_asset_hub_westend(destination, (native_token, amount)), + DispatchError::Module(sp_runtime::ModuleError { + index: 31, + error: [1, 0, 0, 0], + message: Some("SendFailure") + }) + ); + + // set destination version + AssetHubWestend::force_xcm_version(destination, xcm::v3::prelude::XCM_VERSION); + + // TODO: remove this block, when removing `xcm:v2` + { + // send XCM from AssetHubRococo - fails - AssetHubRococo is set to the default/safe `2` + // version, which does not have the `ExportMessage` instruction. If the default `2` is + // changed to `3`, then this assert can go away" + assert_err!( + send_asset_from_asset_hub_westend(destination, (native_token, amount)), + DispatchError::Module(sp_runtime::ModuleError { + index: 31, + error: [1, 0, 0, 0], + message: Some("SendFailure") + }) + ); + // set exact version for BridgeHubWestend to `2` without `ExportMessage` instruction + AssetHubWestend::force_xcm_version( + ParentThen(Parachain(BridgeHubWestend::para_id().into()).into()).into(), + xcm::v2::prelude::XCM_VERSION, + ); + // send XCM from AssetHubWestend - fails - `ExportMessage` is not in `2` + assert_err!( + send_asset_from_asset_hub_westend(destination, (native_token, amount)), + DispatchError::Module(sp_runtime::ModuleError { + index: 31, + error: [1, 0, 0, 0], + message: Some("SendFailure") + }) + ); + } + + // set version with `ExportMessage` for BridgeHubWestend + AssetHubWestend::force_xcm_version( + ParentThen(Parachain(BridgeHubWestend::para_id().into()).into()).into(), + xcm::v3::prelude::XCM_VERSION, + ); + // send XCM from AssetHubWestend - ok + assert_ok!(send_asset_from_asset_hub_westend(destination, (native_token, amount))); + + // `ExportMessage` on local BridgeHub - fails - remote BridgeHub version not known + assert_bridge_hub_westend_message_accepted(false); + + // set version for remote BridgeHub on BridgeHubWestend + BridgeHubWestend::force_xcm_version( + bridge_hub_rococo_location(), + xcm::v3::prelude::XCM_VERSION, + ); + // set version for AssetHubRococo on BridgeHubRococo + BridgeHubRococo::force_xcm_version( + ParentThen(Parachain(AssetHubRococo::para_id().into()).into()).into(), + xcm::v3::prelude::XCM_VERSION, + ); + + // send XCM from AssetHubWestend - ok + assert_ok!(send_asset_from_asset_hub_westend(destination, (native_token, amount))); + assert_bridge_hub_westend_message_accepted(true); + assert_bridge_hub_rococo_message_received(); + // message delivered and processed at destination + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; assert_expected_events!( - BridgeHubWestend, + AssetHubRococo, vec![ - RuntimeEvent::MessageQueue(pallet_message_queue::Event::Processed { - success: false, - .. - }) => {}, + // message processed with failure, but for this scenario it is ok, important is that was delivered + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: false, .. } + ) => {}, ] ); }); + + // TODO: remove this block, when removing `xcm:v2` + { + // set `2` version for remote BridgeHub on BridgeHubRococo, which does not have + // `UniversalOrigin` and `DescendOrigin` + BridgeHubWestend::force_xcm_version( + bridge_hub_rococo_location(), + xcm::v2::prelude::XCM_VERSION, + ); + + // send XCM from AssetHubWestend - ok + assert_ok!(send_asset_from_asset_hub_westend(destination, (native_token, amount))); + // message is not accepted on the local BridgeHub (`DestinationUnsupported`) because we + // cannot add `UniversalOrigin` and `DescendOrigin` + assert_bridge_hub_westend_message_accepted(false); + } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index a4a42aa9e88..0374a99f234 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -846,6 +846,7 @@ impl pallet_xcm_bridge_hub_router::Config for Runtim type UniversalLocation = xcm_config::UniversalLocation; type BridgedNetworkId = xcm_config::bridging::to_westend::WestendNetwork; type Bridges = xcm_config::bridging::NetworkExportTable; + type DestinationVersion = PolkadotXcm; #[cfg(not(feature = "runtime-benchmarks"))] type BridgeHubOrigin = EnsureXcm>; @@ -1416,11 +1417,26 @@ impl_runtime_apis! { xcm_config::bridging::SiblingBridgeHubParaId::get().into() ); } - fn ensure_bridged_target_destination() -> MultiLocation { + fn ensure_bridged_target_destination() -> Result { ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests( xcm_config::bridging::SiblingBridgeHubParaId::get().into() ); - xcm_config::bridging::to_westend::AssetHubWestend::get() + let bridged_asset_hub = xcm_config::bridging::to_westend::AssetHubWestend::get(); + let _ = PolkadotXcm::force_xcm_version( + RuntimeOrigin::root(), + Box::new(bridged_asset_hub), + XCM_VERSION, + ).map_err(|e| { + log::error!( + "Failed to dispatch `force_xcm_version({:?}, {:?}, {:?})`, error: {:?}", + RuntimeOrigin::root(), + bridged_asset_hub, + XCM_VERSION, + e + ); + BenchmarkError::Stop("XcmVersion was not stored!") + })?; + Ok(bridged_asset_hub) } } @@ -1439,7 +1455,7 @@ impl_runtime_apis! { type XcmConfig = xcm_config::XcmConfig; type AccountIdConverter = xcm_config::LocationToAccountId; type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< - xcm_config::XcmConfig, + xcm_config::XcmConfig, ExistentialDepositMultiAsset, xcm_config::PriceForParentDelivery, >; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs index 7e12453583d..aeaaed45452 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_bridge_hub_router` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-11-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-r43aesjn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -58,8 +58,8 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `154` // Estimated: `1639` - // Minimum execution time: 7_924_000 picoseconds. - Weight::from_parts(8_199_000, 0) + // Minimum execution time: 8_110_000 picoseconds. + Weight::from_parts(8_373_000, 0) .saturating_add(Weight::from_parts(0, 1639)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -72,8 +72,8 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `144` // Estimated: `1629` - // Minimum execution time: 4_265_000 picoseconds. - Weight::from_parts(4_417_000, 0) + // Minimum execution time: 4_459_000 picoseconds. + Weight::from_parts(4_663_000, 0) .saturating_add(Weight::from_parts(0, 1629)) .saturating_add(T::DbWeight::get().reads(2)) } @@ -83,12 +83,14 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `150` // Estimated: `1502` - // Minimum execution time: 10_292_000 picoseconds. - Weight::from_parts(10_797_000, 0) + // Minimum execution time: 10_153_000 picoseconds. + Weight::from_parts(10_737_000, 0) .saturating_add(Weight::from_parts(0, 1502)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `PolkadotXcm::SupportedVersion` (r:2 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x3302afcb67e838a3f960251b417b9a4f` (r:1 w:0) @@ -99,8 +101,6 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh /// Proof: `ToWestendXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) @@ -115,12 +115,12 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) fn send_message() -> Weight { // Proof Size summary in bytes: - // Measured: `387` - // Estimated: `3852` - // Minimum execution time: 61_995_000 picoseconds. - Weight::from_parts(65_137_000, 0) - .saturating_add(Weight::from_parts(0, 3852)) - .saturating_add(T::DbWeight::get().reads(11)) + // Measured: `448` + // Estimated: `6388` + // Minimum execution time: 61_258_000 picoseconds. + Weight::from_parts(63_679_000, 0) + .saturating_add(Weight::from_parts(0, 6388)) + .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(4)) } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs index 7bb71a77de7..030a3723319 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs @@ -673,9 +673,16 @@ fn limited_reserve_transfer_assets_for_native_asset_over_bridge_works( mod asset_hub_rococo_tests { use super::*; + use asset_hub_rococo_runtime::{PolkadotXcm, RuntimeOrigin}; fn bridging_to_asset_hub_westend() -> TestBridgingConfig { - asset_test_utils::test_cases_over_bridge::TestBridgingConfig { + let _ = PolkadotXcm::force_xcm_version( + RuntimeOrigin::root(), + Box::new(bridging::to_westend::AssetHubWestend::get()), + XCM_VERSION, + ) + .expect("version saved!"); + TestBridgingConfig { bridged_network: bridging::to_westend::WestendNetwork::get(), local_bridge_hub_para_id: bridging::SiblingBridgeHubParaId::get(), local_bridge_hub_location: bridging::SiblingBridgeHub::get(), diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 7443de54cb6..e44c7b2c827 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -822,6 +822,7 @@ impl pallet_xcm_bridge_hub_router::Config for Runtime type UniversalLocation = xcm_config::UniversalLocation; type BridgedNetworkId = xcm_config::bridging::to_rococo::RococoNetwork; type Bridges = xcm_config::bridging::NetworkExportTable; + type DestinationVersion = PolkadotXcm; #[cfg(not(feature = "runtime-benchmarks"))] type BridgeHubOrigin = EnsureXcm>; @@ -1493,11 +1494,26 @@ impl_runtime_apis! { xcm_config::bridging::SiblingBridgeHubParaId::get().into() ); } - fn ensure_bridged_target_destination() -> MultiLocation { + fn ensure_bridged_target_destination() -> Result { ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests( xcm_config::bridging::SiblingBridgeHubParaId::get().into() ); - xcm_config::bridging::to_rococo::AssetHubRococo::get() + let bridged_asset_hub = xcm_config::bridging::to_rococo::AssetHubRococo::get(); + let _ = PolkadotXcm::force_xcm_version( + RuntimeOrigin::root(), + Box::new(bridged_asset_hub), + XCM_VERSION, + ).map_err(|e| { + log::error!( + "Failed to dispatch `force_xcm_version({:?}, {:?}, {:?})`, error: {:?}", + RuntimeOrigin::root(), + bridged_asset_hub, + XCM_VERSION, + e + ); + BenchmarkError::Stop("XcmVersion was not stored!") + })?; + Ok(bridged_asset_hub) } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs index 9d0d0cbc655..ee8d0ae3c45 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_bridge_hub_router` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-11-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-r43aesjn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -48,8 +48,8 @@ use core::marker::PhantomData; /// Weight functions for `pallet_xcm_bridge_hub_router`. pub struct WeightInfo(PhantomData); impl pallet_xcm_bridge_hub_router::WeightInfo for WeightInfo { - /// Storage: `XcmpQueue::InboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ToRococoXcmRouter::Bridge` (r:1 w:1) @@ -58,22 +58,22 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `193` // Estimated: `1678` - // Minimum execution time: 8_157_000 picoseconds. - Weight::from_parts(8_481_000, 0) + // Minimum execution time: 8_460_000 picoseconds. + Weight::from_parts(8_730_000, 0) .saturating_add(Weight::from_parts(0, 1678)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `XcmpQueue::InboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn on_initialize_when_congested() -> Weight { // Proof Size summary in bytes: // Measured: `111` // Estimated: `1596` - // Minimum execution time: 3_319_000 picoseconds. - Weight::from_parts(3_445_000, 0) + // Minimum execution time: 3_469_000 picoseconds. + Weight::from_parts(3_696_000, 0) .saturating_add(Weight::from_parts(0, 1596)) .saturating_add(T::DbWeight::get().reads(2)) } @@ -83,22 +83,24 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `117` // Estimated: `1502` - // Minimum execution time: 10_396_000 picoseconds. - Weight::from_parts(10_914_000, 0) + // Minimum execution time: 10_315_000 picoseconds. + Weight::from_parts(10_651_000, 0) .saturating_add(Weight::from_parts(0, 1502)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `PolkadotXcm::SupportedVersion` (r:2 w:0) + /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x3302afcb67e838a3f960251b417b9a4f` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x3302afcb67e838a3f960251b417b9a4f` (r:1 w:0) /// Storage: UNKNOWN KEY `0x0973fe64c85043ba1c965cbc38eb63c7` (r:1 w:0) /// Proof: UNKNOWN KEY `0x0973fe64c85043ba1c965cbc38eb63c7` (r:1 w:0) /// Storage: `ToRococoXcmRouter::Bridge` (r:1 w:1) /// Proof: `ToRococoXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) @@ -107,18 +109,18 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `XcmpQueue::InboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) + /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `XcmpQueue::OutboundXcmpMessages` (r:0 w:1) /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) fn send_message() -> Weight { // Proof Size summary in bytes: - // Measured: `426` - // Estimated: `3891` - // Minimum execution time: 45_902_000 picoseconds. - Weight::from_parts(46_887_000, 0) - .saturating_add(Weight::from_parts(0, 3891)) - .saturating_add(T::DbWeight::get().reads(10)) + // Measured: `487` + // Estimated: `6427` + // Minimum execution time: 64_532_000 picoseconds. + Weight::from_parts(66_901_000, 0) + .saturating_add(Weight::from_parts(0, 6427)) + .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(4)) } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs index 7922b04e807..0aaf1d91879 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs @@ -24,9 +24,9 @@ use asset_hub_westend_runtime::{ WestendLocation, XcmConfig, }, AllPalletsWithoutSystem, AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets, - ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, Runtime, - RuntimeCall, RuntimeEvent, SessionKeys, ToRococoXcmRouterInstance, TrustBackedAssetsInstance, - XcmpQueue, + ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, + PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, SessionKeys, + ToRococoXcmRouterInstance, TrustBackedAssetsInstance, XcmpQueue, }; use asset_test_utils::{ test_cases_over_bridge::TestBridgingConfig, CollatorSessionKey, CollatorSessionKeys, ExtBuilder, @@ -635,6 +635,12 @@ asset_test_utils::include_create_and_manage_foreign_assets_for_local_consensus_p ); fn bridging_to_asset_hub_rococo() -> TestBridgingConfig { + let _ = PolkadotXcm::force_xcm_version( + RuntimeOrigin::root(), + Box::new(bridging::to_rococo::AssetHubRococo::get()), + XCM_VERSION, + ) + .expect("version saved!"); TestBridgingConfig { bridged_network: bridging::to_rococo::RococoNetwork::get(), local_bridge_hub_para_id: bridging::SiblingBridgeHubParaId::get(), diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs index ec9b2646c88..546b032e4f2 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs @@ -20,7 +20,7 @@ use crate::{ bridge_common_config::{BridgeParachainWestendInstance, DeliveryRewardInBalance}, weights, xcm_config::UniversalLocation, - AccountId, BridgeWestendMessages, Runtime, RuntimeEvent, RuntimeOrigin, + AccountId, BridgeWestendMessages, PolkadotXcm, Runtime, RuntimeEvent, RuntimeOrigin, XcmOverBridgeHubWestend, XcmRouter, }; use bp_messages::LaneId; @@ -33,7 +33,7 @@ use bridge_runtime_common::{ }, messages_xcm_extension::{ SenderAndLane, XcmAsPlainPayload, XcmBlobHauler, XcmBlobHaulerAdapter, - XcmBlobMessageDispatch, + XcmBlobMessageDispatch, XcmVersionOfDestAndRemoteBridge, }, refund_relayer_extension::{ ActualFeeRefund, RefundBridgedParachainMessages, RefundSignedExtensionAdapter, @@ -58,6 +58,10 @@ parameter_types! { pub const BridgeHubWestendChainId: bp_runtime::ChainId = bp_runtime::BRIDGE_HUB_WESTEND_CHAIN_ID; pub BridgeRococoToWestendMessagesPalletInstance: InteriorMultiLocation = X1(PalletInstance(::index() as u8)); pub WestendGlobalConsensusNetwork: NetworkId = NetworkId::Westend; + pub WestendGlobalConsensusNetworkLocation: MultiLocation = MultiLocation { + parents: 2, + interior: X1(GlobalConsensus(WestendGlobalConsensusNetwork::get())) + }; // see the `FEE_BOOST_PER_MESSAGE` constant to get the meaning of this value pub PriorityBoostPerMessage: u64 = 182_044_444_444_444; @@ -80,6 +84,14 @@ parameter_types! { pub CongestedMessage: Xcm<()> = build_congestion_message(true).into(); pub UncongestedMessage: Xcm<()> = build_congestion_message(false).into(); + + pub BridgeHubWestendLocation: MultiLocation = MultiLocation { + parents: 2, + interior: X2( + GlobalConsensus(WestendGlobalConsensusNetwork::get()), + Parachain(::PARACHAIN_ID) + ) + }; } pub const XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND: LaneId = LaneId([0, 0, 0, 2]); @@ -120,7 +132,6 @@ pub struct ToBridgeHubWestendXcmBlobHauler; impl XcmBlobHauler for ToBridgeHubWestendXcmBlobHauler { type Runtime = Runtime; type MessagesInstance = WithBridgeHubWestendMessagesInstance; - type ToSourceChainSender = XcmRouter; type CongestedMessage = CongestedMessage; type UncongestedMessage = UncongestedMessage; @@ -234,9 +245,11 @@ impl pallet_bridge_messages::Config for Ru pub type XcmOverBridgeHubWestendInstance = pallet_xcm_bridge_hub::Instance1; impl pallet_xcm_bridge_hub::Config for Runtime { type UniversalLocation = UniversalLocation; - type BridgedNetworkId = WestendGlobalConsensusNetwork; + type BridgedNetwork = WestendGlobalConsensusNetworkLocation; type BridgeMessagesPalletInstance = WithBridgeHubWestendMessagesInstance; type MessageExportPrice = (); + type DestinationVersion = + XcmVersionOfDestAndRemoteBridge; type Lanes = ActiveLanes; type LanesSupport = ToBridgeHubWestendXcmBlobHauler; } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index 1bb2faeb2fc..3d1d345a95c 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -853,7 +853,7 @@ impl_runtime_apis! { type XcmConfig = xcm_config::XcmConfig; type AccountIdConverter = xcm_config::LocationToAccountId; type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper< - xcm_config::XcmConfig, + xcm_config::XcmConfig, ExistentialDepositMultiAsset, xcm_config::PriceForParentDelivery, >; @@ -933,6 +933,21 @@ impl_runtime_apis! { fn export_message_origin_and_destination( ) -> Result<(MultiLocation, NetworkId, InteriorMultiLocation), BenchmarkError> { + // save XCM version for remote bridge hub + let _ = PolkadotXcm::force_xcm_version( + RuntimeOrigin::root(), + Box::new(bridge_to_westend_config::BridgeHubWestendLocation::get()), + XCM_VERSION, + ).map_err(|e| { + log::error!( + "Failed to dispatch `force_xcm_version({:?}, {:?}, {:?})`, error: {:?}", + RuntimeOrigin::root(), + bridge_to_westend_config::BridgeHubWestendLocation::get(), + XCM_VERSION, + e + ); + BenchmarkError::Stop("XcmVersion was not stored!") + })?; Ok( ( bridge_to_westend_config::FromAssetHubRococoToAssetHubWestendRoute::get().location, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 0ae6d0b5623..606e47457d2 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-14, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-11-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-r43aesjn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-rococo-dev"), DB CACHE: 1024 // Executed Command: @@ -68,8 +68,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 63_453_000 picoseconds. - Weight::from_parts(64_220_000, 6196) + // Minimum execution time: 61_049_000 picoseconds. + Weight::from_parts(62_672_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -77,8 +77,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_238_000 picoseconds. - Weight::from_parts(2_351_000, 0) + // Minimum execution time: 1_972_000 picoseconds. + Weight::from_parts(2_095_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -86,58 +86,58 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `3497` - // Minimum execution time: 7_953_000 picoseconds. - Weight::from_parts(8_162_000, 3497) + // Minimum execution time: 7_541_000 picoseconds. + Weight::from_parts(7_875_000, 3497) .saturating_add(T::DbWeight::get().reads(1)) } pub fn transact() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_080_000 picoseconds. - Weight::from_parts(9_333_000, 0) + // Minimum execution time: 8_467_000 picoseconds. + Weight::from_parts(8_653_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_415_000 picoseconds. - Weight::from_parts(2_519_000, 0) + // Minimum execution time: 2_141_000 picoseconds. + Weight::from_parts(2_231_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_045_000 picoseconds. - Weight::from_parts(2_184_000, 0) + // Minimum execution time: 1_881_000 picoseconds. + Weight::from_parts(1_941_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_065_000 picoseconds. - Weight::from_parts(2_125_000, 0) + // Minimum execution time: 1_846_000 picoseconds. + Weight::from_parts(1_916_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_077_000 picoseconds. - Weight::from_parts(2_164_000, 0) + // Minimum execution time: 1_857_000 picoseconds. + Weight::from_parts(1_910_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_868_000 picoseconds. - Weight::from_parts(2_933_000, 0) + // Minimum execution time: 2_493_000 picoseconds. + Weight::from_parts(2_570_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_058_000 picoseconds. - Weight::from_parts(2_164_000, 0) + // Minimum execution time: 1_857_000 picoseconds. + Weight::from_parts(1_930_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -159,8 +159,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 55_971_000 picoseconds. - Weight::from_parts(56_869_000, 6196) + // Minimum execution time: 54_805_000 picoseconds. + Weight::from_parts(55_690_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -170,8 +170,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 11_382_000 picoseconds. - Weight::from_parts(11_672_000, 3555) + // Minimum execution time: 11_062_000 picoseconds. + Weight::from_parts(11_505_000, 3555) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -179,8 +179,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_071_000 picoseconds. - Weight::from_parts(2_193_000, 0) + // Minimum execution time: 1_873_000 picoseconds. + Weight::from_parts(1_962_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -200,8 +200,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 22_573_000 picoseconds. - Weight::from_parts(23_423_000, 3503) + // Minimum execution time: 22_356_000 picoseconds. + Weight::from_parts(23_066_000, 3503) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -211,44 +211,44 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_870_000 picoseconds. - Weight::from_parts(3_993_000, 0) + // Minimum execution time: 3_819_000 picoseconds. + Weight::from_parts(3_992_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } pub fn burn_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_483_000 picoseconds. - Weight::from_parts(3_598_000, 0) + // Minimum execution time: 3_033_000 picoseconds. + Weight::from_parts(3_157_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_241_000 picoseconds. - Weight::from_parts(2_297_000, 0) + // Minimum execution time: 1_994_000 picoseconds. + Weight::from_parts(2_056_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_230_000 picoseconds. - Weight::from_parts(2_318_000, 0) + // Minimum execution time: 1_978_000 picoseconds. + Weight::from_parts(2_069_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_051_000 picoseconds. - Weight::from_parts(2_153_000, 0) + // Minimum execution time: 1_894_000 picoseconds. + Weight::from_parts(1_977_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_306_000 picoseconds. - Weight::from_parts(2_380_000, 0) + // Minimum execution time: 2_114_000 picoseconds. + Weight::from_parts(2_223_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -270,8 +270,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 60_201_000 picoseconds. - Weight::from_parts(61_132_000, 6196) + // Minimum execution time: 58_704_000 picoseconds. + Weight::from_parts(59_677_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -279,8 +279,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_554_000 picoseconds. - Weight::from_parts(4_704_000, 0) + // Minimum execution time: 4_506_000 picoseconds. + Weight::from_parts(4_672_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -302,8 +302,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 56_071_000 picoseconds. - Weight::from_parts(56_889_000, 6196) + // Minimum execution time: 54_896_000 picoseconds. + Weight::from_parts(56_331_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -311,25 +311,29 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_093_000 picoseconds. - Weight::from_parts(2_169_000, 0) + // Minimum execution time: 1_946_000 picoseconds. + Weight::from_parts(2_002_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_027_000 picoseconds. - Weight::from_parts(2_172_000, 0) + // Minimum execution time: 1_898_000 picoseconds. + Weight::from_parts(1_961_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_035_000 picoseconds. - Weight::from_parts(2_164_000, 0) + // Minimum execution time: 1_895_000 picoseconds. + Weight::from_parts(1_964_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + // Storage: `PolkadotXcm::SupportedVersion` (r:2 w:0) + // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) // Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) // Storage: `BridgeWestendMessages::OutboundLanes` (r:1 w:1) @@ -341,27 +345,27 @@ impl WeightInfo { /// The range of component `x` is `[1, 1000]`. pub fn export_message(x: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `96` - // Estimated: `1529` - // Minimum execution time: 25_636_000 picoseconds. - Weight::from_parts(25_405_640, 1529) - // Standard Error: 321 - .saturating_add(Weight::from_parts(365_002, 0).saturating_mul(x.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `190` + // Estimated: `6130` + // Minimum execution time: 36_547_000 picoseconds. + Weight::from_parts(37_623_117, 6130) + // Standard Error: 735 + .saturating_add(Weight::from_parts(315_274, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(3)) } pub fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_036_000 picoseconds. - Weight::from_parts(2_136_000, 0) + // Minimum execution time: 1_868_000 picoseconds. + Weight::from_parts(1_910_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_147_000 picoseconds. - Weight::from_parts(2_276_000, 0) + // Minimum execution time: 1_998_000 picoseconds. + Weight::from_parts(2_069_000, 0) } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs index c1af369cdf8..1d544a9dcfa 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs @@ -21,11 +21,11 @@ use bridge_hub_rococo_runtime::{ bridge_common_config, bridge_to_westend_config, xcm_config::{RelayNetwork, TokenLocation, XcmConfig}, AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, Executive, ExistentialDeposit, - ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, SessionKeys, SignedExtra, - TransactionPayment, UncheckedExtrinsic, + ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, SessionKeys, + SignedExtra, TransactionPayment, UncheckedExtrinsic, }; use codec::{Decode, Encode}; -use frame_support::{dispatch::GetDispatchInfo, parameter_types}; +use frame_support::{dispatch::GetDispatchInfo, parameter_types, traits::ConstU8}; use frame_system::pallet_prelude::HeaderFor; use parachains_common::{rococo::fee::WeightToFee, AccountId, AuraId, Balance}; use sp_keyring::AccountKeyring::Alice; @@ -104,8 +104,9 @@ mod bridge_hub_rococo_tests { RequiredStakeForStakeAndSlash, }; use bridge_to_westend_config::{ - BridgeHubWestendChainId, WestendGlobalConsensusNetwork, WithBridgeHubWestendMessageBridge, - WithBridgeHubWestendMessagesInstance, XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, + BridgeHubWestendChainId, BridgeHubWestendLocation, WestendGlobalConsensusNetwork, + WithBridgeHubWestendMessageBridge, WithBridgeHubWestendMessagesInstance, + XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, }; bridge_hub_test_utils::test_cases::include_teleports_for_native_asset_works!( @@ -196,7 +197,7 @@ mod bridge_hub_rococo_tests { Some((TokenLocation::get(), ExistentialDeposit::get()).into()), // value should be >= than value generated by `can_calculate_weight_for_paid_export_message_with_reserve_transfer` Some((TokenLocation::get(), bp_bridge_hub_rococo::BridgeHubRococoBaseXcmFeeInRocs::get()).into()), - || (), + || PolkadotXcm::force_xcm_version(RuntimeOrigin::root(), Box::new(BridgeHubWestendLocation::get()), XCM_VERSION).expect("version saved!"), ) } @@ -211,6 +212,7 @@ mod bridge_hub_rococo_tests { WithBridgeHubWestendMessagesInstance, RelayNetwork, WestendGlobalConsensusNetwork, + ConstU8<2>, >( collator_session_keys(), bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs index 3b773947b47..eb5493872b4 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_rococo_config.rs @@ -18,8 +18,8 @@ use crate::{ bridge_common_config::DeliveryRewardInBalance, weights, xcm_config::UniversalLocation, - AccountId, BridgeRococoMessages, Runtime, RuntimeEvent, RuntimeOrigin, XcmOverBridgeHubRococo, - XcmRouter, + AccountId, BridgeRococoMessages, PolkadotXcm, Runtime, RuntimeEvent, RuntimeOrigin, + XcmOverBridgeHubRococo, XcmRouter, }; use bp_messages::LaneId; use bp_parachains::SingleParaStoredHeaderDataBuilder; @@ -32,7 +32,7 @@ use bridge_runtime_common::{ }, messages_xcm_extension::{ SenderAndLane, XcmAsPlainPayload, XcmBlobHauler, XcmBlobHaulerAdapter, - XcmBlobMessageDispatch, + XcmBlobMessageDispatch, XcmVersionOfDestAndRemoteBridge, }, refund_relayer_extension::{ ActualFeeRefund, RefundBridgedParachainMessages, RefundSignedExtensionAdapter, @@ -65,6 +65,10 @@ parameter_types! { pub const BridgeHubRococoChainId: bp_runtime::ChainId = bp_runtime::BRIDGE_HUB_ROCOCO_CHAIN_ID; pub BridgeWestendToRococoMessagesPalletInstance: InteriorMultiLocation = X1(PalletInstance(::index() as u8)); pub RococoGlobalConsensusNetwork: NetworkId = NetworkId::Rococo; + pub RococoGlobalConsensusNetworkLocation: MultiLocation = MultiLocation { + parents: 2, + interior: X1(GlobalConsensus(RococoGlobalConsensusNetwork::get())) + }; // see the `FEE_BOOST_PER_MESSAGE` constant to get the meaning of this value pub PriorityBoostPerMessage: u64 = 182_044_444_444_444; @@ -87,6 +91,14 @@ parameter_types! { pub CongestedMessage: Xcm<()> = build_congestion_message(true).into(); pub UncongestedMessage: Xcm<()> = build_congestion_message(false).into(); + + pub BridgeHubRococoLocation: MultiLocation = MultiLocation { + parents: 2, + interior: X2( + GlobalConsensus(RococoGlobalConsensusNetwork::get()), + Parachain(::PARACHAIN_ID) + ) + }; } pub const XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO: LaneId = LaneId([0, 0, 0, 2]); @@ -260,9 +272,10 @@ impl pallet_bridge_messages::Config for Run pub type XcmOverBridgeHubRococoInstance = pallet_xcm_bridge_hub::Instance1; impl pallet_xcm_bridge_hub::Config for Runtime { type UniversalLocation = UniversalLocation; - type BridgedNetworkId = RococoGlobalConsensusNetwork; + type BridgedNetwork = RococoGlobalConsensusNetworkLocation; type BridgeMessagesPalletInstance = WithBridgeHubRococoMessagesInstance; type MessageExportPrice = (); + type DestinationVersion = XcmVersionOfDestAndRemoteBridge; type Lanes = ActiveLanes; type LanesSupport = ToBridgeHubRococoXcmBlobHauler; } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index 6157aa90a5a..5ea5cea7530 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -922,6 +922,21 @@ impl_runtime_apis! { fn export_message_origin_and_destination( ) -> Result<(MultiLocation, NetworkId, InteriorMultiLocation), BenchmarkError> { + // save XCM version for remote bridge hub + let _ = PolkadotXcm::force_xcm_version( + RuntimeOrigin::root(), + Box::new(bridge_to_rococo_config::BridgeHubRococoLocation::get()), + XCM_VERSION, + ).map_err(|e| { + log::error!( + "Failed to dispatch `force_xcm_version({:?}, {:?}, {:?})`, error: {:?}", + RuntimeOrigin::root(), + bridge_to_rococo_config::BridgeHubRococoLocation::get(), + XCM_VERSION, + e + ); + BenchmarkError::Stop("XcmVersion was not stored!") + })?; Ok( ( bridge_to_rococo_config::FromAssetHubWestendToAssetHubRococoRoute::get().location, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 7c686190208..8f283403400 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -17,10 +17,10 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-11-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-r43aesjn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-westend-dev"), DB CACHE: 1024 // Executed Command: // target/production/polkadot-parachain @@ -33,10 +33,10 @@ // --heap-pages=4096 // --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json // --pallet=pallet_xcm_benchmarks::generic -// --chain=bridge-hub-rococo-dev +// --chain=bridge-hub-westend-dev // --header=./cumulus/file_header.txt // --template=./cumulus/templates/xcm-bench-template.hbs -// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/ +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -48,8 +48,6 @@ use sp_std::marker::PhantomData; /// Weights for `pallet_xcm_benchmarks::generic`. pub struct WeightInfo(PhantomData); impl WeightInfo { - // Storage: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) - // Proof: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -68,81 +66,79 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn report_holding() -> Weight { // Proof Size summary in bytes: - // Measured: `242` + // Measured: `171` // Estimated: `6196` - // Minimum execution time: 62_732_000 picoseconds. - Weight::from_parts(64_581_000, 6196) - .saturating_add(T::DbWeight::get().reads(10)) + // Minimum execution time: 61_383_000 picoseconds. + Weight::from_parts(62_382_000, 6196) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } pub fn buy_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_987_000 picoseconds. - Weight::from_parts(2_107_000, 0) + // Minimum execution time: 2_057_000 picoseconds. + Weight::from_parts(2_153_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) pub fn query_response() -> Weight { // Proof Size summary in bytes: - // Measured: `103` - // Estimated: `3568` - // Minimum execution time: 8_098_000 picoseconds. - Weight::from_parts(8_564_000, 3568) + // Measured: `32` + // Estimated: `3497` + // Minimum execution time: 7_949_000 picoseconds. + Weight::from_parts(8_250_000, 3497) .saturating_add(T::DbWeight::get().reads(1)) } pub fn transact() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_539_000 picoseconds. - Weight::from_parts(9_085_000, 0) + // Minimum execution time: 8_608_000 picoseconds. + Weight::from_parts(9_086_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_205_000 picoseconds. - Weight::from_parts(2_369_000, 0) + // Minimum execution time: 2_240_000 picoseconds. + Weight::from_parts(2_348_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_828_000 picoseconds. - Weight::from_parts(1_994_000, 0) + // Minimum execution time: 1_969_000 picoseconds. + Weight::from_parts(2_017_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_869_000 picoseconds. - Weight::from_parts(1_946_000, 0) + // Minimum execution time: 1_907_000 picoseconds. + Weight::from_parts(2_001_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_842_000 picoseconds. - Weight::from_parts(1_949_000, 0) + // Minimum execution time: 1_880_000 picoseconds. + Weight::from_parts(1_975_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_460_000 picoseconds. - Weight::from_parts(2_593_000, 0) + // Minimum execution time: 2_549_000 picoseconds. + Weight::from_parts(2_624_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_868_000 picoseconds. - Weight::from_parts(2_003_000, 0) + // Minimum execution time: 1_895_000 picoseconds. + Weight::from_parts(1_963_000, 0) } - // Storage: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) - // Proof: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -161,21 +157,21 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn report_error() -> Weight { // Proof Size summary in bytes: - // Measured: `242` + // Measured: `171` // Estimated: `6196` - // Minimum execution time: 56_813_000 picoseconds. - Weight::from_parts(57_728_000, 6196) - .saturating_add(T::DbWeight::get().reads(10)) + // Minimum execution time: 54_447_000 picoseconds. + Weight::from_parts(55_629_000, 6196) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } // Storage: `PolkadotXcm::AssetTraps` (r:1 w:1) // Proof: `PolkadotXcm::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) pub fn claim_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `160` - // Estimated: `3625` - // Minimum execution time: 11_364_000 picoseconds. - Weight::from_parts(11_872_000, 3625) + // Measured: `90` + // Estimated: `3555` + // Minimum execution time: 11_597_000 picoseconds. + Weight::from_parts(11_809_000, 3555) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -183,8 +179,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_821_000 picoseconds. - Weight::from_parts(1_936_000, 0) + // Minimum execution time: 1_895_000 picoseconds. + Weight::from_parts(1_977_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -202,10 +198,10 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn subscribe_version() -> Weight { // Proof Size summary in bytes: - // Measured: `109` - // Estimated: `3574` - // Minimum execution time: 23_081_000 picoseconds. - Weight::from_parts(23_512_000, 3574) + // Measured: `38` + // Estimated: `3503` + // Minimum execution time: 23_314_000 picoseconds. + Weight::from_parts(23_905_000, 3503) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -215,47 +211,45 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_747_000 picoseconds. - Weight::from_parts(4_068_000, 0) + // Minimum execution time: 3_948_000 picoseconds. + Weight::from_parts(4_084_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } pub fn burn_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_045_000 picoseconds. - Weight::from_parts(3_208_000, 0) + // Minimum execution time: 3_196_000 picoseconds. + Weight::from_parts(3_285_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_962_000 picoseconds. - Weight::from_parts(2_284_000, 0) + // Minimum execution time: 2_040_000 picoseconds. + Weight::from_parts(2_162_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_951_000 picoseconds. - Weight::from_parts(2_026_000, 0) + // Minimum execution time: 1_980_000 picoseconds. + Weight::from_parts(2_082_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_837_000 picoseconds. - Weight::from_parts(2_084_000, 0) + // Minimum execution time: 1_890_000 picoseconds. + Weight::from_parts(1_971_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_042_000 picoseconds. - Weight::from_parts(2_145_000, 0) + // Minimum execution time: 2_131_000 picoseconds. + Weight::from_parts(2_187_000, 0) } - // Storage: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) - // Proof: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -274,22 +268,20 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn query_pallet() -> Weight { // Proof Size summary in bytes: - // Measured: `242` + // Measured: `171` // Estimated: `6196` - // Minimum execution time: 61_350_000 picoseconds. - Weight::from_parts(62_440_000, 6196) - .saturating_add(T::DbWeight::get().reads(10)) + // Minimum execution time: 59_548_000 picoseconds. + Weight::from_parts(60_842_000, 6196) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } pub fn expect_pallet() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_993_000 picoseconds. - Weight::from_parts(5_309_000, 0) + // Minimum execution time: 4_665_000 picoseconds. + Weight::from_parts(4_844_000, 0) } - // Storage: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) - // Proof: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) // Storage: `ParachainSystem::UpwardDeliveryFeeFactor` (r:1 w:0) @@ -308,70 +300,72 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn report_transact_status() -> Weight { // Proof Size summary in bytes: - // Measured: `242` + // Measured: `171` // Estimated: `6196` - // Minimum execution time: 57_133_000 picoseconds. - Weight::from_parts(58_100_000, 6196) - .saturating_add(T::DbWeight::get().reads(10)) + // Minimum execution time: 55_044_000 picoseconds. + Weight::from_parts(56_103_000, 6196) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } pub fn clear_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_899_000 picoseconds. - Weight::from_parts(2_153_000, 0) + // Minimum execution time: 1_904_000 picoseconds. + Weight::from_parts(1_984_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_880_000 picoseconds. - Weight::from_parts(1_960_000, 0) + // Minimum execution time: 1_889_000 picoseconds. + Weight::from_parts(1_950_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_825_000 picoseconds. - Weight::from_parts(1_960_000, 0) + // Minimum execution time: 1_878_000 picoseconds. + Weight::from_parts(1_963_000, 0) } - // Storage: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) - // Proof: UNKNOWN KEY `0x48297505634037ef48c848c99c0b1f1b` (r:1 w:0) // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - // Storage: `BridgeRococoToWococoMessages::PalletOperatingMode` (r:1 w:0) - // Proof: `BridgeRococoToWococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - // Storage: `BridgeRococoToWococoMessages::OutboundLanes` (r:1 w:1) - // Proof: `BridgeRococoToWococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) - // Storage: `BridgeRococoToWococoMessages::OutboundLanesCongestedSignals` (r:1 w:0) - // Proof: `BridgeRococoToWococoMessages::OutboundLanesCongestedSignals` (`max_values`: Some(1), `max_size`: Some(21), added: 516, mode: `MaxEncodedLen`) - // Storage: `BridgeRococoToWococoMessages::OutboundMessages` (r:0 w:1) - // Proof: `BridgeRococoToWococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(2621472), added: 2623947, mode: `MaxEncodedLen`) + // Storage: `PolkadotXcm::SupportedVersion` (r:2 w:0) + // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) + // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + // Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) + // Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + // Storage: `BridgeRococoMessages::OutboundLanes` (r:1 w:1) + // Proof: `BridgeRococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + // Storage: `BridgeRococoMessages::OutboundLanesCongestedSignals` (r:1 w:0) + // Proof: `BridgeRococoMessages::OutboundLanesCongestedSignals` (`max_values`: Some(1), `max_size`: Some(21), added: 516, mode: `MaxEncodedLen`) + // Storage: `BridgeRococoMessages::OutboundMessages` (r:0 w:1) + // Proof: `BridgeRococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(2621472), added: 2623947, mode: `MaxEncodedLen`) /// The range of component `x` is `[1, 1000]`. pub fn export_message(x: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `139` - // Estimated: `3604` - // Minimum execution time: 28_419_000 picoseconds. - Weight::from_parts(29_387_791, 3604) - // Standard Error: 552 - .saturating_add(Weight::from_parts(316_277, 0).saturating_mul(x.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `188` + // Estimated: `6128` + // Minimum execution time: 36_960_000 picoseconds. + Weight::from_parts(38_104_333, 6128) + // Standard Error: 510 + .saturating_add(Weight::from_parts(316_499, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(3)) } pub fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_903_000 picoseconds. - Weight::from_parts(2_023_000, 0) + // Minimum execution time: 1_833_000 picoseconds. + Weight::from_parts(1_950_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_963_000 picoseconds. - Weight::from_parts(2_143_000, 0) + // Minimum execution time: 1_980_000 picoseconds. + Weight::from_parts(2_065_000, 0) } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs index 822dc2340d4..73bddb16369 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs @@ -22,16 +22,16 @@ use bridge_hub_westend_runtime::{ bridge_common_config, bridge_to_rococo_config, xcm_config::{RelayNetwork, WestendLocation, XcmConfig}, AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, Executive, ExistentialDeposit, - ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, SessionKeys, SignedExtra, - TransactionPayment, UncheckedExtrinsic, + ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, SessionKeys, + SignedExtra, TransactionPayment, UncheckedExtrinsic, }; use bridge_to_rococo_config::{ - BridgeGrandpaRococoInstance, BridgeHubRococoChainId, BridgeParachainRococoInstance, - WithBridgeHubRococoMessageBridge, WithBridgeHubRococoMessagesInstance, - XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, + BridgeGrandpaRococoInstance, BridgeHubRococoChainId, BridgeHubRococoLocation, + BridgeParachainRococoInstance, WithBridgeHubRococoMessageBridge, + WithBridgeHubRococoMessagesInstance, XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, }; use codec::{Decode, Encode}; -use frame_support::{dispatch::GetDispatchInfo, parameter_types}; +use frame_support::{dispatch::GetDispatchInfo, parameter_types, traits::ConstU8}; use frame_system::pallet_prelude::HeaderFor; use parachains_common::{westend::fee::WeightToFee, AccountId, AuraId, Balance}; use sp_keyring::AccountKeyring::Alice; @@ -184,7 +184,7 @@ fn handle_export_message_from_system_parachain_add_to_outbound_queue_works() { Some((WestendLocation::get(), ExistentialDeposit::get()).into()), // value should be >= than value generated by `can_calculate_weight_for_paid_export_message_with_reserve_transfer` Some((WestendLocation::get(), bp_bridge_hub_westend::BridgeHubWestendBaseXcmFeeInWnds::get()).into()), - || (), + || PolkadotXcm::force_xcm_version(RuntimeOrigin::root(), Box::new(BridgeHubRococoLocation::get()), XCM_VERSION).expect("version saved!"), ) } @@ -198,6 +198,7 @@ fn message_dispatch_routing_works() { WithBridgeHubRococoMessagesInstance, RelayNetwork, bridge_to_rococo_config::RococoGlobalConsensusNetwork, + ConstU8<2>, >( collator_session_keys(), bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases.rs index fee95a38288..ddcba3b0399 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases.rs @@ -55,7 +55,10 @@ use sp_runtime::{ traits::{Header as HeaderT, Zero}, AccountId32, }; -use xcm::latest::prelude::*; +use xcm::{ + latest::prelude::*, + prelude::{AlwaysLatest, GetVersion}, +}; use xcm_builder::DispatchBlobError; use xcm_executor::{ traits::{TransactAsset, WeightBounds}, @@ -258,6 +261,7 @@ pub fn message_dispatch_routing_works< MessagesPalletInstance, RuntimeNetwork, BridgedNetwork, + NetworkDistanceAsParentCount, >( collator_session_key: CollatorSessionKeys, runtime_para_id: u32, @@ -291,13 +295,19 @@ pub fn message_dispatch_routing_works< HrmpChannelOpener: frame_support::inherent::ProvideInherent< Call = cumulus_pallet_parachain_system::Call, >, - // MessageDispatcher: MessageDispatch, DispatchLevelResult = - // XcmBlobMessageDispatchResult, DispatchPayload = XcmAsPlainPayload>, RuntimeNetwork: Get, BridgedNetwork: Get, + NetworkDistanceAsParentCount: Get, { assert_ne!(runtime_para_id, sibling_parachain_id); + struct NetworkWithParentCount(core::marker::PhantomData<(N, C)>); + impl, C: Get> Get for NetworkWithParentCount { + fn get() -> MultiLocation { + MultiLocation { parents: C::get(), interior: X1(GlobalConsensus(N::get())) } + } + } + ExtBuilder::::default() .with_collators(collator_session_key.collators()) .with_session_keys(collator_session_key.session_keys()) @@ -317,7 +327,11 @@ pub fn message_dispatch_routing_works< ); // 1. this message is sent from other global consensus with destination of this Runtime relay chain (UMP) let bridging_message = - test_data::simulate_message_exporter_on_bridged_chain::( + test_data::simulate_message_exporter_on_bridged_chain::< + BridgedNetwork, + NetworkWithParentCount, + AlwaysLatest, + >( (RuntimeNetwork::get(), Here) ); let result = <>::MessageDispatch>::dispatch( @@ -335,7 +349,11 @@ pub fn message_dispatch_routing_works< // 2. this message is sent from other global consensus with destination of this Runtime sibling parachain (HRMP) let bridging_message = - test_data::simulate_message_exporter_on_bridged_chain::( + test_data::simulate_message_exporter_on_bridged_chain::< + BridgedNetwork, + NetworkWithParentCount, + AlwaysLatest, + >( (RuntimeNetwork::get(), X1(Parachain(sibling_parachain_id))), ); @@ -1524,7 +1542,8 @@ pub mod test_data { /// which are transferred over bridge. pub(crate) fn simulate_message_exporter_on_bridged_chain< SourceNetwork: Get, - DestinationNetwork: Get, + DestinationNetwork: Get, + DestinationVersion: GetVersion, >( (destination_network, destination_junctions): (NetworkId, Junctions), ) -> Vec { @@ -1536,23 +1555,28 @@ pub mod test_data { let channel = 1_u32; // simulate XCM message export - let (ticket, fee) = - validate_export::>( - destination_network, - channel, - universal_source_on_bridged_chain, - destination_junctions, - dummy_xcm(), - ) - .expect("validate_export to pass"); + let (ticket, fee) = validate_export::< + HaulBlobExporter, + >( + destination_network, + channel, + universal_source_on_bridged_chain, + destination_junctions, + dummy_xcm(), + ) + .expect("validate_export to pass"); log::info!( target: "simulate_message_exporter_on_bridged_chain", "HaulBlobExporter::validate fee: {:?}", fee ); - let xcm_hash = - HaulBlobExporter::::deliver(ticket) - .expect("deliver to pass"); + let xcm_hash = HaulBlobExporter::< + GrabbingHaulBlob, + DestinationNetwork, + DestinationVersion, + (), + >::deliver(ticket) + .expect("deliver to pass"); log::info!( target: "simulate_message_exporter_on_bridged_chain", "HaulBlobExporter::deliver xcm_hash: {:?}", diff --git a/cumulus/parachains/runtimes/test-utils/src/lib.rs b/cumulus/parachains/runtimes/test-utils/src/lib.rs index e2a6fb45aec..a8ae63b250a 100644 --- a/cumulus/parachains/runtimes/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/test-utils/src/lib.rs @@ -128,7 +128,7 @@ pub struct ExtBuilder< collators: Vec>, // keys added to pallet session keys: Vec<(AccountIdOf, ValidatorIdOf, SessionKeysOf)>, - // safe xcm version for pallet_xcm + // safe XCM version for pallet_xcm safe_xcm_version: Option, // para id para_id: Option, diff --git a/cumulus/scripts/bridges_common.sh b/cumulus/scripts/bridges_common.sh index 8d64c5ede52..97ef8aa1259 100755 --- a/cumulus/scripts/bridges_common.sh +++ b/cumulus/scripts/bridges_common.sh @@ -187,23 +187,25 @@ function open_hrmp_channels() { ${max_message_size} } -function set_storage() { +function force_xcm_version() { local relay_url=$1 local relay_chain_seed=$2 local runtime_para_id=$3 local runtime_para_endpoint=$4 - local items=$5 - echo " calling set_storage:" + local dest=$5 + local xcm_version=$6 + echo " calling force_xcm_version:" echo " relay_url: ${relay_url}" echo " relay_chain_seed: ${relay_chain_seed}" echo " runtime_para_id: ${runtime_para_id}" echo " runtime_para_endpoint: ${runtime_para_endpoint}" - echo " items: ${items}" + echo " dest: ${dest}" + echo " xcm_version: ${xcm_version}" echo " params:" - # 1. generate data for Transact (System::set_storage) + # 1. generate data for Transact (PolkadotXcm::force_xcm_version) local tmp_output_file=$(mktemp) - generate_hex_encoded_call_data "set-storage" "${runtime_para_endpoint}" "${tmp_output_file}" "$items" + generate_hex_encoded_call_data "force-xcm-version" "${runtime_para_endpoint}" "${tmp_output_file}" "$dest" "$xcm_version" local hex_encoded_data=$(cat $tmp_output_file) # 2. trigger governance call diff --git a/cumulus/scripts/bridges_rococo_westend.sh b/cumulus/scripts/bridges_rococo_westend.sh index 9b3bd350276..8bce141d39a 100755 --- a/cumulus/scripts/bridges_rococo_westend.sh +++ b/cumulus/scripts/bridges_rococo_westend.sh @@ -129,6 +129,7 @@ ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_ThisChain="5EHnXa ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_BridgedChain="5EHnXaT5BhiSGP5h9RgQci1txJ2BDbp7KBRE9k8xty3BMUSi" LANE_ID="00000002" +XCM_VERSION=3 function init_ro_wnd() { ensure_relayer @@ -215,6 +216,14 @@ case "$1" in "ws://127.0.0.1:9942" \ "//Alice" \ 1013 1000 4 524288 + # set XCM version of remote AssetHubWestend + force_xcm_version \ + "ws://127.0.0.1:9942" \ + "//Alice" \ + 1000 \ + "ws://127.0.0.1:9910" \ + "$(jq --null-input '{ "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Westend" }, { "Parachain": 1000 } ] } }')" \ + $XCM_VERSION ;; init-bridge-hub-rococo-local) ensure_polkadot_js_api @@ -236,6 +245,14 @@ case "$1" in "//Alice" \ "$ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhwd_BridgedChain" \ $((1000000000000 + 2000000000000)) + # set XCM version of remote BridgeHubWestend + force_xcm_version \ + "ws://127.0.0.1:9942" \ + "//Alice" \ + 1013 \ + "ws://127.0.0.1:8943" \ + "$(jq --null-input '{ "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Westend" }, { "Parachain": 1002 } ] } }')" \ + $XCM_VERSION ;; init-asset-hub-westend-local) ensure_polkadot_js_api @@ -264,6 +281,14 @@ case "$1" in "ws://127.0.0.1:9945" \ "//Alice" \ 1002 1000 4 524288 + # set XCM version of remote AssetHubRococo + force_xcm_version \ + "ws://127.0.0.1:9945" \ + "//Alice" \ + 1000 \ + "ws://127.0.0.1:9010" \ + "$(jq --null-input '{ "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Rococo" }, { "Parachain": 1000 } ] } }')" \ + $XCM_VERSION ;; init-bridge-hub-westend-local) # SA of sibling asset hub pays for the execution @@ -284,6 +309,14 @@ case "$1" in "//Alice" \ "$ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_BridgedChain" \ $((1000000000000000 + 2000000000000)) + # set XCM version of remote BridgeHubRococo + force_xcm_version \ + "ws://127.0.0.1:9945" \ + "//Alice" \ + 1002 \ + "ws://127.0.0.1:8945" \ + "$(jq --null-input '{ "parents": 2, "interior": { "X2": [ { "GlobalConsensus": "Rococo" }, { "Parachain": 1013 } ] } }')" \ + $XCM_VERSION ;; reserve-transfer-assets-from-asset-hub-rococo-local) ensure_polkadot_js_api diff --git a/cumulus/scripts/generate_hex_encoded_call/index.js b/cumulus/scripts/generate_hex_encoded_call/index.js index 09f0e6aaf61..30f89d754ce 100644 --- a/cumulus/scripts/generate_hex_encoded_call/index.js +++ b/cumulus/scripts/generate_hex_encoded_call/index.js @@ -106,11 +106,11 @@ function forceCreateAsset(endpoint, outputFile, assetId, assetOwnerAccountId, is }); } -function setStorage(endpoint, outputFile, items) { - console.log(`Generating setStorage from RPC endpoint: ${endpoint} to outputFile: ${outputFile}, items: ${items}`); +function forceXcmVersion(endpoint, outputFile, dest, xcm_version) { + console.log(`Generating forceXcmVersion from RPC endpoint: ${endpoint} to outputFile: ${outputFile}, dest: ${dest}, xcm_version: ${xcm_version}`); connect(endpoint) .then((api) => { - const call = api.tx.system.setStorage(JSON.parse(items)); + const call = api.tx.polkadotXcm.forceXcmVersion(JSON.parse(dest), xcm_version); writeHexEncodedBytesToOutput(call.method, outputFile); exit(0); }) @@ -154,8 +154,8 @@ switch (type) { case 'force-create-asset': forceCreateAsset(rpcEnpoint, output, inputArgs[0], inputArgs[1], inputArgs[2], inputArgs[3]); break; - case 'set-storage': - setStorage(rpcEnpoint, output, inputArgs[0]); + case 'force-xcm-version': + forceXcmVersion(rpcEnpoint, output, inputArgs[0], inputArgs[1]); break; case 'check': console.log(`Checking nodejs installation, if you see this everything is ready!`); diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index ab4403f6caa..2848527f150 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -2591,7 +2591,7 @@ impl WrapVersion for Pallet { dest: &MultiLocation, xcm: impl Into>, ) -> Result, ()> { - SupportedVersion::::get(XCM_VERSION, LatestVersionedMultiLocation(dest)) + Self::get_version_for(dest) .or_else(|| { Self::note_unknown_version(dest); SafeXcmVersion::::get() @@ -2608,6 +2608,12 @@ impl WrapVersion for Pallet { } } +impl GetVersion for Pallet { + fn get_version_for(dest: &MultiLocation) -> Option { + SupportedVersion::::get(XCM_VERSION, LatestVersionedMultiLocation(dest)) + } +} + impl VersionChangeNotifier for Pallet { /// Start notifying `location` should the XCM version of this chain change. /// diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index e7f5870c914..2443d3a9cac 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -655,6 +655,17 @@ pub(crate) fn buy_limited_execution( pub(crate) fn new_test_ext_with_balances( balances: Vec<(AccountId, Balance)>, +) -> sp_io::TestExternalities { + new_test_ext_with_balances_and_xcm_version( + balances, + // By default set actual latest XCM version + Some(XCM_VERSION), + ) +} + +pub(crate) fn new_test_ext_with_balances_and_xcm_version( + balances: Vec<(AccountId, Balance)>, + safe_xcm_version: Option, ) -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); @@ -662,7 +673,7 @@ pub(crate) fn new_test_ext_with_balances( .assimilate_storage(&mut t) .unwrap(); - pallet_xcm::GenesisConfig:: { safe_xcm_version: Some(2), ..Default::default() } + pallet_xcm::GenesisConfig:: { safe_xcm_version, ..Default::default() } .assimilate_storage(&mut t) .unwrap(); diff --git a/polkadot/xcm/pallet-xcm/src/tests/mod.rs b/polkadot/xcm/pallet-xcm/src/tests/mod.rs index 5829eb6edec..e7a6fdc9dce 100644 --- a/polkadot/xcm/pallet-xcm/src/tests/mod.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/mod.rs @@ -774,12 +774,13 @@ fn subscription_side_upgrades_work_without_notify() { #[test] fn subscriber_side_subscription_works() { - new_test_ext_with_balances(vec![]).execute_with(|| { + new_test_ext_with_balances_and_xcm_version(vec![], Some(XCM_VERSION)).execute_with(|| { let remote: MultiLocation = Parachain(1000).into(); assert_ok!(XcmPallet::force_subscribe_version_notify( RuntimeOrigin::root(), Box::new(remote.into()), )); + assert_eq!(XcmPallet::get_version_for(&remote), None); take_sent_xcm(); // Assume subscription target is working ok. @@ -798,6 +799,7 @@ fn subscriber_side_subscription_works() { let r = XcmExecutor::::execute_xcm(remote, message, hash, weight); assert_eq!(r, Outcome::Complete(weight)); assert_eq!(take_sent_xcm(), vec![]); + assert_eq!(XcmPallet::get_version_for(&remote), Some(1)); // This message cannot be sent to a v2 remote. let v2_msg = xcm::v2::Xcm::<()>(vec![xcm::v2::Instruction::Trap(0)]); @@ -815,6 +817,8 @@ fn subscriber_side_subscription_works() { let hash = fake_message_hash(&message); let r = XcmExecutor::::execute_xcm(remote, message, hash, weight); assert_eq!(r, Outcome::Complete(weight)); + assert_eq!(take_sent_xcm(), vec![]); + assert_eq!(XcmPallet::get_version_for(&remote), Some(2)); // This message can now be sent to remote as it's v2. assert_eq!( @@ -827,7 +831,7 @@ fn subscriber_side_subscription_works() { /// We should auto-subscribe when we don't know the remote's version. #[test] fn auto_subscription_works() { - new_test_ext_with_balances(vec![]).execute_with(|| { + new_test_ext_with_balances_and_xcm_version(vec![], None).execute_with(|| { let remote_v2: MultiLocation = Parachain(1000).into(); let remote_v3: MultiLocation = Parachain(1001).into(); @@ -995,3 +999,68 @@ fn subscription_side_upgrades_work_with_multistage_notify() { ); }); } + +#[test] +fn get_and_wrap_version_works() { + new_test_ext_with_balances_and_xcm_version(vec![], None).execute_with(|| { + let remote_a: MultiLocation = Parachain(1000).into(); + let remote_b: MultiLocation = Parachain(1001).into(); + let remote_c: MultiLocation = Parachain(1002).into(); + + // no `safe_xcm_version` version at `GenesisConfig` + assert_eq!(XcmPallet::get_version_for(&remote_a), None); + assert_eq!(XcmPallet::get_version_for(&remote_b), None); + assert_eq!(XcmPallet::get_version_for(&remote_c), None); + assert_eq!(VersionDiscoveryQueue::::get().into_inner(), vec![]); + + // set default XCM version (a.k.a. `safe_xcm_version`) + assert_ok!(XcmPallet::force_default_xcm_version(RuntimeOrigin::root(), Some(1))); + assert_eq!(XcmPallet::get_version_for(&remote_a), None); + assert_eq!(XcmPallet::get_version_for(&remote_b), None); + assert_eq!(XcmPallet::get_version_for(&remote_c), None); + assert_eq!(VersionDiscoveryQueue::::get().into_inner(), vec![]); + + // set XCM version only for `remote_a` + assert_ok!(XcmPallet::force_xcm_version( + RuntimeOrigin::root(), + Box::new(remote_a), + XCM_VERSION + )); + assert_eq!(XcmPallet::get_version_for(&remote_a), Some(XCM_VERSION)); + assert_eq!(XcmPallet::get_version_for(&remote_b), None); + assert_eq!(XcmPallet::get_version_for(&remote_c), None); + assert_eq!(VersionDiscoveryQueue::::get().into_inner(), vec![]); + + let xcm = Xcm::<()>::default(); + + // wrap version - works because remote_a has `XCM_VERSION` + assert_eq!( + XcmPallet::wrap_version(&remote_a, xcm.clone()), + Ok(VersionedXcm::from(xcm.clone())) + ); + // does not work because remote_b has unknown version and default is set to 1, and + // `XCM_VERSION` cannot be wrapped to the `1` + assert_eq!(XcmPallet::wrap_version(&remote_b, xcm.clone()), Err(())); + assert_eq!(VersionDiscoveryQueue::::get().into_inner(), vec![(remote_b.into(), 1)]); + + // set default to the `XCM_VERSION` + assert_ok!(XcmPallet::force_default_xcm_version(RuntimeOrigin::root(), Some(XCM_VERSION))); + assert_eq!(XcmPallet::get_version_for(&remote_b), None); + assert_eq!(XcmPallet::get_version_for(&remote_c), None); + + // now works, because default is `XCM_VERSION` + assert_eq!( + XcmPallet::wrap_version(&remote_b, xcm.clone()), + Ok(VersionedXcm::from(xcm.clone())) + ); + assert_eq!(VersionDiscoveryQueue::::get().into_inner(), vec![(remote_b.into(), 2)]); + + // change remote_c to `1` + assert_ok!(XcmPallet::force_xcm_version(RuntimeOrigin::root(), Box::new(remote_c), 1)); + + // does not work because remote_c has `1` and default is `XCM_VERSION` which cannot be + // wrapped to the `1` + assert_eq!(XcmPallet::wrap_version(&remote_c, xcm.clone()), Err(())); + assert_eq!(VersionDiscoveryQueue::::get().into_inner(), vec![(remote_b.into(), 2)]); + }) +} diff --git a/polkadot/xcm/src/lib.rs b/polkadot/xcm/src/lib.rs index d804e4bf735..ddad0b5303b 100644 --- a/polkadot/xcm/src/lib.rs +++ b/polkadot/xcm/src/lib.rs @@ -373,6 +373,12 @@ pub trait WrapVersion { ) -> Result, ()>; } +/// Check and return the `Version` that should be used for the `Xcm` datum for the destination +/// `MultiLocation`, which will interpret it. +pub trait GetVersion { + fn get_version_for(dest: &latest::MultiLocation) -> Option; +} + /// `()` implementation does nothing with the XCM, just sending with whatever version it was /// authored as. impl WrapVersion for () { @@ -395,6 +401,11 @@ impl WrapVersion for AlwaysV2 { Ok(VersionedXcm::::V2(xcm.into().try_into()?)) } } +impl GetVersion for AlwaysV2 { + fn get_version_for(_dest: &latest::MultiLocation) -> Option { + Some(v2::VERSION) + } +} /// `WrapVersion` implementation which attempts to always convert the XCM to version 3 before /// wrapping it. @@ -407,6 +418,11 @@ impl WrapVersion for AlwaysV3 { Ok(VersionedXcm::::V3(xcm.into().try_into()?)) } } +impl GetVersion for AlwaysV3 { + fn get_version_for(_dest: &latest::MultiLocation) -> Option { + Some(v3::VERSION) + } +} /// `WrapVersion` implementation which attempts to always convert the XCM to the latest version /// before wrapping it. @@ -418,8 +434,8 @@ pub type AlwaysLts = AlwaysV3; pub mod prelude { pub use super::{ - latest::prelude::*, AlwaysLatest, AlwaysLts, AlwaysV2, AlwaysV3, IntoVersion, Unsupported, - Version as XcmVersion, VersionedAssetId, VersionedInteriorMultiLocation, + latest::prelude::*, AlwaysLatest, AlwaysLts, AlwaysV2, AlwaysV3, GetVersion, IntoVersion, + Unsupported, Version as XcmVersion, VersionedAssetId, VersionedInteriorMultiLocation, VersionedMultiAsset, VersionedMultiAssets, VersionedMultiLocation, VersionedResponse, VersionedXcm, WrapVersion, }; diff --git a/polkadot/xcm/xcm-builder/src/tests/bridging/local_para_para.rs b/polkadot/xcm/xcm-builder/src/tests/bridging/local_para_para.rs index de08dbee953..b1361cc8577 100644 --- a/polkadot/xcm/xcm-builder/src/tests/bridging/local_para_para.rs +++ b/polkadot/xcm/xcm-builder/src/tests/bridging/local_para_para.rs @@ -23,11 +23,16 @@ use super::*; parameter_types! { pub UniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(1)); pub RemoteUniversalLocation: Junctions = X2(GlobalConsensus(Remote::get()), Parachain(1)); + pub RemoteNetwork: MultiLocation = AncestorThen(2, GlobalConsensus(Remote::get())).into(); } type TheBridge = TestBridge>; -type Router = - TestTopic, UniversalLocation>>; +type Router = TestTopic< + UnpaidLocalExporter< + HaulBlobExporter, + UniversalLocation, + >, +>; /// ```nocompile /// local | remote diff --git a/polkadot/xcm/xcm-builder/src/tests/bridging/local_relay_relay.rs b/polkadot/xcm/xcm-builder/src/tests/bridging/local_relay_relay.rs index 8433b6e0212..5371abccf66 100644 --- a/polkadot/xcm/xcm-builder/src/tests/bridging/local_relay_relay.rs +++ b/polkadot/xcm/xcm-builder/src/tests/bridging/local_relay_relay.rs @@ -23,11 +23,16 @@ use super::*; parameter_types! { pub UniversalLocation: Junctions = X1(GlobalConsensus(Local::get())); pub RemoteUniversalLocation: Junctions = X1(GlobalConsensus(Remote::get())); + pub RemoteNetwork: MultiLocation = AncestorThen(1, GlobalConsensus(Remote::get())).into(); } type TheBridge = TestBridge>; -type Router = - TestTopic, UniversalLocation>>; +type Router = TestTopic< + UnpaidLocalExporter< + HaulBlobExporter, + UniversalLocation, + >, +>; /// ```nocompile /// local | remote diff --git a/polkadot/xcm/xcm-builder/src/tests/bridging/mod.rs b/polkadot/xcm/xcm-builder/src/tests/bridging/mod.rs index 45630dbfc24..0c749b66da6 100644 --- a/polkadot/xcm/xcm-builder/src/tests/bridging/mod.rs +++ b/polkadot/xcm/xcm-builder/src/tests/bridging/mod.rs @@ -20,6 +20,7 @@ use super::mock::*; use crate::{universal_exports::*, WithTopicSource}; use frame_support::{parameter_types, traits::Get}; use std::{cell::RefCell, marker::PhantomData}; +use xcm::AlwaysLatest; use xcm_executor::{ traits::{export_xcm, validate_export}, XcmExecutor, diff --git a/polkadot/xcm/xcm-builder/src/tests/bridging/paid_remote_relay_relay.rs b/polkadot/xcm/xcm-builder/src/tests/bridging/paid_remote_relay_relay.rs index 23d6eb99a90..079eb0175d7 100644 --- a/polkadot/xcm/xcm-builder/src/tests/bridging/paid_remote_relay_relay.rs +++ b/polkadot/xcm/xcm-builder/src/tests/bridging/paid_remote_relay_relay.rs @@ -30,6 +30,7 @@ parameter_types! { pub UniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(100)); pub RelayUniversalLocation: Junctions = X1(GlobalConsensus(Local::get())); pub RemoteUniversalLocation: Junctions = X1(GlobalConsensus(Remote::get())); + pub RemoteNetwork: MultiLocation = AncestorThen(1, GlobalConsensus(Remote::get())).into(); pub BridgeTable: Vec = vec![ NetworkExportTableItem::new( Remote::get(), @@ -41,7 +42,7 @@ parameter_types! { } type TheBridge = TestBridge>; -type RelayExporter = HaulBlobExporter; +type RelayExporter = HaulBlobExporter; type LocalInnerRouter = ExecutingRouter; type LocalBridgeRouter = SovereignPaidRemoteExporter< NetworkExportTable, diff --git a/polkadot/xcm/xcm-builder/src/tests/bridging/remote_para_para.rs b/polkadot/xcm/xcm-builder/src/tests/bridging/remote_para_para.rs index f11143ab9f6..fb6c5da3eb0 100644 --- a/polkadot/xcm/xcm-builder/src/tests/bridging/remote_para_para.rs +++ b/polkadot/xcm/xcm-builder/src/tests/bridging/remote_para_para.rs @@ -24,6 +24,7 @@ parameter_types! { pub UniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(1000)); pub ParaBridgeUniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(1)); pub RemoteParaBridgeUniversalLocation: Junctions = X2(GlobalConsensus(Remote::get()), Parachain(1)); + pub RemoteNetwork: MultiLocation = AncestorThen(2, GlobalConsensus(Remote::get())).into(); pub BridgeTable: Vec = vec![ NetworkExportTableItem::new( Remote::get(), @@ -36,7 +37,7 @@ parameter_types! { type TheBridge = TestBridge< BridgeBlobDispatcher, >; -type RelayExporter = HaulBlobExporter; +type RelayExporter = HaulBlobExporter; type LocalInnerRouter = UnpaidExecutingRouter; type LocalBridgingRouter = diff --git a/polkadot/xcm/xcm-builder/src/tests/bridging/remote_para_para_via_relay.rs b/polkadot/xcm/xcm-builder/src/tests/bridging/remote_para_para_via_relay.rs index 7218e0a0488..0b6dc01e2bf 100644 --- a/polkadot/xcm/xcm-builder/src/tests/bridging/remote_para_para_via_relay.rs +++ b/polkadot/xcm/xcm-builder/src/tests/bridging/remote_para_para_via_relay.rs @@ -24,6 +24,7 @@ parameter_types! { pub UniversalLocation: Junctions = X1(GlobalConsensus(Local::get())); pub ParaBridgeUniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(1)); pub RemoteParaBridgeUniversalLocation: Junctions = X2(GlobalConsensus(Remote::get()), Parachain(1)); + pub RemoteNetwork: MultiLocation = AncestorThen(2, GlobalConsensus(Remote::get())).into(); pub BridgeTable: Vec = vec![ NetworkExportTableItem::new( Remote::get(), @@ -36,7 +37,7 @@ parameter_types! { type TheBridge = TestBridge< BridgeBlobDispatcher, >; -type RelayExporter = HaulBlobExporter; +type RelayExporter = HaulBlobExporter; type LocalInnerRouter = UnpaidExecutingRouter; type LocalBridgingRouter = diff --git a/polkadot/xcm/xcm-builder/src/tests/bridging/remote_relay_relay.rs b/polkadot/xcm/xcm-builder/src/tests/bridging/remote_relay_relay.rs index 45b5efbc44c..e33c7b15b0a 100644 --- a/polkadot/xcm/xcm-builder/src/tests/bridging/remote_relay_relay.rs +++ b/polkadot/xcm/xcm-builder/src/tests/bridging/remote_relay_relay.rs @@ -24,6 +24,7 @@ parameter_types! { pub UniversalLocation: Junctions = X2(GlobalConsensus(Local::get()), Parachain(1000)); pub RelayUniversalLocation: Junctions = X1(GlobalConsensus(Local::get())); pub RemoteUniversalLocation: Junctions = X1(GlobalConsensus(Remote::get())); + pub RemoteNetwork: MultiLocation = AncestorThen(1, GlobalConsensus(Remote::get())).into(); pub BridgeTable: Vec = vec![ NetworkExportTableItem::new( Remote::get(), @@ -35,7 +36,7 @@ parameter_types! { } type TheBridge = TestBridge>; -type RelayExporter = HaulBlobExporter; +type RelayExporter = HaulBlobExporter; type LocalInnerRouter = UnpaidExecutingRouter; type LocalBridgeRouter = diff --git a/polkadot/xcm/xcm-builder/src/universal_exports.rs b/polkadot/xcm/xcm-builder/src/universal_exports.rs index 8e2cf88b3c3..4aa6a0ef7a5 100644 --- a/polkadot/xcm/xcm-builder/src/universal_exports.rs +++ b/polkadot/xcm/xcm-builder/src/universal_exports.rs @@ -422,11 +422,25 @@ impl< } } -pub struct HaulBlobExporter( - PhantomData<(Bridge, BridgedNetwork, Price)>, +pub struct HaulBlobExporter( + PhantomData<(Bridge, BridgedNetwork, DestinationVersion, Price)>, ); -impl, Price: Get> ExportXcm - for HaulBlobExporter +/// `ExportXcm` implementation for `HaulBlobExporter`. +/// +/// # Type Parameters +/// +/// ```text +/// - Bridge: Implements `HaulBlob`. +/// - BridgedNetwork: The relative location of the bridged consensus system with the expected `GlobalConsensus` junction. +/// - DestinationVersion: Implements `GetVersion` for retrieving XCM version for the destination. +/// - Price: potential fees for exporting. +/// ``` +impl< + Bridge: HaulBlob, + BridgedNetwork: Get, + DestinationVersion: GetVersion, + Price: Get, + > ExportXcm for HaulBlobExporter { type Ticket = (Vec, XcmHash); @@ -437,17 +451,35 @@ impl, Price: Get> destination: &mut Option, message: &mut Option>, ) -> Result<((Vec, XcmHash), MultiAssets), SendError> { - let bridged_network = BridgedNetwork::get(); + let (bridged_network, bridged_network_location_parents) = { + let MultiLocation { parents, interior: mut junctions } = BridgedNetwork::get(); + match junctions.take_first() { + Some(GlobalConsensus(network)) => (network, parents), + _ => return Err(SendError::NotApplicable), + } + }; ensure!(&network == &bridged_network, SendError::NotApplicable); // We don't/can't use the `channel` for this adapter. let dest = destination.take().ok_or(SendError::MissingArgument)?; - let universal_dest = match dest.pushed_front_with(GlobalConsensus(bridged_network)) { - Ok(d) => d.into(), - Err((dest, _)) => { - *destination = Some(dest); - return Err(SendError::NotApplicable) - }, - }; + + // Let's resolve the known/supported XCM version for the destination because we don't know + // if it supports the same/latest version. + let (universal_dest, version) = + match dest.pushed_front_with(GlobalConsensus(bridged_network)) { + Ok(d) => { + let version = DestinationVersion::get_version_for(&MultiLocation::from( + AncestorThen(bridged_network_location_parents, d), + )) + .ok_or(SendError::DestinationUnsupported)?; + (d, version) + }, + Err((dest, _)) => { + *destination = Some(dest); + return Err(SendError::NotApplicable) + }, + }; + + // Let's adjust XCM with `UniversalOrigin`, `DescendOrigin` and`SetTopic`. let (local_net, local_sub) = universal_source .take() .ok_or(SendError::MissingArgument)? @@ -462,7 +494,17 @@ impl, Price: Get> if local_sub != Here { message.0.insert(1, DescendOrigin(local_sub)); } - let message = VersionedXcm::from(message); + + // We cannot use the latest `Versioned` because we don't know if the target chain already + // supports the same version. Therefore, we better control the destination version with best + // efforts. + let message = VersionedXcm::from(message) + .into_version(version) + .map_err(|()| SendError::DestinationUnsupported)?; + let universal_dest = VersionedInteriorMultiLocation::from(universal_dest) + .into_version(version) + .map_err(|()| SendError::DestinationUnsupported)?; + let id = maybe_id.unwrap_or_else(|| message.using_encoded(sp_io::hashing::blake2_256)); let blob = BridgeMessage { universal_dest, message }.encode(); Ok(((blob, id), Price::get())) diff --git a/prdoc/pr_2481.prdoc b/prdoc/pr_2481.prdoc new file mode 100644 index 00000000000..d8736b1afd6 --- /dev/null +++ b/prdoc/pr_2481.prdoc @@ -0,0 +1,13 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "xcm-builder: `HaulBlobExporter` with improved XCM version check." + +doc: + - audience: Runtime Dev + description: | + Version check in `HaulBlobExporter` uses new trait `CheckVersion` to check known/configured destination versions, + ensuring compatibility. `HaulBlobExporter` will attempt to downgrade the message to destination's known version + instead of using the latest version. + +crates: [ ] -- GitLab From 313b2c4b6e0e7e262392294f710bc5d864a6d017 Mon Sep 17 00:00:00 2001 From: Francisco Aguirre Date: Tue, 12 Dec 2023 17:36:24 +0100 Subject: [PATCH 45/59] Fix ParentOrSiblings (#2428) We were not filtering for sibling parachains, but for sibling anything --------- Co-authored-by: Branislav Kontur Co-authored-by: command-bot <> --- cumulus/parachains/common/src/xcm_config.rs | 15 +++++++++++++++ .../assets/asset-hub-rococo/src/xcm_config.rs | 8 ++------ .../bridge-hub-rococo/src/xcm_config.rs | 9 +++------ .../bridge-hub-westend/src/xcm_config.rs | 9 +++------ .../collectives-westend/src/xcm_config.rs | 9 +++------ .../contracts/contracts-rococo/src/xcm_config.rs | 9 +++------ 6 files changed, 29 insertions(+), 30 deletions(-) diff --git a/cumulus/parachains/common/src/xcm_config.rs b/cumulus/parachains/common/src/xcm_config.rs index 97dc47cb028..7a63e720b07 100644 --- a/cumulus/parachains/common/src/xcm_config.rs +++ b/cumulus/parachains/common/src/xcm_config.rs @@ -139,6 +139,21 @@ impl> ContainsPair } } +/// Filter to check if a given location is the parent Relay Chain or a sibling parachain. +/// +/// This type should only be used within the context of a parachain, since it does not verify that +/// the parent is indeed a Relay Chain. +pub struct ParentRelayOrSiblingParachains; +impl Contains for ParentRelayOrSiblingParachains { + fn contains(location: &MultiLocation) -> bool { + matches!( + location, + MultiLocation { parents: 1, interior: Here } | + MultiLocation { parents: 1, interior: X1(Parachain(_)) } + ) + } +} + #[cfg(test)] mod tests { use frame_support::{parameter_types, traits::Contains}; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index 4b47aded28f..001f2af19fe 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -33,7 +33,7 @@ use parachains_common::{ impls::ToStakingPot, xcm_config::{ AllSiblingSystemParachains, AssetFeeAsExistentialDepositMultiplier, - ConcreteAssetFromSystem, RelayOrOtherSystemParachains, + ConcreteAssetFromSystem, ParentRelayOrSiblingParachains, RelayOrOtherSystemParachains, }, TREASURY_PALLET_ID, }; @@ -238,10 +238,6 @@ match_types! { MultiLocation { parents: 1, interior: Here } | MultiLocation { parents: 1, interior: X1(Plurality { .. }) } }; - pub type ParentOrSiblings: impl Contains = { - MultiLocation { parents: 1, interior: Here } | - MultiLocation { parents: 1, interior: X1(_) } - }; } /// A call filter for the XCM Transact instruction. This is a temporary measure until we properly @@ -486,7 +482,7 @@ pub type Barrier = TrailingSetTopicAsId< Equals, )>, // Subscriptions for version tracking are OK. - AllowSubscriptionsFrom, + AllowSubscriptionsFrom, ), UniversalLocation, ConstU32<8>, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs index 8092bd16120..bb88c0717b2 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs @@ -34,7 +34,8 @@ use pallet_xcm::XcmPassthrough; use parachains_common::{ impls::ToStakingPot, xcm_config::{ - AllSiblingSystemParachains, ConcreteAssetFromSystem, RelayOrOtherSystemParachains, + AllSiblingSystemParachains, ConcreteAssetFromSystem, ParentRelayOrSiblingParachains, + RelayOrOtherSystemParachains, }, TREASURY_PALLET_ID, }; @@ -126,10 +127,6 @@ match_types! { MultiLocation { parents: 1, interior: Here } | MultiLocation { parents: 1, interior: X1(Plurality { .. }) } }; - pub type ParentOrSiblings: impl Contains = { - MultiLocation { parents: 1, interior: Here } | - MultiLocation { parents: 1, interior: X1(_) } - }; } /// A call filter for the XCM Transact instruction. This is a temporary measure until we properly @@ -212,7 +209,7 @@ pub type Barrier = TrailingSetTopicAsId< Equals, )>, // Subscriptions for version tracking are OK. - AllowSubscriptionsFrom, + AllowSubscriptionsFrom, ), UniversalLocation, ConstU32<8>, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs index 009b17a4675..af3ec500f15 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs @@ -29,7 +29,8 @@ use pallet_xcm::XcmPassthrough; use parachains_common::{ impls::ToStakingPot, xcm_config::{ - AllSiblingSystemParachains, ConcreteAssetFromSystem, RelayOrOtherSystemParachains, + AllSiblingSystemParachains, ConcreteAssetFromSystem, ParentRelayOrSiblingParachains, + RelayOrOtherSystemParachains, }, TREASURY_PALLET_ID, }; @@ -115,10 +116,6 @@ match_types! { MultiLocation { parents: 1, interior: Here } | MultiLocation { parents: 1, interior: X1(Plurality { .. }) } }; - pub type ParentOrSiblings: impl Contains = { - MultiLocation { parents: 1, interior: Here } | - MultiLocation { parents: 1, interior: X1(_) } - }; } /// A call filter for the XCM Transact instruction. This is a temporary measure until we properly @@ -201,7 +198,7 @@ pub type Barrier = TrailingSetTopicAsId< Equals, )>, // Subscriptions for version tracking are OK. - AllowSubscriptionsFrom, + AllowSubscriptionsFrom, ), UniversalLocation, ConstU32<8>, diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs index 9b5b709ab82..c74b111ce2c 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs @@ -28,7 +28,8 @@ use pallet_xcm::XcmPassthrough; use parachains_common::{ impls::ToStakingPot, xcm_config::{ - AllSiblingSystemParachains, ConcreteAssetFromSystem, RelayOrOtherSystemParachains, + AllSiblingSystemParachains, ConcreteAssetFromSystem, ParentRelayOrSiblingParachains, + RelayOrOtherSystemParachains, }, }; use polkadot_parachain_primitives::primitives::Sibling; @@ -137,10 +138,6 @@ match_types! { MultiLocation { parents: 1, interior: Here } | MultiLocation { parents: 1, interior: X1(Plurality { .. }) } }; - pub type ParentOrSiblings: impl Contains = { - MultiLocation { parents: 1, interior: Here } | - MultiLocation { parents: 1, interior: X1(_) } - }; } /// A call filter for the XCM Transact instruction. This is a temporary measure until we properly @@ -242,7 +239,7 @@ pub type Barrier = TrailingSetTopicAsId< // Parent and its pluralities (i.e. governance bodies) get free execution. AllowExplicitUnpaidExecutionFrom, // Subscriptions for version tracking are OK. - AllowSubscriptionsFrom, + AllowSubscriptionsFrom, ), UniversalLocation, ConstU32<8>, diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs index a11c477cc01..e49ec64db92 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs @@ -28,7 +28,8 @@ use frame_system::EnsureRoot; use pallet_xcm::{EnsureXcm, IsMajorityOfBody, XcmPassthrough}; use parachains_common::{ xcm_config::{ - AllSiblingSystemParachains, ConcreteAssetFromSystem, RelayOrOtherSystemParachains, + AllSiblingSystemParachains, ConcreteAssetFromSystem, ParentRelayOrSiblingParachains, + RelayOrOtherSystemParachains, }, TREASURY_PALLET_ID, }; @@ -124,10 +125,6 @@ match_types! { MultiLocation { parents: 1, interior: Here } | MultiLocation { parents: 1, interior: X1(Plurality { .. }) } }; - pub type ParentOrSiblings: impl Contains = { - MultiLocation { parents: 1, interior: Here } | - MultiLocation { parents: 1, interior: X1(_) } - }; } pub type Barrier = TrailingSetTopicAsId< @@ -150,7 +147,7 @@ pub type Barrier = TrailingSetTopicAsId< Equals, )>, // Subscriptions for version tracking are OK. - AllowSubscriptionsFrom, + AllowSubscriptionsFrom, ), UniversalLocation, ConstU32<8>, -- GitLab From d43d2fe23b12355eed4afa6dd3e971a248269262 Mon Sep 17 00:00:00 2001 From: Egor_P Date: Tue, 12 Dec 2023 17:51:54 +0100 Subject: [PATCH 46/59] Update prdoc (#2697) Small update of the title in one of the prdoc files --- prdoc/1.5.0/pr_2625_special.prdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prdoc/1.5.0/pr_2625_special.prdoc b/prdoc/1.5.0/pr_2625_special.prdoc index 21803d93dca..3ffcf598660 100644 --- a/prdoc/1.5.0/pr_2625_special.prdoc +++ b/prdoc/1.5.0/pr_2625_special.prdoc @@ -1,4 +1,4 @@ -title: Bridges update subtree +title: Improved `ExportXcm::validate` implementation for BridgeHubs author: bkontur topic: bridges -- GitLab From 0470bd6851bbf7d1a4af593ede35d9a628510150 Mon Sep 17 00:00:00 2001 From: Parth Date: Tue, 12 Dec 2023 23:50:08 +0400 Subject: [PATCH 47/59] Make crate visible methods of `OverlayedChanges` public (#2597) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description - What does this PR do? This PR make some methods of `OverlayedChanges` public which were previously only visible in same crate. - Why are these changes needed? Since, some methods of the `OverlayedChanges` only have crate level visibility, which makes `OverlayedChanges` somewhat unusable outside the crate to create custom implementation of `Externalities`. We make those method public to enable `OverlayedChanges` to remedy this. - How were these changes implemented and what do they affect? Changes are implemented by replacing crate visibility to public visibility of 4 functions. # Checklist - [x] My PR includes a detailed description as outlined in the "Description" section above - [ ] My PR follows the [labeling requirements](CONTRIBUTING.md#Process) of this project (at minimum one label for `T` required) - [ ] I have made corresponding changes to the documentation (if applicable) - [ ] I have added tests that prove my fix is effective or that my feature works (if applicable) --------- Co-authored-by: Bastian Köcher --- prdoc/pr_2597.prdoc | 17 +++++++++++++++++ .../state-machine/src/overlayed_changes/mod.rs | 8 ++++---- 2 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 prdoc/pr_2597.prdoc diff --git a/prdoc/pr_2597.prdoc b/prdoc/pr_2597.prdoc new file mode 100644 index 00000000000..33d85053184 --- /dev/null +++ b/prdoc/pr_2597.prdoc @@ -0,0 +1,17 @@ +title: Make crate visible methods of `OverlayedChanges` public. + +doc: + - audience: Node Dev + description: | + Make some methods of `OverlayedChanges` namely `set_child_storage`, `clear_child_storage`, `clear_prefix` + and `clear_child_prefix` public which only had crate level visibility. + +migrations: + db: [] + + runtime: [] + +crates: + - name: sp-state-machine + +host_functions: [] diff --git a/substrate/primitives/state-machine/src/overlayed_changes/mod.rs b/substrate/primitives/state-machine/src/overlayed_changes/mod.rs index 9525c2c9dfe..626cf6c3caf 100644 --- a/substrate/primitives/state-machine/src/overlayed_changes/mod.rs +++ b/substrate/primitives/state-machine/src/overlayed_changes/mod.rs @@ -348,7 +348,7 @@ impl OverlayedChanges { /// `None` can be used to delete a value specified by the given key. /// /// Can be rolled back or committed when called inside a transaction. - pub(crate) fn set_child_storage( + pub fn set_child_storage( &mut self, child_info: &ChildInfo, key: StorageKey, @@ -373,7 +373,7 @@ impl OverlayedChanges { /// Clear child storage of given storage key. /// /// Can be rolled back or committed when called inside a transaction. - pub(crate) fn clear_child_storage(&mut self, child_info: &ChildInfo) -> u32 { + pub fn clear_child_storage(&mut self, child_info: &ChildInfo) -> u32 { self.mark_dirty(); let extrinsic_index = self.extrinsic_index(); @@ -391,7 +391,7 @@ impl OverlayedChanges { /// Removes all key-value pairs which keys share the given prefix. /// /// Can be rolled back or committed when called inside a transaction. - pub(crate) fn clear_prefix(&mut self, prefix: &[u8]) -> u32 { + pub fn clear_prefix(&mut self, prefix: &[u8]) -> u32 { self.mark_dirty(); self.top.clear_where(|key, _| key.starts_with(prefix), self.extrinsic_index()) @@ -400,7 +400,7 @@ impl OverlayedChanges { /// Removes all key-value pairs which keys share the given prefix. /// /// Can be rolled back or committed when called inside a transaction - pub(crate) fn clear_child_prefix(&mut self, child_info: &ChildInfo, prefix: &[u8]) -> u32 { + pub fn clear_child_prefix(&mut self, child_info: &ChildInfo, prefix: &[u8]) -> u32 { self.mark_dirty(); let extrinsic_index = self.extrinsic_index(); -- GitLab From d18a682bf710fb3ce2ca21b186fb4e449e9ae857 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Tue, 12 Dec 2023 21:01:36 +0100 Subject: [PATCH 48/59] [ci] Add `-D warnings` for `cargo-check-each-crate` job to fail on warnings (#2670) ## Summary This PR turns on `-D warnings` for `cargo-check-each-crate job` job to fail on warnings e.g. like this: https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/4673130 Before this PR, there was a warning and `cargo-check-each-crate` job did not fail: https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/4641444 ``` warning: unused import: `ToTokens` --> substrate/primitives/api/proc-macro/src/utils.rs:22:34 | 22 | use quote::{format_ident, quote, ToTokens}; | ^^^^^^^^ | = note: `#[warn(unused_imports)]` on by default warning: `sp-api-proc-macro` (lib) generated 1 warning (run `cargo fix --lib -p sp-api-proc-macro` to apply 1 suggestion) ``` Fixes on the way: https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/4641444 https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/4673265 https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/4673410 https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/4673681 https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/4673836 https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/4673941 https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/4674256 https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/4679328 ## Questions - [ ] why does this check triggers only `cargo check --locked`? `--all-features` or `--all-targets` are not needed? Or aren't they avoided intentionally? --------- Co-authored-by: command-bot <> --- .gitlab/pipeline/test.yml | 1 + substrate/client/network/src/behaviour.rs | 2 +- substrate/client/network/src/protocol/message.rs | 4 ---- .../client/network/src/protocol/notifications/upgrade.rs | 8 +++++--- substrate/client/offchain/src/api.rs | 1 - substrate/client/transaction-pool/src/graph/mod.rs | 5 +---- substrate/frame/contracts/proc-macro/src/lib.rs | 2 +- substrate/primitives/api/proc-macro/src/utils.rs | 3 ++- substrate/primitives/state-machine/src/lib.rs | 1 - 9 files changed, 11 insertions(+), 16 deletions(-) diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index f6dad887a68..0e7d96f3dba 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -438,6 +438,7 @@ cargo-check-each-crate: - .run-immediately # - .collect-artifacts variables: + RUSTFLAGS: "-D warnings" # $CI_JOB_NAME is set manually so that cache could be shared for all jobs # "cargo-check-each-crate I/N" jobs CI_JOB_NAME: cargo-check-each-crate diff --git a/substrate/client/network/src/behaviour.rs b/substrate/client/network/src/behaviour.rs index 9f770bc3ba7..745550412fc 100644 --- a/substrate/client/network/src/behaviour.rs +++ b/substrate/client/network/src/behaviour.rs @@ -39,7 +39,7 @@ use parking_lot::Mutex; use sp_runtime::traits::Block as BlockT; use std::{collections::HashSet, sync::Arc, time::Duration}; -pub use crate::request_responses::{InboundFailure, OutboundFailure, RequestId, ResponseFailure}; +pub use crate::request_responses::{InboundFailure, OutboundFailure, ResponseFailure}; /// General behaviour of the network. Combines all protocols together. #[derive(NetworkBehaviour)] diff --git a/substrate/client/network/src/protocol/message.rs b/substrate/client/network/src/protocol/message.rs index 247580083f9..5f2511fd6dd 100644 --- a/substrate/client/network/src/protocol/message.rs +++ b/substrate/client/network/src/protocol/message.rs @@ -19,10 +19,6 @@ //! Network packet message types. These get serialized and put into the lower level protocol //! payload. -pub use self::generic::{ - RemoteCallRequest, RemoteChangesRequest, RemoteChangesResponse, RemoteHeaderRequest, - RemoteHeaderResponse, RemoteReadChildRequest, RemoteReadRequest, -}; use codec::{Decode, Encode}; use sc_client_api::StorageProof; use sc_network_common::message::RequestId; diff --git a/substrate/client/network/src/protocol/notifications/upgrade.rs b/substrate/client/network/src/protocol/notifications/upgrade.rs index 70c6023623f..8fd837f949d 100644 --- a/substrate/client/network/src/protocol/notifications/upgrade.rs +++ b/substrate/client/network/src/protocol/notifications/upgrade.rs @@ -16,12 +16,14 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +#[cfg(test)] +pub(crate) use self::notifications::{ + NotificationsInOpen, NotificationsInSubstreamHandshake, NotificationsOutOpen, +}; pub use self::{ collec::UpgradeCollec, notifications::{ - NotificationsHandshakeError, NotificationsIn, NotificationsInOpen, - NotificationsInSubstream, NotificationsInSubstreamHandshake, NotificationsOut, - NotificationsOutError, NotificationsOutOpen, NotificationsOutSubstream, + NotificationsIn, NotificationsInSubstream, NotificationsOut, NotificationsOutSubstream, }, }; diff --git a/substrate/client/offchain/src/api.rs b/substrate/client/offchain/src/api.rs index 40f866b6d28..65e2f3ba64d 100644 --- a/substrate/client/offchain/src/api.rs +++ b/substrate/client/offchain/src/api.rs @@ -30,7 +30,6 @@ use sp_core::{ }, OpaquePeerId, }; -pub use sp_offchain::STORAGE_PREFIX; mod http; diff --git a/substrate/client/transaction-pool/src/graph/mod.rs b/substrate/client/transaction-pool/src/graph/mod.rs index 5afdddb7402..484a6d6cf9f 100644 --- a/substrate/client/transaction-pool/src/graph/mod.rs +++ b/substrate/client/transaction-pool/src/graph/mod.rs @@ -39,9 +39,6 @@ pub mod watcher; pub use self::{ base_pool::Transaction, - pool::{ - BlockHash, ChainApi, EventStream, ExtrinsicFor, ExtrinsicHash, NumberFor, Options, Pool, - TransactionFor, - }, + pool::{BlockHash, ChainApi, ExtrinsicFor, ExtrinsicHash, NumberFor, Options, Pool}, }; pub use validated_pool::{IsValidator, ValidatedTransaction}; diff --git a/substrate/frame/contracts/proc-macro/src/lib.rs b/substrate/frame/contracts/proc-macro/src/lib.rs index 4ef02497b8e..9dc34d5223b 100644 --- a/substrate/frame/contracts/proc-macro/src/lib.rs +++ b/substrate/frame/contracts/proc-macro/src/lib.rs @@ -74,7 +74,7 @@ fn derive_debug(input: TokenStream, fmt: impl Fn(&Ident) -> TokenStream2) -> Tok #[cfg(not(feature = "full"))] let fields = { drop(fmt); - drop(data); + let _ = data; TokenStream2::new() }; diff --git a/substrate/primitives/api/proc-macro/src/utils.rs b/substrate/primitives/api/proc-macro/src/utils.rs index 68f0a77a399..c8c1f12d90a 100644 --- a/substrate/primitives/api/proc-macro/src/utils.rs +++ b/substrate/primitives/api/proc-macro/src/utils.rs @@ -19,7 +19,7 @@ use crate::common::API_VERSION_ATTRIBUTE; use inflector::Inflector; use proc_macro2::{Span, TokenStream}; use proc_macro_crate::{crate_name, FoundCrate}; -use quote::{format_ident, quote, ToTokens}; +use quote::{format_ident, quote}; use syn::{ parse_quote, spanned::Spanned, token::And, Attribute, Error, FnArg, GenericArgument, Ident, ImplItem, ItemImpl, Pat, Path, PathArguments, Result, ReturnType, Signature, Type, TypePath, @@ -261,6 +261,7 @@ pub fn versioned_trait_name(trait_ident: &Ident, version: u64) -> Ident { /// Extract the documentation from the provided attributes. #[cfg(feature = "frame-metadata")] pub fn get_doc_literals(attrs: &[syn::Attribute]) -> Vec { + use quote::ToTokens; attrs .iter() .filter_map(|attr| { diff --git a/substrate/primitives/state-machine/src/lib.rs b/substrate/primitives/state-machine/src/lib.rs index 1345097e8f6..5909a30a814 100644 --- a/substrate/primitives/state-machine/src/lib.rs +++ b/substrate/primitives/state-machine/src/lib.rs @@ -142,7 +142,6 @@ pub use crate::{ mod std_reexport { pub use crate::{ basic::BasicExternalities, - error::{Error, ExecutionError}, in_memory_backend::new_in_mem, read_only::{InspectState, ReadOnlyExternalities}, testing::TestExternalities, -- GitLab From a84dd0dba58d51503b8942360aa4fb30a5a96af5 Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe <49718502+alexggh@users.noreply.github.com> Date: Wed, 13 Dec 2023 08:43:15 +0200 Subject: [PATCH 49/59] Approve multiple candidates with a single signature (#1191) Initial implementation for the plan discussed here: https://github.com/paritytech/polkadot-sdk/issues/701 Built on top of https://github.com/paritytech/polkadot-sdk/pull/1178 v0: https://github.com/paritytech/polkadot/pull/7554, ## Overall idea When approval-voting checks a candidate and is ready to advertise the approval, defer it in a per-relay chain block until we either have MAX_APPROVAL_COALESCE_COUNT candidates to sign or a candidate has stayed MAX_APPROVALS_COALESCE_TICKS in the queue, in both cases we sign what candidates we have available. This should allow us to reduce the number of approvals messages we have to create/send/verify. The parameters are configurable, so we should find some values that balance: - Security of the network: Delaying broadcasting of an approval shouldn't but the finality at risk and to make sure that never happens we won't delay sending a vote if we are past 2/3 from the no-show time. - Scalability of the network: MAX_APPROVAL_COALESCE_COUNT = 1 & MAX_APPROVALS_COALESCE_TICKS =0, is what we have now and we know from the measurements we did on versi, it bottlenecks approval-distribution/approval-voting when increase significantly the number of validators and parachains - Block storage: In case of disputes we have to import this votes on chain and that increase the necessary storage with MAX_APPROVAL_COALESCE_COUNT * CandidateHash per vote. Given that disputes are not the normal way of the network functioning and we will limit MAX_APPROVAL_COALESCE_COUNT in the single digits numbers, this should be good enough. Alternatively, we could try to create a better way to store this on-chain through indirection, if that's needed. ## Other fixes: - Fixed the fact that we were sending random assignments to non-validators, that was wrong because those won't do anything with it and they won't gossip it either because they do not have a grid topology set, so we would waste the random assignments. - Added metrics to be able to debug potential no-shows and mis-processing of approvals/assignments. ## TODO: - [x] Get feedback, that this is moving in the right direction. @ordian @sandreim @eskimor @burdges, let me know what you think. - [x] More and more testing. - [x] Test in versi. - [x] Make MAX_APPROVAL_COALESCE_COUNT & MAX_APPROVAL_COALESCE_WAIT_MILLIS a parachain host configuration. - [x] Make sure the backwards compatibility works correctly - [x] Make sure this direction is compatible with other streams of work: https://github.com/paritytech/polkadot-sdk/issues/635 & https://github.com/paritytech/polkadot-sdk/issues/742 - [x] Final versi burn-in before merging --------- Signed-off-by: Alexandru Gheorghe --- .gitlab/pipeline/zombienet/polkadot.yml | 8 + .../src/blockchain_rpc_client.rs | 14 +- .../src/rpc_client.rs | 15 +- .../emulated/chains/relays/rococo/src/lib.rs | 2 +- .../emulated/chains/relays/westend/src/lib.rs | 2 +- polkadot/Cargo.toml | 1 - polkadot/cli/Cargo.toml | 2 - .../approval-voting/src/approval_checking.rs | 212 +++-- .../approval_db/common/migration_helpers.rs | 39 + .../src/approval_db/common/mod.rs | 293 ++++++ .../approval-voting/src/approval_db/mod.rs | 2 + .../src/approval_db/v1/tests.rs | 4 - .../src/approval_db/v2/migration_helpers.rs | 74 +- .../approval-voting/src/approval_db/v2/mod.rs | 251 +---- .../src/approval_db/v2/tests.rs | 68 +- .../src/approval_db/v3/migration_helpers.rs | 237 +++++ .../approval-voting/src/approval_db/v3/mod.rs | 137 +++ .../src/approval_db/v3/tests.rs | 575 ++++++++++++ .../node/core/approval-voting/src/backend.rs | 18 +- .../node/core/approval-voting/src/import.rs | 24 +- polkadot/node/core/approval-voting/src/lib.rs | 856 ++++++++++++++---- polkadot/node/core/approval-voting/src/ops.rs | 2 +- .../approval-voting/src/persisted_entries.rs | 292 +++++- .../node/core/approval-voting/src/tests.rs | 581 +++++++++++- .../node/core/approval-voting/src/time.rs | 165 +++- .../core/dispute-coordinator/src/import.rs | 38 +- .../dispute-coordinator/src/initialized.rs | 4 +- .../node/core/dispute-coordinator/src/lib.rs | 2 +- .../core/dispute-coordinator/src/tests.rs | 11 +- .../src/disputes/prioritized_selection/mod.rs | 2 +- polkadot/node/core/runtime-api/src/cache.rs | 31 +- polkadot/node/core/runtime-api/src/lib.rs | 13 + polkadot/node/core/runtime-api/src/tests.rs | 22 +- .../network/approval-distribution/src/lib.rs | 734 +++++++++------ .../approval-distribution/src/metrics.rs | 148 +++ .../approval-distribution/src/tests.rs | 746 ++++++++++++--- .../network/bitfield-distribution/src/lib.rs | 18 +- polkadot/node/network/bridge/src/network.rs | 12 +- polkadot/node/network/bridge/src/rx/mod.rs | 97 +- polkadot/node/network/bridge/src/rx/tests.rs | 16 +- polkadot/node/network/bridge/src/tx/mod.rs | 10 +- .../src/collator_side/mod.rs | 6 +- .../src/validator_side/mod.rs | 6 +- .../node/network/gossip-support/src/lib.rs | 2 +- polkadot/node/network/protocol/Cargo.toml | 3 - .../network/protocol/src/grid_topology.rs | 21 +- polkadot/node/network/protocol/src/lib.rs | 61 +- .../node/network/protocol/src/peer_set.rs | 55 +- .../src/legacy_v1/mod.rs | 30 +- .../network/statement-distribution/src/lib.rs | 8 +- .../statement-distribution/src/v2/mod.rs | 90 +- .../src/v2/tests/grid.rs | 2 +- polkadot/node/primitives/src/approval.rs | 57 +- .../node/primitives/src/disputes/message.rs | 2 +- polkadot/node/primitives/src/disputes/mod.rs | 23 +- polkadot/node/service/Cargo.toml | 4 - .../node/service/src/parachains_db/upgrade.rs | 99 +- polkadot/node/subsystem-types/src/messages.rs | 35 +- .../subsystem-types/src/runtime_client.rs | 33 +- .../undying/collator/Cargo.toml | 3 - polkadot/primitives/src/runtime_api.rs | 17 +- polkadot/primitives/src/v6/mod.rs | 70 +- polkadot/primitives/src/vstaging/mod.rs | 32 + .../src/node/approval/approval-voting.md | 47 +- .../src/protocol-approval.md | 12 + polkadot/runtime/parachains/src/builder.rs | 2 +- .../runtime/parachains/src/configuration.rs | 29 +- .../parachains/src/configuration/migration.rs | 1 + .../src/configuration/migration/v10.rs | 110 ++- .../src/configuration/migration/v11.rs | 329 +++++++ .../src/configuration/migration/v8.rs | 2 +- .../parachains/src/configuration/tests.rs | 1 + polkadot/runtime/parachains/src/disputes.rs | 34 +- .../runtime/parachains/src/disputes/tests.rs | 126 ++- .../src/runtime_api_impl/vstaging.rs | 11 +- polkadot/runtime/rococo/src/lib.rs | 20 +- polkadot/runtime/westend/src/lib.rs | 21 +- .../functional/0001-parachains-pvf.zndsl | 2 + .../functional/0002-parachains-disputes.toml | 4 + .../0009-approval-voting-coalescing.toml | 115 +++ .../0009-approval-voting-coalescing.zndsl | 32 + prdoc/pr_1191.prdoc | 21 + 82 files changed, 5878 insertions(+), 1478 deletions(-) create mode 100644 polkadot/node/core/approval-voting/src/approval_db/common/migration_helpers.rs create mode 100644 polkadot/node/core/approval-voting/src/approval_db/common/mod.rs create mode 100644 polkadot/node/core/approval-voting/src/approval_db/v3/migration_helpers.rs create mode 100644 polkadot/node/core/approval-voting/src/approval_db/v3/mod.rs create mode 100644 polkadot/node/core/approval-voting/src/approval_db/v3/tests.rs create mode 100644 polkadot/runtime/parachains/src/configuration/migration/v11.rs create mode 100644 polkadot/zombienet_tests/functional/0009-approval-voting-coalescing.toml create mode 100644 polkadot/zombienet_tests/functional/0009-approval-voting-coalescing.zndsl create mode 100644 prdoc/pr_1191.prdoc diff --git a/.gitlab/pipeline/zombienet/polkadot.yml b/.gitlab/pipeline/zombienet/polkadot.yml index d1f3a201c80..356abaa93cd 100644 --- a/.gitlab/pipeline/zombienet/polkadot.yml +++ b/.gitlab/pipeline/zombienet/polkadot.yml @@ -131,6 +131,14 @@ zombienet-polkadot-functional-0008-dispute-old-finalized: --local-dir="${LOCAL_DIR}/functional" --test="0008-dispute-old-finalized.zndsl" +zombienet-polkadot-functional-0009-approval-voting-coalescing: + extends: + - .zombienet-polkadot-common + script: + - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh + --local-dir="${LOCAL_DIR}/functional" + --test="0009-approval-voting-coalescing.zndsl" + zombienet-polkadot-smoke-0001-parachains-smoke-test: extends: - .zombienet-polkadot-common diff --git a/cumulus/client/relay-chain-minimal-node/src/blockchain_rpc_client.rs b/cumulus/client/relay-chain-minimal-node/src/blockchain_rpc_client.rs index d9e4155d9c5..ab56b62c4ca 100644 --- a/cumulus/client/relay-chain-minimal-node/src/blockchain_rpc_client.rs +++ b/cumulus/client/relay-chain-minimal-node/src/blockchain_rpc_client.rs @@ -24,7 +24,7 @@ use polkadot_overseer::{ChainApiBackend, RuntimeApiSubsystemClient}; use polkadot_primitives::{ async_backing::{AsyncBackingParams, BackingState}, slashing, - vstaging::NodeFeatures, + vstaging::{ApprovalVotingParams, NodeFeatures}, }; use sc_authority_discovery::{AuthorityDiscovery, Error as AuthorityDiscoveryError}; use sc_client_api::AuxStore; @@ -427,6 +427,18 @@ impl RuntimeApiSubsystemClient for BlockChainRpcClient { Ok(self.rpc_client.parachain_host_para_backing_state(at, para_id).await?) } + /// Approval voting configuration parameters + async fn approval_voting_params( + &self, + at: Hash, + session_index: polkadot_primitives::SessionIndex, + ) -> Result { + Ok(self + .rpc_client + .parachain_host_staging_approval_voting_params(at, session_index) + .await?) + } + async fn node_features(&self, at: Hash) -> Result { Ok(self.rpc_client.parachain_host_node_features(at).await?) } diff --git a/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs b/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs index 8e0d5fae677..c64fff77a29 100644 --- a/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs +++ b/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs @@ -32,7 +32,7 @@ use cumulus_primitives_core::{ relay_chain::{ async_backing::{AsyncBackingParams, BackingState}, slashing, - vstaging::NodeFeatures, + vstaging::{ApprovalVotingParams, NodeFeatures}, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Hash as RelayHash, Header as RelayHeader, InboundHrmpMessage, OccupiedCoreAssumption, @@ -625,6 +625,19 @@ impl RelayChainRpcClient { } #[allow(missing_docs)] + pub async fn parachain_host_staging_approval_voting_params( + &self, + at: RelayHash, + _session_index: SessionIndex, + ) -> Result { + self.call_remote_runtime_function( + "ParachainHost_staging_approval_voting_params", + at, + None::<()>, + ) + .await + } + pub async fn parachain_host_para_backing_state( &self, at: RelayHash, diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/lib.rs index 7ace9614710..0791f63235f 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/src/lib.rs @@ -24,7 +24,7 @@ use emulated_integration_tests_common::{ // Rococo declaration decl_test_relay_chains! { - #[api_version(9)] + #[api_version(10)] pub struct Rococo { genesis = genesis::genesis(), on_init = (), diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/lib.rs index 2ba47250d56..8a5d4bbf808 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/src/lib.rs @@ -24,7 +24,7 @@ use emulated_integration_tests_common::{ // Westend declaration decl_test_relay_chains! { - #[api_version(9)] + #[api_version(10)] pub struct Westend { genesis = genesis::genesis(), on_init = (), diff --git a/polkadot/Cargo.toml b/polkadot/Cargo.toml index 6896d3c4b22..d8c6cc51bea 100644 --- a/polkadot/Cargo.toml +++ b/polkadot/Cargo.toml @@ -64,7 +64,6 @@ jemalloc-allocator = [ "polkadot-node-core-pvf/jemalloc-allocator", "polkadot-overseer/jemalloc-allocator", ] -network-protocol-staging = ["polkadot-cli/network-protocol-staging"] # Enables timeout-based tests supposed to be run only in CI environment as they may be flaky diff --git a/polkadot/cli/Cargo.toml b/polkadot/cli/Cargo.toml index 77f73ead2ed..95b63913ccb 100644 --- a/polkadot/cli/Cargo.toml +++ b/polkadot/cli/Cargo.toml @@ -75,5 +75,3 @@ runtime-metrics = [ "polkadot-node-metrics/runtime-metrics", "service/runtime-metrics", ] - -network-protocol-staging = ["service/network-protocol-staging"] diff --git a/polkadot/node/core/approval-voting/src/approval_checking.rs b/polkadot/node/core/approval-voting/src/approval_checking.rs index 5d24ff16419..0aa6102fbd6 100644 --- a/polkadot/node/core/approval-voting/src/approval_checking.rs +++ b/polkadot/node/core/approval-voting/src/approval_checking.rs @@ -25,6 +25,15 @@ use crate::{ time::Tick, }; +/// Result of counting the necessary tranches needed for approving a block. +#[derive(Debug, PartialEq, Clone)] +pub struct TranchesToApproveResult { + /// The required tranches for approving this block + pub required_tranches: RequiredTranches, + /// The total number of no_shows at the moment we are doing the counting. + pub total_observed_no_shows: usize, +} + /// The required tranches of assignments needed to determine whether a candidate is approved. #[derive(Debug, PartialEq, Clone)] pub enum RequiredTranches { @@ -64,7 +73,7 @@ pub enum RequiredTranches { } /// The result of a check. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq)] pub enum Check { /// The candidate is unapproved. Unapproved, @@ -178,6 +187,7 @@ struct State { next_no_show: Option, /// The last tick at which a considered assignment was received. last_assignment_tick: Option, + total_observed_no_shows: usize, } impl State { @@ -187,41 +197,53 @@ impl State { needed_approvals: usize, n_validators: usize, no_show_duration: Tick, - ) -> RequiredTranches { + ) -> TranchesToApproveResult { let covering = if self.depth == 0 { 0 } else { self.covering }; if self.depth != 0 && self.assignments + covering + self.uncovered >= n_validators { - return RequiredTranches::All + return TranchesToApproveResult { + required_tranches: RequiredTranches::All, + total_observed_no_shows: self.total_observed_no_shows, + } } // If we have enough assignments and all no-shows are covered, we have reached the number // of tranches that we need to have. if self.assignments >= needed_approvals && (covering + self.uncovered) == 0 { - return RequiredTranches::Exact { - needed: tranche, - tolerated_missing: self.covered, - next_no_show: self.next_no_show, - last_assignment_tick: self.last_assignment_tick, + return TranchesToApproveResult { + required_tranches: RequiredTranches::Exact { + needed: tranche, + tolerated_missing: self.covered, + next_no_show: self.next_no_show, + last_assignment_tick: self.last_assignment_tick, + }, + total_observed_no_shows: self.total_observed_no_shows, } } // We're pending more assignments and should look at more tranches. let clock_drift = self.clock_drift(no_show_duration); if self.depth == 0 { - RequiredTranches::Pending { - considered: tranche, - next_no_show: self.next_no_show, - // during the initial assignment-gathering phase, we want to accept assignments - // from any tranche. Note that honest validators will still not broadcast their - // assignment until it is time to do so, regardless of this value. - maximum_broadcast: DelayTranche::max_value(), - clock_drift, + TranchesToApproveResult { + required_tranches: RequiredTranches::Pending { + considered: tranche, + next_no_show: self.next_no_show, + // during the initial assignment-gathering phase, we want to accept assignments + // from any tranche. Note that honest validators will still not broadcast their + // assignment until it is time to do so, regardless of this value. + maximum_broadcast: DelayTranche::max_value(), + clock_drift, + }, + total_observed_no_shows: self.total_observed_no_shows, } } else { - RequiredTranches::Pending { - considered: tranche, - next_no_show: self.next_no_show, - maximum_broadcast: tranche + (covering + self.uncovered) as DelayTranche, - clock_drift, + TranchesToApproveResult { + required_tranches: RequiredTranches::Pending { + considered: tranche, + next_no_show: self.next_no_show, + maximum_broadcast: tranche + (covering + self.uncovered) as DelayTranche, + clock_drift, + }, + total_observed_no_shows: self.total_observed_no_shows, } } } @@ -276,6 +298,7 @@ impl State { uncovered, next_no_show, last_assignment_tick, + total_observed_no_shows: self.total_observed_no_shows + new_no_shows, } } } @@ -372,7 +395,7 @@ pub fn tranches_to_approve( block_tick: Tick, no_show_duration: Tick, needed_approvals: usize, -) -> RequiredTranches { +) -> TranchesToApproveResult { let tick_now = tranche_now as Tick + block_tick; let n_validators = approval_entry.n_validators(); @@ -384,6 +407,7 @@ pub fn tranches_to_approve( uncovered: 0, next_no_show: None, last_assignment_tick: None, + total_observed_no_shows: 0, }; // The `ApprovalEntry` doesn't have any data for empty tranches. We still want to iterate over @@ -434,7 +458,7 @@ pub fn tranches_to_approve( let s = s.advance(n_assignments, no_shows, next_no_show, last_assignment_tick); let output = s.output(tranche, needed_approvals, n_validators, no_show_duration); - *state = match output { + *state = match output.required_tranches { RequiredTranches::Exact { .. } | RequiredTranches::All => { // Wipe the state clean so the next iteration of this closure will terminate // the iterator. This guarantees that we can call `last` further down to see @@ -464,15 +488,17 @@ mod tests { #[test] fn pending_is_not_approved() { - let candidate = approval_db::v1::CandidateEntry { - candidate: dummy_candidate_receipt(dummy_hash()), - session: 0, - block_assignments: BTreeMap::default(), - approvals: BitVec::default(), - } - .into(); + let candidate = CandidateEntry::from_v1( + approval_db::v1::CandidateEntry { + candidate: dummy_candidate_receipt(dummy_hash()), + session: 0, + block_assignments: BTreeMap::default(), + approvals: BitVec::default(), + }, + 0, + ); - let approval_entry = approval_db::v2::ApprovalEntry { + let approval_entry = approval_db::v3::ApprovalEntry { tranches: Vec::new(), assigned_validators: BitVec::default(), our_assignment: None, @@ -497,29 +523,31 @@ mod tests { #[test] fn exact_takes_only_assignments_up_to() { - let mut candidate: CandidateEntry = approval_db::v1::CandidateEntry { - candidate: dummy_candidate_receipt(dummy_hash()), - session: 0, - block_assignments: BTreeMap::default(), - approvals: bitvec![u8, BitOrderLsb0; 0; 10], - } - .into(); + let mut candidate: CandidateEntry = CandidateEntry::from_v1( + approval_db::v1::CandidateEntry { + candidate: dummy_candidate_receipt(dummy_hash()), + session: 0, + block_assignments: BTreeMap::default(), + approvals: bitvec![u8, BitOrderLsb0; 0; 10], + }, + 0, + ); for i in 0..3 { candidate.mark_approval(ValidatorIndex(i)); } - let approval_entry = approval_db::v2::ApprovalEntry { + let approval_entry = approval_db::v3::ApprovalEntry { tranches: vec![ - approval_db::v2::TrancheEntry { + approval_db::v3::TrancheEntry { tranche: 0, assignments: (0..2).map(|i| (ValidatorIndex(i), 0.into())).collect(), }, - approval_db::v2::TrancheEntry { + approval_db::v3::TrancheEntry { tranche: 1, assignments: (2..5).map(|i| (ValidatorIndex(i), 1.into())).collect(), }, - approval_db::v2::TrancheEntry { + approval_db::v3::TrancheEntry { tranche: 2, assignments: (5..10).map(|i| (ValidatorIndex(i), 0.into())).collect(), }, @@ -569,29 +597,31 @@ mod tests { #[test] fn one_honest_node_always_approves() { - let mut candidate: CandidateEntry = approval_db::v1::CandidateEntry { - candidate: dummy_candidate_receipt(dummy_hash()), - session: 0, - block_assignments: BTreeMap::default(), - approvals: bitvec![u8, BitOrderLsb0; 0; 10], - } - .into(); + let mut candidate: CandidateEntry = CandidateEntry::from_v1( + approval_db::v1::CandidateEntry { + candidate: dummy_candidate_receipt(dummy_hash()), + session: 0, + block_assignments: BTreeMap::default(), + approvals: bitvec![u8, BitOrderLsb0; 0; 10], + }, + 0, + ); for i in 0..3 { candidate.mark_approval(ValidatorIndex(i)); } - let approval_entry = approval_db::v2::ApprovalEntry { + let approval_entry = approval_db::v3::ApprovalEntry { tranches: vec![ - approval_db::v2::TrancheEntry { + approval_db::v3::TrancheEntry { tranche: 0, assignments: (0..4).map(|i| (ValidatorIndex(i), 0.into())).collect(), }, - approval_db::v2::TrancheEntry { + approval_db::v3::TrancheEntry { tranche: 1, assignments: (4..6).map(|i| (ValidatorIndex(i), 1.into())).collect(), }, - approval_db::v2::TrancheEntry { + approval_db::v3::TrancheEntry { tranche: 2, assignments: (6..10).map(|i| (ValidatorIndex(i), 0.into())).collect(), }, @@ -647,7 +677,7 @@ mod tests { let no_show_duration = 10; let needed_approvals = 4; - let mut approval_entry: ApprovalEntry = approval_db::v2::ApprovalEntry { + let mut approval_entry: ApprovalEntry = approval_db::v3::ApprovalEntry { tranches: Vec::new(), assigned_validators: bitvec![u8, BitOrderLsb0; 0; 5], our_assignment: None, @@ -675,7 +705,8 @@ mod tests { block_tick, no_show_duration, needed_approvals, - ), + ) + .required_tranches, RequiredTranches::Exact { needed: 1, tolerated_missing: 0, @@ -691,7 +722,7 @@ mod tests { let no_show_duration = 10; let needed_approvals = 4; - let mut approval_entry: ApprovalEntry = approval_db::v2::ApprovalEntry { + let mut approval_entry: ApprovalEntry = approval_db::v3::ApprovalEntry { tranches: Vec::new(), assigned_validators: bitvec![u8, BitOrderLsb0; 0; 10], our_assignment: None, @@ -715,7 +746,8 @@ mod tests { block_tick, no_show_duration, needed_approvals, - ), + ) + .required_tranches, RequiredTranches::Pending { considered: 2, next_no_show: Some(block_tick + no_show_duration), @@ -731,7 +763,7 @@ mod tests { let no_show_duration = 10; let needed_approvals = 4; - let mut approval_entry: ApprovalEntry = approval_db::v2::ApprovalEntry { + let mut approval_entry: ApprovalEntry = approval_db::v3::ApprovalEntry { tranches: Vec::new(), assigned_validators: bitvec![u8, BitOrderLsb0; 0; 10], our_assignment: None, @@ -759,7 +791,8 @@ mod tests { block_tick, no_show_duration, needed_approvals, - ), + ) + .required_tranches, RequiredTranches::Pending { considered: 11, next_no_show: None, @@ -776,7 +809,7 @@ mod tests { let needed_approvals = 4; let n_validators = 8; - let mut approval_entry: ApprovalEntry = approval_db::v2::ApprovalEntry { + let mut approval_entry: ApprovalEntry = approval_db::v3::ApprovalEntry { tranches: Vec::new(), assigned_validators: bitvec![u8, BitOrderLsb0; 0; n_validators], our_assignment: None, @@ -807,7 +840,8 @@ mod tests { block_tick, no_show_duration, needed_approvals, - ), + ) + .required_tranches, RequiredTranches::Pending { considered: 1, next_no_show: None, @@ -826,7 +860,8 @@ mod tests { block_tick, no_show_duration, needed_approvals, - ), + ) + .required_tranches, RequiredTranches::Pending { considered: 1, next_no_show: None, @@ -843,7 +878,7 @@ mod tests { let needed_approvals = 4; let n_validators = 8; - let mut approval_entry: ApprovalEntry = approval_db::v2::ApprovalEntry { + let mut approval_entry: ApprovalEntry = approval_db::v3::ApprovalEntry { tranches: Vec::new(), assigned_validators: bitvec![u8, BitOrderLsb0; 0; n_validators], our_assignment: None, @@ -879,7 +914,8 @@ mod tests { block_tick, no_show_duration, needed_approvals, - ), + ) + .required_tranches, RequiredTranches::Exact { needed: 1, tolerated_missing: 0, @@ -898,7 +934,8 @@ mod tests { block_tick, no_show_duration, needed_approvals, - ), + ) + .required_tranches, RequiredTranches::Exact { needed: 2, tolerated_missing: 1, @@ -917,7 +954,8 @@ mod tests { block_tick, no_show_duration, needed_approvals, - ), + ) + .required_tranches, RequiredTranches::Pending { considered: 2, next_no_show: None, @@ -934,7 +972,7 @@ mod tests { let needed_approvals = 4; let n_validators = 8; - let mut approval_entry: ApprovalEntry = approval_db::v2::ApprovalEntry { + let mut approval_entry: ApprovalEntry = approval_db::v3::ApprovalEntry { tranches: Vec::new(), assigned_validators: bitvec![u8, BitOrderLsb0; 0; n_validators], our_assignment: None, @@ -970,7 +1008,8 @@ mod tests { block_tick, no_show_duration, needed_approvals, - ), + ) + .required_tranches, RequiredTranches::Exact { needed: 2, tolerated_missing: 1, @@ -992,7 +1031,8 @@ mod tests { block_tick, no_show_duration, needed_approvals, - ), + ) + .required_tranches, RequiredTranches::Pending { considered: 2, next_no_show: None, @@ -1013,7 +1053,8 @@ mod tests { block_tick, no_show_duration, needed_approvals, - ), + ) + .required_tranches, RequiredTranches::Exact { needed: 3, tolerated_missing: 2, @@ -1029,22 +1070,24 @@ mod tests { let no_show_duration = 10; let needed_approvals = 3; - let mut candidate: CandidateEntry = approval_db::v1::CandidateEntry { - candidate: dummy_candidate_receipt(dummy_hash()), - session: 0, - block_assignments: BTreeMap::default(), - approvals: bitvec![u8, BitOrderLsb0; 0; 3], - } - .into(); + let mut candidate: CandidateEntry = CandidateEntry::from_v1( + approval_db::v1::CandidateEntry { + candidate: dummy_candidate_receipt(dummy_hash()), + session: 0, + block_assignments: BTreeMap::default(), + approvals: bitvec![u8, BitOrderLsb0; 0; 3], + }, + 0, + ); for i in 0..3 { candidate.mark_approval(ValidatorIndex(i)); } - let approval_entry = approval_db::v2::ApprovalEntry { + let approval_entry = approval_db::v3::ApprovalEntry { tranches: vec![ // Assignments with invalid validator indexes. - approval_db::v2::TrancheEntry { + approval_db::v3::TrancheEntry { tranche: 1, assignments: (2..5).map(|i| (ValidatorIndex(i), 1.into())).collect(), }, @@ -1068,7 +1111,8 @@ mod tests { block_tick, no_show_duration, needed_approvals, - ), + ) + .required_tranches, RequiredTranches::Pending { considered: 10, next_no_show: None, @@ -1094,7 +1138,7 @@ mod tests { ]; for test_tranche in test_tranches { - let mut approval_entry: ApprovalEntry = approval_db::v2::ApprovalEntry { + let mut approval_entry: ApprovalEntry = approval_db::v3::ApprovalEntry { tranches: Vec::new(), backing_group: GroupIndex(0), our_assignment: None, @@ -1345,10 +1389,11 @@ mod tests { uncovered: 0, next_no_show: None, last_assignment_tick: None, + total_observed_no_shows: 0, }; assert_eq!( - state.output(0, 10, 10, 20), + state.output(0, 10, 10, 20).required_tranches, RequiredTranches::Pending { considered: 0, next_no_show: None, @@ -1368,10 +1413,11 @@ mod tests { uncovered: 0, next_no_show: None, last_assignment_tick: None, + total_observed_no_shows: 0, }; assert_eq!( - state.output(0, 10, 10, 20), + state.output(0, 10, 10, 20).required_tranches, RequiredTranches::Exact { needed: 0, tolerated_missing: 0, diff --git a/polkadot/node/core/approval-voting/src/approval_db/common/migration_helpers.rs b/polkadot/node/core/approval-voting/src/approval_db/common/migration_helpers.rs new file mode 100644 index 00000000000..e21c53e4cac --- /dev/null +++ b/polkadot/node/core/approval-voting/src/approval_db/common/migration_helpers.rs @@ -0,0 +1,39 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec}; + +use polkadot_node_primitives::approval::{ + v1::{AssignmentCert, AssignmentCertKind, VrfProof, VrfSignature, RELAY_VRF_MODULO_CONTEXT}, + v2::VrfPreOutput, +}; +pub fn make_bitvec(len: usize) -> BitVec { + bitvec::bitvec![u8, BitOrderLsb0; 0; len] +} + +pub fn dummy_assignment_cert(kind: AssignmentCertKind) -> AssignmentCert { + let ctx = schnorrkel::signing_context(RELAY_VRF_MODULO_CONTEXT); + let msg = b"test-garbage"; + let mut prng = rand_core::OsRng; + let keypair = schnorrkel::Keypair::generate_with(&mut prng); + let (inout, proof, _) = keypair.vrf_sign(ctx.bytes(msg)); + let out = inout.to_output(); + + AssignmentCert { + kind, + vrf: VrfSignature { pre_output: VrfPreOutput(out), proof: VrfProof(proof) }, + } +} diff --git a/polkadot/node/core/approval-voting/src/approval_db/common/mod.rs b/polkadot/node/core/approval-voting/src/approval_db/common/mod.rs new file mode 100644 index 00000000000..249dcf912df --- /dev/null +++ b/polkadot/node/core/approval-voting/src/approval_db/common/mod.rs @@ -0,0 +1,293 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Common helper functions for all versions of approval-voting database. +use std::sync::Arc; + +use parity_scale_codec::{Decode, Encode}; +use polkadot_node_subsystem::{SubsystemError, SubsystemResult}; +use polkadot_node_subsystem_util::database::{DBTransaction, Database}; +use polkadot_primitives::{BlockNumber, CandidateHash, CandidateIndex, Hash}; + +use crate::{ + backend::{Backend, BackendWriteOp, V1ReadBackend, V2ReadBackend}, + persisted_entries, +}; + +use super::{ + v2::{load_block_entry_v1, load_candidate_entry_v1}, + v3::{load_block_entry_v2, load_candidate_entry_v2, BlockEntry, CandidateEntry}, +}; + +pub mod migration_helpers; + +const STORED_BLOCKS_KEY: &[u8] = b"Approvals_StoredBlocks"; + +/// A range from earliest..last block number stored within the DB. +#[derive(Encode, Decode, Debug, Clone, PartialEq)] +pub struct StoredBlockRange(pub BlockNumber, pub BlockNumber); +/// The database config. +#[derive(Debug, Clone, Copy)] +pub struct Config { + /// The column family in the database where data is stored. + pub col_approval_data: u32, +} + +/// `DbBackend` is a concrete implementation of the higher-level Backend trait +pub struct DbBackend { + inner: Arc, + config: Config, +} + +impl DbBackend { + /// Create a new [`DbBackend`] with the supplied key-value store and + /// config. + pub fn new(db: Arc, config: Config) -> Self { + DbBackend { inner: db, config } + } +} + +/// Errors while accessing things from the DB. +#[derive(Debug, derive_more::From, derive_more::Display)] +pub enum Error { + Io(std::io::Error), + InvalidDecoding(parity_scale_codec::Error), + InternalError(SubsystemError), +} + +impl std::error::Error for Error {} + +/// Result alias for DB errors. +pub type Result = std::result::Result; + +impl Backend for DbBackend { + fn load_block_entry( + &self, + block_hash: &Hash, + ) -> SubsystemResult> { + load_block_entry(&*self.inner, &self.config, block_hash).map(|e| e.map(Into::into)) + } + + fn load_candidate_entry( + &self, + candidate_hash: &CandidateHash, + ) -> SubsystemResult> { + load_candidate_entry(&*self.inner, &self.config, candidate_hash).map(|e| e.map(Into::into)) + } + + fn load_blocks_at_height(&self, block_height: &BlockNumber) -> SubsystemResult> { + load_blocks_at_height(&*self.inner, &self.config, block_height) + } + + fn load_all_blocks(&self) -> SubsystemResult> { + load_all_blocks(&*self.inner, &self.config) + } + + fn load_stored_blocks(&self) -> SubsystemResult> { + load_stored_blocks(&*self.inner, &self.config) + } + + /// Atomically write the list of operations, with later operations taking precedence over prior. + fn write(&mut self, ops: I) -> SubsystemResult<()> + where + I: IntoIterator, + { + let mut tx = DBTransaction::new(); + for op in ops { + match op { + BackendWriteOp::WriteStoredBlockRange(stored_block_range) => { + tx.put_vec( + self.config.col_approval_data, + &STORED_BLOCKS_KEY, + stored_block_range.encode(), + ); + }, + BackendWriteOp::DeleteStoredBlockRange => { + tx.delete(self.config.col_approval_data, &STORED_BLOCKS_KEY); + }, + BackendWriteOp::WriteBlocksAtHeight(h, blocks) => { + tx.put_vec( + self.config.col_approval_data, + &blocks_at_height_key(h), + blocks.encode(), + ); + }, + BackendWriteOp::DeleteBlocksAtHeight(h) => { + tx.delete(self.config.col_approval_data, &blocks_at_height_key(h)); + }, + BackendWriteOp::WriteBlockEntry(block_entry) => { + let block_entry: BlockEntry = block_entry.into(); + tx.put_vec( + self.config.col_approval_data, + &block_entry_key(&block_entry.block_hash), + block_entry.encode(), + ); + }, + BackendWriteOp::DeleteBlockEntry(hash) => { + tx.delete(self.config.col_approval_data, &block_entry_key(&hash)); + }, + BackendWriteOp::WriteCandidateEntry(candidate_entry) => { + let candidate_entry: CandidateEntry = candidate_entry.into(); + tx.put_vec( + self.config.col_approval_data, + &candidate_entry_key(&candidate_entry.candidate.hash()), + candidate_entry.encode(), + ); + }, + BackendWriteOp::DeleteCandidateEntry(candidate_hash) => { + tx.delete(self.config.col_approval_data, &candidate_entry_key(&candidate_hash)); + }, + } + } + + self.inner.write(tx).map_err(|e| e.into()) + } +} + +impl V1ReadBackend for DbBackend { + fn load_candidate_entry_v1( + &self, + candidate_hash: &CandidateHash, + candidate_index: CandidateIndex, + ) -> SubsystemResult> { + load_candidate_entry_v1(&*self.inner, &self.config, candidate_hash) + .map(|e| e.map(|e| persisted_entries::CandidateEntry::from_v1(e, candidate_index))) + } + + fn load_block_entry_v1( + &self, + block_hash: &Hash, + ) -> SubsystemResult> { + load_block_entry_v1(&*self.inner, &self.config, block_hash).map(|e| e.map(Into::into)) + } +} + +impl V2ReadBackend for DbBackend { + fn load_candidate_entry_v2( + &self, + candidate_hash: &CandidateHash, + candidate_index: CandidateIndex, + ) -> SubsystemResult> { + load_candidate_entry_v2(&*self.inner, &self.config, candidate_hash) + .map(|e| e.map(|e| persisted_entries::CandidateEntry::from_v2(e, candidate_index))) + } + + fn load_block_entry_v2( + &self, + block_hash: &Hash, + ) -> SubsystemResult> { + load_block_entry_v2(&*self.inner, &self.config, block_hash).map(|e| e.map(Into::into)) + } +} + +pub(crate) fn load_decode( + store: &dyn Database, + col_approval_data: u32, + key: &[u8], +) -> Result> { + match store.get(col_approval_data, key)? { + None => Ok(None), + Some(raw) => D::decode(&mut &raw[..]).map(Some).map_err(Into::into), + } +} + +/// The key a given block entry is stored under. +pub(crate) fn block_entry_key(block_hash: &Hash) -> [u8; 46] { + const BLOCK_ENTRY_PREFIX: [u8; 14] = *b"Approvals_blck"; + + let mut key = [0u8; 14 + 32]; + key[0..14].copy_from_slice(&BLOCK_ENTRY_PREFIX); + key[14..][..32].copy_from_slice(block_hash.as_ref()); + + key +} + +/// The key a given candidate entry is stored under. +pub(crate) fn candidate_entry_key(candidate_hash: &CandidateHash) -> [u8; 46] { + const CANDIDATE_ENTRY_PREFIX: [u8; 14] = *b"Approvals_cand"; + + let mut key = [0u8; 14 + 32]; + key[0..14].copy_from_slice(&CANDIDATE_ENTRY_PREFIX); + key[14..][..32].copy_from_slice(candidate_hash.0.as_ref()); + + key +} + +/// The key a set of block hashes corresponding to a block number is stored under. +pub(crate) fn blocks_at_height_key(block_number: BlockNumber) -> [u8; 16] { + const BLOCKS_AT_HEIGHT_PREFIX: [u8; 12] = *b"Approvals_at"; + + let mut key = [0u8; 12 + 4]; + key[0..12].copy_from_slice(&BLOCKS_AT_HEIGHT_PREFIX); + block_number.using_encoded(|s| key[12..16].copy_from_slice(s)); + + key +} + +/// Return all blocks which have entries in the DB, ascending, by height. +pub fn load_all_blocks(store: &dyn Database, config: &Config) -> SubsystemResult> { + let mut hashes = Vec::new(); + if let Some(stored_blocks) = load_stored_blocks(store, config)? { + for height in stored_blocks.0..stored_blocks.1 { + let blocks = load_blocks_at_height(store, config, &height)?; + hashes.extend(blocks); + } + } + + Ok(hashes) +} + +/// Load the stored-blocks key from the state. +pub fn load_stored_blocks( + store: &dyn Database, + config: &Config, +) -> SubsystemResult> { + load_decode(store, config.col_approval_data, STORED_BLOCKS_KEY) + .map_err(|e| SubsystemError::with_origin("approval-voting", e)) +} + +/// Load a blocks-at-height entry for a given block number. +pub fn load_blocks_at_height( + store: &dyn Database, + config: &Config, + block_number: &BlockNumber, +) -> SubsystemResult> { + load_decode(store, config.col_approval_data, &blocks_at_height_key(*block_number)) + .map(|x| x.unwrap_or_default()) + .map_err(|e| SubsystemError::with_origin("approval-voting", e)) +} + +/// Load a block entry from the aux store. +pub fn load_block_entry( + store: &dyn Database, + config: &Config, + block_hash: &Hash, +) -> SubsystemResult> { + load_decode(store, config.col_approval_data, &block_entry_key(block_hash)) + .map(|u: Option| u.map(|v| v.into())) + .map_err(|e| SubsystemError::with_origin("approval-voting", e)) +} + +/// Load a candidate entry from the aux store in current version format. +pub fn load_candidate_entry( + store: &dyn Database, + config: &Config, + candidate_hash: &CandidateHash, +) -> SubsystemResult> { + load_decode(store, config.col_approval_data, &candidate_entry_key(candidate_hash)) + .map(|u: Option| u.map(|v| v.into())) + .map_err(|e| SubsystemError::with_origin("approval-voting", e)) +} diff --git a/polkadot/node/core/approval-voting/src/approval_db/mod.rs b/polkadot/node/core/approval-voting/src/approval_db/mod.rs index 20fb6aa82d8..78942a507f4 100644 --- a/polkadot/node/core/approval-voting/src/approval_db/mod.rs +++ b/polkadot/node/core/approval-voting/src/approval_db/mod.rs @@ -30,5 +30,7 @@ //! In the future, we may use a temporary DB which doesn't need to be wiped, but for the //! time being we share the same DB with the rest of Substrate. +pub mod common; pub mod v1; pub mod v2; +pub mod v3; diff --git a/polkadot/node/core/approval-voting/src/approval_db/v1/tests.rs b/polkadot/node/core/approval-voting/src/approval_db/v1/tests.rs index 07d8242b772..b979cb7ef45 100644 --- a/polkadot/node/core/approval-voting/src/approval_db/v1/tests.rs +++ b/polkadot/node/core/approval-voting/src/approval_db/v1/tests.rs @@ -40,10 +40,6 @@ fn make_db() -> (DbBackend, Arc) { (DbBackend::new(db_writer.clone(), TEST_CONFIG), db_writer) } -fn make_bitvec(len: usize) -> BitVec { - bitvec::bitvec![u8, BitOrderLsb0; 0; len] -} - fn make_block_entry( block_hash: Hash, parent_hash: Hash, diff --git a/polkadot/node/core/approval-voting/src/approval_db/v2/migration_helpers.rs b/polkadot/node/core/approval-voting/src/approval_db/v2/migration_helpers.rs index efdba41b57a..df6e4754dbd 100644 --- a/polkadot/node/core/approval-voting/src/approval_db/v2/migration_helpers.rs +++ b/polkadot/node/core/approval-voting/src/approval_db/v2/migration_helpers.rs @@ -16,29 +16,19 @@ //! Approval DB migration helpers. use super::*; -use crate::backend::Backend; -use polkadot_node_primitives::approval::v1::{ - AssignmentCert, AssignmentCertKind, VrfPreOutput, VrfProof, VrfSignature, - RELAY_VRF_MODULO_CONTEXT, +use crate::{ + approval_db::common::{ + migration_helpers::{dummy_assignment_cert, make_bitvec}, + Error, Result, StoredBlockRange, + }, + backend::Backend, }; + +use polkadot_node_primitives::approval::v1::AssignmentCertKind; use polkadot_node_subsystem_util::database::Database; use sp_application_crypto::sp_core::H256; use std::{collections::HashSet, sync::Arc}; -fn dummy_assignment_cert(kind: AssignmentCertKind) -> AssignmentCert { - let ctx = schnorrkel::signing_context(RELAY_VRF_MODULO_CONTEXT); - let msg = b"test-garbage"; - let mut prng = rand_core::OsRng; - let keypair = schnorrkel::Keypair::generate_with(&mut prng); - let (inout, proof, _) = keypair.vrf_sign(ctx.bytes(msg)); - let preout = inout.to_output(); - - AssignmentCert { - kind, - vrf: VrfSignature { pre_output: VrfPreOutput(preout), proof: VrfProof(proof) }, - } -} - fn make_block_entry_v1( block_hash: Hash, parent_hash: Hash, @@ -58,14 +48,10 @@ fn make_block_entry_v1( } } -fn make_bitvec(len: usize) -> BitVec { - bitvec::bitvec![u8, BitOrderLsb0; 0; len] -} - /// Migrates `OurAssignment`, `CandidateEntry` and `ApprovalEntry` to version 2. /// Returns on any error. /// Must only be used in parachains DB migration code - `polkadot-service` crate. -pub fn v1_to_v2(db: Arc, config: Config) -> Result<()> { +pub fn v1_to_latest(db: Arc, config: Config) -> Result<()> { let mut backend = crate::DbBackend::new(db, config); let all_blocks = backend .load_all_blocks() @@ -89,11 +75,13 @@ pub fn v1_to_v2(db: Arc, config: Config) -> Result<()> { let mut counter = 0; // Get all candidate entries, approval entries and convert each of them. for block in all_blocks { - for (_core_index, candidate_hash) in block.candidates() { + for (candidate_index, (_core_index, candidate_hash)) in + block.candidates().iter().enumerate() + { // Loading the candidate will also perform the conversion to the updated format and // return that represantation. if let Some(candidate_entry) = backend - .load_candidate_entry_v1(&candidate_hash) + .load_candidate_entry_v1(&candidate_hash, candidate_index as CandidateIndex) .map_err(|e| Error::InternalError(e))? { // Write the updated representation. @@ -113,42 +101,8 @@ pub fn v1_to_v2(db: Arc, config: Config) -> Result<()> { Ok(()) } -// Checks if the migration doesn't leave the DB in an unsane state. -// This function is to be used in tests. -pub fn v1_to_v2_sanity_check( - db: Arc, - config: Config, - expected_candidates: HashSet, -) -> Result<()> { - let backend = crate::DbBackend::new(db, config); - - let all_blocks = backend - .load_all_blocks() - .unwrap() - .iter() - .map(|block_hash| backend.load_block_entry(block_hash).unwrap().unwrap()) - .collect::>(); - - let mut candidates = HashSet::new(); - - // Iterate all blocks and approval entries. - for block in all_blocks { - for (_core_index, candidate_hash) in block.candidates() { - // Loading the candidate will also perform the conversion to the updated format and - // return that represantation. - if let Some(candidate_entry) = backend.load_candidate_entry(&candidate_hash).unwrap() { - candidates.insert(candidate_entry.candidate.hash()); - } - } - } - - assert_eq!(candidates, expected_candidates); - - Ok(()) -} - // Fills the db with dummy data in v1 scheme. -pub fn v1_to_v2_fill_test_data( +pub fn v1_fill_test_data( db: Arc, config: Config, dummy_candidate_create: F, diff --git a/polkadot/node/core/approval-voting/src/approval_db/v2/mod.rs b/polkadot/node/core/approval-voting/src/approval_db/v2/mod.rs index 66df6ee8f65..da42fc5be48 100644 --- a/polkadot/node/core/approval-voting/src/approval_db/v2/mod.rs +++ b/polkadot/node/core/approval-voting/src/approval_db/v2/mod.rs @@ -21,145 +21,23 @@ use polkadot_node_primitives::approval::{v1::DelayTranche, v2::AssignmentCertV2} use polkadot_node_subsystem::{SubsystemError, SubsystemResult}; use polkadot_node_subsystem_util::database::{DBTransaction, Database}; use polkadot_primitives::{ - BlockNumber, CandidateHash, CandidateReceipt, CoreIndex, GroupIndex, Hash, SessionIndex, - ValidatorIndex, ValidatorSignature, + BlockNumber, CandidateHash, CandidateIndex, CandidateReceipt, CoreIndex, GroupIndex, Hash, + SessionIndex, ValidatorIndex, ValidatorSignature, }; use sp_consensus_slots::Slot; use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec}; -use std::{collections::BTreeMap, sync::Arc}; +use std::collections::BTreeMap; -use crate::{ - backend::{Backend, BackendWriteOp, V1ReadBackend}, - persisted_entries, -}; +use crate::backend::V1ReadBackend; -const STORED_BLOCKS_KEY: &[u8] = b"Approvals_StoredBlocks"; +use super::common::{block_entry_key, candidate_entry_key, load_decode, Config}; pub mod migration_helpers; #[cfg(test)] pub mod tests; -/// `DbBackend` is a concrete implementation of the higher-level Backend trait -pub struct DbBackend { - inner: Arc, - config: Config, -} - -impl DbBackend { - /// Create a new [`DbBackend`] with the supplied key-value store and - /// config. - pub fn new(db: Arc, config: Config) -> Self { - DbBackend { inner: db, config } - } -} - -impl V1ReadBackend for DbBackend { - fn load_candidate_entry_v1( - &self, - candidate_hash: &CandidateHash, - ) -> SubsystemResult> { - load_candidate_entry_v1(&*self.inner, &self.config, candidate_hash) - .map(|e| e.map(Into::into)) - } - - fn load_block_entry_v1( - &self, - block_hash: &Hash, - ) -> SubsystemResult> { - load_block_entry_v1(&*self.inner, &self.config, block_hash).map(|e| e.map(Into::into)) - } -} - -impl Backend for DbBackend { - fn load_block_entry( - &self, - block_hash: &Hash, - ) -> SubsystemResult> { - load_block_entry(&*self.inner, &self.config, block_hash).map(|e| e.map(Into::into)) - } - - fn load_candidate_entry( - &self, - candidate_hash: &CandidateHash, - ) -> SubsystemResult> { - load_candidate_entry(&*self.inner, &self.config, candidate_hash).map(|e| e.map(Into::into)) - } - - fn load_blocks_at_height(&self, block_height: &BlockNumber) -> SubsystemResult> { - load_blocks_at_height(&*self.inner, &self.config, block_height) - } - - fn load_all_blocks(&self) -> SubsystemResult> { - load_all_blocks(&*self.inner, &self.config) - } - - fn load_stored_blocks(&self) -> SubsystemResult> { - load_stored_blocks(&*self.inner, &self.config) - } - - /// Atomically write the list of operations, with later operations taking precedence over prior. - fn write(&mut self, ops: I) -> SubsystemResult<()> - where - I: IntoIterator, - { - let mut tx = DBTransaction::new(); - for op in ops { - match op { - BackendWriteOp::WriteStoredBlockRange(stored_block_range) => { - tx.put_vec( - self.config.col_approval_data, - &STORED_BLOCKS_KEY, - stored_block_range.encode(), - ); - }, - BackendWriteOp::DeleteStoredBlockRange => { - tx.delete(self.config.col_approval_data, &STORED_BLOCKS_KEY); - }, - BackendWriteOp::WriteBlocksAtHeight(h, blocks) => { - tx.put_vec( - self.config.col_approval_data, - &blocks_at_height_key(h), - blocks.encode(), - ); - }, - BackendWriteOp::DeleteBlocksAtHeight(h) => { - tx.delete(self.config.col_approval_data, &blocks_at_height_key(h)); - }, - BackendWriteOp::WriteBlockEntry(block_entry) => { - let block_entry: BlockEntry = block_entry.into(); - tx.put_vec( - self.config.col_approval_data, - &block_entry_key(&block_entry.block_hash), - block_entry.encode(), - ); - }, - BackendWriteOp::DeleteBlockEntry(hash) => { - tx.delete(self.config.col_approval_data, &block_entry_key(&hash)); - }, - BackendWriteOp::WriteCandidateEntry(candidate_entry) => { - let candidate_entry: CandidateEntry = candidate_entry.into(); - tx.put_vec( - self.config.col_approval_data, - &candidate_entry_key(&candidate_entry.candidate.hash()), - candidate_entry.encode(), - ); - }, - BackendWriteOp::DeleteCandidateEntry(candidate_hash) => { - tx.delete(self.config.col_approval_data, &candidate_entry_key(&candidate_hash)); - }, - } - } - - self.inner.write(tx).map_err(|e| e.into()) - } -} - -/// A range from earliest..last block number stored within the DB. -#[derive(Encode, Decode, Debug, Clone, PartialEq)] -pub struct StoredBlockRange(pub BlockNumber, pub BlockNumber); - // slot_duration * 2 + DelayTranche gives the number of delay tranches since the // unix epoch. #[derive(Encode, Decode, Clone, Copy, Debug, PartialEq)] @@ -168,13 +46,6 @@ pub struct Tick(u64); /// Convenience type definition pub type Bitfield = BitVec; -/// The database config. -#[derive(Debug, Clone, Copy)] -pub struct Config { - /// The column family in the database where data is stored. - pub col_approval_data: u32, -} - /// Details pertaining to our assignment on a block. #[derive(Encode, Decode, Debug, Clone, PartialEq)] pub struct OurAssignment { @@ -259,118 +130,6 @@ impl From for crate::Tick { } } -/// Errors while accessing things from the DB. -#[derive(Debug, derive_more::From, derive_more::Display)] -pub enum Error { - Io(std::io::Error), - InvalidDecoding(parity_scale_codec::Error), - InternalError(SubsystemError), -} - -impl std::error::Error for Error {} - -/// Result alias for DB errors. -pub type Result = std::result::Result; - -pub(crate) fn load_decode( - store: &dyn Database, - col_approval_data: u32, - key: &[u8], -) -> Result> { - match store.get(col_approval_data, key)? { - None => Ok(None), - Some(raw) => D::decode(&mut &raw[..]).map(Some).map_err(Into::into), - } -} - -/// The key a given block entry is stored under. -pub(crate) fn block_entry_key(block_hash: &Hash) -> [u8; 46] { - const BLOCK_ENTRY_PREFIX: [u8; 14] = *b"Approvals_blck"; - - let mut key = [0u8; 14 + 32]; - key[0..14].copy_from_slice(&BLOCK_ENTRY_PREFIX); - key[14..][..32].copy_from_slice(block_hash.as_ref()); - - key -} - -/// The key a given candidate entry is stored under. -pub(crate) fn candidate_entry_key(candidate_hash: &CandidateHash) -> [u8; 46] { - const CANDIDATE_ENTRY_PREFIX: [u8; 14] = *b"Approvals_cand"; - - let mut key = [0u8; 14 + 32]; - key[0..14].copy_from_slice(&CANDIDATE_ENTRY_PREFIX); - key[14..][..32].copy_from_slice(candidate_hash.0.as_ref()); - - key -} - -/// The key a set of block hashes corresponding to a block number is stored under. -pub(crate) fn blocks_at_height_key(block_number: BlockNumber) -> [u8; 16] { - const BLOCKS_AT_HEIGHT_PREFIX: [u8; 12] = *b"Approvals_at"; - - let mut key = [0u8; 12 + 4]; - key[0..12].copy_from_slice(&BLOCKS_AT_HEIGHT_PREFIX); - block_number.using_encoded(|s| key[12..16].copy_from_slice(s)); - - key -} - -/// Return all blocks which have entries in the DB, ascending, by height. -pub fn load_all_blocks(store: &dyn Database, config: &Config) -> SubsystemResult> { - let mut hashes = Vec::new(); - if let Some(stored_blocks) = load_stored_blocks(store, config)? { - for height in stored_blocks.0..stored_blocks.1 { - let blocks = load_blocks_at_height(store, config, &height)?; - hashes.extend(blocks); - } - } - - Ok(hashes) -} - -/// Load the stored-blocks key from the state. -pub fn load_stored_blocks( - store: &dyn Database, - config: &Config, -) -> SubsystemResult> { - load_decode(store, config.col_approval_data, STORED_BLOCKS_KEY) - .map_err(|e| SubsystemError::with_origin("approval-voting", e)) -} - -/// Load a blocks-at-height entry for a given block number. -pub fn load_blocks_at_height( - store: &dyn Database, - config: &Config, - block_number: &BlockNumber, -) -> SubsystemResult> { - load_decode(store, config.col_approval_data, &blocks_at_height_key(*block_number)) - .map(|x| x.unwrap_or_default()) - .map_err(|e| SubsystemError::with_origin("approval-voting", e)) -} - -/// Load a block entry from the aux store. -pub fn load_block_entry( - store: &dyn Database, - config: &Config, - block_hash: &Hash, -) -> SubsystemResult> { - load_decode(store, config.col_approval_data, &block_entry_key(block_hash)) - .map(|u: Option| u.map(|v| v.into())) - .map_err(|e| SubsystemError::with_origin("approval-voting", e)) -} - -/// Load a candidate entry from the aux store in current version format. -pub fn load_candidate_entry( - store: &dyn Database, - config: &Config, - candidate_hash: &CandidateHash, -) -> SubsystemResult> { - load_decode(store, config.col_approval_data, &candidate_entry_key(candidate_hash)) - .map(|u: Option| u.map(|v| v.into())) - .map_err(|e| SubsystemError::with_origin("approval-voting", e)) -} - /// Load a candidate entry from the aux store in v1 format. pub fn load_candidate_entry_v1( store: &dyn Database, diff --git a/polkadot/node/core/approval-voting/src/approval_db/v2/tests.rs b/polkadot/node/core/approval-voting/src/approval_db/v2/tests.rs index 50a5a924ca8..6021b44c276 100644 --- a/polkadot/node/core/approval-voting/src/approval_db/v2/tests.rs +++ b/polkadot/node/core/approval-voting/src/approval_db/v2/tests.rs @@ -16,13 +16,22 @@ //! Tests for the aux-schema of approval voting. -use super::{DbBackend, StoredBlockRange, *}; use crate::{ + approval_db::{ + common::{migration_helpers::make_bitvec, DbBackend, StoredBlockRange, *}, + v2::*, + v3::{load_block_entry_v2, load_candidate_entry_v2}, + }, backend::{Backend, OverlayedBackend}, ops::{add_block_entry, canonicalize, force_approve, NewCandidateInfo}, }; +use polkadot_primitives::{ + BlockNumber, CandidateHash, CandidateReceipt, CoreIndex, GroupIndex, Hash, +}; + use polkadot_node_subsystem_util::database::Database; use polkadot_primitives::Id as ParaId; +use sp_consensus_slots::Slot; use std::{collections::HashMap, sync::Arc}; use ::test_helpers::{dummy_candidate_receipt, dummy_candidate_receipt_bad_sig, dummy_hash}; @@ -60,10 +69,6 @@ fn make_block_entry( } } -fn make_bitvec(len: usize) -> BitVec { - bitvec::bitvec![u8, BitOrderLsb0; 0; len] -} - fn make_candidate(para_id: ParaId, relay_parent: Hash) -> CandidateReceipt { let mut c = dummy_candidate_receipt(dummy_hash()); @@ -110,7 +115,10 @@ fn read_write() { overlay_db.write_stored_block_range(range.clone()); overlay_db.write_blocks_at_height(1, at_height.clone()); overlay_db.write_block_entry(block_entry.clone().into()); - overlay_db.write_candidate_entry(candidate_entry.clone().into()); + overlay_db.write_candidate_entry(crate::persisted_entries::CandidateEntry::from_v2( + candidate_entry.clone(), + 0, + )); let write_ops = overlay_db.into_write_ops(); db.write(write_ops).unwrap(); @@ -118,11 +126,11 @@ fn read_write() { assert_eq!(load_stored_blocks(store.as_ref(), &TEST_CONFIG).unwrap(), Some(range)); assert_eq!(load_blocks_at_height(store.as_ref(), &TEST_CONFIG, &1).unwrap(), at_height); assert_eq!( - load_block_entry(store.as_ref(), &TEST_CONFIG, &hash_a).unwrap(), + load_block_entry_v2(store.as_ref(), &TEST_CONFIG, &hash_a).unwrap(), Some(block_entry.into()) ); assert_eq!( - load_candidate_entry(store.as_ref(), &TEST_CONFIG, &candidate_hash).unwrap(), + load_candidate_entry_v2(store.as_ref(), &TEST_CONFIG, &candidate_hash).unwrap(), Some(candidate_entry.into()), ); @@ -134,8 +142,8 @@ fn read_write() { db.write(write_ops).unwrap(); assert!(load_blocks_at_height(store.as_ref(), &TEST_CONFIG, &1).unwrap().is_empty()); - assert!(load_block_entry(store.as_ref(), &TEST_CONFIG, &hash_a).unwrap().is_none()); - assert!(load_candidate_entry(store.as_ref(), &TEST_CONFIG, &candidate_hash) + assert!(load_block_entry_v2(store.as_ref(), &TEST_CONFIG, &hash_a).unwrap().is_none()); + assert!(load_candidate_entry_v2(store.as_ref(), &TEST_CONFIG, &candidate_hash) .unwrap() .is_none()); } @@ -196,25 +204,27 @@ fn add_block_entry_works() { db.write(write_ops).unwrap(); assert_eq!( - load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_a).unwrap(), + load_block_entry_v2(store.as_ref(), &TEST_CONFIG, &block_hash_a).unwrap(), Some(block_entry_a.into()) ); assert_eq!( - load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_b).unwrap(), + load_block_entry_v2(store.as_ref(), &TEST_CONFIG, &block_hash_b).unwrap(), Some(block_entry_b.into()) ); - let candidate_entry_a = load_candidate_entry(store.as_ref(), &TEST_CONFIG, &candidate_hash_a) - .unwrap() - .unwrap(); + let candidate_entry_a = + load_candidate_entry_v2(store.as_ref(), &TEST_CONFIG, &candidate_hash_a) + .unwrap() + .unwrap(); assert_eq!( candidate_entry_a.block_assignments.keys().collect::>(), vec![&block_hash_a, &block_hash_b] ); - let candidate_entry_b = load_candidate_entry(store.as_ref(), &TEST_CONFIG, &candidate_hash_b) - .unwrap() - .unwrap(); + let candidate_entry_b = + load_candidate_entry_v2(store.as_ref(), &TEST_CONFIG, &candidate_hash_b) + .unwrap() + .unwrap(); assert_eq!(candidate_entry_b.block_assignments.keys().collect::>(), vec![&block_hash_b]); } @@ -243,11 +253,11 @@ fn add_block_entry_adds_child() { block_entry_a.children.push(block_hash_b); assert_eq!( - load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_a).unwrap(), + load_block_entry_v2(store.as_ref(), &TEST_CONFIG, &block_hash_a).unwrap(), Some(block_entry_a.into()) ); assert_eq!( - load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_b).unwrap(), + load_block_entry_v2(store.as_ref(), &TEST_CONFIG, &block_hash_b).unwrap(), Some(block_entry_b.into()) ); } @@ -365,13 +375,15 @@ fn canonicalize_works() { for (c_hash, in_blocks) in expected { let (entry, in_blocks) = match in_blocks { None => { - assert!(load_candidate_entry(store.as_ref(), &TEST_CONFIG, &c_hash) + assert!(load_candidate_entry_v2(store.as_ref(), &TEST_CONFIG, &c_hash) .unwrap() .is_none()); continue }, Some(i) => ( - load_candidate_entry(store.as_ref(), &TEST_CONFIG, &c_hash).unwrap().unwrap(), + load_candidate_entry_v2(store.as_ref(), &TEST_CONFIG, &c_hash) + .unwrap() + .unwrap(), i, ), }; @@ -388,13 +400,13 @@ fn canonicalize_works() { for (hash, with_candidates) in expected { let (entry, with_candidates) = match with_candidates { None => { - assert!(load_block_entry(store.as_ref(), &TEST_CONFIG, &hash) + assert!(load_block_entry_v2(store.as_ref(), &TEST_CONFIG, &hash) .unwrap() .is_none()); continue }, Some(i) => - (load_block_entry(store.as_ref(), &TEST_CONFIG, &hash).unwrap().unwrap(), i), + (load_block_entry_v2(store.as_ref(), &TEST_CONFIG, &hash).unwrap().unwrap(), i), }; assert_eq!(entry.candidates.len(), with_candidates.len()); @@ -510,22 +522,22 @@ fn force_approve_works() { let write_ops = overlay_db.into_write_ops(); db.write(write_ops).unwrap(); - assert!(load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_a,) + assert!(load_block_entry_v2(store.as_ref(), &TEST_CONFIG, &block_hash_a,) .unwrap() .unwrap() .approved_bitfield .all()); - assert!(load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_b,) + assert!(load_block_entry_v2(store.as_ref(), &TEST_CONFIG, &block_hash_b,) .unwrap() .unwrap() .approved_bitfield .all()); - assert!(load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_c,) + assert!(load_block_entry_v2(store.as_ref(), &TEST_CONFIG, &block_hash_c,) .unwrap() .unwrap() .approved_bitfield .not_any()); - assert!(load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_d,) + assert!(load_block_entry_v2(store.as_ref(), &TEST_CONFIG, &block_hash_d,) .unwrap() .unwrap() .approved_bitfield diff --git a/polkadot/node/core/approval-voting/src/approval_db/v3/migration_helpers.rs b/polkadot/node/core/approval-voting/src/approval_db/v3/migration_helpers.rs new file mode 100644 index 00000000000..ad5e89ef3de --- /dev/null +++ b/polkadot/node/core/approval-voting/src/approval_db/v3/migration_helpers.rs @@ -0,0 +1,237 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Approval DB migration helpers. +use super::*; +use crate::{ + approval_db::common::{ + block_entry_key, candidate_entry_key, + migration_helpers::{dummy_assignment_cert, make_bitvec}, + Config, Error, Result, StoredBlockRange, + }, + backend::{Backend, V2ReadBackend}, +}; +use polkadot_node_primitives::approval::v1::AssignmentCertKind; +use polkadot_node_subsystem_util::database::Database; +use sp_application_crypto::sp_core::H256; +use std::{collections::HashSet, sync::Arc}; + +/// Migrates `BlockEntry`, `CandidateEntry`, `ApprovalEntry` and `OurApproval` to version 3. +/// Returns on any error. +/// Must only be used in parachains DB migration code - `polkadot-service` crate. +pub fn v2_to_latest(db: Arc, config: Config) -> Result<()> { + let mut backend = crate::DbBackend::new(db, config); + let all_blocks = backend + .load_all_blocks() + .map_err(|e| Error::InternalError(e))? + .iter() + .filter_map(|block_hash| { + backend + .load_block_entry_v2(block_hash) + .map_err(|e| Error::InternalError(e)) + .ok()? + }) + .collect::>(); + + gum::info!( + target: crate::LOG_TARGET, + "Migrating candidate entries on top of {} blocks", + all_blocks.len() + ); + + let mut overlay = crate::OverlayedBackend::new(&backend); + let mut counter = 0; + // Get all candidate entries, approval entries and convert each of them. + for block in all_blocks { + for (candidate_index, (_core_index, candidate_hash)) in + block.candidates().iter().enumerate() + { + // Loading the candidate will also perform the conversion to the updated format and + // return that represantation. + if let Some(candidate_entry) = backend + .load_candidate_entry_v2(&candidate_hash, candidate_index as CandidateIndex) + .map_err(|e| Error::InternalError(e))? + { + // Write the updated representation. + overlay.write_candidate_entry(candidate_entry); + counter += 1; + } + } + overlay.write_block_entry(block); + } + + gum::info!(target: crate::LOG_TARGET, "Migrated {} entries", counter); + + // Commit all changes to DB. + let write_ops = overlay.into_write_ops(); + backend.write(write_ops).unwrap(); + + Ok(()) +} + +// Checks if the migration doesn't leave the DB in an unsane state. +// This function is to be used in tests. +pub fn v1_to_latest_sanity_check( + db: Arc, + config: Config, + expected_candidates: HashSet, +) -> Result<()> { + let backend = crate::DbBackend::new(db, config); + + let all_blocks = backend + .load_all_blocks() + .unwrap() + .iter() + .map(|block_hash| backend.load_block_entry(block_hash).unwrap().unwrap()) + .collect::>(); + + let mut candidates = HashSet::new(); + + // Iterate all blocks and approval entries. + for block in all_blocks { + for (_core_index, candidate_hash) in block.candidates() { + // Loading the candidate will also perform the conversion to the updated format and + // return that represantation. + if let Some(candidate_entry) = backend.load_candidate_entry(&candidate_hash).unwrap() { + candidates.insert(candidate_entry.candidate.hash()); + } + } + } + + assert_eq!(candidates, expected_candidates); + + Ok(()) +} + +// Fills the db with dummy data in v2 scheme. +pub fn v2_fill_test_data( + db: Arc, + config: Config, + dummy_candidate_create: F, +) -> Result> +where + F: Fn(H256) -> CandidateReceipt, +{ + let mut backend = crate::DbBackend::new(db.clone(), config); + let mut overlay_db = crate::OverlayedBackend::new(&backend); + let mut expected_candidates = HashSet::new(); + + const RELAY_BLOCK_COUNT: u32 = 10; + + let range = StoredBlockRange(1, 11); + overlay_db.write_stored_block_range(range.clone()); + + for relay_number in 1..=RELAY_BLOCK_COUNT { + let relay_hash = Hash::repeat_byte(relay_number as u8); + let assignment_core_index = CoreIndex(relay_number); + let candidate = dummy_candidate_create(relay_hash); + let candidate_hash = candidate.hash(); + + let at_height = vec![relay_hash]; + + let block_entry = make_block_entry_v2( + relay_hash, + Default::default(), + relay_number, + vec![(assignment_core_index, candidate_hash)], + ); + + let dummy_assignment = crate::approval_db::v2::OurAssignment { + cert: dummy_assignment_cert(AssignmentCertKind::RelayVRFModulo { sample: 0 }).into(), + tranche: 0, + validator_index: ValidatorIndex(0), + triggered: false, + }; + + let candidate_entry = crate::approval_db::v2::CandidateEntry { + candidate, + session: 123, + block_assignments: vec![( + relay_hash, + crate::approval_db::v2::ApprovalEntry { + tranches: Vec::new(), + backing_group: GroupIndex(1), + our_assignment: Some(dummy_assignment), + our_approval_sig: None, + approved: false, + assigned_validators: make_bitvec(1), + }, + )] + .into_iter() + .collect(), + approvals: Default::default(), + }; + + overlay_db.write_blocks_at_height(relay_number, at_height.clone()); + expected_candidates.insert(candidate_entry.candidate.hash()); + + db.write(write_candidate_entry_v2(candidate_entry, config)).unwrap(); + db.write(write_block_entry_v2(block_entry, config)).unwrap(); + } + + let write_ops = overlay_db.into_write_ops(); + backend.write(write_ops).unwrap(); + + Ok(expected_candidates) +} + +fn make_block_entry_v2( + block_hash: Hash, + parent_hash: Hash, + block_number: BlockNumber, + candidates: Vec<(CoreIndex, CandidateHash)>, +) -> crate::approval_db::v2::BlockEntry { + crate::approval_db::v2::BlockEntry { + block_hash, + parent_hash, + block_number, + session: 1, + slot: Slot::from(1), + relay_vrf_story: [0u8; 32], + approved_bitfield: make_bitvec(candidates.len()), + distributed_assignments: make_bitvec(candidates.len()), + candidates, + children: Vec::new(), + } +} + +// Low level DB helper to write a candidate entry in v1 scheme. +fn write_candidate_entry_v2( + candidate_entry: crate::approval_db::v2::CandidateEntry, + config: Config, +) -> DBTransaction { + let mut tx = DBTransaction::new(); + tx.put_vec( + config.col_approval_data, + &candidate_entry_key(&candidate_entry.candidate.hash()), + candidate_entry.encode(), + ); + tx +} + +// Low level DB helper to write a block entry in v1 scheme. +fn write_block_entry_v2( + block_entry: crate::approval_db::v2::BlockEntry, + config: Config, +) -> DBTransaction { + let mut tx = DBTransaction::new(); + tx.put_vec( + config.col_approval_data, + &block_entry_key(&block_entry.block_hash), + block_entry.encode(), + ); + tx +} diff --git a/polkadot/node/core/approval-voting/src/approval_db/v3/mod.rs b/polkadot/node/core/approval-voting/src/approval_db/v3/mod.rs new file mode 100644 index 00000000000..3e4f4302195 --- /dev/null +++ b/polkadot/node/core/approval-voting/src/approval_db/v3/mod.rs @@ -0,0 +1,137 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Version 3 of the DB schema. +//! +//! Version 3 modifies the `our_approval` format of `ApprovalEntry` +//! and adds a new field `pending_signatures` for `BlockEntry` + +use parity_scale_codec::{Decode, Encode}; +use polkadot_node_primitives::approval::v2::CandidateBitfield; +use polkadot_node_subsystem::SubsystemResult; +use polkadot_node_subsystem_util::database::{DBTransaction, Database}; +use polkadot_overseer::SubsystemError; +use polkadot_primitives::{ + BlockNumber, CandidateHash, CandidateIndex, CandidateReceipt, CoreIndex, GroupIndex, Hash, + SessionIndex, ValidatorIndex, ValidatorSignature, +}; + +use sp_consensus_slots::Slot; + +use std::collections::BTreeMap; + +use super::common::{block_entry_key, candidate_entry_key, load_decode, Config}; + +/// Re-export this structs as v3 since they did not change between v2 and v3. +pub use super::v2::{Bitfield, OurAssignment, Tick, TrancheEntry}; + +pub mod migration_helpers; + +#[cfg(test)] +pub mod tests; + +/// Metadata about our approval signature +#[derive(Encode, Decode, Debug, Clone, PartialEq)] +pub struct OurApproval { + /// The signature for the candidates hashes pointed by indices. + pub signature: ValidatorSignature, + /// The indices of the candidates signed in this approval. + pub signed_candidates_indices: CandidateBitfield, +} + +/// Metadata regarding approval of a particular candidate within the context of some +/// particular block. +#[derive(Encode, Decode, Debug, Clone, PartialEq)] +pub struct ApprovalEntry { + pub tranches: Vec, + pub backing_group: GroupIndex, + pub our_assignment: Option, + pub our_approval_sig: Option, + // `n_validators` bits. + pub assigned_validators: Bitfield, + pub approved: bool, +} + +/// Metadata regarding approval of a particular candidate. +#[derive(Encode, Decode, Debug, Clone, PartialEq)] +pub struct CandidateEntry { + pub candidate: CandidateReceipt, + pub session: SessionIndex, + // Assignments are based on blocks, so we need to track assignments separately + // based on the block we are looking at. + pub block_assignments: BTreeMap, + pub approvals: Bitfield, +} + +/// Metadata regarding approval of a particular block, by way of approval of the +/// candidates contained within it. +#[derive(Encode, Decode, Debug, Clone, PartialEq)] +pub struct BlockEntry { + pub block_hash: Hash, + pub block_number: BlockNumber, + pub parent_hash: Hash, + pub session: SessionIndex, + pub slot: Slot, + /// Random bytes derived from the VRF submitted within the block by the block + /// author as a credential and used as input to approval assignment criteria. + pub relay_vrf_story: [u8; 32], + // The candidates included as-of this block and the index of the core they are + // leaving. Sorted ascending by core index. + pub candidates: Vec<(CoreIndex, CandidateHash)>, + // A bitfield where the i'th bit corresponds to the i'th candidate in `candidates`. + // The i'th bit is `true` iff the candidate has been approved in the context of this + // block. The block can be considered approved if the bitfield has all bits set to `true`. + pub approved_bitfield: Bitfield, + pub children: Vec, + // A list of candidates we have checked, but didn't not sign and + // advertise the vote yet. + pub candidates_pending_signature: BTreeMap, + // Assignments we already distributed. A 1 bit means the candidate index for which + // we already have sent out an assignment. We need this to avoid distributing + // multiple core assignments more than once. + pub distributed_assignments: Bitfield, +} + +#[derive(Encode, Decode, Debug, Clone, PartialEq)] +/// Context needed for creating an approval signature for a given candidate. +pub struct CandidateSigningContext { + /// The candidate hash, to be included in the signature. + pub candidate_hash: CandidateHash, + /// The latest tick we have to create and send the approval. + pub sign_no_later_than_tick: Tick, +} + +/// Load a candidate entry from the aux store in v2 format. +pub fn load_candidate_entry_v2( + store: &dyn Database, + config: &Config, + candidate_hash: &CandidateHash, +) -> SubsystemResult> { + load_decode(store, config.col_approval_data, &candidate_entry_key(candidate_hash)) + .map(|u: Option| u.map(|v| v.into())) + .map_err(|e| SubsystemError::with_origin("approval-voting", e)) +} + +/// Load a block entry from the aux store in v2 format. +pub fn load_block_entry_v2( + store: &dyn Database, + config: &Config, + block_hash: &Hash, +) -> SubsystemResult> { + load_decode(store, config.col_approval_data, &block_entry_key(block_hash)) + .map(|u: Option| u.map(|v| v.into())) + .map_err(|e| SubsystemError::with_origin("approval-voting", e)) +} diff --git a/polkadot/node/core/approval-voting/src/approval_db/v3/tests.rs b/polkadot/node/core/approval-voting/src/approval_db/v3/tests.rs new file mode 100644 index 00000000000..08c65461bca --- /dev/null +++ b/polkadot/node/core/approval-voting/src/approval_db/v3/tests.rs @@ -0,0 +1,575 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Tests for the aux-schema of approval voting. + +use crate::{ + approval_db::{ + common::{migration_helpers::make_bitvec, DbBackend, StoredBlockRange, *}, + v3::*, + }, + backend::{Backend, OverlayedBackend}, + ops::{add_block_entry, canonicalize, force_approve, NewCandidateInfo}, +}; +use polkadot_primitives::{ + BlockNumber, CandidateHash, CandidateReceipt, CoreIndex, GroupIndex, Hash, +}; + +use polkadot_node_subsystem_util::database::Database; +use polkadot_primitives::Id as ParaId; +use sp_consensus_slots::Slot; +use std::{collections::HashMap, sync::Arc}; + +use ::test_helpers::{dummy_candidate_receipt, dummy_candidate_receipt_bad_sig, dummy_hash}; + +const DATA_COL: u32 = 0; + +const NUM_COLUMNS: u32 = 1; + +const TEST_CONFIG: Config = Config { col_approval_data: DATA_COL }; + +fn make_db() -> (DbBackend, Arc) { + let db = kvdb_memorydb::create(NUM_COLUMNS); + let db = polkadot_node_subsystem_util::database::kvdb_impl::DbAdapter::new(db, &[]); + let db_writer: Arc = Arc::new(db); + (DbBackend::new(db_writer.clone(), TEST_CONFIG), db_writer) +} + +fn make_block_entry( + block_hash: Hash, + parent_hash: Hash, + block_number: BlockNumber, + candidates: Vec<(CoreIndex, CandidateHash)>, +) -> BlockEntry { + BlockEntry { + block_hash, + parent_hash, + block_number, + session: 1, + slot: Slot::from(1), + relay_vrf_story: [0u8; 32], + approved_bitfield: make_bitvec(candidates.len()), + candidates, + children: Vec::new(), + candidates_pending_signature: Default::default(), + distributed_assignments: Default::default(), + } +} + +fn make_candidate(para_id: ParaId, relay_parent: Hash) -> CandidateReceipt { + let mut c = dummy_candidate_receipt(dummy_hash()); + + c.descriptor.para_id = para_id; + c.descriptor.relay_parent = relay_parent; + + c +} + +#[test] +fn read_write() { + let (mut db, store) = make_db(); + + let hash_a = Hash::repeat_byte(1); + let hash_b = Hash::repeat_byte(2); + let candidate_hash = dummy_candidate_receipt_bad_sig(dummy_hash(), None).hash(); + + let range = StoredBlockRange(10, 20); + let at_height = vec![hash_a, hash_b]; + + let block_entry = + make_block_entry(hash_a, Default::default(), 1, vec![(CoreIndex(0), candidate_hash)]); + + let candidate_entry = CandidateEntry { + candidate: dummy_candidate_receipt_bad_sig(dummy_hash(), None), + session: 5, + block_assignments: vec![( + hash_a, + ApprovalEntry { + tranches: Vec::new(), + backing_group: GroupIndex(1), + our_assignment: None, + our_approval_sig: None, + assigned_validators: Default::default(), + approved: false, + }, + )] + .into_iter() + .collect(), + approvals: Default::default(), + }; + + let mut overlay_db = OverlayedBackend::new(&db); + overlay_db.write_stored_block_range(range.clone()); + overlay_db.write_blocks_at_height(1, at_height.clone()); + overlay_db.write_block_entry(block_entry.clone().into()); + overlay_db.write_candidate_entry(candidate_entry.clone().into()); + + let write_ops = overlay_db.into_write_ops(); + db.write(write_ops).unwrap(); + + assert_eq!(load_stored_blocks(store.as_ref(), &TEST_CONFIG).unwrap(), Some(range)); + assert_eq!(load_blocks_at_height(store.as_ref(), &TEST_CONFIG, &1).unwrap(), at_height); + assert_eq!( + load_block_entry(store.as_ref(), &TEST_CONFIG, &hash_a).unwrap(), + Some(block_entry.into()) + ); + assert_eq!( + load_candidate_entry(store.as_ref(), &TEST_CONFIG, &candidate_hash).unwrap(), + Some(candidate_entry.into()), + ); + + let mut overlay_db = OverlayedBackend::new(&db); + overlay_db.delete_blocks_at_height(1); + overlay_db.delete_block_entry(&hash_a); + overlay_db.delete_candidate_entry(&candidate_hash); + let write_ops = overlay_db.into_write_ops(); + db.write(write_ops).unwrap(); + + assert!(load_blocks_at_height(store.as_ref(), &TEST_CONFIG, &1).unwrap().is_empty()); + assert!(load_block_entry(store.as_ref(), &TEST_CONFIG, &hash_a).unwrap().is_none()); + assert!(load_candidate_entry(store.as_ref(), &TEST_CONFIG, &candidate_hash) + .unwrap() + .is_none()); +} + +#[test] +fn add_block_entry_works() { + let (mut db, store) = make_db(); + + let parent_hash = Hash::repeat_byte(1); + let block_hash_a = Hash::repeat_byte(2); + let block_hash_b = Hash::repeat_byte(69); + + let candidate_receipt_a = make_candidate(ParaId::from(1_u32), parent_hash); + let candidate_receipt_b = make_candidate(ParaId::from(2_u32), parent_hash); + + let candidate_hash_a = candidate_receipt_a.hash(); + let candidate_hash_b = candidate_receipt_b.hash(); + + let block_number = 10; + + let block_entry_a = make_block_entry( + block_hash_a, + parent_hash, + block_number, + vec![(CoreIndex(0), candidate_hash_a)], + ); + + let block_entry_b = make_block_entry( + block_hash_b, + parent_hash, + block_number, + vec![(CoreIndex(0), candidate_hash_a), (CoreIndex(1), candidate_hash_b)], + ); + + let n_validators = 10; + + let mut new_candidate_info = HashMap::new(); + new_candidate_info + .insert(candidate_hash_a, NewCandidateInfo::new(candidate_receipt_a, GroupIndex(0), None)); + + let mut overlay_db = OverlayedBackend::new(&db); + add_block_entry(&mut overlay_db, block_entry_a.clone().into(), n_validators, |h| { + new_candidate_info.get(h).map(|x| x.clone()) + }) + .unwrap(); + let write_ops = overlay_db.into_write_ops(); + db.write(write_ops).unwrap(); + + new_candidate_info + .insert(candidate_hash_b, NewCandidateInfo::new(candidate_receipt_b, GroupIndex(1), None)); + + let mut overlay_db = OverlayedBackend::new(&db); + add_block_entry(&mut overlay_db, block_entry_b.clone().into(), n_validators, |h| { + new_candidate_info.get(h).map(|x| x.clone()) + }) + .unwrap(); + let write_ops = overlay_db.into_write_ops(); + db.write(write_ops).unwrap(); + + assert_eq!( + load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_a).unwrap(), + Some(block_entry_a.into()) + ); + assert_eq!( + load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_b).unwrap(), + Some(block_entry_b.into()) + ); + + let candidate_entry_a = load_candidate_entry(store.as_ref(), &TEST_CONFIG, &candidate_hash_a) + .unwrap() + .unwrap(); + assert_eq!( + candidate_entry_a.block_assignments.keys().collect::>(), + vec![&block_hash_a, &block_hash_b] + ); + + let candidate_entry_b = load_candidate_entry(store.as_ref(), &TEST_CONFIG, &candidate_hash_b) + .unwrap() + .unwrap(); + assert_eq!(candidate_entry_b.block_assignments.keys().collect::>(), vec![&block_hash_b]); +} + +#[test] +fn add_block_entry_adds_child() { + let (mut db, store) = make_db(); + + let parent_hash = Hash::repeat_byte(1); + let block_hash_a = Hash::repeat_byte(2); + let block_hash_b = Hash::repeat_byte(69); + + let mut block_entry_a = make_block_entry(block_hash_a, parent_hash, 1, Vec::new()); + + let block_entry_b = make_block_entry(block_hash_b, block_hash_a, 2, Vec::new()); + + let n_validators = 10; + + let mut overlay_db = OverlayedBackend::new(&db); + add_block_entry(&mut overlay_db, block_entry_a.clone().into(), n_validators, |_| None).unwrap(); + + add_block_entry(&mut overlay_db, block_entry_b.clone().into(), n_validators, |_| None).unwrap(); + + let write_ops = overlay_db.into_write_ops(); + db.write(write_ops).unwrap(); + + block_entry_a.children.push(block_hash_b); + + assert_eq!( + load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_a).unwrap(), + Some(block_entry_a.into()) + ); + assert_eq!( + load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_b).unwrap(), + Some(block_entry_b.into()) + ); +} + +#[test] +fn canonicalize_works() { + let (mut db, store) = make_db(); + + // -> B1 -> C1 -> D1 + // A -> B2 -> C2 -> D2 + // + // We'll canonicalize C1. Everytning except D1 should disappear. + // + // Candidates: + // Cand1 in B2 + // Cand2 in C2 + // Cand3 in C2 and D1 + // Cand4 in D1 + // Cand5 in D2 + // Only Cand3 and Cand4 should remain after canonicalize. + + let n_validators = 10; + + let mut overlay_db = OverlayedBackend::new(&db); + overlay_db.write_stored_block_range(StoredBlockRange(1, 5)); + let write_ops = overlay_db.into_write_ops(); + db.write(write_ops).unwrap(); + + let genesis = Hash::repeat_byte(0); + + let block_hash_a = Hash::repeat_byte(1); + let block_hash_b1 = Hash::repeat_byte(2); + let block_hash_b2 = Hash::repeat_byte(3); + let block_hash_c1 = Hash::repeat_byte(4); + let block_hash_c2 = Hash::repeat_byte(5); + let block_hash_d1 = Hash::repeat_byte(6); + let block_hash_d2 = Hash::repeat_byte(7); + + let candidate_receipt_genesis = make_candidate(ParaId::from(1_u32), genesis); + let candidate_receipt_a = make_candidate(ParaId::from(2_u32), block_hash_a); + let candidate_receipt_b = make_candidate(ParaId::from(3_u32), block_hash_a); + let candidate_receipt_b1 = make_candidate(ParaId::from(4_u32), block_hash_b1); + let candidate_receipt_c1 = make_candidate(ParaId::from(5_u32), block_hash_c1); + + let cand_hash_1 = candidate_receipt_genesis.hash(); + let cand_hash_2 = candidate_receipt_a.hash(); + let cand_hash_3 = candidate_receipt_b.hash(); + let cand_hash_4 = candidate_receipt_b1.hash(); + let cand_hash_5 = candidate_receipt_c1.hash(); + + let block_entry_a = make_block_entry(block_hash_a, genesis, 1, Vec::new()); + let block_entry_b1 = make_block_entry(block_hash_b1, block_hash_a, 2, Vec::new()); + let block_entry_b2 = + make_block_entry(block_hash_b2, block_hash_a, 2, vec![(CoreIndex(0), cand_hash_1)]); + let block_entry_c1 = make_block_entry(block_hash_c1, block_hash_b1, 3, Vec::new()); + let block_entry_c2 = make_block_entry( + block_hash_c2, + block_hash_b2, + 3, + vec![(CoreIndex(0), cand_hash_2), (CoreIndex(1), cand_hash_3)], + ); + let block_entry_d1 = make_block_entry( + block_hash_d1, + block_hash_c1, + 4, + vec![(CoreIndex(0), cand_hash_3), (CoreIndex(1), cand_hash_4)], + ); + let block_entry_d2 = + make_block_entry(block_hash_d2, block_hash_c2, 4, vec![(CoreIndex(0), cand_hash_5)]); + + let candidate_info = { + let mut candidate_info = HashMap::new(); + candidate_info.insert( + cand_hash_1, + NewCandidateInfo::new(candidate_receipt_genesis, GroupIndex(1), None), + ); + + candidate_info + .insert(cand_hash_2, NewCandidateInfo::new(candidate_receipt_a, GroupIndex(2), None)); + + candidate_info + .insert(cand_hash_3, NewCandidateInfo::new(candidate_receipt_b, GroupIndex(3), None)); + + candidate_info + .insert(cand_hash_4, NewCandidateInfo::new(candidate_receipt_b1, GroupIndex(4), None)); + + candidate_info + .insert(cand_hash_5, NewCandidateInfo::new(candidate_receipt_c1, GroupIndex(5), None)); + + candidate_info + }; + + // now insert all the blocks. + let blocks = vec![ + block_entry_a.clone(), + block_entry_b1.clone(), + block_entry_b2.clone(), + block_entry_c1.clone(), + block_entry_c2.clone(), + block_entry_d1.clone(), + block_entry_d2.clone(), + ]; + + let mut overlay_db = OverlayedBackend::new(&db); + for block_entry in blocks { + add_block_entry(&mut overlay_db, block_entry.into(), n_validators, |h| { + candidate_info.get(h).map(|x| x.clone()) + }) + .unwrap(); + } + let write_ops = overlay_db.into_write_ops(); + db.write(write_ops).unwrap(); + + let check_candidates_in_store = |expected: Vec<(CandidateHash, Option>)>| { + for (c_hash, in_blocks) in expected { + let (entry, in_blocks) = match in_blocks { + None => { + assert!(load_candidate_entry(store.as_ref(), &TEST_CONFIG, &c_hash) + .unwrap() + .is_none()); + continue + }, + Some(i) => ( + load_candidate_entry(store.as_ref(), &TEST_CONFIG, &c_hash).unwrap().unwrap(), + i, + ), + }; + + assert_eq!(entry.block_assignments.len(), in_blocks.len()); + + for x in in_blocks { + assert!(entry.block_assignments.contains_key(&x)); + } + } + }; + + let check_blocks_in_store = |expected: Vec<(Hash, Option>)>| { + for (hash, with_candidates) in expected { + let (entry, with_candidates) = match with_candidates { + None => { + assert!(load_block_entry(store.as_ref(), &TEST_CONFIG, &hash) + .unwrap() + .is_none()); + continue + }, + Some(i) => + (load_block_entry(store.as_ref(), &TEST_CONFIG, &hash).unwrap().unwrap(), i), + }; + + assert_eq!(entry.candidates.len(), with_candidates.len()); + + for x in with_candidates { + assert!(entry.candidates.iter().any(|(_, c)| c == &x)); + } + } + }; + + check_candidates_in_store(vec![ + (cand_hash_1, Some(vec![block_hash_b2])), + (cand_hash_2, Some(vec![block_hash_c2])), + (cand_hash_3, Some(vec![block_hash_c2, block_hash_d1])), + (cand_hash_4, Some(vec![block_hash_d1])), + (cand_hash_5, Some(vec![block_hash_d2])), + ]); + + check_blocks_in_store(vec![ + (block_hash_a, Some(vec![])), + (block_hash_b1, Some(vec![])), + (block_hash_b2, Some(vec![cand_hash_1])), + (block_hash_c1, Some(vec![])), + (block_hash_c2, Some(vec![cand_hash_2, cand_hash_3])), + (block_hash_d1, Some(vec![cand_hash_3, cand_hash_4])), + (block_hash_d2, Some(vec![cand_hash_5])), + ]); + + let mut overlay_db = OverlayedBackend::new(&db); + canonicalize(&mut overlay_db, 3, block_hash_c1).unwrap(); + let write_ops = overlay_db.into_write_ops(); + db.write(write_ops).unwrap(); + + assert_eq!( + load_stored_blocks(store.as_ref(), &TEST_CONFIG).unwrap().unwrap(), + StoredBlockRange(4, 5) + ); + + check_candidates_in_store(vec![ + (cand_hash_1, None), + (cand_hash_2, None), + (cand_hash_3, Some(vec![block_hash_d1])), + (cand_hash_4, Some(vec![block_hash_d1])), + (cand_hash_5, None), + ]); + + check_blocks_in_store(vec![ + (block_hash_a, None), + (block_hash_b1, None), + (block_hash_b2, None), + (block_hash_c1, None), + (block_hash_c2, None), + (block_hash_d1, Some(vec![cand_hash_3, cand_hash_4])), + (block_hash_d2, None), + ]); +} + +#[test] +fn force_approve_works() { + let (mut db, store) = make_db(); + let n_validators = 10; + + let mut overlay_db = OverlayedBackend::new(&db); + overlay_db.write_stored_block_range(StoredBlockRange(1, 4)); + let write_ops = overlay_db.into_write_ops(); + db.write(write_ops).unwrap(); + + let candidate_hash = CandidateHash(Hash::repeat_byte(42)); + let single_candidate_vec = vec![(CoreIndex(0), candidate_hash)]; + let candidate_info = { + let mut candidate_info = HashMap::new(); + candidate_info.insert( + candidate_hash, + NewCandidateInfo::new( + make_candidate(ParaId::from(1_u32), Default::default()), + GroupIndex(1), + None, + ), + ); + + candidate_info + }; + + let block_hash_a = Hash::repeat_byte(1); // 1 + let block_hash_b = Hash::repeat_byte(2); + let block_hash_c = Hash::repeat_byte(3); + let block_hash_d = Hash::repeat_byte(4); // 4 + + let block_entry_a = + make_block_entry(block_hash_a, Default::default(), 1, single_candidate_vec.clone()); + let block_entry_b = + make_block_entry(block_hash_b, block_hash_a, 2, single_candidate_vec.clone()); + let block_entry_c = + make_block_entry(block_hash_c, block_hash_b, 3, single_candidate_vec.clone()); + let block_entry_d = + make_block_entry(block_hash_d, block_hash_c, 4, single_candidate_vec.clone()); + + let blocks = vec![ + block_entry_a.clone(), + block_entry_b.clone(), + block_entry_c.clone(), + block_entry_d.clone(), + ]; + + let mut overlay_db = OverlayedBackend::new(&db); + for block_entry in blocks { + add_block_entry(&mut overlay_db, block_entry.into(), n_validators, |h| { + candidate_info.get(h).map(|x| x.clone()) + }) + .unwrap(); + } + let approved_hashes = force_approve(&mut overlay_db, block_hash_d, 2).unwrap(); + let write_ops = overlay_db.into_write_ops(); + db.write(write_ops).unwrap(); + + assert!(load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_a,) + .unwrap() + .unwrap() + .approved_bitfield + .all()); + assert!(load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_b,) + .unwrap() + .unwrap() + .approved_bitfield + .all()); + assert!(load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_c,) + .unwrap() + .unwrap() + .approved_bitfield + .not_any()); + assert!(load_block_entry(store.as_ref(), &TEST_CONFIG, &block_hash_d,) + .unwrap() + .unwrap() + .approved_bitfield + .not_any()); + assert_eq!(approved_hashes, vec![block_hash_b, block_hash_a]); +} + +#[test] +fn load_all_blocks_works() { + let (mut db, store) = make_db(); + + let parent_hash = Hash::repeat_byte(1); + let block_hash_a = Hash::repeat_byte(2); + let block_hash_b = Hash::repeat_byte(69); + let block_hash_c = Hash::repeat_byte(42); + + let block_number = 10; + + let block_entry_a = make_block_entry(block_hash_a, parent_hash, block_number, vec![]); + + let block_entry_b = make_block_entry(block_hash_b, parent_hash, block_number, vec![]); + + let block_entry_c = make_block_entry(block_hash_c, block_hash_a, block_number + 1, vec![]); + + let n_validators = 10; + + let mut overlay_db = OverlayedBackend::new(&db); + add_block_entry(&mut overlay_db, block_entry_a.clone().into(), n_validators, |_| None).unwrap(); + + // add C before B to test sorting. + add_block_entry(&mut overlay_db, block_entry_c.clone().into(), n_validators, |_| None).unwrap(); + + add_block_entry(&mut overlay_db, block_entry_b.clone().into(), n_validators, |_| None).unwrap(); + + let write_ops = overlay_db.into_write_ops(); + db.write(write_ops).unwrap(); + + assert_eq!( + load_all_blocks(store.as_ref(), &TEST_CONFIG).unwrap(), + vec![block_hash_a, block_hash_b, block_hash_c], + ) +} diff --git a/polkadot/node/core/approval-voting/src/backend.rs b/polkadot/node/core/approval-voting/src/backend.rs index d98f3c5fd20..9ce25334c0f 100644 --- a/polkadot/node/core/approval-voting/src/backend.rs +++ b/polkadot/node/core/approval-voting/src/backend.rs @@ -22,12 +22,12 @@ //! before any commit to the underlying storage is made. use polkadot_node_subsystem::SubsystemResult; -use polkadot_primitives::{BlockNumber, CandidateHash, Hash}; +use polkadot_primitives::{BlockNumber, CandidateHash, CandidateIndex, Hash}; use std::collections::HashMap; use super::{ - approval_db::v2::StoredBlockRange, + approval_db::common::StoredBlockRange, persisted_entries::{BlockEntry, CandidateEntry}, }; @@ -72,12 +72,26 @@ pub trait V1ReadBackend: Backend { fn load_candidate_entry_v1( &self, candidate_hash: &CandidateHash, + candidate_index: CandidateIndex, ) -> SubsystemResult>; /// Load a block entry from the DB with scheme version 1. fn load_block_entry_v1(&self, block_hash: &Hash) -> SubsystemResult>; } +/// A read only backend to enable db migration from version 2 of DB. +pub trait V2ReadBackend: Backend { + /// Load a candidate entry from the DB with scheme version 1. + fn load_candidate_entry_v2( + &self, + candidate_hash: &CandidateHash, + candidate_index: CandidateIndex, + ) -> SubsystemResult>; + + /// Load a block entry from the DB with scheme version 1. + fn load_block_entry_v2(&self, block_hash: &Hash) -> SubsystemResult>; +} + // Status of block range in the `OverlayedBackend`. #[derive(PartialEq)] enum BlockRangeStatus { diff --git a/polkadot/node/core/approval-voting/src/import.rs b/polkadot/node/core/approval-voting/src/import.rs index a64685326cf..7a56e9fd112 100644 --- a/polkadot/node/core/approval-voting/src/import.rs +++ b/polkadot/node/core/approval-voting/src/import.rs @@ -56,7 +56,7 @@ use futures::{channel::oneshot, prelude::*}; use std::collections::HashMap; -use super::approval_db::v2; +use super::approval_db::v3; use crate::{ backend::{Backend, OverlayedBackend}, criteria::{AssignmentCriteria, OurAssignment}, @@ -512,7 +512,7 @@ pub(crate) async fn handle_new_head( ctx.send_message(ChainSelectionMessage::Approved(block_hash)).await; } - let block_entry = v2::BlockEntry { + let block_entry = v3::BlockEntry { block_hash, parent_hash: block_header.parent_hash, block_number: block_header.number, @@ -525,6 +525,7 @@ pub(crate) async fn handle_new_head( .collect(), approved_bitfield, children: Vec::new(), + candidates_pending_signature: Default::default(), distributed_assignments: Default::default(), }; @@ -604,7 +605,10 @@ pub(crate) async fn handle_new_head( #[cfg(test)] pub(crate) mod tests { use super::*; - use crate::{approval_db::v2::DbBackend, RuntimeInfo, RuntimeInfoConfig}; + use crate::{ + approval_db::common::{load_block_entry, DbBackend}, + RuntimeInfo, RuntimeInfoConfig, + }; use ::test_helpers::{dummy_candidate_receipt, dummy_hash}; use assert_matches::assert_matches; use polkadot_node_primitives::{ @@ -627,7 +631,7 @@ pub(crate) mod tests { pub(crate) use sp_runtime::{Digest, DigestItem}; use std::{pin::Pin, sync::Arc}; - use crate::{approval_db::v2::Config as DatabaseConfig, criteria, BlockEntry}; + use crate::{approval_db::common::Config as DatabaseConfig, criteria, BlockEntry}; const DATA_COL: u32 = 0; @@ -1347,7 +1351,7 @@ pub(crate) mod tests { let (state, mut session_info_provider) = single_session_state(); overlay_db.write_block_entry( - v2::BlockEntry { + v3::BlockEntry { block_hash: parent_hash, parent_hash: Default::default(), block_number: 4, @@ -1357,6 +1361,7 @@ pub(crate) mod tests { candidates: Vec::new(), approved_bitfield: Default::default(), children: Vec::new(), + candidates_pending_signature: Default::default(), distributed_assignments: Default::default(), } .into(), @@ -1389,11 +1394,10 @@ pub(crate) mod tests { assert_eq!(candidates[1].1.approvals().len(), 6); // the first candidate should be insta-approved // the second should not - let entry: BlockEntry = - v2::load_block_entry(db_writer.as_ref(), &TEST_CONFIG, &hash) - .unwrap() - .unwrap() - .into(); + let entry: BlockEntry = load_block_entry(db_writer.as_ref(), &TEST_CONFIG, &hash) + .unwrap() + .unwrap() + .into(); assert!(entry.is_candidate_approved(&candidates[0].0)); assert!(!entry.is_candidate_approved(&candidates[1].0)); }) diff --git a/polkadot/node/core/approval-voting/src/lib.rs b/polkadot/node/core/approval-voting/src/lib.rs index ef01727b7eb..af76b576d7c 100644 --- a/polkadot/node/core/approval-voting/src/lib.rs +++ b/polkadot/node/core/approval-voting/src/lib.rs @@ -21,14 +21,15 @@ //! of others. It uses this information to determine when candidates and blocks have //! been sufficiently approved to finalize. +use itertools::Itertools; use jaeger::{hash_to_trace_identifier, PerLeafSpan}; use polkadot_node_jaeger as jaeger; use polkadot_node_primitives::{ approval::{ - v1::{BlockApprovalMeta, DelayTranche, IndirectSignedApprovalVote}, + v1::{BlockApprovalMeta, DelayTranche}, v2::{ AssignmentCertKindV2, BitfieldError, CandidateBitfield, CoreBitfield, - IndirectAssignmentCertV2, + IndirectAssignmentCertV2, IndirectSignedApprovalVoteV2, }, }, ValidationResult, DISPUTE_WINDOW, @@ -53,9 +54,10 @@ use polkadot_node_subsystem_util::{ TimeoutExt, }; use polkadot_primitives::{ - ApprovalVote, BlockNumber, CandidateHash, CandidateIndex, CandidateReceipt, DisputeStatement, - ExecutorParams, GroupIndex, Hash, PvfExecKind, SessionIndex, SessionInfo, - ValidDisputeStatementKind, ValidatorId, ValidatorIndex, ValidatorPair, ValidatorSignature, + vstaging::{ApprovalVoteMultipleCandidates, ApprovalVotingParams}, + BlockNumber, CandidateHash, CandidateIndex, CandidateReceipt, DisputeStatement, ExecutorParams, + GroupIndex, Hash, PvfExecKind, SessionIndex, SessionInfo, ValidDisputeStatementKind, + ValidatorId, ValidatorIndex, ValidatorPair, ValidatorSignature, }; use sc_keystore::LocalKeystore; use sp_application_crypto::Pair; @@ -67,9 +69,11 @@ use futures::{ future::{BoxFuture, RemoteHandle}, prelude::*, stream::FuturesUnordered, + StreamExt, }; use std::{ + cmp::min, collections::{ btree_map::Entry as BTMEntry, hash_map::Entry as HMEntry, BTreeMap, HashMap, HashSet, }, @@ -83,7 +87,7 @@ use approval_checking::RequiredTranches; use bitvec::{order::Lsb0, vec::BitVec}; use criteria::{AssignmentCriteria, RealAssignmentCriteria}; use persisted_entries::{ApprovalEntry, BlockEntry, CandidateEntry}; -use time::{slot_number_to_tick, Clock, ClockExt, SystemClock, Tick}; +use time::{slot_number_to_tick, Clock, ClockExt, DelayedApprovalTimer, SystemClock, Tick}; mod approval_checking; pub mod approval_db; @@ -95,9 +99,11 @@ mod persisted_entries; mod time; use crate::{ - approval_db::v2::{Config as DatabaseConfig, DbBackend}, + approval_checking::{Check, TranchesToApproveResult}, + approval_db::common::{Config as DatabaseConfig, DbBackend}, backend::{Backend, OverlayedBackend}, criteria::InvalidAssignmentReason, + persisted_entries::OurApproval, }; #[cfg(test)] @@ -115,6 +121,9 @@ const TICK_TOO_FAR_IN_FUTURE: Tick = 20; // 10 seconds. const APPROVAL_DELAY: Tick = 2; pub(crate) const LOG_TARGET: &str = "parachain::approval-voting"; +// The max number of ticks we delay sending the approval after we are ready to issue the approval +const MAX_APPROVAL_COALESCE_WAIT_TICKS: Tick = 12; + /// Configuration for the approval voting subsystem #[derive(Debug, Clone)] pub struct Config { @@ -158,7 +167,14 @@ struct MetricsInner { assignments_produced: prometheus::Histogram, approvals_produced_total: prometheus::CounterVec, no_shows_total: prometheus::Counter, + // The difference from `no_shows_total` is that this counts all observed no-shows at any + // moment in time. While `no_shows_total` catches that the no-shows at the moment the candidate + // is approved, approvals might arrive late and `no_shows_total` wouldn't catch that number. + observed_no_shows: prometheus::Counter, + approved_by_one_third: prometheus::Counter, wakeups_triggered_total: prometheus::Counter, + coalesced_approvals_buckets: prometheus::Histogram, + coalesced_approvals_delay: prometheus::Histogram, candidate_approval_time_ticks: prometheus::Histogram, block_approval_time_ticks: prometheus::Histogram, time_db_transaction: prometheus::Histogram, @@ -184,6 +200,22 @@ impl Metrics { } } + fn on_approval_coalesce(&self, num_coalesced: u32) { + if let Some(metrics) = &self.0 { + // Count how many candidates we covered with this coalesced approvals, + // so that the heat-map really gives a good understanding of the scales. + for _ in 0..num_coalesced { + metrics.coalesced_approvals_buckets.observe(num_coalesced as f64) + } + } + } + + fn on_delayed_approval(&self, delayed_ticks: u64) { + if let Some(metrics) = &self.0 { + metrics.coalesced_approvals_delay.observe(delayed_ticks as f64) + } + } + fn on_approval_stale(&self) { if let Some(metrics) = &self.0 { metrics.approvals_produced_total.with_label_values(&["stale"]).inc() @@ -220,6 +252,18 @@ impl Metrics { } } + fn on_observed_no_shows(&self, n: usize) { + if let Some(metrics) = &self.0 { + metrics.observed_no_shows.inc_by(n as u64); + } + } + + fn on_approved_by_one_third(&self) { + if let Some(metrics) = &self.0 { + metrics.approved_by_one_third.inc(); + } + } + fn on_wakeup(&self) { if let Some(metrics) = &self.0 { metrics.wakeups_triggered_total.inc(); @@ -297,6 +341,13 @@ impl metrics::Metrics for Metrics { )?, registry, )?, + observed_no_shows: prometheus::register( + prometheus::Counter::new( + "polkadot_parachain_approvals_observed_no_shows_total", + "Number of observed no shows at any moment in time", + )?, + registry, + )?, wakeups_triggered_total: prometheus::register( prometheus::Counter::new( "polkadot_parachain_approvals_wakeups_total", @@ -313,6 +364,31 @@ impl metrics::Metrics for Metrics { )?, registry, )?, + coalesced_approvals_buckets: prometheus::register( + prometheus::Histogram::with_opts( + prometheus::HistogramOpts::new( + "polkadot_parachain_approvals_coalesced_approvals_buckets", + "Number of coalesced approvals.", + ).buckets(vec![1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5]), + )?, + registry, + )?, + coalesced_approvals_delay: prometheus::register( + prometheus::Histogram::with_opts( + prometheus::HistogramOpts::new( + "polkadot_parachain_approvals_coalescing_delay", + "Number of ticks we delay the sending of a candidate approval", + ).buckets(vec![1.1, 2.1, 3.1, 4.1, 6.1, 8.1, 12.1, 20.1, 32.1]), + )?, + registry, + )?, + approved_by_one_third: prometheus::register( + prometheus::Counter::new( + "polkadot_parachain_approved_by_one_third", + "Number of candidates where more than one third had to vote ", + )?, + registry, + )?, block_approval_time_ticks: prometheus::register( prometheus::Histogram::with_opts( prometheus::HistogramOpts::new( @@ -383,8 +459,8 @@ impl ApprovalVotingSubsystem { /// The operation is not allowed for blocks older than the last finalized one. pub fn revert_to(&self, hash: Hash) -> Result<(), SubsystemError> { let config = - approval_db::v2::Config { col_approval_data: self.db_config.col_approval_data }; - let mut backend = approval_db::v2::DbBackend::new(self.db.clone(), config); + approval_db::common::Config { col_approval_data: self.db_config.col_approval_data }; + let mut backend = approval_db::common::DbBackend::new(self.db.clone(), config); let mut overlay = OverlayedBackend::new(&backend); ops::revert_to(&mut overlay, hash)?; @@ -559,6 +635,7 @@ struct ApprovalStatus { required_tranches: RequiredTranches, tranche_now: DelayTranche, block_tick: Tick, + last_no_shows: usize, } #[derive(Copy, Clone)] @@ -733,22 +810,73 @@ impl State { ); if let Some(approval_entry) = candidate_entry.approval_entry(&block_hash) { - let required_tranches = approval_checking::tranches_to_approve( - approval_entry, - candidate_entry.approvals(), - tranche_now, - block_tick, - no_show_duration, - session_info.needed_approvals as _, - ); + let TranchesToApproveResult { required_tranches, total_observed_no_shows } = + approval_checking::tranches_to_approve( + approval_entry, + candidate_entry.approvals(), + tranche_now, + block_tick, + no_show_duration, + session_info.needed_approvals as _, + ); - let status = ApprovalStatus { required_tranches, block_tick, tranche_now }; + let status = ApprovalStatus { + required_tranches, + block_tick, + tranche_now, + last_no_shows: total_observed_no_shows, + }; Some((approval_entry, status)) } else { None } } + + // Returns the approval voting params from the RuntimeApi. + #[overseer::contextbounds(ApprovalVoting, prefix = self::overseer)] + async fn get_approval_voting_params_or_default( + &self, + ctx: &mut Context, + session_index: SessionIndex, + block_hash: Hash, + ) -> Option { + let (s_tx, s_rx) = oneshot::channel(); + + ctx.send_message(RuntimeApiMessage::Request( + block_hash, + RuntimeApiRequest::ApprovalVotingParams(session_index, s_tx), + )) + .await; + + match s_rx.await { + Ok(Ok(params)) => { + gum::trace!( + target: LOG_TARGET, + approval_voting_params = ?params, + session = ?session_index, + "Using the following subsystem params" + ); + Some(params) + }, + Ok(Err(err)) => { + gum::debug!( + target: LOG_TARGET, + ?err, + "Could not request approval voting params from runtime" + ); + None + }, + Err(err) => { + gum::debug!( + target: LOG_TARGET, + ?err, + "Could not request approval voting params from runtime" + ); + None + }, + } + } } #[derive(Debug, Clone)] @@ -807,6 +935,7 @@ where }); let mut wakeups = Wakeups::default(); let mut currently_checking_set = CurrentlyCheckingSet::default(); + let mut delayed_approvals_timers = DelayedApprovalTimer::default(); let mut approvals_cache = LruMap::new(ByLength::new(APPROVAL_CACHE_SIZE)); let mut last_finalized_height: Option = { @@ -885,17 +1014,49 @@ where } actions + }, + (block_hash, validator_index) = delayed_approvals_timers.select_next_some() => { + gum::debug!( + target: LOG_TARGET, + ?block_hash, + ?validator_index, + "Sign approval for multiple candidates", + ); + + match maybe_create_signature( + &mut overlayed_db, + &mut session_info_provider, + &state, + &mut ctx, + block_hash, + validator_index, + &subsystem.metrics, + ).await { + Ok(Some(next_wakeup)) => { + delayed_approvals_timers.maybe_arm_timer(next_wakeup, state.clock.as_ref(), block_hash, validator_index); + }, + Ok(None) => {} + Err(err) => { + gum::error!( + target: LOG_TARGET, + ?err, + "Failed to create signature", + ); + } + } + vec![] } }; if handle_actions( &mut ctx, - &state, + &mut state, &mut overlayed_db, &mut session_info_provider, &subsystem.metrics, &mut wakeups, &mut currently_checking_set, + &mut delayed_approvals_timers, &mut approvals_cache, &mut subsystem.mode, actions, @@ -937,12 +1098,13 @@ where #[overseer::contextbounds(ApprovalVoting, prefix = self::overseer)] async fn handle_actions( ctx: &mut Context, - state: &State, + state: &mut State, overlayed_db: &mut OverlayedBackend<'_, impl Backend>, session_info_provider: &mut RuntimeInfo, metrics: &Metrics, wakeups: &mut Wakeups, currently_checking_set: &mut CurrentlyCheckingSet, + delayed_approvals_timers: &mut DelayedApprovalTimer, approvals_cache: &mut LruMap, mode: &mut Mode, actions: Vec, @@ -973,6 +1135,7 @@ async fn handle_actions( session_info_provider, metrics, candidate_hash, + delayed_approvals_timers, approval_request, ) .await? @@ -1075,7 +1238,11 @@ async fn handle_actions( Action::BecomeActive => { *mode = Mode::Active; - let messages = distribution_messages_for_activation(overlayed_db, state)?; + let messages = distribution_messages_for_activation( + overlayed_db, + state, + delayed_approvals_timers, + )?; ctx.send_messages(messages.into_iter()).await; }, @@ -1101,7 +1268,7 @@ fn cores_to_candidate_indices( .iter() .position(|(core_index, _)| core_index.0 == claimed_core_index as u32) { - candidate_indices.push(candidate_index as CandidateIndex); + candidate_indices.push(candidate_index as _); } } @@ -1134,6 +1301,7 @@ fn get_assignment_core_indices( fn distribution_messages_for_activation( db: &OverlayedBackend<'_, impl Backend>, state: &State, + delayed_approvals_timers: &mut DelayedApprovalTimer, ) -> SubsystemResult> { let all_blocks: Vec = db.load_all_blocks()?; @@ -1172,8 +1340,8 @@ fn distribution_messages_for_activation( slot: block_entry.slot(), session: block_entry.session(), }); - - for (i, (_, candidate_hash)) in block_entry.candidates().iter().enumerate() { + let mut signatures_queued = HashSet::new(); + for (_, candidate_hash) in block_entry.candidates() { let _candidate_span = distribution_message_span.child("candidate").with_candidate(*candidate_hash); let candidate_entry = match db.load_candidate_entry(&candidate_hash)? { @@ -1200,6 +1368,15 @@ fn distribution_messages_for_activation( &candidate_hash, &block_entry, ) { + if block_entry.has_candidates_pending_signature() { + delayed_approvals_timers.maybe_arm_timer( + state.clock.tick_now(), + state.clock.as_ref(), + block_entry.block_hash(), + assignment.validator_index(), + ) + } + match cores_to_candidate_indices( &claimed_core_indices, &block_entry, @@ -1267,15 +1444,19 @@ fn distribution_messages_for_activation( continue }, } - - messages.push(ApprovalDistributionMessage::DistributeApproval( - IndirectSignedApprovalVote { - block_hash, - candidate_index: i as _, - validator: assignment.validator_index(), - signature: approval_sig, - }, - )); + if signatures_queued + .insert(approval_sig.signed_candidates_indices.clone()) + { + messages.push(ApprovalDistributionMessage::DistributeApproval( + IndirectSignedApprovalVoteV2 { + block_hash, + candidate_indices: approval_sig + .signed_candidates_indices, + validator: assignment.validator_index(), + signature: approval_sig.signature, + }, + )) + }; } else { gum::warn!( target: LOG_TARGET, @@ -1481,7 +1662,7 @@ async fn get_approval_signatures_for_candidate( ctx: &mut Context, db: &OverlayedBackend<'_, impl Backend>, candidate_hash: CandidateHash, - tx: oneshot::Sender>, + tx: oneshot::Sender, ValidatorSignature)>>, ) -> SubsystemResult<()> { let send_votes = |votes| { if let Err(_) = tx.send(votes) { @@ -1507,6 +1688,11 @@ async fn get_approval_signatures_for_candidate( let relay_hashes = entry.block_assignments.keys(); let mut candidate_indices = HashSet::new(); + let mut candidate_indices_to_candidate_hashes: HashMap< + Hash, + HashMap, + > = HashMap::new(); + // Retrieve `CoreIndices`/`CandidateIndices` as required by approval-distribution: for hash in relay_hashes { let entry = match db.load_block_entry(hash)? { @@ -1524,8 +1710,11 @@ async fn get_approval_signatures_for_candidate( for (candidate_index, (_core_index, c_hash)) in entry.candidates().iter().enumerate() { if c_hash == &candidate_hash { candidate_indices.insert((*hash, candidate_index as u32)); - break } + candidate_indices_to_candidate_hashes + .entry(*hash) + .or_default() + .insert(candidate_index as _, *c_hash); } } @@ -1550,7 +1739,55 @@ async fn get_approval_signatures_for_candidate( target: LOG_TARGET, "Request for approval signatures got cancelled by `approval-distribution`." ), - Some(Ok(votes)) => send_votes(votes), + Some(Ok(votes)) => { + let votes = votes + .into_iter() + .filter_map(|(validator_index, (hash, signed_candidates_indices, signature))| { + let candidates_hashes = candidate_indices_to_candidate_hashes.get(&hash); + + if candidates_hashes.is_none() { + gum::warn!( + target: LOG_TARGET, + ?hash, + "Possible bug! Could not find map of candidate_hashes for block hash received from approval-distribution" + ); + } + + let num_signed_candidates = signed_candidates_indices.len(); + + let signed_candidates_hashes: Vec = + signed_candidates_indices + .into_iter() + .filter_map(|candidate_index| { + candidates_hashes.and_then(|candidate_hashes| { + if let Some(candidate_hash) = + candidate_hashes.get(&candidate_index) + { + Some(*candidate_hash) + } else { + gum::warn!( + target: LOG_TARGET, + ?candidate_index, + "Possible bug! Could not find candidate hash for candidate_index coming from approval-distribution" + ); + None + } + }) + }) + .collect(); + if num_signed_candidates == signed_candidates_hashes.len() { + Some((validator_index, (signed_candidates_hashes, signature))) + } else { + gum::warn!( + target: LOG_TARGET, + "Possible bug! Could not find all hashes for candidates coming from approval-distribution" + ); + None + } + }) + .collect(); + send_votes(votes) + }, } }; @@ -2184,7 +2421,7 @@ async fn check_and_import_approval( db: &mut OverlayedBackend<'_, impl Backend>, session_info_provider: &mut RuntimeInfo, metrics: &Metrics, - approval: IndirectSignedApprovalVote, + approval: IndirectSignedApprovalVoteV2, with_response: impl FnOnce(ApprovalCheckResult) -> T, ) -> SubsystemResult<(Vec, T)> where @@ -2196,13 +2433,12 @@ where return Ok((Vec::new(), t)) }}; } - let mut span = state .spans .get(&approval.block_hash) .map(|span| span.child("check-and-import-approval")) .unwrap_or_else(|| jaeger::Span::new(approval.block_hash, "check-and-import-approval")) - .with_uint_tag("candidate-index", approval.candidate_index as u64) + .with_string_fmt_debug_tag("candidate-index", approval.candidate_indices.clone()) .with_relay_parent(approval.block_hash) .with_stage(jaeger::Stage::ApprovalChecking); @@ -2215,105 +2451,163 @@ where }, }; - let session_info = match get_session_info( - session_info_provider, - sender, - approval.block_hash, - block_entry.session(), - ) - .await - { - Some(s) => s, - None => { - respond_early!(ApprovalCheckResult::Bad(ApprovalCheckError::UnknownSessionIndex( - block_entry.session() - ),)) - }, - }; + let approved_candidates_info: Result, ApprovalCheckError> = + approval + .candidate_indices + .iter_ones() + .map(|candidate_index| { + block_entry + .candidate(candidate_index) + .ok_or(ApprovalCheckError::InvalidCandidateIndex(candidate_index as _)) + .map(|candidate| (candidate_index as _, candidate.1)) + }) + .collect(); - let approved_candidate_hash = match block_entry.candidate(approval.candidate_index as usize) { - Some((_, h)) => *h, - None => respond_early!(ApprovalCheckResult::Bad( - ApprovalCheckError::InvalidCandidateIndex(approval.candidate_index), - )), + let approved_candidates_info = match approved_candidates_info { + Ok(approved_candidates_info) => approved_candidates_info, + Err(err) => { + respond_early!(ApprovalCheckResult::Bad(err)) + }, }; - span.add_string_tag("candidate-hash", format!("{:?}", approved_candidate_hash)); + span.add_string_tag("candidate-hashes", format!("{:?}", approved_candidates_info)); span.add_string_tag( - "traceID", - format!("{:?}", hash_to_trace_identifier(approved_candidate_hash.0)), + "traceIDs", + format!( + "{:?}", + approved_candidates_info + .iter() + .map(|(_, approved_candidate_hash)| hash_to_trace_identifier( + approved_candidate_hash.0 + )) + .collect_vec() + ), ); - let pubkey = match session_info.validators.get(approval.validator) { - Some(k) => k, - None => respond_early!(ApprovalCheckResult::Bad( - ApprovalCheckError::InvalidValidatorIndex(approval.validator), - )), - }; + { + let session_info = match get_session_info( + session_info_provider, + sender, + approval.block_hash, + block_entry.session(), + ) + .await + { + Some(s) => s, + None => { + respond_early!(ApprovalCheckResult::Bad(ApprovalCheckError::UnknownSessionIndex( + block_entry.session() + ),)) + }, + }; - // Signature check: - match DisputeStatement::Valid(ValidDisputeStatementKind::ApprovalChecking).check_signature( - &pubkey, - approved_candidate_hash, - block_entry.session(), - &approval.signature, - ) { - Err(_) => respond_early!(ApprovalCheckResult::Bad(ApprovalCheckError::InvalidSignature( - approval.validator - ),)), - Ok(()) => {}, - }; + let pubkey = match session_info.validators.get(approval.validator) { + Some(k) => k, + None => respond_early!(ApprovalCheckResult::Bad( + ApprovalCheckError::InvalidValidatorIndex(approval.validator), + )), + }; - let candidate_entry = match db.load_candidate_entry(&approved_candidate_hash)? { - Some(c) => c, - None => { - respond_early!(ApprovalCheckResult::Bad(ApprovalCheckError::InvalidCandidate( - approval.candidate_index, - approved_candidate_hash - ),)) - }, - }; + gum::trace!( + target: LOG_TARGET, + "Received approval for num_candidates {:}", + approval.candidate_indices.count_ones() + ); - // Don't accept approvals until assignment. - match candidate_entry.approval_entry(&approval.block_hash) { - None => { - respond_early!(ApprovalCheckResult::Bad(ApprovalCheckError::Internal( - approval.block_hash, - approved_candidate_hash - ),)) - }, - Some(e) if !e.is_assigned(approval.validator) => { - respond_early!(ApprovalCheckResult::Bad(ApprovalCheckError::NoAssignment( - approval.validator - ),)) - }, - _ => {}, + let candidate_hashes: Vec = + approved_candidates_info.iter().map(|candidate| candidate.1).collect(); + // Signature check: + match DisputeStatement::Valid( + ValidDisputeStatementKind::ApprovalCheckingMultipleCandidates(candidate_hashes.clone()), + ) + .check_signature( + &pubkey, + if let Some(candidate_hash) = candidate_hashes.first() { + *candidate_hash + } else { + respond_early!(ApprovalCheckResult::Bad(ApprovalCheckError::InvalidValidatorIndex( + approval.validator + ),)) + }, + block_entry.session(), + &approval.signature, + ) { + Err(_) => { + gum::error!( + target: LOG_TARGET, + "Error while checking signature {:}", + approval.candidate_indices.count_ones() + ); + respond_early!(ApprovalCheckResult::Bad(ApprovalCheckError::InvalidSignature( + approval.validator + ),)) + }, + Ok(()) => {}, + }; } - // importing the approval can be heavy as it may trigger acceptance for a series of blocks. - let t = with_response(ApprovalCheckResult::Accepted); + let mut actions = Vec::new(); + for (approval_candidate_index, approved_candidate_hash) in approved_candidates_info { + let block_entry = match db.load_block_entry(&approval.block_hash)? { + Some(b) => b, + None => { + respond_early!(ApprovalCheckResult::Bad(ApprovalCheckError::UnknownBlock( + approval.block_hash + ),)) + }, + }; - gum::trace!( - target: LOG_TARGET, - validator_index = approval.validator.0, - validator = ?pubkey, - candidate_hash = ?approved_candidate_hash, - para_id = ?candidate_entry.candidate_receipt().descriptor.para_id, - "Importing approval vote", - ); + let candidate_entry = match db.load_candidate_entry(&approved_candidate_hash)? { + Some(c) => c, + None => { + respond_early!(ApprovalCheckResult::Bad(ApprovalCheckError::InvalidCandidate( + approval_candidate_index, + approved_candidate_hash + ),)) + }, + }; - let actions = advance_approval_state( - sender, - state, - db, - session_info_provider, - &metrics, - block_entry, - approved_candidate_hash, - candidate_entry, - ApprovalStateTransition::RemoteApproval(approval.validator), - ) - .await; + // Don't accept approvals until assignment. + match candidate_entry.approval_entry(&approval.block_hash) { + None => { + respond_early!(ApprovalCheckResult::Bad(ApprovalCheckError::Internal( + approval.block_hash, + approved_candidate_hash + ),)) + }, + Some(e) if !e.is_assigned(approval.validator) => { + respond_early!(ApprovalCheckResult::Bad(ApprovalCheckError::NoAssignment( + approval.validator + ),)) + }, + _ => {}, + } + + gum::debug!( + target: LOG_TARGET, + validator_index = approval.validator.0, + candidate_hash = ?approved_candidate_hash, + para_id = ?candidate_entry.candidate_receipt().descriptor.para_id, + "Importing approval vote", + ); + + let new_actions = advance_approval_state( + sender, + state, + db, + session_info_provider, + &metrics, + block_entry, + approved_candidate_hash, + candidate_entry, + ApprovalStateTransition::RemoteApproval(approval.validator), + ) + .await; + actions.extend(new_actions); + } + + // importing the approval can be heavy as it may trigger acceptance for a series of blocks. + let t = with_response(ApprovalCheckResult::Accepted); Ok((actions, t)) } @@ -2321,7 +2615,7 @@ where #[derive(Debug)] enum ApprovalStateTransition { RemoteApproval(ValidatorIndex), - LocalApproval(ValidatorIndex, ValidatorSignature), + LocalApproval(ValidatorIndex), WakeupProcessed, } @@ -2329,7 +2623,7 @@ impl ApprovalStateTransition { fn validator_index(&self) -> Option { match *self { ApprovalStateTransition::RemoteApproval(v) | - ApprovalStateTransition::LocalApproval(v, _) => Some(v), + ApprovalStateTransition::LocalApproval(v) => Some(v), ApprovalStateTransition::WakeupProcessed => None, } } @@ -2337,7 +2631,7 @@ impl ApprovalStateTransition { fn is_local_approval(&self) -> bool { match *self { ApprovalStateTransition::RemoteApproval(_) => false, - ApprovalStateTransition::LocalApproval(_, _) => true, + ApprovalStateTransition::LocalApproval(_) => true, ApprovalStateTransition::WakeupProcessed => false, } } @@ -2404,7 +2698,16 @@ where // assignment tick of `now - APPROVAL_DELAY` - that is, that // all counted assignments are at least `APPROVAL_DELAY` ticks old. let is_approved = check.is_approved(tick_now.saturating_sub(APPROVAL_DELAY)); - + if status.last_no_shows != 0 { + metrics.on_observed_no_shows(status.last_no_shows); + gum::debug!( + target: LOG_TARGET, + ?candidate_hash, + ?block_hash, + last_no_shows = ?status.last_no_shows, + "Observed no_shows", + ); + } if is_approved { gum::trace!( target: LOG_TARGET, @@ -2422,6 +2725,12 @@ where if no_shows != 0 { metrics.on_no_shows(no_shows); } + if check == Check::ApprovedOneThird { + // No-shows are not counted when more than one third of validators approve a + // candidate, so count candidates where more than one third of validators had to + // approve it, this is indicative of something breaking. + metrics.on_approved_by_one_third() + } metrics.on_candidate_approved(status.tranche_now as _); @@ -2430,6 +2739,10 @@ where actions.push(Action::NoteApprovedInChainSelection(block_hash)); } + db.write_block_entry(block_entry.into()); + } else if transition.is_local_approval() { + // Local approvals always update the block_entry, so we need to flush it to + // the database. db.write_block_entry(block_entry.into()); } @@ -2458,10 +2771,6 @@ where approval_entry.mark_approved(); } - if let ApprovalStateTransition::LocalApproval(_, ref sig) = transition { - approval_entry.import_approval_sig(sig.clone()); - } - actions.extend(schedule_wakeup_action( &approval_entry, block_hash, @@ -2599,7 +2908,7 @@ async fn process_wakeup( let should_trigger = should_trigger_assignment( &approval_entry, &candidate_entry, - tranches_to_approve, + tranches_to_approve.required_tranches, tranche_now, ); @@ -2924,11 +3233,12 @@ async fn launch_approval( #[overseer::contextbounds(ApprovalVoting, prefix = self::overseer)] async fn issue_approval( ctx: &mut Context, - state: &State, + state: &mut State, db: &mut OverlayedBackend<'_, impl Backend>, session_info_provider: &mut RuntimeInfo, metrics: &Metrics, candidate_hash: CandidateHash, + delayed_approvals_timers: &mut DelayedApprovalTimer, ApprovalVoteRequest { validator_index, block_hash }: ApprovalVoteRequest, ) -> SubsystemResult> { let mut issue_approval_span = state @@ -2942,7 +3252,7 @@ async fn issue_approval( .with_validator_index(validator_index) .with_stage(jaeger::Stage::ApprovalChecking); - let block_entry = match db.load_block_entry(&block_hash)? { + let mut block_entry = match db.load_block_entry(&block_hash)? { Some(b) => b, None => { // not a cause for alarm - just lost a race with pruning, most likely. @@ -2968,21 +3278,6 @@ async fn issue_approval( }; issue_approval_span.add_int_tag("candidate_index", candidate_index as i64); - let session_info = match get_session_info( - session_info_provider, - ctx.sender(), - block_entry.parent_hash(), - block_entry.session(), - ) - .await - { - Some(s) => s, - None => { - metrics.on_approval_error(); - return Ok(Vec::new()) - }, - }; - let candidate_hash = match block_entry.candidate(candidate_index as usize) { Some((_, h)) => *h, None => { @@ -3013,10 +3308,149 @@ async fn issue_approval( }, }; + let session_info = match get_session_info( + session_info_provider, + ctx.sender(), + block_entry.parent_hash(), + block_entry.session(), + ) + .await + { + Some(s) => s, + None => return Ok(Vec::new()), + }; + + if block_entry + .defer_candidate_signature( + candidate_index as _, + candidate_hash, + compute_delayed_approval_sending_tick( + state, + &block_entry, + &candidate_entry, + session_info, + &metrics, + ), + ) + .is_some() + { + gum::error!( + target: LOG_TARGET, + ?candidate_hash, + ?block_hash, + validator_index = validator_index.0, + "Possible bug, we shouldn't have to defer a candidate more than once", + ); + } + + gum::info!( + target: LOG_TARGET, + ?candidate_hash, + ?block_hash, + validator_index = validator_index.0, + "Ready to issue approval vote", + ); + + let actions = advance_approval_state( + ctx.sender(), + state, + db, + session_info_provider, + metrics, + block_entry, + candidate_hash, + candidate_entry, + ApprovalStateTransition::LocalApproval(validator_index as _), + ) + .await; + + if let Some(next_wakeup) = maybe_create_signature( + db, + session_info_provider, + state, + ctx, + block_hash, + validator_index, + metrics, + ) + .await? + { + delayed_approvals_timers.maybe_arm_timer( + next_wakeup, + state.clock.as_ref(), + block_hash, + validator_index, + ); + } + Ok(actions) +} + +// Create signature for the approved candidates pending signatures +#[overseer::contextbounds(ApprovalVoting, prefix = self::overseer)] +async fn maybe_create_signature( + db: &mut OverlayedBackend<'_, impl Backend>, + session_info_provider: &mut RuntimeInfo, + state: &State, + ctx: &mut Context, + block_hash: Hash, + validator_index: ValidatorIndex, + metrics: &Metrics, +) -> SubsystemResult> { + let mut block_entry = match db.load_block_entry(&block_hash)? { + Some(b) => b, + None => { + // not a cause for alarm - just lost a race with pruning, most likely. + metrics.on_approval_stale(); + gum::debug!( + target: LOG_TARGET, + "Could not find block that needs signature {:}", block_hash + ); + return Ok(None) + }, + }; + + let approval_params = state + .get_approval_voting_params_or_default(ctx, block_entry.session(), block_hash) + .await + .unwrap_or_default(); + + gum::trace!( + target: LOG_TARGET, + "Candidates pending signatures {:}", block_entry.num_candidates_pending_signature() + ); + let tick_now = state.clock.tick_now(); + + let (candidates_to_sign, sign_no_later_then) = block_entry + .get_candidates_that_need_signature(tick_now, approval_params.max_approval_coalesce_count); + + let (candidates_hashes, candidates_indices) = match candidates_to_sign { + Some(candidates_to_sign) => candidates_to_sign, + None => return Ok(sign_no_later_then), + }; + + let session_info = match get_session_info( + session_info_provider, + ctx.sender(), + block_entry.parent_hash(), + block_entry.session(), + ) + .await + { + Some(s) => s, + None => { + metrics.on_approval_error(); + gum::error!( + target: LOG_TARGET, + "Could not retrieve the session" + ); + return Ok(None) + }, + }; + let validator_pubkey = match session_info.validators.get(validator_index) { Some(p) => p, None => { - gum::warn!( + gum::error!( target: LOG_TARGET, "Validator index {} out of bounds in session {}", validator_index.0, @@ -3024,72 +3458,89 @@ async fn issue_approval( ); metrics.on_approval_error(); - return Ok(Vec::new()) + return Ok(None) }, }; - let session = block_entry.session(); - let sig = match sign_approval(&state.keystore, &validator_pubkey, candidate_hash, session) { + let signature = match sign_approval( + &state.keystore, + &validator_pubkey, + &candidates_hashes, + block_entry.session(), + ) { Some(sig) => sig, None => { - gum::warn!( + gum::error!( target: LOG_TARGET, validator_index = ?validator_index, - session, + session = ?block_entry.session(), "Could not issue approval signature. Assignment key present but not validator key?", ); metrics.on_approval_error(); - return Ok(Vec::new()) + return Ok(None) }, }; + metrics.on_approval_coalesce(candidates_hashes.len() as u32); - gum::trace!( - target: LOG_TARGET, - ?candidate_hash, - ?block_hash, - validator_index = validator_index.0, - "Issuing approval vote", - ); + let candidate_entries = candidates_hashes + .iter() + .map(|candidate_hash| db.load_candidate_entry(candidate_hash)) + .collect::>>>()?; - let actions = advance_approval_state( - ctx.sender(), - state, - db, - session_info_provider, - metrics, - block_entry, - candidate_hash, - candidate_entry, - ApprovalStateTransition::LocalApproval(validator_index as _, sig.clone()), - ) - .await; + for mut candidate_entry in candidate_entries { + let approval_entry = candidate_entry.as_mut().and_then(|candidate_entry| { + candidate_entry.approval_entry_mut(&block_entry.block_hash()) + }); + + match approval_entry { + Some(approval_entry) => approval_entry.import_approval_sig(OurApproval { + signature: signature.clone(), + signed_candidates_indices: candidates_indices.clone(), + }), + None => { + gum::error!( + target: LOG_TARGET, + candidate_entry = ?candidate_entry, + "Candidate scheduled for signing approval entry should not be None" + ); + }, + }; + candidate_entry.map(|candidate_entry| db.write_candidate_entry(candidate_entry)); + } metrics.on_approval_produced(); - // dispatch to approval distribution. ctx.send_unbounded_message(ApprovalDistributionMessage::DistributeApproval( - IndirectSignedApprovalVote { - block_hash, - candidate_index: candidate_index as _, + IndirectSignedApprovalVoteV2 { + block_hash: block_entry.block_hash(), + candidate_indices: candidates_indices, validator: validator_index, - signature: sig, + signature, }, )); - Ok(actions) + gum::trace!( + target: LOG_TARGET, + ?block_hash, + signed_candidates = ?block_entry.num_candidates_pending_signature(), + "Issue approval votes", + ); + block_entry.issued_approval(); + db.write_block_entry(block_entry.into()); + Ok(None) } // Sign an approval vote. Fails if the key isn't present in the store. fn sign_approval( keystore: &LocalKeystore, public: &ValidatorId, - candidate_hash: CandidateHash, + candidate_hashes: &[CandidateHash], session_index: SessionIndex, ) -> Option { let key = keystore.key_pair::(public).ok().flatten()?; - let payload = ApprovalVote(candidate_hash).signing_payload(session_index); + let payload = ApprovalVoteMultipleCandidates(candidate_hashes).signing_payload(session_index); Some(key.sign(&payload[..])) } @@ -3119,3 +3570,38 @@ fn issue_local_invalid_statement( false, )); } + +// Computes what is the latest tick we can send an approval +fn compute_delayed_approval_sending_tick( + state: &State, + block_entry: &BlockEntry, + candidate_entry: &CandidateEntry, + session_info: &SessionInfo, + metrics: &Metrics, +) -> Tick { + let current_block_tick = slot_number_to_tick(state.slot_duration_millis, block_entry.slot()); + let assignment_tranche = candidate_entry + .approval_entry(&block_entry.block_hash()) + .and_then(|approval_entry| approval_entry.our_assignment()) + .map(|our_assignment| our_assignment.tranche()) + .unwrap_or_default(); + + let assignment_triggered_tick = current_block_tick + assignment_tranche as Tick; + + let no_show_duration_ticks = slot_number_to_tick( + state.slot_duration_millis, + Slot::from(u64::from(session_info.no_show_slots)), + ); + let tick_now = state.clock.tick_now(); + + let sign_no_later_than = min( + tick_now + MAX_APPROVAL_COALESCE_WAIT_TICKS as Tick, + // We don't want to accidentally cause no-shows, so if we are past + // the second half of the no show time, force the sending of the + // approval immediately. + assignment_triggered_tick + no_show_duration_ticks / 2, + ); + + metrics.on_delayed_approval(sign_no_later_than.checked_sub(tick_now).unwrap_or_default()); + sign_no_later_than +} diff --git a/polkadot/node/core/approval-voting/src/ops.rs b/polkadot/node/core/approval-voting/src/ops.rs index a6f0ecf9d1f..2a8fdba5aa3 100644 --- a/polkadot/node/core/approval-voting/src/ops.rs +++ b/polkadot/node/core/approval-voting/src/ops.rs @@ -25,7 +25,7 @@ use polkadot_primitives::{BlockNumber, CandidateHash, CandidateReceipt, GroupInd use std::collections::{hash_map::Entry, BTreeMap, HashMap}; use super::{ - approval_db::v2::{OurAssignment, StoredBlockRange}, + approval_db::{common::StoredBlockRange, v2::OurAssignment}, backend::{Backend, OverlayedBackend}, persisted_entries::{ApprovalEntry, BlockEntry, CandidateEntry}, LOG_TARGET, diff --git a/polkadot/node/core/approval-voting/src/persisted_entries.rs b/polkadot/node/core/approval-voting/src/persisted_entries.rs index 9cfe1c4cf8d..ef47bdb2213 100644 --- a/polkadot/node/core/approval-voting/src/persisted_entries.rs +++ b/polkadot/node/core/approval-voting/src/persisted_entries.rs @@ -20,13 +20,14 @@ //! Within that context, things are plain-old-data. Within this module, //! data and logic are intertwined. +use itertools::Itertools; use polkadot_node_primitives::approval::{ v1::{DelayTranche, RelayVRFStory}, v2::{AssignmentCertV2, CandidateBitfield}, }; use polkadot_primitives::{ - BlockNumber, CandidateHash, CandidateReceipt, CoreIndex, GroupIndex, Hash, SessionIndex, - ValidatorIndex, ValidatorSignature, + BlockNumber, CandidateHash, CandidateIndex, CandidateReceipt, CoreIndex, GroupIndex, Hash, + SessionIndex, ValidatorIndex, ValidatorSignature, }; use sp_consensus_slots::Slot; @@ -76,6 +77,45 @@ impl From for crate::approval_db::v2::TrancheEntry { } } +impl From for OurApproval { + fn from(approval: crate::approval_db::v3::OurApproval) -> Self { + Self { + signature: approval.signature, + signed_candidates_indices: approval.signed_candidates_indices, + } + } +} +impl From for crate::approval_db::v3::OurApproval { + fn from(approval: OurApproval) -> Self { + Self { + signature: approval.signature, + signed_candidates_indices: approval.signed_candidates_indices, + } + } +} + +/// Metadata about our approval signature +#[derive(Debug, Clone, PartialEq)] +pub struct OurApproval { + /// The signature for the candidates hashes pointed by indices. + pub signature: ValidatorSignature, + /// The indices of the candidates signed in this approval. + pub signed_candidates_indices: CandidateBitfield, +} + +impl OurApproval { + /// Converts a ValidatorSignature to an OurApproval. + /// It used in converting the database from v1 to latest. + pub fn from_v1(value: ValidatorSignature, candidate_index: CandidateIndex) -> Self { + Self { signature: value, signed_candidates_indices: candidate_index.into() } + } + + /// Converts a ValidatorSignature to an OurApproval. + /// It used in converting the database from v2 to latest. + pub fn from_v2(value: ValidatorSignature, candidate_index: CandidateIndex) -> Self { + Self::from_v1(value, candidate_index) + } +} /// Metadata regarding approval of a particular candidate within the context of some /// particular block. #[derive(Debug, Clone, PartialEq)] @@ -83,7 +123,7 @@ pub struct ApprovalEntry { tranches: Vec, backing_group: GroupIndex, our_assignment: Option, - our_approval_sig: Option, + our_approval_sig: Option, // `n_validators` bits. assigned_validators: Bitfield, approved: bool, @@ -95,7 +135,7 @@ impl ApprovalEntry { tranches: Vec, backing_group: GroupIndex, our_assignment: Option, - our_approval_sig: Option, + our_approval_sig: Option, // `n_validators` bits. assigned_validators: Bitfield, approved: bool, @@ -137,7 +177,7 @@ impl ApprovalEntry { } /// Import our local approval vote signature for this candidate. - pub fn import_approval_sig(&mut self, approval_sig: ValidatorSignature) { + pub fn import_approval_sig(&mut self, approval_sig: OurApproval) { self.our_approval_sig = Some(approval_sig); } @@ -224,7 +264,7 @@ impl ApprovalEntry { /// Get the assignment cert & approval signature. /// /// The approval signature will only be `Some` if the assignment is too. - pub fn local_statements(&self) -> (Option, Option) { + pub fn local_statements(&self) -> (Option, Option) { let approval_sig = self.our_approval_sig.clone(); if let Some(our_assignment) = self.our_assignment.as_ref().filter(|a| a.triggered()) { (Some(our_assignment.clone()), approval_sig) @@ -232,10 +272,44 @@ impl ApprovalEntry { (None, None) } } + + // Convert an ApprovalEntry from v1 version to latest version + pub fn from_v1( + value: crate::approval_db::v1::ApprovalEntry, + candidate_index: CandidateIndex, + ) -> Self { + ApprovalEntry { + tranches: value.tranches.into_iter().map(|tranche| tranche.into()).collect(), + backing_group: value.backing_group, + our_assignment: value.our_assignment.map(|assignment| assignment.into()), + our_approval_sig: value + .our_approval_sig + .map(|sig| OurApproval::from_v1(sig, candidate_index)), + assigned_validators: value.assignments, + approved: value.approved, + } + } + + // Convert an ApprovalEntry from v1 version to latest version + pub fn from_v2( + value: crate::approval_db::v2::ApprovalEntry, + candidate_index: CandidateIndex, + ) -> Self { + ApprovalEntry { + tranches: value.tranches.into_iter().map(|tranche| tranche.into()).collect(), + backing_group: value.backing_group, + our_assignment: value.our_assignment.map(|assignment| assignment.into()), + our_approval_sig: value + .our_approval_sig + .map(|sig| OurApproval::from_v2(sig, candidate_index)), + assigned_validators: value.assigned_validators, + approved: value.approved, + } + } } -impl From for ApprovalEntry { - fn from(entry: crate::approval_db::v2::ApprovalEntry) -> Self { +impl From for ApprovalEntry { + fn from(entry: crate::approval_db::v3::ApprovalEntry) -> Self { ApprovalEntry { tranches: entry.tranches.into_iter().map(Into::into).collect(), backing_group: entry.backing_group, @@ -247,7 +321,7 @@ impl From for ApprovalEntry { } } -impl From for crate::approval_db::v2::ApprovalEntry { +impl From for crate::approval_db::v3::ApprovalEntry { fn from(entry: ApprovalEntry) -> Self { Self { tranches: entry.tranches.into_iter().map(Into::into).collect(), @@ -303,10 +377,44 @@ impl CandidateEntry { pub fn approval_entry(&self, block_hash: &Hash) -> Option<&ApprovalEntry> { self.block_assignments.get(block_hash) } + + /// Convert a CandidateEntry from a v1 to its latest equivalent. + pub fn from_v1( + value: crate::approval_db::v1::CandidateEntry, + candidate_index: CandidateIndex, + ) -> Self { + Self { + approvals: value.approvals, + block_assignments: value + .block_assignments + .into_iter() + .map(|(h, ae)| (h, ApprovalEntry::from_v1(ae, candidate_index))) + .collect(), + candidate: value.candidate, + session: value.session, + } + } + + /// Convert a CandidateEntry from a v2 to its latest equivalent. + pub fn from_v2( + value: crate::approval_db::v2::CandidateEntry, + candidate_index: CandidateIndex, + ) -> Self { + Self { + approvals: value.approvals, + block_assignments: value + .block_assignments + .into_iter() + .map(|(h, ae)| (h, ApprovalEntry::from_v2(ae, candidate_index))) + .collect(), + candidate: value.candidate, + session: value.session, + } + } } -impl From for CandidateEntry { - fn from(entry: crate::approval_db::v2::CandidateEntry) -> Self { +impl From for CandidateEntry { + fn from(entry: crate::approval_db::v3::CandidateEntry) -> Self { CandidateEntry { candidate: entry.candidate, session: entry.session, @@ -320,7 +428,7 @@ impl From for CandidateEntry { } } -impl From for crate::approval_db::v2::CandidateEntry { +impl From for crate::approval_db::v3::CandidateEntry { fn from(entry: CandidateEntry) -> Self { Self { candidate: entry.candidate, @@ -353,12 +461,21 @@ pub struct BlockEntry { // block. The block can be considered approved if the bitfield has all bits set to `true`. pub approved_bitfield: Bitfield, pub children: Vec, + // A list of candidates we have checked, but didn't not sign and + // advertise the vote yet. + candidates_pending_signature: BTreeMap, // A list of assignments for which we already distributed the assignment. // We use this to ensure we don't distribute multiple core assignments twice as we track // individual wakeups for each core. distributed_assignments: Bitfield, } +#[derive(Debug, Clone, PartialEq)] +pub struct CandidateSigningContext { + pub candidate_hash: CandidateHash, + pub sign_no_later_than_tick: Tick, +} + impl BlockEntry { /// Mark a candidate as fully approved in the bitfield. pub fn mark_approved_by_hash(&mut self, candidate_hash: &CandidateHash) { @@ -447,10 +564,97 @@ impl BlockEntry { distributed } + + /// Defer signing and issuing an approval for a candidate no later than the specified tick + pub fn defer_candidate_signature( + &mut self, + candidate_index: CandidateIndex, + candidate_hash: CandidateHash, + sign_no_later_than_tick: Tick, + ) -> Option { + self.candidates_pending_signature.insert( + candidate_index, + CandidateSigningContext { candidate_hash, sign_no_later_than_tick }, + ) + } + + /// Returns the number of candidates waiting for an approval to be issued. + pub fn num_candidates_pending_signature(&self) -> usize { + self.candidates_pending_signature.len() + } + + /// Return if we have candidates waiting for signature to be issued + pub fn has_candidates_pending_signature(&self) -> bool { + !self.candidates_pending_signature.is_empty() + } + + /// Candidate hashes for candidates pending signatures + fn candidate_hashes_pending_signature(&self) -> Vec { + self.candidates_pending_signature + .values() + .map(|unsigned_approval| unsigned_approval.candidate_hash) + .collect() + } + + /// Candidate indices for candidates pending signature + fn candidate_indices_pending_signature(&self) -> Option { + self.candidates_pending_signature + .keys() + .map(|val| *val) + .collect_vec() + .try_into() + .ok() + } + + /// Returns a list of candidates hashes that need need signature created at the current tick: + /// This might happen in other of the two reasons: + /// 1. We queued more than max_approval_coalesce_count candidates. + /// 2. We have candidates that waiting in the queue past their `sign_no_later_than_tick` + /// + /// Additionally, we also return the first tick when we will have to create a signature, + /// so that the caller can arm the timer if it is not already armed. + pub fn get_candidates_that_need_signature( + &self, + tick_now: Tick, + max_approval_coalesce_count: u32, + ) -> (Option<(Vec, CandidateBitfield)>, Option) { + let sign_no_later_than_tick = self + .candidates_pending_signature + .values() + .min_by(|a, b| a.sign_no_later_than_tick.cmp(&b.sign_no_later_than_tick)) + .map(|val| val.sign_no_later_than_tick); + + if let Some(sign_no_later_than_tick) = sign_no_later_than_tick { + if sign_no_later_than_tick <= tick_now || + self.num_candidates_pending_signature() >= max_approval_coalesce_count as usize + { + ( + self.candidate_indices_pending_signature().and_then(|candidate_indices| { + Some((self.candidate_hashes_pending_signature(), candidate_indices)) + }), + Some(sign_no_later_than_tick), + ) + } else { + // We can still wait for other candidates to queue in, so just make sure + // we wake up at the tick we have to sign the longest waiting candidate. + (Default::default(), Some(sign_no_later_than_tick)) + } + } else { + // No cached candidates, nothing to do here, this just means the timer fired, + // but the signatures were already sent because we gathered more than + // max_approval_coalesce_count. + (Default::default(), sign_no_later_than_tick) + } + } + + /// Clears the candidates pending signature because the approval was issued. + pub fn issued_approval(&mut self) { + self.candidates_pending_signature.clear(); + } } -impl From for BlockEntry { - fn from(entry: crate::approval_db::v2::BlockEntry) -> Self { +impl From for BlockEntry { + fn from(entry: crate::approval_db::v3::BlockEntry) -> Self { BlockEntry { block_hash: entry.block_hash, parent_hash: entry.parent_hash, @@ -461,6 +665,11 @@ impl From for BlockEntry { candidates: entry.candidates, approved_bitfield: entry.approved_bitfield, children: entry.children, + candidates_pending_signature: entry + .candidates_pending_signature + .into_iter() + .map(|(candidate_index, signing_context)| (candidate_index, signing_context.into())) + .collect(), distributed_assignments: entry.distributed_assignments, } } @@ -479,11 +688,30 @@ impl From for BlockEntry { approved_bitfield: entry.approved_bitfield, children: entry.children, distributed_assignments: Default::default(), + candidates_pending_signature: Default::default(), } } } -impl From for crate::approval_db::v2::BlockEntry { +impl From for BlockEntry { + fn from(entry: crate::approval_db::v2::BlockEntry) -> Self { + BlockEntry { + block_hash: entry.block_hash, + parent_hash: entry.parent_hash, + block_number: entry.block_number, + session: entry.session, + slot: entry.slot, + relay_vrf_story: RelayVRFStory(entry.relay_vrf_story), + candidates: entry.candidates, + approved_bitfield: entry.approved_bitfield, + children: entry.children, + distributed_assignments: entry.distributed_assignments, + candidates_pending_signature: Default::default(), + } + } +} + +impl From for crate::approval_db::v3::BlockEntry { fn from(entry: BlockEntry) -> Self { Self { block_hash: entry.block_hash, @@ -495,36 +723,30 @@ impl From for crate::approval_db::v2::BlockEntry { candidates: entry.candidates, approved_bitfield: entry.approved_bitfield, children: entry.children, + candidates_pending_signature: entry + .candidates_pending_signature + .into_iter() + .map(|(candidate_index, signing_context)| (candidate_index, signing_context.into())) + .collect(), distributed_assignments: entry.distributed_assignments, } } } -/// Migration helpers. -impl From for CandidateEntry { - fn from(value: crate::approval_db::v1::CandidateEntry) -> Self { +impl From for CandidateSigningContext { + fn from(signing_context: crate::approval_db::v3::CandidateSigningContext) -> Self { Self { - approvals: value.approvals, - block_assignments: value - .block_assignments - .into_iter() - .map(|(h, ae)| (h, ae.into())) - .collect(), - candidate: value.candidate, - session: value.session, + candidate_hash: signing_context.candidate_hash, + sign_no_later_than_tick: signing_context.sign_no_later_than_tick.into(), } } } -impl From for ApprovalEntry { - fn from(value: crate::approval_db::v1::ApprovalEntry) -> Self { - ApprovalEntry { - tranches: value.tranches.into_iter().map(|tranche| tranche.into()).collect(), - backing_group: value.backing_group, - our_assignment: value.our_assignment.map(|assignment| assignment.into()), - our_approval_sig: value.our_approval_sig, - assigned_validators: value.assignments, - approved: value.approved, +impl From for crate::approval_db::v3::CandidateSigningContext { + fn from(signing_context: CandidateSigningContext) -> Self { + Self { + candidate_hash: signing_context.candidate_hash, + sign_no_later_than_tick: signing_context.sign_no_later_than_tick.into(), } } } diff --git a/polkadot/node/core/approval-voting/src/tests.rs b/polkadot/node/core/approval-voting/src/tests.rs index cdfc170cd2b..498cf62bb30 100644 --- a/polkadot/node/core/approval-voting/src/tests.rs +++ b/polkadot/node/core/approval-voting/src/tests.rs @@ -37,8 +37,8 @@ use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_node_subsystem_util::TimeoutExt; use polkadot_overseer::HeadSupportsParachains; use polkadot_primitives::{ - vstaging::NodeFeatures, CandidateCommitments, CandidateEvent, CoreIndex, GroupIndex, Header, - Id as ParaId, IndexedVec, ValidationCode, ValidatorSignature, + vstaging::NodeFeatures, ApprovalVote, CandidateCommitments, CandidateEvent, CoreIndex, + GroupIndex, Header, Id as ParaId, IndexedVec, ValidationCode, ValidatorSignature, }; use std::time::Duration; @@ -56,7 +56,7 @@ use std::{ }; use super::{ - approval_db::v2::StoredBlockRange, + approval_db::common::StoredBlockRange, backend::BackendWriteOp, import::tests::{ garbage_vrf_signature, AllowedSlots, BabeEpoch, BabeEpochConfiguration, @@ -116,7 +116,7 @@ fn make_sync_oracle(val: bool) -> (Box, TestSyncOracleHan #[cfg(test)] pub mod test_constants { - use crate::approval_db::v2::Config as DatabaseConfig; + use crate::approval_db::common::Config as DatabaseConfig; const DATA_COL: u32 = 0; pub(crate) const NUM_COLUMNS: u32 = 1; @@ -281,6 +281,7 @@ impl V1ReadBackend for TestStoreInner { fn load_candidate_entry_v1( &self, candidate_hash: &CandidateHash, + _candidate_index: CandidateIndex, ) -> SubsystemResult> { self.load_candidate_entry(candidate_hash) } @@ -364,6 +365,7 @@ impl V1ReadBackend for TestStore { fn load_candidate_entry_v1( &self, candidate_hash: &CandidateHash, + _candidate_index: CandidateIndex, ) -> SubsystemResult> { self.load_candidate_entry(candidate_hash) } @@ -446,6 +448,15 @@ fn sign_approval( key.sign(&ApprovalVote(candidate_hash).signing_payload(session_index)).into() } +fn sign_approval_multiple_candidates( + key: Sr25519Keyring, + candidate_hashes: Vec, + session_index: SessionIndex, +) -> ValidatorSignature { + key.sign(&ApprovalVoteMultipleCandidates(&candidate_hashes).signing_payload(session_index)) + .into() +} + type VirtualOverseer = test_helpers::TestSubsystemContextHandle; #[derive(Default)] @@ -641,7 +652,12 @@ async fn check_and_import_approval( overseer, FromOrchestra::Communication { msg: ApprovalVotingMessage::CheckAndImportApproval( - IndirectSignedApprovalVote { block_hash, candidate_index, validator, signature }, + IndirectSignedApprovalVoteV2 { + block_hash, + candidate_indices: candidate_index.into(), + validator, + signature, + }, tx, ), }, @@ -2014,6 +2030,91 @@ fn forkful_import_at_same_height_act_on_leaf() { }); } +#[test] +fn test_signing_a_single_candidate_is_backwards_compatible() { + let session_index = 1; + let block_hash = Hash::repeat_byte(0x01); + let candidate_descriptors = (1..10) + .into_iter() + .map(|val| make_candidate(ParaId::from(val as u32), &block_hash)) + .collect::>(); + + let candidate_hashes = candidate_descriptors + .iter() + .map(|candidate_descriptor| candidate_descriptor.hash()) + .collect_vec(); + + let first_descriptor = candidate_descriptors.first().unwrap(); + + let candidate_hash = first_descriptor.hash(); + + let sig_a = sign_approval(Sr25519Keyring::Alice, candidate_hash, session_index); + + let sig_b = sign_approval(Sr25519Keyring::Alice, candidate_hash, session_index); + + assert!(DisputeStatement::Valid(ValidDisputeStatementKind::ApprovalChecking) + .check_signature( + &Sr25519Keyring::Alice.public().into(), + candidate_hash, + session_index, + &sig_a, + ) + .is_ok()); + + assert!(DisputeStatement::Valid(ValidDisputeStatementKind::ApprovalChecking) + .check_signature( + &Sr25519Keyring::Alice.public().into(), + candidate_hash, + session_index, + &sig_b, + ) + .is_ok()); + + let sig_c = sign_approval_multiple_candidates( + Sr25519Keyring::Alice, + vec![candidate_hash], + session_index, + ); + + assert!(DisputeStatement::Valid( + ValidDisputeStatementKind::ApprovalCheckingMultipleCandidates(vec![candidate_hash]) + ) + .check_signature(&Sr25519Keyring::Alice.public().into(), candidate_hash, session_index, &sig_c,) + .is_ok()); + + assert!(DisputeStatement::Valid(ValidDisputeStatementKind::ApprovalChecking) + .check_signature( + &Sr25519Keyring::Alice.public().into(), + candidate_hash, + session_index, + &sig_c, + ) + .is_ok()); + + assert!(DisputeStatement::Valid( + ValidDisputeStatementKind::ApprovalCheckingMultipleCandidates(vec![candidate_hash]) + ) + .check_signature(&Sr25519Keyring::Alice.public().into(), candidate_hash, session_index, &sig_a,) + .is_ok()); + + let sig_all = sign_approval_multiple_candidates( + Sr25519Keyring::Alice, + candidate_hashes.clone(), + session_index, + ); + + assert!(DisputeStatement::Valid( + ValidDisputeStatementKind::ApprovalCheckingMultipleCandidates(candidate_hashes.clone()) + ) + .check_signature( + &Sr25519Keyring::Alice.public().into(), + *candidate_hashes.first().expect("test"), + session_index, + &sig_all, + ) + .is_ok()); +} + #[test] fn import_checked_approval_updates_entries_and_schedules() { let config = HarnessConfig::default(); @@ -2730,11 +2831,29 @@ async fn handle_double_assignment_import( } ); + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::ApprovalVotingParams(_, sender))) => { + let _ = sender.send(Ok(ApprovalVotingParams { + max_approval_coalesce_count: 1, + })); + } + ); + assert_matches!( overseer_recv(virtual_overseer).await, AllMessages::ApprovalDistribution(ApprovalDistributionMessage::DistributeApproval(_)) ); + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::ApprovalVotingParams(_, sender))) => { + let _ = sender.send(Ok(ApprovalVotingParams { + max_approval_coalesce_count: 1, + })); + } + ); + assert_matches!( overseer_recv(virtual_overseer).await, AllMessages::ApprovalDistribution(ApprovalDistributionMessage::DistributeApproval(_)) @@ -3469,3 +3588,455 @@ fn waits_until_approving_assignments_are_old_enough() { virtual_overseer }); } + +#[test] +fn test_approval_is_sent_on_max_approval_coalesce_count() { + let assignment_criteria = Box::new(MockAssignmentCriteria( + || { + let mut assignments = HashMap::new(); + let _ = assignments.insert( + CoreIndex(0), + approval_db::v2::OurAssignment { + cert: garbage_assignment_cert(AssignmentCertKind::RelayVRFModulo { sample: 0 }) + .into(), + tranche: 0, + validator_index: ValidatorIndex(0), + triggered: false, + } + .into(), + ); + + let assignments_cert = + garbage_assignment_cert_v2(AssignmentCertKindV2::RelayVRFModuloCompact { + core_bitfield: vec![CoreIndex(0), CoreIndex(1), CoreIndex(2)] + .try_into() + .unwrap(), + }); + let _ = assignments.insert( + CoreIndex(0), + approval_db::v2::OurAssignment { + cert: assignments_cert.clone(), + tranche: 0, + validator_index: ValidatorIndex(0), + triggered: false, + } + .into(), + ); + + let _ = assignments.insert( + CoreIndex(1), + approval_db::v2::OurAssignment { + cert: assignments_cert.clone(), + tranche: 0, + validator_index: ValidatorIndex(0), + triggered: false, + } + .into(), + ); + assignments + }, + |_| Ok(0), + )); + + let config = HarnessConfigBuilder::default().assignment_criteria(assignment_criteria).build(); + let store = config.backend(); + + test_harness(config, |test_harness| async move { + let TestHarness { mut virtual_overseer, clock, sync_oracle_handle: _sync_oracle_handle } = + test_harness; + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ChainApi(ChainApiMessage::FinalizedBlockNumber(rx)) => { + rx.send(Ok(0)).unwrap(); + } + ); + + let block_hash = Hash::repeat_byte(0x01); + + let candidate_commitments = CandidateCommitments::default(); + + let candidate_receipt1 = { + let mut receipt = dummy_candidate_receipt(block_hash); + receipt.descriptor.para_id = ParaId::from(1_u32); + receipt.commitments_hash = candidate_commitments.hash(); + receipt + }; + + let candidate_hash1 = candidate_receipt1.hash(); + + let candidate_receipt2 = { + let mut receipt = dummy_candidate_receipt(block_hash); + receipt.descriptor.para_id = ParaId::from(2_u32); + receipt.commitments_hash = candidate_commitments.hash(); + receipt + }; + + let slot = Slot::from(1); + let candidate_index1 = 0; + let candidate_index2 = 1; + + let validators = vec![ + Sr25519Keyring::Alice, + Sr25519Keyring::Bob, + Sr25519Keyring::Charlie, + Sr25519Keyring::Dave, + Sr25519Keyring::Eve, + ]; + let session_info = SessionInfo { + validator_groups: IndexedVec::>::from(vec![ + vec![ValidatorIndex(0), ValidatorIndex(1)], + vec![ValidatorIndex(2)], + vec![ValidatorIndex(3), ValidatorIndex(4)], + ]), + ..session_info(&validators) + }; + + let candidates = Some(vec![ + (candidate_receipt1.clone(), CoreIndex(0), GroupIndex(0)), + (candidate_receipt2.clone(), CoreIndex(1), GroupIndex(1)), + ]); + ChainBuilder::new() + .add_block( + block_hash, + ChainBuilder::GENESIS_HASH, + 1, + BlockConfig { + slot, + candidates: candidates.clone(), + session_info: Some(session_info.clone()), + }, + ) + .build(&mut virtual_overseer) + .await; + + assert!(!clock.inner.lock().current_wakeup_is(1)); + clock.inner.lock().wakeup_all(1); + + assert!(clock.inner.lock().current_wakeup_is(slot_to_tick(slot))); + clock.inner.lock().wakeup_all(slot_to_tick(slot)); + + futures_timer::Delay::new(Duration::from_millis(200)).await; + + clock.inner.lock().wakeup_all(slot_to_tick(slot + 2)); + + assert_eq!(clock.inner.lock().wakeups.len(), 0); + + futures_timer::Delay::new(Duration::from_millis(200)).await; + + let candidate_entry = store.load_candidate_entry(&candidate_hash1).unwrap().unwrap(); + let our_assignment = + candidate_entry.approval_entry(&block_hash).unwrap().our_assignment().unwrap(); + assert!(our_assignment.triggered()); + + handle_approval_on_max_coalesce_count( + &mut virtual_overseer, + vec![candidate_index1, candidate_index2], + ) + .await; + + virtual_overseer + }); +} + +async fn handle_approval_on_max_coalesce_count( + virtual_overseer: &mut VirtualOverseer, + candidate_indicies: Vec, +) { + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::DistributeAssignment( + _, + c_indices, + )) => { + assert_eq!(TryInto::::try_into(candidate_indicies.clone()).unwrap(), c_indices); + } + ); + + for _ in &candidate_indicies { + recover_available_data(virtual_overseer).await; + fetch_validation_code(virtual_overseer).await; + } + + for _ in &candidate_indicies { + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::CandidateValidation(CandidateValidationMessage::ValidateFromExhaustive{exec_kind, response_sender, ..}) if exec_kind == PvfExecKind::Approval => { + response_sender.send(Ok(ValidationResult::Valid(Default::default(), Default::default()))) + .unwrap(); + } + ); + } + + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::ApprovalVotingParams(_, sender))) => { + let _ = sender.send(Ok(ApprovalVotingParams { + max_approval_coalesce_count: 2, + })); + } + ); + + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::ApprovalVotingParams(_, sender))) => { + let _ = sender.send(Ok(ApprovalVotingParams { + max_approval_coalesce_count: 2, + })); + } + ); + + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::DistributeApproval(vote)) => { + assert_eq!(TryInto::::try_into(candidate_indicies).unwrap(), vote.candidate_indices); + } + ); + + // Assert that there are no more messages being sent by the subsystem + assert!(overseer_recv(virtual_overseer).timeout(TIMEOUT / 2).await.is_none()); +} + +async fn handle_approval_on_max_wait_time( + virtual_overseer: &mut VirtualOverseer, + candidate_indicies: Vec, + clock: Box, +) { + const TICK_NOW_BEGIN: u64 = 1; + const MAX_COALESCE_COUNT: u32 = 3; + + clock.inner.lock().set_tick(TICK_NOW_BEGIN); + + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::DistributeAssignment( + _, + c_indices, + )) => { + assert_eq!(TryInto::::try_into(candidate_indicies.clone()).unwrap(), c_indices); + } + ); + + for _ in &candidate_indicies { + recover_available_data(virtual_overseer).await; + fetch_validation_code(virtual_overseer).await; + } + + for _ in &candidate_indicies { + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::CandidateValidation(CandidateValidationMessage::ValidateFromExhaustive{exec_kind, response_sender, ..}) if exec_kind == PvfExecKind::Approval => { + response_sender.send(Ok(ValidationResult::Valid(Default::default(), Default::default()))) + .unwrap(); + } + ); + } + + // First time we fetch the configuration when we are ready to approve the first candidate + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::ApprovalVotingParams(_, sender))) => { + let _ = sender.send(Ok(ApprovalVotingParams { + max_approval_coalesce_count: MAX_COALESCE_COUNT, + })); + } + ); + + // Second time we fetch the configuration when we are ready to approve the second candidate + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::ApprovalVotingParams(_, sender))) => { + let _ = sender.send(Ok(ApprovalVotingParams { + max_approval_coalesce_count: MAX_COALESCE_COUNT, + })); + } + ); + + assert!(overseer_recv(virtual_overseer).timeout(TIMEOUT / 2).await.is_none()); + + // Move the clock just before we should send the approval + clock + .inner + .lock() + .set_tick(MAX_APPROVAL_COALESCE_WAIT_TICKS as Tick + TICK_NOW_BEGIN - 1); + + assert!(overseer_recv(virtual_overseer).timeout(TIMEOUT / 2).await.is_none()); + + // Move the clock tick, so we can trigger a force sending of the approvals + clock + .inner + .lock() + .set_tick(MAX_APPROVAL_COALESCE_WAIT_TICKS as Tick + TICK_NOW_BEGIN); + + // Third time we fetch the configuration when timer expires and we are ready to sent the + // approval + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request(_, RuntimeApiRequest::ApprovalVotingParams(_, sender))) => { + let _ = sender.send(Ok(ApprovalVotingParams { + max_approval_coalesce_count: 3, + })); + } + ); + + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::DistributeApproval(vote)) => { + assert_eq!(TryInto::::try_into(candidate_indicies).unwrap(), vote.candidate_indices); + } + ); + + // Assert that there are no more messages being sent by the subsystem + assert!(overseer_recv(virtual_overseer).timeout(TIMEOUT / 2).await.is_none()); +} + +#[test] +fn test_approval_is_sent_on_max_approval_coalesce_wait() { + let assignment_criteria = Box::new(MockAssignmentCriteria( + || { + let mut assignments = HashMap::new(); + let _ = assignments.insert( + CoreIndex(0), + approval_db::v2::OurAssignment { + cert: garbage_assignment_cert(AssignmentCertKind::RelayVRFModulo { sample: 0 }) + .into(), + tranche: 0, + validator_index: ValidatorIndex(0), + triggered: false, + } + .into(), + ); + + let assignments_cert = + garbage_assignment_cert_v2(AssignmentCertKindV2::RelayVRFModuloCompact { + core_bitfield: vec![CoreIndex(0), CoreIndex(1), CoreIndex(2)] + .try_into() + .unwrap(), + }); + let _ = assignments.insert( + CoreIndex(0), + approval_db::v2::OurAssignment { + cert: assignments_cert.clone(), + tranche: 0, + validator_index: ValidatorIndex(0), + triggered: false, + } + .into(), + ); + + let _ = assignments.insert( + CoreIndex(1), + approval_db::v2::OurAssignment { + cert: assignments_cert.clone(), + tranche: 0, + validator_index: ValidatorIndex(0), + triggered: false, + } + .into(), + ); + assignments + }, + |_| Ok(0), + )); + + let config = HarnessConfigBuilder::default().assignment_criteria(assignment_criteria).build(); + let store = config.backend(); + + test_harness(config, |test_harness| async move { + let TestHarness { mut virtual_overseer, clock, sync_oracle_handle: _sync_oracle_handle } = + test_harness; + + assert_matches!( + overseer_recv(&mut virtual_overseer).await, + AllMessages::ChainApi(ChainApiMessage::FinalizedBlockNumber(rx)) => { + rx.send(Ok(0)).unwrap(); + } + ); + + let block_hash = Hash::repeat_byte(0x01); + + let candidate_commitments = CandidateCommitments::default(); + + let candidate_receipt1 = { + let mut receipt = dummy_candidate_receipt(block_hash); + receipt.descriptor.para_id = ParaId::from(1_u32); + receipt.commitments_hash = candidate_commitments.hash(); + receipt + }; + + let candidate_hash1 = candidate_receipt1.hash(); + + let candidate_receipt2 = { + let mut receipt = dummy_candidate_receipt(block_hash); + receipt.descriptor.para_id = ParaId::from(2_u32); + receipt.commitments_hash = candidate_commitments.hash(); + receipt + }; + + let slot = Slot::from(1); + let candidate_index1 = 0; + let candidate_index2 = 1; + + let validators = vec![ + Sr25519Keyring::Alice, + Sr25519Keyring::Bob, + Sr25519Keyring::Charlie, + Sr25519Keyring::Dave, + Sr25519Keyring::Eve, + ]; + let session_info = SessionInfo { + validator_groups: IndexedVec::>::from(vec![ + vec![ValidatorIndex(0), ValidatorIndex(1)], + vec![ValidatorIndex(2)], + vec![ValidatorIndex(3), ValidatorIndex(4)], + ]), + ..session_info(&validators) + }; + + let candidates = Some(vec![ + (candidate_receipt1.clone(), CoreIndex(0), GroupIndex(0)), + (candidate_receipt2.clone(), CoreIndex(1), GroupIndex(1)), + ]); + ChainBuilder::new() + .add_block( + block_hash, + ChainBuilder::GENESIS_HASH, + 1, + BlockConfig { + slot, + candidates: candidates.clone(), + session_info: Some(session_info.clone()), + }, + ) + .build(&mut virtual_overseer) + .await; + + assert!(!clock.inner.lock().current_wakeup_is(1)); + clock.inner.lock().wakeup_all(1); + + assert!(clock.inner.lock().current_wakeup_is(slot_to_tick(slot))); + clock.inner.lock().wakeup_all(slot_to_tick(slot)); + + futures_timer::Delay::new(Duration::from_millis(200)).await; + + clock.inner.lock().wakeup_all(slot_to_tick(slot + 2)); + + assert_eq!(clock.inner.lock().wakeups.len(), 0); + + futures_timer::Delay::new(Duration::from_millis(200)).await; + + let candidate_entry = store.load_candidate_entry(&candidate_hash1).unwrap().unwrap(); + let our_assignment = + candidate_entry.approval_entry(&block_hash).unwrap().our_assignment().unwrap(); + assert!(our_assignment.triggered()); + + handle_approval_on_max_wait_time( + &mut virtual_overseer, + vec![candidate_index1, candidate_index2], + clock, + ) + .await; + + virtual_overseer + }); +} diff --git a/polkadot/node/core/approval-voting/src/time.rs b/polkadot/node/core/approval-voting/src/time.rs index a45866402c8..61091f3c34c 100644 --- a/polkadot/node/core/approval-voting/src/time.rs +++ b/polkadot/node/core/approval-voting/src/time.rs @@ -16,14 +16,23 @@ //! Time utilities for approval voting. -use futures::prelude::*; +use futures::{ + future::BoxFuture, + prelude::*, + stream::{FusedStream, FuturesUnordered}, + Stream, StreamExt, +}; + use polkadot_node_primitives::approval::v1::DelayTranche; use sp_consensus_slots::Slot; use std::{ + collections::HashSet, pin::Pin, + task::Poll, time::{Duration, SystemTime}, }; +use polkadot_primitives::{Hash, ValidatorIndex}; const TICK_DURATION_MILLIS: u64 = 500; /// A base unit of time, starting from the Unix epoch, split into half-second intervals. @@ -88,3 +97,157 @@ pub(crate) fn slot_number_to_tick(slot_duration_millis: u64, slot: Slot) -> Tick let ticks_per_slot = slot_duration_millis / TICK_DURATION_MILLIS; u64::from(slot) * ticks_per_slot } + +/// A list of delayed futures that gets triggered when the waiting time has expired and it is +/// time to sign the candidate. +/// We have a timer per relay-chain block. +#[derive(Default)] +pub struct DelayedApprovalTimer { + timers: FuturesUnordered>, + blocks: HashSet, +} + +impl DelayedApprovalTimer { + /// Starts a single timer per block hash + /// + /// Guarantees that if a timer already exits for the give block hash, + /// no additional timer is started. + pub(crate) fn maybe_arm_timer( + &mut self, + wait_untill: Tick, + clock: &dyn Clock, + block_hash: Hash, + validator_index: ValidatorIndex, + ) { + if self.blocks.insert(block_hash) { + let clock_wait = clock.wait(wait_untill); + self.timers.push(Box::pin(async move { + clock_wait.await; + (block_hash, validator_index) + })); + } + } +} + +impl Stream for DelayedApprovalTimer { + type Item = (Hash, ValidatorIndex); + + fn poll_next( + mut self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + let poll_result = self.timers.poll_next_unpin(cx); + match poll_result { + Poll::Ready(Some(result)) => { + self.blocks.remove(&result.0); + Poll::Ready(Some(result)) + }, + _ => poll_result, + } + } +} + +impl FusedStream for DelayedApprovalTimer { + fn is_terminated(&self) -> bool { + self.timers.is_terminated() + } +} + +#[cfg(test)] +mod tests { + use std::time::Duration; + + use futures::{executor::block_on, FutureExt, StreamExt}; + use futures_timer::Delay; + use polkadot_primitives::{Hash, ValidatorIndex}; + + use crate::time::{Clock, SystemClock}; + + use super::DelayedApprovalTimer; + + #[test] + fn test_select_empty_timer() { + block_on(async move { + let mut timer = DelayedApprovalTimer::default(); + + for _ in 1..10 { + let result = futures::select!( + _ = timer.select_next_some() => { + 0 + } + // Only this arm should fire + _ = Delay::new(Duration::from_millis(100)).fuse() => { + 1 + } + ); + + assert_eq!(result, 1); + } + }); + } + + #[test] + fn test_timer_functionality() { + block_on(async move { + let mut timer = DelayedApprovalTimer::default(); + let test_hashes = + vec![Hash::repeat_byte(0x01), Hash::repeat_byte(0x02), Hash::repeat_byte(0x03)]; + for (index, hash) in test_hashes.iter().enumerate() { + timer.maybe_arm_timer( + SystemClock.tick_now() + index as u64, + &SystemClock, + *hash, + ValidatorIndex::from(2), + ); + timer.maybe_arm_timer( + SystemClock.tick_now() + index as u64, + &SystemClock, + *hash, + ValidatorIndex::from(2), + ); + } + let timeout_hash = Hash::repeat_byte(0x02); + for i in 0..test_hashes.len() * 2 { + let result = futures::select!( + (hash, _) = timer.select_next_some() => { + hash + } + // Timers should fire only once, so for the rest of the iterations we should timeout through here. + _ = Delay::new(Duration::from_secs(2)).fuse() => { + timeout_hash + } + ); + assert_eq!(test_hashes.get(i).cloned().unwrap_or(timeout_hash), result); + } + + // Now check timer can be restarted if already fired + for (index, hash) in test_hashes.iter().enumerate() { + timer.maybe_arm_timer( + SystemClock.tick_now() + index as u64, + &SystemClock, + *hash, + ValidatorIndex::from(2), + ); + timer.maybe_arm_timer( + SystemClock.tick_now() + index as u64, + &SystemClock, + *hash, + ValidatorIndex::from(2), + ); + } + + for i in 0..test_hashes.len() * 2 { + let result = futures::select!( + (hash, _) = timer.select_next_some() => { + hash + } + // Timers should fire only once, so for the rest of the iterations we should timeout through here. + _ = Delay::new(Duration::from_secs(2)).fuse() => { + timeout_hash + } + ); + assert_eq!(test_hashes.get(i).cloned().unwrap_or(timeout_hash), result); + } + }); + } +} diff --git a/polkadot/node/core/dispute-coordinator/src/import.rs b/polkadot/node/core/dispute-coordinator/src/import.rs index 837ad7856e7..98c12bd509b 100644 --- a/polkadot/node/core/dispute-coordinator/src/import.rs +++ b/polkadot/node/core/dispute-coordinator/src/import.rs @@ -34,9 +34,9 @@ use polkadot_node_primitives::{ use polkadot_node_subsystem::overseer; use polkadot_node_subsystem_util::runtime::RuntimeInfo; use polkadot_primitives::{ - CandidateReceipt, DisputeStatement, ExecutorParams, Hash, IndexedVec, SessionIndex, - SessionInfo, ValidDisputeStatementKind, ValidatorId, ValidatorIndex, ValidatorPair, - ValidatorSignature, + CandidateHash, CandidateReceipt, DisputeStatement, ExecutorParams, Hash, IndexedVec, + SessionIndex, SessionInfo, ValidDisputeStatementKind, ValidatorId, ValidatorIndex, + ValidatorPair, ValidatorSignature, }; use sc_keystore::LocalKeystore; @@ -126,7 +126,9 @@ impl OwnVoteState { let our_valid_votes = controlled_indices .iter() .filter_map(|i| votes.valid.raw().get_key_value(i)) - .map(|(index, (kind, sig))| (*index, (DisputeStatement::Valid(*kind), sig.clone()))); + .map(|(index, (kind, sig))| { + (*index, (DisputeStatement::Valid(kind.clone()), sig.clone())) + }); let our_invalid_votes = controlled_indices .iter() .filter_map(|i| votes.invalid.get_key_value(i)) @@ -305,7 +307,7 @@ impl CandidateVoteState { DisputeStatement::Valid(valid_kind) => { let fresh = votes.valid.insert_vote( val_index, - *valid_kind, + valid_kind.clone(), statement.into_validator_signature(), ); if fresh { @@ -511,7 +513,7 @@ impl ImportResult { pub fn import_approval_votes( self, env: &CandidateEnvironment, - approval_votes: HashMap, + approval_votes: HashMap, ValidatorSignature)>, now: Timestamp, ) -> Self { let Self { @@ -525,19 +527,33 @@ impl ImportResult { let (mut votes, _) = new_state.into_old_state(); - for (index, sig) in approval_votes.into_iter() { + for (index, (candidate_hashes, sig)) in approval_votes.into_iter() { debug_assert!( { let pub_key = &env.session_info().validators.get(index).expect("indices are validated by approval-voting subsystem; qed"); - let candidate_hash = votes.candidate_receipt.hash(); let session_index = env.session_index(); - DisputeStatement::Valid(ValidDisputeStatementKind::ApprovalChecking) - .check_signature(pub_key, candidate_hash, session_index, &sig) + candidate_hashes.contains(&votes.candidate_receipt.hash()) && DisputeStatement::Valid(ValidDisputeStatementKind::ApprovalCheckingMultipleCandidates(candidate_hashes.clone())) + .check_signature(pub_key, *candidate_hashes.first().expect("Valid votes have at least one candidate; qed"), session_index, &sig) .is_ok() }, "Signature check for imported approval votes failed! This is a serious bug. Session: {:?}, candidate hash: {:?}, validator index: {:?}", env.session_index(), votes.candidate_receipt.hash(), index ); - if votes.valid.insert_vote(index, ValidDisputeStatementKind::ApprovalChecking, sig) { + if votes.valid.insert_vote( + index, + // There is a hidden dependency here between approval-voting and this subsystem. + // We should be able to start emitting + // ValidDisputeStatementKind::ApprovalCheckingMultipleCandidates only after: + // 1. Runtime have been upgraded to know about the new format. + // 2. All nodes have been upgraded to know about the new format. + // Once those two requirements have been met we should be able to increase + // max_approval_coalesce_count to values greater than 1. + if candidate_hashes.len() > 1 { + ValidDisputeStatementKind::ApprovalCheckingMultipleCandidates(candidate_hashes) + } else { + ValidDisputeStatementKind::ApprovalChecking + }, + sig, + ) { imported_valid_votes += 1; imported_approval_votes += 1; } diff --git a/polkadot/node/core/dispute-coordinator/src/initialized.rs b/polkadot/node/core/dispute-coordinator/src/initialized.rs index e44530b3f1b..d9cd4e39d3c 100644 --- a/polkadot/node/core/dispute-coordinator/src/initialized.rs +++ b/polkadot/node/core/dispute-coordinator/src/initialized.rs @@ -642,7 +642,7 @@ impl Initialized { }; debug_assert!( SignedDisputeStatement::new_checked( - DisputeStatement::Valid(valid_statement_kind), + DisputeStatement::Valid(valid_statement_kind.clone()), candidate_hash, session, validator_public.clone(), @@ -656,7 +656,7 @@ impl Initialized { ); let signed_dispute_statement = SignedDisputeStatement::new_unchecked_from_trusted_source( - DisputeStatement::Valid(valid_statement_kind), + DisputeStatement::Valid(valid_statement_kind.clone()), candidate_hash, session, validator_public, diff --git a/polkadot/node/core/dispute-coordinator/src/lib.rs b/polkadot/node/core/dispute-coordinator/src/lib.rs index e96fee81240..5067d3673da 100644 --- a/polkadot/node/core/dispute-coordinator/src/lib.rs +++ b/polkadot/node/core/dispute-coordinator/src/lib.rs @@ -576,7 +576,7 @@ pub fn make_dispute_message( .next() .ok_or(DisputeMessageCreationError::NoOppositeVote)?; let other_vote = SignedDisputeStatement::new_checked( - DisputeStatement::Valid(*statement_kind), + DisputeStatement::Valid(statement_kind.clone()), *our_vote.candidate_hash(), our_vote.session_index(), validators diff --git a/polkadot/node/core/dispute-coordinator/src/tests.rs b/polkadot/node/core/dispute-coordinator/src/tests.rs index 6912bbf67e1..da449773fe8 100644 --- a/polkadot/node/core/dispute-coordinator/src/tests.rs +++ b/polkadot/node/core/dispute-coordinator/src/tests.rs @@ -661,7 +661,7 @@ fn make_candidate_included_event(candidate_receipt: CandidateReceipt) -> Candida pub async fn handle_approval_vote_request( ctx_handle: &mut VirtualOverseer, expected_hash: &CandidateHash, - votes_to_send: HashMap, + votes_to_send: HashMap, ValidatorSignature)>, ) { assert_matches!( ctx_handle.recv().await, @@ -868,9 +868,12 @@ fn approval_vote_import_works() { .await; gum::trace!("After sending `ImportStatements`"); - let approval_votes = [(ValidatorIndex(4), approval_vote.into_validator_signature())] - .into_iter() - .collect(); + let approval_votes = [( + ValidatorIndex(4), + (vec![candidate_receipt1.hash()], approval_vote.into_validator_signature()), + )] + .into_iter() + .collect(); handle_approval_vote_request(&mut virtual_overseer, &candidate_hash1, approval_votes) .await; diff --git a/polkadot/node/core/provisioner/src/disputes/prioritized_selection/mod.rs b/polkadot/node/core/provisioner/src/disputes/prioritized_selection/mod.rs index 096b73d271a..cb55ce39bc8 100644 --- a/polkadot/node/core/provisioner/src/disputes/prioritized_selection/mod.rs +++ b/polkadot/node/core/provisioner/src/disputes/prioritized_selection/mod.rs @@ -221,7 +221,7 @@ where votes.valid.retain(|validator_idx, (statement_kind, _)| { is_vote_worth_to_keep( validator_idx, - DisputeStatement::Valid(*statement_kind), + DisputeStatement::Valid(statement_kind.clone()), &onchain_state, ) }); diff --git a/polkadot/node/core/runtime-api/src/cache.rs b/polkadot/node/core/runtime-api/src/cache.rs index 8a7a3dc08b8..5eca551db0a 100644 --- a/polkadot/node/core/runtime-api/src/cache.rs +++ b/polkadot/node/core/runtime-api/src/cache.rs @@ -20,12 +20,13 @@ use schnellru::{ByLength, LruMap}; use sp_consensus_babe::Epoch; use polkadot_primitives::{ - async_backing, slashing, vstaging, AuthorityDiscoveryId, BlockNumber, CandidateCommitments, - CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreState, DisputeState, - ExecutorParams, GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage, - InboundHrmpMessage, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, - ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash, - ValidatorId, ValidatorIndex, ValidatorSignature, + async_backing, slashing, + vstaging::{self, ApprovalVotingParams}, + AuthorityDiscoveryId, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, + CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Hash, + Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, OccupiedCoreAssumption, + PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, + ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, }; /// For consistency we have the same capacity for all caches. We use 128 as we'll only need that @@ -68,6 +69,7 @@ pub(crate) struct RequestResultCache { para_backing_state: LruMap<(Hash, ParaId), Option>, async_backing_params: LruMap, node_features: LruMap, + approval_voting_params: LruMap, } impl Default for RequestResultCache { @@ -98,6 +100,7 @@ impl Default for RequestResultCache { unapplied_slashes: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), key_ownership_proof: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), minimum_backing_votes: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), + approval_voting_params: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), disabled_validators: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), para_backing_state: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), async_backing_params: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), @@ -507,6 +510,21 @@ impl RequestResultCache { ) { self.async_backing_params.insert(key, value); } + + pub(crate) fn approval_voting_params( + &mut self, + key: (Hash, SessionIndex), + ) -> Option<&ApprovalVotingParams> { + self.approval_voting_params.get(&key.1).map(|v| &*v) + } + + pub(crate) fn cache_approval_voting_params( + &mut self, + session_index: SessionIndex, + value: ApprovalVotingParams, + ) { + self.approval_voting_params.insert(session_index, value); + } } pub(crate) enum RequestResult { @@ -554,6 +572,7 @@ pub(crate) enum RequestResult { slashing::OpaqueKeyOwnershipProof, Option<()>, ), + ApprovalVotingParams(Hash, SessionIndex, ApprovalVotingParams), DisabledValidators(Hash, Vec), ParaBackingState(Hash, ParaId, Option), AsyncBackingParams(Hash, async_backing::AsyncBackingParams), diff --git a/polkadot/node/core/runtime-api/src/lib.rs b/polkadot/node/core/runtime-api/src/lib.rs index 8689355c413..4bedfd82734 100644 --- a/polkadot/node/core/runtime-api/src/lib.rs +++ b/polkadot/node/core/runtime-api/src/lib.rs @@ -165,6 +165,8 @@ where KeyOwnershipProof(relay_parent, validator_id, key_ownership_proof) => self .requests_cache .cache_key_ownership_proof((relay_parent, validator_id), key_ownership_proof), + RequestResult::ApprovalVotingParams(_relay_parent, session_index, params) => + self.requests_cache.cache_approval_voting_params(session_index, params), SubmitReportDisputeLost(_, _, _, _) => {}, DisabledValidators(relay_parent, disabled_validators) => self.requests_cache.cache_disabled_validators(relay_parent, disabled_validators), @@ -300,6 +302,9 @@ where Request::SubmitReportDisputeLost(dispute_proof, key_ownership_proof, sender) }, ), + Request::ApprovalVotingParams(session_index, sender) => + query!(approval_voting_params(session_index), sender) + .map(|sender| Request::ApprovalVotingParams(session_index, sender)), Request::DisabledValidators(sender) => query!(disabled_validators(), sender) .map(|sender| Request::DisabledValidators(sender)), Request::ParaBackingState(para, sender) => query!(para_backing_state(para), sender) @@ -571,6 +576,14 @@ where ver = Request::KEY_OWNERSHIP_PROOF_RUNTIME_REQUIREMENT, sender ), + Request::ApprovalVotingParams(session_index, sender) => { + query!( + ApprovalVotingParams, + approval_voting_params(session_index), + ver = Request::APPROVAL_VOTING_PARAMS_REQUIREMENT, + sender + ) + }, Request::SubmitReportDisputeLost(dispute_proof, key_ownership_proof, sender) => query!( SubmitReportDisputeLost, submit_report_dispute_lost(dispute_proof, key_ownership_proof), diff --git a/polkadot/node/core/runtime-api/src/tests.rs b/polkadot/node/core/runtime-api/src/tests.rs index b939bffb0e7..f91723b3d39 100644 --- a/polkadot/node/core/runtime-api/src/tests.rs +++ b/polkadot/node/core/runtime-api/src/tests.rs @@ -20,12 +20,13 @@ use polkadot_node_primitives::{BabeAllowedSlots, BabeEpoch, BabeEpochConfigurati use polkadot_node_subsystem::SpawnGlue; use polkadot_node_subsystem_test_helpers::make_subsystem_context; use polkadot_primitives::{ - async_backing, slashing, vstaging::NodeFeatures, AuthorityDiscoveryId, BlockNumber, - CandidateCommitments, CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreState, - DisputeState, ExecutorParams, GroupRotationInfo, Id as ParaId, InboundDownwardMessage, - InboundHrmpMessage, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, - ScrapedOnChainVotes, SessionIndex, SessionInfo, Slot, ValidationCode, ValidationCodeHash, - ValidatorId, ValidatorIndex, ValidatorSignature, + async_backing, slashing, + vstaging::{ApprovalVotingParams, NodeFeatures}, + AuthorityDiscoveryId, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, + CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, GroupRotationInfo, + Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, OccupiedCoreAssumption, + PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, + Slot, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, }; use sp_api::ApiError; use sp_core::testing::TaskExecutor; @@ -242,6 +243,15 @@ impl RuntimeApiSubsystemClient for MockSubsystemClient { todo!("Not required for tests") } + /// Approval voting configuration parameters + async fn approval_voting_params( + &self, + _: Hash, + _: SessionIndex, + ) -> Result { + todo!("Not required for tests") + } + async fn current_epoch(&self, _: Hash) -> Result { Ok(self.babe_epoch.as_ref().unwrap().clone()) } diff --git a/polkadot/node/network/approval-distribution/src/lib.rs b/polkadot/node/network/approval-distribution/src/lib.rs index 47482eef764..d520febaef5 100644 --- a/polkadot/node/network/approval-distribution/src/lib.rs +++ b/polkadot/node/network/approval-distribution/src/lib.rs @@ -32,14 +32,15 @@ use polkadot_node_network_protocol::{ self as net_protocol, filter_by_peer_version, grid_topology::{RandomRouting, RequiredRouting, SessionGridTopologies, SessionGridTopology}, peer_set::MAX_NOTIFICATION_SIZE, - v1 as protocol_v1, v2 as protocol_v2, vstaging as protocol_vstaging, PeerId, + v1 as protocol_v1, v2 as protocol_v2, v3 as protocol_v3, PeerId, UnifiedReputationChange as Rep, Versioned, View, }; use polkadot_node_primitives::approval::{ - v1::{ - AssignmentCertKind, BlockApprovalMeta, IndirectAssignmentCert, IndirectSignedApprovalVote, + v1::{AssignmentCertKind, BlockApprovalMeta, IndirectAssignmentCert}, + v2::{ + AsBitIndex, AssignmentCertKindV2, CandidateBitfield, IndirectAssignmentCertV2, + IndirectSignedApprovalVoteV2, }, - v2::{AsBitIndex, AssignmentCertKindV2, CandidateBitfield, IndirectAssignmentCertV2}, }; use polkadot_node_subsystem::{ messages::{ @@ -113,6 +114,14 @@ struct ApprovalRouting { required_routing: RequiredRouting, local: bool, random_routing: RandomRouting, + peers_randomly_routed: Vec, +} + +impl ApprovalRouting { + fn mark_randomly_sent(&mut self, peer: PeerId) { + self.random_routing.inc_sent(); + self.peers_randomly_routed.push(peer); + } } // This struct is responsible for tracking the full state of an assignment and grid routing @@ -121,9 +130,9 @@ struct ApprovalEntry { // The assignment certificate. assignment: IndirectAssignmentCertV2, // The candidates claimed by the certificate. A mapping between bit index and candidate index. - candidates: CandidateBitfield, + assignment_claimed_candidates: CandidateBitfield, // The approval signatures for each `CandidateIndex` claimed by the assignment certificate. - approvals: HashMap, + approvals: HashMap, // The validator index of the assignment signer. validator_index: ValidatorIndex, // Information required for gossiping to other peers using the grid topology. @@ -136,6 +145,8 @@ enum ApprovalEntryError { CandidateIndexOutOfBounds, InvalidCandidateIndex, DuplicateApproval, + UnknownAssignment, + AssignmentsFollowedDifferentPaths(RequiredRouting, RequiredRouting), } impl ApprovalEntry { @@ -148,7 +159,7 @@ impl ApprovalEntry { validator_index: assignment.validator, assignment, approvals: HashMap::with_capacity(candidates.len()), - candidates, + assignment_claimed_candidates: candidates, routing_info, } } @@ -156,23 +167,15 @@ impl ApprovalEntry { // Create a `MessageSubject` to reference the assignment. pub fn create_assignment_knowledge(&self, block_hash: Hash) -> (MessageSubject, MessageKind) { ( - MessageSubject(block_hash, self.candidates.clone(), self.validator_index), + MessageSubject( + block_hash, + self.assignment_claimed_candidates.clone(), + self.validator_index, + ), MessageKind::Assignment, ) } - // Create a `MessageSubject` to reference the approval. - pub fn create_approval_knowledge( - &self, - block_hash: Hash, - candidate_index: CandidateIndex, - ) -> (MessageSubject, MessageKind) { - ( - MessageSubject(block_hash, candidate_index.into(), self.validator_index), - MessageKind::Approval, - ) - } - // Updates routing information and returns the previous information if any. pub fn routing_info_mut(&mut self) -> &mut ApprovalRouting { &mut self.routing_info @@ -188,11 +191,21 @@ impl ApprovalEntry { self.routing_info.required_routing = required_routing; } + // Tells if this entry assignment covers at least one candidate in the approval + pub fn includes_approval_candidates(&self, approval: &IndirectSignedApprovalVoteV2) -> bool { + for candidate_index in approval.candidate_indices.iter_ones() { + if self.assignment_claimed_candidates.bit_at((candidate_index).as_bit_index()) { + return true + } + } + return false + } + // Records a new approval. Returns error if the claimed candidate is not found or we already // have received the approval. pub fn note_approval( &mut self, - approval: IndirectSignedApprovalVote, + approval: IndirectSignedApprovalVoteV2, ) -> Result<(), ApprovalEntryError> { // First do some sanity checks: // - check validator index matches @@ -202,37 +215,29 @@ impl ApprovalEntry { return Err(ApprovalEntryError::InvalidValidatorIndex) } - if self.candidates.len() <= approval.candidate_index as usize { - return Err(ApprovalEntryError::CandidateIndexOutOfBounds) - } - - if !self.candidates.bit_at(approval.candidate_index.as_bit_index()) { + // We need at least one of the candidates in the approval to be in this assignment + if !self.includes_approval_candidates(&approval) { return Err(ApprovalEntryError::InvalidCandidateIndex) } - if self.approvals.contains_key(&approval.candidate_index) { + if self.approvals.contains_key(&approval.candidate_indices) { return Err(ApprovalEntryError::DuplicateApproval) } - self.approvals.insert(approval.candidate_index, approval); + self.approvals.insert(approval.candidate_indices.clone(), approval.clone()); Ok(()) } // Get the assignment certiticate and claimed candidates. pub fn assignment(&self) -> (IndirectAssignmentCertV2, CandidateBitfield) { - (self.assignment.clone(), self.candidates.clone()) + (self.assignment.clone(), self.assignment_claimed_candidates.clone()) } // Get all approvals for all candidates claimed by the assignment. - pub fn approvals(&self) -> Vec { + pub fn approvals(&self) -> Vec { self.approvals.values().cloned().collect::>() } - // Get the approval for a specific candidate index. - pub fn approval(&self, candidate_index: CandidateIndex) -> Option { - self.approvals.get(&candidate_index).cloned() - } - // Get validator index. pub fn validator_index(&self) -> ValidatorIndex { self.validator_index @@ -430,6 +435,41 @@ impl PeerKnowledge { fn contains(&self, message: &MessageSubject, kind: MessageKind) -> bool { self.sent.contains(message, kind) || self.received.contains(message, kind) } + + // Generate the knowledge keys for querying if all assignments of an approval are known + // by this peer. + fn generate_assignments_keys( + approval: &IndirectSignedApprovalVoteV2, + ) -> Vec<(MessageSubject, MessageKind)> { + approval + .candidate_indices + .iter_ones() + .map(|candidate_index| { + ( + MessageSubject( + approval.block_hash, + (candidate_index as CandidateIndex).into(), + approval.validator, + ), + MessageKind::Assignment, + ) + }) + .collect_vec() + } + + // Generate the knowledge keys for querying if an approval is known by peer. + fn generate_approval_key( + approval: &IndirectSignedApprovalVoteV2, + ) -> (MessageSubject, MessageKind) { + ( + MessageSubject( + approval.block_hash, + approval.candidate_indices.clone(), + approval.validator, + ), + MessageKind::Approval, + ) + } } /// Information about blocks in our current view as well as whether peers know of them. @@ -462,13 +502,13 @@ impl BlockEntry { // First map one entry per candidate to the same key we will use in `approval_entries`. // Key is (Validator_index, CandidateBitfield) that links the `ApprovalEntry` to the (K,V) // entry in `candidate_entry.messages`. - for claimed_candidate_index in entry.candidates.iter_ones() { + for claimed_candidate_index in entry.assignment_claimed_candidates.iter_ones() { match self.candidates.get_mut(claimed_candidate_index) { Some(candidate_entry) => { candidate_entry - .messages + .assignments .entry(entry.validator_index()) - .or_insert(entry.candidates.clone()); + .or_insert(entry.assignment_claimed_candidates.clone()); }, None => { // This should never happen, but if it happens, it means the subsystem is @@ -484,50 +524,107 @@ impl BlockEntry { } self.approval_entries - .entry((entry.validator_index, entry.candidates.clone())) + .entry((entry.validator_index, entry.assignment_claimed_candidates.clone())) .or_insert(entry) } - // Returns a mutable reference of `ApprovalEntry` for `candidate_index` from validator - // `validator_index`. - pub fn approval_entry( + // Tels if all candidate_indices are valid candidates + pub fn contains_candidates(&self, candidate_indices: &CandidateBitfield) -> bool { + candidate_indices + .iter_ones() + .all(|candidate_index| self.candidates.get(candidate_index as usize).is_some()) + } + + // Saves the given approval in all ApprovalEntries that contain an assignment for any of the + // candidates in the approval. + // + // Returns the required routing needed for this approval and the lit of random peers the + // covering assignments were sent. + pub fn note_approval( &mut self, - candidate_index: CandidateIndex, - validator_index: ValidatorIndex, - ) -> Option<&mut ApprovalEntry> { - self.candidates - .get(candidate_index as usize) - .map_or(None, |candidate_entry| candidate_entry.messages.get(&validator_index)) - .map_or(None, |candidate_indices| { - self.approval_entries.get_mut(&(validator_index, candidate_indices.clone())) + approval: IndirectSignedApprovalVoteV2, + ) -> Result<(RequiredRouting, HashSet), ApprovalEntryError> { + let mut required_routing = None; + let mut peers_randomly_routed_to = HashSet::new(); + + if self.candidates.len() < approval.candidate_indices.len() as usize { + return Err(ApprovalEntryError::CandidateIndexOutOfBounds) + } + + // First determine all assignments bitfields that might be covered by this approval + let covered_assignments_bitfields: HashSet = approval + .candidate_indices + .iter_ones() + .filter_map(|candidate_index| { + self.candidates.get_mut(candidate_index).map_or(None, |candidate_entry| { + candidate_entry.assignments.get(&approval.validator).cloned() + }) }) - } + .collect(); - // Get all approval entries for a given candidate. - pub fn approval_entries(&self, candidate_index: CandidateIndex) -> Vec<&ApprovalEntry> { - // Get the keys for fetching `ApprovalEntry` from `self.approval_entries`, - let approval_entry_keys = self - .candidates - .get(candidate_index as usize) - .map(|candidate_entry| &candidate_entry.messages); - - if let Some(approval_entry_keys) = approval_entry_keys { - // Ensure no duplicates. - let approval_entry_keys = approval_entry_keys.iter().unique().collect::>(); - - let mut entries = Vec::new(); - for (validator_index, candidate_indices) in approval_entry_keys { - if let Some(entry) = - self.approval_entries.get(&(*validator_index, candidate_indices.clone())) - { - entries.push(entry); + // Mark the vote in all approval entries + for assignment_bitfield in covered_assignments_bitfields { + if let Some(approval_entry) = + self.approval_entries.get_mut(&(approval.validator, assignment_bitfield)) + { + approval_entry.note_approval(approval.clone())?; + peers_randomly_routed_to + .extend(approval_entry.routing_info().peers_randomly_routed.iter()); + + if let Some(required_routing) = required_routing { + if required_routing != approval_entry.routing_info().required_routing { + // This shouldn't happen since the required routing is computed based on the + // validator_index, so two assignments from the same validators will have + // the same required routing. + return Err(ApprovalEntryError::AssignmentsFollowedDifferentPaths( + required_routing, + approval_entry.routing_info().required_routing, + )) + } + } else { + required_routing = Some(approval_entry.routing_info().required_routing) } } - entries + } + + if let Some(required_routing) = required_routing { + Ok((required_routing, peers_randomly_routed_to)) } else { - vec![] + Err(ApprovalEntryError::UnknownAssignment) } } + + /// Returns the list of approval votes covering this candidate + pub fn approval_votes( + &self, + candidate_index: CandidateIndex, + ) -> Vec { + let result: Option< + HashMap<(ValidatorIndex, CandidateBitfield), IndirectSignedApprovalVoteV2>, + > = self.candidates.get(candidate_index as usize).map(|candidate_entry| { + candidate_entry + .assignments + .iter() + .filter_map(|(validator, assignment_bitfield)| { + self.approval_entries.get(&(*validator, assignment_bitfield.clone())) + }) + .flat_map(|approval_entry| { + approval_entry + .approvals + .clone() + .into_iter() + .filter(|(approved_candidates, _)| { + approved_candidates.bit_at(candidate_index.as_bit_index()) + }) + .map(|(approved_candidates, vote)| { + ((approval_entry.validator_index, approved_candidates), vote) + }) + }) + .collect() + }); + + result.map(|result| result.into_values().collect_vec()).unwrap_or_default() + } } // Information about candidates in the context of a particular block they are included in. @@ -537,7 +634,7 @@ impl BlockEntry { struct CandidateEntry { // The value represents part of the lookup key in `approval_entries` to fetch the assignment // and existing votes. - messages: HashMap, + assignments: HashMap, } #[derive(Debug, Clone, PartialEq)] @@ -557,7 +654,7 @@ impl MessageSource { enum PendingMessage { Assignment(IndirectAssignmentCertV2, CandidateBitfield), - Approval(IndirectSignedApprovalVote), + Approval(IndirectSignedApprovalVoteV2), } #[overseer::contextbounds(ApprovalDistribution, prefix = self::overseer)] @@ -830,6 +927,49 @@ impl State { } } + // Entry point for processing an approval coming from a peer. + async fn process_incoming_approvals( + &mut self, + ctx: &mut Context, + metrics: &Metrics, + peer_id: PeerId, + approvals: Vec, + ) { + gum::trace!( + target: LOG_TARGET, + peer_id = %peer_id, + num = approvals.len(), + "Processing approvals from a peer", + ); + for approval_vote in approvals.into_iter() { + if let Some(pending) = self.pending_known.get_mut(&approval_vote.block_hash) { + let block_hash = approval_vote.block_hash; + let validator_index = approval_vote.validator; + + gum::trace!( + target: LOG_TARGET, + %peer_id, + ?block_hash, + ?validator_index, + "Pending assignment candidates {:?}", + approval_vote.candidate_indices, + ); + + pending.push((peer_id, PendingMessage::Approval(approval_vote))); + + continue + } + + self.import_and_circulate_approval( + ctx, + metrics, + MessageSource::Peer(peer_id), + approval_vote, + ) + .await; + } + } + async fn process_incoming_peer_message( &mut self, ctx: &mut Context, @@ -838,16 +978,14 @@ impl State { msg: Versioned< protocol_v1::ApprovalDistributionMessage, protocol_v2::ApprovalDistributionMessage, - protocol_vstaging::ApprovalDistributionMessage, + protocol_v3::ApprovalDistributionMessage, >, rng: &mut R, ) where R: CryptoRng + Rng, { match msg { - Versioned::VStaging(protocol_vstaging::ApprovalDistributionMessage::Assignments( - assignments, - )) => { + Versioned::V3(protocol_v3::ApprovalDistributionMessage::Assignments(assignments)) => { gum::trace!( target: LOG_TARGET, peer_id = %peer_id, @@ -887,45 +1025,18 @@ impl State { ) .await; }, - Versioned::VStaging(protocol_vstaging::ApprovalDistributionMessage::Approvals( - approvals, - )) | + Versioned::V3(protocol_v3::ApprovalDistributionMessage::Approvals(approvals)) => { + self.process_incoming_approvals(ctx, metrics, peer_id, approvals).await; + }, Versioned::V1(protocol_v1::ApprovalDistributionMessage::Approvals(approvals)) | Versioned::V2(protocol_v2::ApprovalDistributionMessage::Approvals(approvals)) => { - gum::trace!( - target: LOG_TARGET, - peer_id = %peer_id, - num = approvals.len(), - "Processing approvals from a peer", - ); - for approval_vote in approvals.into_iter() { - if let Some(pending) = self.pending_known.get_mut(&approval_vote.block_hash) { - let block_hash = approval_vote.block_hash; - let candidate_index = approval_vote.candidate_index; - let validator_index = approval_vote.validator; - - gum::trace!( - target: LOG_TARGET, - %peer_id, - ?block_hash, - ?candidate_index, - ?validator_index, - "Pending assignment", - ); - - pending.push((peer_id, PendingMessage::Approval(approval_vote))); - - continue - } - - self.import_and_circulate_approval( - ctx, - metrics, - MessageSource::Peer(peer_id), - approval_vote, - ) - .await; - } + self.process_incoming_approvals( + ctx, + metrics, + peer_id, + approvals.into_iter().map(|approval| approval.into()).collect::>(), + ) + .await; }, } } @@ -1071,8 +1182,11 @@ impl State { COST_UNEXPECTED_MESSAGE, ) .await; + gum::debug!(target: LOG_TARGET, "Received assignment for invalid block"); + metrics.on_assignment_recent_outdated(); } } + metrics.on_assignment_invalid_block(); return }, }; @@ -1105,6 +1219,7 @@ impl State { COST_DUPLICATE_MESSAGE, ) .await; + metrics.on_assignment_duplicate(); } else { gum::trace!( target: LOG_TARGET, @@ -1132,6 +1247,7 @@ impl State { COST_UNEXPECTED_MESSAGE, ) .await; + metrics.on_assignment_out_of_view(); }, } @@ -1148,6 +1264,7 @@ impl State { gum::trace!(target: LOG_TARGET, ?peer_id, ?message_subject, "Known assignment"); peer_knowledge.received.insert(message_subject, message_kind); } + metrics.on_assignment_good_known(); return } @@ -1204,6 +1321,8 @@ impl State { ?peer_id, "Got an `AcceptedDuplicate` assignment", ); + metrics.on_assignment_duplicatevoting(); + return }, AssignmentCheckResult::TooFarInFuture => { @@ -1220,6 +1339,8 @@ impl State { COST_ASSIGNMENT_TOO_FAR_IN_THE_FUTURE, ) .await; + metrics.on_assignment_far(); + return }, AssignmentCheckResult::Bad(error) => { @@ -1237,6 +1358,7 @@ impl State { COST_INVALID_MESSAGE, ) .await; + metrics.on_assignment_bad(); return }, } @@ -1275,7 +1397,12 @@ impl State { let approval_entry = entry.insert_approval_entry(ApprovalEntry::new( assignment.clone(), claimed_candidate_indices.clone(), - ApprovalRouting { required_routing, local, random_routing: Default::default() }, + ApprovalRouting { + required_routing, + local, + random_routing: Default::default(), + peers_randomly_routed: Default::default(), + }, )); // Dispatch the message to all peers in the routing set which @@ -1305,6 +1432,10 @@ impl State { continue } + if !topology.map(|topology| topology.is_validator(&peer)).unwrap_or(false) { + continue + } + // Note: at this point, we haven't received the message from any peers // other than the source peer, and we just got it, so we haven't sent it // to any peers either. @@ -1312,7 +1443,7 @@ impl State { approval_entry.routing_info().random_routing.sample(n_peers_total, rng); if route_random { - approval_entry.routing_info_mut().random_routing.inc_sent(); + approval_entry.routing_info_mut().mark_randomly_sent(peer); peers.push(peer); } } @@ -1346,12 +1477,94 @@ impl State { } } + // Checks if an approval can be processed. + // Returns true if we can continue with processing the approval and false otherwise. + async fn check_approval_can_be_processed( + ctx: &mut Context, + assignments_knowledge_key: &Vec<(MessageSubject, MessageKind)>, + approval_knowledge_key: &(MessageSubject, MessageKind), + entry: &mut BlockEntry, + reputation: &mut ReputationAggregator, + peer_id: PeerId, + metrics: &Metrics, + ) -> bool { + for message_subject in assignments_knowledge_key { + if !entry.knowledge.contains(&message_subject.0, message_subject.1) { + gum::trace!( + target: LOG_TARGET, + ?peer_id, + ?message_subject, + "Unknown approval assignment", + ); + modify_reputation(reputation, ctx.sender(), peer_id, COST_UNEXPECTED_MESSAGE).await; + metrics.on_approval_unknown_assignment(); + return false + } + } + + // check if our knowledge of the peer already contains this approval + match entry.known_by.entry(peer_id) { + hash_map::Entry::Occupied(mut knowledge) => { + let peer_knowledge = knowledge.get_mut(); + if peer_knowledge.contains(&approval_knowledge_key.0, approval_knowledge_key.1) { + if !peer_knowledge + .received + .insert(approval_knowledge_key.0.clone(), approval_knowledge_key.1) + { + gum::trace!( + target: LOG_TARGET, + ?peer_id, + ?approval_knowledge_key, + "Duplicate approval", + ); + + modify_reputation( + reputation, + ctx.sender(), + peer_id, + COST_DUPLICATE_MESSAGE, + ) + .await; + metrics.on_approval_duplicate(); + } + return false + } + }, + hash_map::Entry::Vacant(_) => { + gum::debug!( + target: LOG_TARGET, + ?peer_id, + ?approval_knowledge_key, + "Approval from a peer is out of view", + ); + modify_reputation(reputation, ctx.sender(), peer_id, COST_UNEXPECTED_MESSAGE).await; + metrics.on_approval_out_of_view(); + }, + } + + if entry.knowledge.contains(&approval_knowledge_key.0, approval_knowledge_key.1) { + if let Some(peer_knowledge) = entry.known_by.get_mut(&peer_id) { + peer_knowledge + .received + .insert(approval_knowledge_key.0.clone(), approval_knowledge_key.1); + } + + // We already processed this approval no need to continue. + gum::trace!(target: LOG_TARGET, ?peer_id, ?approval_knowledge_key, "Known approval"); + metrics.on_approval_good_known(); + modify_reputation(reputation, ctx.sender(), peer_id, BENEFIT_VALID_MESSAGE).await; + false + } else { + true + } + } + async fn import_and_circulate_approval( &mut self, ctx: &mut Context, metrics: &Metrics, source: MessageSource, - vote: IndirectSignedApprovalVote, + vote: IndirectSignedApprovalVoteV2, ) { let _span = self .spans @@ -1370,10 +1583,9 @@ impl State { let block_hash = vote.block_hash; let validator_index = vote.validator; - let candidate_index = vote.candidate_index; - + let candidate_indices = &vote.candidate_indices; let entry = match self.blocks.get_mut(&block_hash) { - Some(entry) if entry.candidates.get(candidate_index as usize).is_some() => entry, + Some(entry) if entry.contains_candidates(&vote.candidate_indices) => entry, _ => { if let Some(peer_id) = source.peer_id() { if !self.recent_outdated_blocks.is_recent_outdated(&block_hash) { @@ -1382,7 +1594,7 @@ impl State { ?peer_id, ?block_hash, ?validator_index, - ?candidate_index, + ?candidate_indices, "Approval from a peer is out of view", ); modify_reputation( @@ -1392,6 +1604,9 @@ impl State { COST_UNEXPECTED_MESSAGE, ) .await; + metrics.on_approval_invalid_block(); + } else { + metrics.on_approval_recent_outdated(); } } return @@ -1399,81 +1614,21 @@ impl State { }; // compute metadata on the assignment. - let message_subject = MessageSubject(block_hash, candidate_index.into(), validator_index); - let message_kind = MessageKind::Approval; + let assignments_knowledge_keys = PeerKnowledge::generate_assignments_keys(&vote); + let approval_knwowledge_key = PeerKnowledge::generate_approval_key(&vote); if let Some(peer_id) = source.peer_id() { - if !entry.knowledge.contains(&message_subject, MessageKind::Assignment) { - gum::debug!( - target: LOG_TARGET, - ?peer_id, - ?message_subject, - "Unknown approval assignment", - ); - modify_reputation( - &mut self.reputation, - ctx.sender(), - peer_id, - COST_UNEXPECTED_MESSAGE, - ) - .await; - return - } - - // check if our knowledge of the peer already contains this approval - match entry.known_by.entry(peer_id) { - hash_map::Entry::Occupied(mut knowledge) => { - let peer_knowledge = knowledge.get_mut(); - if peer_knowledge.contains(&message_subject, message_kind) { - if !peer_knowledge.received.insert(message_subject.clone(), message_kind) { - gum::debug!( - target: LOG_TARGET, - ?peer_id, - ?message_subject, - "Duplicate approval", - ); - - modify_reputation( - &mut self.reputation, - ctx.sender(), - peer_id, - COST_DUPLICATE_MESSAGE, - ) - .await; - } - return - } - }, - hash_map::Entry::Vacant(_) => { - gum::debug!( - target: LOG_TARGET, - ?peer_id, - ?message_subject, - "Approval from a peer is out of view", - ); - modify_reputation( - &mut self.reputation, - ctx.sender(), - peer_id, - COST_UNEXPECTED_MESSAGE, - ) - .await; - }, - } - - // if the approval is known to be valid, reward the peer - if entry.knowledge.contains(&message_subject, message_kind) { - gum::trace!(target: LOG_TARGET, ?peer_id, ?message_subject, "Known approval"); - modify_reputation( - &mut self.reputation, - ctx.sender(), - peer_id, - BENEFIT_VALID_MESSAGE, - ) - .await; - if let Some(peer_knowledge) = entry.known_by.get_mut(&peer_id) { - peer_knowledge.received.insert(message_subject.clone(), message_kind); - } + if !Self::check_approval_can_be_processed( + ctx, + &assignments_knowledge_keys, + &approval_knwowledge_key, + entry, + &mut self.reputation, + peer_id, + metrics, + ) + .await + { return } @@ -1495,8 +1650,8 @@ impl State { gum::trace!( target: LOG_TARGET, ?peer_id, - ?message_subject, ?result, + ?vote, "Checked approval", ); match result { @@ -1509,9 +1664,13 @@ impl State { ) .await; - entry.knowledge.insert(message_subject.clone(), message_kind); + entry + .knowledge + .insert(approval_knwowledge_key.0.clone(), approval_knwowledge_key.1); if let Some(peer_knowledge) = entry.known_by.get_mut(&peer_id) { - peer_knowledge.received.insert(message_subject.clone(), message_kind); + peer_knowledge + .received + .insert(approval_knwowledge_key.0.clone(), approval_knwowledge_key.1); } }, ApprovalCheckResult::Bad(error) => { @@ -1528,74 +1687,55 @@ impl State { %error, "Got a bad approval from peer", ); + metrics.on_approval_bad(); return }, } } else { - if !entry.knowledge.insert(message_subject.clone(), message_kind) { - // if we already imported an approval, there is no need to distribute it again + if !entry + .knowledge + .insert(approval_knwowledge_key.0.clone(), approval_knwowledge_key.1) + { + // if we already imported all approvals, there is no need to distribute it again gum::warn!( target: LOG_TARGET, - ?message_subject, "Importing locally an already known approval", ); return } else { gum::debug!( target: LOG_TARGET, - ?message_subject, "Importing locally a new approval", ); } } - let required_routing = match entry.approval_entry(candidate_index, validator_index) { - Some(approval_entry) => { - // Invariant: to our knowledge, none of the peers except for the `source` know about - // the approval. - metrics.on_approval_imported(); - - if let Err(err) = approval_entry.note_approval(vote.clone()) { - // this would indicate a bug in approval-voting: - // - validator index mismatch - // - candidate index mismatch - // - duplicate approval - gum::warn!( - target: LOG_TARGET, - hash = ?block_hash, - ?candidate_index, - ?validator_index, - ?err, - "Possible bug: Vote import failed", - ); - - return - } - - approval_entry.routing_info().required_routing - }, - None => { - let peer_id = source.peer_id(); - // This indicates a bug in approval-distribution, since we check the knowledge at - // the begining of the function. + let (required_routing, peers_randomly_routed_to) = match entry.note_approval(vote.clone()) { + Ok(required_routing) => required_routing, + Err(err) => { gum::warn!( target: LOG_TARGET, - ?peer_id, - ?message_subject, - "Unknown approval assignment", + hash = ?block_hash, + validator_index = ?vote.validator, + candidate_bitfield = ?vote.candidate_indices, + ?err, + "Possible bug: Vote import failed", ); - // No rep change as this is caused by an issue + metrics.on_approval_bug(); return }, }; + // Invariant: to our knowledge, none of the peers except for the `source` know about the + // approval. + metrics.on_approval_imported(); + // Dispatch a ApprovalDistributionV1Message::Approval(vote) // to all peers required by the topology, with the exception of the source peer. let topology = self.topologies.get_topology(entry.session); let source_peer = source.peer_id(); - let message_subject = &message_subject; - let peer_filter = move |peer, knowledge: &PeerKnowledge| { + let peer_filter = move |peer| { if Some(peer) == source_peer.as_ref() { return false } @@ -1611,13 +1751,13 @@ impl State { // 3. Any randomly selected peers have been sent the assignment already. let in_topology = topology .map_or(false, |t| t.local_grid_neighbors().route_to_peer(required_routing, peer)); - in_topology || knowledge.sent.contains(message_subject, MessageKind::Assignment) + in_topology || peers_randomly_routed_to.contains(peer) }; let peers = entry .known_by .iter() - .filter(|(p, k)| peer_filter(p, k)) + .filter(|(p, _)| peer_filter(p)) .filter_map(|(p, _)| self.peer_views.get(p).map(|entry| (*p, entry.version))) .collect::>(); @@ -1625,7 +1765,7 @@ impl State { for peer in peers.iter() { // we already filtered peers above, so this should always be Some if let Some(entry) = entry.known_by.get_mut(&peer.0) { - entry.sent.insert(message_subject.clone(), message_kind); + entry.sent.insert(approval_knwowledge_key.0.clone(), approval_knwowledge_key.1); } } @@ -1634,7 +1774,6 @@ impl State { gum::trace!( target: LOG_TARGET, ?block_hash, - ?candidate_index, local = source.peer_id().is_none(), num_peers = peers.len(), "Sending an approval to peers", @@ -1647,7 +1786,7 @@ impl State { fn get_approval_signatures( &mut self, indices: HashSet<(Hash, CandidateIndex)>, - ) -> HashMap { + ) -> HashMap, ValidatorSignature)> { let mut all_sigs = HashMap::new(); for (hash, index) in indices { let _span = self @@ -1670,11 +1809,20 @@ impl State { Some(e) => e, }; - let sigs = block_entry - .approval_entries(index) - .into_iter() - .filter_map(|approval_entry| approval_entry.approval(index)) - .map(|approval| (approval.validator, approval.signature)); + let sigs = block_entry.approval_votes(index).into_iter().map(|approval| { + ( + approval.validator, + ( + hash, + approval + .candidate_indices + .iter_ones() + .map(|val| val as CandidateIndex) + .collect_vec(), + approval.signature, + ), + ) + }); all_sigs.extend(sigs); } all_sigs @@ -1718,23 +1866,31 @@ impl State { let peer_knowledge = entry.known_by.entry(peer_id).or_default(); let topology = topologies.get_topology(entry.session); - // We want to iterate the `approval_entries` of the block entry as these contain all - // assignments that also link all approval votes. + // We want to iterate the `approval_entries` of the block entry as these contain + // all assignments that also link all approval votes. for approval_entry in entry.approval_entries.values_mut() { // Propagate the message to all peers in the required routing set OR // randomly sample peers. { let required_routing = approval_entry.routing_info().required_routing; - let random_routing = &mut approval_entry.routing_info_mut().random_routing; + let routing_info = &mut approval_entry.routing_info_mut(); let rng = &mut *rng; let mut peer_filter = move |peer_id| { let in_topology = topology.as_ref().map_or(false, |t| { t.local_grid_neighbors().route_to_peer(required_routing, peer_id) }); in_topology || { - let route_random = random_routing.sample(total_peers, rng); + if !topology + .map(|topology| topology.is_validator(peer_id)) + .unwrap_or(false) + { + return false + } + + let route_random = + routing_info.random_routing.sample(total_peers, rng); if route_random { - random_routing.inc_sent(); + routing_info.mark_randomly_sent(*peer_id); } route_random @@ -1751,7 +1907,8 @@ impl State { let (assignment_knowledge, message_kind) = approval_entry.create_assignment_knowledge(block); - // Only send stuff a peer doesn't know in the context of a relay chain block. + // Only send stuff a peer doesn't know in the context of a relay chain + // block. if !peer_knowledge.contains(&assignment_knowledge, message_kind) { peer_knowledge.sent.insert(assignment_knowledge, message_kind); assignments_to_send.push(assignment_message); @@ -1759,12 +1916,12 @@ impl State { // Filter approval votes. for approval_message in approval_messages { - let (approval_knowledge, message_kind) = approval_entry - .create_approval_knowledge(block, approval_message.candidate_index); + let approval_knowledge = + PeerKnowledge::generate_approval_key(&approval_message); - if !peer_knowledge.contains(&approval_knowledge, message_kind) { - peer_knowledge.sent.insert(approval_knowledge, message_kind); + if !peer_knowledge.contains(&approval_knowledge.0, approval_knowledge.1) { approvals_to_send.push(approval_message); + peer_knowledge.sent.insert(approval_knowledge.0, approval_knowledge.1); } } } @@ -1937,6 +2094,7 @@ impl State { // Punish the peer for the invalid message. modify_reputation(&mut self.reputation, sender, peer_id, COST_OVERSIZED_BITFIELD) .await; + gum::error!(target: LOG_TARGET, block_hash = ?cert.block_hash, ?candidate_index, validator_index = ?cert.validator, kind = ?cert.cert.kind, "Bad assignment v1"); } else { sanitized_assignments.push((cert.into(), candidate_index.into())) } @@ -1979,6 +2137,9 @@ impl State { // Punish the peer for the invalid message. modify_reputation(&mut self.reputation, sender, peer_id, COST_OVERSIZED_BITFIELD) .await; + for candidate_index in candidate_bitfield.iter_ones() { + gum::error!(target: LOG_TARGET, block_hash = ?cert.block_hash, ?candidate_index, validator_index = ?cert.validator, "Bad assignment v2"); + } } else { sanitized_assignments.push((cert, candidate_bitfield)) } @@ -2066,11 +2227,10 @@ async fn adjust_required_routing_and_propagate { gum::debug!( target: LOG_TARGET, - "Distributing our approval vote on candidate (block={}, index={})", + "Distributing our approval vote on candidate (block={}, index={:?})", vote.block_hash, - vote.candidate_index, + vote.candidate_indices, ); state @@ -2296,7 +2456,7 @@ pub const MAX_ASSIGNMENT_BATCH_SIZE: usize = ensure_size_not_zero( /// The maximum amount of approvals per batch is 33% of maximum allowed by protocol. pub const MAX_APPROVAL_BATCH_SIZE: usize = ensure_size_not_zero( - MAX_NOTIFICATION_SIZE as usize / std::mem::size_of::() / 3, + MAX_NOTIFICATION_SIZE as usize / std::mem::size_of::() / 3, ); // Low level helper for sending assignments. @@ -2306,12 +2466,12 @@ async fn send_assignments_batched_inner( peers: Vec, peer_version: ValidationVersion, ) { - if peer_version == ValidationVersion::VStaging { + if peer_version == ValidationVersion::V3 { sender .send_message(NetworkBridgeTxMessage::SendValidationMessage( peers, - Versioned::VStaging(protocol_vstaging::ValidationProtocol::ApprovalDistribution( - protocol_vstaging::ApprovalDistributionMessage::Assignments( + Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( + protocol_v3::ApprovalDistributionMessage::Assignments( batch.into_iter().collect(), ), )), @@ -2362,7 +2522,7 @@ pub(crate) async fn send_assignments_batched( ) { let v1_peers = filter_by_peer_version(peers, ValidationVersion::V1.into()); let v2_peers = filter_by_peer_version(peers, ValidationVersion::V2.into()); - let vstaging_peers = filter_by_peer_version(peers, ValidationVersion::VStaging.into()); + let v3_peers = filter_by_peer_version(peers, ValidationVersion::V3.into()); // V1 and V2 validation protocol do not have any changes with regard to // ApprovalDistributionMessage so they can be treated the same. @@ -2400,18 +2560,13 @@ pub(crate) async fn send_assignments_batched( } } - if !vstaging_peers.is_empty() { - let mut vstaging = v2_assignments.into_iter().peekable(); + if !v3_peers.is_empty() { + let mut v3 = v2_assignments.into_iter().peekable(); - while vstaging.peek().is_some() { - let batch = vstaging.by_ref().take(MAX_ASSIGNMENT_BATCH_SIZE).collect::>(); - send_assignments_batched_inner( - sender, - batch, - vstaging_peers.clone(), - ValidationVersion::VStaging, - ) - .await; + while v3.peek().is_some() { + let batch = v3.by_ref().take(MAX_ASSIGNMENT_BATCH_SIZE).collect::>(); + send_assignments_batched_inner(sender, batch, v3_peers.clone(), ValidationVersion::V3) + .await; } } } @@ -2419,15 +2574,20 @@ pub(crate) async fn send_assignments_batched( /// Send approvals while honoring the `max_notification_size` of the protocol and peer version. pub(crate) async fn send_approvals_batched( sender: &mut impl overseer::ApprovalDistributionSenderTrait, - approvals: impl IntoIterator + Clone, + approvals: impl IntoIterator + Clone, peers: &[(PeerId, ProtocolVersion)], ) { let v1_peers = filter_by_peer_version(peers, ValidationVersion::V1.into()); let v2_peers = filter_by_peer_version(peers, ValidationVersion::V2.into()); - let vstaging_peers = filter_by_peer_version(peers, ValidationVersion::VStaging.into()); + let v3_peers = filter_by_peer_version(peers, ValidationVersion::V3.into()); if !v1_peers.is_empty() || !v2_peers.is_empty() { - let mut batches = approvals.clone().into_iter().peekable(); + let mut batches = approvals + .clone() + .into_iter() + .filter(|approval| approval.candidate_indices.count_ones() == 1) + .filter_map(|val| val.try_into().ok()) + .peekable(); while batches.peek().is_some() { let batch: Vec<_> = batches.by_ref().take(MAX_APPROVAL_BATCH_SIZE).collect(); @@ -2456,7 +2616,7 @@ pub(crate) async fn send_approvals_batched( } } - if !vstaging_peers.is_empty() { + if !v3_peers.is_empty() { let mut batches = approvals.into_iter().peekable(); while batches.peek().is_some() { @@ -2464,12 +2624,10 @@ pub(crate) async fn send_approvals_batched( sender .send_message(NetworkBridgeTxMessage::SendValidationMessage( - vstaging_peers.clone(), - Versioned::VStaging( - protocol_vstaging::ValidationProtocol::ApprovalDistribution( - protocol_vstaging::ApprovalDistributionMessage::Approvals(batch), - ), - ), + v3_peers.clone(), + Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( + protocol_v3::ApprovalDistributionMessage::Approvals(batch), + )), )) .await; } diff --git a/polkadot/node/network/approval-distribution/src/metrics.rs b/polkadot/node/network/approval-distribution/src/metrics.rs index 6864259e6fd..0642b1b2e0c 100644 --- a/polkadot/node/network/approval-distribution/src/metrics.rs +++ b/polkadot/node/network/approval-distribution/src/metrics.rs @@ -31,6 +31,8 @@ struct MetricsInner { time_unify_with_peer: prometheus::Histogram, time_import_pending_now_known: prometheus::Histogram, time_awaiting_approval_voting: prometheus::Histogram, + assignments_received_result: prometheus::CounterVec, + approvals_received_result: prometheus::CounterVec, } trait AsLabel { @@ -78,6 +80,132 @@ impl Metrics { .map(|metrics| metrics.time_import_pending_now_known.start_timer()) } + pub fn on_approval_already_known(&self) { + if let Some(metrics) = &self.0 { + metrics.approvals_received_result.with_label_values(&["known"]).inc() + } + } + + pub fn on_approval_entry_not_found(&self) { + if let Some(metrics) = &self.0 { + metrics.approvals_received_result.with_label_values(&["noapprovalentry"]).inc() + } + } + + pub fn on_approval_recent_outdated(&self) { + if let Some(metrics) = &self.0 { + metrics.approvals_received_result.with_label_values(&["outdated"]).inc() + } + } + + pub fn on_approval_invalid_block(&self) { + if let Some(metrics) = &self.0 { + metrics.approvals_received_result.with_label_values(&["invalidblock"]).inc() + } + } + + pub fn on_approval_unknown_assignment(&self) { + if let Some(metrics) = &self.0 { + metrics + .approvals_received_result + .with_label_values(&["unknownassignment"]) + .inc() + } + } + + pub fn on_approval_duplicate(&self) { + if let Some(metrics) = &self.0 { + metrics.approvals_received_result.with_label_values(&["duplicate"]).inc() + } + } + + pub fn on_approval_out_of_view(&self) { + if let Some(metrics) = &self.0 { + metrics.approvals_received_result.with_label_values(&["outofview"]).inc() + } + } + + pub fn on_approval_good_known(&self) { + if let Some(metrics) = &self.0 { + metrics.approvals_received_result.with_label_values(&["goodknown"]).inc() + } + } + + pub fn on_approval_bad(&self) { + if let Some(metrics) = &self.0 { + metrics.approvals_received_result.with_label_values(&["bad"]).inc() + } + } + + pub fn on_approval_unexpected(&self) { + if let Some(metrics) = &self.0 { + metrics.approvals_received_result.with_label_values(&["unexpected"]).inc() + } + } + + pub fn on_approval_bug(&self) { + if let Some(metrics) = &self.0 { + metrics.approvals_received_result.with_label_values(&["bug"]).inc() + } + } + + pub fn on_assignment_already_known(&self) { + if let Some(metrics) = &self.0 { + metrics.assignments_received_result.with_label_values(&["known"]).inc() + } + } + + pub fn on_assignment_recent_outdated(&self) { + if let Some(metrics) = &self.0 { + metrics.assignments_received_result.with_label_values(&["outdated"]).inc() + } + } + + pub fn on_assignment_invalid_block(&self) { + if let Some(metrics) = &self.0 { + metrics.assignments_received_result.with_label_values(&["invalidblock"]).inc() + } + } + + pub fn on_assignment_duplicate(&self) { + if let Some(metrics) = &self.0 { + metrics.assignments_received_result.with_label_values(&["duplicate"]).inc() + } + } + + pub fn on_assignment_out_of_view(&self) { + if let Some(metrics) = &self.0 { + metrics.assignments_received_result.with_label_values(&["outofview"]).inc() + } + } + + pub fn on_assignment_good_known(&self) { + if let Some(metrics) = &self.0 { + metrics.assignments_received_result.with_label_values(&["goodknown"]).inc() + } + } + + pub fn on_assignment_bad(&self) { + if let Some(metrics) = &self.0 { + metrics.assignments_received_result.with_label_values(&["bad"]).inc() + } + } + + pub fn on_assignment_duplicatevoting(&self) { + if let Some(metrics) = &self.0 { + metrics + .assignments_received_result + .with_label_values(&["duplicatevoting"]) + .inc() + } + } + + pub fn on_assignment_far(&self) { + if let Some(metrics) = &self.0 { + metrics.assignments_received_result.with_label_values(&["far"]).inc() + } + } + pub(crate) fn time_awaiting_approval_voting( &self, ) -> Option { @@ -167,6 +295,26 @@ impl MetricsTrait for Metrics { ).buckets(vec![0.0001, 0.0004, 0.0016, 0.0064, 0.0256, 0.1024, 0.4096, 1.6384, 3.2768, 4.9152, 6.5536,]))?, registry, )?, + assignments_received_result: prometheus::register( + prometheus::CounterVec::new( + prometheus::Opts::new( + "polkadot_parachain_assignments_received_result", + "Result of a processed assignement", + ), + &["status"] + )?, + registry, + )?, + approvals_received_result: prometheus::register( + prometheus::CounterVec::new( + prometheus::Opts::new( + "polkadot_parachain_approvals_received_result", + "Result of a processed approval", + ), + &["status"] + )?, + registry, + )?, }; Ok(Metrics(Some(metrics))) } diff --git a/polkadot/node/network/approval-distribution/src/tests.rs b/polkadot/node/network/approval-distribution/src/tests.rs index 4d272d7af0e..ad5d0bb0a9c 100644 --- a/polkadot/node/network/approval-distribution/src/tests.rs +++ b/polkadot/node/network/approval-distribution/src/tests.rs @@ -25,8 +25,8 @@ use polkadot_node_network_protocol::{ }; use polkadot_node_primitives::approval::{ v1::{ - AssignmentCert, AssignmentCertKind, IndirectAssignmentCert, VrfPreOutput, VrfProof, - VrfSignature, + AssignmentCert, AssignmentCertKind, IndirectAssignmentCert, IndirectSignedApprovalVote, + VrfPreOutput, VrfProof, VrfSignature, }, v2::{ AssignmentCertKindV2, AssignmentCertV2, CoreBitfield, IndirectAssignmentCertV2, @@ -133,14 +133,13 @@ fn make_gossip_topology( all_peers: &[(PeerId, AuthorityDiscoveryId)], neighbors_x: &[usize], neighbors_y: &[usize], + local_index: usize, ) -> network_bridge_event::NewGossipTopology { // This builds a grid topology which is a square matrix. // The local validator occupies the top left-hand corner. // The X peers occupy the same row and the Y peers occupy // the same column. - let local_index = 1; - assert_eq!( neighbors_x.len(), neighbors_y.len(), @@ -277,16 +276,16 @@ async fn send_message_from_peer_v2( .await; } -async fn send_message_from_peer_vstaging( +async fn send_message_from_peer_v3( virtual_overseer: &mut VirtualOverseer, peer_id: &PeerId, - msg: protocol_vstaging::ApprovalDistributionMessage, + msg: protocol_v3::ApprovalDistributionMessage, ) { overseer_send( virtual_overseer, ApprovalDistributionMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerMessage( *peer_id, - Versioned::VStaging(msg), + Versioned::V3(msg), )), ) .await; @@ -380,10 +379,11 @@ fn state_with_reputation_delay() -> State { /// the new peer sends us the same assignment #[test] fn try_import_the_same_assignment() { - let peer_a = PeerId::random(); - let peer_b = PeerId::random(); - let peer_c = PeerId::random(); - let peer_d = PeerId::random(); + let peers = make_peers_and_authority_ids(15); + let peer_a = peers.get(0).unwrap().0; + let peer_b = peers.get(1).unwrap().0; + let peer_c = peers.get(2).unwrap().0; + let peer_d = peers.get(4).unwrap().0; let parent_hash = Hash::repeat_byte(0xFF); let hash = Hash::repeat_byte(0xAA); @@ -394,6 +394,10 @@ fn try_import_the_same_assignment() { setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V1).await; setup_peer_with_view(overseer, &peer_c, view![hash], ValidationVersion::V1).await; + // Set up a gossip topology, where a, b, c and d are topology neighboors to the node under + // testing. + setup_gossip_topology(overseer, make_gossip_topology(1, &peers, &[0, 1], &[2, 4], 3)).await; + // new block `hash_a` with 1 candidates let meta = BlockApprovalMeta { hash, @@ -446,7 +450,7 @@ fn try_import_the_same_assignment() { ); // setup new peer with V2 - setup_peer_with_view(overseer, &peer_d, view![], ValidationVersion::VStaging).await; + setup_peer_with_view(overseer, &peer_d, view![], ValidationVersion::V3).await; // send the same assignment from peer_d let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments); @@ -464,19 +468,24 @@ fn try_import_the_same_assignment() { /// cores. #[test] fn try_import_the_same_assignment_v2() { - let peer_a = PeerId::random(); - let peer_b = PeerId::random(); - let peer_c = PeerId::random(); - let peer_d = PeerId::random(); + let peers = make_peers_and_authority_ids(15); + let peer_a = peers.get(0).unwrap().0; + let peer_b = peers.get(1).unwrap().0; + let peer_c = peers.get(2).unwrap().0; + let peer_d = peers.get(4).unwrap().0; let parent_hash = Hash::repeat_byte(0xFF); let hash = Hash::repeat_byte(0xAA); let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; // setup peers - setup_peer_with_view(overseer, &peer_a, view![], ValidationVersion::VStaging).await; - setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::VStaging).await; - setup_peer_with_view(overseer, &peer_c, view![hash], ValidationVersion::VStaging).await; + setup_peer_with_view(overseer, &peer_a, view![], ValidationVersion::V3).await; + setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V3).await; + setup_peer_with_view(overseer, &peer_c, view![hash], ValidationVersion::V3).await; + + // Set up a gossip topology, where a, b, c and d are topology neighboors to the node under + // testing. + setup_gossip_topology(overseer, make_gossip_topology(1, &peers, &[0, 1], &[2, 4], 3)).await; // new block `hash_a` with 1 candidates let meta = BlockApprovalMeta { @@ -503,8 +512,8 @@ fn try_import_the_same_assignment_v2() { let cert = fake_assignment_cert_v2(hash, validator_index, core_bitfield.clone()); let assignments = vec![(cert.clone(), cores.clone().try_into().unwrap())]; - let msg = protocol_vstaging::ApprovalDistributionMessage::Assignments(assignments.clone()); - send_message_from_peer_vstaging(overseer, &peer_a, msg).await; + let msg = protocol_v3::ApprovalDistributionMessage::Assignments(assignments.clone()); + send_message_from_peer_v3(overseer, &peer_a, msg).await; expect_reputation_change(overseer, &peer_a, COST_UNEXPECTED_MESSAGE).await; @@ -528,8 +537,8 @@ fn try_import_the_same_assignment_v2() { overseer_recv(overseer).await, AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( peers, - Versioned::VStaging(protocol_vstaging::ValidationProtocol::ApprovalDistribution( - protocol_vstaging::ApprovalDistributionMessage::Assignments(assignments) + Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( + protocol_v3::ApprovalDistributionMessage::Assignments(assignments) )) )) => { assert_eq!(peers.len(), 2); @@ -538,11 +547,11 @@ fn try_import_the_same_assignment_v2() { ); // setup new peer - setup_peer_with_view(overseer, &peer_d, view![], ValidationVersion::VStaging).await; + setup_peer_with_view(overseer, &peer_d, view![], ValidationVersion::V3).await; // send the same assignment from peer_d - let msg = protocol_vstaging::ApprovalDistributionMessage::Assignments(assignments); - send_message_from_peer_vstaging(overseer, &peer_d, msg).await; + let msg = protocol_v3::ApprovalDistributionMessage::Assignments(assignments); + send_message_from_peer_v3(overseer, &peer_d, msg).await; expect_reputation_change(overseer, &peer_d, COST_UNEXPECTED_MESSAGE).await; expect_reputation_change(overseer, &peer_d, BENEFIT_VALID_MESSAGE).await; @@ -705,14 +714,19 @@ fn spam_attack_results_in_negative_reputation_change() { #[test] fn peer_sending_us_the_same_we_just_sent_them_is_ok() { let parent_hash = Hash::repeat_byte(0xFF); - let peer_a = PeerId::random(); let hash = Hash::repeat_byte(0xAA); + let peers = make_peers_and_authority_ids(8); + let peer_a = peers.first().unwrap().0; + let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; let peer = &peer_a; setup_peer_with_view(overseer, peer, view![], ValidationVersion::V1).await; + // Setup a topology where peer_a is neigboor to current node. + setup_gossip_topology(overseer, make_gossip_topology(1, &peers, &[0], &[2], 1)).await; + // new block `hash` with 1 candidates let meta = BlockApprovalMeta { hash, @@ -780,10 +794,12 @@ fn peer_sending_us_the_same_we_just_sent_them_is_ok() { } #[test] -fn import_approval_happy_path() { - let peer_a = PeerId::random(); - let peer_b = PeerId::random(); - let peer_c = PeerId::random(); +fn import_approval_happy_path_v1_v2_peers() { + let peers = make_peers_and_authority_ids(15); + + let peer_a = peers.get(0).unwrap().0; + let peer_b = peers.get(1).unwrap().0; + let peer_c = peers.get(2).unwrap().0; let parent_hash = Hash::repeat_byte(0xFF); let hash = Hash::repeat_byte(0xAA); @@ -791,7 +807,7 @@ fn import_approval_happy_path() { let overseer = &mut virtual_overseer; // setup peers with V1 and V2 protocol versions setup_peer_with_view(overseer, &peer_a, view![], ValidationVersion::V1).await; - setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::VStaging).await; + setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V3).await; setup_peer_with_view(overseer, &peer_c, view![hash], ValidationVersion::V1).await; // new block `hash_a` with 1 candidates @@ -806,6 +822,9 @@ fn import_approval_happy_path() { let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); overseer_send(overseer, msg).await; + // Set up a gossip topology, where a, b, and c are topology neighboors to the node. + setup_gossip_topology(overseer, make_gossip_topology(1, &peers, &[0, 1], &[2, 4], 3)).await; + // import an assignment related to `hash` locally let validator_index = ValidatorIndex(0); let candidate_index = 0u32; @@ -838,8 +857,8 @@ fn import_approval_happy_path() { overseer_recv(overseer).await, AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( peers, - Versioned::VStaging(protocol_vstaging::ValidationProtocol::ApprovalDistribution( - protocol_vstaging::ApprovalDistributionMessage::Assignments(assignments) + Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( + protocol_v3::ApprovalDistributionMessage::Assignments(assignments) )) )) => { assert_eq!(peers.len(), 1); @@ -848,14 +867,15 @@ fn import_approval_happy_path() { ); // send the an approval from peer_b - let approval = IndirectSignedApprovalVote { + let approval = IndirectSignedApprovalVoteV2 { block_hash: hash, - candidate_index, + candidate_indices: candidate_index.into(), validator: validator_index, signature: dummy_signature(), }; - let msg = protocol_v1::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); - send_message_from_peer(overseer, &peer_b, msg).await; + let msg: protocol_v3::ApprovalDistributionMessage = + protocol_v3::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); + send_message_from_peer_v3(overseer, &peer_b, msg).await; assert_matches!( overseer_recv(overseer).await, @@ -886,6 +906,474 @@ fn import_approval_happy_path() { }); } +// Test a v2 approval that signs multiple candidate is correctly processed. +#[test] +fn import_approval_happy_path_v2() { + let peers = make_peers_and_authority_ids(15); + + let peer_a = peers.get(0).unwrap().0; + let peer_b = peers.get(1).unwrap().0; + let peer_c = peers.get(2).unwrap().0; + let parent_hash = Hash::repeat_byte(0xFF); + let hash = Hash::repeat_byte(0xAA); + + let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + // setup peers with V2 protocol versions + setup_peer_with_view(overseer, &peer_a, view![], ValidationVersion::V3).await; + setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V3).await; + setup_peer_with_view(overseer, &peer_c, view![hash], ValidationVersion::V3).await; + + // new block `hash_a` with 1 candidates + let meta = BlockApprovalMeta { + hash, + parent_hash, + number: 1, + candidates: vec![Default::default(); 2], + slot: 1.into(), + session: 1, + }; + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; + + // Set up a gossip topology, where a, b, and c are topology neighboors to the node. + setup_gossip_topology(overseer, make_gossip_topology(1, &peers, &[0, 1], &[2, 4], 3)).await; + + // import an assignment related to `hash` locally + let validator_index = ValidatorIndex(0); + let candidate_indices: CandidateBitfield = + vec![0 as CandidateIndex, 1 as CandidateIndex].try_into().unwrap(); + let candidate_bitfields = vec![CoreIndex(0), CoreIndex(1)].try_into().unwrap(); + let cert = fake_assignment_cert_v2(hash, validator_index, candidate_bitfields); + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeAssignment( + cert.clone().into(), + candidate_indices.clone(), + ), + ) + .await; + + // 1 peer is v2 + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( + protocol_v3::ApprovalDistributionMessage::Assignments(assignments) + )) + )) => { + assert_eq!(peers.len(), 2); + assert_eq!(assignments.len(), 1); + } + ); + + // send the an approval from peer_b + let approval = IndirectSignedApprovalVoteV2 { + block_hash: hash, + candidate_indices, + validator: validator_index, + signature: dummy_signature(), + }; + let msg = protocol_v3::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); + send_message_from_peer_v3(overseer, &peer_b, msg).await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportApproval( + vote, + tx, + )) => { + assert_eq!(vote, approval); + tx.send(ApprovalCheckResult::Accepted).unwrap(); + } + ); + + expect_reputation_change(overseer, &peer_b, BENEFIT_VALID_MESSAGE_FIRST).await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( + protocol_v3::ApprovalDistributionMessage::Approvals(approvals) + )) + )) => { + assert_eq!(peers.len(), 1); + assert_eq!(approvals.len(), 1); + } + ); + virtual_overseer + }); +} + +// Tests that votes that cover multiple assignments candidates are correctly processed on importing +#[test] +fn multiple_assignments_covered_with_one_approval_vote() { + let peers = make_peers_and_authority_ids(15); + + let peer_a = peers.get(0).unwrap().0; + let peer_b = peers.get(1).unwrap().0; + let peer_c = peers.get(2).unwrap().0; + let peer_d = peers.get(4).unwrap().0; + let parent_hash = Hash::repeat_byte(0xFF); + let hash = Hash::repeat_byte(0xAA); + + let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + // setup peers with V2 protocol versions + setup_peer_with_view(overseer, &peer_a, view![hash], ValidationVersion::V3).await; + setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V3).await; + setup_peer_with_view(overseer, &peer_c, view![hash], ValidationVersion::V3).await; + setup_peer_with_view(overseer, &peer_d, view![hash], ValidationVersion::V3).await; + + // new block `hash_a` with 1 candidates + let meta = BlockApprovalMeta { + hash, + parent_hash, + number: 1, + candidates: vec![Default::default(); 2], + slot: 1.into(), + session: 1, + }; + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; + + // Set up a gossip topology, where a, b, and c, d are topology neighboors to the node. + setup_gossip_topology(overseer, make_gossip_topology(1, &peers, &[0, 1], &[2, 4], 3)).await; + + // import an assignment related to `hash` locally + let validator_index = ValidatorIndex(2); // peer_c is the originator + let candidate_indices: CandidateBitfield = + vec![0 as CandidateIndex, 1 as CandidateIndex].try_into().unwrap(); + + let core_bitfields = vec![CoreIndex(0)].try_into().unwrap(); + let cert = fake_assignment_cert_v2(hash, validator_index, core_bitfields); + + // send the candidate 0 assignment from peer_b + let assignment = IndirectAssignmentCertV2 { + block_hash: hash, + validator: validator_index, + cert: cert.cert, + }; + let msg = protocol_v3::ApprovalDistributionMessage::Assignments(vec![( + assignment, + (0 as CandidateIndex).into(), + )]); + send_message_from_peer_v3(overseer, &peer_d, msg).await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( + _, _, + tx, + )) => { + tx.send(AssignmentCheckResult::Accepted).unwrap(); + } + ); + expect_reputation_change(overseer, &peer_d, BENEFIT_VALID_MESSAGE_FIRST).await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( + protocol_v3::ApprovalDistributionMessage::Assignments(assignments) + )) + )) => { + assert!(peers.len() >= 2); + assert!(peers.contains(&peer_a)); + assert!(peers.contains(&peer_b)); + assert_eq!(assignments.len(), 1); + } + ); + + let candidate_bitfields = vec![CoreIndex(1)].try_into().unwrap(); + let cert = fake_assignment_cert_v2(hash, validator_index, candidate_bitfields); + + // send the candidate 1 assignment from peer_c + let assignment = IndirectAssignmentCertV2 { + block_hash: hash, + validator: validator_index, + cert: cert.cert, + }; + let msg = protocol_v3::ApprovalDistributionMessage::Assignments(vec![( + assignment, + (1 as CandidateIndex).into(), + )]); + + send_message_from_peer_v3(overseer, &peer_c, msg).await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( + _, _, + tx, + )) => { + tx.send(AssignmentCheckResult::Accepted).unwrap(); + } + ); + expect_reputation_change(overseer, &peer_c, BENEFIT_VALID_MESSAGE_FIRST).await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( + protocol_v3::ApprovalDistributionMessage::Assignments(assignments) + )) + )) => { + assert!(peers.len() >= 2); + assert!(peers.contains(&peer_b)); + assert!(peers.contains(&peer_a)); + assert_eq!(assignments.len(), 1); + } + ); + + // send an approval from peer_b + let approval = IndirectSignedApprovalVoteV2 { + block_hash: hash, + candidate_indices, + validator: validator_index, + signature: dummy_signature(), + }; + let msg = protocol_v3::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); + send_message_from_peer_v3(overseer, &peer_d, msg).await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportApproval( + vote, + tx, + )) => { + assert_eq!(vote, approval); + tx.send(ApprovalCheckResult::Accepted).unwrap(); + } + ); + + expect_reputation_change(overseer, &peer_d, BENEFIT_VALID_MESSAGE_FIRST).await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( + protocol_v3::ApprovalDistributionMessage::Approvals(approvals) + )) + )) => { + assert!(peers.len() >= 2); + assert!(peers.contains(&peer_b)); + assert!(peers.contains(&peer_a)); + assert_eq!(approvals.len(), 1); + } + ); + for candidate_index in 0..1 { + let (tx_distribution, rx_distribution) = oneshot::channel(); + let mut candidates_requesting_signatures = HashSet::new(); + candidates_requesting_signatures.insert((hash, candidate_index)); + overseer_send( + overseer, + ApprovalDistributionMessage::GetApprovalSignatures( + candidates_requesting_signatures, + tx_distribution, + ), + ) + .await; + let signatures = rx_distribution.await.unwrap(); + + assert_eq!(signatures.len(), 1); + for (signing_validator, signature) in signatures { + assert_eq!(validator_index, signing_validator); + assert_eq!(signature.0, hash); + assert_eq!(signature.2, approval.signature); + assert_eq!(signature.1, vec![0, 1]); + } + } + virtual_overseer + }); +} + +// Tests that votes that cover multiple assignments candidates are correctly processed when unify +// with peer view +#[test] +fn unify_with_peer_multiple_assignments_covered_with_one_approval_vote() { + let peers = make_peers_and_authority_ids(15); + + let peer_a = peers.get(0).unwrap().0; + let peer_b = peers.get(1).unwrap().0; + let peer_d = peers.get(4).unwrap().0; + let parent_hash = Hash::repeat_byte(0xFF); + let hash = Hash::repeat_byte(0xAA); + + let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + setup_peer_with_view(overseer, &peer_d, view![hash], ValidationVersion::V3).await; + + // new block `hash_a` with 1 candidates + let meta = BlockApprovalMeta { + hash, + parent_hash, + number: 1, + candidates: vec![Default::default(); 2], + slot: 1.into(), + session: 1, + }; + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; + + // Set up a gossip topology, where a, b, and c, d are topology neighboors to the node. + setup_gossip_topology(overseer, make_gossip_topology(1, &peers, &[0, 1], &[2, 4], 3)).await; + + // import an assignment related to `hash` locally + let validator_index = ValidatorIndex(2); // peer_c is the originator + let candidate_indices: CandidateBitfield = + vec![0 as CandidateIndex, 1 as CandidateIndex].try_into().unwrap(); + + let core_bitfields = vec![CoreIndex(0)].try_into().unwrap(); + let cert = fake_assignment_cert_v2(hash, validator_index, core_bitfields); + + // send the candidate 0 assignment from peer_b + let assignment = IndirectAssignmentCertV2 { + block_hash: hash, + validator: validator_index, + cert: cert.cert, + }; + let msg = protocol_v3::ApprovalDistributionMessage::Assignments(vec![( + assignment, + (0 as CandidateIndex).into(), + )]); + send_message_from_peer_v3(overseer, &peer_d, msg).await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( + _, _, + tx, + )) => { + tx.send(AssignmentCheckResult::Accepted).unwrap(); + } + ); + expect_reputation_change(overseer, &peer_d, BENEFIT_VALID_MESSAGE_FIRST).await; + + let candidate_bitfields = vec![CoreIndex(1)].try_into().unwrap(); + let cert = fake_assignment_cert_v2(hash, validator_index, candidate_bitfields); + + // send the candidate 1 assignment from peer_c + let assignment = IndirectAssignmentCertV2 { + block_hash: hash, + validator: validator_index, + cert: cert.cert, + }; + let msg = protocol_v3::ApprovalDistributionMessage::Assignments(vec![( + assignment, + (1 as CandidateIndex).into(), + )]); + + send_message_from_peer_v3(overseer, &peer_d, msg).await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( + _, _, + tx, + )) => { + tx.send(AssignmentCheckResult::Accepted).unwrap(); + } + ); + expect_reputation_change(overseer, &peer_d, BENEFIT_VALID_MESSAGE_FIRST).await; + + // send an approval from peer_b + let approval = IndirectSignedApprovalVoteV2 { + block_hash: hash, + candidate_indices, + validator: validator_index, + signature: dummy_signature(), + }; + let msg = protocol_v3::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); + send_message_from_peer_v3(overseer, &peer_d, msg).await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportApproval( + vote, + tx, + )) => { + assert_eq!(vote, approval); + tx.send(ApprovalCheckResult::Accepted).unwrap(); + } + ); + + expect_reputation_change(overseer, &peer_d, BENEFIT_VALID_MESSAGE_FIRST).await; + + // setup peers with V2 protocol versions + setup_peer_with_view(overseer, &peer_a, view![hash], ValidationVersion::V3).await; + setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V3).await; + let mut expected_peers_assignments = vec![peer_a, peer_b]; + let mut expected_peers_approvals = vec![peer_a, peer_b]; + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( + protocol_v3::ApprovalDistributionMessage::Assignments(assignments) + )) + )) => { + assert!(peers.len() == 1); + assert!(expected_peers_assignments.contains(peers.first().unwrap())); + expected_peers_assignments.retain(|peer| peer != peers.first().unwrap()); + assert_eq!(assignments.len(), 2); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( + protocol_v3::ApprovalDistributionMessage::Approvals(approvals) + )) + )) => { + assert!(peers.len() == 1); + assert!(expected_peers_approvals.contains(peers.first().unwrap())); + expected_peers_approvals.retain(|peer| peer != peers.first().unwrap()); + assert_eq!(approvals.len(), 1); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( + protocol_v3::ApprovalDistributionMessage::Assignments(assignments) + )) + )) => { + assert!(peers.len() == 1); + assert!(expected_peers_assignments.contains(peers.first().unwrap())); + expected_peers_assignments.retain(|peer| peer != peers.first().unwrap()); + assert_eq!(assignments.len(), 2); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( + protocol_v3::ApprovalDistributionMessage::Approvals(approvals) + )) + )) => { + assert!(peers.len() == 1); + assert!(expected_peers_approvals.contains(peers.first().unwrap())); + expected_peers_approvals.retain(|peer| peer != peers.first().unwrap()); + assert_eq!(approvals.len(), 1); + } + ); + + virtual_overseer + }); +} + #[test] fn import_approval_bad() { let peer_a = PeerId::random(); @@ -916,14 +1404,14 @@ fn import_approval_bad() { let cert = fake_assignment_cert(hash, validator_index); // send the an approval from peer_b, we don't have an assignment yet - let approval = IndirectSignedApprovalVote { + let approval = IndirectSignedApprovalVoteV2 { block_hash: hash, - candidate_index, + candidate_indices: candidate_index.into(), validator: validator_index, signature: dummy_signature(), }; - let msg = protocol_v1::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); - send_message_from_peer(overseer, &peer_b, msg).await; + let msg = protocol_v3::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); + send_message_from_peer_v3(overseer, &peer_b, msg).await; expect_reputation_change(overseer, &peer_b, COST_UNEXPECTED_MESSAGE).await; @@ -948,8 +1436,8 @@ fn import_approval_bad() { expect_reputation_change(overseer, &peer_b, BENEFIT_VALID_MESSAGE_FIRST).await; // and try again - let msg = protocol_v1::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); - send_message_from_peer(overseer, &peer_b, msg).await; + let msg = protocol_v3::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); + send_message_from_peer_v3(overseer, &peer_b, msg).await; assert_matches!( overseer_recv(overseer).await, @@ -1048,7 +1536,8 @@ fn update_peer_view() { let hash_b = Hash::repeat_byte(0xBB); let hash_c = Hash::repeat_byte(0xCC); let hash_d = Hash::repeat_byte(0xDD); - let peer_a = PeerId::random(); + let peers = make_peers_and_authority_ids(8); + let peer_a = peers.first().unwrap().0; let peer = &peer_a; let state = test_harness(State::default(), |mut virtual_overseer| async move { @@ -1082,6 +1571,9 @@ fn update_peer_view() { let msg = ApprovalDistributionMessage::NewBlocks(vec![meta_a, meta_b, meta_c]); overseer_send(overseer, msg).await; + // Setup a topology where peer_a is neigboor to current node. + setup_gossip_topology(overseer, make_gossip_topology(1, &peers, &[0], &[2], 1)).await; + let cert_a = fake_assignment_cert(hash_a, ValidatorIndex(0)); let cert_b = fake_assignment_cert(hash_b, ValidatorIndex(0)); @@ -1264,14 +1756,14 @@ fn import_remotely_then_locally() { assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); // send the approval remotely - let approval = IndirectSignedApprovalVote { + let approval = IndirectSignedApprovalVoteV2 { block_hash: hash, - candidate_index, + candidate_indices: candidate_index.into(), validator: validator_index, signature: dummy_signature(), }; - let msg = protocol_v1::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); - send_message_from_peer(overseer, peer, msg).await; + let msg = protocol_v3::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); + send_message_from_peer_v3(overseer, peer, msg).await; assert_matches!( overseer_recv(overseer).await, @@ -1295,7 +1787,8 @@ fn import_remotely_then_locally() { #[test] fn sends_assignments_even_when_state_is_approved() { - let peer_a = PeerId::random(); + let peers = make_peers_and_authority_ids(8); + let peer_a = peers.first().unwrap().0; let parent_hash = Hash::repeat_byte(0xFF); let hash = Hash::repeat_byte(0xAA); let peer = &peer_a; @@ -1315,6 +1808,9 @@ fn sends_assignments_even_when_state_is_approved() { let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); overseer_send(overseer, msg).await; + // Setup a topology where peer_a is neigboor to current node. + setup_gossip_topology(overseer, make_gossip_topology(1, &peers, &[0], &[2], 1)).await; + let validator_index = ValidatorIndex(0); let candidate_index = 0u32; @@ -1336,8 +1832,11 @@ fn sends_assignments_even_when_state_is_approved() { ) .await; - overseer_send(overseer, ApprovalDistributionMessage::DistributeApproval(approval.clone())) - .await; + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeApproval(approval.clone().into()), + ) + .await; // connect the peer. setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await; @@ -1380,7 +1879,8 @@ fn sends_assignments_even_when_state_is_approved() { /// assignemnts. #[test] fn sends_assignments_even_when_state_is_approved_v2() { - let peer_a = PeerId::random(); + let peers = make_peers_and_authority_ids(8); + let peer_a = peers.first().unwrap().0; let parent_hash = Hash::repeat_byte(0xFF); let hash = Hash::repeat_byte(0xAA); let peer = &peer_a; @@ -1400,6 +1900,9 @@ fn sends_assignments_even_when_state_is_approved_v2() { let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); overseer_send(overseer, msg).await; + // Setup a topology where peer_a is neigboor to current node. + setup_gossip_topology(overseer, make_gossip_topology(1, &peers, &[0], &[2], 1)).await; + let validator_index = ValidatorIndex(0); let cores = vec![0, 1, 2, 3]; let candidate_bitfield: CandidateBitfield = cores.clone().try_into().unwrap(); @@ -1416,9 +1919,9 @@ fn sends_assignments_even_when_state_is_approved_v2() { // Assumes candidate index == core index. let approvals = cores .iter() - .map(|core| IndirectSignedApprovalVote { + .map(|core| IndirectSignedApprovalVoteV2 { block_hash: hash, - candidate_index: *core, + candidate_indices: (*core).into(), validator: validator_index, signature: dummy_signature(), }) @@ -1442,7 +1945,7 @@ fn sends_assignments_even_when_state_is_approved_v2() { } // connect the peer. - setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::VStaging).await; + setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V3).await; let assignments = vec![(cert.clone(), candidate_bitfield.clone())]; @@ -1450,8 +1953,8 @@ fn sends_assignments_even_when_state_is_approved_v2() { overseer_recv(overseer).await, AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( peers, - Versioned::VStaging(protocol_vstaging::ValidationProtocol::ApprovalDistribution( - protocol_vstaging::ApprovalDistributionMessage::Assignments(sent_assignments) + Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( + protocol_v3::ApprovalDistributionMessage::Assignments(sent_assignments) )) )) => { assert_eq!(peers, vec![*peer]); @@ -1463,14 +1966,14 @@ fn sends_assignments_even_when_state_is_approved_v2() { overseer_recv(overseer).await, AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( peers, - Versioned::VStaging(protocol_vstaging::ValidationProtocol::ApprovalDistribution( - protocol_vstaging::ApprovalDistributionMessage::Approvals(sent_approvals) + Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( + protocol_v3::ApprovalDistributionMessage::Approvals(sent_approvals) )) )) => { // Construct a hashmaps of approvals for comparison. Approval distribution reorders messages because they are kept in a // hashmap as well. - let sent_approvals = sent_approvals.into_iter().map(|approval| (approval.candidate_index, approval)).collect::>(); - let approvals = approvals.into_iter().map(|approval| (approval.candidate_index, approval)).collect::>(); + let sent_approvals = sent_approvals.into_iter().map(|approval| (approval.candidate_indices.clone(), approval)).collect::>(); + let approvals = approvals.into_iter().map(|approval| (approval.candidate_indices.clone(), approval)).collect::>(); assert_eq!(peers, vec![*peer]); assert_eq!(sent_approvals, approvals); @@ -1580,13 +2083,19 @@ fn propagates_locally_generated_assignment_to_both_dimensions() { // Set up a gossip topology. setup_gossip_topology( overseer, - make_gossip_topology(1, &peers, &[0, 10, 20, 30], &[50, 51, 52, 53]), + make_gossip_topology( + 1, + &peers, + &[0, 10, 20, 30, 40, 60, 70, 80], + &[50, 51, 52, 53, 54, 55, 56, 57], + 1, + ), ) .await; let expected_indices = [ // Both dimensions in the gossip topology - 0, 10, 20, 30, 50, 51, 52, 53, + 0, 10, 20, 30, 40, 60, 70, 80, 50, 51, 52, 53, 54, 55, 56, 57, ]; // new block `hash_a` with 1 candidates @@ -1623,8 +2132,11 @@ fn propagates_locally_generated_assignment_to_both_dimensions() { ) .await; - overseer_send(overseer, ApprovalDistributionMessage::DistributeApproval(approval.clone())) - .await; + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeApproval(approval.clone().into()), + ) + .await; let assignments = vec![(cert.clone(), candidate_index)]; let approvals = vec![approval.clone()]; @@ -1688,7 +2200,7 @@ fn propagates_assignments_along_unshared_dimension() { // Set up a gossip topology. setup_gossip_topology( overseer, - make_gossip_topology(1, &peers, &[0, 10, 20, 30], &[50, 51, 52, 53]), + make_gossip_topology(1, &peers, &[0, 10, 20, 30], &[50, 51, 52, 53], 1), ) .await; @@ -1831,13 +2343,19 @@ fn propagates_to_required_after_connect() { // Set up a gossip topology. setup_gossip_topology( overseer, - make_gossip_topology(1, &peers, &[0, 10, 20, 30], &[50, 51, 52, 53]), + make_gossip_topology( + 1, + &peers, + &[0, 10, 20, 30, 40, 60, 70, 80], + &[50, 51, 52, 53, 54, 55, 56, 57], + 1, + ), ) .await; let expected_indices = [ // Both dimensions in the gossip topology, minus omitted. - 20, 30, 52, 53, + 20, 30, 40, 60, 70, 80, 52, 53, 54, 55, 56, 57, ]; // new block `hash_a` with 1 candidates @@ -1874,8 +2392,11 @@ fn propagates_to_required_after_connect() { ) .await; - overseer_send(overseer, ApprovalDistributionMessage::DistributeApproval(approval.clone())) - .await; + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeApproval(approval.clone().into()), + ) + .await; let assignments = vec![(cert.clone(), candidate_index)]; let approvals = vec![approval.clone()]; @@ -2002,53 +2523,21 @@ fn sends_to_more_peers_after_getting_topology() { ) .await; - overseer_send(overseer, ApprovalDistributionMessage::DistributeApproval(approval.clone())) - .await; + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeApproval(approval.clone().into()), + ) + .await; let assignments = vec![(cert.clone(), candidate_index)]; let approvals = vec![approval.clone()]; - let mut expected_indices = vec![0, 10, 20, 30, 50, 51, 52, 53]; - let assignment_sent_peers = assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - sent_peers, - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Assignments(sent_assignments) - )) - )) => { - // Only sends to random peers. - assert_eq!(sent_peers.len(), 4); - for peer in &sent_peers { - let i = peers.iter().position(|p| peer == &p.0).unwrap(); - // Random gossip before topology can send to topology-targeted peers. - // Remove them from the expected indices so we don't expect - // them to get the messages again after the assignment. - expected_indices.retain(|&i2| i2 != i); - } - assert_eq!(sent_assignments, assignments); - sent_peers - } - ); - - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - sent_peers, - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Approvals(sent_approvals) - )) - )) => { - // Random sampling is reused from the assignment. - assert_eq!(sent_peers, assignment_sent_peers); - assert_eq!(sent_approvals, approvals); - } - ); + let expected_indices = vec![0, 10, 20, 30, 50, 51, 52, 53]; // Set up a gossip topology. setup_gossip_topology( overseer, - make_gossip_topology(1, &peers, &[0, 10, 20, 30], &[50, 51, 52, 53]), + make_gossip_topology(1, &peers, &[0, 10, 20, 30], &[50, 51, 52, 53], 1), ) .await; @@ -2151,7 +2640,7 @@ fn originator_aggression_l1() { // Set up a gossip topology. setup_gossip_topology( overseer, - make_gossip_topology(1, &peers, &[0, 10, 20, 30], &[50, 51, 52, 53]), + make_gossip_topology(1, &peers, &[0, 10, 20, 30], &[50, 51, 52, 53], 1), ) .await; @@ -2164,8 +2653,11 @@ fn originator_aggression_l1() { ) .await; - overseer_send(overseer, ApprovalDistributionMessage::DistributeApproval(approval.clone())) - .await; + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeApproval(approval.clone().into()), + ) + .await; let assignments = vec![(cert.clone(), candidate_index)]; let approvals = vec![approval.clone()]; @@ -2307,7 +2799,7 @@ fn non_originator_aggression_l1() { // Set up a gossip topology. setup_gossip_topology( overseer, - make_gossip_topology(1, &peers, &[0, 10, 20, 30], &[50, 51, 52, 53]), + make_gossip_topology(1, &peers, &[0, 10, 20, 30], &[50, 51, 52, 53], 1), ) .await; @@ -2412,7 +2904,7 @@ fn non_originator_aggression_l2() { // Set up a gossip topology. setup_gossip_topology( overseer, - make_gossip_topology(1, &peers, &[0, 10, 20, 30], &[50, 51, 52, 53]), + make_gossip_topology(1, &peers, &[0, 10, 20, 30], &[50, 51, 52, 53], 1), ) .await; @@ -2558,7 +3050,7 @@ fn resends_messages_periodically() { // Set up a gossip topology. setup_gossip_topology( overseer, - make_gossip_topology(1, &peers, &[0, 10, 20, 30], &[50, 51, 52, 53]), + make_gossip_topology(1, &peers, &[0, 10, 20, 30], &[50, 51, 52, 53], 1), ) .await; @@ -2681,12 +3173,13 @@ fn resends_messages_periodically() { /// Tests that peers correctly receive versioned messages. #[test] fn import_versioned_approval() { - let peer_a = PeerId::random(); - let peer_b = PeerId::random(); - let peer_c = PeerId::random(); + let peers = make_peers_and_authority_ids(15); + let peer_a = peers.get(0).unwrap().0; + let peer_b = peers.get(1).unwrap().0; + let peer_c = peers.get(2).unwrap().0; + let parent_hash = Hash::repeat_byte(0xFF); let hash = Hash::repeat_byte(0xAA); - let state = state_without_reputation_delay(); let _ = test_harness(state, |mut virtual_overseer| async move { let overseer = &mut virtual_overseer; @@ -2695,6 +3188,10 @@ fn import_versioned_approval() { setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V1).await; setup_peer_with_view(overseer, &peer_c, view![hash], ValidationVersion::V2).await; + // Set up a gossip topology, where a, b, c and d are topology neighboors to the node under + // testing. + setup_gossip_topology(overseer, make_gossip_topology(1, &peers, &[0, 1], &[2, 4], 3)).await; + // new block `hash_a` with 1 candidates let meta = BlockApprovalMeta { hash, @@ -2762,7 +3259,7 @@ fn import_versioned_approval() { vote, tx, )) => { - assert_eq!(vote, approval); + assert_eq!(vote, approval.into()); tx.send(ApprovalCheckResult::Accepted).unwrap(); } ); @@ -2782,6 +3279,7 @@ fn import_versioned_approval() { assert_eq!(approvals.len(), 1); } ); + assert_matches!( overseer_recv(overseer).await, AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( @@ -2821,9 +3319,9 @@ fn batch_test_round(message_count: usize) { .collect(); let approvals: Vec<_> = validators - .map(|index| IndirectSignedApprovalVote { + .map(|index| IndirectSignedApprovalVoteV2 { block_hash: Hash::zero(), - candidate_index: 0, + candidate_indices: 0u32.into(), validator: ValidatorIndex(index as u32), signature: dummy_signature(), }) @@ -2890,7 +3388,7 @@ fn batch_test_round(message_count: usize) { assert_eq!(peers.len(), 1); for (message_index, approval) in sent_approvals.iter().enumerate() { - assert_eq!(approval, &approvals[approval_index + message_index]); + assert_eq!(approval, &approvals[approval_index + message_index].clone().try_into().unwrap()); } } ); diff --git a/polkadot/node/network/bitfield-distribution/src/lib.rs b/polkadot/node/network/bitfield-distribution/src/lib.rs index 9cc79aee849..76baf499cad 100644 --- a/polkadot/node/network/bitfield-distribution/src/lib.rs +++ b/polkadot/node/network/bitfield-distribution/src/lib.rs @@ -32,7 +32,7 @@ use polkadot_node_network_protocol::{ GridNeighbors, RandomRouting, RequiredRouting, SessionBoundGridTopologyStorage, }, peer_set::{ProtocolVersion, ValidationVersion}, - v1 as protocol_v1, v2 as protocol_v2, vstaging as protocol_vstaging, OurView, PeerId, + v1 as protocol_v1, v2 as protocol_v2, v3 as protocol_v3, OurView, PeerId, UnifiedReputationChange as Rep, Versioned, View, }; use polkadot_node_subsystem::{ @@ -102,8 +102,8 @@ impl BitfieldGossipMessage { self.relay_parent, self.signed_availability.into(), )), - Some(ValidationVersion::VStaging) => - Versioned::VStaging(protocol_vstaging::BitfieldDistributionMessage::Bitfield( + Some(ValidationVersion::V3) => + Versioned::V3(protocol_v3::BitfieldDistributionMessage::Bitfield( self.relay_parent, self.signed_availability.into(), )), @@ -503,8 +503,8 @@ async fn relay_message( let v2_interested_peers = filter_by_peer_version(&interested_peers, ValidationVersion::V2.into()); - let vstaging_interested_peers = - filter_by_peer_version(&interested_peers, ValidationVersion::VStaging.into()); + let v3_interested_peers = + filter_by_peer_version(&interested_peers, ValidationVersion::V3.into()); if !v1_interested_peers.is_empty() { ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( @@ -522,10 +522,10 @@ async fn relay_message( .await } - if !vstaging_interested_peers.is_empty() { + if !v3_interested_peers.is_empty() { ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( - vstaging_interested_peers, - message.into_validation_protocol(ValidationVersion::VStaging.into()), + v3_interested_peers, + message.into_validation_protocol(ValidationVersion::V3.into()), )) .await } @@ -551,7 +551,7 @@ async fn process_incoming_peer_message( relay_parent, bitfield, )) | - Versioned::VStaging(protocol_vstaging::BitfieldDistributionMessage::Bitfield( + Versioned::V3(protocol_v3::BitfieldDistributionMessage::Bitfield( relay_parent, bitfield, )) => (relay_parent, bitfield), diff --git a/polkadot/node/network/bridge/src/network.rs b/polkadot/node/network/bridge/src/network.rs index a9339a5c443..2fcf5cec489 100644 --- a/polkadot/node/network/bridge/src/network.rs +++ b/polkadot/node/network/bridge/src/network.rs @@ -33,7 +33,7 @@ use sc_network::{ use polkadot_node_network_protocol::{ peer_set::{CollationVersion, PeerSet, ProtocolVersion, ValidationVersion}, request_response::{OutgoingRequest, Recipient, ReqProtocolNames, Requests}, - v1 as protocol_v1, v2 as protocol_v2, vstaging as protocol_vstaging, PeerId, + v1 as protocol_v1, v2 as protocol_v2, v3 as protocol_v3, PeerId, }; use polkadot_primitives::{AuthorityDiscoveryId, Block, Hash}; @@ -62,20 +62,20 @@ pub(crate) fn send_validation_message_v1( ); } -// Helper function to send a validation vstaging message to a list of peers. +// Helper function to send a validation v3 message to a list of peers. // Messages are always sent via the main protocol, even legacy protocol messages. -pub(crate) fn send_validation_message_vstaging( +pub(crate) fn send_validation_message_v3( peers: Vec, - message: WireMessage, + message: WireMessage, metrics: &Metrics, notification_sinks: &Arc>>>, ) { - gum::trace!(target: LOG_TARGET, ?peers, ?message, "Sending validation vstaging message to peers",); + gum::trace!(target: LOG_TARGET, ?peers, ?message, "Sending validation v3 message to peers",); send_message( peers, PeerSet::Validation, - ValidationVersion::VStaging.into(), + ValidationVersion::V3.into(), message, metrics, notification_sinks, diff --git a/polkadot/node/network/bridge/src/rx/mod.rs b/polkadot/node/network/bridge/src/rx/mod.rs index 40cd167a968..49d81aea76a 100644 --- a/polkadot/node/network/bridge/src/rx/mod.rs +++ b/polkadot/node/network/bridge/src/rx/mod.rs @@ -37,8 +37,8 @@ use polkadot_node_network_protocol::{ CollationVersion, PeerSet, PeerSetProtocolNames, PerPeerSet, ProtocolVersion, ValidationVersion, }, - v1 as protocol_v1, v2 as protocol_v2, vstaging as protocol_vstaging, ObservedRole, OurView, - PeerId, UnifiedReputationChange as Rep, View, + v1 as protocol_v1, v2 as protocol_v2, v3 as protocol_v3, ObservedRole, OurView, PeerId, + UnifiedReputationChange as Rep, View, }; use polkadot_node_subsystem::{ @@ -70,7 +70,7 @@ use super::validator_discovery; /// Defines the `Network` trait with an implementation for an `Arc`. use crate::network::{ send_collation_message_v1, send_collation_message_v2, send_validation_message_v1, - send_validation_message_v2, send_validation_message_vstaging, Network, + send_validation_message_v2, send_validation_message_v3, Network, }; use crate::{network::get_peer_id_by_authority_id, WireMessage}; @@ -294,9 +294,9 @@ async fn handle_validation_message( metrics, notification_sinks, ), - ValidationVersion::VStaging => send_validation_message_vstaging( + ValidationVersion::V3 => send_validation_message_v3( vec![peer], - WireMessage::::ViewUpdate(local_view), + WireMessage::::ViewUpdate(local_view), metrics, notification_sinks, ), @@ -360,48 +360,47 @@ async fn handle_validation_message( ?peer, ); - let (events, reports) = - if expected_versions[PeerSet::Validation] == Some(ValidationVersion::V1.into()) { - handle_peer_messages::( - peer, - PeerSet::Validation, - &mut shared.0.lock().validation_peers, - vec![notification.into()], - metrics, - ) - } else if expected_versions[PeerSet::Validation] == - Some(ValidationVersion::V2.into()) - { - handle_peer_messages::( - peer, - PeerSet::Validation, - &mut shared.0.lock().validation_peers, - vec![notification.into()], - metrics, - ) - } else if expected_versions[PeerSet::Validation] == - Some(ValidationVersion::VStaging.into()) - { - handle_peer_messages::( - peer, - PeerSet::Validation, - &mut shared.0.lock().validation_peers, - vec![notification.into()], - metrics, - ) - } else { - gum::warn!( - target: LOG_TARGET, - version = ?expected_versions[PeerSet::Validation], - "Major logic bug. Peer somehow has unsupported validation protocol version." - ); + let (events, reports) = if expected_versions[PeerSet::Validation] == + Some(ValidationVersion::V1.into()) + { + handle_peer_messages::( + peer, + PeerSet::Validation, + &mut shared.0.lock().validation_peers, + vec![notification.into()], + metrics, + ) + } else if expected_versions[PeerSet::Validation] == Some(ValidationVersion::V2.into()) { + handle_peer_messages::( + peer, + PeerSet::Validation, + &mut shared.0.lock().validation_peers, + vec![notification.into()], + metrics, + ) + } else if expected_versions[PeerSet::Validation] == Some(ValidationVersion::V3.into()) { + handle_peer_messages::( + peer, + PeerSet::Validation, + &mut shared.0.lock().validation_peers, + vec![notification.into()], + metrics, + ) + } else { + gum::warn!( + target: LOG_TARGET, + version = ?expected_versions[PeerSet::Validation], + "Major logic bug. Peer somehow has unsupported validation protocol version." + ); - never!("Only versions 1 and 2 are supported; peer set connection checked above; qed"); + never!( + "Only versions 1 and 2 are supported; peer set connection checked above; qed" + ); - // If a peer somehow triggers this, we'll disconnect them - // eventually. - (Vec::new(), vec![UNCONNECTED_PEERSET_COST]) - }; + // If a peer somehow triggers this, we'll disconnect them + // eventually. + (Vec::new(), vec![UNCONNECTED_PEERSET_COST]) + }; for report in reports { network_service.report_peer(peer, report.into()); @@ -980,8 +979,8 @@ fn update_our_view( filter_by_peer_version(&validation_peers, ValidationVersion::V2.into()); let v2_collation_peers = filter_by_peer_version(&collation_peers, CollationVersion::V2.into()); - let vstaging_validation_peers = - filter_by_peer_version(&validation_peers, ValidationVersion::VStaging.into()); + let v3_validation_peers = + filter_by_peer_version(&validation_peers, ValidationVersion::V3.into()); send_validation_message_v1( v1_validation_peers, @@ -1011,8 +1010,8 @@ fn update_our_view( notification_sinks, ); - send_validation_message_vstaging( - vstaging_validation_peers, + send_validation_message_v3( + v3_validation_peers, WireMessage::ViewUpdate(new_view.clone()), metrics, notification_sinks, diff --git a/polkadot/node/network/bridge/src/rx/tests.rs b/polkadot/node/network/bridge/src/rx/tests.rs index e0b86feb644..6847b8a7e24 100644 --- a/polkadot/node/network/bridge/src/rx/tests.rs +++ b/polkadot/node/network/bridge/src/rx/tests.rs @@ -224,7 +224,7 @@ impl TestNetworkHandle { PeerSet::Validation => Some(ProtocolName::from("/polkadot/validation/1")), PeerSet::Collation => Some(ProtocolName::from("/polkadot/collation/1")), }, - ValidationVersion::VStaging => match peer_set { + ValidationVersion::V3 => match peer_set { PeerSet::Validation => Some(ProtocolName::from("/polkadot/validation/3")), PeerSet::Collation => unreachable!(), }, @@ -1433,8 +1433,8 @@ fn network_protocol_versioning_view_update() { ValidationVersion::V2 => WireMessage::::ViewUpdate(view.clone()) .encode(), - ValidationVersion::VStaging => - WireMessage::::ViewUpdate(view.clone()) + ValidationVersion::V3 => + WireMessage::::ViewUpdate(view.clone()) .encode(), }; assert_network_actions_contains( @@ -1469,7 +1469,7 @@ fn network_protocol_versioning_subsystem_msg() { NetworkBridgeEvent::PeerConnected( peer, ObservedRole::Full, - ValidationVersion::V2.into(), + ValidationVersion::V3.into(), None, ), &mut virtual_overseer, @@ -1484,9 +1484,9 @@ fn network_protocol_versioning_subsystem_msg() { } let approval_distribution_message = - protocol_v2::ApprovalDistributionMessage::Approvals(Vec::new()); + protocol_v3::ApprovalDistributionMessage::Approvals(Vec::new()); - let msg = protocol_v2::ValidationProtocol::ApprovalDistribution( + let msg = protocol_v3::ValidationProtocol::ApprovalDistribution( approval_distribution_message.clone(), ); @@ -1502,7 +1502,7 @@ fn network_protocol_versioning_subsystem_msg() { virtual_overseer.recv().await, AllMessages::ApprovalDistribution( ApprovalDistributionMessage::NetworkBridgeUpdate( - NetworkBridgeEvent::PeerMessage(p, Versioned::V2(m)) + NetworkBridgeEvent::PeerMessage(p, Versioned::V3(m)) ) ) => { assert_eq!(p, peer); @@ -1536,7 +1536,7 @@ fn network_protocol_versioning_subsystem_msg() { virtual_overseer.recv().await, AllMessages::StatementDistribution( StatementDistributionMessage::NetworkBridgeUpdate( - NetworkBridgeEvent::PeerMessage(p, Versioned::V2(m)) + NetworkBridgeEvent::PeerMessage(p, Versioned::V3(m)) ) ) => { assert_eq!(p, peer); diff --git a/polkadot/node/network/bridge/src/tx/mod.rs b/polkadot/node/network/bridge/src/tx/mod.rs index bdcd1574e33..22802608e1d 100644 --- a/polkadot/node/network/bridge/src/tx/mod.rs +++ b/polkadot/node/network/bridge/src/tx/mod.rs @@ -41,7 +41,7 @@ use crate::validator_discovery; /// Defines the `Network` trait with an implementation for an `Arc`. use crate::network::{ send_collation_message_v1, send_collation_message_v2, send_validation_message_v1, - send_validation_message_v2, send_validation_message_vstaging, Network, + send_validation_message_v2, send_validation_message_v3, Network, }; use crate::metrics::Metrics; @@ -205,7 +205,7 @@ where &metrics, notification_sinks, ), - Versioned::VStaging(msg) => send_validation_message_vstaging( + Versioned::V3(msg) => send_validation_message_v3( peers, WireMessage::ProtocolMessage(msg), &metrics, @@ -235,7 +235,7 @@ where &metrics, notification_sinks, ), - Versioned::VStaging(msg) => send_validation_message_vstaging( + Versioned::V3(msg) => send_validation_message_v3( peers, WireMessage::ProtocolMessage(msg), &metrics, @@ -264,7 +264,7 @@ where &metrics, notification_sinks, ), - Versioned::V2(msg) | Versioned::VStaging(msg) => send_collation_message_v2( + Versioned::V2(msg) | Versioned::V3(msg) => send_collation_message_v2( peers, WireMessage::ProtocolMessage(msg), &metrics, @@ -287,7 +287,7 @@ where &metrics, notification_sinks, ), - Versioned::V2(msg) | Versioned::VStaging(msg) => send_collation_message_v2( + Versioned::V2(msg) | Versioned::V3(msg) => send_collation_message_v2( peers, WireMessage::ProtocolMessage(msg), &metrics, diff --git a/polkadot/node/network/collator-protocol/src/collator_side/mod.rs b/polkadot/node/network/collator-protocol/src/collator_side/mod.rs index b3a396e1be3..8fb0bb21544 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/mod.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/mod.rs @@ -882,7 +882,7 @@ async fn handle_incoming_peer_message( match msg { Versioned::V1(V1::Declare(..)) | Versioned::V2(V2::Declare(..)) | - Versioned::VStaging(V2::Declare(..)) => { + Versioned::V3(V2::Declare(..)) => { gum::trace!( target: LOG_TARGET, ?origin, @@ -895,7 +895,7 @@ async fn handle_incoming_peer_message( }, Versioned::V1(V1::AdvertiseCollation(_)) | Versioned::V2(V2::AdvertiseCollation { .. }) | - Versioned::VStaging(V2::AdvertiseCollation { .. }) => { + Versioned::V3(V2::AdvertiseCollation { .. }) => { gum::trace!( target: LOG_TARGET, ?origin, @@ -911,7 +911,7 @@ async fn handle_incoming_peer_message( }, Versioned::V1(V1::CollationSeconded(relay_parent, statement)) | Versioned::V2(V2::CollationSeconded(relay_parent, statement)) | - Versioned::VStaging(V2::CollationSeconded(relay_parent, statement)) => { + Versioned::V3(V2::CollationSeconded(relay_parent, statement)) => { if !matches!(statement.unchecked_payload(), Statement::Seconded(_)) { gum::warn!( target: LOG_TARGET, diff --git a/polkadot/node/network/collator-protocol/src/validator_side/mod.rs b/polkadot/node/network/collator-protocol/src/validator_side/mod.rs index 20b3b9ea1d2..48ad3c711a6 100644 --- a/polkadot/node/network/collator-protocol/src/validator_side/mod.rs +++ b/polkadot/node/network/collator-protocol/src/validator_side/mod.rs @@ -777,7 +777,7 @@ async fn process_incoming_peer_message( match msg { Versioned::V1(V1::Declare(collator_id, para_id, signature)) | Versioned::V2(V2::Declare(collator_id, para_id, signature)) | - Versioned::VStaging(V2::Declare(collator_id, para_id, signature)) => { + Versioned::V3(V2::Declare(collator_id, para_id, signature)) => { if collator_peer_id(&state.peer_data, &collator_id).is_some() { modify_reputation( &mut state.reputation, @@ -894,7 +894,7 @@ async fn process_incoming_peer_message( candidate_hash, parent_head_data_hash, }) | - Versioned::VStaging(V2::AdvertiseCollation { + Versioned::V3(V2::AdvertiseCollation { relay_parent, candidate_hash, parent_head_data_hash, @@ -923,7 +923,7 @@ async fn process_incoming_peer_message( }, Versioned::V1(V1::CollationSeconded(..)) | Versioned::V2(V2::CollationSeconded(..)) | - Versioned::VStaging(V2::CollationSeconded(..)) => { + Versioned::V3(V2::CollationSeconded(..)) => { gum::warn!( target: LOG_TARGET, peer_id = ?origin, diff --git a/polkadot/node/network/gossip-support/src/lib.rs b/polkadot/node/network/gossip-support/src/lib.rs index 0d1b04f2ba2..22417795d5e 100644 --- a/polkadot/node/network/gossip-support/src/lib.rs +++ b/polkadot/node/network/gossip-support/src/lib.rs @@ -477,7 +477,7 @@ where match message { Versioned::V1(m) => match m {}, Versioned::V2(m) => match m {}, - Versioned::VStaging(m) => match m {}, + Versioned::V3(m) => match m {}, } }, } diff --git a/polkadot/node/network/protocol/Cargo.toml b/polkadot/node/network/protocol/Cargo.toml index c33b9eae325..379334ded24 100644 --- a/polkadot/node/network/protocol/Cargo.toml +++ b/polkadot/node/network/protocol/Cargo.toml @@ -27,6 +27,3 @@ bitvec = "1" [dev-dependencies] rand_chacha = "0.3.1" - -[features] -network-protocol-staging = [] diff --git a/polkadot/node/network/protocol/src/grid_topology.rs b/polkadot/node/network/protocol/src/grid_topology.rs index 99dd513c4d7..8bd9adbc17c 100644 --- a/polkadot/node/network/protocol/src/grid_topology.rs +++ b/polkadot/node/network/protocol/src/grid_topology.rs @@ -73,12 +73,20 @@ pub struct SessionGridTopology { shuffled_indices: Vec, /// The canonical shuffling of validators for the session. canonical_shuffling: Vec, + /// The list of peer-ids in an efficient way to search. + peer_ids: HashSet, } impl SessionGridTopology { /// Create a new session grid topology. pub fn new(shuffled_indices: Vec, canonical_shuffling: Vec) -> Self { - SessionGridTopology { shuffled_indices, canonical_shuffling } + let mut peer_ids = HashSet::new(); + for peer_info in canonical_shuffling.iter() { + for peer_id in peer_info.peer_ids.iter() { + peer_ids.insert(*peer_id); + } + } + SessionGridTopology { shuffled_indices, canonical_shuffling, peer_ids } } /// Produces the outgoing routing logic for a particular peer. @@ -111,6 +119,11 @@ impl SessionGridTopology { Some(grid_subset) } + + /// Tells if a given peer id is validator in a session + pub fn is_validator(&self, peer: &PeerId) -> bool { + self.peer_ids.contains(peer) + } } struct MatrixNeighbors { @@ -273,6 +286,11 @@ impl SessionGridTopologyEntry { pub fn get(&self) -> &SessionGridTopology { &self.topology } + + /// Tells if a given peer id is validator in a session + pub fn is_validator(&self, peer: &PeerId) -> bool { + self.topology.is_validator(peer) + } } /// A set of topologies indexed by session @@ -347,6 +365,7 @@ impl Default for SessionBoundGridTopologyStorage { topology: SessionGridTopology { shuffled_indices: Vec::new(), canonical_shuffling: Vec::new(), + peer_ids: Default::default(), }, local_neighbors: GridNeighbors::empty(), }, diff --git a/polkadot/node/network/protocol/src/lib.rs b/polkadot/node/network/protocol/src/lib.rs index 9aeeb98ea9d..ae72230ee43 100644 --- a/polkadot/node/network/protocol/src/lib.rs +++ b/polkadot/node/network/protocol/src/lib.rs @@ -253,29 +253,29 @@ impl View { /// A protocol-versioned type. #[derive(Debug, Clone, PartialEq, Eq)] -pub enum Versioned { +pub enum Versioned { /// V1 type. V1(V1), /// V2 type. V2(V2), - /// VStaging type - VStaging(VStaging), + /// V3 type + V3(V3), } -impl Versioned<&'_ V1, &'_ V2, &'_ VStaging> { +impl Versioned<&'_ V1, &'_ V2, &'_ V3> { /// Convert to a fully-owned version of the message. - pub fn clone_inner(&self) -> Versioned { + pub fn clone_inner(&self) -> Versioned { match *self { Versioned::V1(inner) => Versioned::V1(inner.clone()), Versioned::V2(inner) => Versioned::V2(inner.clone()), - Versioned::VStaging(inner) => Versioned::VStaging(inner.clone()), + Versioned::V3(inner) => Versioned::V3(inner.clone()), } } } /// All supported versions of the validation protocol message. pub type VersionedValidationProtocol = - Versioned; + Versioned; impl From for VersionedValidationProtocol { fn from(v1: v1::ValidationProtocol) -> Self { @@ -289,9 +289,9 @@ impl From for VersionedValidationProtocol { } } -impl From for VersionedValidationProtocol { - fn from(vstaging: vstaging::ValidationProtocol) -> Self { - VersionedValidationProtocol::VStaging(vstaging) +impl From for VersionedValidationProtocol { + fn from(v3: v3::ValidationProtocol) -> Self { + VersionedValidationProtocol::V3(v3) } } @@ -317,7 +317,7 @@ macro_rules! impl_versioned_full_protocol_from { match versioned_from { Versioned::V1(x) => Versioned::V1(x.into()), Versioned::V2(x) => Versioned::V2(x.into()), - Versioned::VStaging(x) => Versioned::VStaging(x.into()), + Versioned::V3(x) => Versioned::V3(x.into()), } } } @@ -331,7 +331,7 @@ macro_rules! impl_versioned_try_from { $out:ty, $v1_pat:pat => $v1_out:expr, $v2_pat:pat => $v2_out:expr, - $vstaging_pat:pat => $vstaging_out:expr + $v3_pat:pat => $v3_out:expr ) => { impl TryFrom<$from> for $out { type Error = crate::WrongVariant; @@ -341,7 +341,7 @@ macro_rules! impl_versioned_try_from { match x { Versioned::V1($v1_pat) => Ok(Versioned::V1($v1_out)), Versioned::V2($v2_pat) => Ok(Versioned::V2($v2_out)), - Versioned::VStaging($vstaging_pat) => Ok(Versioned::VStaging($vstaging_out)), + Versioned::V3($v3_pat) => Ok(Versioned::V3($v3_out)), _ => Err(crate::WrongVariant), } } @@ -355,8 +355,7 @@ macro_rules! impl_versioned_try_from { match x { Versioned::V1($v1_pat) => Ok(Versioned::V1($v1_out.clone())), Versioned::V2($v2_pat) => Ok(Versioned::V2($v2_out.clone())), - Versioned::VStaging($vstaging_pat) => - Ok(Versioned::VStaging($vstaging_out.clone())), + Versioned::V3($v3_pat) => Ok(Versioned::V3($v3_out.clone())), _ => Err(crate::WrongVariant), } } @@ -368,7 +367,7 @@ macro_rules! impl_versioned_try_from { pub type BitfieldDistributionMessage = Versioned< v1::BitfieldDistributionMessage, v2::BitfieldDistributionMessage, - vstaging::BitfieldDistributionMessage, + v3::BitfieldDistributionMessage, >; impl_versioned_full_protocol_from!( BitfieldDistributionMessage, @@ -380,14 +379,14 @@ impl_versioned_try_from!( BitfieldDistributionMessage, v1::ValidationProtocol::BitfieldDistribution(x) => x, v2::ValidationProtocol::BitfieldDistribution(x) => x, - vstaging::ValidationProtocol::BitfieldDistribution(x) => x + v3::ValidationProtocol::BitfieldDistribution(x) => x ); /// Version-annotated messages used by the statement distribution subsystem. pub type StatementDistributionMessage = Versioned< v1::StatementDistributionMessage, v2::StatementDistributionMessage, - vstaging::StatementDistributionMessage, + v3::StatementDistributionMessage, >; impl_versioned_full_protocol_from!( StatementDistributionMessage, @@ -399,14 +398,14 @@ impl_versioned_try_from!( StatementDistributionMessage, v1::ValidationProtocol::StatementDistribution(x) => x, v2::ValidationProtocol::StatementDistribution(x) => x, - vstaging::ValidationProtocol::StatementDistribution(x) => x + v3::ValidationProtocol::StatementDistribution(x) => x ); /// Version-annotated messages used by the approval distribution subsystem. pub type ApprovalDistributionMessage = Versioned< v1::ApprovalDistributionMessage, v2::ApprovalDistributionMessage, - vstaging::ApprovalDistributionMessage, + v3::ApprovalDistributionMessage, >; impl_versioned_full_protocol_from!( ApprovalDistributionMessage, @@ -418,7 +417,7 @@ impl_versioned_try_from!( ApprovalDistributionMessage, v1::ValidationProtocol::ApprovalDistribution(x) => x, v2::ValidationProtocol::ApprovalDistribution(x) => x, - vstaging::ValidationProtocol::ApprovalDistribution(x) => x + v3::ValidationProtocol::ApprovalDistribution(x) => x ); @@ -426,7 +425,7 @@ impl_versioned_try_from!( pub type GossipSupportNetworkMessage = Versioned< v1::GossipSupportNetworkMessage, v2::GossipSupportNetworkMessage, - vstaging::GossipSupportNetworkMessage, + v3::GossipSupportNetworkMessage, >; // This is a void enum placeholder, so never gets sent over the wire. @@ -871,19 +870,17 @@ pub mod v2 { } } -/// vstaging network protocol types, intended to become v3. -/// Initial purpose is for chaning ApprovalDistributionMessage to -/// include more than one assignment in the message. -pub mod vstaging { +/// v3 network protocol types. +/// Purpose is for chaning ApprovalDistributionMessage to +/// include more than one assignment and approval in a message. +pub mod v3 { use parity_scale_codec::{Decode, Encode}; - use polkadot_node_primitives::approval::{ - v1::IndirectSignedApprovalVote, - v2::{CandidateBitfield, IndirectAssignmentCertV2}, + use polkadot_node_primitives::approval::v2::{ + CandidateBitfield, IndirectAssignmentCertV2, IndirectSignedApprovalVoteV2, }; - /// This parts of the protocol did not change from v2, so just alias them in vstaging, - /// no reason why they can't be change untill vstaging becomes v3 and is released. + /// This parts of the protocol did not change from v2, so just alias them in v3. pub use super::v2::{ declare_signature_payload, BackedCandidateAcknowledgement, BackedCandidateManifest, BitfieldDistributionMessage, GossipSupportNetworkMessage, StatementDistributionMessage, @@ -903,7 +900,7 @@ pub mod vstaging { Assignments(Vec<(IndirectAssignmentCertV2, CandidateBitfield)>), /// Approvals for candidates in some recent, unfinalized block. #[codec(index = 1)] - Approvals(Vec), + Approvals(Vec), } /// All network messages on the validation peer-set. diff --git a/polkadot/node/network/protocol/src/peer_set.rs b/polkadot/node/network/protocol/src/peer_set.rs index 7e257d508b5..cb329607ad6 100644 --- a/polkadot/node/network/protocol/src/peer_set.rs +++ b/polkadot/node/network/protocol/src/peer_set.rs @@ -73,7 +73,11 @@ impl PeerSet { // Networking layer relies on `get_main_name()` being the main name of the protocol // for peersets and connection management. let protocol = peerset_protocol_names.get_main_name(self); - let fallback_names = PeerSetProtocolNames::get_fallback_names(self); + let fallback_names = PeerSetProtocolNames::get_fallback_names( + self, + &peerset_protocol_names.genesis_hash, + peerset_protocol_names.fork_id.as_deref(), + ); let max_notification_size = self.get_max_notification_size(is_authority); match self { @@ -127,15 +131,8 @@ impl PeerSet { /// Networking layer relies on `get_main_version()` being the version /// of the main protocol name reported by [`PeerSetProtocolNames::get_main_name()`]. pub fn get_main_version(self) -> ProtocolVersion { - #[cfg(not(feature = "network-protocol-staging"))] - match self { - PeerSet::Validation => ValidationVersion::V2.into(), - PeerSet::Collation => CollationVersion::V2.into(), - } - - #[cfg(feature = "network-protocol-staging")] match self { - PeerSet::Validation => ValidationVersion::VStaging.into(), + PeerSet::Validation => ValidationVersion::V3.into(), PeerSet::Collation => CollationVersion::V2.into(), } } @@ -163,7 +160,7 @@ impl PeerSet { Some("validation/1") } else if version == ValidationVersion::V2.into() { Some("validation/2") - } else if version == ValidationVersion::VStaging.into() { + } else if version == ValidationVersion::V3.into() { Some("validation/3") } else { None @@ -236,9 +233,10 @@ pub enum ValidationVersion { V1 = 1, /// The second version. V2 = 2, - /// The staging version to gather changes - /// that before the release become v3. - VStaging = 3, + /// The third version where changes to ApprovalDistributionMessage had been made. + /// The changes are translatable to V2 format untill assignments v2 and approvals + /// coalescing is enabled through a runtime upgrade. + V3 = 3, } /// Supported collation protocol versions. Only versions defined here must be used in the codebase. @@ -299,6 +297,8 @@ impl From for ProtocolVersion { pub struct PeerSetProtocolNames { protocols: HashMap, names: HashMap<(PeerSet, ProtocolVersion), ProtocolName>, + genesis_hash: Hash, + fork_id: Option, } impl PeerSetProtocolNames { @@ -333,7 +333,7 @@ impl PeerSetProtocolNames { } Self::register_legacy_protocol(&mut protocols, protocol); } - Self { protocols, names } + Self { protocols, names, genesis_hash, fork_id: fork_id.map(|fork_id| fork_id.into()) } } /// Helper function to register main protocol. @@ -437,9 +437,30 @@ impl PeerSetProtocolNames { } /// Get the protocol fallback names. Currently only holds the legacy name - /// for `LEGACY_PROTOCOL_VERSION` = 1. - fn get_fallback_names(protocol: PeerSet) -> Vec { - std::iter::once(Self::get_legacy_name(protocol)).collect() + /// for `LEGACY_PROTOCOL_VERSION` = 1 and v2 for validation. + fn get_fallback_names( + protocol: PeerSet, + genesis_hash: &Hash, + fork_id: Option<&str>, + ) -> Vec { + let mut fallbacks = vec![Self::get_legacy_name(protocol)]; + match protocol { + PeerSet::Validation => { + // Fallbacks are tried one by one, till one matches so push v2 at the top, so + // that it is used ahead of the legacy one(v1). + fallbacks.insert( + 0, + Self::generate_name( + genesis_hash, + fork_id, + protocol, + ValidationVersion::V2.into(), + ), + ) + }, + PeerSet::Collation => {}, + }; + fallbacks } } diff --git a/polkadot/node/network/statement-distribution/src/legacy_v1/mod.rs b/polkadot/node/network/statement-distribution/src/legacy_v1/mod.rs index d9866af1ee2..93f97fe1dd6 100644 --- a/polkadot/node/network/statement-distribution/src/legacy_v1/mod.rs +++ b/polkadot/node/network/statement-distribution/src/legacy_v1/mod.rs @@ -22,8 +22,8 @@ use polkadot_node_network_protocol::{ grid_topology::{GridNeighbors, RequiredRouting, SessionBoundGridTopologyStorage}, peer_set::{IsAuthority, PeerSet, ValidationVersion}, v1::{self as protocol_v1, StatementMetadata}, - v2 as protocol_v2, vstaging as protocol_vstaging, IfDisconnected, PeerId, - UnifiedReputationChange as Rep, Versioned, View, + v2 as protocol_v2, v3 as protocol_v3, IfDisconnected, PeerId, UnifiedReputationChange as Rep, + Versioned, View, }; use polkadot_node_primitives::{ SignedFullStatement, Statement, StatementWithPVD, UncheckedSignedFullStatement, @@ -1075,7 +1075,7 @@ async fn circulate_statement<'a, Context>( }) .partition::, _>(|(_, _, version)| match version { ValidationVersion::V1 => true, - ValidationVersion::V2 | ValidationVersion::VStaging => false, + ValidationVersion::V2 | ValidationVersion::V3 => false, }); // partition is handy here but not if we add more protocol versions let payload = v1_statement_message(relay_parent, stored.statement.clone(), metrics); @@ -1108,8 +1108,7 @@ async fn circulate_statement<'a, Context>( .collect(); let v2_peers_to_send = filter_by_peer_version(&peers_to_send, ValidationVersion::V2.into()); - let vstaging_to_send = - filter_by_peer_version(&peers_to_send, ValidationVersion::VStaging.into()); + let v3_to_send = filter_by_peer_version(&peers_to_send, ValidationVersion::V3.into()); if !v2_peers_to_send.is_empty() { gum::trace!( @@ -1126,17 +1125,17 @@ async fn circulate_statement<'a, Context>( .await; } - if !vstaging_to_send.is_empty() { + if !v3_to_send.is_empty() { gum::trace!( target: LOG_TARGET, - ?vstaging_to_send, + ?v3_to_send, ?relay_parent, statement = ?stored.statement, - "Sending statement to vstaging peers", + "Sending statement to v3 peers", ); ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( - vstaging_to_send, - compatible_v1_message(ValidationVersion::VStaging, payload.clone()).into(), + v3_to_send, + compatible_v1_message(ValidationVersion::V3, payload.clone()).into(), )) .await; } @@ -1472,10 +1471,8 @@ async fn handle_incoming_message<'a, Context>( let message = match message { Versioned::V1(m) => m, Versioned::V2(protocol_v2::StatementDistributionMessage::V1Compatibility(m)) | - Versioned::VStaging(protocol_vstaging::StatementDistributionMessage::V1Compatibility( - m, - )) => m, - Versioned::V2(_) | Versioned::VStaging(_) => { + Versioned::V3(protocol_v3::StatementDistributionMessage::V1Compatibility(m)) => m, + Versioned::V2(_) | Versioned::V3(_) => { // The higher-level subsystem code is supposed to filter out // all non v1 messages. gum::debug!( @@ -2201,8 +2198,7 @@ fn compatible_v1_message( ValidationVersion::V1 => Versioned::V1(message), ValidationVersion::V2 => Versioned::V2(protocol_v2::StatementDistributionMessage::V1Compatibility(message)), - ValidationVersion::VStaging => Versioned::VStaging( - protocol_vstaging::StatementDistributionMessage::V1Compatibility(message), - ), + ValidationVersion::V3 => + Versioned::V3(protocol_v3::StatementDistributionMessage::V1Compatibility(message)), } } diff --git a/polkadot/node/network/statement-distribution/src/lib.rs b/polkadot/node/network/statement-distribution/src/lib.rs index ef1fc7cd78b..a1ba1137b5a 100644 --- a/polkadot/node/network/statement-distribution/src/lib.rs +++ b/polkadot/node/network/statement-distribution/src/lib.rs @@ -27,7 +27,7 @@ use std::time::Duration; use polkadot_node_network_protocol::{ request_response::{v1 as request_v1, v2::AttestedCandidateRequest, IncomingRequestReceiver}, - v2 as protocol_v2, vstaging as protocol_vstaging, Versioned, + v2 as protocol_v2, v3 as protocol_v3, Versioned, }; use polkadot_node_primitives::StatementWithPVD; use polkadot_node_subsystem::{ @@ -400,11 +400,11 @@ impl StatementDistributionSubsystem { Versioned::V2( protocol_v2::StatementDistributionMessage::V1Compatibility(_), ) | - Versioned::VStaging( - protocol_vstaging::StatementDistributionMessage::V1Compatibility(_), + Versioned::V3( + protocol_v3::StatementDistributionMessage::V1Compatibility(_), ) => VersionTarget::Legacy, Versioned::V1(_) => VersionTarget::Legacy, - Versioned::V2(_) | Versioned::VStaging(_) => VersionTarget::Current, + Versioned::V2(_) | Versioned::V3(_) => VersionTarget::Current, }, _ => VersionTarget::Both, }; diff --git a/polkadot/node/network/statement-distribution/src/v2/mod.rs b/polkadot/node/network/statement-distribution/src/v2/mod.rs index 406f1130590..2f06d3685b8 100644 --- a/polkadot/node/network/statement-distribution/src/v2/mod.rs +++ b/polkadot/node/network/statement-distribution/src/v2/mod.rs @@ -29,8 +29,7 @@ use polkadot_node_network_protocol::{ MAX_PARALLEL_ATTESTED_CANDIDATE_REQUESTS, }, v2::{self as protocol_v2, StatementFilter}, - vstaging as protocol_vstaging, IfDisconnected, PeerId, UnifiedReputationChange as Rep, - Versioned, View, + v3 as protocol_v3, IfDisconnected, PeerId, UnifiedReputationChange as Rep, Versioned, View, }; use polkadot_node_primitives::{ SignedFullStatementWithPVD, StatementWithPVD as FullStatementWithPVD, @@ -366,7 +365,7 @@ pub(crate) async fn handle_network_update( gum::trace!(target: LOG_TARGET, ?peer_id, ?role, ?protocol_version, "Peer connected"); let versioned_protocol = if protocol_version != ValidationVersion::V2.into() && - protocol_version != ValidationVersion::VStaging.into() + protocol_version != ValidationVersion::V3.into() { return } else { @@ -432,28 +431,28 @@ pub(crate) async fn handle_network_update( net_protocol::StatementDistributionMessage::V2( protocol_v2::StatementDistributionMessage::V1Compatibility(_), ) | - net_protocol::StatementDistributionMessage::VStaging( - protocol_vstaging::StatementDistributionMessage::V1Compatibility(_), + net_protocol::StatementDistributionMessage::V3( + protocol_v3::StatementDistributionMessage::V1Compatibility(_), ) => return, net_protocol::StatementDistributionMessage::V2( protocol_v2::StatementDistributionMessage::Statement(relay_parent, statement), ) | - net_protocol::StatementDistributionMessage::VStaging( - protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, statement), + net_protocol::StatementDistributionMessage::V3( + protocol_v3::StatementDistributionMessage::Statement(relay_parent, statement), ) => handle_incoming_statement(ctx, state, peer_id, relay_parent, statement, reputation) .await, net_protocol::StatementDistributionMessage::V2( protocol_v2::StatementDistributionMessage::BackedCandidateManifest(inner), ) | - net_protocol::StatementDistributionMessage::VStaging( - protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest(inner), + net_protocol::StatementDistributionMessage::V3( + protocol_v3::StatementDistributionMessage::BackedCandidateManifest(inner), ) => handle_incoming_manifest(ctx, state, peer_id, inner, reputation).await, net_protocol::StatementDistributionMessage::V2( protocol_v2::StatementDistributionMessage::BackedCandidateKnown(inner), ) | - net_protocol::StatementDistributionMessage::VStaging( - protocol_vstaging::StatementDistributionMessage::BackedCandidateKnown(inner), + net_protocol::StatementDistributionMessage::V3( + protocol_v3::StatementDistributionMessage::BackedCandidateKnown(inner), ) => handle_incoming_acknowledgement(ctx, state, peer_id, inner, reputation).await, }, NetworkBridgeEvent::PeerViewChange(peer_id, view) => @@ -806,13 +805,13 @@ fn pending_statement_network_message( protocol_v2::StatementDistributionMessage::Statement(relay_parent, signed) }) .map(|msg| (vec![peer.0], Versioned::V2(msg).into())), - ValidationVersion::VStaging => statement_store + ValidationVersion::V3 => statement_store .validator_statement(originator, compact) .map(|s| s.as_unchecked().clone()) .map(|signed| { - protocol_vstaging::StatementDistributionMessage::Statement(relay_parent, signed) + protocol_v3::StatementDistributionMessage::Statement(relay_parent, signed) }) - .map(|msg| (vec![peer.0], Versioned::VStaging(msg).into())), + .map(|msg| (vec![peer.0], Versioned::V3(msg).into())), ValidationVersion::V1 => { gum::error!( target: LOG_TARGET, @@ -945,10 +944,10 @@ async fn send_pending_grid_messages( ) .into(), )), - ValidationVersion::VStaging => messages.push(( + ValidationVersion::V3 => messages.push(( vec![peer_id.0], - Versioned::VStaging( - protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest( + Versioned::V3( + protocol_v3::StatementDistributionMessage::BackedCandidateManifest( manifest, ), ) @@ -960,7 +959,7 @@ async fn send_pending_grid_messages( "Bug ValidationVersion::V1 should not be used in statement-distribution v2, legacy should have handled this" ); - } + }, }; }, grid::ManifestKind::Acknowledgement => { @@ -1308,8 +1307,8 @@ async fn circulate_statement( let statement_to_v2_peers = filter_by_peer_version(&statement_to_peers, ValidationVersion::V2.into()); - let statement_to_vstaging_peers = - filter_by_peer_version(&statement_to_peers, ValidationVersion::VStaging.into()); + let statement_to_v3_peers = + filter_by_peer_version(&statement_to_peers, ValidationVersion::V3.into()); // ship off the network messages to the network bridge. if !statement_to_v2_peers.is_empty() { @@ -1331,17 +1330,17 @@ async fn circulate_statement( .await; } - if !statement_to_vstaging_peers.is_empty() { + if !statement_to_v3_peers.is_empty() { gum::debug!( target: LOG_TARGET, ?compact_statement, n_peers = ?statement_to_peers.len(), - "Sending statement to vstaging peers", + "Sending statement to v3 peers", ); ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( - statement_to_vstaging_peers, - Versioned::VStaging(protocol_vstaging::StatementDistributionMessage::Statement( + statement_to_v3_peers, + Versioned::V3(protocol_v3::StatementDistributionMessage::Statement( relay_parent, statement.as_unchecked().clone(), )) @@ -1887,8 +1886,7 @@ async fn provide_candidate_to_grid( } let manifest_peers_v2 = filter_by_peer_version(&manifest_peers, ValidationVersion::V2.into()); - let manifest_peers_vstaging = - filter_by_peer_version(&manifest_peers, ValidationVersion::VStaging.into()); + let manifest_peers_v3 = filter_by_peer_version(&manifest_peers, ValidationVersion::V3.into()); if !manifest_peers_v2.is_empty() { gum::debug!( target: LOG_TARGET, @@ -1908,27 +1906,27 @@ async fn provide_candidate_to_grid( .await; } - if !manifest_peers_vstaging.is_empty() { + if !manifest_peers_v3.is_empty() { gum::debug!( target: LOG_TARGET, ?candidate_hash, local_validator = ?per_session.local_validator, - n_peers = manifest_peers_vstaging.len(), - "Sending manifest to vstaging peers" + n_peers = manifest_peers_v3.len(), + "Sending manifest to v3 peers" ); ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( - manifest_peers_vstaging, - Versioned::VStaging( - protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest(manifest), - ) + manifest_peers_v3, + Versioned::V3(protocol_v3::StatementDistributionMessage::BackedCandidateManifest( + manifest, + )) .into(), )) .await; } let ack_peers_v2 = filter_by_peer_version(&ack_peers, ValidationVersion::V2.into()); - let ack_peers_vstaging = filter_by_peer_version(&ack_peers, ValidationVersion::VStaging.into()); + let ack_peers_v3 = filter_by_peer_version(&ack_peers, ValidationVersion::V3.into()); if !ack_peers_v2.is_empty() { gum::debug!( target: LOG_TARGET, @@ -1948,22 +1946,20 @@ async fn provide_candidate_to_grid( .await; } - if !ack_peers_vstaging.is_empty() { + if !ack_peers_v3.is_empty() { gum::debug!( target: LOG_TARGET, ?candidate_hash, local_validator = ?per_session.local_validator, - n_peers = ack_peers_vstaging.len(), - "Sending acknowledgement to vstaging peers" + n_peers = ack_peers_v3.len(), + "Sending acknowledgement to v3 peers" ); ctx.send_message(NetworkBridgeTxMessage::SendValidationMessage( - ack_peers_vstaging, - Versioned::VStaging( - protocol_vstaging::StatementDistributionMessage::BackedCandidateKnown( - acknowledgement, - ), - ) + ack_peers_v3, + Versioned::V3(protocol_v3::StatementDistributionMessage::BackedCandidateKnown( + acknowledgement, + )) .into(), )) .await; @@ -2293,8 +2289,8 @@ fn post_acknowledgement_statement_messages( ) .into(), )), - ValidationVersion::VStaging => messages.push(Versioned::VStaging( - protocol_vstaging::StatementDistributionMessage::Statement( + ValidationVersion::V3 => messages.push(Versioned::V3( + protocol_v3::StatementDistributionMessage::Statement( relay_parent, statement.as_unchecked().clone(), ) @@ -2441,9 +2437,9 @@ fn acknowledgement_and_statement_messages( let mut messages = match peer.1 { ValidationVersion::V2 => vec![(vec![peer.0], msg_v2.into())], - ValidationVersion::VStaging => vec![( + ValidationVersion::V3 => vec![( vec![peer.0], - Versioned::VStaging(protocol_v2::StatementDistributionMessage::BackedCandidateKnown( + Versioned::V3(protocol_v2::StatementDistributionMessage::BackedCandidateKnown( acknowledgement, )) .into(), diff --git a/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs b/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs index 116116659cb..aa1a473b833 100644 --- a/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs +++ b/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs @@ -2830,7 +2830,7 @@ fn inactive_local_participates_in_grid() { send_peer_message( &mut overseer, peer_a.clone(), - protocol_vstaging::StatementDistributionMessage::BackedCandidateManifest(manifest), + protocol_v3::StatementDistributionMessage::BackedCandidateManifest(manifest), ) .await; diff --git a/polkadot/node/primitives/src/approval.rs b/polkadot/node/primitives/src/approval.rs index cc9136b8ae3..f2a79e025af 100644 --- a/polkadot/node/primitives/src/approval.rs +++ b/polkadot/node/primitives/src/approval.rs @@ -219,7 +219,9 @@ pub mod v2 { use std::ops::BitOr; use bitvec::{prelude::Lsb0, vec::BitVec}; - use polkadot_primitives::{CandidateIndex, CoreIndex, Hash, ValidatorIndex}; + use polkadot_primitives::{ + CandidateIndex, CoreIndex, Hash, ValidatorIndex, ValidatorSignature, + }; /// A static context associated with producing randomness for a core. pub const CORE_RANDOMNESS_CONTEXT: &[u8] = b"A&V CORE v2"; @@ -473,6 +475,59 @@ pub mod v2 { }) } } + + impl From for IndirectSignedApprovalVoteV2 { + fn from(value: super::v1::IndirectSignedApprovalVote) -> Self { + Self { + block_hash: value.block_hash, + validator: value.validator, + candidate_indices: value.candidate_index.into(), + signature: value.signature, + } + } + } + + /// Errors that can occur when trying to convert to/from approvals v1/v2 + #[derive(Debug)] + pub enum ApprovalConversionError { + /// More than one candidate was signed. + MoreThanOneCandidate(usize), + } + + impl TryFrom for super::v1::IndirectSignedApprovalVote { + type Error = ApprovalConversionError; + + fn try_from(value: IndirectSignedApprovalVoteV2) -> Result { + if value.candidate_indices.count_ones() != 1 { + return Err(ApprovalConversionError::MoreThanOneCandidate( + value.candidate_indices.count_ones(), + )) + } + Ok(Self { + block_hash: value.block_hash, + validator: value.validator, + candidate_index: value.candidate_indices.first_one().expect("Qed we checked above") + as u32, + signature: value.signature, + }) + } + } + + /// A signed approval vote which references the candidate indirectly via the block. + /// + /// In practice, we have a look-up from block hash and candidate index to candidate hash, + /// so this can be transformed into a `SignedApprovalVote`. + #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] + pub struct IndirectSignedApprovalVoteV2 { + /// A block hash where the candidate appears. + pub block_hash: Hash, + /// The index of the candidate in the list of candidates fully included as-of the block. + pub candidate_indices: CandidateBitfield, + /// The validator index. + pub validator: ValidatorIndex, + /// The signature by the validator. + pub signature: ValidatorSignature, + } } #[cfg(test)] diff --git a/polkadot/node/primitives/src/disputes/message.rs b/polkadot/node/primitives/src/disputes/message.rs index 89d3ea6c0af..31fe73a7ba1 100644 --- a/polkadot/node/primitives/src/disputes/message.rs +++ b/polkadot/node/primitives/src/disputes/message.rs @@ -170,7 +170,7 @@ impl DisputeMessage { let valid_vote = ValidDisputeVote { validator_index: valid_index, signature: valid_statement.validator_signature().clone(), - kind: *valid_kind, + kind: valid_kind.clone(), }; let invalid_vote = InvalidDisputeVote { diff --git a/polkadot/node/primitives/src/disputes/mod.rs b/polkadot/node/primitives/src/disputes/mod.rs index 500b705be95..768b95f6553 100644 --- a/polkadot/node/primitives/src/disputes/mod.rs +++ b/polkadot/node/primitives/src/disputes/mod.rs @@ -46,6 +46,15 @@ pub struct SignedDisputeStatement { session_index: SessionIndex, } +/// Errors encountered while signing a dispute statement +#[derive(Debug)] +pub enum SignedDisputeStatementError { + /// Encountered a keystore error while signing + KeyStoreError(KeystoreError), + /// Could not generate signing payload + PayloadError, +} + /// Tracked votes on candidates, for the purposes of dispute resolution. #[derive(Debug, Clone)] pub struct CandidateVotes { @@ -107,8 +116,9 @@ impl ValidCandidateVotes { ValidDisputeStatementKind::BackingValid(_) | ValidDisputeStatementKind::BackingSeconded(_) => false, ValidDisputeStatementKind::Explicit | - ValidDisputeStatementKind::ApprovalChecking => { - occupied.insert((kind, sig)); + ValidDisputeStatementKind::ApprovalChecking | + ValidDisputeStatementKind::ApprovalCheckingMultipleCandidates(_) => { + occupied.insert((kind.clone(), sig)); kind != occupied.get().0 }, }, @@ -213,16 +223,19 @@ impl SignedDisputeStatement { candidate_hash: CandidateHash, session_index: SessionIndex, validator_public: ValidatorId, - ) -> Result, KeystoreError> { + ) -> Result, SignedDisputeStatementError> { let dispute_statement = if valid { DisputeStatement::Valid(ValidDisputeStatementKind::Explicit) } else { DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit) }; - let data = dispute_statement.payload_data(candidate_hash, session_index); + let data = dispute_statement + .payload_data(candidate_hash, session_index) + .map_err(|_| SignedDisputeStatementError::PayloadError)?; let signature = keystore - .sr25519_sign(ValidatorId::ID, validator_public.as_ref(), &data)? + .sr25519_sign(ValidatorId::ID, validator_public.as_ref(), &data) + .map_err(SignedDisputeStatementError::KeyStoreError)? .map(|sig| Self { dispute_statement, candidate_hash, diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index 448ab605aa9..81eff49ee30 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -225,7 +225,3 @@ runtime-metrics = [ "rococo-runtime?/runtime-metrics", "westend-runtime?/runtime-metrics", ] - -network-protocol-staging = [ - "polkadot-node-network-protocol/network-protocol-staging", -] diff --git a/polkadot/node/service/src/parachains_db/upgrade.rs b/polkadot/node/service/src/parachains_db/upgrade.rs index 1d76c79d3e3..d22eebb5c8d 100644 --- a/polkadot/node/service/src/parachains_db/upgrade.rs +++ b/polkadot/node/service/src/parachains_db/upgrade.rs @@ -20,10 +20,16 @@ use std::{ fs, io, path::{Path, PathBuf}, str::FromStr, + sync::Arc, }; -use polkadot_node_core_approval_voting::approval_db::v2::{ - migration_helpers::v1_to_v2, Config as ApprovalDbConfig, +use polkadot_node_core_approval_voting::approval_db::{ + common::{Config as ApprovalDbConfig, Result as ApprovalDbResult}, + v2::migration_helpers::v1_to_latest, + v3::migration_helpers::v2_to_latest, +}; +use polkadot_node_subsystem_util::database::{ + kvdb_impl::DbAdapter as RocksDbAdapter, paritydb_impl::DbAdapter as ParityDbAdapter, Database, }; type Version = u32; @@ -32,7 +38,9 @@ const VERSION_FILE_NAME: &'static str = "parachain_db_version"; /// Current db version. /// Version 4 changes approval db format for `OurAssignment`. -pub(crate) const CURRENT_VERSION: Version = 4; +/// Version 5 changes approval db format to hold some additional +/// information about delayed approvals. +pub(crate) const CURRENT_VERSION: Version = 5; #[derive(thiserror::Error, Debug)] pub enum Error { @@ -101,7 +109,8 @@ pub(crate) fn try_upgrade_db_to_next_version( // 2 -> 3 migration Some(2) => migrate_from_version_2_to_3(db_path, db_kind)?, // 3 -> 4 migration - Some(3) => migrate_from_version_3_to_4(db_path, db_kind)?, + Some(3) => migrate_from_version_3_or_4_to_5(db_path, db_kind, v1_to_latest)?, + Some(4) => migrate_from_version_3_or_4_to_5(db_path, db_kind, v2_to_latest)?, // Already at current version, do nothing. Some(CURRENT_VERSION) => CURRENT_VERSION, // This is an arbitrary future version, we don't handle it. @@ -174,14 +183,19 @@ fn migrate_from_version_1_to_2(path: &Path, db_kind: DatabaseKind) -> Result Result { +fn migrate_from_version_3_or_4_to_5( + path: &Path, + db_kind: DatabaseKind, + migration_function: F, +) -> Result +where + F: Fn(Arc, ApprovalDbConfig) -> ApprovalDbResult<()>, +{ gum::info!(target: LOG_TARGET, "Migrating parachains db from version 3 to version 4 ..."); - use polkadot_node_subsystem_util::database::{ - kvdb_impl::DbAdapter as RocksDbAdapter, paritydb_impl::DbAdapter as ParityDbAdapter, - }; - use std::sync::Arc; let approval_db_config = ApprovalDbConfig { col_approval_data: super::REAL_COLUMNS.col_approval_data }; @@ -194,7 +208,8 @@ fn migrate_from_version_3_to_4(path: &Path, db_kind: DatabaseKind) -> Result { let db_path = path @@ -207,7 +222,8 @@ fn migrate_from_version_3_to_4(path: &Path, db_kind: DatabaseKind) -> Result), /// Get the node features. NodeFeatures(SessionIndex, RuntimeApiSender), + /// Approval voting params + /// `V10` + ApprovalVotingParams(SessionIndex, RuntimeApiSender), } impl RuntimeApiRequest { @@ -751,6 +755,9 @@ impl RuntimeApiRequest { /// `Node features` pub const NODE_FEATURES_RUNTIME_REQUIREMENT: u32 = 9; + + /// `approval_voting_params` + pub const APPROVAL_VOTING_PARAMS_REQUIREMENT: u32 = 10; } /// A message to the Runtime API subsystem. @@ -936,7 +943,7 @@ pub enum ApprovalVotingMessage { /// protocol. /// /// Should not be sent unless the block hash within the indirect vote is known. - CheckAndImportApproval(IndirectSignedApprovalVote, oneshot::Sender), + CheckAndImportApproval(IndirectSignedApprovalVoteV2, oneshot::Sender), /// Returns the highest possible ancestor hash of the provided block hash which is /// acceptable to vote on finality for. /// The `BlockNumber` provided is the number of the block's ancestor which is the @@ -952,7 +959,7 @@ pub enum ApprovalVotingMessage { /// requires calling into `approval-distribution`: Calls should be infrequent and bounded. GetApprovalSignaturesForCandidate( CandidateHash, - oneshot::Sender>, + oneshot::Sender, ValidatorSignature)>>, ), } @@ -968,7 +975,7 @@ pub enum ApprovalDistributionMessage { /// Distribute an approval vote for the local validator. The approval vote is assumed to be /// valid, relevant, and the corresponding approval already issued. /// If not, the subsystem is free to drop the message. - DistributeApproval(IndirectSignedApprovalVote), + DistributeApproval(IndirectSignedApprovalVoteV2), /// An update from the network bridge. #[from] NetworkBridgeUpdate(NetworkBridgeEvent), @@ -976,7 +983,7 @@ pub enum ApprovalDistributionMessage { /// Get all approval signatures for all chains a candidate appeared in. GetApprovalSignatures( HashSet<(Hash, CandidateIndex)>, - oneshot::Sender>, + oneshot::Sender, ValidatorSignature)>>, ), /// Approval checking lag update measured in blocks. ApprovalCheckingLagUpdate(BlockNumber), diff --git a/polkadot/node/subsystem-types/src/runtime_client.rs b/polkadot/node/subsystem-types/src/runtime_client.rs index 21df1483b9e..7f618307610 100644 --- a/polkadot/node/subsystem-types/src/runtime_client.rs +++ b/polkadot/node/subsystem-types/src/runtime_client.rs @@ -16,12 +16,15 @@ use async_trait::async_trait; use polkadot_primitives::{ - async_backing, runtime_api::ParachainHost, slashing, vstaging, Block, BlockNumber, - CandidateCommitments, CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreState, - DisputeState, ExecutorParams, GroupRotationInfo, Hash, Header, Id, InboundDownwardMessage, - InboundHrmpMessage, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, - ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash, - ValidatorId, ValidatorIndex, ValidatorSignature, + async_backing, + runtime_api::ParachainHost, + slashing, + vstaging::{self, ApprovalVotingParams}, + Block, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, + CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Hash, + Header, Id, InboundDownwardMessage, InboundHrmpMessage, OccupiedCoreAssumption, + PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, + ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, }; use sc_client_api::HeaderBackend; use sc_transaction_pool_api::OffchainTransactionPoolFactory; @@ -316,9 +319,16 @@ pub trait RuntimeApiSubsystemClient { async fn disabled_validators(&self, at: Hash) -> Result, ApiError>; // === v9 === - /// Get the node features. async fn node_features(&self, at: Hash) -> Result; + + // == v10: Approval voting params == + /// Approval voting configuration parameters + async fn approval_voting_params( + &self, + at: Hash, + session_index: SessionIndex, + ) -> Result; } /// Default implementation of [`RuntimeApiSubsystemClient`] using the client. @@ -575,4 +585,13 @@ where async fn disabled_validators(&self, at: Hash) -> Result, ApiError> { self.client.runtime_api().disabled_validators(at) } + + /// Approval voting configuration parameters + async fn approval_voting_params( + &self, + at: Hash, + _session_index: SessionIndex, + ) -> Result { + self.client.runtime_api().approval_voting_params(at) + } } diff --git a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml index 8e4022a718f..29d36452eee 100644 --- a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml @@ -39,6 +39,3 @@ sc-service = { path = "../../../../../substrate/client/service" } sp-keyring = { path = "../../../../../substrate/primitives/keyring" } tokio = { version = "1.24.2", features = ["macros"] } - -[features] -network-protocol-staging = ["polkadot-cli/network-protocol-staging"] diff --git a/polkadot/primitives/src/runtime_api.rs b/polkadot/primitives/src/runtime_api.rs index 331728b2590..d661005e32f 100644 --- a/polkadot/primitives/src/runtime_api.rs +++ b/polkadot/primitives/src/runtime_api.rs @@ -114,12 +114,14 @@ //! separated from the stable primitives. use crate::{ - async_backing, slashing, vstaging, AsyncBackingParams, BlockNumber, CandidateCommitments, - CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreState, DisputeState, - ExecutorParams, GroupRotationInfo, Hash, OccupiedCoreAssumption, PersistedValidationData, - PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidatorId, ValidatorIndex, - ValidatorSignature, + async_backing, slashing, + vstaging::{self, ApprovalVotingParams}, + AsyncBackingParams, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, + CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Hash, + OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, + SessionIndex, SessionInfo, ValidatorId, ValidatorIndex, ValidatorSignature, }; + use polkadot_core_primitives as pcp; use polkadot_parachain_primitives::primitives as ppp; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; @@ -274,5 +276,10 @@ sp_api::decl_runtime_apis! { /// This is a staging method! Do not use on production runtimes! #[api_version(9)] fn node_features() -> vstaging::NodeFeatures; + + /***** Added in v10 *****/ + /// Approval voting configuration parameters + #[api_version(10)] + fn approval_voting_params() -> ApprovalVotingParams; } } diff --git a/polkadot/primitives/src/v6/mod.rs b/polkadot/primitives/src/v6/mod.rs index 83b590dc320..c3a947644ff 100644 --- a/polkadot/primitives/src/v6/mod.rs +++ b/polkadot/primitives/src/v6/mod.rs @@ -1070,6 +1070,26 @@ impl ApprovalVote { } } +/// A vote of approval for multiple candidates. +#[derive(Clone, RuntimeDebug)] +pub struct ApprovalVoteMultipleCandidates<'a>(pub &'a [CandidateHash]); + +impl<'a> ApprovalVoteMultipleCandidates<'a> { + /// Yields the signing payload for this approval vote. + pub fn signing_payload(&self, session_index: SessionIndex) -> Vec { + const MAGIC: [u8; 4] = *b"APPR"; + // Make this backwards compatible with `ApprovalVote` so if we have just on candidate the + // signature will look the same. + // This gives us the nice benefit that old nodes can still check signatures when len is 1 + // and the new node can check the signature coming from old nodes. + if self.0.len() == 1 { + (MAGIC, self.0.first().expect("QED: we just checked"), session_index).encode() + } else { + (MAGIC, &self.0, session_index).encode() + } + } +} + /// Custom validity errors used in Polkadot while validating transactions. #[repr(u8)] pub enum ValidityError { @@ -1246,25 +1266,42 @@ pub enum DisputeStatement { impl DisputeStatement { /// Get the payload data for this type of dispute statement. - pub fn payload_data(&self, candidate_hash: CandidateHash, session: SessionIndex) -> Vec { - match *self { + /// + /// Returns Error if the candidate_hash is not included in the list of signed + /// candidate from ApprovalCheckingMultipleCandidate. + pub fn payload_data( + &self, + candidate_hash: CandidateHash, + session: SessionIndex, + ) -> Result, ()> { + match self { DisputeStatement::Valid(ValidDisputeStatementKind::Explicit) => - ExplicitDisputeStatement { valid: true, candidate_hash, session }.signing_payload(), + Ok(ExplicitDisputeStatement { valid: true, candidate_hash, session } + .signing_payload()), DisputeStatement::Valid(ValidDisputeStatementKind::BackingSeconded( inclusion_parent, - )) => CompactStatement::Seconded(candidate_hash).signing_payload(&SigningContext { + )) => Ok(CompactStatement::Seconded(candidate_hash).signing_payload(&SigningContext { session_index: session, - parent_hash: inclusion_parent, - }), + parent_hash: *inclusion_parent, + })), DisputeStatement::Valid(ValidDisputeStatementKind::BackingValid(inclusion_parent)) => - CompactStatement::Valid(candidate_hash).signing_payload(&SigningContext { + Ok(CompactStatement::Valid(candidate_hash).signing_payload(&SigningContext { session_index: session, - parent_hash: inclusion_parent, - }), + parent_hash: *inclusion_parent, + })), DisputeStatement::Valid(ValidDisputeStatementKind::ApprovalChecking) => - ApprovalVote(candidate_hash).signing_payload(session), + Ok(ApprovalVote(candidate_hash).signing_payload(session)), + DisputeStatement::Valid( + ValidDisputeStatementKind::ApprovalCheckingMultipleCandidates(candidate_hashes), + ) => + if candidate_hashes.contains(&candidate_hash) { + Ok(ApprovalVoteMultipleCandidates(candidate_hashes).signing_payload(session)) + } else { + Err(()) + }, DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit) => - ExplicitDisputeStatement { valid: false, candidate_hash, session }.signing_payload(), + Ok(ExplicitDisputeStatement { valid: false, candidate_hash, session } + .signing_payload()), } } @@ -1276,7 +1313,7 @@ impl DisputeStatement { session: SessionIndex, validator_signature: &ValidatorSignature, ) -> Result<(), ()> { - let payload = self.payload_data(candidate_hash, session); + let payload = self.payload_data(candidate_hash, session)?; if validator_signature.verify(&payload[..], &validator_public) { Ok(()) @@ -1308,13 +1345,14 @@ impl DisputeStatement { Self::Valid(ValidDisputeStatementKind::BackingValid(_)) => true, Self::Valid(ValidDisputeStatementKind::Explicit) | Self::Valid(ValidDisputeStatementKind::ApprovalChecking) | + Self::Valid(ValidDisputeStatementKind::ApprovalCheckingMultipleCandidates(_)) | Self::Invalid(_) => false, } } } /// Different kinds of statements of validity on a candidate. -#[derive(Encode, Decode, Copy, Clone, PartialEq, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, Clone, PartialEq, RuntimeDebug, TypeInfo)] pub enum ValidDisputeStatementKind { /// An explicit statement issued as part of a dispute. #[codec(index = 0)] @@ -1328,6 +1366,12 @@ pub enum ValidDisputeStatementKind { /// An approval vote from the approval checking phase. #[codec(index = 3)] ApprovalChecking, + /// An approval vote from the new version. + /// We can't create this version untill all nodes + /// have been updated to support it and max_approval_coalesce_count + /// is set to more than 1. + #[codec(index = 4)] + ApprovalCheckingMultipleCandidates(Vec), } /// Different kinds of statements of invalidity on a candidate. diff --git a/polkadot/primitives/src/vstaging/mod.rs b/polkadot/primitives/src/vstaging/mod.rs index 1639dc15e21..630bcf8679a 100644 --- a/polkadot/primitives/src/vstaging/mod.rs +++ b/polkadot/primitives/src/vstaging/mod.rs @@ -17,6 +17,38 @@ //! Staging Primitives. // Put any primitives used by staging APIs functions here +pub use crate::v6::*; +use sp_std::prelude::*; + +use parity_scale_codec::{Decode, Encode}; +use primitives::RuntimeDebug; +use scale_info::TypeInfo; + +/// Approval voting configuration parameters +#[derive( + RuntimeDebug, + Copy, + Clone, + PartialEq, + Encode, + Decode, + TypeInfo, + serde::Serialize, + serde::Deserialize, +)] +pub struct ApprovalVotingParams { + /// The maximum number of candidates `approval-voting` can vote for with + /// a single signatures. + /// + /// Setting it to 1, means we send the approval as soon as we have it available. + pub max_approval_coalesce_count: u32, +} + +impl Default for ApprovalVotingParams { + fn default() -> Self { + Self { max_approval_coalesce_count: 1 } + } +} use bitvec::vec::BitVec; diff --git a/polkadot/roadmap/implementers-guide/src/node/approval/approval-voting.md b/polkadot/roadmap/implementers-guide/src/node/approval/approval-voting.md index 1a17f90d9ba..345b3d2e697 100644 --- a/polkadot/roadmap/implementers-guide/src/node/approval/approval-voting.md +++ b/polkadot/roadmap/implementers-guide/src/node/approval/approval-voting.md @@ -4,10 +4,13 @@ Reading the [section on the approval protocol](../../protocol-approval.md) will aims of this subsystem. Approval votes are split into two parts: Assignments and Approvals. Validators first broadcast their assignment to -indicate intent to check a candidate. Upon successfully checking, they broadcast an approval vote. If a validator -doesn't broadcast their approval vote shortly after issuing an assignment, this is an indication that they are being -prevented from recovering or validating the block data and that more validators should self-select to check the -candidate. This is known as a "no-show". +indicate intent to check a candidate. Upon successfully checking, they don't immediately send the vote instead +they queue the check for a short period of time `MAX_APPROVAL_COALESCE_WAIT_TICKS` to give the opportunity of the +validator to vote for more than one candidate. Once MAX_APPROVAL_COALESCE_WAIT_TICKS have passed or at least +`MAX_APPROVAL_COALESCE_COUNT` are ready they broadcast an approval vote for all candidates. If a validator +doesn't broadcast their approval vote shortly after issuing an assignment, this is an indication that they are +being prevented from recovering or validating the block data and that more validators should self-select to +check the candidate. This is known as a "no-show". The core of this subsystem is a Tick-based timer loop, where Ticks are 500ms. We also reason about time in terms of `DelayTranche`s, which measure the number of ticks elapsed since a block was produced. We track metadata for all @@ -120,6 +123,13 @@ struct BlockEntry { // this block. The block can be considered approved has all bits set to 1 approved_bitfield: Bitfield, children: Vec, + // A list of candidates we have checked, but didn't not sign and + // advertise the vote yet. + candidates_pending_signature: BTreeMap, + // Assignments we already distributed. A 1 bit means the candidate index for which + // we already have sent out an assignment. We need this to avoid distributing + // multiple core assignments more than once. + distributed_assignments: Bitfield, } // slot_duration * 2 + DelayTranche gives the number of delay tranches since the @@ -303,12 +313,12 @@ entry. The cert itself contains information necessary to determine the candidate On receiving a `CheckAndImportApproval(indirect_approval_vote, response_channel)` message: * Fetch the `BlockEntry` from the indirect approval vote's `block_hash`. If none, return `ApprovalCheckResult::Bad`. - * Fetch the `CandidateEntry` from the indirect approval vote's `candidate_index`. If the block did not trigger + * Fetch all `CandidateEntry` from the indirect approval vote's `candidate_indices`. If the block did not trigger inclusion of enough candidates, return `ApprovalCheckResult::Bad`. - * Construct a `SignedApprovalVote` using the candidate hash and check against the validator's approval key, based on - the session info of the block. If invalid or no such validator, return `ApprovalCheckResult::Bad`. + * Construct a `SignedApprovalVote` using the candidates hashes and check against the validator's approval key, + based on the session info of the block. If invalid or no such validator, return `ApprovalCheckResult::Bad`. * Send `ApprovalCheckResult::Accepted` - * [Import the checked approval vote](#import-checked-approval) + * [Import the checked approval vote](#import-checked-approval) for all candidates #### `ApprovalVotingMessage::ApprovedAncestor` @@ -402,10 +412,25 @@ On receiving an `ApprovedAncestor(Hash, BlockNumber, response_channel)`: #### Issue Approval Vote * Fetch the block entry and candidate entry. Ignore if `None` - we've probably just lost a race with finality. - * Construct a `SignedApprovalVote` with the validator index for the session. * [Import the checked approval vote](#import-checked-approval). It is "checked" as we've just issued the signature. - * Construct a `IndirectSignedApprovalVote` using the information about the vote. - * Dispatch `ApprovalDistributionMessage::DistributeApproval`. + * IF `MAX_APPROVAL_COALESCE_COUNT` candidates are in the waiting queue + * Construct a `SignedApprovalVote` with the validator index for the session and all candidate hashes in the waiting queue. + * Construct a `IndirectSignedApprovalVote` using the information about the vote. + * Dispatch `ApprovalDistributionMessage::DistributeApproval`. + * ELSE + * Queue the candidate in the `BlockEntry::candidates_pending_signature` + * Arm a per BlockEntry timer with latest tick we can send the vote. + +### Delayed vote distribution + * [Issue Approval Vote](#issue-approval-vote) arms once a per block timer if there are no requirements to send the + vote immediately. + * When the timer wakes up it will either: + * IF there is a candidate in the queue past its sending tick: + * Construct a `SignedApprovalVote` with the validator index for the session and all candidate hashes in the waiting queue. + * Construct a `IndirectSignedApprovalVote` using the information about the vote. + * Dispatch `ApprovalDistributionMessage::DistributeApproval`. + * ELSE + * Re-arm the timer with latest tick we have the send a the vote. ### Determining Approval of Candidate diff --git a/polkadot/roadmap/implementers-guide/src/protocol-approval.md b/polkadot/roadmap/implementers-guide/src/protocol-approval.md index 70bc0233d65..b6aa16646ad 100644 --- a/polkadot/roadmap/implementers-guide/src/protocol-approval.md +++ b/polkadot/roadmap/implementers-guide/src/protocol-approval.md @@ -296,6 +296,18 @@ provide somewhat more security. TODO: When? Is this optimal for the network? etc. +## Approval coalescing +To reduce the necessary network bandwidth and cpu time when a validator has more than one candidate to approve we are +doing our best effort to send a single message that approves all available candidates with a single signature. +The implemented heuristic, is that each time we are ready to create a signature and send a vote for a candidate we +delay sending it until one of three things happen: +- We gathered a maximum of `MAX_APPROVAL_COALESCE_COUNT` candidates that we have already checked and we are + ready to sign approval for. +- `MAX_APPROVAL_COALESCE_WAIT_TICKS` have passed since checking oldest candidate and we were ready to sign + and send the approval message. +- We are already in the last third of the no-show period in order to avoid creating accidental no-shows, which in + turn might trigger other assignments. + ## On-chain verification We should verify approval on-chain to reward approval checkers. We therefore require the "no show" timeout to be longer diff --git a/polkadot/runtime/parachains/src/builder.rs b/polkadot/runtime/parachains/src/builder.rs index dced24df0ae..23916bbdc8a 100644 --- a/polkadot/runtime/parachains/src/builder.rs +++ b/polkadot/runtime/parachains/src/builder.rs @@ -636,7 +636,7 @@ impl BenchBuilder { } else { DisputeStatement::Valid(ValidDisputeStatementKind::Explicit) }; - let data = dispute_statement.payload_data(candidate_hash, session); + let data = dispute_statement.payload_data(candidate_hash, session).unwrap(); let statement_sig = validator_public.sign(&data).unwrap(); (dispute_statement, ValidatorIndex(validator_index), statement_sig) diff --git a/polkadot/runtime/parachains/src/configuration.rs b/polkadot/runtime/parachains/src/configuration.rs index bff9cc34b4f..272c227dfef 100644 --- a/polkadot/runtime/parachains/src/configuration.rs +++ b/polkadot/runtime/parachains/src/configuration.rs @@ -26,8 +26,9 @@ use polkadot_parachain_primitives::primitives::{ MAX_HORIZONTAL_MESSAGE_NUM, MAX_UPWARD_MESSAGE_NUM, }; use primitives::{ - vstaging::NodeFeatures, AsyncBackingParams, Balance, ExecutorParamError, ExecutorParams, - SessionIndex, LEGACY_MIN_BACKING_VOTES, MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, MAX_POV_SIZE, + vstaging::{ApprovalVotingParams, NodeFeatures}, + AsyncBackingParams, Balance, ExecutorParamError, ExecutorParams, SessionIndex, + LEGACY_MIN_BACKING_VOTES, MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, MAX_POV_SIZE, ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, }; use sp_runtime::{traits::Zero, Perbill}; @@ -263,6 +264,8 @@ pub struct HostConfiguration { pub minimum_backing_votes: u32, /// Node features enablement. pub node_features: NodeFeatures, + /// Params used by approval-voting + pub approval_voting_params: ApprovalVotingParams, } impl> Default for HostConfiguration { @@ -308,6 +311,7 @@ impl> Default for HostConfiguration /// v8-v9: /// v9-v10: - const STORAGE_VERSION: StorageVersion = StorageVersion::new(10); + /// v10-11: + const STORAGE_VERSION: StorageVersion = StorageVersion::new(11); #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] @@ -1191,6 +1196,7 @@ pub mod pallet { config.on_demand_ttl = new; }) } + /// Set the minimum backing votes threshold. #[pallet::call_index(52)] #[pallet::weight(( @@ -1203,6 +1209,7 @@ pub mod pallet { config.minimum_backing_votes = new; }) } + /// Set/Unset a node feature. #[pallet::call_index(53)] #[pallet::weight(( @@ -1220,6 +1227,22 @@ pub mod pallet { config.node_features.set(index, value); }) } + + /// Set approval-voting-params. + #[pallet::call_index(54)] + #[pallet::weight(( + T::WeightInfo::set_config_with_executor_params(), + DispatchClass::Operational, + ))] + pub fn set_approval_voting_params( + origin: OriginFor, + new: ApprovalVotingParams, + ) -> DispatchResult { + ensure_root(origin)?; + Self::schedule_config_update(|config| { + config.approval_voting_params = new; + }) + } } #[pallet::hooks] diff --git a/polkadot/runtime/parachains/src/configuration/migration.rs b/polkadot/runtime/parachains/src/configuration/migration.rs index db323d3aad9..2838b73092d 100644 --- a/polkadot/runtime/parachains/src/configuration/migration.rs +++ b/polkadot/runtime/parachains/src/configuration/migration.rs @@ -17,6 +17,7 @@ //! A module that is responsible for migration of storage. pub mod v10; +pub mod v11; pub mod v6; pub mod v7; pub mod v8; diff --git a/polkadot/runtime/parachains/src/configuration/migration/v10.rs b/polkadot/runtime/parachains/src/configuration/migration/v10.rs index 3c934082dc1..cf228610e5c 100644 --- a/polkadot/runtime/parachains/src/configuration/migration/v10.rs +++ b/polkadot/runtime/parachains/src/configuration/migration/v10.rs @@ -16,17 +16,121 @@ //! A module that is responsible for migration of storage. -use crate::configuration::{self, Config, Pallet}; +use crate::configuration::{Config, Pallet}; use frame_support::{pallet_prelude::*, traits::Defensive, weights::Weight}; use frame_system::pallet_prelude::BlockNumberFor; -use primitives::{vstaging::NodeFeatures, SessionIndex}; +use primitives::{ + vstaging::NodeFeatures, AsyncBackingParams, Balance, ExecutorParams, SessionIndex, + LEGACY_MIN_BACKING_VOTES, ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, +}; +use sp_runtime::Perbill; use sp_std::vec::Vec; use frame_support::traits::OnRuntimeUpgrade; use super::v9::V9HostConfiguration; +// All configuration of the runtime with respect to paras. +#[derive(Clone, Encode, PartialEq, Decode, Debug)] +pub struct V10HostConfiguration { + pub max_code_size: u32, + pub max_head_data_size: u32, + pub max_upward_queue_count: u32, + pub max_upward_queue_size: u32, + pub max_upward_message_size: u32, + pub max_upward_message_num_per_candidate: u32, + pub hrmp_max_message_num_per_candidate: u32, + pub validation_upgrade_cooldown: BlockNumber, + pub validation_upgrade_delay: BlockNumber, + pub async_backing_params: AsyncBackingParams, + pub max_pov_size: u32, + pub max_downward_message_size: u32, + pub hrmp_max_parachain_outbound_channels: u32, + pub hrmp_sender_deposit: Balance, + pub hrmp_recipient_deposit: Balance, + pub hrmp_channel_max_capacity: u32, + pub hrmp_channel_max_total_size: u32, + pub hrmp_max_parachain_inbound_channels: u32, + pub hrmp_channel_max_message_size: u32, + pub executor_params: ExecutorParams, + pub code_retention_period: BlockNumber, + pub on_demand_cores: u32, + pub on_demand_retries: u32, + pub on_demand_queue_max_size: u32, + pub on_demand_target_queue_utilization: Perbill, + pub on_demand_fee_variability: Perbill, + pub on_demand_base_fee: Balance, + pub on_demand_ttl: BlockNumber, + pub group_rotation_frequency: BlockNumber, + pub paras_availability_period: BlockNumber, + pub scheduling_lookahead: u32, + pub max_validators_per_core: Option, + pub max_validators: Option, + pub dispute_period: SessionIndex, + pub dispute_post_conclusion_acceptance_period: BlockNumber, + pub no_show_slots: u32, + pub n_delay_tranches: u32, + pub zeroth_delay_tranche_width: u32, + pub needed_approvals: u32, + pub relay_vrf_modulo_samples: u32, + pub pvf_voting_ttl: SessionIndex, + pub minimum_validation_upgrade_delay: BlockNumber, + pub minimum_backing_votes: u32, + pub node_features: NodeFeatures, +} -type V10HostConfiguration = configuration::HostConfiguration; +impl> Default for V10HostConfiguration { + fn default() -> Self { + Self { + async_backing_params: AsyncBackingParams { + max_candidate_depth: 0, + allowed_ancestry_len: 0, + }, + group_rotation_frequency: 1u32.into(), + paras_availability_period: 1u32.into(), + no_show_slots: 1u32.into(), + validation_upgrade_cooldown: Default::default(), + validation_upgrade_delay: 2u32.into(), + code_retention_period: Default::default(), + max_code_size: Default::default(), + max_pov_size: Default::default(), + max_head_data_size: Default::default(), + on_demand_cores: Default::default(), + on_demand_retries: Default::default(), + scheduling_lookahead: 1, + max_validators_per_core: Default::default(), + max_validators: None, + dispute_period: 6, + dispute_post_conclusion_acceptance_period: 100.into(), + n_delay_tranches: Default::default(), + zeroth_delay_tranche_width: Default::default(), + needed_approvals: Default::default(), + relay_vrf_modulo_samples: Default::default(), + max_upward_queue_count: Default::default(), + max_upward_queue_size: Default::default(), + max_downward_message_size: Default::default(), + max_upward_message_size: Default::default(), + max_upward_message_num_per_candidate: Default::default(), + hrmp_sender_deposit: Default::default(), + hrmp_recipient_deposit: Default::default(), + hrmp_channel_max_capacity: Default::default(), + hrmp_channel_max_total_size: Default::default(), + hrmp_max_parachain_inbound_channels: Default::default(), + hrmp_channel_max_message_size: Default::default(), + hrmp_max_parachain_outbound_channels: Default::default(), + hrmp_max_message_num_per_candidate: Default::default(), + pvf_voting_ttl: 2u32.into(), + minimum_validation_upgrade_delay: 2.into(), + executor_params: Default::default(), + on_demand_queue_max_size: ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, + on_demand_base_fee: 10_000_000u128, + on_demand_fee_variability: Perbill::from_percent(3), + on_demand_target_queue_utilization: Perbill::from_percent(25), + on_demand_ttl: 5u32.into(), + minimum_backing_votes: LEGACY_MIN_BACKING_VOTES, + node_features: NodeFeatures::EMPTY, + } + } +} mod v9 { use super::*; diff --git a/polkadot/runtime/parachains/src/configuration/migration/v11.rs b/polkadot/runtime/parachains/src/configuration/migration/v11.rs new file mode 100644 index 00000000000..b7dec7070f9 --- /dev/null +++ b/polkadot/runtime/parachains/src/configuration/migration/v11.rs @@ -0,0 +1,329 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! A module that is responsible for migration of storage. + +use crate::configuration::{self, Config, Pallet}; +use frame_support::{ + migrations::VersionedMigration, pallet_prelude::*, traits::Defensive, weights::Weight, +}; +use frame_system::pallet_prelude::BlockNumberFor; +use primitives::{vstaging::ApprovalVotingParams, SessionIndex}; +use sp_std::vec::Vec; + +use frame_support::traits::OnRuntimeUpgrade; + +use super::v10::V10HostConfiguration; +type V11HostConfiguration = configuration::HostConfiguration; + +mod v10 { + use super::*; + + #[frame_support::storage_alias] + pub(crate) type ActiveConfig = + StorageValue, V10HostConfiguration>, OptionQuery>; + + #[frame_support::storage_alias] + pub(crate) type PendingConfigs = StorageValue< + Pallet, + Vec<(SessionIndex, V10HostConfiguration>)>, + OptionQuery, + >; +} + +mod v11 { + use super::*; + + #[frame_support::storage_alias] + pub(crate) type ActiveConfig = + StorageValue, V11HostConfiguration>, OptionQuery>; + + #[frame_support::storage_alias] + pub(crate) type PendingConfigs = StorageValue< + Pallet, + Vec<(SessionIndex, V11HostConfiguration>)>, + OptionQuery, + >; +} + +pub type MigrateToV11 = VersionedMigration< + 10, + 11, + UncheckedMigrateToV11, + Pallet, + ::DbWeight, +>; + +pub struct UncheckedMigrateToV11(sp_std::marker::PhantomData); +impl OnRuntimeUpgrade for UncheckedMigrateToV11 { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { + log::trace!(target: crate::configuration::LOG_TARGET, "Running pre_upgrade() for HostConfiguration MigrateToV11"); + Ok(Vec::new()) + } + + fn on_runtime_upgrade() -> Weight { + log::info!(target: configuration::LOG_TARGET, "HostConfiguration MigrateToV11 started"); + let weight_consumed = migrate_to_v11::(); + + log::info!(target: configuration::LOG_TARGET, "HostConfiguration MigrateToV11 executed successfully"); + + weight_consumed + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { + log::trace!(target: crate::configuration::LOG_TARGET, "Running post_upgrade() for HostConfiguration MigrateToV11"); + ensure!( + StorageVersion::get::>() >= 11, + "Storage version should be >= 11 after the migration" + ); + + Ok(()) + } +} + +fn migrate_to_v11() -> Weight { + // Unusual formatting is justified: + // - make it easier to verify that fields assign what they supposed to assign. + // - this code is transient and will be removed after all migrations are done. + // - this code is important enough to optimize for legibility sacrificing consistency. + #[rustfmt::skip] + let translate = + |pre: V10HostConfiguration>| -> + V11HostConfiguration> + { + V11HostConfiguration { +max_code_size : pre.max_code_size, +max_head_data_size : pre.max_head_data_size, +max_upward_queue_count : pre.max_upward_queue_count, +max_upward_queue_size : pre.max_upward_queue_size, +max_upward_message_size : pre.max_upward_message_size, +max_upward_message_num_per_candidate : pre.max_upward_message_num_per_candidate, +hrmp_max_message_num_per_candidate : pre.hrmp_max_message_num_per_candidate, +validation_upgrade_cooldown : pre.validation_upgrade_cooldown, +validation_upgrade_delay : pre.validation_upgrade_delay, +max_pov_size : pre.max_pov_size, +max_downward_message_size : pre.max_downward_message_size, +hrmp_sender_deposit : pre.hrmp_sender_deposit, +hrmp_recipient_deposit : pre.hrmp_recipient_deposit, +hrmp_channel_max_capacity : pre.hrmp_channel_max_capacity, +hrmp_channel_max_total_size : pre.hrmp_channel_max_total_size, +hrmp_max_parachain_inbound_channels : pre.hrmp_max_parachain_inbound_channels, +hrmp_max_parachain_outbound_channels : pre.hrmp_max_parachain_outbound_channels, +hrmp_channel_max_message_size : pre.hrmp_channel_max_message_size, +code_retention_period : pre.code_retention_period, +on_demand_cores : pre.on_demand_cores, +on_demand_retries : pre.on_demand_retries, +group_rotation_frequency : pre.group_rotation_frequency, +paras_availability_period : pre.paras_availability_period, +scheduling_lookahead : pre.scheduling_lookahead, +max_validators_per_core : pre.max_validators_per_core, +max_validators : pre.max_validators, +dispute_period : pre.dispute_period, +dispute_post_conclusion_acceptance_period: pre.dispute_post_conclusion_acceptance_period, +no_show_slots : pre.no_show_slots, +n_delay_tranches : pre.n_delay_tranches, +zeroth_delay_tranche_width : pre.zeroth_delay_tranche_width, +needed_approvals : pre.needed_approvals, +relay_vrf_modulo_samples : pre.relay_vrf_modulo_samples, +pvf_voting_ttl : pre.pvf_voting_ttl, +minimum_validation_upgrade_delay : pre.minimum_validation_upgrade_delay, +async_backing_params : pre.async_backing_params, +executor_params : pre.executor_params, +on_demand_queue_max_size : pre.on_demand_queue_max_size, +on_demand_base_fee : pre.on_demand_base_fee, +on_demand_fee_variability : pre.on_demand_fee_variability, +on_demand_target_queue_utilization : pre.on_demand_target_queue_utilization, +on_demand_ttl : pre.on_demand_ttl, +minimum_backing_votes : pre.minimum_backing_votes, +node_features : pre.node_features, +approval_voting_params : ApprovalVotingParams { + max_approval_coalesce_count: 1, + } + } + }; + + let v10 = v10::ActiveConfig::::get() + .defensive_proof("Could not decode old config") + .unwrap_or_default(); + let v11 = translate(v10); + v11::ActiveConfig::::set(Some(v11)); + + // Allowed to be empty. + let pending_v9 = v10::PendingConfigs::::get().unwrap_or_default(); + let mut pending_v10 = Vec::new(); + + for (session, v10) in pending_v9.into_iter() { + let v11 = translate(v10); + pending_v10.push((session, v11)); + } + v11::PendingConfigs::::set(Some(pending_v10.clone())); + + let num_configs = (pending_v10.len() + 1) as u64; + T::DbWeight::get().reads_writes(num_configs, num_configs) +} + +#[cfg(test)] +mod tests { + use primitives::LEGACY_MIN_BACKING_VOTES; + + use super::*; + use crate::mock::{new_test_ext, Test}; + + #[test] + fn v11_deserialized_from_actual_data() { + // Example how to get new `raw_config`: + // We'll obtain the raw_config at a specified a block + // Steps: + // 1. Go to Polkadot.js -> Developer -> Chain state -> Storage: https://polkadot.js.org/apps/#/chainstate + // 2. Set these parameters: + // 2.1. selected state query: configuration; activeConfig(): + // PolkadotRuntimeParachainsConfigurationHostConfiguration + // 2.2. blockhash to query at: + // 0xf89d3ab5312c5f70d396dc59612f0aa65806c798346f9db4b35278baed2e0e53 (the hash of + // the block) + // 2.3. Note the value of encoded storage key -> + // 0x06de3d8a54d27e44a9d5ce189618f22db4b49d95320d9021994c850f25b8e385 for the + // referenced block. + // 2.4. You'll also need the decoded values to update the test. + // 3. Go to Polkadot.js -> Developer -> Chain state -> Raw storage + // 3.1 Enter the encoded storage key and you get the raw config. + + // This exceeds the maximal line width length, but that's fine, since this is not code and + // doesn't need to be read and also leaving it as one line allows to easily copy it. + let raw_config = + hex_literal::hex![" + 0000300000800000080000000000100000c8000005000000050000000200000002000000000000000000000000005000000010000400000000000000000000000000000000000000000000000000000000000000000000000800000000200000040000000000100000b004000000000000000000001027000080b2e60e80c3c9018096980000000000000000000000000005000000140000000400000001000000010100000000060000006400000002000000190000000000000002000000020000000200000005000000020000000001000000" + ]; + + let v11 = + V11HostConfiguration::::decode(&mut &raw_config[..]).unwrap(); + + // We check only a sample of the values here. If we missed any fields or messed up data + // types that would skew all the fields coming after. + assert_eq!(v11.max_code_size, 3_145_728); + assert_eq!(v11.validation_upgrade_cooldown, 2); + assert_eq!(v11.max_pov_size, 5_242_880); + assert_eq!(v11.hrmp_channel_max_message_size, 1_048_576); + assert_eq!(v11.n_delay_tranches, 25); + assert_eq!(v11.minimum_validation_upgrade_delay, 5); + assert_eq!(v11.group_rotation_frequency, 20); + assert_eq!(v11.on_demand_cores, 0); + assert_eq!(v11.on_demand_base_fee, 10_000_000); + assert_eq!(v11.minimum_backing_votes, LEGACY_MIN_BACKING_VOTES); + assert_eq!(v11.approval_voting_params.max_approval_coalesce_count, 1); + } + + #[test] + fn test_migrate_to_v11() { + // Host configuration has lots of fields. However, in this migration we only add one + // field. The most important part to check are a couple of the last fields. We also pick + // extra fields to check arbitrarily, e.g. depending on their position (i.e. the middle) and + // also their type. + // + // We specify only the picked fields and the rest should be provided by the `Default` + // implementation. That implementation is copied over between the two types and should work + // fine. + let v10 = V10HostConfiguration:: { + needed_approvals: 69, + paras_availability_period: 55, + hrmp_recipient_deposit: 1337, + max_pov_size: 1111, + minimum_validation_upgrade_delay: 20, + ..Default::default() + }; + + let mut pending_configs = Vec::new(); + pending_configs.push((100, v10.clone())); + pending_configs.push((300, v10.clone())); + + new_test_ext(Default::default()).execute_with(|| { + // Implant the v10 version in the state. + v10::ActiveConfig::::set(Some(v10)); + v10::PendingConfigs::::set(Some(pending_configs)); + + migrate_to_v11::(); + + let v11 = v11::ActiveConfig::::get().unwrap(); + assert_eq!(v11.approval_voting_params.max_approval_coalesce_count, 1); + + let mut configs_to_check = v11::PendingConfigs::::get().unwrap(); + configs_to_check.push((0, v11.clone())); + + for (_, v10) in configs_to_check { + #[rustfmt::skip] + { + assert_eq!(v10.max_code_size , v11.max_code_size); + assert_eq!(v10.max_head_data_size , v11.max_head_data_size); + assert_eq!(v10.max_upward_queue_count , v11.max_upward_queue_count); + assert_eq!(v10.max_upward_queue_size , v11.max_upward_queue_size); + assert_eq!(v10.max_upward_message_size , v11.max_upward_message_size); + assert_eq!(v10.max_upward_message_num_per_candidate , v11.max_upward_message_num_per_candidate); + assert_eq!(v10.hrmp_max_message_num_per_candidate , v11.hrmp_max_message_num_per_candidate); + assert_eq!(v10.validation_upgrade_cooldown , v11.validation_upgrade_cooldown); + assert_eq!(v10.validation_upgrade_delay , v11.validation_upgrade_delay); + assert_eq!(v10.max_pov_size , v11.max_pov_size); + assert_eq!(v10.max_downward_message_size , v11.max_downward_message_size); + assert_eq!(v10.hrmp_max_parachain_outbound_channels , v11.hrmp_max_parachain_outbound_channels); + assert_eq!(v10.hrmp_sender_deposit , v11.hrmp_sender_deposit); + assert_eq!(v10.hrmp_recipient_deposit , v11.hrmp_recipient_deposit); + assert_eq!(v10.hrmp_channel_max_capacity , v11.hrmp_channel_max_capacity); + assert_eq!(v10.hrmp_channel_max_total_size , v11.hrmp_channel_max_total_size); + assert_eq!(v10.hrmp_max_parachain_inbound_channels , v11.hrmp_max_parachain_inbound_channels); + assert_eq!(v10.hrmp_channel_max_message_size , v11.hrmp_channel_max_message_size); + assert_eq!(v10.code_retention_period , v11.code_retention_period); + assert_eq!(v10.on_demand_cores , v11.on_demand_cores); + assert_eq!(v10.on_demand_retries , v11.on_demand_retries); + assert_eq!(v10.group_rotation_frequency , v11.group_rotation_frequency); + assert_eq!(v10.paras_availability_period , v11.paras_availability_period); + assert_eq!(v10.scheduling_lookahead , v11.scheduling_lookahead); + assert_eq!(v10.max_validators_per_core , v11.max_validators_per_core); + assert_eq!(v10.max_validators , v11.max_validators); + assert_eq!(v10.dispute_period , v11.dispute_period); + assert_eq!(v10.no_show_slots , v11.no_show_slots); + assert_eq!(v10.n_delay_tranches , v11.n_delay_tranches); + assert_eq!(v10.zeroth_delay_tranche_width , v11.zeroth_delay_tranche_width); + assert_eq!(v10.needed_approvals , v11.needed_approvals); + assert_eq!(v10.relay_vrf_modulo_samples , v11.relay_vrf_modulo_samples); + assert_eq!(v10.pvf_voting_ttl , v11.pvf_voting_ttl); + assert_eq!(v10.minimum_validation_upgrade_delay , v11.minimum_validation_upgrade_delay); + assert_eq!(v10.async_backing_params.allowed_ancestry_len, v11.async_backing_params.allowed_ancestry_len); + assert_eq!(v10.async_backing_params.max_candidate_depth , v11.async_backing_params.max_candidate_depth); + assert_eq!(v10.executor_params , v11.executor_params); + assert_eq!(v10.minimum_backing_votes , v11.minimum_backing_votes); + }; // ; makes this a statement. `rustfmt::skip` cannot be put on an expression. + } + }); + } + + // Test that migration doesn't panic in case there're no pending configurations upgrades in + // pallet's storage. + #[test] + fn test_migrate_to_v11_no_pending() { + let v10 = V10HostConfiguration::::default(); + + new_test_ext(Default::default()).execute_with(|| { + // Implant the v10 version in the state. + v10::ActiveConfig::::set(Some(v10)); + // Ensure there're no pending configs. + v11::PendingConfigs::::set(None); + + // Shouldn't fail. + migrate_to_v11::(); + }); + } +} diff --git a/polkadot/runtime/parachains/src/configuration/migration/v8.rs b/polkadot/runtime/parachains/src/configuration/migration/v8.rs index d1bc9005112..537dfa9abd7 100644 --- a/polkadot/runtime/parachains/src/configuration/migration/v8.rs +++ b/polkadot/runtime/parachains/src/configuration/migration/v8.rs @@ -250,7 +250,7 @@ on_demand_fee_variability : Perbill::from_percent(3), on_demand_target_queue_utilization : Perbill::from_percent(25), on_demand_ttl : 5u32.into(), } - }; +}; let v7 = v7::ActiveConfig::::get() .defensive_proof("Could not decode old config") diff --git a/polkadot/runtime/parachains/src/configuration/tests.rs b/polkadot/runtime/parachains/src/configuration/tests.rs index b62a45355e1..d88572d3b55 100644 --- a/polkadot/runtime/parachains/src/configuration/tests.rs +++ b/polkadot/runtime/parachains/src/configuration/tests.rs @@ -313,6 +313,7 @@ fn setting_pending_config_members() { pvf_voting_ttl: 3, minimum_validation_upgrade_delay: 20, executor_params: Default::default(), + approval_voting_params: ApprovalVotingParams { max_approval_coalesce_count: 1 }, on_demand_queue_max_size: 10_000u32, on_demand_base_fee: 10_000_000u128, on_demand_fee_variability: Perbill::from_percent(3), diff --git a/polkadot/runtime/parachains/src/disputes.rs b/polkadot/runtime/parachains/src/disputes.rs index cf2e99e7359..c2383dad305 100644 --- a/polkadot/runtime/parachains/src/disputes.rs +++ b/polkadot/runtime/parachains/src/disputes.rs @@ -25,11 +25,11 @@ use frame_system::pallet_prelude::*; use parity_scale_codec::{Decode, Encode}; use polkadot_runtime_metrics::get_current_time; use primitives::{ - byzantine_threshold, supermajority_threshold, ApprovalVote, CandidateHash, - CheckedDisputeStatementSet, CheckedMultiDisputeStatementSet, CompactStatement, ConsensusLog, - DisputeState, DisputeStatement, DisputeStatementSet, ExplicitDisputeStatement, - InvalidDisputeStatementKind, MultiDisputeStatementSet, SessionIndex, SigningContext, - ValidDisputeStatementKind, ValidatorId, ValidatorIndex, ValidatorSignature, + byzantine_threshold, supermajority_threshold, vstaging::ApprovalVoteMultipleCandidates, + ApprovalVote, CandidateHash, CheckedDisputeStatementSet, CheckedMultiDisputeStatementSet, + CompactStatement, ConsensusLog, DisputeState, DisputeStatement, DisputeStatementSet, + ExplicitDisputeStatement, InvalidDisputeStatementKind, MultiDisputeStatementSet, SessionIndex, + SigningContext, ValidDisputeStatementKind, ValidatorId, ValidatorIndex, ValidatorSignature, }; use scale_info::TypeInfo; use sp_runtime::{ @@ -952,6 +952,8 @@ impl Pallet { None => return StatementSetFilter::RemoveAll, }; + let config = >::config(); + let n_validators = session_info.validators.len(); // Check for ancient. @@ -1015,7 +1017,14 @@ impl Pallet { set.session, statement, signature, + // This is here to prevent malicious nodes of generating + // `ValidDisputeStatementKind::ApprovalCheckingMultipleCandidates` before that + // is enabled, via setting `max_approval_coalesce_count` in the parachain host + // config. + config.approval_voting_params.max_approval_coalesce_count > 1, ) { + log::warn!("Failed to check dispute signature"); + importer.undo(undo); filter.remove_index(i); continue @@ -1260,22 +1269,31 @@ fn check_signature( session: SessionIndex, statement: &DisputeStatement, validator_signature: &ValidatorSignature, + approval_multiple_candidates_enabled: bool, ) -> Result<(), ()> { - let payload = match *statement { + let payload = match statement { DisputeStatement::Valid(ValidDisputeStatementKind::Explicit) => ExplicitDisputeStatement { valid: true, candidate_hash, session }.signing_payload(), DisputeStatement::Valid(ValidDisputeStatementKind::BackingSeconded(inclusion_parent)) => CompactStatement::Seconded(candidate_hash).signing_payload(&SigningContext { session_index: session, - parent_hash: inclusion_parent, + parent_hash: *inclusion_parent, }), DisputeStatement::Valid(ValidDisputeStatementKind::BackingValid(inclusion_parent)) => CompactStatement::Valid(candidate_hash).signing_payload(&SigningContext { session_index: session, - parent_hash: inclusion_parent, + parent_hash: *inclusion_parent, }), DisputeStatement::Valid(ValidDisputeStatementKind::ApprovalChecking) => ApprovalVote(candidate_hash).signing_payload(session), + DisputeStatement::Valid(ValidDisputeStatementKind::ApprovalCheckingMultipleCandidates( + candidates, + )) => + if approval_multiple_candidates_enabled && candidates.contains(&candidate_hash) { + ApprovalVoteMultipleCandidates(candidates).signing_payload(session) + } else { + return Err(()) + }, DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit) => ExplicitDisputeStatement { valid: false, candidate_hash, session }.signing_payload(), }; diff --git a/polkadot/runtime/parachains/src/disputes/tests.rs b/polkadot/runtime/parachains/src/disputes/tests.rs index 0757084084f..1f3f00132d6 100644 --- a/polkadot/runtime/parachains/src/disputes/tests.rs +++ b/polkadot/runtime/parachains/src/disputes/tests.rs @@ -1500,7 +1500,8 @@ fn test_check_signature() { candidate_hash, session, &statement_1, - &signed_1 + &signed_1, + true, ) .is_ok()); assert!(check_signature( @@ -1508,7 +1509,8 @@ fn test_check_signature() { candidate_hash, session, &statement_1, - &signed_1 + &signed_1, + true ) .is_err()); assert!(check_signature( @@ -1516,7 +1518,8 @@ fn test_check_signature() { wrong_candidate_hash, session, &statement_1, - &signed_1 + &signed_1, + true, ) .is_err()); assert!(check_signature( @@ -1524,7 +1527,8 @@ fn test_check_signature() { candidate_hash, wrong_session, &statement_1, - &signed_1 + &signed_1, + true ) .is_err()); assert!(check_signature( @@ -1532,7 +1536,8 @@ fn test_check_signature() { candidate_hash, session, &statement_2, - &signed_1 + &signed_1, + true, ) .is_err()); assert!(check_signature( @@ -1540,7 +1545,8 @@ fn test_check_signature() { candidate_hash, session, &statement_3, - &signed_1 + &signed_1, + true ) .is_err()); assert!(check_signature( @@ -1548,7 +1554,8 @@ fn test_check_signature() { candidate_hash, session, &statement_4, - &signed_1 + &signed_1, + true ) .is_err()); assert!(check_signature( @@ -1556,7 +1563,8 @@ fn test_check_signature() { candidate_hash, session, &statement_5, - &signed_1 + &signed_1, + true, ) .is_err()); @@ -1565,7 +1573,8 @@ fn test_check_signature() { candidate_hash, session, &statement_2, - &signed_2 + &signed_2, + true, ) .is_ok()); assert!(check_signature( @@ -1573,7 +1582,8 @@ fn test_check_signature() { candidate_hash, session, &statement_2, - &signed_2 + &signed_2, + true, ) .is_err()); assert!(check_signature( @@ -1581,7 +1591,8 @@ fn test_check_signature() { wrong_candidate_hash, session, &statement_2, - &signed_2 + &signed_2, + true, ) .is_err()); assert!(check_signature( @@ -1589,7 +1600,8 @@ fn test_check_signature() { candidate_hash, wrong_session, &statement_2, - &signed_2 + &signed_2, + true ) .is_err()); assert!(check_signature( @@ -1597,7 +1609,8 @@ fn test_check_signature() { candidate_hash, session, &wrong_statement_2, - &signed_2 + &signed_2, + true, ) .is_err()); assert!(check_signature( @@ -1605,7 +1618,8 @@ fn test_check_signature() { candidate_hash, session, &statement_1, - &signed_2 + &signed_2, + true, ) .is_err()); assert!(check_signature( @@ -1613,7 +1627,8 @@ fn test_check_signature() { candidate_hash, session, &statement_3, - &signed_2 + &signed_2, + true, ) .is_err()); assert!(check_signature( @@ -1621,7 +1636,8 @@ fn test_check_signature() { candidate_hash, session, &statement_4, - &signed_2 + &signed_2, + true, ) .is_err()); assert!(check_signature( @@ -1629,7 +1645,8 @@ fn test_check_signature() { candidate_hash, session, &statement_5, - &signed_2 + &signed_2, + true, ) .is_err()); @@ -1638,7 +1655,8 @@ fn test_check_signature() { candidate_hash, session, &statement_3, - &signed_3 + &signed_3, + true, ) .is_ok()); assert!(check_signature( @@ -1646,7 +1664,8 @@ fn test_check_signature() { candidate_hash, session, &statement_3, - &signed_3 + &signed_3, + true, ) .is_err()); assert!(check_signature( @@ -1654,7 +1673,8 @@ fn test_check_signature() { wrong_candidate_hash, session, &statement_3, - &signed_3 + &signed_3, + true, ) .is_err()); assert!(check_signature( @@ -1662,7 +1682,8 @@ fn test_check_signature() { candidate_hash, wrong_session, &statement_3, - &signed_3 + &signed_3, + true, ) .is_err()); assert!(check_signature( @@ -1670,7 +1691,8 @@ fn test_check_signature() { candidate_hash, session, &wrong_statement_3, - &signed_3 + &signed_3, + true, ) .is_err()); assert!(check_signature( @@ -1678,7 +1700,8 @@ fn test_check_signature() { candidate_hash, session, &statement_1, - &signed_3 + &signed_3, + true, ) .is_err()); assert!(check_signature( @@ -1686,7 +1709,8 @@ fn test_check_signature() { candidate_hash, session, &statement_2, - &signed_3 + &signed_3, + true ) .is_err()); assert!(check_signature( @@ -1694,7 +1718,8 @@ fn test_check_signature() { candidate_hash, session, &statement_4, - &signed_3 + &signed_3, + true, ) .is_err()); assert!(check_signature( @@ -1702,7 +1727,8 @@ fn test_check_signature() { candidate_hash, session, &statement_5, - &signed_3 + &signed_3, + true, ) .is_err()); @@ -1711,7 +1737,8 @@ fn test_check_signature() { candidate_hash, session, &statement_4, - &signed_4 + &signed_4, + true, ) .is_ok()); assert!(check_signature( @@ -1719,7 +1746,8 @@ fn test_check_signature() { candidate_hash, session, &statement_4, - &signed_4 + &signed_4, + true, ) .is_err()); assert!(check_signature( @@ -1727,7 +1755,8 @@ fn test_check_signature() { wrong_candidate_hash, session, &statement_4, - &signed_4 + &signed_4, + true, ) .is_err()); assert!(check_signature( @@ -1735,7 +1764,8 @@ fn test_check_signature() { candidate_hash, wrong_session, &statement_4, - &signed_4 + &signed_4, + true, ) .is_err()); assert!(check_signature( @@ -1743,7 +1773,8 @@ fn test_check_signature() { candidate_hash, session, &statement_1, - &signed_4 + &signed_4, + true, ) .is_err()); assert!(check_signature( @@ -1751,7 +1782,8 @@ fn test_check_signature() { candidate_hash, session, &statement_2, - &signed_4 + &signed_4, + true, ) .is_err()); assert!(check_signature( @@ -1759,7 +1791,8 @@ fn test_check_signature() { candidate_hash, session, &statement_3, - &signed_4 + &signed_4, + true, ) .is_err()); assert!(check_signature( @@ -1767,7 +1800,8 @@ fn test_check_signature() { candidate_hash, session, &statement_5, - &signed_4 + &signed_4, + true, ) .is_err()); @@ -1776,7 +1810,8 @@ fn test_check_signature() { candidate_hash, session, &statement_5, - &signed_5 + &signed_5, + true, ) .is_ok()); assert!(check_signature( @@ -1784,7 +1819,8 @@ fn test_check_signature() { candidate_hash, session, &statement_5, - &signed_5 + &signed_5, + true, ) .is_err()); assert!(check_signature( @@ -1792,7 +1828,8 @@ fn test_check_signature() { wrong_candidate_hash, session, &statement_5, - &signed_5 + &signed_5, + true, ) .is_err()); assert!(check_signature( @@ -1800,7 +1837,8 @@ fn test_check_signature() { candidate_hash, wrong_session, &statement_5, - &signed_5 + &signed_5, + true, ) .is_err()); assert!(check_signature( @@ -1808,7 +1846,8 @@ fn test_check_signature() { candidate_hash, session, &statement_1, - &signed_5 + &signed_5, + true, ) .is_err()); assert!(check_signature( @@ -1816,7 +1855,8 @@ fn test_check_signature() { candidate_hash, session, &statement_2, - &signed_5 + &signed_5, + true, ) .is_err()); assert!(check_signature( @@ -1824,7 +1864,8 @@ fn test_check_signature() { candidate_hash, session, &statement_3, - &signed_5 + &signed_5, + true, ) .is_err()); assert!(check_signature( @@ -1832,7 +1873,8 @@ fn test_check_signature() { candidate_hash, session, &statement_4, - &signed_5 + &signed_5, + true, ) .is_err()); } diff --git a/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs b/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs index 200fd57915f..0da50f6a537 100644 --- a/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs +++ b/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs @@ -17,7 +17,10 @@ //! Put implementations of functions from staging APIs here. use crate::{configuration, initializer, shared}; -use primitives::{vstaging::NodeFeatures, ValidatorIndex}; +use primitives::{ + vstaging::{ApprovalVotingParams, NodeFeatures}, + ValidatorIndex, +}; use sp_std::{collections::btree_map::BTreeMap, prelude::Vec}; /// Implementation for `DisabledValidators` @@ -47,3 +50,9 @@ where pub fn node_features() -> NodeFeatures { >::config().node_features } + +/// Approval voting subsystem configuration parameteres +pub fn approval_voting_params() -> ApprovalVotingParams { + let config = >::config(); + config.approval_voting_params +} diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 1e40f14f492..43df232e92a 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -23,12 +23,13 @@ use pallet_nis::WithMaximumOf; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use primitives::{ - slashing, vstaging::NodeFeatures, AccountId, AccountIndex, Balance, BlockNumber, - CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreState, DisputeState, - ExecutorParams, GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage, - InboundHrmpMessage, Moment, Nonce, OccupiedCoreAssumption, PersistedValidationData, - ScrapedOnChainVotes, SessionInfo, Signature, ValidationCode, ValidationCodeHash, ValidatorId, - ValidatorIndex, PARACHAIN_KEY_TYPE_ID, + slashing, + vstaging::{ApprovalVotingParams, NodeFeatures}, + AccountId, AccountIndex, Balance, BlockNumber, CandidateEvent, CandidateHash, + CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Hash, + Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, Moment, Nonce, + OccupiedCoreAssumption, PersistedValidationData, ScrapedOnChainVotes, SessionInfo, Signature, + ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, PARACHAIN_KEY_TYPE_ID, }; use runtime_common::{ assigned_slots, auctions, claims, crowdloan, identity_migrator, impl_runtime_weights, @@ -1631,6 +1632,7 @@ pub mod migrations { // Remove `im-online` pallet on-chain storage frame_support::migrations::RemovePallet::DbWeight>, + parachains_configuration::migration::v11::MigrateToV11, ); } @@ -1792,7 +1794,7 @@ sp_api::impl_runtime_apis! { } } - #[api_version(9)] + #[api_version(10)] impl primitives::runtime_api::ParachainHost for Runtime { fn validators() -> Vec { parachains_runtime_api_impl::validators::() @@ -1936,6 +1938,10 @@ sp_api::impl_runtime_apis! { parachains_runtime_api_impl::async_backing_params::() } + fn approval_voting_params() -> ApprovalVotingParams { + parachains_staging_runtime_api_impl::approval_voting_params::() + } + fn disabled_validators() -> Vec { parachains_staging_runtime_api_impl::disabled_validators::() } diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 0a70a493b29..9b8eff480f2 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -45,12 +45,14 @@ use pallet_session::historical as session_historical; use pallet_transaction_payment::{CurrencyAdapter, FeeDetails, RuntimeDispatchInfo}; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use primitives::{ - slashing, vstaging::NodeFeatures, AccountId, AccountIndex, Balance, BlockNumber, - CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreState, DisputeState, - ExecutorParams, GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage, - InboundHrmpMessage, Moment, Nonce, OccupiedCoreAssumption, PersistedValidationData, - PvfCheckStatement, ScrapedOnChainVotes, SessionInfo, Signature, ValidationCode, - ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, PARACHAIN_KEY_TYPE_ID, + slashing, + vstaging::{ApprovalVotingParams, NodeFeatures}, + AccountId, AccountIndex, Balance, BlockNumber, CandidateEvent, CandidateHash, + CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Hash, + Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, Moment, Nonce, + OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, + SessionInfo, Signature, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, + ValidatorSignature, PARACHAIN_KEY_TYPE_ID, }; use runtime_common::{ assigned_slots, auctions, crowdloan, @@ -1649,6 +1651,7 @@ pub mod migrations { ImOnlinePalletName, ::DbWeight, >, + parachains_configuration::migration::v11::MigrateToV11, ); } @@ -1789,7 +1792,7 @@ sp_api::impl_runtime_apis! { } } - #[api_version(9)] + #[api_version(10)] impl primitives::runtime_api::ParachainHost for Runtime { fn validators() -> Vec { parachains_runtime_api_impl::validators::() @@ -1933,6 +1936,10 @@ sp_api::impl_runtime_apis! { parachains_runtime_api_impl::async_backing_params::() } + fn approval_voting_params() -> ApprovalVotingParams { + parachains_staging_runtime_api_impl::approval_voting_params::() + } + fn disabled_validators() -> Vec { parachains_staging_runtime_api_impl::disabled_validators::() } diff --git a/polkadot/zombienet_tests/functional/0001-parachains-pvf.zndsl b/polkadot/zombienet_tests/functional/0001-parachains-pvf.zndsl index 135999a092a..3e1d8ba771c 100644 --- a/polkadot/zombienet_tests/functional/0001-parachains-pvf.zndsl +++ b/polkadot/zombienet_tests/functional/0001-parachains-pvf.zndsl @@ -32,6 +32,8 @@ alice: parachain 2005 block height is at least 10 within 300 seconds alice: parachain 2006 block height is at least 10 within 300 seconds alice: parachain 2007 block height is at least 10 within 300 seconds +alice: reports substrate_block_height{status="finalized"} is at least 30 within 400 seconds + # Check preparation time is under 10s. # Check all buckets <= 10. alice: reports histogram polkadot_pvf_preparation_time has at least 1 samples in buckets ["0.1", "0.5", "1", "2", "3", "10"] within 10 seconds diff --git a/polkadot/zombienet_tests/functional/0002-parachains-disputes.toml b/polkadot/zombienet_tests/functional/0002-parachains-disputes.toml index e70322e13e6..27cd81dface 100644 --- a/polkadot/zombienet_tests/functional/0002-parachains-disputes.toml +++ b/polkadot/zombienet_tests/functional/0002-parachains-disputes.toml @@ -5,6 +5,10 @@ timeout = 1000 max_validators_per_core = 5 needed_approvals = 8 +[relaychain.genesis.runtime.runtime_genesis_config.configuration.config.approval_voting_params] + max_approval_coalesce_count = 5 + + [relaychain] default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" chain = "rococo-local" diff --git a/polkadot/zombienet_tests/functional/0009-approval-voting-coalescing.toml b/polkadot/zombienet_tests/functional/0009-approval-voting-coalescing.toml new file mode 100644 index 00000000000..19c7015403d --- /dev/null +++ b/polkadot/zombienet_tests/functional/0009-approval-voting-coalescing.toml @@ -0,0 +1,115 @@ +[settings] +timeout = 1000 + +[relaychain] +default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" +chain = "rococo-local" + +[relaychain.genesis.runtimeGenesis.patch.configuration.config] + needed_approvals = 4 + relay_vrf_modulo_samples = 6 + +[relaychain.genesis.runtimeGenesis.patch.configuration.config.approval_voting_params] + max_approval_coalesce_count = 5 + +[relaychain.default_resources] +limits = { memory = "4G", cpu = "2" } +requests = { memory = "2G", cpu = "1" } + + [[relaychain.node_groups]] + name = "alice" + args = [ "-lparachain=trace,runtime=debug" ] + count = 13 + +[[parachains]] +id = 2000 +addToGenesis = true +genesis_state_generator = "undying-collator export-genesis-state --pov-size=100000 --pvf-complexity=1" + + [parachains.collator] + name = "collator01" + image = "{{COL_IMAGE}}" + command = "undying-collator" + args = ["-lparachain=debug", "--pov-size=100000", "--pvf-complexity=1", "--parachain-id=2000"] + +[[parachains]] +id = 2001 +addToGenesis = true +genesis_state_generator = "undying-collator export-genesis-state --pov-size=100000 --pvf-complexity=10" + + [parachains.collator] + name = "collator02" + image = "{{COL_IMAGE}}" + command = "undying-collator" + args = ["-lparachain=debug", "--pov-size=100000", "--parachain-id=2001", "--pvf-complexity=10"] + +[[parachains]] +id = 2002 +addToGenesis = true +genesis_state_generator = "undying-collator export-genesis-state --pov-size=100000 --pvf-complexity=100" + + [parachains.collator] + name = "collator03" + image = "{{COL_IMAGE}}" + command = "undying-collator" + args = ["-lparachain=debug", "--pov-size=100000", "--parachain-id=2002", "--pvf-complexity=100"] + +[[parachains]] +id = 2003 +addToGenesis = true +genesis_state_generator = "undying-collator export-genesis-state --pov-size=20000 --pvf-complexity=300" + + [parachains.collator] + name = "collator04" + image = "{{COL_IMAGE}}" + command = "undying-collator" + args = ["-lparachain=debug", "--pov-size=20000", "--parachain-id=2003", "--pvf-complexity=300"] + +[[parachains]] +id = 2004 +addToGenesis = true +genesis_state_generator = "undying-collator export-genesis-state --pov-size=100000 --pvf-complexity=300" + + [parachains.collator] + name = "collator05" + image = "{{COL_IMAGE}}" + command = "undying-collator" + args = ["-lparachain=debug", "--pov-size=100000", "--parachain-id=2004", "--pvf-complexity=300"] + +[[parachains]] +id = 2005 +addToGenesis = true +genesis_state_generator = "undying-collator export-genesis-state --pov-size=20000 --pvf-complexity=400" + + [parachains.collator] + name = "collator06" + image = "{{COL_IMAGE}}" + command = "undying-collator" + args = ["-lparachain=debug", "--pov-size=20000", "--pvf-complexity=400", "--parachain-id=2005"] + +[[parachains]] +id = 2006 +addToGenesis = true +genesis_state_generator = "undying-collator export-genesis-state --pov-size=100000 --pvf-complexity=300" + + [parachains.collator] + name = "collator07" + image = "{{COL_IMAGE}}" + command = "undying-collator" + args = ["-lparachain=debug", "--pov-size=100000", "--pvf-complexity=300", "--parachain-id=2006"] + +[[parachains]] +id = 2007 +addToGenesis = true +genesis_state_generator = "undying-collator export-genesis-state --pov-size=100000 --pvf-complexity=300" + + [parachains.collator] + name = "collator08" + image = "{{COL_IMAGE}}" + command = "undying-collator" + args = ["-lparachain=debug", "--pov-size=100000", "--pvf-complexity=300", "--parachain-id=2007"] + +[types.Header] +number = "u64" +parent_hash = "Hash" +post_state = "Hash" \ No newline at end of file diff --git a/polkadot/zombienet_tests/functional/0009-approval-voting-coalescing.zndsl b/polkadot/zombienet_tests/functional/0009-approval-voting-coalescing.zndsl new file mode 100644 index 00000000000..1fc4f678446 --- /dev/null +++ b/polkadot/zombienet_tests/functional/0009-approval-voting-coalescing.zndsl @@ -0,0 +1,32 @@ +Description: Approval voting coalescing does not lag finality +Network: ./0009-approval-voting-coalescing.toml +Creds: config + +# Check authority status. +alice: reports node_roles is 4 + +# Ensure parachains are registered. +alice: parachain 2000 is registered within 60 seconds +alice: parachain 2001 is registered within 60 seconds +alice: parachain 2002 is registered within 60 seconds +alice: parachain 2003 is registered within 60 seconds +alice: parachain 2004 is registered within 60 seconds +alice: parachain 2005 is registered within 60 seconds +alice: parachain 2006 is registered within 60 seconds +alice: parachain 2007 is registered within 60 seconds + +# Ensure parachains made progress. +alice: parachain 2000 block height is at least 10 within 300 seconds +alice: parachain 2001 block height is at least 10 within 300 seconds +alice: parachain 2002 block height is at least 10 within 300 seconds +alice: parachain 2003 block height is at least 10 within 300 seconds +alice: parachain 2004 block height is at least 10 within 300 seconds +alice: parachain 2005 block height is at least 10 within 300 seconds +alice: parachain 2006 block height is at least 10 within 300 seconds +alice: parachain 2007 block height is at least 10 within 300 seconds + +alice: reports substrate_block_height{status="finalized"} is at least 30 within 400 seconds + +alice: reports polkadot_parachain_approval_checking_finality_lag < 3 + +alice: reports polkadot_parachain_approvals_no_shows_total < 3 within 10 seconds diff --git a/prdoc/pr_1191.prdoc b/prdoc/pr_1191.prdoc new file mode 100644 index 00000000000..26626731be4 --- /dev/null +++ b/prdoc/pr_1191.prdoc @@ -0,0 +1,21 @@ +title: Approve multiple candidates with a single signature + +doc: + - audience: Node Operator + description: | + Changed approval-voting, approval-distribution to approve multiple candidate with a single message, it adds: + * A new parachains_db version. + * A new validation protocol to support the new message types. + The new logic will be disabled and will be enabled at a later date after all validators have upgraded. + +migrations: + db: + - name: Parachains database change from v4 to v5. + description: | + Approval-voting column format has been updated with several new fields. All existing data will be automatically + be migrated to the new values. + +crates: + - name: "polkadot" + +host_functions: [] -- GitLab From 8683bbeefb688364f5f9e445dffb42fc266dd8f0 Mon Sep 17 00:00:00 2001 From: Joshy Orndorff Date: Wed, 13 Dec 2023 04:18:33 -0500 Subject: [PATCH 50/59] Rename `ExportGenesisStateCommand` to `ExportGenesisHeadCommand` and make it respect custom genesis block builders (#2331) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #2326. This PR both fixes a logic bug and replaces an incorrect name. ## Bug Fix: Respecting custom genesis builder Prior to this PR the standard logic for creating a genesis block was repeated inside of cumulus. This PR removes that duplicated logic, and calls into the proper `BuildGenesisBlock` implementation. One consequence is that if the genesis block has already been initialized, it will not be re-created, but rather read from the database like it is for other node invocations. So you need to watch out for old unpurged data during the development process. Offchain tools may need to be updated accordingly. I've already filed https://github.com/paritytech/zombienet/issues/1519 ## Rename: It doesn't export state. It exports head data. The name export-genesis-state was always wrong, nad it's never too late to right a wrong. I've changed the name of the struct to `ExportGenesisHeadCommand`. There is still the question of what to do with individual nodes' public CLIs. I have updated the parachain template to a reasonable default that preserves compatibility with tools that will expect `export-genesis-state` to still work. And I've chosen not to modify the public CLIs of any other nodes in the repo. I'll leave it up to their individual owners/maintains to decide whether that is appropriate. --------- Co-authored-by: Joshy Orndorff Co-authored-by: Bastian Köcher Co-authored-by: Bastian Köcher --- Cargo.lock | 1 + cumulus/client/cli/Cargo.toml | 1 + cumulus/client/cli/src/lib.rs | 85 ++++++------------- cumulus/parachain-template/node/src/cli.rs | 7 +- .../parachain-template/node/src/command.rs | 4 +- cumulus/polkadot-parachain/src/cli.rs | 3 +- cumulus/polkadot-parachain/src/command.rs | 4 +- cumulus/test/service/src/cli.rs | 37 +------- cumulus/test/service/src/genesis.rs | 43 +++++++++- cumulus/test/service/src/lib.rs | 4 +- cumulus/test/service/src/main.rs | 44 +++------- .../test-parachains/adder/collator/src/cli.rs | 6 +- .../undying/collator/src/cli.rs | 6 +- prdoc/pr_2331.prdoc | 17 ++++ 14 files changed, 119 insertions(+), 143 deletions(-) create mode 100644 prdoc/pr_2331.prdoc diff --git a/Cargo.lock b/Cargo.lock index ba8cccca1ed..0e2194829c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3324,6 +3324,7 @@ dependencies = [ "sc-cli", "sc-client-api", "sc-service", + "sp-blockchain", "sp-core", "sp-runtime", "url", diff --git a/cumulus/client/cli/Cargo.toml b/cumulus/client/cli/Cargo.toml index c1b27673c40..af4912e2b2d 100644 --- a/cumulus/client/cli/Cargo.toml +++ b/cumulus/client/cli/Cargo.toml @@ -18,3 +18,4 @@ sc-chain-spec = { path = "../../../substrate/client/chain-spec" } sc-service = { path = "../../../substrate/client/service" } sp-core = { path = "../../../substrate/primitives/core" } sp-runtime = { path = "../../../substrate/primitives/runtime" } +sp-blockchain = { path = "../../../substrate/primitives/blockchain" } diff --git a/cumulus/client/cli/src/lib.rs b/cumulus/client/cli/src/lib.rs index 7e78afe6efb..1cebecb0043 100644 --- a/cumulus/client/cli/src/lib.rs +++ b/cumulus/client/cli/src/lib.rs @@ -23,20 +23,18 @@ use std::{ io::{self, Write}, net::SocketAddr, path::PathBuf, + sync::Arc, }; use codec::Encode; use sc_chain_spec::ChainSpec; -use sc_client_api::ExecutorProvider; +use sc_client_api::HeaderBackend; use sc_service::{ config::{PrometheusConfig, TelemetryEndpoints}, BasePath, TransactionPoolOptions, }; use sp_core::hexdisplay::HexDisplay; -use sp_runtime::{ - traits::{Block as BlockT, Hash as HashT, Header as HeaderT, Zero}, - StateVersion, -}; +use sp_runtime::traits::{Block as BlockT, Zero}; use url::Url; /// The `purge-chain` command used to remove the whole chain: the parachain and the relay chain. @@ -129,9 +127,9 @@ impl sc_cli::CliConfiguration for PurgeChainCmd { } } -/// Command for exporting the genesis state of the parachain +/// Command for exporting the genesis head data of the parachain #[derive(Debug, clap::Parser)] -pub struct ExportGenesisStateCommand { +pub struct ExportGenesisHeadCommand { /// Output file name or stdout if unspecified. #[arg()] pub output: Option, @@ -145,24 +143,29 @@ pub struct ExportGenesisStateCommand { pub shared_params: sc_cli::SharedParams, } -impl ExportGenesisStateCommand { - /// Run the export-genesis-state command - pub fn run( - &self, - chain_spec: &dyn ChainSpec, - client: &impl ExecutorProvider, - ) -> sc_cli::Result<()> { - let state_version = sc_chain_spec::resolve_state_version_from_wasm( - &chain_spec.build_storage()?, - client.executor(), - )?; - - let block: Block = generate_genesis_block(chain_spec, state_version)?; - let raw_header = block.header().encode(); +impl ExportGenesisHeadCommand { + /// Run the export-genesis-head command + pub fn run(&self, client: Arc) -> sc_cli::Result<()> + where + B: BlockT, + C: HeaderBackend + 'static, + { + let genesis_hash = client.hash(Zero::zero())?.ok_or(sc_cli::Error::Client( + sp_blockchain::Error::Backend( + "Failed to lookup genesis block hash when exporting genesis head data.".into(), + ), + ))?; + let genesis_header = client.header(genesis_hash)?.ok_or(sc_cli::Error::Client( + sp_blockchain::Error::Backend( + "Failed to lookup genesis header by hash when exporting genesis head data.".into(), + ), + ))?; + + let raw_header = genesis_header.encode(); let output_buf = if self.raw { raw_header } else { - format!("0x{:?}", HexDisplay::from(&block.header().encode())).into_bytes() + format!("0x{:?}", HexDisplay::from(&genesis_header.encode())).into_bytes() }; if let Some(output) = &self.output { @@ -175,43 +178,7 @@ impl ExportGenesisStateCommand { } } -/// Generate the genesis block from a given ChainSpec. -pub fn generate_genesis_block( - chain_spec: &dyn ChainSpec, - genesis_state_version: StateVersion, -) -> Result { - let storage = chain_spec.build_storage()?; - - let child_roots = storage.children_default.iter().map(|(sk, child_content)| { - let state_root = <<::Header as HeaderT>::Hashing as HashT>::trie_root( - child_content.data.clone().into_iter().collect(), - genesis_state_version, - ); - (sk.clone(), state_root.encode()) - }); - let state_root = <<::Header as HeaderT>::Hashing as HashT>::trie_root( - storage.top.clone().into_iter().chain(child_roots).collect(), - genesis_state_version, - ); - - let extrinsics_root = <<::Header as HeaderT>::Hashing as HashT>::trie_root( - Vec::new(), - genesis_state_version, - ); - - Ok(Block::new( - <::Header as HeaderT>::new( - Zero::zero(), - extrinsics_root, - state_root, - Default::default(), - Default::default(), - ), - Default::default(), - )) -} - -impl sc_cli::CliConfiguration for ExportGenesisStateCommand { +impl sc_cli::CliConfiguration for ExportGenesisHeadCommand { fn shared_params(&self) -> &sc_cli::SharedParams { &self.shared_params } diff --git a/cumulus/parachain-template/node/src/cli.rs b/cumulus/parachain-template/node/src/cli.rs index 098f59b0f37..73ef996b750 100644 --- a/cumulus/parachain-template/node/src/cli.rs +++ b/cumulus/parachain-template/node/src/cli.rs @@ -24,8 +24,11 @@ pub enum Subcommand { /// Remove the whole chain. PurgeChain(cumulus_client_cli::PurgeChainCmd), - /// Export the genesis state of the parachain. - ExportGenesisState(cumulus_client_cli::ExportGenesisStateCommand), + /// Export the genesis head data of the parachain. + /// + /// Head data is the encoded block header. + #[command(alias = "export-genesis-state")] + ExportGenesisHead(cumulus_client_cli::ExportGenesisHeadCommand), /// Export the genesis wasm of the parachain. ExportGenesisWasm(cumulus_client_cli::ExportGenesisWasmCommand), diff --git a/cumulus/parachain-template/node/src/command.rs b/cumulus/parachain-template/node/src/command.rs index 4dd8463f6be..6ddb68a359a 100644 --- a/cumulus/parachain-template/node/src/command.rs +++ b/cumulus/parachain-template/node/src/command.rs @@ -162,12 +162,12 @@ pub fn run() -> Result<()> { cmd.run(config, polkadot_config) }) }, - Some(Subcommand::ExportGenesisState(cmd)) => { + Some(Subcommand::ExportGenesisHead(cmd)) => { let runner = cli.create_runner(cmd)?; runner.sync_run(|config| { let partials = new_partial(&config)?; - cmd.run(&*config.chain_spec, &*partials.client) + cmd.run(partials.client) }) }, Some(Subcommand::ExportGenesisWasm(cmd)) => { diff --git a/cumulus/polkadot-parachain/src/cli.rs b/cumulus/polkadot-parachain/src/cli.rs index 63e4baf27ae..fec6e144e40 100644 --- a/cumulus/polkadot-parachain/src/cli.rs +++ b/cumulus/polkadot-parachain/src/cli.rs @@ -45,7 +45,8 @@ pub enum Subcommand { PurgeChain(cumulus_client_cli::PurgeChainCmd), /// Export the genesis state of the parachain. - ExportGenesisState(cumulus_client_cli::ExportGenesisStateCommand), + #[command(alias = "export-genesis-state")] + ExportGenesisHead(cumulus_client_cli::ExportGenesisHeadCommand), /// Export the genesis wasm of the parachain. ExportGenesisWasm(cumulus_client_cli::ExportGenesisWasmCommand), diff --git a/cumulus/polkadot-parachain/src/command.rs b/cumulus/polkadot-parachain/src/command.rs index 98dcc2fea4a..d1b020cc7c9 100644 --- a/cumulus/polkadot-parachain/src/command.rs +++ b/cumulus/polkadot-parachain/src/command.rs @@ -530,10 +530,10 @@ pub fn run() -> Result<()> { cmd.run(config, polkadot_config) }) }, - Some(Subcommand::ExportGenesisState(cmd)) => { + Some(Subcommand::ExportGenesisHead(cmd)) => { let runner = cli.create_runner(cmd)?; runner.sync_run(|config| { - construct_partials!(config, |partials| cmd.run(&*config.chain_spec, &*partials.client)) + construct_partials!(config, |partials| cmd.run(partials.client)) }) }, Some(Subcommand::ExportGenesisWasm(cmd)) => { diff --git a/cumulus/test/service/src/cli.rs b/cumulus/test/service/src/cli.rs index ef1159a3c1f..3dc5b8e3101 100644 --- a/cumulus/test/service/src/cli.rs +++ b/cumulus/test/service/src/cli.rs @@ -16,6 +16,7 @@ use std::{net::SocketAddr, path::PathBuf}; +use cumulus_client_cli::{ExportGenesisHeadCommand, ExportGenesisWasmCommand}; use polkadot_service::{ChainSpec, ParaId, PrometheusConfig}; use sc_cli::{ CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams, NetworkParams, @@ -60,45 +61,13 @@ pub enum Subcommand { BuildSpec(sc_cli::BuildSpecCmd), /// Export the genesis state of the parachain. - ExportGenesisState(ExportGenesisStateCommand), + #[command(alias = "export-genesis-state")] + ExportGenesisHead(ExportGenesisHeadCommand), /// Export the genesis wasm of the parachain. ExportGenesisWasm(ExportGenesisWasmCommand), } -#[derive(Debug, clap::Parser)] -#[group(skip)] -pub struct ExportGenesisStateCommand { - #[arg(default_value_t = 2000u32)] - pub parachain_id: u32, - - #[command(flatten)] - pub base: cumulus_client_cli::ExportGenesisStateCommand, -} - -impl CliConfiguration for ExportGenesisStateCommand { - fn shared_params(&self) -> &SharedParams { - &self.base.shared_params - } -} - -/// Command for exporting the genesis wasm file. -#[derive(Debug, clap::Parser)] -#[group(skip)] -pub struct ExportGenesisWasmCommand { - #[arg(default_value_t = 2000u32)] - pub parachain_id: u32, - - #[command(flatten)] - pub base: cumulus_client_cli::ExportGenesisWasmCommand, -} - -impl CliConfiguration for ExportGenesisWasmCommand { - fn shared_params(&self) -> &SharedParams { - &self.base.shared_params - } -} - #[derive(Debug)] pub struct RelayChainCli { /// The actual relay chain cli object. diff --git a/cumulus/test/service/src/genesis.rs b/cumulus/test/service/src/genesis.rs index d4a9a225626..be4b0427b2e 100644 --- a/cumulus/test/service/src/genesis.rs +++ b/cumulus/test/service/src/genesis.rs @@ -15,11 +15,50 @@ // along with Cumulus. If not, see . use codec::Encode; -use cumulus_client_cli::generate_genesis_block; use cumulus_primitives_core::ParaId; use cumulus_test_runtime::Block; use polkadot_primitives::HeadData; -use sp_runtime::traits::Block as BlockT; +use sc_chain_spec::ChainSpec; +use sp_runtime::{ + traits::{Block as BlockT, Hash as HashT, Header as HeaderT, Zero}, + StateVersion, +}; + +/// Generate a simple test genesis block from a given ChainSpec. +pub fn generate_genesis_block( + chain_spec: &dyn ChainSpec, + genesis_state_version: StateVersion, +) -> Result { + let storage = chain_spec.build_storage()?; + + let child_roots = storage.children_default.iter().map(|(sk, child_content)| { + let state_root = <<::Header as HeaderT>::Hashing as HashT>::trie_root( + child_content.data.clone().into_iter().collect(), + genesis_state_version, + ); + (sk.clone(), state_root.encode()) + }); + let state_root = <<::Header as HeaderT>::Hashing as HashT>::trie_root( + storage.top.clone().into_iter().chain(child_roots).collect(), + genesis_state_version, + ); + + let extrinsics_root = <<::Header as HeaderT>::Hashing as HashT>::trie_root( + Vec::new(), + genesis_state_version, + ); + + Ok(Block::new( + <::Header as HeaderT>::new( + Zero::zero(), + extrinsics_root, + state_root, + Default::default(), + Default::default(), + ), + Default::default(), + )) +} /// Returns the initial head data for a parachain ID. pub fn initial_head_data(para_id: ParaId) -> HeadData { diff --git a/cumulus/test/service/src/lib.rs b/cumulus/test/service/src/lib.rs index 627d060d8a0..586c4603c76 100644 --- a/cumulus/test/service/src/lib.rs +++ b/cumulus/test/service/src/lib.rs @@ -22,7 +22,9 @@ pub mod bench_utils; pub mod chain_spec; -mod genesis; + +/// Utilities for creating test genesis block and head data +pub mod genesis; use runtime::AccountId; use sc_executor::{HeapAllocStrategy, WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY}; diff --git a/cumulus/test/service/src/main.rs b/cumulus/test/service/src/main.rs index 55a0f12d671..aace92ca965 100644 --- a/cumulus/test/service/src/main.rs +++ b/cumulus/test/service/src/main.rs @@ -16,16 +16,14 @@ mod cli; -use std::{io::Write, sync::Arc}; +use std::sync::Arc; use cli::{RelayChainCli, Subcommand, TestCollatorCli}; -use cumulus_client_cli::generate_genesis_block; use cumulus_primitives_core::{relay_chain::CollatorPair, ParaId}; -use cumulus_test_service::AnnounceBlockFn; +use cumulus_test_service::{new_partial, AnnounceBlockFn}; use polkadot_service::runtime_traits::AccountIdConversion; use sc_cli::{CliConfiguration, SubstrateCli}; -use sp_core::{hexdisplay::HexDisplay, Encode, Pair}; -use sp_runtime::traits::Block; +use sp_core::Pair; pub fn wrap_announce_block() -> Box AnnounceBlockFn> { tracing::info!("Block announcements disabled."); @@ -44,38 +42,16 @@ fn main() -> Result<(), sc_cli::Error> { runner.sync_run(|config| cmd.run(config.chain_spec, config.network)) }, - Some(Subcommand::ExportGenesisState(params)) => { - let mut builder = sc_cli::LoggerBuilder::new(""); - builder.with_profiling(sc_tracing::TracingReceiver::Log, ""); - let _ = builder.init(); - - let spec = - cli.load_spec(¶ms.base.shared_params.chain.clone().unwrap_or_default())?; - let state_version = cumulus_test_service::runtime::VERSION.state_version(); - - let block: parachains_common::Block = generate_genesis_block(&*spec, state_version)?; - let raw_header = block.header().encode(); - let output_buf = if params.base.raw { - raw_header - } else { - format!("0x{:?}", HexDisplay::from(&block.header().encode())).into_bytes() - }; - - if let Some(output) = ¶ms.base.output { - std::fs::write(output, output_buf)?; - } else { - std::io::stdout().write_all(&output_buf)?; - } - - Ok(()) + Some(Subcommand::ExportGenesisHead(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.sync_run(|mut config| { + let partial = new_partial(&mut config, false)?; + cmd.run(partial.client) + }) }, Some(Subcommand::ExportGenesisWasm(cmd)) => { let runner = cli.create_runner(cmd)?; - runner.sync_run(|_config| { - let parachain_id = ParaId::from(cmd.parachain_id); - let spec = cumulus_test_service::get_chain_spec(Some(parachain_id)); - cmd.base.run(&spec) - }) + runner.sync_run(|config| cmd.run(&*config.chain_spec)) }, None => { let log_filters = cli.run.normalize().log_filters(); diff --git a/polkadot/parachain/test-parachains/adder/collator/src/cli.rs b/polkadot/parachain/test-parachains/adder/collator/src/cli.rs index 14b25970683..f81e4cc0fff 100644 --- a/polkadot/parachain/test-parachains/adder/collator/src/cli.rs +++ b/polkadot/parachain/test-parachains/adder/collator/src/cli.rs @@ -24,16 +24,16 @@ use sc_cli::SubstrateCli; pub enum Subcommand { /// Export the genesis state of the parachain. #[command(name = "export-genesis-state")] - ExportGenesisState(ExportGenesisStateCommand), + ExportGenesisState(ExportGenesisHeadCommand), /// Export the genesis wasm of the parachain. #[command(name = "export-genesis-wasm")] ExportGenesisWasm(ExportGenesisWasmCommand), } -/// Command for exporting the genesis state of the parachain +/// Command for exporting the genesis head data of the parachain #[derive(Debug, Parser)] -pub struct ExportGenesisStateCommand {} +pub struct ExportGenesisHeadCommand {} /// Command for exporting the genesis wasm file. #[derive(Debug, Parser)] diff --git a/polkadot/parachain/test-parachains/undying/collator/src/cli.rs b/polkadot/parachain/test-parachains/undying/collator/src/cli.rs index d04122f2f68..9572887a51a 100644 --- a/polkadot/parachain/test-parachains/undying/collator/src/cli.rs +++ b/polkadot/parachain/test-parachains/undying/collator/src/cli.rs @@ -25,16 +25,16 @@ use std::path::PathBuf; pub enum Subcommand { /// Export the genesis state of the parachain. #[command(name = "export-genesis-state")] - ExportGenesisState(ExportGenesisStateCommand), + ExportGenesisState(ExportGenesisHeadCommand), /// Export the genesis wasm of the parachain. #[command(name = "export-genesis-wasm")] ExportGenesisWasm(ExportGenesisWasmCommand), } -/// Command for exporting the genesis state of the parachain +/// Command for exporting the genesis head data of the parachain #[derive(Debug, Parser)] -pub struct ExportGenesisStateCommand { +pub struct ExportGenesisHeadCommand { /// Output file name or stdout if unspecified. #[arg()] pub output: Option, diff --git a/prdoc/pr_2331.prdoc b/prdoc/pr_2331.prdoc new file mode 100644 index 00000000000..e3daf4c45bd --- /dev/null +++ b/prdoc/pr_2331.prdoc @@ -0,0 +1,17 @@ +title: Rename `ExportGenesisStateCommand` to `ExportGenesisHeadCommand` + +doc: + - audience: Node Operator + description: | + The `export-genesis-state` subcommand is now called `export-gensis-head`, but + `export-genesis-state` stays as an alias to not break any scripts. + + - audience: Node Dev + description: | + The struct `ExportGenesisStateCommand` is now called `ExportGenesisHeadCommand`. + So, you only need to rename the import and usage. The `run` function is now + taking only a `client` as argument to fetch the genesis header. This way + the exported genesis head is respecting custom genesis block builders. + +crates: + - name: "cumulus-client-cli" -- GitLab From 3c5fcbe637b184e44a000d4e19f8bfd49667dbe4 Mon Sep 17 00:00:00 2001 From: Chevdor Date: Wed, 13 Dec 2023 10:28:34 +0100 Subject: [PATCH 51/59] Add `check runtimes` GH Workflow (#2252) This PR introduces: - a new script - a new GH Workflow - runtime reference spec files for `rococo` and `westend` It brings a mechanism to check that part(s) of the runtimes' metadata that should not change over time, actually did not change over time. Ideally, the GHW should trigger when a release is edited but GH seem to [have an issue](https://github.com/orgs/community/discussions/47794) that prevents the trigger from working. This is why the check has been implemented as `workflow_dispatch` for a start. The `workflow_dispatch` requires a `release_id` that can be found using: ``` curl -s -H "Authorization: Bearer ${GITHUB_TOKEN}" \ https://api.github.com/repos/paritytech/polkadot-sdk/releases | \ jq '.[] | { name: .name, id: .id }' ``` as documented in the workflow. A sample run can be seen [here](https://github.com/chevdor/polkadot-sdk/actions/runs/6811176342). --- .github/runtime_specs/rococo.json | 17 +++ .github/runtime_specs/westend.json | 17 +++ .github/scripts/check-runtime.py | 124 ++++++++++++++++++ .github/scripts/common/lib.sh | 11 +- .../build-and-attach-release-runtimes.yml | 2 +- .github/workflows/check-publish.yml | 2 +- .github/workflows/check-runtimes.yml | 94 +++++++++++++ 7 files changed, 262 insertions(+), 5 deletions(-) create mode 100644 .github/runtime_specs/rococo.json create mode 100644 .github/runtime_specs/westend.json create mode 100755 .github/scripts/check-runtime.py create mode 100644 .github/workflows/check-runtimes.yml diff --git a/.github/runtime_specs/rococo.json b/.github/runtime_specs/rococo.json new file mode 100644 index 00000000000..6568b06400c --- /dev/null +++ b/.github/runtime_specs/rococo.json @@ -0,0 +1,17 @@ +{ + "pallets": { + "1": { + "constants": { + "EpochDuration": { + "value": [ 88, 2, 0, 0, 0, 0, 0, 0 ]} + } + }, + + "2": { + "constants": { + "MinimumPeriod": { + "value": [ 184, 11, 0, 0, 0, 0, 0, 0 ]} + } + } + } + } diff --git a/.github/runtime_specs/westend.json b/.github/runtime_specs/westend.json new file mode 100644 index 00000000000..6568b06400c --- /dev/null +++ b/.github/runtime_specs/westend.json @@ -0,0 +1,17 @@ +{ + "pallets": { + "1": { + "constants": { + "EpochDuration": { + "value": [ 88, 2, 0, 0, 0, 0, 0, 0 ]} + } + }, + + "2": { + "constants": { + "MinimumPeriod": { + "value": [ 184, 11, 0, 0, 0, 0, 0, 0 ]} + } + } + } + } diff --git a/.github/scripts/check-runtime.py b/.github/scripts/check-runtime.py new file mode 100755 index 00000000000..9f3d047e01f --- /dev/null +++ b/.github/scripts/check-runtime.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python3 + +import json +import sys +import logging +import os + + +def check_constant(spec_pallet_id, spec_pallet_value, meta_constant): + """ + Check a single constant + + :param spec_pallet_id: + :param spec_pallet_value: + :param meta_constant: + :return: + """ + if meta_constant['name'] == list(spec_pallet_value.keys())[0]: + constant = meta_constant['name'] + res = list(spec_pallet_value.values())[0]["value"] == meta_constant["value"] + + logging.debug(f" Checking pallet:{spec_pallet_id}/constants/{constant}") + logging.debug(f" spec_pallet_value: {spec_pallet_value}") + logging.debug(f" meta_constant: {meta_constant}") + logging.info(f"pallet:{spec_pallet_id}/constants/{constant} -> {res}") + return res + else: + # logging.warning(f" Skipping pallet:{spec_pallet_id}/constants/{meta_constant['name']}") + pass + + +def check_pallet(metadata, spec_pallet): + """ + Check one pallet + + :param metadata: + :param spec_pallet_id: + :param spec_pallet_value: + :return: + """ + + spec_pallet_id, spec_pallet_value = spec_pallet + logging.debug(f"Pallet: {spec_pallet_id}") + + metadata_pallets = metadata["pallets"] + metadata_pallet = metadata_pallets[spec_pallet_id] + + res = map(lambda meta_constant_value: check_constant( + spec_pallet_id, spec_pallet_value["constants"], meta_constant_value), + metadata_pallet["constants"].values()) + res = list(filter(lambda item: item is not None, res)) + return all(res) + + +def check_pallets(metadata, specs): + """ + CHeck all pallets + + :param metadata: + :param specs: + :return: + """ + + res = list(map(lambda spec_pallet: check_pallet(metadata, spec_pallet), + specs['pallets'].items())) + res = list(filter(lambda item: item is not None, res)) + return all(res) + + +def check_metadata(metadata, specs): + """ + Check metadata (json) against a list of expectations + + :param metadata: Metadata in JSON format + :param expectation: Expectations + :return: Bool + """ + + res = check_pallets(metadata, specs) + return res + + +def help(): + """ Show some simple help """ + + print(f"You must pass 2 args, you passed {len(sys.argv) - 1}") + print("Sample call:") + print("check-runtime.py ") + + +def load_json(file): + """ Load json from a file """ + + f = open(file) + return json.load(f) + + +def main(): + LOGLEVEL = os.environ.get('LOGLEVEL', 'INFO').upper() + logging.basicConfig(level=LOGLEVEL) + + if len(sys.argv) != 3: + help() + exit(1) + + metadata_file = sys.argv[1] + specs_file = sys.argv[2] + print(f"Checking metadata from: {metadata_file} with specs from: {specs_file}") + + metadata = load_json(metadata_file) + specs = load_json(specs_file) + + res = check_metadata(metadata, specs) + + if res: + logging.info(f"OK") + exit(0) + else: + print("") + logging.info(f"Some errors were found, run again with LOGLEVEL=debug") + exit(1) + +if __name__ == "__main__": + main() diff --git a/.github/scripts/common/lib.sh b/.github/scripts/common/lib.sh index 2a835b4472b..e499dfabd64 100755 --- a/.github/scripts/common/lib.sh +++ b/.github/scripts/common/lib.sh @@ -202,21 +202,26 @@ fetch_release_artifacts() { echo "Release ID : $RELEASE_ID" echo "Repo : $REPO" echo "Binary : $BINARY" + OUTPUT_DIR=${OUTPUT_DIR:-"./release-artifacts/${BINARY}"} + echo "OUTPUT_DIR : $OUTPUT_DIR" + echo "Fetching release info..." curl -L -s \ -H "Accept: application/vnd.github+json" \ -H "Authorization: Bearer ${GITHUB_TOKEN}" \ -H "X-GitHub-Api-Version: 2022-11-28" \ https://api.github.com/repos/${REPO}/releases/${RELEASE_ID} > release.json - # Get Asset ids + echo "Extract asset ids..." ids=($(jq -r '.assets[].id' < release.json )) + echo "Extract asset count..." count=$(jq '.assets|length' < release.json ) # Fetch artifacts - mkdir -p "./release-artifacts/${BINARY}" - pushd "./release-artifacts/${BINARY}" > /dev/null + mkdir -p "$OUTPUT_DIR" + pushd "$OUTPUT_DIR" > /dev/null + echo "Fetching assets..." iter=1 for id in "${ids[@]}" do diff --git a/.github/workflows/build-and-attach-release-runtimes.yml b/.github/workflows/build-and-attach-release-runtimes.yml index a480784aea3..f7003379cf0 100644 --- a/.github/workflows/build-and-attach-release-runtimes.yml +++ b/.github/workflows/build-and-attach-release-runtimes.yml @@ -31,7 +31,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Build ${{ matrix.runtime.name }} ${{ matrix.build_config.type }} id: srtool_build diff --git a/.github/workflows/check-publish.yml b/.github/workflows/check-publish.yml index db0863888b8..1941bd98167 100644 --- a/.github/workflows/check-publish.yml +++ b/.github/workflows/check-publish.yml @@ -12,7 +12,7 @@ jobs: check-publish: runs-on: ubuntu-latest steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Rust Cache uses: Swatinem/rust-cache@3cf7f8cc28d1b4e7d01e3783be10a97d55d483c8 # v2.7.1 diff --git a/.github/workflows/check-runtimes.yml b/.github/workflows/check-runtimes.yml new file mode 100644 index 00000000000..0e5ad104766 --- /dev/null +++ b/.github/workflows/check-runtimes.yml @@ -0,0 +1,94 @@ +name: Check Runtimes Specs +# This GH Workflow fetches the runtimes available in a release. +# It then compares their metadata with reference specs located under +# .github/runtime_specs. + +on: + workflow_dispatch: + inputs: + release_id: + description: | + Release ID. + You can find it using the command: + curl -s \ + -H "Authorization: Bearer ${GITHUB_TOKEN}" https://api.github.com/repos/paritytech/polkadot-sdk/releases | \ + jq '.[] | { name: .name, id: .id }' + required: true + type: string + + # This trigger unfortunately does not work as expected. + # https://github.com/orgs/community/discussions/47794 + # release: + # types: [edited] + +env: + RUNTIME_SPECS_DIR: .github/runtime_specs + DATA_DIR: runtimes + RELEASE_ID: ${{ inputs.release_id }} + REPO: ${{ github.repository }} + +jobs: + find-specs: + name: Fetch runtime specs + outputs: + specs: ${{ steps.get-list.outputs.specs }} + runs-on: ubuntu-latest + steps: + - name: Checkout the repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - name: Get list + id: get-list + run: | + lst=$(ls $RUNTIME_SPECS_DIR/*.json | xargs -I{} basename "{}" .json | jq -R .| jq -sc .) + echo "Found: $lst" + echo "specs=$lst" >> $GITHUB_OUTPUT + + check-runtimes: + name: Check runtime specs + runs-on: ubuntu-latest + needs: + - find-specs + + strategy: + matrix: + specs: ${{ fromJSON(needs.find-specs.outputs.specs) }} + + steps: + - name: Checkout the repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - name: Fetch release artifacts based on release id + env: + OUTPUT_DIR: ${{ env.DATA_DIR }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + . ./.github/scripts/common/lib.sh + fetch_release_artifacts + + - name: Install tooling + env: + SUBWASM_VERSION: v0.20.0 + DL_BASE_URL: https://github.com/chevdor/subwasm/releases/download + run: | + wget $DL_BASE_URL/$SUBWASM_VERSION/subwasm_linux_amd64_$SUBWASM_VERSION.deb \ + -O subwasm.deb + sudo dpkg -i subwasm.deb + subwasm --version + + - name: Extract metadata JSON for ${{ matrix.specs }} + env: + RUNTIME: ${{ matrix.specs }} + run: | + WASM=$(ls ${DATA_DIR}/${RUNTIME}*.wasm) + echo "WASM=$WASM" + subwasm show --json "$WASM" > "${DATA_DIR}/${RUNTIME}.json" + + - name: Check specs for ${{ matrix.specs }} + id: build + env: + RUNTIME: ${{ matrix.specs }} + LOGLEVEL: info + run: | + python --version + .github/scripts/check-runtime.py "${DATA_DIR}/${RUNTIME}.json" "${RUNTIME_SPECS_DIR}/${RUNTIME}.json" -- GitLab From 9ecb2d3391ee27f1d6c8af1a53416f8224653fd9 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Wed, 13 Dec 2023 12:31:12 +0300 Subject: [PATCH 52/59] Tests for BridgeHub(s) <> remote GRANDPA chain (#2692) So far the `bridge-hub-test-utils` contained a tests set for testing BridgeHub runtime that is bridging with the remote **parachain**. But we have https://github.com/paritytech/polkadot-sdk/pull/2540 coming, which would add Rococo <> Bulletin chain bridge (where Bulletin = standalone chain that is using GRANDPA finality). Then it'll be expanded to Polkadot BH as well. So this PR adds the same set of tests to the `bridge-hub-test-utils`, but for the case when remote chain is the chain with GRANDPA finality. There's a lot of changes in this PR - I'll describe some: - I've added `BasicParachainRuntime` trait to decrease number of lines we need to add to `where` clause. Could revert, but imo it is useful; - `cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data` is a submodule for generating test data for the test sets. `from_parachain.rs` is used in tests for the case when remote chain is a parachain, `from_grandpa_chain.rs` - for the bridges with remote GRANDPA chains. `mod.rs` has some code, shared by both types of tests; - `cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data` is a submodule with all test cases. The `mod.rs` has tests, suitable for all cases. There's also `wth_parachain.rs` and `with_grandpa_chain.rs` with the same meaning as above; - I've merged the "core" code of two previous tests - `relayed_incoming_message_works` and `complex_relay_extrinsic_works` into one single `relayed_incoming_message_works` test. So now we are always constructing extrinsics and are dispatching them using executive module (meaning all signed extensions are also tested). New test set is used here: https://github.com/paritytech/polkadot-sdk/pull/2540. Once this PR is merged, I'll merge that other PR with master to remove duplicate changes. I'm also planning to cleanup generic constraints + remove some unnecessary assumptions about used chains in a follow-up PRs. But for now I think this PR has enough changes, so don't want to complicate it even more. --- Breaking changes for the code that have used those tests before: - the `construct_and_apply_extrinsic` callback now accepts the `RuntimeCall` instead of the `pallet_utility::Call`; - the `construct_and_apply_extrinsic` now may be called multiple times for the single test, so make sure the `frame_system::CheckNonce` is correctly constructed; - all previous tests have been moved from `bridge_hub_test_utils::test_cases` to `bridge_hub_test_utils::test_cases::from_parachain` module; - there are several changes in test arguments - please refer to https://github.com/paritytech/polkadot-sdk/compare/sv-tests-for-bridge-with-remote-grandpa-chain?expand=1#diff-79a28d4d3e1749050341c2424f00c4c139825b1a20937767f83e58b95166735c for details. --- Cargo.lock | 2 + .../bridge-hub-rococo/tests/tests.rs | 32 +- .../bridge-hub-westend/tests/tests.rs | 32 +- .../bridge-hubs/test-utils/Cargo.toml | 3 + .../bridge-hubs/test-utils/src/lib.rs | 2 + .../bridge-hubs/test-utils/src/test_cases.rs | 1588 ----------------- .../src/test_cases/from_grandpa_chain.rs | 442 +++++ .../src/test_cases/from_parachain.rs | 544 ++++++ .../test-utils/src/test_cases/helpers.rs | 340 ++++ .../test-utils/src/test_cases/mod.rs | 485 +++++ .../src/test_data/from_grandpa_chain.rs | 244 +++ .../src/test_data/from_parachain.rs | 326 ++++ .../test-utils/src/test_data/mod.rs | 144 ++ .../parachains/runtimes/test-utils/src/lib.rs | 55 +- 14 files changed, 2588 insertions(+), 1651 deletions(-) delete mode 100644 cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_grandpa_chain.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_parachain.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_grandpa_chain.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_parachain.rs create mode 100644 cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 0e2194829c2..9e17e6803d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1991,6 +1991,7 @@ dependencies = [ "frame-executive", "frame-support", "frame-system", + "impl-trait-for-tuples", "log", "pallet-balances", "pallet-bridge-grandpa", @@ -2009,6 +2010,7 @@ dependencies = [ "sp-io", "sp-keyring", "sp-runtime", + "sp-std 8.0.0", "sp-tracing 10.0.0", "staging-parachain-info", "staging-xcm", diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs index 1d544a9dcfa..662012a4b41 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs @@ -26,7 +26,6 @@ use bridge_hub_rococo_runtime::{ }; use codec::{Decode, Encode}; use frame_support::{dispatch::GetDispatchInfo, parameter_types, traits::ConstU8}; -use frame_system::pallet_prelude::HeaderFor; use parachains_common::{rococo::fee::WeightToFee, AccountId, AuraId, Balance}; use sp_keyring::AccountKeyring::Alice; use sp_runtime::{ @@ -46,13 +45,16 @@ fn construct_extrinsic( sender: sp_keyring::AccountKeyring, call: RuntimeCall, ) -> UncheckedExtrinsic { + let account_id = AccountId32::from(sender.public()); let extra: SignedExtra = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), frame_system::CheckGenesis::::new(), frame_system::CheckEra::::from(Era::immortal()), - frame_system::CheckNonce::::from(0), + frame_system::CheckNonce::::from( + frame_system::Pallet::::account(&account_id).nonce, + ), frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(0), BridgeRejectObsoleteHeadersAndMessages::default(), @@ -62,7 +64,7 @@ fn construct_extrinsic( let signature = payload.using_encoded(|e| sender.sign(e)); UncheckedExtrinsic::new_signed( call, - AccountId32::from(sender.public()).into(), + account_id.into(), Signature::Sr25519(signature.clone()), extra, ) @@ -70,10 +72,9 @@ fn construct_extrinsic( fn construct_and_apply_extrinsic( relayer_at_target: sp_keyring::AccountKeyring, - batch: pallet_utility::Call, + call: RuntimeCall, ) -> sp_runtime::DispatchOutcome { - let batch_call = RuntimeCall::Utility(batch); - let xt = construct_extrinsic(relayer_at_target, batch_call); + let xt = construct_extrinsic(relayer_at_target, call); let r = Executive::apply_extrinsic(xt); r.unwrap() } @@ -85,10 +86,6 @@ fn construct_and_estimate_extrinsic_fee(batch: pallet_utility::Call) -> TransactionPayment::compute_fee(xt.encoded_size() as _, &batch_info, 0) } -fn executive_init_block(header: &HeaderFor) { - Executive::initialize_block(header) -} - fn collator_session_keys() -> bridge_hub_test_utils::CollatorSessionKeys { bridge_hub_test_utils::CollatorSessionKeys::new( AccountId::from(Alice), @@ -237,10 +234,9 @@ mod bridge_hub_rococo_tests { #[test] fn relayed_incoming_message_works() { // from Westend - bridge_hub_test_utils::test_cases::relayed_incoming_message_works::< + bridge_hub_test_utils::test_cases::from_parachain::relayed_incoming_message_works::< Runtime, AllPalletsWithoutSystem, - XcmConfig, ParachainSystem, BridgeGrandpaWestendInstance, BridgeParachainWestendInstance, @@ -250,17 +246,19 @@ mod bridge_hub_rococo_tests { collator_session_keys(), bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, + BridgeHubWestendChainId::get(), SIBLING_PARACHAIN_ID, Rococo, XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, || (), + construct_and_apply_extrinsic, ) } #[test] pub fn complex_relay_extrinsic_works() { // for Westend - bridge_hub_test_utils::test_cases::complex_relay_extrinsic_works::< + bridge_hub_test_utils::test_cases::from_parachain::complex_relay_extrinsic_works::< Runtime, AllPalletsWithoutSystem, XcmConfig, @@ -277,10 +275,8 @@ mod bridge_hub_rococo_tests { BridgeHubWestendChainId::get(), Rococo, XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, - ExistentialDeposit::get(), - executive_init_block, - construct_and_apply_extrinsic, || (), + construct_and_apply_extrinsic, ); } @@ -304,7 +300,7 @@ mod bridge_hub_rococo_tests { #[test] pub fn can_calculate_fee_for_complex_message_delivery_transaction() { - let estimated = bridge_hub_test_utils::test_cases::can_calculate_fee_for_complex_message_delivery_transaction::< + let estimated = bridge_hub_test_utils::test_cases::from_parachain::can_calculate_fee_for_complex_message_delivery_transaction::< Runtime, BridgeGrandpaWestendInstance, BridgeParachainWestendInstance, @@ -327,7 +323,7 @@ mod bridge_hub_rococo_tests { #[test] pub fn can_calculate_fee_for_complex_message_confirmation_transaction() { - let estimated = bridge_hub_test_utils::test_cases::can_calculate_fee_for_complex_message_confirmation_transaction::< + let estimated = bridge_hub_test_utils::test_cases::from_parachain::can_calculate_fee_for_complex_message_confirmation_transaction::< Runtime, BridgeGrandpaWestendInstance, BridgeParachainWestendInstance, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs index 73bddb16369..ffa2fb1cfdc 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs @@ -32,7 +32,6 @@ use bridge_to_rococo_config::{ }; use codec::{Decode, Encode}; use frame_support::{dispatch::GetDispatchInfo, parameter_types, traits::ConstU8}; -use frame_system::pallet_prelude::HeaderFor; use parachains_common::{westend::fee::WeightToFee, AccountId, AuraId, Balance}; use sp_keyring::AccountKeyring::Alice; use sp_runtime::{ @@ -52,13 +51,16 @@ fn construct_extrinsic( sender: sp_keyring::AccountKeyring, call: RuntimeCall, ) -> UncheckedExtrinsic { + let account_id = AccountId32::from(sender.public()); let extra: SignedExtra = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), frame_system::CheckGenesis::::new(), frame_system::CheckEra::::from(Era::immortal()), - frame_system::CheckNonce::::from(0), + frame_system::CheckNonce::::from( + frame_system::Pallet::::account(&account_id).nonce, + ), frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(0), BridgeRejectObsoleteHeadersAndMessages::default(), @@ -68,7 +70,7 @@ fn construct_extrinsic( let signature = payload.using_encoded(|e| sender.sign(e)); UncheckedExtrinsic::new_signed( call, - AccountId32::from(sender.public()).into(), + account_id.into(), Signature::Sr25519(signature.clone()), extra, ) @@ -76,10 +78,9 @@ fn construct_extrinsic( fn construct_and_apply_extrinsic( relayer_at_target: sp_keyring::AccountKeyring, - batch: pallet_utility::Call, + call: RuntimeCall, ) -> sp_runtime::DispatchOutcome { - let batch_call = RuntimeCall::Utility(batch); - let xt = construct_extrinsic(relayer_at_target, batch_call); + let xt = construct_extrinsic(relayer_at_target, call); let r = Executive::apply_extrinsic(xt); r.unwrap() } @@ -91,10 +92,6 @@ fn construct_and_estimate_extrinsic_fee(batch: pallet_utility::Call) -> TransactionPayment::compute_fee(xt.encoded_size() as _, &batch_info, 0) } -fn executive_init_block(header: &HeaderFor) { - Executive::initialize_block(header) -} - fn collator_session_keys() -> bridge_hub_test_utils::CollatorSessionKeys { bridge_hub_test_utils::CollatorSessionKeys::new( AccountId::from(Alice), @@ -222,10 +219,9 @@ fn message_dispatch_routing_works() { #[test] fn relayed_incoming_message_works() { - bridge_hub_test_utils::test_cases::relayed_incoming_message_works::< + bridge_hub_test_utils::test_cases::from_parachain::relayed_incoming_message_works::< Runtime, AllPalletsWithoutSystem, - XcmConfig, ParachainSystem, BridgeGrandpaRococoInstance, BridgeParachainRococoInstance, @@ -235,16 +231,18 @@ fn relayed_incoming_message_works() { collator_session_keys(), bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, + BridgeHubRococoChainId::get(), SIBLING_PARACHAIN_ID, Westend, XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, || (), + construct_and_apply_extrinsic, ) } #[test] pub fn complex_relay_extrinsic_works() { - bridge_hub_test_utils::test_cases::complex_relay_extrinsic_works::< + bridge_hub_test_utils::test_cases::from_parachain::complex_relay_extrinsic_works::< Runtime, AllPalletsWithoutSystem, XcmConfig, @@ -261,10 +259,8 @@ pub fn complex_relay_extrinsic_works() { BridgeHubRococoChainId::get(), Westend, XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, - ExistentialDeposit::get(), - executive_init_block, - construct_and_apply_extrinsic, || (), + construct_and_apply_extrinsic, ); } @@ -288,7 +284,7 @@ pub fn can_calculate_weight_for_paid_export_message_with_reserve_transfer() { #[test] pub fn can_calculate_fee_for_complex_message_delivery_transaction() { - let estimated = bridge_hub_test_utils::test_cases::can_calculate_fee_for_complex_message_delivery_transaction::< + let estimated = bridge_hub_test_utils::test_cases::from_parachain::can_calculate_fee_for_complex_message_delivery_transaction::< Runtime, BridgeGrandpaRococoInstance, BridgeParachainRococoInstance, @@ -311,7 +307,7 @@ pub fn can_calculate_fee_for_complex_message_delivery_transaction() { #[test] pub fn can_calculate_fee_for_complex_message_confirmation_transaction() { - let estimated = bridge_hub_test_utils::test_cases::can_calculate_fee_for_complex_message_confirmation_transaction::< + let estimated = bridge_hub_test_utils::test_cases::from_parachain::can_calculate_fee_for_complex_message_confirmation_transaction::< Runtime, BridgeGrandpaRococoInstance, BridgeParachainRococoInstance, diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml index 7325a87165c..35cab04fcc4 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml @@ -8,6 +8,7 @@ license = "Apache-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } +impl-trait-for-tuples = "0.2" log = { version = "0.4.20", default-features = false } # Substrate @@ -19,6 +20,7 @@ sp-core = { path = "../../../../../substrate/primitives/core", default-features sp-io = { path = "../../../../../substrate/primitives/io", default-features = false } sp-keyring = { path = "../../../../../substrate/primitives/keyring" } sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false } +sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } sp-tracing = { path = "../../../../../substrate/primitives/tracing" } pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false } pallet-utility = { path = "../../../../../substrate/frame/utility", default-features = false } @@ -90,6 +92,7 @@ std = [ "sp-core/std", "sp-io/std", "sp-runtime/std", + "sp-std/std", "xcm-builder/std", "xcm-executor/std", "xcm/std", diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/lib.rs index 26eb09b73fa..445f001f1a4 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/lib.rs @@ -17,5 +17,7 @@ //! Module contains predefined test-case scenarios for "BridgeHub" `Runtime`s. pub mod test_cases; +pub mod test_data; + pub use bp_test_utils::test_header; pub use parachains_runtimes_test_utils::*; diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases.rs deleted file mode 100644 index ddcba3b0399..00000000000 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases.rs +++ /dev/null @@ -1,1588 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -//! Module contains predefined test-case scenarios for `Runtime` with bridging capabilities. - -use bp_messages::{ - source_chain::TargetHeaderChain, - target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch, SourceHeaderChain}, - LaneId, MessageKey, OutboundLaneData, UnrewardedRelayersState, Weight, -}; -use bp_parachains::{BestParaHeadHash, ParaInfo}; -use bp_polkadot_core::parachains::{ParaHash, ParaId}; -use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; -use bp_runtime::{HeaderOf, Parachain, StorageProofSize, UnderlyingChainOf}; -use bp_test_utils::{make_default_justification, prepare_parachain_heads_proof}; -use bridge_runtime_common::{ - messages::{ - source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, - BridgedChain as MessageBridgedChain, MessageBridge, - }, - messages_generation::{ - encode_all_messages, encode_lane_data, prepare_message_delivery_storage_proof, - prepare_messages_storage_proof, - }, - messages_xcm_extension::{XcmAsPlainPayload, XcmBlobMessageDispatchResult}, -}; -use codec::Encode; -use frame_support::{ - assert_ok, - traits::{Get, OnFinalize, OnInitialize, OriginTrait, PalletInfoAccess}, -}; -use frame_system::pallet_prelude::{BlockNumberFor, HeaderFor}; -use pallet_bridge_grandpa::BridgedHeader; -use parachains_common::AccountId; -use parachains_runtimes_test_utils::{ - mock_open_hrmp_channel, AccountIdOf, BalanceOf, CollatorSessionKeys, ExtBuilder, ValidatorIdOf, - XcmReceivedFrom, -}; -use sp_core::H256; -use sp_keyring::AccountKeyring::*; -use sp_runtime::{ - traits::{Header as HeaderT, Zero}, - AccountId32, -}; -use xcm::{ - latest::prelude::*, - prelude::{AlwaysLatest, GetVersion}, -}; -use xcm_builder::DispatchBlobError; -use xcm_executor::{ - traits::{TransactAsset, WeightBounds}, - XcmExecutor, -}; - -// Re-export test_case from assets -pub use asset_test_utils::include_teleports_for_native_asset_works; - -type RuntimeHelper = - parachains_runtimes_test_utils::RuntimeHelper; - -// Re-export test_case from `parachains-runtimes-test-utils` -pub use parachains_runtimes_test_utils::test_cases::change_storage_constant_by_governance_works; - -/// Test-case makes sure that `Runtime` can process bridging initialize via governance-like call -pub fn initialize_bridge_by_governance_works( - collator_session_key: CollatorSessionKeys, - runtime_para_id: u32, - runtime_call_encode: Box< - dyn Fn(pallet_bridge_grandpa::Call) -> Vec, - >, -) where - Runtime: frame_system::Config - + pallet_balances::Config - + pallet_session::Config - + pallet_xcm::Config - + parachain_info::Config - + pallet_collator_selection::Config - + cumulus_pallet_parachain_system::Config - + pallet_bridge_grandpa::Config, - GrandpaPalletInstance: 'static, - ValidatorIdOf: From>, -{ - ExtBuilder::::default() - .with_collators(collator_session_key.collators()) - .with_session_keys(collator_session_key.session_keys()) - .with_para_id(runtime_para_id.into()) - .with_tracing() - .build() - .execute_with(|| { - // check mode before - assert_eq!( - pallet_bridge_grandpa::PalletOperatingMode::::try_get(), - Err(()) - ); - - // encode `initialize` call - let initialize_call = runtime_call_encode(pallet_bridge_grandpa::Call::< - Runtime, - GrandpaPalletInstance, - >::initialize { - init_data: test_data::initialization_data::(12345), - }); - - // overestimate - check weight for `pallet_bridge_grandpa::Pallet::initialize()` call - let require_weight_at_most = - ::DbWeight::get().reads_writes(7, 7); - - // execute XCM with Transacts to `initialize bridge` as governance does - assert_ok!(RuntimeHelper::::execute_as_governance( - initialize_call, - require_weight_at_most - ) - .ensure_complete()); - - // check mode after - assert_eq!( - pallet_bridge_grandpa::PalletOperatingMode::::try_get(), - Ok(bp_runtime::BasicOperatingMode::Normal) - ); - }) -} - -/// Test-case makes sure that `Runtime` can handle xcm `ExportMessage`: -/// Checks if received XCM messages is correctly added to the message outbound queue for delivery. -/// For SystemParachains we expect unpaid execution. -pub fn handle_export_message_from_system_parachain_to_outbound_queue_works< - Runtime, - XcmConfig, - MessagesPalletInstance, ->( - collator_session_key: CollatorSessionKeys, - runtime_para_id: u32, - sibling_parachain_id: u32, - unwrap_pallet_bridge_messages_event: Box< - dyn Fn(Vec) -> Option>, - >, - export_message_instruction: fn() -> Instruction, - expected_lane_id: LaneId, - existential_deposit: Option, - maybe_paid_export_message: Option, - prepare_configuration: impl Fn(), -) where - Runtime: frame_system::Config - + pallet_balances::Config - + pallet_session::Config - + pallet_xcm::Config - + parachain_info::Config - + pallet_collator_selection::Config - + cumulus_pallet_parachain_system::Config - + pallet_bridge_messages::Config, - XcmConfig: xcm_executor::Config, - MessagesPalletInstance: 'static, - ValidatorIdOf: From>, -{ - assert_ne!(runtime_para_id, sibling_parachain_id); - let sibling_parachain_location = MultiLocation::new(1, Parachain(sibling_parachain_id)); - - ExtBuilder::::default() - .with_collators(collator_session_key.collators()) - .with_session_keys(collator_session_key.session_keys()) - .with_para_id(runtime_para_id.into()) - .with_tracing() - .build() - .execute_with(|| { - prepare_configuration(); - - // check queue before - assert_eq!( - pallet_bridge_messages::OutboundLanes::::try_get( - expected_lane_id - ), - Err(()) - ); - - // prepare `ExportMessage` - let xcm = if let Some(fee) = maybe_paid_export_message { - // deposit ED to origin (if needed) - if let Some(ed) = existential_deposit { - XcmConfig::AssetTransactor::deposit_asset( - &ed, - &sibling_parachain_location, - Some(&XcmContext::with_message_id([0; 32])), - ) - .expect("deposited ed"); - } - // deposit fee to origin - XcmConfig::AssetTransactor::deposit_asset( - &fee, - &sibling_parachain_location, - Some(&XcmContext::with_message_id([0; 32])), - ) - .expect("deposited fee"); - - Xcm(vec![ - WithdrawAsset(MultiAssets::from(vec![fee.clone()])), - BuyExecution { fees: fee, weight_limit: Unlimited }, - export_message_instruction(), - ]) - } else { - Xcm(vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - export_message_instruction(), - ]) - }; - - // execute XCM - let hash = xcm.using_encoded(sp_io::hashing::blake2_256); - assert_ok!(XcmExecutor::::execute_xcm( - sibling_parachain_location, - xcm, - hash, - RuntimeHelper::::xcm_max_weight(XcmReceivedFrom::Sibling), - ) - .ensure_complete()); - - // check queue after - assert_eq!( - pallet_bridge_messages::OutboundLanes::::try_get( - expected_lane_id - ), - Ok(OutboundLaneData { - oldest_unpruned_nonce: 1, - latest_received_nonce: 0, - latest_generated_nonce: 1, - }) - ); - - // check events - let mut events = >::events() - .into_iter() - .filter_map(|e| unwrap_pallet_bridge_messages_event(e.event.encode())); - assert!( - events.any(|e| matches!(e, pallet_bridge_messages::Event::MessageAccepted { .. })) - ); - }) -} - -/// Test-case makes sure that Runtime can route XCM messages received in inbound queue, -/// We just test here `MessageDispatch` configuration. -/// We expect that runtime can route messages: -/// 1. to Parent (relay chain) -/// 2. to Sibling parachain -pub fn message_dispatch_routing_works< - Runtime, - AllPalletsWithoutSystem, - XcmConfig, - HrmpChannelOpener, - MessagesPalletInstance, - RuntimeNetwork, - BridgedNetwork, - NetworkDistanceAsParentCount, ->( - collator_session_key: CollatorSessionKeys, - runtime_para_id: u32, - sibling_parachain_id: u32, - unwrap_cumulus_pallet_parachain_system_event: Box< - dyn Fn(Vec) -> Option>, - >, - unwrap_cumulus_pallet_xcmp_queue_event: Box< - dyn Fn(Vec) -> Option>, - >, - expected_lane_id: LaneId, - prepare_configuration: impl Fn(), -) where - Runtime: frame_system::Config - + pallet_balances::Config - + pallet_session::Config - + pallet_xcm::Config - + parachain_info::Config - + pallet_collator_selection::Config - + cumulus_pallet_parachain_system::Config - + cumulus_pallet_xcmp_queue::Config - + pallet_bridge_messages::Config, - AllPalletsWithoutSystem: - OnInitialize> + OnFinalize>, - ::AccountId: - Into<<::RuntimeOrigin as OriginTrait>::AccountId>, - XcmConfig: xcm_executor::Config, - MessagesPalletInstance: 'static, - ValidatorIdOf: From>, - ::AccountId: From, - HrmpChannelOpener: frame_support::inherent::ProvideInherent< - Call = cumulus_pallet_parachain_system::Call, - >, - RuntimeNetwork: Get, - BridgedNetwork: Get, - NetworkDistanceAsParentCount: Get, -{ - assert_ne!(runtime_para_id, sibling_parachain_id); - - struct NetworkWithParentCount(core::marker::PhantomData<(N, C)>); - impl, C: Get> Get for NetworkWithParentCount { - fn get() -> MultiLocation { - MultiLocation { parents: C::get(), interior: X1(GlobalConsensus(N::get())) } - } - } - - ExtBuilder::::default() - .with_collators(collator_session_key.collators()) - .with_session_keys(collator_session_key.session_keys()) - .with_safe_xcm_version(XCM_VERSION) - .with_para_id(runtime_para_id.into()) - .with_tracing() - .build() - .execute_with(|| { - prepare_configuration(); - - let mut alice = [0u8; 32]; - alice[0] = 1; - - let included_head = RuntimeHelper::::run_to_block( - 2, - AccountId::from(alice).into(), - ); - // 1. this message is sent from other global consensus with destination of this Runtime relay chain (UMP) - let bridging_message = - test_data::simulate_message_exporter_on_bridged_chain::< - BridgedNetwork, - NetworkWithParentCount, - AlwaysLatest, - >( - (RuntimeNetwork::get(), Here) - ); - let result = <>::MessageDispatch>::dispatch( - test_data::dispatch_message(expected_lane_id, 1, bridging_message) - ); - assert_eq!(format!("{:?}", result.dispatch_level_result), format!("{:?}", XcmBlobMessageDispatchResult::Dispatched)); - - // check events - UpwardMessageSent - let mut events = >::events() - .into_iter() - .filter_map(|e| unwrap_cumulus_pallet_parachain_system_event(e.event.encode())); - assert!( - events.any(|e| matches!(e, cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. })) - ); - - // 2. this message is sent from other global consensus with destination of this Runtime sibling parachain (HRMP) - let bridging_message = - test_data::simulate_message_exporter_on_bridged_chain::< - BridgedNetwork, - NetworkWithParentCount, - AlwaysLatest, - >( - (RuntimeNetwork::get(), X1(Parachain(sibling_parachain_id))), - ); - - // 2.1. WITHOUT opened hrmp channel -> RoutingError - let result = - <>::MessageDispatch>::dispatch( - DispatchMessage { - key: MessageKey { lane_id: expected_lane_id, nonce: 1 }, - data: DispatchMessageData { payload: Ok(bridging_message.clone()) }, - } - ); - assert_eq!(format!("{:?}", result.dispatch_level_result), format!("{:?}", XcmBlobMessageDispatchResult::NotDispatched(Some(DispatchBlobError::RoutingError)))); - - // check events - no XcmpMessageSent - assert_eq!(>::events() - .into_iter() - .filter_map(|e| unwrap_cumulus_pallet_xcmp_queue_event(e.event.encode())) - .count(), 0); - - // 2.1. WITH hrmp channel -> Ok - mock_open_hrmp_channel::(runtime_para_id.into(), sibling_parachain_id.into(), included_head, &alice); - let result = <>::MessageDispatch>::dispatch( - DispatchMessage { - key: MessageKey { lane_id: expected_lane_id, nonce: 1 }, - data: DispatchMessageData { payload: Ok(bridging_message) }, - } - ); - assert_eq!(format!("{:?}", result.dispatch_level_result), format!("{:?}", XcmBlobMessageDispatchResult::Dispatched)); - - // check events - XcmpMessageSent - let mut events = >::events() - .into_iter() - .filter_map(|e| unwrap_cumulus_pallet_xcmp_queue_event(e.event.encode())); - assert!( - events.any(|e| matches!(e, cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. })) - ); - }) -} - -/// Test-case makes sure that Runtime can dispatch XCM messages submitted by relayer, -/// with proofs (finality, para heads, message) independently submitted. -pub fn relayed_incoming_message_works( - collator_session_key: CollatorSessionKeys, - runtime_para_id: u32, - bridged_para_id: u32, - sibling_parachain_id: u32, - local_relay_chain_id: NetworkId, - lane_id: LaneId, - prepare_configuration: impl Fn(), -) where - Runtime: frame_system::Config - + pallet_balances::Config - + pallet_session::Config - + pallet_xcm::Config - + parachain_info::Config - + pallet_collator_selection::Config - + cumulus_pallet_parachain_system::Config - + cumulus_pallet_xcmp_queue::Config - + pallet_bridge_grandpa::Config - + pallet_bridge_parachains::Config - + pallet_bridge_messages::Config, - AllPalletsWithoutSystem: OnInitialize> - + OnFinalize>, - GPI: 'static, - PPI: 'static, - MPI: 'static, - MB: MessageBridge, - ::BridgedChain: Send + Sync + 'static, - ::ThisChain: Send + Sync + 'static, - UnderlyingChainOf>: bp_runtime::Chain + Parachain, - XcmConfig: xcm_executor::Config, - HrmpChannelOpener: frame_support::inherent::ProvideInherent< - Call = cumulus_pallet_parachain_system::Call, - >, - ValidatorIdOf: From>, - <>::SourceHeaderChain as SourceHeaderChain>::MessagesProof: From>, - <>::BridgedChain as bp_runtime::Chain>::Hash: From, - ParaHash: From<<>::BridgedChain as bp_runtime::Chain>::Hash>, - ::AccountId: - Into<<::RuntimeOrigin as OriginTrait>::AccountId>, - ::AccountId: From, - AccountIdOf: From, - >::InboundRelayer: From, -{ - assert_ne!(runtime_para_id, sibling_parachain_id); - - ExtBuilder::::default() - .with_collators(collator_session_key.collators()) - .with_session_keys(collator_session_key.session_keys()) - .with_safe_xcm_version(XCM_VERSION) - .with_para_id(runtime_para_id.into()) - .with_tracing() - .build() - .execute_with(|| { - prepare_configuration(); - - let mut alice = [0u8; 32]; - alice[0] = 1; - - let included_head = RuntimeHelper::::run_to_block( - 2, - AccountId::from(alice).into(), - ); - mock_open_hrmp_channel::( - runtime_para_id.into(), - sibling_parachain_id.into(), - included_head, - &alice, - ); - - // start with bridged chain block#0 - let init_data = test_data::initialization_data::(0); - pallet_bridge_grandpa::Pallet::::initialize( - RuntimeHelper::::root_origin(), - init_data, - ) - .unwrap(); - - // set up relayer details and proofs - - let message_destination = - X2(GlobalConsensus(local_relay_chain_id), Parachain(sibling_parachain_id)); - // some random numbers (checked by test) - let message_nonce = 1; - let para_header_number = 5; - let relay_header_number = 1; - - let relayer_at_target = Bob; - let relayer_id_on_target: AccountIdOf = relayer_at_target.public().into(); - let relayer_at_source = Dave; - let relayer_id_on_source: AccountId32 = relayer_at_source.public().into(); - - let xcm = vec![xcm::v3::Instruction::<()>::ClearOrigin; 42]; - let expected_dispatch = xcm::latest::Xcm::<()>({ - let mut expected_instructions = xcm.clone(); - // dispatch prepends bridge pallet instance - expected_instructions.insert( - 0, - DescendOrigin(X1(PalletInstance( - as PalletInfoAccess>::index() - as u8, - ))), - ); - expected_instructions - }); - // generate bridged relay chain finality, parachain heads and message proofs, - // to be submitted by relayer to this chain. - let ( - relay_chain_header, - grandpa_justification, - bridged_para_head, - parachain_heads, - para_heads_proof, - message_proof, - ) = test_data::make_complex_relayer_delivery_proofs::< - >::BridgedChain, - MB, - (), - >( - lane_id, - xcm.into(), - message_nonce, - message_destination, - para_header_number, - relay_header_number, - bridged_para_id, - ); - - // submit bridged relay chain finality proof - { - let result = pallet_bridge_grandpa::Pallet::::submit_finality_proof( - RuntimeHelper::::origin_of(relayer_id_on_target.clone()), - Box::new(relay_chain_header.clone()), - grandpa_justification, - ); - assert_ok!(result); - assert_eq!(result.unwrap().pays_fee, frame_support::dispatch::Pays::Yes); - } - - // verify finality proof correctly imported - assert_eq!( - pallet_bridge_grandpa::BestFinalized::::get().unwrap().1, - relay_chain_header.hash() - ); - assert!(pallet_bridge_grandpa::ImportedHeaders::::contains_key( - relay_chain_header.hash() - )); - - // submit parachain heads proof - { - let result = - pallet_bridge_parachains::Pallet::::submit_parachain_heads( - RuntimeHelper::::origin_of(relayer_id_on_target.clone()), - (relay_header_number, relay_chain_header.hash().into()), - parachain_heads, - para_heads_proof, - ); - assert_ok!(result); - assert_eq!(result.unwrap().pays_fee, frame_support::dispatch::Pays::Yes); - } - // verify parachain head proof correctly imported - assert_eq!( - pallet_bridge_parachains::ParasInfo::::get(ParaId(bridged_para_id)), - Some(ParaInfo { - best_head_hash: BestParaHeadHash { - at_relay_block_number: relay_header_number, - head_hash: bridged_para_head.hash() - }, - next_imported_hash_position: 1, - }) - ); - - // import message - assert!(RuntimeHelper::>::take_xcm( - sibling_parachain_id.into() - ) - .is_none()); - assert_eq!( - pallet_bridge_messages::InboundLanes::::get(lane_id) - .last_delivered_nonce(), - 0, - ); - // submit message proof - { - let result = pallet_bridge_messages::Pallet::::receive_messages_proof( - RuntimeHelper::::origin_of(relayer_id_on_target), - relayer_id_on_source.into(), - message_proof.into(), - 1, - Weight::MAX / 1000, - ); - assert_ok!(result); - assert_eq!(result.unwrap().pays_fee, frame_support::dispatch::Pays::Yes); - } - // verify message correctly imported and dispatched - assert_eq!( - pallet_bridge_messages::InboundLanes::::get(lane_id) - .last_delivered_nonce(), - 1, - ); - - // verify relayed bridged XCM message is dispatched to destination sibling para - let dispatched = RuntimeHelper::>::take_xcm( - sibling_parachain_id.into(), - ) - .unwrap(); - // verify contains original message - let dispatched = xcm::latest::Xcm::<()>::try_from(dispatched).unwrap(); - let mut dispatched_clone = dispatched.clone(); - for (idx, expected_instr) in expected_dispatch.0.iter().enumerate() { - assert_eq!(expected_instr, &dispatched.0[idx]); - assert_eq!(expected_instr, &dispatched_clone.0.remove(0)); - } - match dispatched_clone.0.len() { - 0 => (), - 1 => assert!(matches!(dispatched_clone.0[0], SetTopic(_))), - count => assert!(false, "Unexpected messages count: {:?}", count), - } - }) -} - -/// Test-case makes sure that Runtime can dispatch XCM messages submitted by relayer, -/// with proofs (finality, para heads, message) batched together in signed extrinsic. -/// Also verifies relayer transaction signed extensions work as intended. -pub fn complex_relay_extrinsic_works( - collator_session_key: CollatorSessionKeys, - runtime_para_id: u32, - bridged_para_id: u32, - sibling_parachain_id: u32, - bridged_chain_id: bp_runtime::ChainId, - local_relay_chain_id: NetworkId, - lane_id: LaneId, - existential_deposit: BalanceOf, - executive_init_block: fn(&HeaderFor), - construct_and_apply_extrinsic: fn( - sp_keyring::AccountKeyring, - pallet_utility::Call:: - ) -> sp_runtime::DispatchOutcome, - prepare_configuration: impl Fn(), -) where - Runtime: frame_system::Config - + pallet_balances::Config - + pallet_utility::Config - + pallet_session::Config - + pallet_xcm::Config - + parachain_info::Config - + pallet_collator_selection::Config - + cumulus_pallet_parachain_system::Config - + cumulus_pallet_xcmp_queue::Config - + pallet_bridge_grandpa::Config - + pallet_bridge_parachains::Config - + pallet_bridge_messages::Config - + pallet_bridge_relayers::Config, - AllPalletsWithoutSystem: OnInitialize> - + OnFinalize>, - GPI: 'static, - PPI: 'static, - MPI: 'static, - MB: MessageBridge, - ::BridgedChain: Send + Sync + 'static, - ::ThisChain: Send + Sync + 'static, - UnderlyingChainOf>: bp_runtime::Chain + Parachain, - XcmConfig: xcm_executor::Config, - HrmpChannelOpener: frame_support::inherent::ProvideInherent< - Call = cumulus_pallet_parachain_system::Call, - >, - ValidatorIdOf: From>, - <>::SourceHeaderChain as SourceHeaderChain>::MessagesProof: From>, - <>::BridgedChain as bp_runtime::Chain>::Hash: From, - ParaHash: From<<>::BridgedChain as bp_runtime::Chain>::Hash>, - ::AccountId: - Into<<::RuntimeOrigin as OriginTrait>::AccountId>, - AccountIdOf: From, - ::AccountId: From, - >::InboundRelayer: From, - ::RuntimeCall: - From> - + From> - + From> -{ - assert_ne!(runtime_para_id, sibling_parachain_id); - - // Relayer account at local/this BH. - let relayer_at_target = Bob; - let relayer_id_on_target: AccountIdOf = relayer_at_target.public().into(); - let relayer_initial_balance = existential_deposit * 100000u32.into(); - // Relayer account at remote/bridged BH. - let relayer_at_source = Dave; - let relayer_id_on_source: AccountId32 = relayer_at_source.public().into(); - - ExtBuilder::::default() - .with_collators(collator_session_key.collators()) - .with_session_keys(collator_session_key.session_keys()) - .with_safe_xcm_version(XCM_VERSION) - .with_para_id(runtime_para_id.into()) - .with_balances(vec![(relayer_id_on_target.clone(), relayer_initial_balance)]) - .with_tracing() - .build() - .execute_with(|| { - prepare_configuration(); - - let mut alice = [0u8; 32]; - alice[0] = 1; - - let included_head = RuntimeHelper::::run_to_block( - 2, - AccountId::from(alice).into(), - ); - let zero: BlockNumberFor = 0u32.into(); - let genesis_hash = frame_system::Pallet::::block_hash(zero); - let mut header: HeaderFor = bp_test_utils::test_header(1u32.into()); - header.set_parent_hash(genesis_hash); - executive_init_block(&header); - - mock_open_hrmp_channel::( - runtime_para_id.into(), - sibling_parachain_id.into(), - included_head, - &alice, - ); - - // start with bridged chain block#0 - let init_data = test_data::initialization_data::(0); - pallet_bridge_grandpa::Pallet::::initialize( - RuntimeHelper::::root_origin(), - init_data, - ) - .unwrap(); - - // set up relayer details and proofs - - let message_destination = - X2(GlobalConsensus(local_relay_chain_id), Parachain(sibling_parachain_id)); - // some random numbers (checked by test) - let message_nonce = 1; - let para_header_number = 5; - let relay_header_number = 1; - - let xcm = vec![xcm::latest::Instruction::<()>::ClearOrigin; 42]; - let expected_dispatch = xcm::latest::Xcm::<()>({ - let mut expected_instructions = xcm.clone(); - // dispatch prepends bridge pallet instance - expected_instructions.insert( - 0, - DescendOrigin(X1(PalletInstance( - as PalletInfoAccess>::index() - as u8, - ))), - ); - expected_instructions - }); - // generate bridged relay chain finality, parachain heads and message proofs, - // to be submitted by relayer to this chain. - let ( - relay_chain_header, - grandpa_justification, - bridged_para_head, - parachain_heads, - para_heads_proof, - message_proof, - ) = test_data::make_complex_relayer_delivery_proofs::< - >::BridgedChain, - MB, - (), - >( - lane_id, - xcm.clone().into(), - message_nonce, - message_destination, - para_header_number, - relay_header_number, - bridged_para_id, - ); - - let relay_chain_header_hash = relay_chain_header.hash(); - let batch = test_data::make_complex_relayer_delivery_batch::( - relay_chain_header, - grandpa_justification, - parachain_heads, - para_heads_proof, - message_proof, - relayer_id_on_source, - ); - - // sanity checks - before relayer extrinsic - assert!(RuntimeHelper::>::take_xcm( - sibling_parachain_id.into() - ) - .is_none()); - assert_eq!( - pallet_bridge_messages::InboundLanes::::get(lane_id) - .last_delivered_nonce(), - 0, - ); - let msg_proofs_rewards_account = RewardsAccountParams::new( - lane_id, - bridged_chain_id, - RewardsAccountOwner::ThisChain, - ); - assert_eq!( - pallet_bridge_relayers::RelayerRewards::::get( - relayer_id_on_target.clone(), - msg_proofs_rewards_account - ), - None, - ); - - // construct and apply extrinsic containing batch calls: - // bridged relay chain finality proof - // + parachain heads proof - // + submit message proof - let dispatch_outcome = construct_and_apply_extrinsic(relayer_at_target, batch); - - // verify finality proof correctly imported - assert_ok!(dispatch_outcome); - assert_eq!( - >::get().unwrap().1, - relay_chain_header_hash - ); - assert!(>::contains_key( - relay_chain_header_hash - )); - // verify parachain head proof correctly imported - assert_eq!( - pallet_bridge_parachains::ParasInfo::::get(ParaId(bridged_para_id)), - Some(ParaInfo { - best_head_hash: BestParaHeadHash { - at_relay_block_number: relay_header_number, - head_hash: bridged_para_head.hash() - }, - next_imported_hash_position: 1, - }) - ); - // verify message correctly imported and dispatched - assert_eq!( - pallet_bridge_messages::InboundLanes::::get(lane_id) - .last_delivered_nonce(), - 1, - ); - // verify relayer is refunded - assert!(pallet_bridge_relayers::RelayerRewards::::get( - relayer_id_on_target, - msg_proofs_rewards_account - ) - .is_some()); - - // verify relayed bridged XCM message is dispatched to destination sibling para - let dispatched = RuntimeHelper::>::take_xcm( - sibling_parachain_id.into(), - ) - .unwrap(); - // verify contains original message - let dispatched = xcm::latest::Xcm::<()>::try_from(dispatched).unwrap(); - let mut dispatched_clone = dispatched.clone(); - for (idx, expected_instr) in expected_dispatch.0.iter().enumerate() { - assert_eq!(expected_instr, &dispatched.0[idx]); - assert_eq!(expected_instr, &dispatched_clone.0.remove(0)); - } - match dispatched_clone.0.len() { - 0 => (), - 1 => assert!(matches!(dispatched_clone.0[0], SetTopic(_))), - count => assert!(false, "Unexpected messages count: {:?}", count), - } - }) -} - -/// Estimates XCM execution fee for paid `ExportMessage` processing. -pub fn can_calculate_weight_for_paid_export_message_with_reserve_transfer< - Runtime, - XcmConfig, - WeightToFee, ->() -> u128 -where - Runtime: frame_system::Config + pallet_balances::Config, - XcmConfig: xcm_executor::Config, - WeightToFee: frame_support::weights::WeightToFee>, - ::Balance: From + Into, -{ - // data here are not relevant for weighing - let mut xcm = Xcm(vec![ - WithdrawAsset(MultiAssets::from(vec![MultiAsset { - id: Concrete(MultiLocation { parents: 1, interior: Here }), - fun: Fungible(34333299), - }])), - BuyExecution { - fees: MultiAsset { - id: Concrete(MultiLocation { parents: 1, interior: Here }), - fun: Fungible(34333299), - }, - weight_limit: Unlimited, - }, - ExportMessage { - network: Polkadot, - destination: X1(Parachain(1000)), - xcm: Xcm(vec![ - ReserveAssetDeposited(MultiAssets::from(vec![MultiAsset { - id: Concrete(MultiLocation { - parents: 2, - interior: X1(GlobalConsensus(Kusama)), - }), - fun: Fungible(1000000000000), - }])), - ClearOrigin, - BuyExecution { - fees: MultiAsset { - id: Concrete(MultiLocation { - parents: 2, - interior: X1(GlobalConsensus(Kusama)), - }), - fun: Fungible(1000000000000), - }, - weight_limit: Unlimited, - }, - DepositAsset { - assets: Wild(AllCounted(1)), - beneficiary: MultiLocation { - parents: 0, - interior: X1(xcm::latest::prelude::AccountId32 { - network: None, - id: [ - 212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, - 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, - 109, 162, 125, - ], - }), - }, - }, - SetTopic([ - 116, 82, 194, 132, 171, 114, 217, 165, 23, 37, 161, 177, 165, 179, 247, 114, - 137, 101, 147, 70, 28, 157, 168, 32, 154, 63, 74, 228, 152, 180, 5, 63, - ]), - ]), - }, - DepositAsset { - assets: Wild(All), - beneficiary: MultiLocation { parents: 1, interior: X1(Parachain(1000)) }, - }, - SetTopic([ - 36, 224, 250, 165, 82, 195, 67, 110, 160, 170, 140, 87, 217, 62, 201, 164, 42, 98, 219, - 157, 124, 105, 248, 25, 131, 218, 199, 36, 109, 173, 100, 122, - ]), - ]); - - // get weight - let weight = XcmConfig::Weigher::weight(&mut xcm); - assert_ok!(weight); - let weight = weight.unwrap(); - // check if sane - let max_expected = Runtime::BlockWeights::get().max_block / 10; - assert!( - weight.all_lte(max_expected), - "calculated weight: {:?}, max_expected: {:?}", - weight, - max_expected - ); - - // check fee, should not be 0 - let estimated_fee = WeightToFee::weight_to_fee(&weight); - assert!(estimated_fee > BalanceOf::::zero()); - - sp_tracing::try_init_simple(); - log::error!( - target: "bridges::estimate", - "Estimate fee: {:?} for `ExportMessage` for runtime: {:?}", - estimated_fee, - Runtime::Version::get(), - ); - - estimated_fee.into() -} - -/// Estimates transaction fee for default message delivery transaction (batched with required -/// proofs) from bridged parachain. -pub fn can_calculate_fee_for_complex_message_delivery_transaction( - collator_session_key: CollatorSessionKeys, - compute_extrinsic_fee: fn(pallet_utility::Call::) -> u128, -) -> u128 -where - Runtime: frame_system::Config - + pallet_balances::Config - + pallet_session::Config - + pallet_xcm::Config - + parachain_info::Config - + pallet_collator_selection::Config - + cumulus_pallet_parachain_system::Config - + pallet_bridge_grandpa::Config - + pallet_bridge_parachains::Config - + pallet_bridge_messages::Config - + pallet_utility::Config, - GPI: 'static, - PPI: 'static, - MPI: 'static, - MB: MessageBridge, - ::BridgedChain: Send + Sync + 'static, - ::ThisChain: Send + Sync + 'static, - UnderlyingChainOf>: bp_runtime::Chain + Parachain, - ValidatorIdOf: From>, - <>::SourceHeaderChain as SourceHeaderChain>::MessagesProof: - From>, - <>::BridgedChain as bp_runtime::Chain>::Hash: From, - ParaHash: From<<>::BridgedChain as bp_runtime::Chain>::Hash>, - ::AccountId: - Into<<::RuntimeOrigin as OriginTrait>::AccountId>, - ::AccountId: From, - AccountIdOf: From, - >::InboundRelayer: From, - ::RuntimeCall: - From> - + From> - + From>, -{ - ExtBuilder::::default() - .with_collators(collator_session_key.collators()) - .with_session_keys(collator_session_key.session_keys()) - .with_safe_xcm_version(XCM_VERSION) - .with_para_id(1000.into()) - .with_tracing() - .build() - .execute_with(|| { - // generate bridged relay chain finality, parachain heads and message proofs, - // to be submitted by relayer to this chain. - // - // we don't care about parameter values here, apart from the XCM message size. But we - // do not need to have a large message here, because we're charging for every byte of - // the message additionally - let ( - relay_chain_header, - grandpa_justification, - _, - parachain_heads, - para_heads_proof, - message_proof, - ) = test_data::make_complex_relayer_delivery_proofs::< - >::BridgedChain, - MB, - (), - >( - LaneId::default(), - vec![xcm::v3::Instruction::<()>::ClearOrigin; 1_024].into(), - 1, - X2(GlobalConsensus(Polkadot), Parachain(1_000)), - 1, - 5, - 1_000, - ); - - // generate batch call that provides finality for bridged relay and parachains + message - // proof - let batch = test_data::make_complex_relayer_delivery_batch::( - relay_chain_header, - grandpa_justification, - parachain_heads, - para_heads_proof, - message_proof, - Dave.public().into(), - ); - let estimated_fee = compute_extrinsic_fee(batch); - - log::error!( - target: "bridges::estimate", - "Estimate fee: {:?} for single message delivery for runtime: {:?}", - estimated_fee, - Runtime::Version::get(), - ); - - estimated_fee - }) -} - -/// Estimates transaction fee for default message confirmation transaction (batched with required -/// proofs) from bridged parachain. -pub fn can_calculate_fee_for_complex_message_confirmation_transaction( - collator_session_key: CollatorSessionKeys, - compute_extrinsic_fee: fn(pallet_utility::Call::) -> u128, -) -> u128 -where - Runtime: frame_system::Config - + pallet_balances::Config - + pallet_session::Config - + pallet_xcm::Config - + parachain_info::Config - + pallet_collator_selection::Config - + cumulus_pallet_parachain_system::Config - + pallet_bridge_grandpa::Config - + pallet_bridge_parachains::Config - + pallet_bridge_messages::Config - + pallet_utility::Config, - GPI: 'static, - PPI: 'static, - MPI: 'static, - MB: MessageBridge, - ::BridgedChain: Send + Sync + 'static, - ::ThisChain: Send + Sync + 'static, - <::ThisChain as bp_runtime::Chain>::AccountId: From, - UnderlyingChainOf>: bp_runtime::Chain + Parachain, - ValidatorIdOf: From>, - <>::SourceHeaderChain as SourceHeaderChain>::MessagesProof: - From>, - <>::BridgedChain as bp_runtime::Chain>::Hash: From, - ParaHash: From<<>::BridgedChain as bp_runtime::Chain>::Hash>, - ::AccountId: - Into<<::RuntimeOrigin as OriginTrait>::AccountId>, - ::AccountId: From, - AccountIdOf: From, - >::InboundRelayer: From, - <>::TargetHeaderChain as TargetHeaderChain< - XcmAsPlainPayload, - Runtime::AccountId, - >>::MessagesDeliveryProof: From>, - ::RuntimeCall: - From> - + From> - + From>, -{ - ExtBuilder::::default() - .with_collators(collator_session_key.collators()) - .with_session_keys(collator_session_key.session_keys()) - .with_safe_xcm_version(XCM_VERSION) - .with_para_id(1000.into()) - .with_tracing() - .build() - .execute_with(|| { - // generate bridged relay chain finality, parachain heads and message proofs, - // to be submitted by relayer to this chain. - let unrewarded_relayers = UnrewardedRelayersState { - unrewarded_relayer_entries: 1, - total_messages: 1, - ..Default::default() - }; - let ( - relay_chain_header, - grandpa_justification, - _, - parachain_heads, - para_heads_proof, - message_delivery_proof, - ) = test_data::make_complex_relayer_confirmation_proofs::< - >::BridgedChain, - MB, - (), - >(LaneId::default(), 1, 5, 1_000, Alice.public().into(), unrewarded_relayers.clone()); - - // generate batch call that provides finality for bridged relay and parachains + message - // proof - let batch = test_data::make_complex_relayer_confirmation_batch::( - relay_chain_header, - grandpa_justification, - parachain_heads, - para_heads_proof, - message_delivery_proof, - unrewarded_relayers, - ); - let estimated_fee = compute_extrinsic_fee(batch); - - log::error!( - target: "bridges::estimate", - "Estimate fee: {:?} for single message confirmation for runtime: {:?}", - estimated_fee, - Runtime::Version::get(), - ); - - estimated_fee - }) -} - -pub mod test_data { - use super::*; - use bp_header_chain::{justification::GrandpaJustification, ChainWithGrandpa}; - use bp_messages::{DeliveredMessages, InboundLaneData, MessageNonce, UnrewardedRelayer}; - use bp_polkadot_core::parachains::{ParaHash, ParaHead, ParaHeadsProof, ParaId}; - use bp_runtime::{BasicOperatingMode, HashOf}; - use bp_test_utils::authority_list; - use sp_runtime::{DigestItem, SaturatedConversion}; - use xcm_builder::{HaulBlob, HaulBlobError, HaulBlobExporter}; - use xcm_executor::traits::{validate_export, ExportXcm}; - - pub fn prepare_inbound_xcm( - xcm_message: Xcm, - destination: InteriorMultiLocation, - ) -> Vec { - let location = xcm::VersionedInteriorMultiLocation::V3(destination); - let xcm = xcm::VersionedXcm::::V3(xcm_message); - // this is the `BridgeMessage` from polkadot xcm builder, but it has no constructor - // or public fields, so just tuple - // (double encoding, because `.encode()` is called on original Xcm BLOB when it is pushed - // to the storage) - (location, xcm).encode().encode() - } - - /// Prepare a batch call with relay finality proof, parachain head proof and message proof. - pub fn make_complex_relayer_delivery_batch( - relay_chain_header: BridgedHeader, - grandpa_justification: GrandpaJustification>, - parachain_heads: Vec<(ParaId, ParaHash)>, - para_heads_proof: ParaHeadsProof, - message_proof: FromBridgedChainMessagesProof, - relayer_id_at_bridged_chain: AccountId32, - ) -> pallet_utility::Call where - Runtime:pallet_bridge_grandpa::Config - + pallet_bridge_parachains::Config - + pallet_bridge_messages::Config - + pallet_utility::Config, - GPI: 'static, - PPI: 'static, - MPI: 'static, - ParaHash: From<<>::BridgedChain as bp_runtime::Chain>::Hash>, - <>::BridgedChain as bp_runtime::Chain>::Hash: From, - <>::SourceHeaderChain as SourceHeaderChain>::MessagesProof: - From>, - >::InboundRelayer: From, - ::RuntimeCall: - From> - + From> - + From>, - { - let relay_chain_header_hash = relay_chain_header.hash(); - let relay_chain_header_number = *relay_chain_header.number(); - let submit_grandpa = pallet_bridge_grandpa::Call::::submit_finality_proof { - finality_target: Box::new(relay_chain_header), - justification: grandpa_justification, - }; - let submit_para_head = - pallet_bridge_parachains::Call::::submit_parachain_heads { - at_relay_block: ( - relay_chain_header_number.saturated_into(), - relay_chain_header_hash.into(), - ), - parachains: parachain_heads, - parachain_heads_proof: para_heads_proof, - }; - let submit_message = pallet_bridge_messages::Call::::receive_messages_proof { - relayer_id_at_bridged_chain: relayer_id_at_bridged_chain.into(), - proof: message_proof.into(), - messages_count: 1, - dispatch_weight: Weight::from_parts(1000000000, 0), - }; - pallet_utility::Call::::batch_all { - calls: vec![submit_grandpa.into(), submit_para_head.into(), submit_message.into()], - } - } - - /// Prepare a batch call with relay finality proof, parachain head proof and message delivery - /// proof. - pub fn make_complex_relayer_confirmation_batch( - relay_chain_header: BridgedHeader, - grandpa_justification: GrandpaJustification>, - parachain_heads: Vec<(ParaId, ParaHash)>, - para_heads_proof: ParaHeadsProof, - message_delivery_proof: FromBridgedChainMessagesDeliveryProof, - relayers_state: UnrewardedRelayersState, - ) -> pallet_utility::Call where - Runtime:pallet_bridge_grandpa::Config - + pallet_bridge_parachains::Config - + pallet_bridge_messages::Config - + pallet_utility::Config, - GPI: 'static, - PPI: 'static, - MPI: 'static, - ParaHash: From<<>::BridgedChain as bp_runtime::Chain>::Hash>, - <>::BridgedChain as bp_runtime::Chain>::Hash: From, - <>::TargetHeaderChain as TargetHeaderChain< - XcmAsPlainPayload, - Runtime::AccountId, - >>::MessagesDeliveryProof: From>, - ::RuntimeCall: - From> - + From> - + From>, - { - let relay_chain_header_hash = relay_chain_header.hash(); - let relay_chain_header_number = *relay_chain_header.number(); - let submit_grandpa = pallet_bridge_grandpa::Call::::submit_finality_proof { - finality_target: Box::new(relay_chain_header), - justification: grandpa_justification, - }; - let submit_para_head = - pallet_bridge_parachains::Call::::submit_parachain_heads { - at_relay_block: ( - relay_chain_header_number.saturated_into(), - relay_chain_header_hash.into(), - ), - parachains: parachain_heads, - parachain_heads_proof: para_heads_proof, - }; - let submit_message_delivery_proof = - pallet_bridge_messages::Call::::receive_messages_delivery_proof { - proof: message_delivery_proof.into(), - relayers_state, - }; - pallet_utility::Call::::batch_all { - calls: vec![ - submit_grandpa.into(), - submit_para_head.into(), - submit_message_delivery_proof.into(), - ], - } - } - - /// Prepare storage proofs of messages, stored at the source chain. - pub fn make_complex_relayer_delivery_proofs( - lane_id: LaneId, - xcm_message: Xcm, - message_nonce: MessageNonce, - message_destination: Junctions, - para_header_number: u32, - relay_header_number: u32, - bridged_para_id: u32, - ) -> ( - HeaderOf, - GrandpaJustification>, - ParaHead, - Vec<(ParaId, ParaHash)>, - ParaHeadsProof, - FromBridgedChainMessagesProof, - ) - where - BridgedRelayChain: ChainWithGrandpa, - HashOf: From, - MB: MessageBridge, - ::BridgedChain: Send + Sync + 'static, - ::ThisChain: Send + Sync + 'static, - UnderlyingChainOf>: bp_runtime::Chain + Parachain, - { - let message_payload = prepare_inbound_xcm(xcm_message, message_destination); - let message_size = StorageProofSize::Minimal(message_payload.len() as u32); - // prepare para storage proof containing message - let (para_state_root, para_storage_proof) = prepare_messages_storage_proof::( - lane_id, - message_nonce..=message_nonce, - None, - message_size, - message_payload, - encode_all_messages, - encode_lane_data, - ); - - let ( - relay_chain_header, - justification, - bridged_para_head, - parachain_heads, - para_heads_proof, - ) = make_complex_bridged_heads_proof::( - para_state_root, - para_header_number, - relay_header_number, - bridged_para_id, - ); - - let message_proof = FromBridgedChainMessagesProof { - bridged_header_hash: bridged_para_head.hash(), - storage_proof: para_storage_proof, - lane: lane_id, - nonces_start: message_nonce, - nonces_end: message_nonce, - }; - - ( - relay_chain_header, - justification, - bridged_para_head, - parachain_heads, - para_heads_proof, - message_proof, - ) - } - - /// Prepare storage proofs of message confirmations, stored at the target chain. - pub fn make_complex_relayer_confirmation_proofs( - lane_id: LaneId, - para_header_number: u32, - relay_header_number: u32, - bridged_para_id: u32, - relayer_id_at_this_chain: AccountId32, - relayers_state: UnrewardedRelayersState, - ) -> ( - HeaderOf, - GrandpaJustification>, - ParaHead, - Vec<(ParaId, ParaHash)>, - ParaHeadsProof, - FromBridgedChainMessagesDeliveryProof, - ) - where - BridgedRelayChain: ChainWithGrandpa, - HashOf: From, - MB: MessageBridge, - ::BridgedChain: Send + Sync + 'static, - ::ThisChain: Send + Sync + 'static, - <::ThisChain as bp_runtime::Chain>::AccountId: From, - UnderlyingChainOf>: bp_runtime::Chain + Parachain, - { - // prepare para storage proof containing message delivery proof - let (para_state_root, para_storage_proof) = prepare_message_delivery_storage_proof::( - lane_id, - InboundLaneData { - relayers: vec![ - UnrewardedRelayer { - relayer: relayer_id_at_this_chain.into(), - messages: DeliveredMessages::new(1) - }; - relayers_state.unrewarded_relayer_entries as usize - ] - .into(), - last_confirmed_nonce: 1, - }, - StorageProofSize::Minimal(0), - ); - - let ( - relay_chain_header, - justification, - bridged_para_head, - parachain_heads, - para_heads_proof, - ) = make_complex_bridged_heads_proof::( - para_state_root, - para_header_number, - relay_header_number, - bridged_para_id, - ); - - let message_delivery_proof = FromBridgedChainMessagesDeliveryProof { - bridged_header_hash: bridged_para_head.hash(), - storage_proof: para_storage_proof, - lane: lane_id, - }; - - ( - relay_chain_header, - justification, - bridged_para_head, - parachain_heads, - para_heads_proof, - message_delivery_proof, - ) - } - - /// Make bridged parachain header with given state root and relay header that is finalizing it. - pub fn make_complex_bridged_heads_proof( - para_state_root: ParaHash, - para_header_number: u32, - relay_header_number: u32, - bridged_para_id: u32, - ) -> ( - HeaderOf, - GrandpaJustification>, - ParaHead, - Vec<(ParaId, ParaHash)>, - ParaHeadsProof, - ) - where - BridgedRelayChain: ChainWithGrandpa, - HashOf: From, - MB: MessageBridge, - ::BridgedChain: Send + Sync + 'static, - ::ThisChain: Send + Sync + 'static, - UnderlyingChainOf>: bp_runtime::Chain + Parachain, - { - let bridged_para_head = ParaHead( - bp_test_utils::test_header_with_root::>( - para_header_number.into(), - para_state_root.into(), - ) - .encode(), - ); - let (relay_state_root, para_heads_proof, parachain_heads) = - prepare_parachain_heads_proof::>(vec![( - bridged_para_id, - bridged_para_head.clone(), - )]); - assert_eq!(bridged_para_head.hash(), parachain_heads[0].1); - - // import bridged relay chain block#1 with state root containing head#5 of bridged parachain - let mut relay_chain_header: BridgedRelayChain::Header = - bp_test_utils::test_header_with_root( - relay_header_number.into(), - relay_state_root.into(), - ); - // to compute proper cost of GRANDPA call, let's add some dummy bytes to header, so that the - // `submit_finality_proof` call size would be close to maximal expected (and refundable) - let expected_bytes_in_grandpa_call = BridgedRelayChain::AVERAGE_HEADER_SIZE - .saturating_mul(BridgedRelayChain::REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY) - .saturating_add(BridgedRelayChain::MAX_MANDATORY_HEADER_SIZE) - as usize; - let extra_bytes_required = - expected_bytes_in_grandpa_call.saturating_sub(relay_chain_header.encoded_size()); - relay_chain_header - .digest_mut() - .push(DigestItem::Other(vec![42; extra_bytes_required])); - - let justification = make_default_justification(&relay_chain_header); - (relay_chain_header, justification, bridged_para_head, parachain_heads, para_heads_proof) - } - - /// Helper that creates InitializationData mock data, that can be used to initialize bridge - /// GRANDPA pallet - pub fn initialization_data< - Runtime: pallet_bridge_grandpa::Config, - GrandpaPalletInstance: 'static, - >( - block_number: u32, - ) -> bp_header_chain::InitializationData> { - bp_header_chain::InitializationData { - header: Box::new(bp_test_utils::test_header(block_number.into())), - authority_list: authority_list(), - set_id: 1, - operating_mode: BasicOperatingMode::Normal, - } - } - - /// Dummy xcm - pub(crate) fn dummy_xcm() -> Xcm<()> { - vec![Trap(42)].into() - } - - pub(crate) fn dispatch_message( - lane_id: LaneId, - nonce: MessageNonce, - payload: Vec, - ) -> DispatchMessage> { - DispatchMessage { - key: MessageKey { lane_id, nonce }, - data: DispatchMessageData { payload: Ok(payload) }, - } - } - - /// Macro used for simulate_export_message and capturing bytes - macro_rules! grab_haul_blob ( - ($name:ident, $grabbed_payload:ident) => { - std::thread_local! { - static $grabbed_payload: std::cell::RefCell>> = std::cell::RefCell::new(None); - } - - struct $name; - impl HaulBlob for $name { - fn haul_blob(blob: Vec) -> Result<(), HaulBlobError>{ - $grabbed_payload.with(|rm| *rm.borrow_mut() = Some(blob)); - Ok(()) - } - } - } - ); - - /// Simulates `HaulBlobExporter` and all its wrapping and captures generated plain bytes, - /// which are transferred over bridge. - pub(crate) fn simulate_message_exporter_on_bridged_chain< - SourceNetwork: Get, - DestinationNetwork: Get, - DestinationVersion: GetVersion, - >( - (destination_network, destination_junctions): (NetworkId, Junctions), - ) -> Vec { - grab_haul_blob!(GrabbingHaulBlob, GRABBED_HAUL_BLOB_PAYLOAD); - - // lets pretend that some parachain on bridged chain exported the message - let universal_source_on_bridged_chain = - X2(GlobalConsensus(SourceNetwork::get()), Parachain(5678)); - let channel = 1_u32; - - // simulate XCM message export - let (ticket, fee) = validate_export::< - HaulBlobExporter, - >( - destination_network, - channel, - universal_source_on_bridged_chain, - destination_junctions, - dummy_xcm(), - ) - .expect("validate_export to pass"); - log::info!( - target: "simulate_message_exporter_on_bridged_chain", - "HaulBlobExporter::validate fee: {:?}", - fee - ); - let xcm_hash = HaulBlobExporter::< - GrabbingHaulBlob, - DestinationNetwork, - DestinationVersion, - (), - >::deliver(ticket) - .expect("deliver to pass"); - log::info!( - target: "simulate_message_exporter_on_bridged_chain", - "HaulBlobExporter::deliver xcm_hash: {:?}", - xcm_hash - ); - - GRABBED_HAUL_BLOB_PAYLOAD.with(|r| r.take().expect("Encoded message should be here")) - } -} diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_grandpa_chain.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_grandpa_chain.rs new file mode 100644 index 00000000000..3a0bbf8f571 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_grandpa_chain.rs @@ -0,0 +1,442 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +//! Module contains predefined test-case scenarios for `Runtime` with bridging capabilities +//! with remote GRANDPA chain. + +use crate::{ + test_cases::{helpers, run_test}, + test_data, +}; + +use bp_header_chain::ChainWithGrandpa; +use bp_messages::{ + source_chain::TargetHeaderChain, target_chain::SourceHeaderChain, LaneId, + UnrewardedRelayersState, +}; +use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; +use bp_runtime::{HashOf, UnderlyingChainOf}; +use bridge_runtime_common::{ + messages::{ + source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, + BridgedChain as MessageBridgedChain, MessageBridge, ThisChain as MessageThisChain, + }, + messages_xcm_extension::XcmAsPlainPayload, +}; +use frame_support::traits::{Get, OnFinalize, OnInitialize, OriginTrait}; +use frame_system::pallet_prelude::BlockNumberFor; +use parachains_runtimes_test_utils::{ + AccountIdOf, BasicParachainRuntime, CollatorSessionKeys, ValidatorIdOf, +}; +use sp_keyring::AccountKeyring::*; +use sp_runtime::{traits::Header as HeaderT, AccountId32}; +use xcm::latest::prelude::*; + +/// Test-case makes sure that Runtime can dispatch XCM messages submitted by relayer, +/// with proofs (finality, message) independently submitted. +/// Also verifies relayer transaction signed extensions work as intended. +pub fn relayed_incoming_message_works< + Runtime, + AllPalletsWithoutSystem, + HrmpChannelOpener, + GPI, + MPI, + MB, +>( + collator_session_key: CollatorSessionKeys, + runtime_para_id: u32, + bridged_chain_id: bp_runtime::ChainId, + sibling_parachain_id: u32, + local_relay_chain_id: NetworkId, + lane_id: LaneId, + prepare_configuration: impl Fn(), + construct_and_apply_extrinsic: fn( + sp_keyring::AccountKeyring, + ::RuntimeCall, + ) -> sp_runtime::DispatchOutcome, +) where + Runtime: BasicParachainRuntime + + cumulus_pallet_xcmp_queue::Config + + pallet_bridge_grandpa::Config< + GPI, + BridgedChain = UnderlyingChainOf>, + > + pallet_bridge_messages::Config + + pallet_bridge_relayers::Config, + AllPalletsWithoutSystem: + OnInitialize> + OnFinalize>, + GPI: 'static, + MPI: 'static, + MB: MessageBridge, + ::BridgedChain: Send + Sync + 'static, + ::ThisChain: Send + Sync + 'static, + UnderlyingChainOf>: ChainWithGrandpa, + HrmpChannelOpener: frame_support::inherent::ProvideInherent< + Call = cumulus_pallet_parachain_system::Call, + >, + ValidatorIdOf: From>, + >::SourceHeaderChain: SourceHeaderChain< + MessagesProof = FromBridgedChainMessagesProof>>, + >, + ::AccountId: + Into<<::RuntimeOrigin as OriginTrait>::AccountId>, + ::AccountId: From, + AccountIdOf: From, + >::InboundRelayer: From, + ::RuntimeCall: From> + + From>, +{ + helpers::relayed_incoming_message_works::< + Runtime, + AllPalletsWithoutSystem, + HrmpChannelOpener, + MPI, + >( + collator_session_key, + runtime_para_id, + sibling_parachain_id, + local_relay_chain_id, + construct_and_apply_extrinsic, + |relayer_id_at_this_chain, + relayer_id_at_bridged_chain, + message_destination, + message_nonce, + xcm| { + let relay_header_number = 5u32.into(); + + prepare_configuration(); + + // start with bridged relay chain block#0 + helpers::initialize_bridge_grandpa_pallet::( + test_data::initialization_data::(0), + ); + + // generate bridged relay chain finality, parachain heads and message proofs, + // to be submitted by relayer to this chain. + let (relay_chain_header, grandpa_justification, message_proof) = + test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::( + lane_id, + xcm.into(), + message_nonce, + message_destination, + relay_header_number, + ); + + let relay_chain_header_hash = relay_chain_header.hash(); + vec![ + ( + pallet_bridge_grandpa::Call::::submit_finality_proof { + finality_target: Box::new(relay_chain_header), + justification: grandpa_justification, + }.into(), + helpers::VerifySubmitGrandpaFinalityProofOutcome::::expect_best_header_hash(relay_chain_header_hash), + ), + ( + pallet_bridge_messages::Call::::receive_messages_proof { + relayer_id_at_bridged_chain, + proof: message_proof, + messages_count: 1, + dispatch_weight: Weight::from_parts(1000000000, 0), + }.into(), + Box::new(( + helpers::VerifySubmitMessagesProofOutcome::::expect_last_delivered_nonce(lane_id, 1), + helpers::VerifyRelayerRewarded::::expect_relayer_reward( + relayer_id_at_this_chain, + RewardsAccountParams::new( + lane_id, + bridged_chain_id, + RewardsAccountOwner::ThisChain, + ), + ), + )), + ), + ] + }, + ); +} + +/// Test-case makes sure that Runtime can dispatch XCM messages submitted by relayer, +/// with proofs (finality, message) batched together in signed extrinsic. +/// Also verifies relayer transaction signed extensions work as intended. +pub fn complex_relay_extrinsic_works< + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + HrmpChannelOpener, + GPI, + MPI, + MB, +>( + collator_session_key: CollatorSessionKeys, + runtime_para_id: u32, + sibling_parachain_id: u32, + bridged_chain_id: bp_runtime::ChainId, + local_relay_chain_id: NetworkId, + lane_id: LaneId, + prepare_configuration: impl Fn(), + construct_and_apply_extrinsic: fn( + sp_keyring::AccountKeyring, + ::RuntimeCall, + ) -> sp_runtime::DispatchOutcome, +) where + Runtime: BasicParachainRuntime + + cumulus_pallet_xcmp_queue::Config + + pallet_bridge_grandpa::Config< + GPI, + BridgedChain = UnderlyingChainOf>, + > + pallet_bridge_messages::Config + + pallet_bridge_relayers::Config + + pallet_utility::Config, + AllPalletsWithoutSystem: + OnInitialize> + OnFinalize>, + GPI: 'static, + MPI: 'static, + MB: MessageBridge, + ::BridgedChain: Send + Sync + 'static, + ::ThisChain: Send + Sync + 'static, + UnderlyingChainOf>: ChainWithGrandpa, + HrmpChannelOpener: frame_support::inherent::ProvideInherent< + Call = cumulus_pallet_parachain_system::Call, + >, + ValidatorIdOf: From>, + >::SourceHeaderChain: SourceHeaderChain< + MessagesProof = FromBridgedChainMessagesProof>>, + >, + ::AccountId: + Into<<::RuntimeOrigin as OriginTrait>::AccountId>, + ::AccountId: From, + AccountIdOf: From, + >::InboundRelayer: From, + ::RuntimeCall: From> + + From>, + ::RuntimeCall: From>, +{ + helpers::relayed_incoming_message_works::< + Runtime, + AllPalletsWithoutSystem, + HrmpChannelOpener, + MPI, + >( + collator_session_key, + runtime_para_id, + sibling_parachain_id, + local_relay_chain_id, + construct_and_apply_extrinsic, + |relayer_id_at_this_chain, + relayer_id_at_bridged_chain, + message_destination, + message_nonce, + xcm| { + let relay_header_number = 1u32.into(); + + prepare_configuration(); + + // start with bridged relay chain block#0 + helpers::initialize_bridge_grandpa_pallet::( + test_data::initialization_data::(0), + ); + + // generate bridged relay chain finality, parachain heads and message proofs, + // to be submitted by relayer to this chain. + let (relay_chain_header, grandpa_justification, message_proof) = + test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::( + lane_id, + xcm.into(), + message_nonce, + message_destination, + relay_header_number, + ); + + let relay_chain_header_hash = relay_chain_header.hash(); + vec![( + pallet_utility::Call::::batch_all { + calls: vec![ + pallet_bridge_grandpa::Call::::submit_finality_proof { + finality_target: Box::new(relay_chain_header), + justification: grandpa_justification, + }.into(), + pallet_bridge_messages::Call::::receive_messages_proof { + relayer_id_at_bridged_chain, + proof: message_proof, + messages_count: 1, + dispatch_weight: Weight::from_parts(1000000000, 0), + }.into(), + ], + }.into(), + Box::new(( + helpers::VerifySubmitGrandpaFinalityProofOutcome::::expect_best_header_hash(relay_chain_header_hash), + helpers::VerifySubmitMessagesProofOutcome::::expect_last_delivered_nonce(lane_id, 1), + helpers::VerifyRelayerRewarded::::expect_relayer_reward( + relayer_id_at_this_chain, + RewardsAccountParams::new( + lane_id, + bridged_chain_id, + RewardsAccountOwner::ThisChain, + ), + ), + )), + )] + }, + ); +} + +/// Estimates transaction fee for default message delivery transaction (batched with required +/// proofs) from bridged GRANDPA chain. +pub fn can_calculate_fee_for_complex_message_delivery_transaction( + collator_session_key: CollatorSessionKeys, + compute_extrinsic_fee: fn(pallet_utility::Call) -> u128, +) -> u128 +where + Runtime: BasicParachainRuntime + + pallet_bridge_grandpa::Config< + GPI, + BridgedChain = UnderlyingChainOf>, + > + pallet_bridge_messages::Config< + MPI, + InboundPayload = XcmAsPlainPayload, + InboundRelayer = bp_runtime::AccountIdOf>, + > + pallet_utility::Config, + GPI: 'static, + MPI: 'static, + MB: MessageBridge, + ::BridgedChain: Send + Sync + 'static, + ::ThisChain: Send + Sync + 'static, + UnderlyingChainOf>: bp_runtime::Chain + ChainWithGrandpa, + ValidatorIdOf: From>, + >::SourceHeaderChain: SourceHeaderChain< + MessagesProof = FromBridgedChainMessagesProof>>, + >, + bp_runtime::AccountIdOf>: From, + ::RuntimeCall: From> + + From>, +{ + run_test::(collator_session_key, 1000, vec![], || { + // generate bridged relay chain finality, parachain heads and message proofs, + // to be submitted by relayer to this chain. + // + // we don't care about parameter values here, apart from the XCM message size. But we + // do not need to have a large message here, because we're charging for every byte of + // the message additionally + let (relay_chain_header, grandpa_justification, message_proof) = + test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::( + LaneId::default(), + vec![xcm::v3::Instruction::<()>::ClearOrigin; 1_024].into(), + 1, + X2(GlobalConsensus(Polkadot), Parachain(1_000)), + 1u32.into(), + ); + + // generate batch call that provides finality for bridged relay and parachains + message + // proof + let batch = test_data::from_grandpa_chain::make_complex_relayer_delivery_batch::< + Runtime, + GPI, + MPI, + >( + relay_chain_header, + grandpa_justification, + message_proof, + Dave.public().into(), + ); + let estimated_fee = compute_extrinsic_fee(batch); + + log::error!( + target: "bridges::estimate", + "Estimate fee: {:?} for single message delivery for runtime: {:?}", + estimated_fee, + Runtime::Version::get(), + ); + + estimated_fee + }) +} + +/// Estimates transaction fee for default message confirmation transaction (batched with required +/// proofs) from bridged GRANDPA chain. +pub fn can_calculate_fee_for_complex_message_confirmation_transaction( + collator_session_key: CollatorSessionKeys, + compute_extrinsic_fee: fn(pallet_utility::Call) -> u128, +) -> u128 +where + Runtime: BasicParachainRuntime + + pallet_bridge_grandpa::Config< + GPI, + BridgedChain = UnderlyingChainOf>, + > + pallet_bridge_messages::Config + + pallet_utility::Config, + GPI: 'static, + MPI: 'static, + MB: MessageBridge, + ::BridgedChain: Send + Sync + 'static, + ::ThisChain: Send + Sync + 'static, + <::ThisChain as bp_runtime::Chain>::AccountId: From, + UnderlyingChainOf>: ChainWithGrandpa, + ValidatorIdOf: From>, + ::AccountId: + Into<<::RuntimeOrigin as OriginTrait>::AccountId>, + ::AccountId: From, + AccountIdOf: From, + >::InboundRelayer: From, + >::TargetHeaderChain: TargetHeaderChain< + XcmAsPlainPayload, + Runtime::AccountId, + MessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof< + HashOf>>, + >, + >, + ::RuntimeCall: From> + + From>, + bp_runtime::AccountIdOf>: From, +{ + run_test::(collator_session_key, 1000, vec![], || { + // generate bridged relay chain finality, parachain heads and message proofs, + // to be submitted by relayer to this chain. + let unrewarded_relayers = UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + total_messages: 1, + ..Default::default() + }; + let (relay_chain_header, grandpa_justification, message_delivery_proof) = + test_data::from_grandpa_chain::make_complex_relayer_confirmation_proofs::( + LaneId::default(), + 1u32.into(), + Alice.public().into(), + unrewarded_relayers.clone(), + ); + + // generate batch call that provides finality for bridged relay and parachains + message + // proof + let batch = test_data::from_grandpa_chain::make_complex_relayer_confirmation_batch::< + Runtime, + GPI, + MPI, + >( + relay_chain_header, + grandpa_justification, + message_delivery_proof, + unrewarded_relayers, + ); + let estimated_fee = compute_extrinsic_fee(batch); + + log::error!( + target: "bridges::estimate", + "Estimate fee: {:?} for single message confirmation for runtime: {:?}", + estimated_fee, + Runtime::Version::get(), + ); + + estimated_fee + }) +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_parachain.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_parachain.rs new file mode 100644 index 00000000000..7e4ff8f874d --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/from_parachain.rs @@ -0,0 +1,544 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +//! Module contains predefined test-case scenarios for `Runtime` with bridging capabilities +//! with remote parachain. + +use crate::{ + test_cases::{helpers, run_test}, + test_data, +}; + +use bp_messages::{ + source_chain::TargetHeaderChain, target_chain::SourceHeaderChain, LaneId, + UnrewardedRelayersState, +}; +use bp_polkadot_core::parachains::ParaHash; +use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; +use bp_runtime::{Parachain, UnderlyingChainOf}; +use bridge_runtime_common::{ + messages::{ + source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, + BridgedChain as MessageBridgedChain, MessageBridge, + }, + messages_xcm_extension::XcmAsPlainPayload, +}; +use frame_support::traits::{Get, OnFinalize, OnInitialize, OriginTrait}; +use frame_system::pallet_prelude::BlockNumberFor; +use pallet_bridge_parachains::{RelayBlockHash, RelayBlockNumber}; +use parachains_runtimes_test_utils::{ + AccountIdOf, BasicParachainRuntime, CollatorSessionKeys, ValidatorIdOf, +}; +use sp_keyring::AccountKeyring::*; +use sp_runtime::{traits::Header as HeaderT, AccountId32}; +use xcm::latest::prelude::*; + +/// Test-case makes sure that Runtime can dispatch XCM messages submitted by relayer, +/// with proofs (finality, para heads, message) independently submitted. +/// Also verifies relayer transaction signed extensions work as intended. +pub fn relayed_incoming_message_works< + Runtime, + AllPalletsWithoutSystem, + HrmpChannelOpener, + GPI, + PPI, + MPI, + MB, +>( + collator_session_key: CollatorSessionKeys, + runtime_para_id: u32, + bridged_para_id: u32, + bridged_chain_id: bp_runtime::ChainId, + sibling_parachain_id: u32, + local_relay_chain_id: NetworkId, + lane_id: LaneId, + prepare_configuration: impl Fn(), + construct_and_apply_extrinsic: fn( + sp_keyring::AccountKeyring, + ::RuntimeCall, + ) -> sp_runtime::DispatchOutcome, +) where + Runtime: BasicParachainRuntime + + cumulus_pallet_xcmp_queue::Config + + cumulus_pallet_parachain_system::Config + + pallet_bridge_grandpa::Config + + pallet_bridge_parachains::Config + + pallet_bridge_messages::Config + + pallet_bridge_relayers::Config, + AllPalletsWithoutSystem: + OnInitialize> + OnFinalize>, + GPI: 'static, + PPI: 'static, + MPI: 'static, + MB: MessageBridge, + ::BridgedChain: Send + Sync + 'static, + ::ThisChain: Send + Sync + 'static, + UnderlyingChainOf>: bp_runtime::Chain + Parachain, + HrmpChannelOpener: frame_support::inherent::ProvideInherent< + Call = cumulus_pallet_parachain_system::Call, + >, + ValidatorIdOf: From>, + >::SourceHeaderChain: + SourceHeaderChain>, + >::BridgedChain: + bp_runtime::Chain, + ParaHash: From< + <>::BridgedChain as bp_runtime::Chain>::Hash, + >, + ::AccountId: + Into<<::RuntimeOrigin as OriginTrait>::AccountId>, + ::AccountId: From, + AccountIdOf: From, + >::InboundRelayer: From, + ::RuntimeCall: From> + + From> + + From>, +{ + helpers::relayed_incoming_message_works::< + Runtime, + AllPalletsWithoutSystem, + HrmpChannelOpener, + MPI, + >( + collator_session_key, + runtime_para_id, + sibling_parachain_id, + local_relay_chain_id, + construct_and_apply_extrinsic, + |relayer_id_at_this_chain, + relayer_id_at_bridged_chain, + message_destination, + message_nonce, + xcm| { + let para_header_number = 5; + let relay_header_number = 1; + + prepare_configuration(); + + // start with bridged relay chain block#0 + helpers::initialize_bridge_grandpa_pallet::( + test_data::initialization_data::(0), + ); + + // generate bridged relay chain finality, parachain heads and message proofs, + // to be submitted by relayer to this chain. + let ( + relay_chain_header, + grandpa_justification, + parachain_head, + parachain_heads, + para_heads_proof, + message_proof, + ) = test_data::from_parachain::make_complex_relayer_delivery_proofs::< + >::BridgedChain, + MB, + (), + >( + lane_id, + xcm.into(), + message_nonce, + message_destination, + para_header_number, + relay_header_number, + bridged_para_id, + ); + + let parachain_head_hash = parachain_head.hash(); + let relay_chain_header_hash = relay_chain_header.hash(); + let relay_chain_header_number = *relay_chain_header.number(); + vec![ + ( + pallet_bridge_grandpa::Call::::submit_finality_proof { + finality_target: Box::new(relay_chain_header), + justification: grandpa_justification, + }.into(), + helpers::VerifySubmitGrandpaFinalityProofOutcome::::expect_best_header_hash(relay_chain_header_hash), + ), + ( + pallet_bridge_parachains::Call::::submit_parachain_heads { + at_relay_block: (relay_chain_header_number, relay_chain_header_hash), + parachains: parachain_heads, + parachain_heads_proof: para_heads_proof, + }.into(), + helpers::VerifySubmitParachainHeaderProofOutcome::::expect_best_header_hash(bridged_para_id, parachain_head_hash), + ), + ( + pallet_bridge_messages::Call::::receive_messages_proof { + relayer_id_at_bridged_chain, + proof: message_proof, + messages_count: 1, + dispatch_weight: Weight::from_parts(1000000000, 0), + }.into(), + Box::new(( + helpers::VerifySubmitMessagesProofOutcome::::expect_last_delivered_nonce(lane_id, 1), + helpers::VerifyRelayerRewarded::::expect_relayer_reward( + relayer_id_at_this_chain, + RewardsAccountParams::new( + lane_id, + bridged_chain_id, + RewardsAccountOwner::ThisChain, + ), + ), + )), + ), + ] + }, + ); +} + +/// Test-case makes sure that Runtime can dispatch XCM messages submitted by relayer, +/// with proofs (finality, para heads, message) batched together in signed extrinsic. +/// Also verifies relayer transaction signed extensions work as intended. +pub fn complex_relay_extrinsic_works< + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + HrmpChannelOpener, + GPI, + PPI, + MPI, + MB, +>( + collator_session_key: CollatorSessionKeys, + runtime_para_id: u32, + bridged_para_id: u32, + sibling_parachain_id: u32, + bridged_chain_id: bp_runtime::ChainId, + local_relay_chain_id: NetworkId, + lane_id: LaneId, + prepare_configuration: impl Fn(), + construct_and_apply_extrinsic: fn( + sp_keyring::AccountKeyring, + ::RuntimeCall, + ) -> sp_runtime::DispatchOutcome, +) where + Runtime: BasicParachainRuntime + + cumulus_pallet_xcmp_queue::Config + + cumulus_pallet_parachain_system::Config + + pallet_bridge_grandpa::Config + + pallet_bridge_parachains::Config + + pallet_bridge_messages::Config + + pallet_bridge_relayers::Config + + pallet_utility::Config, + AllPalletsWithoutSystem: + OnInitialize> + OnFinalize>, + GPI: 'static, + PPI: 'static, + MPI: 'static, + MB: MessageBridge, + ::BridgedChain: Send + Sync + 'static, + ::ThisChain: Send + Sync + 'static, + UnderlyingChainOf>: bp_runtime::Chain + Parachain, + HrmpChannelOpener: frame_support::inherent::ProvideInherent< + Call = cumulus_pallet_parachain_system::Call, + >, + ValidatorIdOf: From>, + >::SourceHeaderChain: + SourceHeaderChain>, + >::BridgedChain: + bp_runtime::Chain, + ParaHash: From< + <>::BridgedChain as bp_runtime::Chain>::Hash, + >, + ::AccountId: + Into<<::RuntimeOrigin as OriginTrait>::AccountId>, + ::AccountId: From, + AccountIdOf: From, + >::InboundRelayer: From, + ::RuntimeCall: From> + + From> + + From>, + ::RuntimeCall: From>, +{ + helpers::relayed_incoming_message_works::< + Runtime, + AllPalletsWithoutSystem, + HrmpChannelOpener, + MPI, + >( + collator_session_key, + runtime_para_id, + sibling_parachain_id, + local_relay_chain_id, + construct_and_apply_extrinsic, + |relayer_id_at_this_chain, + relayer_id_at_bridged_chain, + message_destination, + message_nonce, + xcm| { + let para_header_number = 5; + let relay_header_number = 1; + + prepare_configuration(); + + // start with bridged relay chain block#0 + helpers::initialize_bridge_grandpa_pallet::( + test_data::initialization_data::(0), + ); + + // generate bridged relay chain finality, parachain heads and message proofs, + // to be submitted by relayer to this chain. + let ( + relay_chain_header, + grandpa_justification, + parachain_head, + parachain_heads, + para_heads_proof, + message_proof, + ) = test_data::from_parachain::make_complex_relayer_delivery_proofs::< + >::BridgedChain, + MB, + (), + >( + lane_id, + xcm.into(), + message_nonce, + message_destination, + para_header_number, + relay_header_number, + bridged_para_id, + ); + + let parachain_head_hash = parachain_head.hash(); + let relay_chain_header_hash = relay_chain_header.hash(); + let relay_chain_header_number = *relay_chain_header.number(); + vec![( + pallet_utility::Call::::batch_all { + calls: vec![ + pallet_bridge_grandpa::Call::::submit_finality_proof { + finality_target: Box::new(relay_chain_header), + justification: grandpa_justification, + }.into(), + pallet_bridge_parachains::Call::::submit_parachain_heads { + at_relay_block: (relay_chain_header_number, relay_chain_header_hash), + parachains: parachain_heads, + parachain_heads_proof: para_heads_proof, + }.into(), + pallet_bridge_messages::Call::::receive_messages_proof { + relayer_id_at_bridged_chain, + proof: message_proof, + messages_count: 1, + dispatch_weight: Weight::from_parts(1000000000, 0), + }.into(), + ], + }.into(), + Box::new(( + helpers::VerifySubmitGrandpaFinalityProofOutcome::::expect_best_header_hash(relay_chain_header_hash), + helpers::VerifySubmitParachainHeaderProofOutcome::::expect_best_header_hash(bridged_para_id, parachain_head_hash), + helpers::VerifySubmitMessagesProofOutcome::::expect_last_delivered_nonce(lane_id, 1), + helpers::VerifyRelayerRewarded::::expect_relayer_reward( + relayer_id_at_this_chain, + RewardsAccountParams::new( + lane_id, + bridged_chain_id, + RewardsAccountOwner::ThisChain, + ), + ), + )), + )] + }, + ); +} + +/// Estimates transaction fee for default message delivery transaction (batched with required +/// proofs) from bridged parachain. +pub fn can_calculate_fee_for_complex_message_delivery_transaction( + collator_session_key: CollatorSessionKeys, + compute_extrinsic_fee: fn(pallet_utility::Call::) -> u128, +) -> u128 +where + Runtime: frame_system::Config + + pallet_balances::Config + + pallet_session::Config + + pallet_xcm::Config + + parachain_info::Config + + pallet_collator_selection::Config + + cumulus_pallet_parachain_system::Config + + pallet_bridge_grandpa::Config + + pallet_bridge_parachains::Config + + pallet_bridge_messages::Config + + pallet_utility::Config, + GPI: 'static, + PPI: 'static, + MPI: 'static, + MB: MessageBridge, + ::BridgedChain: Send + Sync + 'static, + ::ThisChain: Send + Sync + 'static, + UnderlyingChainOf>: bp_runtime::Chain + Parachain, + ValidatorIdOf: From>, + <>::SourceHeaderChain as SourceHeaderChain>::MessagesProof: + From>, + >::BridgedChain: bp_runtime::Chain, + ParaHash: From<<>::BridgedChain as bp_runtime::Chain>::Hash>, + ::AccountId: + Into<<::RuntimeOrigin as OriginTrait>::AccountId>, + ::AccountId: From, + AccountIdOf: From, + >::InboundRelayer: From, + ::RuntimeCall: + From> + + From> + + From>, +{ + run_test::(collator_session_key, 1000, vec![], || { + // generate bridged relay chain finality, parachain heads and message proofs, + // to be submitted by relayer to this chain. + // + // we don't care about parameter values here, apart from the XCM message size. But we + // do not need to have a large message here, because we're charging for every byte of + // the message additionally + let ( + relay_chain_header, + grandpa_justification, + _, + parachain_heads, + para_heads_proof, + message_proof, + ) = test_data::from_parachain::make_complex_relayer_delivery_proofs::< + >::BridgedChain, + MB, + (), + >( + LaneId::default(), + vec![xcm::v3::Instruction::<()>::ClearOrigin; 1_024].into(), + 1, + X2(GlobalConsensus(Polkadot), Parachain(1_000)), + 1, + 5, + 1_000, + ); + + // generate batch call that provides finality for bridged relay and parachains + message + // proof + let batch = test_data::from_parachain::make_complex_relayer_delivery_batch::< + Runtime, + GPI, + PPI, + MPI, + >( + relay_chain_header, + grandpa_justification, + parachain_heads, + para_heads_proof, + message_proof, + Dave.public().into(), + ); + let estimated_fee = compute_extrinsic_fee(batch); + + log::error!( + target: "bridges::estimate", + "Estimate fee: {:?} for single message delivery for runtime: {:?}", + estimated_fee, + Runtime::Version::get(), + ); + + estimated_fee + }) +} + +/// Estimates transaction fee for default message confirmation transaction (batched with required +/// proofs) from bridged parachain. +pub fn can_calculate_fee_for_complex_message_confirmation_transaction( + collator_session_key: CollatorSessionKeys, + compute_extrinsic_fee: fn(pallet_utility::Call::) -> u128, +) -> u128 +where + Runtime: frame_system::Config + + pallet_balances::Config + + pallet_session::Config + + pallet_xcm::Config + + parachain_info::Config + + pallet_collator_selection::Config + + cumulus_pallet_parachain_system::Config + + pallet_bridge_grandpa::Config + + pallet_bridge_parachains::Config + + pallet_bridge_messages::Config + + pallet_utility::Config, + GPI: 'static, + PPI: 'static, + MPI: 'static, + MB: MessageBridge, + ::BridgedChain: Send + Sync + 'static, + ::ThisChain: Send + Sync + 'static, + <::ThisChain as bp_runtime::Chain>::AccountId: From, + UnderlyingChainOf>: bp_runtime::Chain + Parachain, + ValidatorIdOf: From>, + <>::SourceHeaderChain as SourceHeaderChain>::MessagesProof: + From>, + >::BridgedChain: bp_runtime::Chain, + ParaHash: From<<>::BridgedChain as bp_runtime::Chain>::Hash>, + ::AccountId: + Into<<::RuntimeOrigin as OriginTrait>::AccountId>, + ::AccountId: From, + AccountIdOf: From, + >::InboundRelayer: From, + <>::TargetHeaderChain as TargetHeaderChain< + XcmAsPlainPayload, + Runtime::AccountId, + >>::MessagesDeliveryProof: From>, + ::RuntimeCall: + From> + + From> + + From>, +{ + run_test::(collator_session_key, 1000, vec![], || { + // generate bridged relay chain finality, parachain heads and message proofs, + // to be submitted by relayer to this chain. + let unrewarded_relayers = UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + total_messages: 1, + ..Default::default() + }; + let ( + relay_chain_header, + grandpa_justification, + _, + parachain_heads, + para_heads_proof, + message_delivery_proof, + ) = test_data::from_parachain::make_complex_relayer_confirmation_proofs::< + >::BridgedChain, + MB, + (), + >(LaneId::default(), 1, 5, 1_000, Alice.public().into(), unrewarded_relayers.clone()); + + // generate batch call that provides finality for bridged relay and parachains + message + // proof + let batch = test_data::from_parachain::make_complex_relayer_confirmation_batch::< + Runtime, + GPI, + PPI, + MPI, + >( + relay_chain_header, + grandpa_justification, + parachain_heads, + para_heads_proof, + message_delivery_proof, + unrewarded_relayers, + ); + let estimated_fee = compute_extrinsic_fee(batch); + + log::error!( + target: "bridges::estimate", + "Estimate fee: {:?} for single message confirmation for runtime: {:?}", + estimated_fee, + Runtime::Version::get(), + ); + + estimated_fee + }) +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs new file mode 100644 index 00000000000..192aa017fff --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs @@ -0,0 +1,340 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +//! Module contains tests code, that is shared by all types of bridges + +use crate::test_cases::{run_test, RuntimeHelper}; + +use asset_test_utils::BasicParachainRuntime; +use bp_messages::{LaneId, MessageNonce}; +use bp_polkadot_core::parachains::{ParaHash, ParaId}; +use bp_relayers::RewardsAccountParams; +use frame_support::{ + assert_ok, + traits::{OnFinalize, OnInitialize, PalletInfoAccess}, +}; +use frame_system::pallet_prelude::BlockNumberFor; +use pallet_bridge_grandpa::{BridgedBlockHash, BridgedHeader}; +use parachains_common::AccountId; +use parachains_runtimes_test_utils::{ + mock_open_hrmp_channel, AccountIdOf, CollatorSessionKeys, ValidatorIdOf, +}; +use sp_core::Get; +use sp_keyring::AccountKeyring::*; +use sp_runtime::AccountId32; +use sp_std::marker::PhantomData; +use xcm::latest::prelude::*; + +#[impl_trait_for_tuples::impl_for_tuples(30)] +pub trait VerifyTransactionOutcome { + fn verify_outcome(&self); +} + +impl VerifyTransactionOutcome for Box { + fn verify_outcome(&self) { + VerifyTransactionOutcome::verify_outcome(&**self) + } +} + +/// Checks that the best finalized header hash in the bridge GRANDPA pallet equals to given one. +pub struct VerifySubmitGrandpaFinalityProofOutcome +where + Runtime: pallet_bridge_grandpa::Config, + GPI: 'static, +{ + expected_best_hash: BridgedBlockHash, +} + +impl VerifySubmitGrandpaFinalityProofOutcome +where + Runtime: pallet_bridge_grandpa::Config, + GPI: 'static, +{ + /// Expect given header hash to be the best after transaction. + pub fn expect_best_header_hash( + expected_best_hash: BridgedBlockHash, + ) -> Box { + Box::new(Self { expected_best_hash }) + } +} + +impl VerifyTransactionOutcome + for VerifySubmitGrandpaFinalityProofOutcome +where + Runtime: pallet_bridge_grandpa::Config, + GPI: 'static, +{ + fn verify_outcome(&self) { + assert_eq!( + pallet_bridge_grandpa::BestFinalized::::get().unwrap().1, + self.expected_best_hash + ); + assert!(pallet_bridge_grandpa::ImportedHeaders::::contains_key( + self.expected_best_hash + )); + } +} + +/// Checks that the best parachain header hash in the bridge parachains pallet equals to given one. +pub struct VerifySubmitParachainHeaderProofOutcome { + bridged_para_id: u32, + expected_best_hash: ParaHash, + _marker: PhantomData<(Runtime, PPI)>, +} + +impl VerifySubmitParachainHeaderProofOutcome +where + Runtime: pallet_bridge_parachains::Config, + PPI: 'static, +{ + /// Expect given header hash to be the best after transaction. + pub fn expect_best_header_hash( + bridged_para_id: u32, + expected_best_hash: ParaHash, + ) -> Box { + Box::new(Self { bridged_para_id, expected_best_hash, _marker: PhantomData }) + } +} + +impl VerifyTransactionOutcome + for VerifySubmitParachainHeaderProofOutcome +where + Runtime: pallet_bridge_parachains::Config, + PPI: 'static, +{ + fn verify_outcome(&self) { + assert_eq!( + pallet_bridge_parachains::ParasInfo::::get(ParaId(self.bridged_para_id)) + .map(|info| info.best_head_hash.head_hash), + Some(self.expected_best_hash), + ); + } +} + +/// Checks that the latest delivered nonce in the bridge messages pallet equals to given one. +pub struct VerifySubmitMessagesProofOutcome { + lane: LaneId, + expected_nonce: MessageNonce, + _marker: PhantomData<(Runtime, MPI)>, +} + +impl VerifySubmitMessagesProofOutcome +where + Runtime: pallet_bridge_messages::Config, + MPI: 'static, +{ + /// Expect given delivered nonce to be the latest after transaction. + pub fn expect_last_delivered_nonce( + lane: LaneId, + expected_nonce: MessageNonce, + ) -> Box { + Box::new(Self { lane, expected_nonce, _marker: PhantomData }) + } +} + +impl VerifyTransactionOutcome for VerifySubmitMessagesProofOutcome +where + Runtime: pallet_bridge_messages::Config, + MPI: 'static, +{ + fn verify_outcome(&self) { + assert_eq!( + pallet_bridge_messages::InboundLanes::::get(self.lane) + .last_delivered_nonce(), + self.expected_nonce, + ); + } +} + +/// Verifies that relayer is rewarded at this chain. +pub struct VerifyRelayerRewarded { + relayer: Runtime::AccountId, + reward_params: RewardsAccountParams, +} + +impl VerifyRelayerRewarded +where + Runtime: pallet_bridge_relayers::Config, +{ + /// Expect given delivered nonce to be the latest after transaction. + pub fn expect_relayer_reward( + relayer: Runtime::AccountId, + reward_params: RewardsAccountParams, + ) -> Box { + Box::new(Self { relayer, reward_params }) + } +} + +impl VerifyTransactionOutcome for VerifyRelayerRewarded +where + Runtime: pallet_bridge_relayers::Config, +{ + fn verify_outcome(&self) { + assert!(pallet_bridge_relayers::RelayerRewards::::get( + &self.relayer, + &self.reward_params, + ) + .is_some()); + } +} + +/// Initialize bridge GRANDPA pallet. +pub(crate) fn initialize_bridge_grandpa_pallet( + init_data: bp_header_chain::InitializationData>, +) where + Runtime: pallet_bridge_grandpa::Config, +{ + pallet_bridge_grandpa::Pallet::::initialize( + RuntimeHelper::::root_origin(), + init_data, + ) + .unwrap(); +} + +/// Runtime calls and their verifiers. +pub type CallsAndVerifiers = + Vec<(::RuntimeCall, Box)>; + +/// Test-case makes sure that Runtime can dispatch XCM messages submitted by relayer, +/// with proofs (finality, message) independently submitted. +pub fn relayed_incoming_message_works( + collator_session_key: CollatorSessionKeys, + runtime_para_id: u32, + sibling_parachain_id: u32, + local_relay_chain_id: NetworkId, + construct_and_apply_extrinsic: fn( + sp_keyring::AccountKeyring, + ::RuntimeCall, + ) -> sp_runtime::DispatchOutcome, + prepare_message_proof_import: impl FnOnce( + Runtime::AccountId, + Runtime::InboundRelayer, + InteriorMultiLocation, + MessageNonce, + Xcm<()>, + ) -> CallsAndVerifiers, +) where + Runtime: BasicParachainRuntime + + cumulus_pallet_xcmp_queue::Config + + pallet_bridge_messages::Config, + AllPalletsWithoutSystem: + OnInitialize> + OnFinalize>, + HrmpChannelOpener: frame_support::inherent::ProvideInherent< + Call = cumulus_pallet_parachain_system::Call, + >, + MPI: 'static, + ValidatorIdOf: From>, + AccountIdOf: From + From, + >::InboundRelayer: From, +{ + let relayer_at_target = Bob; + let relayer_id_on_target: AccountId32 = relayer_at_target.public().into(); + let relayer_at_source = Dave; + let relayer_id_on_source: AccountId32 = relayer_at_source.public().into(); + + assert_ne!(runtime_para_id, sibling_parachain_id); + + run_test::( + collator_session_key, + runtime_para_id, + vec![( + relayer_id_on_target.clone().into(), + Runtime::ExistentialDeposit::get() * 100000u32.into(), + )], + || { + let mut alice = [0u8; 32]; + alice[0] = 1; + + let included_head = RuntimeHelper::::run_to_block( + 2, + AccountId::from(alice).into(), + ); + mock_open_hrmp_channel::( + runtime_para_id.into(), + sibling_parachain_id.into(), + included_head, + &alice, + ); + + // set up relayer details and proofs + + let message_destination = + X2(GlobalConsensus(local_relay_chain_id), Parachain(sibling_parachain_id)); + // some random numbers (checked by test) + let message_nonce = 1; + + let xcm = vec![xcm::v3::Instruction::<()>::ClearOrigin; 42]; + let expected_dispatch = xcm::latest::Xcm::<()>({ + let mut expected_instructions = xcm.clone(); + // dispatch prepends bridge pallet instance + expected_instructions.insert( + 0, + DescendOrigin(X1(PalletInstance( + as PalletInfoAccess>::index() + as u8, + ))), + ); + expected_instructions + }); + + execute_and_verify_calls::( + relayer_at_target, + construct_and_apply_extrinsic, + prepare_message_proof_import( + relayer_id_on_target.clone().into(), + relayer_id_on_source.clone().into(), + message_destination, + message_nonce, + xcm.clone().into(), + ), + ); + + // verify that imported XCM contains original message + let imported_xcm = + RuntimeHelper::>::take_xcm( + sibling_parachain_id.into(), + ) + .unwrap(); + let dispatched = xcm::latest::Xcm::<()>::try_from(imported_xcm).unwrap(); + let mut dispatched_clone = dispatched.clone(); + for (idx, expected_instr) in expected_dispatch.0.iter().enumerate() { + assert_eq!(expected_instr, &dispatched.0[idx]); + assert_eq!(expected_instr, &dispatched_clone.0.remove(0)); + } + match dispatched_clone.0.len() { + 0 => (), + 1 => assert!(matches!(dispatched_clone.0[0], SetTopic(_))), + count => assert!(false, "Unexpected messages count: {:?}", count), + } + }, + ) +} + +/// Execute every call and verify its outcome. +fn execute_and_verify_calls( + submitter: sp_keyring::AccountKeyring, + construct_and_apply_extrinsic: fn( + sp_keyring::AccountKeyring, + ::RuntimeCall, + ) -> sp_runtime::DispatchOutcome, + calls_and_verifiers: CallsAndVerifiers, +) { + for (call, verifier) in calls_and_verifiers { + let dispatch_outcome = construct_and_apply_extrinsic(submitter, call); + assert_ok!(dispatch_outcome); + verifier.verify_outcome(); + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs new file mode 100644 index 00000000000..cc347ecf30d --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/mod.rs @@ -0,0 +1,485 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +//! Module contains predefined test-case scenarios for `Runtime` with bridging capabilities. +//! +//! This file contains tests, suitable for all bridge runtimes. See `from_parachain` and +//! `from_grandpa_chain` submodules for tests, that are specific to the bridged chain type. + +pub mod from_grandpa_chain; +pub mod from_parachain; + +pub(crate) mod helpers; + +use crate::test_data; + +use asset_test_utils::BasicParachainRuntime; +use bp_messages::{ + target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch}, + LaneId, MessageKey, OutboundLaneData, +}; +use bridge_runtime_common::messages_xcm_extension::{ + XcmAsPlainPayload, XcmBlobMessageDispatchResult, +}; +use codec::Encode; +use frame_support::{ + assert_ok, + traits::{Get, OnFinalize, OnInitialize, OriginTrait}, +}; +use frame_system::pallet_prelude::BlockNumberFor; +use parachains_common::AccountId; +use parachains_runtimes_test_utils::{ + mock_open_hrmp_channel, AccountIdOf, BalanceOf, CollatorSessionKeys, ExtBuilder, ValidatorIdOf, + XcmReceivedFrom, +}; +use sp_runtime::{traits::Zero, AccountId32}; +use xcm::{latest::prelude::*, AlwaysLatest}; +use xcm_builder::DispatchBlobError; +use xcm_executor::{ + traits::{TransactAsset, WeightBounds}, + XcmExecutor, +}; + +// Re-export test_case from assets +pub use asset_test_utils::include_teleports_for_native_asset_works; + +pub type RuntimeHelper = + parachains_runtimes_test_utils::RuntimeHelper; + +// Re-export test_case from `parachains-runtimes-test-utils` +pub use parachains_runtimes_test_utils::test_cases::change_storage_constant_by_governance_works; + +/// Prepare default runtime storage and run test within this context. +pub fn run_test( + collator_session_key: CollatorSessionKeys, + runtime_para_id: u32, + balances: Vec<(Runtime::AccountId, Runtime::Balance)>, + test: impl FnOnce() -> T, +) -> T +where + Runtime: BasicParachainRuntime, + ValidatorIdOf: From>, +{ + ExtBuilder::::default() + .with_collators(collator_session_key.collators()) + .with_session_keys(collator_session_key.session_keys()) + .with_safe_xcm_version(XCM_VERSION) + .with_para_id(runtime_para_id.into()) + .with_balances(balances) + .with_tracing() + .build() + .execute_with(|| test()) +} + +/// Test-case makes sure that `Runtime` can process bridging initialize via governance-like call +pub fn initialize_bridge_by_governance_works( + collator_session_key: CollatorSessionKeys, + runtime_para_id: u32, + runtime_call_encode: Box< + dyn Fn(pallet_bridge_grandpa::Call) -> Vec, + >, +) where + Runtime: BasicParachainRuntime + pallet_bridge_grandpa::Config, + GrandpaPalletInstance: 'static, + ValidatorIdOf: From>, +{ + run_test::(collator_session_key, runtime_para_id, vec![], || { + // check mode before + assert_eq!( + pallet_bridge_grandpa::PalletOperatingMode::::try_get(), + Err(()) + ); + + // encode `initialize` call + let initialize_call = runtime_call_encode(pallet_bridge_grandpa::Call::< + Runtime, + GrandpaPalletInstance, + >::initialize { + init_data: test_data::initialization_data::(12345), + }); + + // overestimate - check weight for `pallet_bridge_grandpa::Pallet::initialize()` call + let require_weight_at_most = + ::DbWeight::get().reads_writes(7, 7); + + // execute XCM with Transacts to `initialize bridge` as governance does + assert_ok!(RuntimeHelper::::execute_as_governance( + initialize_call, + require_weight_at_most + ) + .ensure_complete()); + + // check mode after + assert_eq!( + pallet_bridge_grandpa::PalletOperatingMode::::try_get(), + Ok(bp_runtime::BasicOperatingMode::Normal) + ); + }) +} + +/// Test-case makes sure that `Runtime` can handle xcm `ExportMessage`: +/// Checks if received XCM messages is correctly added to the message outbound queue for delivery. +/// For SystemParachains we expect unpaid execution. +pub fn handle_export_message_from_system_parachain_to_outbound_queue_works< + Runtime, + XcmConfig, + MessagesPalletInstance, +>( + collator_session_key: CollatorSessionKeys, + runtime_para_id: u32, + sibling_parachain_id: u32, + unwrap_pallet_bridge_messages_event: Box< + dyn Fn(Vec) -> Option>, + >, + export_message_instruction: fn() -> Instruction, + expected_lane_id: LaneId, + existential_deposit: Option, + maybe_paid_export_message: Option, + prepare_configuration: impl Fn(), +) where + Runtime: BasicParachainRuntime + pallet_bridge_messages::Config, + XcmConfig: xcm_executor::Config, + MessagesPalletInstance: 'static, + ValidatorIdOf: From>, +{ + assert_ne!(runtime_para_id, sibling_parachain_id); + let sibling_parachain_location = MultiLocation::new(1, Parachain(sibling_parachain_id)); + + run_test::(collator_session_key, runtime_para_id, vec![], || { + prepare_configuration(); + + // check queue before + assert_eq!( + pallet_bridge_messages::OutboundLanes::::try_get( + expected_lane_id + ), + Err(()) + ); + + // prepare `ExportMessage` + let xcm = if let Some(fee) = maybe_paid_export_message { + // deposit ED to origin (if needed) + if let Some(ed) = existential_deposit { + XcmConfig::AssetTransactor::deposit_asset( + &ed, + &sibling_parachain_location, + Some(&XcmContext::with_message_id([0; 32])), + ) + .expect("deposited ed"); + } + // deposit fee to origin + XcmConfig::AssetTransactor::deposit_asset( + &fee, + &sibling_parachain_location, + Some(&XcmContext::with_message_id([0; 32])), + ) + .expect("deposited fee"); + + Xcm(vec![ + WithdrawAsset(MultiAssets::from(vec![fee.clone()])), + BuyExecution { fees: fee, weight_limit: Unlimited }, + export_message_instruction(), + ]) + } else { + Xcm(vec![ + UnpaidExecution { weight_limit: Unlimited, check_origin: None }, + export_message_instruction(), + ]) + }; + + // execute XCM + let hash = xcm.using_encoded(sp_io::hashing::blake2_256); + assert_ok!(XcmExecutor::::execute_xcm( + sibling_parachain_location, + xcm, + hash, + RuntimeHelper::::xcm_max_weight(XcmReceivedFrom::Sibling), + ) + .ensure_complete()); + + // check queue after + assert_eq!( + pallet_bridge_messages::OutboundLanes::::try_get( + expected_lane_id + ), + Ok(OutboundLaneData { + oldest_unpruned_nonce: 1, + latest_received_nonce: 0, + latest_generated_nonce: 1, + }) + ); + + // check events + let mut events = >::events() + .into_iter() + .filter_map(|e| unwrap_pallet_bridge_messages_event(e.event.encode())); + assert!(events.any(|e| matches!(e, pallet_bridge_messages::Event::MessageAccepted { .. }))); + }) +} + +/// Test-case makes sure that Runtime can route XCM messages received in inbound queue, +/// We just test here `MessageDispatch` configuration. +/// We expect that runtime can route messages: +/// 1. to Parent (relay chain) +/// 2. to Sibling parachain +pub fn message_dispatch_routing_works< + Runtime, + AllPalletsWithoutSystem, + XcmConfig, + HrmpChannelOpener, + MessagesPalletInstance, + RuntimeNetwork, + BridgedNetwork, + NetworkDistanceAsParentCount, +>( + collator_session_key: CollatorSessionKeys, + runtime_para_id: u32, + sibling_parachain_id: u32, + unwrap_cumulus_pallet_parachain_system_event: Box< + dyn Fn(Vec) -> Option>, + >, + unwrap_cumulus_pallet_xcmp_queue_event: Box< + dyn Fn(Vec) -> Option>, + >, + expected_lane_id: LaneId, + prepare_configuration: impl Fn(), +) where + Runtime: BasicParachainRuntime + + cumulus_pallet_xcmp_queue::Config + + pallet_bridge_messages::Config, + AllPalletsWithoutSystem: + OnInitialize> + OnFinalize>, + ::AccountId: + Into<<::RuntimeOrigin as OriginTrait>::AccountId>, + XcmConfig: xcm_executor::Config, + MessagesPalletInstance: 'static, + ValidatorIdOf: From>, + ::AccountId: From, + HrmpChannelOpener: frame_support::inherent::ProvideInherent< + Call = cumulus_pallet_parachain_system::Call, + >, + RuntimeNetwork: Get, + BridgedNetwork: Get, + NetworkDistanceAsParentCount: Get, +{ + struct NetworkWithParentCount(core::marker::PhantomData<(N, C)>); + impl, C: Get> Get for NetworkWithParentCount { + fn get() -> MultiLocation { + MultiLocation { parents: C::get(), interior: X1(GlobalConsensus(N::get())) } + } + } + + assert_ne!(runtime_para_id, sibling_parachain_id); + + run_test::(collator_session_key, runtime_para_id, vec![], || { + prepare_configuration(); + + let mut alice = [0u8; 32]; + alice[0] = 1; + + let included_head = RuntimeHelper::::run_to_block( + 2, + AccountId::from(alice).into(), + ); + // 1. this message is sent from other global consensus with destination of this Runtime + // relay chain (UMP) + let bridging_message = test_data::simulate_message_exporter_on_bridged_chain::< + BridgedNetwork, + NetworkWithParentCount, + AlwaysLatest, + >((RuntimeNetwork::get(), Here)); + let result = <>::MessageDispatch>::dispatch( + test_data::dispatch_message(expected_lane_id, 1, bridging_message) + ); + assert_eq!( + format!("{:?}", result.dispatch_level_result), + format!("{:?}", XcmBlobMessageDispatchResult::Dispatched) + ); + + // check events - UpwardMessageSent + let mut events = >::events() + .into_iter() + .filter_map(|e| unwrap_cumulus_pallet_parachain_system_event(e.event.encode())); + assert!(events.any(|e| matches!( + e, + cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. } + ))); + + // 2. this message is sent from other global consensus with destination of this Runtime + // sibling parachain (HRMP) + let bridging_message = test_data::simulate_message_exporter_on_bridged_chain::< + BridgedNetwork, + NetworkWithParentCount, + AlwaysLatest, + >((RuntimeNetwork::get(), X1(Parachain(sibling_parachain_id)))); + + // 2.1. WITHOUT opened hrmp channel -> RoutingError + let result = + <>::MessageDispatch>::dispatch( + DispatchMessage { + key: MessageKey { lane_id: expected_lane_id, nonce: 1 }, + data: DispatchMessageData { payload: Ok(bridging_message.clone()) }, + } + ); + assert_eq!( + format!("{:?}", result.dispatch_level_result), + format!( + "{:?}", + XcmBlobMessageDispatchResult::NotDispatched(Some(DispatchBlobError::RoutingError)) + ) + ); + + // check events - no XcmpMessageSent + assert_eq!( + >::events() + .into_iter() + .filter_map(|e| unwrap_cumulus_pallet_xcmp_queue_event(e.event.encode())) + .count(), + 0 + ); + + // 2.1. WITH hrmp channel -> Ok + mock_open_hrmp_channel::( + runtime_para_id.into(), + sibling_parachain_id.into(), + included_head, + &alice, + ); + let result = <>::MessageDispatch>::dispatch( + DispatchMessage { + key: MessageKey { lane_id: expected_lane_id, nonce: 1 }, + data: DispatchMessageData { payload: Ok(bridging_message) }, + } + ); + assert_eq!( + format!("{:?}", result.dispatch_level_result), + format!("{:?}", XcmBlobMessageDispatchResult::Dispatched) + ); + + // check events - XcmpMessageSent + let mut events = >::events() + .into_iter() + .filter_map(|e| unwrap_cumulus_pallet_xcmp_queue_event(e.event.encode())); + assert!( + events.any(|e| matches!(e, cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. })) + ); + }) +} + +/// Estimates XCM execution fee for paid `ExportMessage` processing. +pub fn can_calculate_weight_for_paid_export_message_with_reserve_transfer< + Runtime, + XcmConfig, + WeightToFee, +>() -> u128 +where + Runtime: frame_system::Config + pallet_balances::Config, + XcmConfig: xcm_executor::Config, + WeightToFee: frame_support::weights::WeightToFee>, + ::Balance: From + Into, +{ + // data here are not relevant for weighing + let mut xcm = Xcm(vec![ + WithdrawAsset(MultiAssets::from(vec![MultiAsset { + id: Concrete(MultiLocation { parents: 1, interior: Here }), + fun: Fungible(34333299), + }])), + BuyExecution { + fees: MultiAsset { + id: Concrete(MultiLocation { parents: 1, interior: Here }), + fun: Fungible(34333299), + }, + weight_limit: Unlimited, + }, + ExportMessage { + network: Polkadot, + destination: X1(Parachain(1000)), + xcm: Xcm(vec![ + ReserveAssetDeposited(MultiAssets::from(vec![MultiAsset { + id: Concrete(MultiLocation { + parents: 2, + interior: X1(GlobalConsensus(Kusama)), + }), + fun: Fungible(1000000000000), + }])), + ClearOrigin, + BuyExecution { + fees: MultiAsset { + id: Concrete(MultiLocation { + parents: 2, + interior: X1(GlobalConsensus(Kusama)), + }), + fun: Fungible(1000000000000), + }, + weight_limit: Unlimited, + }, + DepositAsset { + assets: Wild(AllCounted(1)), + beneficiary: MultiLocation { + parents: 0, + interior: X1(xcm::latest::prelude::AccountId32 { + network: None, + id: [ + 212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, + 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, + 109, 162, 125, + ], + }), + }, + }, + SetTopic([ + 116, 82, 194, 132, 171, 114, 217, 165, 23, 37, 161, 177, 165, 179, 247, 114, + 137, 101, 147, 70, 28, 157, 168, 32, 154, 63, 74, 228, 152, 180, 5, 63, + ]), + ]), + }, + DepositAsset { + assets: Wild(All), + beneficiary: MultiLocation { parents: 1, interior: X1(Parachain(1000)) }, + }, + SetTopic([ + 36, 224, 250, 165, 82, 195, 67, 110, 160, 170, 140, 87, 217, 62, 201, 164, 42, 98, 219, + 157, 124, 105, 248, 25, 131, 218, 199, 36, 109, 173, 100, 122, + ]), + ]); + + // get weight + let weight = XcmConfig::Weigher::weight(&mut xcm); + assert_ok!(weight); + let weight = weight.unwrap(); + // check if sane + let max_expected = Runtime::BlockWeights::get().max_block / 10; + assert!( + weight.all_lte(max_expected), + "calculated weight: {:?}, max_expected: {:?}", + weight, + max_expected + ); + + // check fee, should not be 0 + let estimated_fee = WeightToFee::weight_to_fee(&weight); + assert!(estimated_fee > BalanceOf::::zero()); + + sp_tracing::try_init_simple(); + log::error!( + target: "bridges::estimate", + "Estimate fee: {:?} for `ExportMessage` for runtime: {:?}", + estimated_fee, + Runtime::Version::get(), + ); + + estimated_fee.into() +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_grandpa_chain.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_grandpa_chain.rs new file mode 100644 index 00000000000..017ec0fd540 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_grandpa_chain.rs @@ -0,0 +1,244 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +//! Generating test data for bridges with remote GRANDPA chains. + +use crate::test_data::prepare_inbound_xcm; + +use bp_messages::{ + source_chain::TargetHeaderChain, target_chain::SourceHeaderChain, LaneId, MessageNonce, + UnrewardedRelayersState, +}; +use bp_runtime::{AccountIdOf, BlockNumberOf, HeaderOf, StorageProofSize, UnderlyingChainOf}; +use bp_test_utils::make_default_justification; +use bridge_runtime_common::{ + messages::{ + source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, + BridgedChain as MessageBridgedChain, MessageBridge, ThisChain as MessageThisChain, + }, + messages_generation::{ + encode_all_messages, encode_lane_data, prepare_message_delivery_storage_proof, + prepare_messages_storage_proof, + }, + messages_xcm_extension::XcmAsPlainPayload, +}; +use codec::Encode; +use pallet_bridge_grandpa::{BridgedChain, BridgedHeader}; +use sp_runtime::traits::Header as HeaderT; +use xcm::latest::prelude::*; + +use bp_header_chain::{justification::GrandpaJustification, ChainWithGrandpa}; +use bp_messages::{DeliveredMessages, InboundLaneData, UnrewardedRelayer}; +use bp_runtime::HashOf; +use sp_runtime::DigestItem; + +/// Prepare a batch call with bridged GRANDPA finality and message proof. +pub fn make_complex_relayer_delivery_batch( + bridged_header: BridgedHeader, + bridged_justification: GrandpaJustification>, + message_proof: FromBridgedChainMessagesProof>>, + relayer_id_at_bridged_chain: AccountIdOf>, +) -> pallet_utility::Call +where + Runtime: pallet_bridge_grandpa::Config + + pallet_bridge_messages::Config< + MPI, + InboundPayload = XcmAsPlainPayload, + InboundRelayer = AccountIdOf>, + > + pallet_utility::Config, + GPI: 'static, + MPI: 'static, + >::SourceHeaderChain: SourceHeaderChain< + MessagesProof = FromBridgedChainMessagesProof>>, + >, + ::RuntimeCall: From> + + From>, +{ + let submit_grandpa = pallet_bridge_grandpa::Call::::submit_finality_proof { + finality_target: Box::new(bridged_header), + justification: bridged_justification, + }; + let submit_message = pallet_bridge_messages::Call::::receive_messages_proof { + relayer_id_at_bridged_chain, + proof: message_proof, + messages_count: 1, + dispatch_weight: Weight::from_parts(1000000000, 0), + }; + pallet_utility::Call::::batch_all { + calls: vec![submit_grandpa.into(), submit_message.into()], + } +} + +/// Prepare a batch call with bridged GRANDPA finality and message delivery proof. +pub fn make_complex_relayer_confirmation_batch( + bridged_header: BridgedHeader, + bridged_justification: GrandpaJustification>, + message_delivery_proof: FromBridgedChainMessagesDeliveryProof< + HashOf>, + >, + relayers_state: UnrewardedRelayersState, +) -> pallet_utility::Call +where + Runtime: pallet_bridge_grandpa::Config + + pallet_bridge_messages::Config + + pallet_utility::Config, + GPI: 'static, + MPI: 'static, + >::TargetHeaderChain: TargetHeaderChain< + XcmAsPlainPayload, + Runtime::AccountId, + MessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof< + HashOf>, + >, + >, + ::RuntimeCall: From> + + From>, +{ + let submit_grandpa = pallet_bridge_grandpa::Call::::submit_finality_proof { + finality_target: Box::new(bridged_header), + justification: bridged_justification, + }; + let submit_message_delivery_proof = + pallet_bridge_messages::Call::::receive_messages_delivery_proof { + proof: message_delivery_proof, + relayers_state, + }; + pallet_utility::Call::::batch_all { + calls: vec![submit_grandpa.into(), submit_message_delivery_proof.into()], + } +} + +/// Prepare storage proofs of messages, stored at the (bridged) source GRANDPA chain. +pub fn make_complex_relayer_delivery_proofs( + lane_id: LaneId, + xcm_message: Xcm, + message_nonce: MessageNonce, + message_destination: Junctions, + header_number: BlockNumberOf>, +) -> ( + HeaderOf>, + GrandpaJustification>>, + FromBridgedChainMessagesProof>>, +) +where + MB: MessageBridge, + MessageBridgedChain: Send + Sync + 'static, + UnderlyingChainOf>: ChainWithGrandpa, +{ + let message_payload = prepare_inbound_xcm(xcm_message, message_destination); + let message_size = StorageProofSize::Minimal(message_payload.len() as u32); + // prepare para storage proof containing message + let (state_root, storage_proof) = prepare_messages_storage_proof::( + lane_id, + message_nonce..=message_nonce, + None, + message_size, + message_payload, + encode_all_messages, + encode_lane_data, + ); + + let (header, justification) = make_complex_bridged_grandpa_header_proof::< + MessageBridgedChain, + >(state_root, header_number); + + let message_proof = FromBridgedChainMessagesProof { + bridged_header_hash: header.hash(), + storage_proof, + lane: lane_id, + nonces_start: message_nonce, + nonces_end: message_nonce, + }; + + (header, justification, message_proof) +} + +/// Prepare storage proofs of message confirmations, stored at the (bridged) target GRANDPA chain. +pub fn make_complex_relayer_confirmation_proofs( + lane_id: LaneId, + header_number: BlockNumberOf>, + relayer_id_at_this_chain: AccountIdOf>, + relayers_state: UnrewardedRelayersState, +) -> ( + HeaderOf>, + GrandpaJustification>>, + FromBridgedChainMessagesDeliveryProof>>, +) +where + MB: MessageBridge, + MessageBridgedChain: Send + Sync + 'static, + MessageThisChain: Send + Sync + 'static, + UnderlyingChainOf>: ChainWithGrandpa, +{ + // prepare storage proof containing message delivery proof + let (state_root, storage_proof) = prepare_message_delivery_storage_proof::( + lane_id, + InboundLaneData { + relayers: vec![ + UnrewardedRelayer { + relayer: relayer_id_at_this_chain, + messages: DeliveredMessages::new(1) + }; + relayers_state.unrewarded_relayer_entries as usize + ] + .into(), + last_confirmed_nonce: 1, + }, + StorageProofSize::Minimal(0), + ); + + let (header, justification) = + make_complex_bridged_grandpa_header_proof::(state_root, header_number); + + let message_delivery_proof = FromBridgedChainMessagesDeliveryProof { + bridged_header_hash: header.hash(), + storage_proof, + lane: lane_id, + }; + + (header, justification, message_delivery_proof) +} + +/// Make bridged GRANDPA chain header with given state root. +pub fn make_complex_bridged_grandpa_header_proof( + state_root: HashOf, + header_number: BlockNumberOf, +) -> (HeaderOf, GrandpaJustification>) +where + BridgedChain: ChainWithGrandpa, +{ + let mut header = bp_test_utils::test_header_with_root::>( + header_number.into(), + state_root.into(), + ); + + // to compute proper cost of GRANDPA call, let's add some dummy bytes to header, so that the + // `submit_finality_proof` call size would be close to maximal expected (and refundable) + let extra_bytes_required = maximal_expected_submit_finality_proof_call_size::() + .saturating_sub(header.encoded_size()); + header.digest_mut().push(DigestItem::Other(vec![42; extra_bytes_required])); + + let justification = make_default_justification(&header); + (header, justification) +} + +/// Maximal expected `submit_finality_proof` call size. +pub fn maximal_expected_submit_finality_proof_call_size() -> usize { + bp_header_chain::max_expected_submit_finality_proof_arguments_size::( + false, + BridgedChain::MAX_AUTHORITIES_COUNT * 2 / 3 + 1, + ) as usize +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_parachain.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_parachain.rs new file mode 100644 index 00000000000..7ac10aa9e73 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/from_parachain.rs @@ -0,0 +1,326 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +//! Generating test data for bridges with remote parachains. + +use super::{from_grandpa_chain::make_complex_bridged_grandpa_header_proof, prepare_inbound_xcm}; + +use bp_messages::{ + source_chain::TargetHeaderChain, target_chain::SourceHeaderChain, LaneId, + UnrewardedRelayersState, Weight, +}; +use bp_runtime::{BlockNumberOf, HeaderOf, Parachain, StorageProofSize, UnderlyingChainOf}; +use bp_test_utils::prepare_parachain_heads_proof; +use bridge_runtime_common::{ + messages::{ + source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, + BridgedChain as MessageBridgedChain, MessageBridge, + }, + messages_generation::{ + encode_all_messages, encode_lane_data, prepare_message_delivery_storage_proof, + prepare_messages_storage_proof, + }, + messages_xcm_extension::XcmAsPlainPayload, +}; +use codec::Encode; +use pallet_bridge_grandpa::BridgedHeader; +use pallet_bridge_parachains::{RelayBlockHash, RelayBlockNumber}; +use sp_runtime::{traits::Header as HeaderT, AccountId32}; +use xcm::latest::prelude::*; + +use bp_header_chain::{justification::GrandpaJustification, ChainWithGrandpa}; +use bp_messages::{DeliveredMessages, InboundLaneData, MessageNonce, UnrewardedRelayer}; +use bp_polkadot_core::parachains::{ParaHash, ParaHead, ParaHeadsProof, ParaId}; +use sp_runtime::SaturatedConversion; + +/// Prepare a batch call with relay finality proof, parachain head proof and message proof. +pub fn make_complex_relayer_delivery_batch( + relay_chain_header: BridgedHeader, + grandpa_justification: GrandpaJustification>, + parachain_heads: Vec<(ParaId, ParaHash)>, + para_heads_proof: ParaHeadsProof, + message_proof: FromBridgedChainMessagesProof, + relayer_id_at_bridged_chain: AccountId32, +) -> pallet_utility::Call where + Runtime:pallet_bridge_grandpa::Config + + pallet_bridge_parachains::Config + + pallet_bridge_messages::Config + + pallet_utility::Config, + GPI: 'static, + PPI: 'static, + MPI: 'static, + ParaHash: From<<>::BridgedChain as bp_runtime::Chain>::Hash>, + <>::BridgedChain as bp_runtime::Chain>::Hash: From, + <>::SourceHeaderChain as SourceHeaderChain>::MessagesProof: + From>, + >::InboundRelayer: From, + ::RuntimeCall: + From> + + From> + + From>, +{ + let relay_chain_header_hash = relay_chain_header.hash(); + let relay_chain_header_number = *relay_chain_header.number(); + let submit_grandpa = pallet_bridge_grandpa::Call::::submit_finality_proof { + finality_target: Box::new(relay_chain_header), + justification: grandpa_justification, + }; + let submit_para_head = pallet_bridge_parachains::Call::::submit_parachain_heads { + at_relay_block: ( + relay_chain_header_number.saturated_into(), + relay_chain_header_hash.into(), + ), + parachains: parachain_heads, + parachain_heads_proof: para_heads_proof, + }; + let submit_message = pallet_bridge_messages::Call::::receive_messages_proof { + relayer_id_at_bridged_chain: relayer_id_at_bridged_chain.into(), + proof: message_proof.into(), + messages_count: 1, + dispatch_weight: Weight::from_parts(1000000000, 0), + }; + pallet_utility::Call::::batch_all { + calls: vec![submit_grandpa.into(), submit_para_head.into(), submit_message.into()], + } +} + +/// Prepare a batch call with relay finality proof, parachain head proof and message delivery +/// proof. +pub fn make_complex_relayer_confirmation_batch( + relay_chain_header: BridgedHeader, + grandpa_justification: GrandpaJustification>, + parachain_heads: Vec<(ParaId, ParaHash)>, + para_heads_proof: ParaHeadsProof, + message_delivery_proof: FromBridgedChainMessagesDeliveryProof, + relayers_state: UnrewardedRelayersState, +) -> pallet_utility::Call +where + Runtime: pallet_bridge_grandpa::Config + + pallet_bridge_parachains::Config + + pallet_bridge_messages::Config + + pallet_utility::Config, + GPI: 'static, + PPI: 'static, + MPI: 'static, + >::BridgedChain: + bp_runtime::Chain + ChainWithGrandpa, + <>::TargetHeaderChain as TargetHeaderChain< + XcmAsPlainPayload, + Runtime::AccountId, + >>::MessagesDeliveryProof: From>, + ::RuntimeCall: From> + + From> + + From>, +{ + let relay_chain_header_hash = relay_chain_header.hash(); + let relay_chain_header_number = *relay_chain_header.number(); + let submit_grandpa = pallet_bridge_grandpa::Call::::submit_finality_proof { + finality_target: Box::new(relay_chain_header), + justification: grandpa_justification, + }; + let submit_para_head = pallet_bridge_parachains::Call::::submit_parachain_heads { + at_relay_block: ( + relay_chain_header_number.saturated_into(), + relay_chain_header_hash.into(), + ), + parachains: parachain_heads, + parachain_heads_proof: para_heads_proof, + }; + let submit_message_delivery_proof = + pallet_bridge_messages::Call::::receive_messages_delivery_proof { + proof: message_delivery_proof.into(), + relayers_state, + }; + pallet_utility::Call::::batch_all { + calls: vec![ + submit_grandpa.into(), + submit_para_head.into(), + submit_message_delivery_proof.into(), + ], + } +} + +/// Prepare storage proofs of messages, stored at the source chain. +pub fn make_complex_relayer_delivery_proofs( + lane_id: LaneId, + xcm_message: Xcm, + message_nonce: MessageNonce, + message_destination: Junctions, + para_header_number: u32, + relay_header_number: u32, + bridged_para_id: u32, +) -> ( + HeaderOf, + GrandpaJustification>, + ParaHead, + Vec<(ParaId, ParaHash)>, + ParaHeadsProof, + FromBridgedChainMessagesProof, +) +where + BridgedRelayChain: + bp_runtime::Chain + ChainWithGrandpa, + MB: MessageBridge, + ::BridgedChain: Send + Sync + 'static, + ::ThisChain: Send + Sync + 'static, + UnderlyingChainOf>: bp_runtime::Chain + Parachain, +{ + let message_payload = prepare_inbound_xcm(xcm_message, message_destination); + let message_size = StorageProofSize::Minimal(message_payload.len() as u32); + // prepare para storage proof containing message + let (para_state_root, para_storage_proof) = prepare_messages_storage_proof::( + lane_id, + message_nonce..=message_nonce, + None, + message_size, + message_payload, + encode_all_messages, + encode_lane_data, + ); + + let (relay_chain_header, justification, bridged_para_head, parachain_heads, para_heads_proof) = + make_complex_bridged_parachain_heads_proof::( + para_state_root, + para_header_number, + relay_header_number, + bridged_para_id, + ); + + let message_proof = FromBridgedChainMessagesProof { + bridged_header_hash: bridged_para_head.hash(), + storage_proof: para_storage_proof, + lane: lane_id, + nonces_start: message_nonce, + nonces_end: message_nonce, + }; + + ( + relay_chain_header, + justification, + bridged_para_head, + parachain_heads, + para_heads_proof, + message_proof, + ) +} + +/// Prepare storage proofs of message confirmations, stored at the target parachain. +pub fn make_complex_relayer_confirmation_proofs( + lane_id: LaneId, + para_header_number: u32, + relay_header_number: u32, + bridged_para_id: u32, + relayer_id_at_this_chain: AccountId32, + relayers_state: UnrewardedRelayersState, +) -> ( + HeaderOf, + GrandpaJustification>, + ParaHead, + Vec<(ParaId, ParaHash)>, + ParaHeadsProof, + FromBridgedChainMessagesDeliveryProof, +) +where + BridgedRelayChain: + bp_runtime::Chain + ChainWithGrandpa, + MB: MessageBridge, + ::BridgedChain: Send + Sync + 'static, + ::ThisChain: Send + Sync + 'static, + <::ThisChain as bp_runtime::Chain>::AccountId: From, + UnderlyingChainOf>: bp_runtime::Chain + Parachain, +{ + // prepare para storage proof containing message delivery proof + let (para_state_root, para_storage_proof) = prepare_message_delivery_storage_proof::( + lane_id, + InboundLaneData { + relayers: vec![ + UnrewardedRelayer { + relayer: relayer_id_at_this_chain.into(), + messages: DeliveredMessages::new(1) + }; + relayers_state.unrewarded_relayer_entries as usize + ] + .into(), + last_confirmed_nonce: 1, + }, + StorageProofSize::Minimal(0), + ); + + let (relay_chain_header, justification, bridged_para_head, parachain_heads, para_heads_proof) = + make_complex_bridged_parachain_heads_proof::( + para_state_root, + para_header_number, + relay_header_number, + bridged_para_id, + ); + + let message_delivery_proof = FromBridgedChainMessagesDeliveryProof { + bridged_header_hash: bridged_para_head.hash(), + storage_proof: para_storage_proof, + lane: lane_id, + }; + + ( + relay_chain_header, + justification, + bridged_para_head, + parachain_heads, + para_heads_proof, + message_delivery_proof, + ) +} + +/// Make bridged parachain header with given state root and relay header that is finalizing it. +pub fn make_complex_bridged_parachain_heads_proof( + para_state_root: ParaHash, + para_header_number: u32, + relay_header_number: BlockNumberOf, + bridged_para_id: u32, +) -> ( + HeaderOf, + GrandpaJustification>, + ParaHead, + Vec<(ParaId, ParaHash)>, + ParaHeadsProof, +) +where + BridgedRelayChain: + bp_runtime::Chain + ChainWithGrandpa, + MB: MessageBridge, + ::BridgedChain: Send + Sync + 'static, + ::ThisChain: Send + Sync + 'static, + UnderlyingChainOf>: bp_runtime::Chain + Parachain, +{ + let bridged_para_head = ParaHead( + bp_test_utils::test_header_with_root::>( + para_header_number.into(), + para_state_root, + ) + .encode(), + ); + let (relay_state_root, para_heads_proof, parachain_heads) = + prepare_parachain_heads_proof::>(vec![( + bridged_para_id, + bridged_para_head.clone(), + )]); + assert_eq!(bridged_para_head.hash(), parachain_heads[0].1); + + let (relay_chain_header, justification) = make_complex_bridged_grandpa_header_proof::< + BridgedRelayChain, + >(relay_state_root, relay_header_number); + + (relay_chain_header, justification, bridged_para_head, parachain_heads, para_heads_proof) +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/mod.rs new file mode 100644 index 00000000000..f905d21b187 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_data/mod.rs @@ -0,0 +1,144 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +//! Generating test data, used by all tests. + +pub mod from_grandpa_chain; +pub mod from_parachain; + +use bp_messages::{ + target_chain::{DispatchMessage, DispatchMessageData}, + LaneId, MessageKey, +}; +use codec::Encode; +use frame_support::traits::Get; +use pallet_bridge_grandpa::BridgedHeader; +use xcm::latest::prelude::*; + +use bp_messages::MessageNonce; +use bp_runtime::BasicOperatingMode; +use bp_test_utils::authority_list; +use xcm::GetVersion; +use xcm_builder::{HaulBlob, HaulBlobError, HaulBlobExporter}; +use xcm_executor::traits::{validate_export, ExportXcm}; + +pub fn prepare_inbound_xcm( + xcm_message: Xcm, + destination: InteriorMultiLocation, +) -> Vec { + let location = xcm::VersionedInteriorMultiLocation::V3(destination); + let xcm = xcm::VersionedXcm::::V3(xcm_message); + // this is the `BridgeMessage` from polkadot xcm builder, but it has no constructor + // or public fields, so just tuple + // (double encoding, because `.encode()` is called on original Xcm BLOB when it is pushed + // to the storage) + (location, xcm).encode().encode() +} + +/// Helper that creates InitializationData mock data, that can be used to initialize bridge +/// GRANDPA pallet +pub fn initialization_data< + Runtime: pallet_bridge_grandpa::Config, + GrandpaPalletInstance: 'static, +>( + block_number: u32, +) -> bp_header_chain::InitializationData> { + bp_header_chain::InitializationData { + header: Box::new(bp_test_utils::test_header(block_number.into())), + authority_list: authority_list(), + set_id: 1, + operating_mode: BasicOperatingMode::Normal, + } +} + +/// Dummy xcm +pub(crate) fn dummy_xcm() -> Xcm<()> { + vec![Trap(42)].into() +} + +pub(crate) fn dispatch_message( + lane_id: LaneId, + nonce: MessageNonce, + payload: Vec, +) -> DispatchMessage> { + DispatchMessage { + key: MessageKey { lane_id, nonce }, + data: DispatchMessageData { payload: Ok(payload) }, + } +} + +/// Macro used for simulate_export_message and capturing bytes +macro_rules! grab_haul_blob ( + ($name:ident, $grabbed_payload:ident) => { + std::thread_local! { + static $grabbed_payload: std::cell::RefCell>> = std::cell::RefCell::new(None); + } + + struct $name; + impl HaulBlob for $name { + fn haul_blob(blob: Vec) -> Result<(), HaulBlobError>{ + $grabbed_payload.with(|rm| *rm.borrow_mut() = Some(blob)); + Ok(()) + } + } + } +); + +/// Simulates `HaulBlobExporter` and all its wrapping and captures generated plain bytes, +/// which are transferred over bridge. +pub(crate) fn simulate_message_exporter_on_bridged_chain< + SourceNetwork: Get, + DestinationNetwork: Get, + DestinationVersion: GetVersion, +>( + (destination_network, destination_junctions): (NetworkId, Junctions), +) -> Vec { + grab_haul_blob!(GrabbingHaulBlob, GRABBED_HAUL_BLOB_PAYLOAD); + + // lets pretend that some parachain on bridged chain exported the message + let universal_source_on_bridged_chain = + X2(GlobalConsensus(SourceNetwork::get()), Parachain(5678)); + let channel = 1_u32; + + // simulate XCM message export + let (ticket, fee) = validate_export::< + HaulBlobExporter, + >( + destination_network, + channel, + universal_source_on_bridged_chain, + destination_junctions, + dummy_xcm(), + ) + .expect("validate_export to pass"); + log::info!( + target: "simulate_message_exporter_on_bridged_chain", + "HaulBlobExporter::validate fee: {:?}", + fee + ); + let xcm_hash = + HaulBlobExporter::::deliver( + ticket, + ) + .expect("deliver to pass"); + log::info!( + target: "simulate_message_exporter_on_bridged_chain", + "HaulBlobExporter::deliver xcm_hash: {:?}", + xcm_hash + ); + + GRABBED_HAUL_BLOB_PAYLOAD.with(|r| r.take().expect("Encoded message should be here")) +} diff --git a/cumulus/parachains/runtimes/test-utils/src/lib.rs b/cumulus/parachains/runtimes/test-utils/src/lib.rs index a8ae63b250a..ca1e1633d4f 100644 --- a/cumulus/parachains/runtimes/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/test-utils/src/lib.rs @@ -114,14 +114,34 @@ impl BasicParachainRuntime for T +where + T: frame_system::Config + pallet_balances::Config + pallet_session::Config + pallet_xcm::Config - + parachain_info::Config, -> { + + parachain_info::Config + + pallet_collator_selection::Config + + cumulus_pallet_parachain_system::Config, + ValidatorIdOf: From>, +{ +} + +/// Basic builder based on balances, collators and pallet_session. +pub struct ExtBuilder { // endowed accounts with balances balances: Vec<(AccountIdOf, BalanceOf)>, // collators to test block prod @@ -135,14 +155,7 @@ pub struct ExtBuilder< _runtime: PhantomData, } -impl< - Runtime: frame_system::Config - + pallet_balances::Config - + pallet_session::Config - + pallet_xcm::Config - + parachain_info::Config, - > Default for ExtBuilder -{ +impl Default for ExtBuilder { fn default() -> ExtBuilder { ExtBuilder { balances: vec![], @@ -155,14 +168,7 @@ impl< } } -impl< - Runtime: frame_system::Config - + pallet_balances::Config - + pallet_session::Config - + pallet_xcm::Config - + parachain_info::Config, - > ExtBuilder -{ +impl ExtBuilder { pub fn with_balances( mut self, balances: Vec<(AccountIdOf, BalanceOf)>, @@ -198,12 +204,7 @@ impl< self } - pub fn build(self) -> sp_io::TestExternalities - where - Runtime: - pallet_collator_selection::Config + pallet_balances::Config + pallet_session::Config, - ValidatorIdOf: From>, - { + pub fn build(self) -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); pallet_xcm::GenesisConfig:: { -- GitLab From bc82eb6ec9888e0598df9ecdc2d17bcc1f3cd8d4 Mon Sep 17 00:00:00 2001 From: gupnik Date: Wed, 13 Dec 2023 15:30:24 +0530 Subject: [PATCH 53/59] Fixes parsing for config attrs in pallet macros (#2677) --- .../support/procedural/src/derive_impl.rs | 7 ++ .../procedural/src/pallet/expand/call.rs | 22 +++++-- .../procedural/src/pallet/expand/error.rs | 37 ++++++----- .../procedural/src/pallet/parse/call.rs | 4 ++ .../procedural/src/pallet/parse/error.rs | 26 ++++++-- .../frame/support/test/tests/derive_impl.rs | 52 +++++++++++++++ substrate/frame/support/test/tests/pallet.rs | 64 ++++++++++++++++++- 7 files changed, 187 insertions(+), 25 deletions(-) create mode 100644 substrate/frame/support/test/tests/derive_impl.rs diff --git a/substrate/frame/support/procedural/src/derive_impl.rs b/substrate/frame/support/procedural/src/derive_impl.rs index 3e044053116..d6d5bf68efd 100644 --- a/substrate/frame/support/procedural/src/derive_impl.rs +++ b/substrate/frame/support/procedural/src/derive_impl.rs @@ -136,9 +136,15 @@ fn combine_impls( return None } if let ImplItem::Type(typ) = item.clone() { + let cfg_attrs = typ + .attrs + .iter() + .filter(|attr| attr.path().get_ident().map_or(false, |ident| ident == "cfg")) + .map(|attr| attr.to_token_stream()); if is_runtime_type(&typ) { let item: ImplItem = if inject_runtime_types { parse_quote! { + #( #cfg_attrs )* type #ident = #ident; } } else { @@ -148,6 +154,7 @@ fn combine_impls( } // modify and insert uncolliding type items let modified_item: ImplItem = parse_quote! { + #( #cfg_attrs )* type #ident = <#default_impl_path as #disambiguation_path>::#ident; }; return Some(modified_item) diff --git a/substrate/frame/support/procedural/src/pallet/expand/call.rs b/substrate/frame/support/procedural/src/pallet/expand/call.rs index cf302faafc7..624cde018dc 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/call.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/call.rs @@ -241,6 +241,15 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { }) .collect::>(); + let cfg_attrs = methods + .iter() + .map(|method| { + let attrs = + method.cfg_attrs.iter().map(|attr| attr.to_token_stream()).collect::>(); + quote::quote!( #( #attrs )* ) + }) + .collect::>(); + let feeless_check = methods.iter().map(|method| &method.feeless_check).collect::>(); let feeless_check_result = feeless_check.iter().zip(args_name.iter()).map(|(feeless_check, arg_name)| { @@ -297,6 +306,7 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { #frame_support::Never, ), #( + #cfg_attrs #[doc = #fn_doc] #[codec(index = #call_index)] #fn_name { @@ -310,6 +320,7 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { impl<#type_impl_gen> #call_ident<#type_use_gen> #where_clause { #( + #cfg_attrs #[doc = #new_call_variant_doc] pub fn #new_call_variant_fn_name( #( #args_name_stripped: #args_type ),* @@ -328,6 +339,7 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { fn get_dispatch_info(&self) -> #frame_support::dispatch::DispatchInfo { match *self { #( + #cfg_attrs Self::#fn_name { #( #args_name_pattern_ref, )* } => { let __pallet_base_weight = #fn_weight; @@ -365,6 +377,7 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { fn is_feeless(&self, origin: &Self::Origin) -> bool { match *self { #( + #cfg_attrs Self::#fn_name { #( #args_name_pattern_ref, )* } => { #feeless_check_result }, @@ -379,13 +392,13 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { { fn get_call_name(&self) -> &'static str { match *self { - #( Self::#fn_name { .. } => stringify!(#fn_name), )* + #( #cfg_attrs Self::#fn_name { .. } => stringify!(#fn_name), )* Self::__Ignore(_, _) => unreachable!("__PhantomItem cannot be used."), } } fn get_call_names() -> &'static [&'static str] { - &[ #( stringify!(#fn_name), )* ] + &[ #( #cfg_attrs stringify!(#fn_name), )* ] } } @@ -394,13 +407,13 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { { fn get_call_index(&self) -> u8 { match *self { - #( Self::#fn_name { .. } => #call_index, )* + #( #cfg_attrs Self::#fn_name { .. } => #call_index, )* Self::__Ignore(_, _) => unreachable!("__PhantomItem cannot be used."), } } fn get_call_indices() -> &'static [u8] { - &[ #( #call_index, )* ] + &[ #( #cfg_attrs #call_index, )* ] } } @@ -416,6 +429,7 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { #frame_support::dispatch_context::run_in_context(|| { match self { #( + #cfg_attrs Self::#fn_name { #( #args_name_pattern, )* } => { #frame_support::__private::sp_tracing::enter_span!( #frame_support::__private::sp_tracing::trace_span!(stringify!(#fn_name)) diff --git a/substrate/frame/support/procedural/src/pallet/expand/error.rs b/substrate/frame/support/procedural/src/pallet/expand/error.rs index 877489fd605..72fb6e92357 100644 --- a/substrate/frame/support/procedural/src/pallet/expand/error.rs +++ b/substrate/frame/support/procedural/src/pallet/expand/error.rs @@ -16,10 +16,14 @@ // limitations under the License. use crate::{ - pallet::{parse::error::VariantField, Def}, + pallet::{ + parse::error::{VariantDef, VariantField}, + Def, + }, COUNTER, }; use frame_support_procedural_tools::get_doc_literals; +use quote::ToTokens; use syn::spanned::Spanned; /// @@ -67,20 +71,23 @@ pub fn expand_error(def: &mut Def) -> proc_macro2::TokenStream { ) ); - let as_str_matches = error.variants.iter().map(|(variant, field_ty, _)| { - let variant_str = variant.to_string(); - match field_ty { - Some(VariantField { is_named: true }) => { - quote::quote_spanned!(error.attr_span => Self::#variant { .. } => #variant_str,) - }, - Some(VariantField { is_named: false }) => { - quote::quote_spanned!(error.attr_span => Self::#variant(..) => #variant_str,) - }, - None => { - quote::quote_spanned!(error.attr_span => Self::#variant => #variant_str,) - }, - } - }); + let as_str_matches = error.variants.iter().map( + |VariantDef { ident: variant, field: field_ty, docs: _, cfg_attrs }| { + let variant_str = variant.to_string(); + let cfg_attrs = cfg_attrs.iter().map(|attr| attr.to_token_stream()); + match field_ty { + Some(VariantField { is_named: true }) => { + quote::quote_spanned!(error.attr_span => #( #cfg_attrs )* Self::#variant { .. } => #variant_str,) + }, + Some(VariantField { is_named: false }) => { + quote::quote_spanned!(error.attr_span => #( #cfg_attrs )* Self::#variant(..) => #variant_str,) + }, + None => { + quote::quote_spanned!(error.attr_span => #( #cfg_attrs )* Self::#variant => #variant_str,) + }, + } + }, + ); let error_item = { let item = &mut def.item.content.as_mut().expect("Checked by def parser").1[error.index]; diff --git a/substrate/frame/support/procedural/src/pallet/parse/call.rs b/substrate/frame/support/procedural/src/pallet/parse/call.rs index 58e14365e76..4e09b86fdde 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/call.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/call.rs @@ -85,6 +85,8 @@ pub struct CallVariantDef { pub docs: Vec, /// Attributes annotated at the top of the dispatchable function. pub attrs: Vec, + /// The `cfg` attributes. + pub cfg_attrs: Vec, /// The optional `feeless_if` attribute on the `pallet::call`. pub feeless_check: Option, } @@ -266,6 +268,7 @@ impl CallDef { return Err(syn::Error::new(method.sig.span(), msg)) } + let cfg_attrs: Vec = helper::get_item_cfg_attrs(&method.attrs); let mut call_idx_attrs = vec![]; let mut weight_attrs = vec![]; let mut feeless_attrs = vec![]; @@ -442,6 +445,7 @@ impl CallDef { args, docs, attrs: method.attrs.clone(), + cfg_attrs, feeless_check, }); } else { diff --git a/substrate/frame/support/procedural/src/pallet/parse/error.rs b/substrate/frame/support/procedural/src/pallet/parse/error.rs index 6f82ce61fc9..362df8d7340 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/error.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/error.rs @@ -25,19 +25,31 @@ mod keyword { syn::custom_keyword!(Error); } -/// Records information about the error enum variants. +/// Records information about the error enum variant field. pub struct VariantField { /// Whether or not the field is named, i.e. whether it is a tuple variant or struct variant. pub is_named: bool, } +/// Records information about the error enum variants. +pub struct VariantDef { + /// The variant ident. + pub ident: syn::Ident, + /// The variant field, if any. + pub field: Option, + /// The variant doc literals. + pub docs: Vec, + /// The `cfg` attributes. + pub cfg_attrs: Vec, +} + /// This checks error declaration as a enum declaration with only variants without fields nor /// discriminant. pub struct ErrorDef { /// The index of error item in pallet module. pub index: usize, - /// Variants ident, optional field and doc literals (ordered as declaration order) - pub variants: Vec<(syn::Ident, Option, Vec)>, + /// Variant definitions. + pub variants: Vec, /// A set of usage of instance, must be check for consistency with trait. pub instances: Vec, /// The keyword error used (contains span). @@ -87,8 +99,14 @@ impl ErrorDef { let span = variant.discriminant.as_ref().unwrap().0.span(); return Err(syn::Error::new(span, msg)) } + let cfg_attrs: Vec = helper::get_item_cfg_attrs(&variant.attrs); - Ok((variant.ident.clone(), field_ty, get_doc_literals(&variant.attrs))) + Ok(VariantDef { + ident: variant.ident.clone(), + field: field_ty, + docs: get_doc_literals(&variant.attrs), + cfg_attrs, + }) }) .collect::>()?; diff --git a/substrate/frame/support/test/tests/derive_impl.rs b/substrate/frame/support/test/tests/derive_impl.rs new file mode 100644 index 00000000000..675e85f4bfc --- /dev/null +++ b/substrate/frame/support/test/tests/derive_impl.rs @@ -0,0 +1,52 @@ +// This file is part of Substrate. + +// Copyright (C) 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 frame_support::derive_impl; + +trait Shape { + fn area(&self) -> u32; +} + +struct SomeRectangle {} + +#[frame_support::register_default_impl(SomeRectangle)] +impl Shape for SomeRectangle { + #[cfg(not(feature = "feature-frame-testing"))] + fn area(&self) -> u32 { + 10 + } + + #[cfg(feature = "feature-frame-testing")] + fn area(&self) -> u32 { + 0 + } +} + +struct SomeSquare {} + +#[derive_impl(SomeRectangle)] +impl Shape for SomeSquare {} + +#[test] +fn test_feature_parsing() { + let square = SomeSquare {}; + #[cfg(not(feature = "feature-frame-testing"))] + assert_eq!(square.area(), 10); + + #[cfg(feature = "feature-frame-testing")] + assert_eq!(square.area(), 0); +} diff --git a/substrate/frame/support/test/tests/pallet.rs b/substrate/frame/support/test/tests/pallet.rs index d2e5b185163..0223979d7f0 100644 --- a/substrate/frame/support/test/tests/pallet.rs +++ b/substrate/frame/support/test/tests/pallet.rs @@ -257,6 +257,13 @@ pub mod pallet { pub fn check_for_dispatch_context(_origin: OriginFor) -> DispatchResult { with_context::<(), _>(|_| ()).ok_or_else(|| DispatchError::Unavailable) } + + #[cfg(feature = "frame-feature-testing")] + #[pallet::call_index(5)] + #[pallet::weight({1})] + pub fn foo_feature_test(_origin: OriginFor) -> DispatchResult { + Ok(()) + } } #[pallet::error] @@ -269,6 +276,8 @@ pub mod pallet { #[codec(skip)] Skipped(u128), CompactU8(#[codec(compact)] u8), + #[cfg(feature = "frame-feature-testing")] + FeatureTest, } #[pallet::event] @@ -796,6 +805,7 @@ fn call_expand() { } ); assert_eq!(call_foo.get_call_name(), "foo"); + #[cfg(not(feature = "frame-feature-testing"))] assert_eq!( pallet::Call::::get_call_names(), &[ @@ -806,9 +816,24 @@ fn call_expand() { "check_for_dispatch_context" ], ); + #[cfg(feature = "frame-feature-testing")] + assert_eq!( + pallet::Call::::get_call_names(), + &[ + "foo", + "foo_storage_layer", + "foo_index_out_of_order", + "foo_no_post_info", + "check_for_dispatch_context", + "foo_feature_test" + ], + ); assert_eq!(call_foo.get_call_index(), 0u8); - assert_eq!(pallet::Call::::get_call_indices(), &[0u8, 1u8, 4u8, 2u8, 3u8]) + #[cfg(not(feature = "frame-feature-testing"))] + assert_eq!(pallet::Call::::get_call_indices(), &[0u8, 1u8, 4u8, 2u8, 3u8]); + #[cfg(feature = "frame-feature-testing")] + assert_eq!(pallet::Call::::get_call_indices(), &[0u8, 1u8, 4u8, 2u8, 3u8, 5u8]); } #[test] @@ -816,7 +841,10 @@ fn call_expand_index() { let call_foo = pallet::Call::::foo_index_out_of_order {}; assert_eq!(call_foo.get_call_index(), 4u8); - assert_eq!(pallet::Call::::get_call_indices(), &[0u8, 1u8, 4u8, 2u8, 3u8]) + #[cfg(not(feature = "frame-feature-testing"))] + assert_eq!(pallet::Call::::get_call_indices(), &[0u8, 1u8, 4u8, 2u8, 3u8]); + #[cfg(feature = "frame-feature-testing")] + assert_eq!(pallet::Call::::get_call_indices(), &[0u8, 1u8, 4u8, 2u8, 3u8, 5u8]); } #[test] @@ -838,6 +866,8 @@ fn error_expand() { }), ); assert_eq!( as PalletError>::MAX_ENCODED_SIZE, 3); + #[cfg(feature = "frame-feature-testing")] + assert_eq!(format!("{:?}", pallet::Error::::FeatureTest), String::from("FeatureTest"),); } #[test] @@ -2379,3 +2409,33 @@ fn test_dispatch_context() { .dispatch(RuntimeOrigin::root())); }); } + +#[test] +fn test_call_feature_parsing() { + let call = pallet::Call::::check_for_dispatch_context {}; + match call { + pallet::Call::::check_for_dispatch_context {} | + pallet::Call::::foo { .. } | + pallet::Call::foo_storage_layer { .. } | + pallet::Call::foo_index_out_of_order {} | + pallet::Call::foo_no_post_info {} => (), + #[cfg(feature = "frame-feature-testing")] + pallet::Call::foo_feature_test {} => (), + pallet::Call::__Ignore(_, _) => (), + } +} + +#[test] +fn test_error_feature_parsing() { + let err = pallet::Error::::InsufficientProposersBalance; + match err { + pallet::Error::InsufficientProposersBalance | + pallet::Error::NonExistentStorageValue | + pallet::Error::Code(_) | + pallet::Error::Skipped(_) | + pallet::Error::CompactU8(_) => (), + #[cfg(feature = "frame-feature-testing")] + pallet::Error::FeatureTest => (), + pallet::Error::__Ignore(_, _) => (), + } +} -- GitLab From 4c4407a8930267e139db93019c01444acf49e1ce Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Wed, 13 Dec 2023 12:33:19 +0100 Subject: [PATCH 54/59] Updated benchmarks related to the Rococo/Westend bridge (#2639) Co-authored-by: command-bot <> --- .../weights/pallet_xcm_bridge_hub_router.rs | 20 +- .../weights/pallet_xcm_bridge_hub_router.rs | 20 +- .../src/weights/pallet_bridge_grandpa.rs | 16 +- .../src/weights/pallet_bridge_messages.rs | 58 +++--- .../src/weights/pallet_bridge_parachains.rs | 20 +- .../src/weights/pallet_bridge_relayers.rs | 34 ++-- .../xcm/pallet_xcm_benchmarks_generic.rs | 130 ++++++------ .../src/weights/pallet_bridge_grandpa.rs | 28 ++- .../src/weights/pallet_bridge_messages.rs | 187 +++++++++--------- .../src/weights/pallet_bridge_parachains.rs | 78 ++++---- .../src/weights/pallet_bridge_relayers.rs | 30 +-- .../xcm/pallet_xcm_benchmarks_generic.rs | 142 +++++++------ 12 files changed, 376 insertions(+), 387 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs index aeaaed45452..775bc3bdb80 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_bridge_hub_router` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-12-12, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-r43aesjn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-itmxxexx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -58,8 +58,8 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `154` // Estimated: `1639` - // Minimum execution time: 8_110_000 picoseconds. - Weight::from_parts(8_373_000, 0) + // Minimum execution time: 7_853_000 picoseconds. + Weight::from_parts(8_443_000, 0) .saturating_add(Weight::from_parts(0, 1639)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -72,8 +72,8 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `144` // Estimated: `1629` - // Minimum execution time: 4_459_000 picoseconds. - Weight::from_parts(4_663_000, 0) + // Minimum execution time: 4_333_000 picoseconds. + Weight::from_parts(4_501_000, 0) .saturating_add(Weight::from_parts(0, 1629)) .saturating_add(T::DbWeight::get().reads(2)) } @@ -83,8 +83,8 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `150` // Estimated: `1502` - // Minimum execution time: 10_153_000 picoseconds. - Weight::from_parts(10_737_000, 0) + // Minimum execution time: 10_167_000 picoseconds. + Weight::from_parts(10_667_000, 0) .saturating_add(Weight::from_parts(0, 1502)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -117,8 +117,8 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `448` // Estimated: `6388` - // Minimum execution time: 61_258_000 picoseconds. - Weight::from_parts(63_679_000, 0) + // Minimum execution time: 60_584_000 picoseconds. + Weight::from_parts(62_467_000, 0) .saturating_add(Weight::from_parts(0, 6388)) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(4)) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs index ee8d0ae3c45..84d717b0283 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_bridge_hub_router` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-12-12, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-r43aesjn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-itmxxexx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -58,8 +58,8 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `193` // Estimated: `1678` - // Minimum execution time: 8_460_000 picoseconds. - Weight::from_parts(8_730_000, 0) + // Minimum execution time: 8_095_000 picoseconds. + Weight::from_parts(8_393_000, 0) .saturating_add(Weight::from_parts(0, 1678)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -72,8 +72,8 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `111` // Estimated: `1596` - // Minimum execution time: 3_469_000 picoseconds. - Weight::from_parts(3_696_000, 0) + // Minimum execution time: 3_417_000 picoseconds. + Weight::from_parts(3_583_000, 0) .saturating_add(Weight::from_parts(0, 1596)) .saturating_add(T::DbWeight::get().reads(2)) } @@ -83,8 +83,8 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `117` // Estimated: `1502` - // Minimum execution time: 10_315_000 picoseconds. - Weight::from_parts(10_651_000, 0) + // Minimum execution time: 10_280_000 picoseconds. + Weight::from_parts(10_703_000, 0) .saturating_add(Weight::from_parts(0, 1502)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -117,8 +117,8 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `487` // Estimated: `6427` - // Minimum execution time: 64_532_000 picoseconds. - Weight::from_parts(66_901_000, 0) + // Minimum execution time: 63_624_000 picoseconds. + Weight::from_parts(66_071_000, 0) .saturating_add(Weight::from_parts(0, 6427)) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(4)) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs index aaa6a3e0622..8c2435599f5 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_bridge_grandpa` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-14, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-12-12, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-itmxxexx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -66,13 +66,13 @@ impl pallet_bridge_grandpa::WeightInfo for WeightInfo pallet_bridge_messages::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `538` // Estimated: `52645` - // Minimum execution time: 41_577_000 picoseconds. - Weight::from_parts(42_621_000, 0) + // Minimum execution time: 39_918_000 picoseconds. + Weight::from_parts(40_996_000, 0) .saturating_add(Weight::from_parts(0, 52645)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) @@ -82,8 +82,8 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `538` // Estimated: `52645` - // Minimum execution time: 52_880_000 picoseconds. - Weight::from_parts(53_697_000, 0) + // Minimum execution time: 50_245_000 picoseconds. + Weight::from_parts(51_441_000, 0) .saturating_add(Weight::from_parts(0, 52645)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) @@ -102,8 +102,8 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `538` // Estimated: `52645` - // Minimum execution time: 47_424_000 picoseconds. - Weight::from_parts(48_445_000, 0) + // Minimum execution time: 44_572_000 picoseconds. + Weight::from_parts(45_629_000, 0) .saturating_add(Weight::from_parts(0, 52645)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) @@ -120,8 +120,8 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `506` // Estimated: `52645` - // Minimum execution time: 40_619_000 picoseconds. - Weight::from_parts(42_262_000, 0) + // Minimum execution time: 38_804_000 picoseconds. + Weight::from_parts(39_516_000, 0) .saturating_add(Weight::from_parts(0, 52645)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)) @@ -138,8 +138,8 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `506` // Estimated: `52645` - // Minimum execution time: 74_603_000 picoseconds. - Weight::from_parts(78_209_000, 0) + // Minimum execution time: 68_674_000 picoseconds. + Weight::from_parts(72_690_000, 0) .saturating_add(Weight::from_parts(0, 52645)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)) @@ -156,11 +156,11 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_single_message() -> Weight { // Proof Size summary in bytes: - // Measured: `377` - // Estimated: `3842` - // Minimum execution time: 33_762_000 picoseconds. - Weight::from_parts(34_405_000, 0) - .saturating_add(Weight::from_parts(0, 3842)) + // Measured: `413` + // Estimated: `3878` + // Minimum execution time: 32_833_000 picoseconds. + Weight::from_parts(33_442_000, 0) + .saturating_add(Weight::from_parts(0, 3878)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -176,11 +176,11 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { // Proof Size summary in bytes: - // Measured: `377` - // Estimated: `3842` - // Minimum execution time: 33_805_000 picoseconds. - Weight::from_parts(35_051_000, 0) - .saturating_add(Weight::from_parts(0, 3842)) + // Measured: `413` + // Estimated: `3878` + // Minimum execution time: 32_528_000 picoseconds. + Weight::from_parts(33_627_000, 0) + .saturating_add(Weight::from_parts(0, 3878)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -196,10 +196,10 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { // Proof Size summary in bytes: - // Measured: `377` + // Measured: `413` // Estimated: `6086` - // Minimum execution time: 38_612_000 picoseconds. - Weight::from_parts(39_412_000, 0) + // Minimum execution time: 37_493_000 picoseconds. + Weight::from_parts(38_324_000, 0) .saturating_add(Weight::from_parts(0, 6086)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) @@ -231,11 +231,11 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `669` // Estimated: `52645` - // Minimum execution time: 69_285_000 picoseconds. - Weight::from_parts(70_867_498, 0) + // Minimum execution time: 64_104_000 picoseconds. + Weight::from_parts(66_006_268, 0) .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 111 - .saturating_add(Weight::from_parts(7_489, 0).saturating_mul(i.into())) + // Standard Error: 91 + .saturating_add(Weight::from_parts(7_932, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs index 5c7c4a63682..ea68852804e 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_bridge_parachains` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-14, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-12-12, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-itmxxexx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -59,13 +59,15 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:0 w:1) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// The range of component `p` is `[1, 2]`. - fn submit_parachain_heads_with_n_parachains(_p: u32, ) -> Weight { + fn submit_parachain_heads_with_n_parachains(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `434` // Estimated: `2543` - // Minimum execution time: 31_987_000 picoseconds. - Weight::from_parts(33_060_534, 0) + // Minimum execution time: 31_135_000 picoseconds. + Weight::from_parts(32_061_351, 0) .saturating_add(Weight::from_parts(0, 2543)) + // Standard Error: 80_309 + .saturating_add(Weight::from_parts(99_724, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -83,8 +85,8 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `434` // Estimated: `2543` - // Minimum execution time: 33_360_000 picoseconds. - Weight::from_parts(34_182_000, 0) + // Minimum execution time: 32_263_000 picoseconds. + Weight::from_parts(33_139_000, 0) .saturating_add(Weight::from_parts(0, 2543)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) @@ -103,8 +105,8 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `434` // Estimated: `2543` - // Minimum execution time: 65_246_000 picoseconds. - Weight::from_parts(65_985_000, 0) + // Minimum execution time: 61_313_000 picoseconds. + Weight::from_parts(62_200_000, 0) .saturating_add(Weight::from_parts(0, 2543)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs index 70af694645d..5ab4cb900d8 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_bridge_relayers` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-14, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-12-12, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yprdrvc7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-itmxxexx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -54,10 +54,10 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn claim_rewards() -> Weight { // Proof Size summary in bytes: - // Measured: `207` + // Measured: `244` // Estimated: `3593` - // Minimum execution time: 46_579_000 picoseconds. - Weight::from_parts(48_298_000, 0) + // Minimum execution time: 45_393_000 picoseconds. + Weight::from_parts(46_210_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -70,10 +70,10 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< /// Proof: `Balances::Reserves` (`max_values`: None, `max_size`: Some(1249), added: 3724, mode: `MaxEncodedLen`) fn register() -> Weight { // Proof Size summary in bytes: - // Measured: `61` + // Measured: `97` // Estimated: `4714` - // Minimum execution time: 24_219_000 picoseconds. - Weight::from_parts(24_993_000, 0) + // Minimum execution time: 23_767_000 picoseconds. + Weight::from_parts(24_217_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -84,10 +84,10 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< /// Proof: `Balances::Reserves` (`max_values`: None, `max_size`: Some(1249), added: 3724, mode: `MaxEncodedLen`) fn deregister() -> Weight { // Proof Size summary in bytes: - // Measured: `160` + // Measured: `197` // Estimated: `4714` - // Minimum execution time: 26_279_000 picoseconds. - Weight::from_parts(26_810_000, 0) + // Minimum execution time: 25_745_000 picoseconds. + Weight::from_parts(26_319_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -100,10 +100,10 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn slash_and_deregister() -> Weight { // Proof Size summary in bytes: - // Measured: `263` + // Measured: `300` // Estimated: `4714` - // Minimum execution time: 27_672_000 picoseconds. - Weight::from_parts(28_946_000, 0) + // Minimum execution time: 27_497_000 picoseconds. + Weight::from_parts(27_939_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) @@ -112,10 +112,10 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn register_relayer_reward() -> Weight { // Proof Size summary in bytes: - // Measured: `6` + // Measured: `42` // Estimated: `3538` - // Minimum execution time: 5_487_000 picoseconds. - Weight::from_parts(5_725_000, 0) + // Minimum execution time: 5_584_000 picoseconds. + Weight::from_parts(5_908_000, 0) .saturating_add(Weight::from_parts(0, 3538)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 606e47457d2..abd84f8e89b 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-12-12, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-r43aesjn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-itmxxexx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-rococo-dev"), DB CACHE: 1024 // Executed Command: @@ -68,8 +68,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 61_049_000 picoseconds. - Weight::from_parts(62_672_000, 6196) + // Minimum execution time: 61_813_000 picoseconds. + Weight::from_parts(62_996_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -77,8 +77,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_972_000 picoseconds. - Weight::from_parts(2_095_000, 0) + // Minimum execution time: 2_044_000 picoseconds. + Weight::from_parts(2_112_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -86,58 +86,58 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `3497` - // Minimum execution time: 7_541_000 picoseconds. - Weight::from_parts(7_875_000, 3497) + // Minimum execution time: 7_472_000 picoseconds. + Weight::from_parts(7_723_000, 3497) .saturating_add(T::DbWeight::get().reads(1)) } pub fn transact() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_467_000 picoseconds. - Weight::from_parts(8_653_000, 0) + // Minimum execution time: 8_414_000 picoseconds. + Weight::from_parts(8_765_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_141_000 picoseconds. - Weight::from_parts(2_231_000, 0) + // Minimum execution time: 2_192_000 picoseconds. + Weight::from_parts(2_243_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_881_000 picoseconds. - Weight::from_parts(1_941_000, 0) + // Minimum execution time: 1_866_000 picoseconds. + Weight::from_parts(1_931_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_846_000 picoseconds. - Weight::from_parts(1_916_000, 0) + // Minimum execution time: 1_847_000 picoseconds. + Weight::from_parts(1_921_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_857_000 picoseconds. - Weight::from_parts(1_910_000, 0) + // Minimum execution time: 1_797_000 picoseconds. + Weight::from_parts(1_880_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_493_000 picoseconds. - Weight::from_parts(2_570_000, 0) + // Minimum execution time: 2_458_000 picoseconds. + Weight::from_parts(2_523_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_857_000 picoseconds. - Weight::from_parts(1_930_000, 0) + // Minimum execution time: 1_833_000 picoseconds. + Weight::from_parts(1_906_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -159,8 +159,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 54_805_000 picoseconds. - Weight::from_parts(55_690_000, 6196) + // Minimum execution time: 54_659_000 picoseconds. + Weight::from_parts(56_025_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -170,8 +170,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 11_062_000 picoseconds. - Weight::from_parts(11_505_000, 3555) + // Minimum execution time: 10_953_000 picoseconds. + Weight::from_parts(11_220_000, 3555) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -179,8 +179,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_873_000 picoseconds. - Weight::from_parts(1_962_000, 0) + // Minimum execution time: 1_834_000 picoseconds. + Weight::from_parts(1_892_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -200,8 +200,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 22_356_000 picoseconds. - Weight::from_parts(23_066_000, 3503) + // Minimum execution time: 22_238_000 picoseconds. + Weight::from_parts(22_690_000, 3503) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -211,44 +211,44 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_819_000 picoseconds. - Weight::from_parts(3_992_000, 0) + // Minimum execution time: 3_798_000 picoseconds. + Weight::from_parts(3_936_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } pub fn burn_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_033_000 picoseconds. - Weight::from_parts(3_157_000, 0) + // Minimum execution time: 2_985_000 picoseconds. + Weight::from_parts(3_099_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_994_000 picoseconds. - Weight::from_parts(2_056_000, 0) + // Minimum execution time: 1_955_000 picoseconds. + Weight::from_parts(2_050_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_978_000 picoseconds. - Weight::from_parts(2_069_000, 0) + // Minimum execution time: 1_939_000 picoseconds. + Weight::from_parts(1_990_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_894_000 picoseconds. - Weight::from_parts(1_977_000, 0) + // Minimum execution time: 1_841_000 picoseconds. + Weight::from_parts(1_900_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_114_000 picoseconds. - Weight::from_parts(2_223_000, 0) + // Minimum execution time: 2_081_000 picoseconds. + Weight::from_parts(2_145_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -270,8 +270,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 58_704_000 picoseconds. - Weight::from_parts(59_677_000, 6196) + // Minimum execution time: 59_600_000 picoseconds. + Weight::from_parts(61_572_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -279,8 +279,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_506_000 picoseconds. - Weight::from_parts(4_672_000, 0) + // Minimum execution time: 4_390_000 picoseconds. + Weight::from_parts(4_517_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -302,8 +302,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 54_896_000 picoseconds. - Weight::from_parts(56_331_000, 6196) + // Minimum execution time: 53_864_000 picoseconds. + Weight::from_parts(55_527_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -311,29 +311,27 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_946_000 picoseconds. - Weight::from_parts(2_002_000, 0) + // Minimum execution time: 1_879_000 picoseconds. + Weight::from_parts(1_947_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_898_000 picoseconds. - Weight::from_parts(1_961_000, 0) + // Minimum execution time: 1_827_000 picoseconds. + Weight::from_parts(1_900_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_895_000 picoseconds. - Weight::from_parts(1_964_000, 0) + // Minimum execution time: 1_824_000 picoseconds. + Weight::from_parts(1_898_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) // Storage: `PolkadotXcm::SupportedVersion` (r:2 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) // Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) // Storage: `BridgeWestendMessages::OutboundLanes` (r:1 w:1) @@ -347,25 +345,25 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `190` // Estimated: `6130` - // Minimum execution time: 36_547_000 picoseconds. - Weight::from_parts(37_623_117, 6130) - // Standard Error: 735 - .saturating_add(Weight::from_parts(315_274, 0).saturating_mul(x.into())) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(3)) + // Minimum execution time: 41_598_000 picoseconds. + Weight::from_parts(42_219_173, 6130) + // Standard Error: 426 + .saturating_add(Weight::from_parts(452_460, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(2)) } pub fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_868_000 picoseconds. - Weight::from_parts(1_910_000, 0) + // Minimum execution time: 1_812_000 picoseconds. + Weight::from_parts(1_898_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_998_000 picoseconds. - Weight::from_parts(2_069_000, 0) + // Minimum execution time: 1_915_000 picoseconds. + Weight::from_parts(1_976_000, 0) } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_grandpa.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_grandpa.rs index b0634ff2ccf..e87ed668dfc 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_grandpa.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_grandpa.rs @@ -17,10 +17,10 @@ //! Autogenerated weights for `pallet_bridge_grandpa` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-12-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `runner-itmxxexx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: // target/production/polkadot-parachain @@ -33,9 +33,9 @@ // --heap-pages=4096 // --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json // --pallet=pallet_bridge_grandpa -// --chain=bridge-hub-rococo-dev +// --chain=bridge-hub-westend-dev // --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/ +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -62,21 +62,17 @@ impl pallet_bridge_grandpa::WeightInfo for WeightInfo Weight { // Proof Size summary in bytes: - // Measured: `268 + p * (60 ±0)` + // Measured: `231 + p * (60 ±0)` // Estimated: `51735` - // Minimum execution time: 304_726_000 picoseconds. - Weight::from_parts(16_868_060, 0) + // Minimum execution time: 303_549_000 picoseconds. + Weight::from_parts(306_232_000, 0) .saturating_add(Weight::from_parts(0, 51735)) - // Standard Error: 2_802 - .saturating_add(Weight::from_parts(55_200_017, 0).saturating_mul(p.into())) - // Standard Error: 46_745 - .saturating_add(Weight::from_parts(2_689_151, 0).saturating_mul(v.into())) + // Standard Error: 4_641 + .saturating_add(Weight::from_parts(55_196_301, 0).saturating_mul(p.into())) + // Standard Error: 35_813 + .saturating_add(Weight::from_parts(70_584, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(5)) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_messages.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_messages.rs index 5d229497f3e..305a8726fa1 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_messages.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_messages.rs @@ -17,10 +17,10 @@ //! Autogenerated weights for `pallet_bridge_messages` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-12-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `runner-itmxxexx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: // target/production/polkadot-parachain @@ -33,9 +33,9 @@ // --heap-pages=4096 // --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json // --pallet=pallet_bridge_messages -// --chain=bridge-hub-rococo-dev +// --chain=bridge-hub-westend-dev // --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/ +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -48,170 +48,170 @@ use core::marker::PhantomData; /// Weight functions for `pallet_bridge_messages`. pub struct WeightInfo(PhantomData); impl pallet_bridge_messages::WeightInfo for WeightInfo { - /// Storage: `BridgeWestendToRococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWestendToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeWestendToRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendToRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `575` + // Measured: `502` // Estimated: `52645` - // Minimum execution time: 42_332_000 picoseconds. - Weight::from_parts(43_375_000, 0) + // Minimum execution time: 40_646_000 picoseconds. + Weight::from_parts(41_754_000, 0) .saturating_add(Weight::from_parts(0, 52645)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `BridgeWestendToRococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWestendToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeWestendToRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendToRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_two_messages_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `575` + // Measured: `502` // Estimated: `52645` - // Minimum execution time: 53_139_000 picoseconds. - Weight::from_parts(54_236_000, 0) + // Minimum execution time: 50_898_000 picoseconds. + Weight::from_parts(52_743_000, 0) .saturating_add(Weight::from_parts(0, 52645)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `BridgeWestendToRococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWestendToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeWestendToRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendToRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof_with_outbound_lane_state() -> Weight { // Proof Size summary in bytes: - // Measured: `575` + // Measured: `502` // Estimated: `52645` - // Minimum execution time: 47_466_000 picoseconds. - Weight::from_parts(48_724_000, 0) + // Minimum execution time: 45_848_000 picoseconds. + Weight::from_parts(47_036_000, 0) .saturating_add(Weight::from_parts(0, 52645)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `BridgeWestendToRococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWestendToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeWestendToRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendToRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) fn receive_single_message_proof_1_kb() -> Weight { // Proof Size summary in bytes: - // Measured: `543` + // Measured: `433` // Estimated: `52645` - // Minimum execution time: 40_962_000 picoseconds. - Weight::from_parts(42_002_000, 0) + // Minimum execution time: 39_085_000 picoseconds. + Weight::from_parts(41_623_000, 0) .saturating_add(Weight::from_parts(0, 52645)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `BridgeWestendToRococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWestendToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeWestendToRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendToRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) fn receive_single_message_proof_16_kb() -> Weight { // Proof Size summary in bytes: - // Measured: `543` + // Measured: `433` // Estimated: `52645` - // Minimum execution time: 71_599_000 picoseconds. - Weight::from_parts(74_307_000, 0) + // Minimum execution time: 72_754_000 picoseconds. + Weight::from_parts(74_985_000, 0) .saturating_add(Weight::from_parts(0, 52645)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `BridgeWestendToRococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWestendToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeWestendToRococoMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendToRococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoMessages::OutboundLanes` (r:1 w:1) + /// Proof: `BridgeRococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_single_message() -> Weight { // Proof Size summary in bytes: - // Measured: `414` - // Estimated: `3879` - // Minimum execution time: 31_206_000 picoseconds. - Weight::from_parts(32_045_000, 0) - .saturating_add(Weight::from_parts(0, 3879)) + // Measured: `337` + // Estimated: `3802` + // Minimum execution time: 31_479_000 picoseconds. + Weight::from_parts(32_280_000, 0) + .saturating_add(Weight::from_parts(0, 3802)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `BridgeWestendToRococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWestendToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeWestendToRococoMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendToRococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoMessages::OutboundLanes` (r:1 w:1) + /// Proof: `BridgeRococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { // Proof Size summary in bytes: - // Measured: `414` - // Estimated: `3879` - // Minimum execution time: 31_211_000 picoseconds. - Weight::from_parts(32_171_000, 0) - .saturating_add(Weight::from_parts(0, 3879)) + // Measured: `337` + // Estimated: `3802` + // Minimum execution time: 31_807_000 picoseconds. + Weight::from_parts(32_219_000, 0) + .saturating_add(Weight::from_parts(0, 3802)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: `BridgeWestendToRococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWestendToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeWestendToRococoMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendToRococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoMessages::OutboundLanes` (r:1 w:1) + /// Proof: `BridgeRococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:2 w:2) /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { // Proof Size summary in bytes: - // Measured: `414` + // Measured: `337` // Estimated: `6086` - // Minimum execution time: 33_790_000 picoseconds. - Weight::from_parts(34_708_000, 0) + // Minimum execution time: 36_450_000 picoseconds. + Weight::from_parts(37_288_000, 0) .saturating_add(Weight::from_parts(0, 6086)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `BridgeWestendToRococoMessages::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeWestendToRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:1 w:0) - /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// Storage: `BridgeWestendToRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendToRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) + /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) + /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) @@ -227,18 +227,15 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `XcmpQueue::OutboundXcmpMessages` (r:0 w:1) /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `i` is `[128, 2048]`. - /// The range of component `i` is `[128, 2048]`. - /// The range of component `i` is `[128, 2048]`. - /// The range of component `i` is `[128, 2048]`. fn receive_single_message_proof_with_dispatch(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `777` + // Measured: `633` // Estimated: `52645` - // Minimum execution time: 61_938_000 picoseconds. - Weight::from_parts(63_009_714, 0) + // Minimum execution time: 67_047_000 picoseconds. + Weight::from_parts(68_717_105, 0) .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 23 - .saturating_add(Weight::from_parts(6_677, 0).saturating_mul(i.into())) + // Standard Error: 138 + .saturating_add(Weight::from_parts(8_056, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(4)) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_parachains.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_parachains.rs index 81cb0a66b7d..9819bd40654 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_parachains.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_parachains.rs @@ -17,10 +17,10 @@ //! Autogenerated weights for `pallet_bridge_parachains` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-12-12, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `runner-itmxxexx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: // target/production/polkadot-parachain @@ -33,9 +33,9 @@ // --heap-pages=4096 // --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json // --pallet=pallet_bridge_parachains -// --chain=bridge-hub-rococo-dev +// --chain=bridge-hub-westend-dev // --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/ +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -48,65 +48,63 @@ use core::marker::PhantomData; /// Weight functions for `pallet_bridge_parachains`. pub struct WeightInfo(PhantomData); impl pallet_bridge_parachains::WeightInfo for WeightInfo { - /// Storage: `BridgeRococoParachain::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoParachain::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoParachains::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoParachains::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoGrandpa::ImportedHeaders` (r:1 w:0) /// Proof: `BridgeRococoGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoParachain::ParasInfo` (r:1 w:1) - /// Proof: `BridgeRococoParachain::ParasInfo` (`max_values`: Some(1), `max_size`: Some(60), added: 555, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoParachain::ImportedParaHashes` (r:1 w:1) - /// Proof: `BridgeRococoParachain::ImportedParaHashes` (`max_values`: Some(64), `max_size`: Some(64), added: 1054, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:0 w:1) - /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) - /// The range of component `p` is `[1, 2]`. - /// The range of component `p` is `[1, 2]`. + /// Storage: `BridgeRococoParachains::ParasInfo` (r:1 w:1) + /// Proof: `BridgeRococoParachains::ParasInfo` (`max_values`: Some(1), `max_size`: Some(60), added: 555, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoParachains::ImportedParaHashes` (r:1 w:1) + /// Proof: `BridgeRococoParachains::ImportedParaHashes` (`max_values`: Some(64), `max_size`: Some(64), added: 1054, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:0 w:1) + /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// The range of component `p` is `[1, 2]`. fn submit_parachain_heads_with_n_parachains(_p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `367` + // Measured: `291` // Estimated: `2543` - // Minimum execution time: 31_241_000 picoseconds. - Weight::from_parts(32_488_584, 0) + // Minimum execution time: 29_994_000 picoseconds. + Weight::from_parts(31_005_636, 0) .saturating_add(Weight::from_parts(0, 2543)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `BridgeRococoParachain::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoParachain::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoParachains::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoParachains::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoGrandpa::ImportedHeaders` (r:1 w:0) /// Proof: `BridgeRococoGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoParachain::ParasInfo` (r:1 w:1) - /// Proof: `BridgeRococoParachain::ParasInfo` (`max_values`: Some(1), `max_size`: Some(60), added: 555, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoParachain::ImportedParaHashes` (r:1 w:1) - /// Proof: `BridgeRococoParachain::ImportedParaHashes` (`max_values`: Some(64), `max_size`: Some(64), added: 1054, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:0 w:1) - /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoParachains::ParasInfo` (r:1 w:1) + /// Proof: `BridgeRococoParachains::ParasInfo` (`max_values`: Some(1), `max_size`: Some(60), added: 555, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoParachains::ImportedParaHashes` (r:1 w:1) + /// Proof: `BridgeRococoParachains::ImportedParaHashes` (`max_values`: Some(64), `max_size`: Some(64), added: 1054, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:0 w:1) + /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) fn submit_parachain_heads_with_1kb_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `367` + // Measured: `291` // Estimated: `2543` - // Minimum execution time: 32_962_000 picoseconds. - Weight::from_parts(33_658_000, 0) + // Minimum execution time: 31_425_000 picoseconds. + Weight::from_parts(32_163_000, 0) .saturating_add(Weight::from_parts(0, 2543)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `BridgeRococoParachain::PalletOperatingMode` (r:1 w:0) - /// Proof: `BridgeRococoParachain::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoParachains::PalletOperatingMode` (r:1 w:0) + /// Proof: `BridgeRococoParachains::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoGrandpa::ImportedHeaders` (r:1 w:0) /// Proof: `BridgeRococoGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoParachain::ParasInfo` (r:1 w:1) - /// Proof: `BridgeRococoParachain::ParasInfo` (`max_values`: Some(1), `max_size`: Some(60), added: 555, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoParachain::ImportedParaHashes` (r:1 w:1) - /// Proof: `BridgeRococoParachain::ImportedParaHashes` (`max_values`: Some(64), `max_size`: Some(64), added: 1054, mode: `MaxEncodedLen`) - /// Storage: `BridgeRococoParachain::ImportedParaHeads` (r:0 w:1) - /// Proof: `BridgeRococoParachain::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoParachains::ParasInfo` (r:1 w:1) + /// Proof: `BridgeRococoParachains::ParasInfo` (`max_values`: Some(1), `max_size`: Some(60), added: 555, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoParachains::ImportedParaHashes` (r:1 w:1) + /// Proof: `BridgeRococoParachains::ImportedParaHashes` (`max_values`: Some(64), `max_size`: Some(64), added: 1054, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:0 w:1) + /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) fn submit_parachain_heads_with_16kb_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `367` + // Measured: `291` // Estimated: `2543` - // Minimum execution time: 62_685_000 picoseconds. - Weight::from_parts(64_589_000, 0) + // Minimum execution time: 60_062_000 picoseconds. + Weight::from_parts(61_201_000, 0) .saturating_add(Weight::from_parts(0, 2543)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_relayers.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_relayers.rs index fde670ab927..ed96f0cd87c 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_relayers.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_relayers.rs @@ -17,10 +17,10 @@ //! Autogenerated weights for `pallet_bridge_relayers` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-10-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-12-12, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-vmdtonbz-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `runner-itmxxexx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: // target/production/polkadot-parachain @@ -33,9 +33,9 @@ // --heap-pages=4096 // --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json // --pallet=pallet_bridge_relayers -// --chain=bridge-hub-rococo-dev +// --chain=bridge-hub-westend-dev // --header=./cumulus/file_header.txt -// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/ +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -56,8 +56,8 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `207` // Estimated: `3593` - // Minimum execution time: 45_338_000 picoseconds. - Weight::from_parts(45_836_000, 0) + // Minimum execution time: 45_732_000 picoseconds. + Weight::from_parts(46_282_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -72,8 +72,8 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `61` // Estimated: `4714` - // Minimum execution time: 23_561_000 picoseconds. - Weight::from_parts(24_012_000, 0) + // Minimum execution time: 22_934_000 picoseconds. + Weight::from_parts(23_531_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -86,8 +86,8 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `160` // Estimated: `4714` - // Minimum execution time: 25_133_000 picoseconds. - Weight::from_parts(25_728_000, 0) + // Minimum execution time: 25_187_000 picoseconds. + Weight::from_parts(25_679_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -102,8 +102,8 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `263` // Estimated: `4714` - // Minimum execution time: 27_356_000 picoseconds. - Weight::from_parts(27_828_000, 0) + // Minimum execution time: 27_015_000 picoseconds. + Weight::from_parts(27_608_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) @@ -114,8 +114,8 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `6` // Estimated: `3538` - // Minimum execution time: 2_955_000 picoseconds. - Weight::from_parts(3_084_000, 0) + // Minimum execution time: 5_207_000 picoseconds. + Weight::from_parts(5_394_000, 0) .saturating_add(Weight::from_parts(0, 3538)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 8f283403400..9281a880c7e 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-12-12, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-r43aesjn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-itmxxexx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-westend-dev"), DB CACHE: 1024 // Executed Command: @@ -66,10 +66,10 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn report_holding() -> Weight { // Proof Size summary in bytes: - // Measured: `171` + // Measured: `208` // Estimated: `6196` - // Minimum execution time: 61_383_000 picoseconds. - Weight::from_parts(62_382_000, 6196) + // Minimum execution time: 61_577_000 picoseconds. + Weight::from_parts(63_216_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -77,8 +77,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_057_000 picoseconds. - Weight::from_parts(2_153_000, 0) + // Minimum execution time: 2_019_000 picoseconds. + Weight::from_parts(2_146_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -86,58 +86,58 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `3497` - // Minimum execution time: 7_949_000 picoseconds. - Weight::from_parts(8_250_000, 3497) + // Minimum execution time: 7_473_000 picoseconds. + Weight::from_parts(7_784_000, 3497) .saturating_add(T::DbWeight::get().reads(1)) } pub fn transact() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_608_000 picoseconds. - Weight::from_parts(9_086_000, 0) + // Minimum execution time: 8_385_000 picoseconds. + Weight::from_parts(8_768_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_240_000 picoseconds. - Weight::from_parts(2_348_000, 0) + // Minimum execution time: 2_181_000 picoseconds. + Weight::from_parts(2_304_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_969_000 picoseconds. - Weight::from_parts(2_017_000, 0) + // Minimum execution time: 1_858_000 picoseconds. + Weight::from_parts(1_919_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_907_000 picoseconds. - Weight::from_parts(2_001_000, 0) + // Minimum execution time: 1_855_000 picoseconds. + Weight::from_parts(1_979_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_880_000 picoseconds. - Weight::from_parts(1_975_000, 0) + // Minimum execution time: 1_823_000 picoseconds. + Weight::from_parts(1_890_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_549_000 picoseconds. - Weight::from_parts(2_624_000, 0) + // Minimum execution time: 2_407_000 picoseconds. + Weight::from_parts(2_507_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_895_000 picoseconds. - Weight::from_parts(1_963_000, 0) + // Minimum execution time: 1_838_000 picoseconds. + Weight::from_parts(1_894_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -157,10 +157,10 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn report_error() -> Weight { // Proof Size summary in bytes: - // Measured: `171` + // Measured: `208` // Estimated: `6196` - // Minimum execution time: 54_447_000 picoseconds. - Weight::from_parts(55_629_000, 6196) + // Minimum execution time: 54_847_000 picoseconds. + Weight::from_parts(55_742_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -170,8 +170,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 11_597_000 picoseconds. - Weight::from_parts(11_809_000, 3555) + // Minimum execution time: 10_614_000 picoseconds. + Weight::from_parts(11_344_000, 3555) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -179,8 +179,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_895_000 picoseconds. - Weight::from_parts(1_977_000, 0) + // Minimum execution time: 1_826_000 picoseconds. + Weight::from_parts(1_899_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -200,8 +200,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 23_314_000 picoseconds. - Weight::from_parts(23_905_000, 3503) + // Minimum execution time: 22_312_000 picoseconds. + Weight::from_parts(22_607_000, 3503) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -211,44 +211,44 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_948_000 picoseconds. - Weight::from_parts(4_084_000, 0) + // Minimum execution time: 3_728_000 picoseconds. + Weight::from_parts(3_914_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } pub fn burn_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_196_000 picoseconds. - Weight::from_parts(3_285_000, 0) + // Minimum execution time: 3_054_000 picoseconds. + Weight::from_parts(3_140_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_040_000 picoseconds. - Weight::from_parts(2_162_000, 0) + // Minimum execution time: 1_996_000 picoseconds. + Weight::from_parts(2_148_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_980_000 picoseconds. - Weight::from_parts(2_082_000, 0) + // Minimum execution time: 2_008_000 picoseconds. + Weight::from_parts(2_077_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_890_000 picoseconds. - Weight::from_parts(1_971_000, 0) + // Minimum execution time: 1_837_000 picoseconds. + Weight::from_parts(1_913_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_131_000 picoseconds. - Weight::from_parts(2_187_000, 0) + // Minimum execution time: 2_052_000 picoseconds. + Weight::from_parts(2_120_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -268,10 +268,10 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn query_pallet() -> Weight { // Proof Size summary in bytes: - // Measured: `171` + // Measured: `208` // Estimated: `6196` - // Minimum execution time: 59_548_000 picoseconds. - Weight::from_parts(60_842_000, 6196) + // Minimum execution time: 58_725_000 picoseconds. + Weight::from_parts(60_271_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -279,8 +279,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_665_000 picoseconds. - Weight::from_parts(4_844_000, 0) + // Minimum execution time: 4_570_000 picoseconds. + Weight::from_parts(4_707_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -300,10 +300,10 @@ impl WeightInfo { // Proof: `ParachainSystem::PendingUpwardMessages` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) pub fn report_transact_status() -> Weight { // Proof Size summary in bytes: - // Measured: `171` + // Measured: `208` // Estimated: `6196` - // Minimum execution time: 55_044_000 picoseconds. - Weight::from_parts(56_103_000, 6196) + // Minimum execution time: 54_903_000 picoseconds. + Weight::from_parts(55_711_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -311,29 +311,27 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_904_000 picoseconds. - Weight::from_parts(1_984_000, 0) + // Minimum execution time: 1_872_000 picoseconds. + Weight::from_parts(1_938_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_889_000 picoseconds. - Weight::from_parts(1_950_000, 0) + // Minimum execution time: 1_836_000 picoseconds. + Weight::from_parts(1_903_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_878_000 picoseconds. - Weight::from_parts(1_963_000, 0) + // Minimum execution time: 1_847_000 picoseconds. + Weight::from_parts(1_900_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) // Storage: `PolkadotXcm::SupportedVersion` (r:2 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - // Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - // Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) // Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) // Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) // Storage: `BridgeRococoMessages::OutboundLanes` (r:1 w:1) @@ -345,27 +343,27 @@ impl WeightInfo { /// The range of component `x` is `[1, 1000]`. pub fn export_message(x: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `188` - // Estimated: `6128` - // Minimum execution time: 36_960_000 picoseconds. - Weight::from_parts(38_104_333, 6128) - // Standard Error: 510 - .saturating_add(Weight::from_parts(316_499, 0).saturating_mul(x.into())) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(3)) + // Measured: `225` + // Estimated: `6165` + // Minimum execution time: 41_750_000 picoseconds. + Weight::from_parts(43_496_915, 6165) + // Standard Error: 623 + .saturating_add(Weight::from_parts(457_907, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(2)) } pub fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_833_000 picoseconds. - Weight::from_parts(1_950_000, 0) + // Minimum execution time: 1_826_000 picoseconds. + Weight::from_parts(1_911_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_980_000 picoseconds. - Weight::from_parts(2_065_000, 0) + // Minimum execution time: 1_967_000 picoseconds. + Weight::from_parts(2_096_000, 0) } } -- GitLab From be8e626806eafa8aa5b980d387bb0086d80accc2 Mon Sep 17 00:00:00 2001 From: Squirrel Date: Wed, 13 Dec 2023 14:11:07 +0000 Subject: [PATCH 55/59] Set clippy lints in workspace (requires rust 1.74) (#2390) We currently use a bit of a hack in `.cargo/config` to make sure that clippy isn't too annoying by specifying the list of lints. There is now a stable way to define lints for a workspace. The only down side is that every crate seems to have to opt into this so there's a *few* files modified in this PR. Dependencies: - [x] PR that upgrades CI to use rust 1.74 is merged. --------- Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Co-authored-by: Branislav Kontur Co-authored-by: Liam Aharon --- .cargo/config.toml | 34 ------------------- .config/taplo.toml | 2 +- .gitlab/pipeline/check.yml | 4 ++- Cargo.toml | 28 +++++++++++++++ bridges/bin/runtime-common/Cargo.toml | 3 ++ bridges/modules/grandpa/Cargo.toml | 3 ++ bridges/modules/messages/Cargo.toml | 3 ++ bridges/modules/parachains/Cargo.toml | 3 ++ bridges/modules/relayers/Cargo.toml | 3 ++ .../modules/xcm-bridge-hub-router/Cargo.toml | 3 ++ bridges/modules/xcm-bridge-hub/Cargo.toml | 3 ++ .../chain-asset-hub-rococo/Cargo.toml | 3 ++ .../chain-asset-hub-westend/Cargo.toml | 3 ++ .../chain-bridge-hub-cumulus/Cargo.toml | 3 ++ .../chain-bridge-hub-kusama/Cargo.toml | 3 ++ .../chain-bridge-hub-polkadot/Cargo.toml | 3 ++ .../chain-bridge-hub-rococo/Cargo.toml | 3 ++ .../chain-bridge-hub-westend/Cargo.toml | 3 ++ bridges/primitives/chain-kusama/Cargo.toml | 3 ++ .../chain-polkadot-bulletin/Cargo.toml | 3 ++ bridges/primitives/chain-polkadot/Cargo.toml | 3 ++ bridges/primitives/chain-rococo/Cargo.toml | 3 ++ bridges/primitives/chain-westend/Cargo.toml | 3 ++ bridges/primitives/header-chain/Cargo.toml | 3 ++ bridges/primitives/messages/Cargo.toml | 3 ++ bridges/primitives/parachains/Cargo.toml | 3 ++ bridges/primitives/polkadot-core/Cargo.toml | 3 ++ bridges/primitives/relayers/Cargo.toml | 3 ++ bridges/primitives/runtime/Cargo.toml | 3 ++ bridges/primitives/test-utils/Cargo.toml | 3 ++ .../xcm-bridge-hub-router/Cargo.toml | 3 ++ bridges/primitives/xcm-bridge-hub/Cargo.toml | 3 ++ cumulus/client/cli/Cargo.toml | 3 ++ cumulus/client/collator/Cargo.toml | 3 ++ cumulus/client/consensus/aura/Cargo.toml | 3 ++ cumulus/client/consensus/common/Cargo.toml | 3 ++ cumulus/client/consensus/proposer/Cargo.toml | 3 ++ .../client/consensus/relay-chain/Cargo.toml | 3 ++ cumulus/client/network/Cargo.toml | 3 ++ cumulus/client/pov-recovery/Cargo.toml | 3 ++ .../Cargo.toml | 3 ++ .../client/relay-chain-interface/Cargo.toml | 3 ++ .../relay-chain-minimal-node/Cargo.toml | 3 ++ .../relay-chain-rpc-interface/Cargo.toml | 2 ++ cumulus/client/service/Cargo.toml | 3 ++ cumulus/pallets/aura-ext/Cargo.toml | 3 ++ cumulus/pallets/collator-selection/Cargo.toml | 3 ++ cumulus/pallets/dmp-queue/Cargo.toml | 3 ++ cumulus/pallets/parachain-system/Cargo.toml | 3 ++ .../parachain-system/proc-macro/Cargo.toml | 3 ++ .../pallets/session-benchmarking/Cargo.toml | 3 ++ cumulus/pallets/solo-to-para/Cargo.toml | 3 ++ cumulus/pallets/xcm/Cargo.toml | 3 ++ cumulus/pallets/xcmp-queue/Cargo.toml | 3 ++ cumulus/parachain-template/node/Cargo.toml | 3 ++ .../pallets/template/Cargo.toml | 3 ++ cumulus/parachain-template/runtime/Cargo.toml | 3 ++ cumulus/parachains/common/Cargo.toml | 3 ++ .../assets/asset-hub-rococo/Cargo.toml | 3 ++ .../assets/asset-hub-westend/Cargo.toml | 3 ++ .../bridges/bridge-hub-rococo/Cargo.toml | 3 ++ .../bridges/bridge-hub-westend/Cargo.toml | 3 ++ .../collectives-westend/Cargo.toml | 3 ++ .../parachains/testing/penpal/Cargo.toml | 3 ++ .../emulated/chains/relays/rococo/Cargo.toml | 3 ++ .../emulated/chains/relays/westend/Cargo.toml | 3 ++ .../emulated/common/Cargo.toml | 3 ++ .../networks/rococo-system/Cargo.toml | 3 ++ .../networks/rococo-westend-system/Cargo.toml | 3 ++ .../networks/westend-system/Cargo.toml | 3 ++ .../tests/assets/asset-hub-rococo/Cargo.toml | 3 ++ .../tests/assets/asset-hub-westend/Cargo.toml | 3 ++ .../bridges/bridge-hub-rococo/Cargo.toml | 3 ++ .../bridges/bridge-hub-westend/Cargo.toml | 3 ++ .../pallets/collective-content/Cargo.toml | 3 ++ .../pallets/parachain-info/Cargo.toml | 3 ++ cumulus/parachains/pallets/ping/Cargo.toml | 3 ++ .../assets/asset-hub-rococo/Cargo.toml | 3 ++ .../assets/asset-hub-westend/Cargo.toml | 3 ++ .../runtimes/assets/common/Cargo.toml | 3 ++ .../runtimes/assets/test-utils/Cargo.toml | 3 ++ .../bridge-hubs/bridge-hub-rococo/Cargo.toml | 3 ++ .../bridge-hubs/bridge-hub-westend/Cargo.toml | 3 ++ .../bridge-hubs/test-utils/Cargo.toml | 3 ++ .../collectives-westend/Cargo.toml | 3 ++ .../contracts/contracts-rococo/Cargo.toml | 3 ++ .../glutton/glutton-westend/Cargo.toml | 3 ++ .../runtimes/starters/seedling/Cargo.toml | 3 ++ .../runtimes/starters/shell/Cargo.toml | 3 ++ .../parachains/runtimes/test-utils/Cargo.toml | 3 ++ .../runtimes/testing/penpal/Cargo.toml | 3 ++ .../testing/rococo-parachain/Cargo.toml | 3 ++ cumulus/polkadot-parachain/Cargo.toml | 3 ++ cumulus/primitives/aura/Cargo.toml | 3 ++ cumulus/primitives/core/Cargo.toml | 3 ++ .../primitives/parachain-inherent/Cargo.toml | 3 ++ .../proof-size-hostfunction/Cargo.toml | 3 ++ cumulus/primitives/timestamp/Cargo.toml | 3 ++ cumulus/primitives/utility/Cargo.toml | 3 ++ cumulus/test/client/Cargo.toml | 3 ++ cumulus/test/relay-sproof-builder/Cargo.toml | 3 ++ cumulus/test/runtime/Cargo.toml | 3 ++ cumulus/test/service/Cargo.toml | 3 ++ cumulus/xcm/xcm-emulator/Cargo.toml | 3 ++ docs/sdk/Cargo.toml | 3 ++ polkadot/Cargo.toml | 3 ++ polkadot/cli/Cargo.toml | 3 ++ polkadot/core-primitives/Cargo.toml | 3 ++ polkadot/erasure-coding/Cargo.toml | 3 ++ polkadot/erasure-coding/fuzzer/Cargo.toml | 3 ++ polkadot/node/collation-generation/Cargo.toml | 3 ++ polkadot/node/core/approval-voting/Cargo.toml | 3 ++ polkadot/node/core/av-store/Cargo.toml | 3 ++ polkadot/node/core/backing/Cargo.toml | 3 ++ .../node/core/bitfield-signing/Cargo.toml | 3 ++ .../node/core/candidate-validation/Cargo.toml | 3 ++ polkadot/node/core/chain-api/Cargo.toml | 3 ++ polkadot/node/core/chain-selection/Cargo.toml | 3 ++ .../node/core/dispute-coordinator/Cargo.toml | 3 ++ .../node/core/parachains-inherent/Cargo.toml | 3 ++ .../core/prospective-parachains/Cargo.toml | 3 ++ polkadot/node/core/provisioner/Cargo.toml | 3 ++ polkadot/node/core/pvf-checker/Cargo.toml | 3 ++ polkadot/node/core/pvf/Cargo.toml | 3 ++ .../benches/host_prepare_rococo_runtime.rs | 3 +- polkadot/node/core/pvf/common/Cargo.toml | 3 ++ .../node/core/pvf/execute-worker/Cargo.toml | 3 ++ .../node/core/pvf/prepare-worker/Cargo.toml | 3 ++ polkadot/node/core/runtime-api/Cargo.toml | 3 ++ polkadot/node/gum/Cargo.toml | 3 ++ polkadot/node/gum/proc-macro/Cargo.toml | 3 ++ polkadot/node/jaeger/Cargo.toml | 3 ++ polkadot/node/malus/Cargo.toml | 3 ++ polkadot/node/metrics/Cargo.toml | 3 ++ .../network/approval-distribution/Cargo.toml | 3 ++ .../availability-distribution/Cargo.toml | 3 ++ .../network/availability-recovery/Cargo.toml | 3 ++ .../network/bitfield-distribution/Cargo.toml | 3 ++ polkadot/node/network/bridge/Cargo.toml | 3 ++ .../node/network/collator-protocol/Cargo.toml | 3 ++ .../network/dispute-distribution/Cargo.toml | 3 ++ .../node/network/gossip-support/Cargo.toml | 3 ++ polkadot/node/network/protocol/Cargo.toml | 3 ++ .../network/statement-distribution/Cargo.toml | 3 ++ polkadot/node/overseer/Cargo.toml | 3 ++ polkadot/node/primitives/Cargo.toml | 3 ++ polkadot/node/service/Cargo.toml | 3 ++ .../node/subsystem-test-helpers/Cargo.toml | 3 ++ polkadot/node/subsystem-types/Cargo.toml | 3 ++ polkadot/node/subsystem-util/Cargo.toml | 3 ++ polkadot/node/subsystem/Cargo.toml | 3 ++ polkadot/node/test/client/Cargo.toml | 3 ++ polkadot/node/test/service/Cargo.toml | 3 ++ polkadot/node/tracking-allocator/Cargo.toml | 3 ++ .../node/zombienet-backchannel/Cargo.toml | 3 ++ polkadot/parachain/Cargo.toml | 3 ++ polkadot/parachain/test-parachains/Cargo.toml | 3 ++ .../test-parachains/adder/Cargo.toml | 3 ++ .../test-parachains/adder/collator/Cargo.toml | 3 ++ .../parachain/test-parachains/halt/Cargo.toml | 3 ++ .../test-parachains/undying/Cargo.toml | 3 ++ .../undying/collator/Cargo.toml | 3 ++ polkadot/primitives/Cargo.toml | 3 ++ polkadot/primitives/test-helpers/Cargo.toml | 3 ++ polkadot/rpc/Cargo.toml | 3 ++ polkadot/runtime/common/Cargo.toml | 3 ++ .../common/slot_range_helper/Cargo.toml | 3 ++ polkadot/runtime/metrics/Cargo.toml | 3 ++ polkadot/runtime/parachains/Cargo.toml | 3 ++ polkadot/runtime/rococo/Cargo.toml | 3 ++ polkadot/runtime/rococo/constants/Cargo.toml | 3 ++ polkadot/runtime/test-runtime/Cargo.toml | 3 ++ .../runtime/test-runtime/constants/Cargo.toml | 3 ++ polkadot/runtime/westend/Cargo.toml | 3 ++ polkadot/runtime/westend/constants/Cargo.toml | 3 ++ polkadot/statement-table/Cargo.toml | 3 ++ polkadot/utils/generate-bags/Cargo.toml | 3 ++ .../remote-ext-tests/bags-list/Cargo.toml | 3 ++ polkadot/xcm/Cargo.toml | 3 ++ polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml | 3 ++ polkadot/xcm/pallet-xcm/Cargo.toml | 3 ++ polkadot/xcm/procedural/Cargo.toml | 3 ++ polkadot/xcm/xcm-builder/Cargo.toml | 3 ++ polkadot/xcm/xcm-executor/Cargo.toml | 3 ++ .../xcm-executor/integration-tests/Cargo.toml | 3 ++ polkadot/xcm/xcm-simulator/Cargo.toml | 3 ++ polkadot/xcm/xcm-simulator/example/Cargo.toml | 3 ++ polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml | 3 ++ substrate/bin/minimal/node/Cargo.toml | 3 ++ substrate/bin/minimal/runtime/Cargo.toml | 3 ++ substrate/bin/node-template/node/Cargo.toml | 3 ++ .../node-template/pallets/template/Cargo.toml | 3 ++ .../bin/node-template/runtime/Cargo.toml | 3 ++ substrate/bin/node/bench/Cargo.toml | 3 ++ substrate/bin/node/cli/Cargo.toml | 3 ++ substrate/bin/node/inspect/Cargo.toml | 3 ++ substrate/bin/node/primitives/Cargo.toml | 3 ++ substrate/bin/node/rpc/Cargo.toml | 3 ++ substrate/bin/node/runtime/Cargo.toml | 3 ++ substrate/bin/node/testing/Cargo.toml | 3 ++ .../bin/utils/chain-spec-builder/Cargo.toml | 3 ++ substrate/bin/utils/subkey/Cargo.toml | 3 ++ substrate/client/allocator/Cargo.toml | 3 ++ substrate/client/api/Cargo.toml | 3 ++ .../client/authority-discovery/Cargo.toml | 3 ++ substrate/client/basic-authorship/Cargo.toml | 3 ++ substrate/client/block-builder/Cargo.toml | 3 ++ substrate/client/chain-spec/Cargo.toml | 3 ++ substrate/client/chain-spec/derive/Cargo.toml | 3 ++ substrate/client/cli/Cargo.toml | 3 ++ substrate/client/consensus/aura/Cargo.toml | 3 ++ substrate/client/consensus/babe/Cargo.toml | 3 ++ .../client/consensus/babe/rpc/Cargo.toml | 3 ++ substrate/client/consensus/beefy/Cargo.toml | 3 ++ .../client/consensus/beefy/rpc/Cargo.toml | 3 ++ substrate/client/consensus/common/Cargo.toml | 3 ++ substrate/client/consensus/epochs/Cargo.toml | 3 ++ substrate/client/consensus/grandpa/Cargo.toml | 3 ++ .../client/consensus/grandpa/rpc/Cargo.toml | 3 ++ .../client/consensus/manual-seal/Cargo.toml | 3 ++ substrate/client/consensus/pow/Cargo.toml | 3 ++ substrate/client/consensus/slots/Cargo.toml | 3 ++ substrate/client/db/Cargo.toml | 3 ++ substrate/client/executor/Cargo.toml | 3 ++ substrate/client/executor/common/Cargo.toml | 3 ++ .../client/executor/runtime-test/Cargo.toml | 3 ++ substrate/client/executor/wasmtime/Cargo.toml | 3 ++ substrate/client/informant/Cargo.toml | 3 ++ substrate/client/keystore/Cargo.toml | 3 ++ .../client/merkle-mountain-range/Cargo.toml | 3 ++ .../merkle-mountain-range/rpc/Cargo.toml | 3 ++ substrate/client/mixnet/Cargo.toml | 3 ++ substrate/client/network-gossip/Cargo.toml | 3 ++ substrate/client/network/Cargo.toml | 3 ++ substrate/client/network/bitswap/Cargo.toml | 3 ++ substrate/client/network/common/Cargo.toml | 3 ++ substrate/client/network/light/Cargo.toml | 3 ++ substrate/client/network/statement/Cargo.toml | 3 ++ substrate/client/network/sync/Cargo.toml | 3 ++ substrate/client/network/test/Cargo.toml | 3 ++ .../client/network/transactions/Cargo.toml | 3 ++ substrate/client/offchain/Cargo.toml | 3 ++ substrate/client/proposer-metrics/Cargo.toml | 3 ++ substrate/client/rpc-api/Cargo.toml | 3 ++ substrate/client/rpc-servers/Cargo.toml | 3 ++ substrate/client/rpc-spec-v2/Cargo.toml | 3 ++ substrate/client/rpc/Cargo.toml | 3 ++ substrate/client/service/Cargo.toml | 3 ++ substrate/client/service/test/Cargo.toml | 3 ++ substrate/client/state-db/Cargo.toml | 3 ++ substrate/client/statement-store/Cargo.toml | 3 ++ substrate/client/storage-monitor/Cargo.toml | 3 ++ substrate/client/sync-state-rpc/Cargo.toml | 3 ++ substrate/client/sysinfo/Cargo.toml | 3 ++ substrate/client/telemetry/Cargo.toml | 3 ++ substrate/client/tracing/Cargo.toml | 3 ++ .../client/tracing/proc-macro/Cargo.toml | 3 ++ substrate/client/transaction-pool/Cargo.toml | 3 ++ .../client/transaction-pool/api/Cargo.toml | 3 ++ substrate/client/utils/Cargo.toml | 3 ++ substrate/frame/Cargo.toml | 3 ++ substrate/frame/alliance/Cargo.toml | 3 ++ substrate/frame/asset-conversion/Cargo.toml | 3 ++ substrate/frame/asset-rate/Cargo.toml | 3 ++ substrate/frame/assets/Cargo.toml | 3 ++ substrate/frame/atomic-swap/Cargo.toml | 3 ++ substrate/frame/aura/Cargo.toml | 3 ++ .../frame/authority-discovery/Cargo.toml | 3 ++ substrate/frame/authorship/Cargo.toml | 3 ++ substrate/frame/babe/Cargo.toml | 3 ++ substrate/frame/bags-list/Cargo.toml | 3 ++ substrate/frame/bags-list/fuzzer/Cargo.toml | 3 ++ .../frame/bags-list/remote-tests/Cargo.toml | 3 ++ substrate/frame/balances/Cargo.toml | 3 ++ substrate/frame/beefy-mmr/Cargo.toml | 3 ++ substrate/frame/beefy/Cargo.toml | 3 ++ substrate/frame/benchmarking/Cargo.toml | 3 ++ substrate/frame/benchmarking/pov/Cargo.toml | 3 ++ substrate/frame/bounties/Cargo.toml | 3 ++ substrate/frame/broker/Cargo.toml | 3 ++ substrate/frame/child-bounties/Cargo.toml | 3 ++ substrate/frame/collective/Cargo.toml | 3 ++ substrate/frame/contracts/Cargo.toml | 3 ++ substrate/frame/contracts/fixtures/Cargo.toml | 3 ++ .../fixtures/contracts/common/Cargo.toml | 3 ++ .../frame/contracts/mock-network/Cargo.toml | 3 ++ .../frame/contracts/primitives/Cargo.toml | 3 ++ .../frame/contracts/proc-macro/Cargo.toml | 3 ++ substrate/frame/contracts/uapi/Cargo.toml | 3 ++ substrate/frame/conviction-voting/Cargo.toml | 3 ++ substrate/frame/core-fellowship/Cargo.toml | 3 ++ substrate/frame/democracy/Cargo.toml | 3 ++ .../election-provider-multi-phase/Cargo.toml | 3 ++ .../test-staking-e2e/Cargo.toml | 3 ++ .../election-provider-support/Cargo.toml | 3 ++ .../benchmarking/Cargo.toml | 3 ++ .../solution-type/Cargo.toml | 3 ++ .../solution-type/fuzzer/Cargo.toml | 3 ++ substrate/frame/elections-phragmen/Cargo.toml | 3 ++ substrate/frame/examples/Cargo.toml | 3 ++ substrate/frame/examples/basic/Cargo.toml | 3 ++ .../frame/examples/default-config/Cargo.toml | 3 ++ substrate/frame/examples/dev-mode/Cargo.toml | 3 ++ .../frame/examples/frame-crate/Cargo.toml | 3 ++ .../frame/examples/kitchensink/Cargo.toml | 3 ++ .../frame/examples/offchain-worker/Cargo.toml | 3 ++ substrate/frame/examples/split/Cargo.toml | 3 ++ substrate/frame/examples/tasks/Cargo.toml | 3 ++ substrate/frame/executive/Cargo.toml | 3 ++ substrate/frame/fast-unstake/Cargo.toml | 3 ++ substrate/frame/glutton/Cargo.toml | 3 ++ substrate/frame/grandpa/Cargo.toml | 3 ++ substrate/frame/identity/Cargo.toml | 3 ++ substrate/frame/im-online/Cargo.toml | 3 ++ substrate/frame/indices/Cargo.toml | 3 ++ .../Cargo.toml | 3 ++ substrate/frame/lottery/Cargo.toml | 3 ++ substrate/frame/membership/Cargo.toml | 3 ++ .../frame/merkle-mountain-range/Cargo.toml | 3 ++ substrate/frame/message-queue/Cargo.toml | 3 ++ substrate/frame/mixnet/Cargo.toml | 3 ++ substrate/frame/multisig/Cargo.toml | 3 ++ .../frame/nft-fractionalization/Cargo.toml | 3 ++ substrate/frame/nfts/Cargo.toml | 3 ++ substrate/frame/nfts/runtime-api/Cargo.toml | 3 ++ substrate/frame/nicks/Cargo.toml | 3 ++ substrate/frame/nis/Cargo.toml | 3 ++ substrate/frame/node-authorization/Cargo.toml | 3 ++ substrate/frame/nomination-pools/Cargo.toml | 3 ++ .../nomination-pools/benchmarking/Cargo.toml | 3 ++ .../frame/nomination-pools/fuzzer/Cargo.toml | 3 ++ .../nomination-pools/runtime-api/Cargo.toml | 3 ++ .../nomination-pools/test-staking/Cargo.toml | 3 ++ substrate/frame/offences/Cargo.toml | 3 ++ .../frame/offences/benchmarking/Cargo.toml | 3 ++ substrate/frame/paged-list/Cargo.toml | 3 ++ substrate/frame/paged-list/fuzzer/Cargo.toml | 3 ++ substrate/frame/preimage/Cargo.toml | 3 ++ substrate/frame/proxy/Cargo.toml | 3 ++ substrate/frame/ranked-collective/Cargo.toml | 3 ++ substrate/frame/recovery/Cargo.toml | 3 ++ substrate/frame/referenda/Cargo.toml | 3 ++ substrate/frame/remark/Cargo.toml | 3 ++ substrate/frame/root-offences/Cargo.toml | 3 ++ substrate/frame/root-testing/Cargo.toml | 3 ++ substrate/frame/safe-mode/Cargo.toml | 3 ++ substrate/frame/salary/Cargo.toml | 3 ++ substrate/frame/sassafras/Cargo.toml | 3 ++ substrate/frame/scheduler/Cargo.toml | 3 ++ substrate/frame/scored-pool/Cargo.toml | 3 ++ substrate/frame/session/Cargo.toml | 3 ++ .../frame/session/benchmarking/Cargo.toml | 3 ++ substrate/frame/society/Cargo.toml | 3 ++ substrate/frame/staking/Cargo.toml | 3 ++ .../frame/staking/reward-curve/Cargo.toml | 3 ++ substrate/frame/staking/reward-fn/Cargo.toml | 3 ++ .../frame/staking/runtime-api/Cargo.toml | 3 ++ .../frame/state-trie-migration/Cargo.toml | 3 ++ substrate/frame/statement/Cargo.toml | 3 ++ substrate/frame/sudo/Cargo.toml | 3 ++ substrate/frame/support/Cargo.toml | 3 ++ substrate/frame/support/procedural/Cargo.toml | 3 ++ .../frame/support/procedural/tools/Cargo.toml | 3 ++ .../procedural/tools/derive/Cargo.toml | 3 ++ substrate/frame/support/test/Cargo.toml | 3 ++ .../support/test/compile_pass/Cargo.toml | 3 ++ .../frame/support/test/pallet/Cargo.toml | 3 ++ .../support/test/stg_frame_crate/Cargo.toml | 3 ++ substrate/frame/system/Cargo.toml | 3 ++ .../frame/system/benchmarking/Cargo.toml | 3 ++ .../frame/system/rpc/runtime-api/Cargo.toml | 3 ++ substrate/frame/timestamp/Cargo.toml | 3 ++ substrate/frame/tips/Cargo.toml | 3 ++ .../frame/transaction-payment/Cargo.toml | 3 ++ .../asset-conversion-tx-payment/Cargo.toml | 3 ++ .../asset-tx-payment/Cargo.toml | 3 ++ .../frame/transaction-payment/rpc/Cargo.toml | 3 ++ .../rpc/runtime-api/Cargo.toml | 3 ++ .../skip-feeless-payment/Cargo.toml | 3 ++ .../frame/transaction-storage/Cargo.toml | 3 ++ substrate/frame/treasury/Cargo.toml | 3 ++ substrate/frame/try-runtime/Cargo.toml | 3 ++ substrate/frame/tx-pause/Cargo.toml | 3 ++ substrate/frame/uniques/Cargo.toml | 3 ++ substrate/frame/utility/Cargo.toml | 3 ++ substrate/frame/vesting/Cargo.toml | 3 ++ substrate/frame/whitelist/Cargo.toml | 3 ++ substrate/primitives/api/Cargo.toml | 3 ++ .../primitives/api/proc-macro/Cargo.toml | 3 ++ substrate/primitives/api/test/Cargo.toml | 3 ++ .../primitives/application-crypto/Cargo.toml | 3 ++ .../application-crypto/test/Cargo.toml | 3 ++ substrate/primitives/arithmetic/Cargo.toml | 3 ++ .../primitives/arithmetic/fuzzer/Cargo.toml | 3 ++ .../primitives/authority-discovery/Cargo.toml | 3 ++ substrate/primitives/block-builder/Cargo.toml | 3 ++ substrate/primitives/blockchain/Cargo.toml | 3 ++ .../primitives/consensus/aura/Cargo.toml | 3 ++ .../primitives/consensus/babe/Cargo.toml | 3 ++ .../primitives/consensus/beefy/Cargo.toml | 3 ++ .../primitives/consensus/common/Cargo.toml | 3 ++ .../primitives/consensus/grandpa/Cargo.toml | 3 ++ substrate/primitives/consensus/pow/Cargo.toml | 3 ++ .../primitives/consensus/sassafras/Cargo.toml | 3 ++ .../primitives/consensus/slots/Cargo.toml | 3 ++ substrate/primitives/core/Cargo.toml | 3 ++ substrate/primitives/core/fuzz/Cargo.toml | 3 ++ substrate/primitives/core/hashing/Cargo.toml | 3 ++ .../core/hashing/proc-macro/Cargo.toml | 3 ++ .../primitives/crypto/ec-utils/Cargo.toml | 3 ++ substrate/primitives/database/Cargo.toml | 3 ++ substrate/primitives/debug-derive/Cargo.toml | 2 ++ substrate/primitives/externalities/Cargo.toml | 3 ++ .../primitives/genesis-builder/Cargo.toml | 3 ++ substrate/primitives/inherents/Cargo.toml | 3 ++ substrate/primitives/io/Cargo.toml | 3 ++ substrate/primitives/keyring/Cargo.toml | 3 ++ substrate/primitives/keystore/Cargo.toml | 3 ++ .../maybe-compressed-blob/Cargo.toml | 3 ++ .../merkle-mountain-range/Cargo.toml | 3 ++ substrate/primitives/metadata-ir/Cargo.toml | 3 ++ substrate/primitives/mixnet/Cargo.toml | 3 ++ .../primitives/npos-elections/Cargo.toml | 3 ++ .../npos-elections/fuzzer/Cargo.toml | 3 ++ substrate/primitives/offchain/Cargo.toml | 3 ++ substrate/primitives/panic-handler/Cargo.toml | 3 ++ substrate/primitives/rpc/Cargo.toml | 3 ++ .../primitives/runtime-interface/Cargo.toml | 3 ++ .../runtime-interface/proc-macro/Cargo.toml | 3 ++ .../test-wasm-deprecated/Cargo.toml | 3 ++ .../runtime-interface/test-wasm/Cargo.toml | 3 ++ .../runtime-interface/test/Cargo.toml | 3 ++ substrate/primitives/runtime/Cargo.toml | 3 ++ substrate/primitives/session/Cargo.toml | 3 ++ substrate/primitives/staking/Cargo.toml | 3 ++ substrate/primitives/state-machine/Cargo.toml | 3 ++ .../primitives/statement-store/Cargo.toml | 3 ++ substrate/primitives/std/Cargo.toml | 3 ++ substrate/primitives/storage/Cargo.toml | 3 ++ .../primitives/test-primitives/Cargo.toml | 3 ++ substrate/primitives/timestamp/Cargo.toml | 3 ++ substrate/primitives/tracing/Cargo.toml | 3 ++ .../primitives/transaction-pool/Cargo.toml | 3 ++ .../transaction-storage-proof/Cargo.toml | 3 ++ substrate/primitives/trie/Cargo.toml | 3 ++ substrate/primitives/version/Cargo.toml | 3 ++ .../primitives/version/proc-macro/Cargo.toml | 3 ++ .../primitives/wasm-interface/Cargo.toml | 3 ++ substrate/primitives/weights/Cargo.toml | 3 ++ .../ci/node-template-release/Cargo.toml | 3 ++ substrate/test-utils/Cargo.toml | 3 ++ substrate/test-utils/cli/Cargo.toml | 3 ++ substrate/test-utils/client/Cargo.toml | 3 ++ substrate/test-utils/runtime/Cargo.toml | 3 ++ .../test-utils/runtime/client/Cargo.toml | 3 ++ .../runtime/transaction-pool/Cargo.toml | 3 ++ substrate/utils/binary-merkle-tree/Cargo.toml | 3 ++ substrate/utils/build-script-utils/Cargo.toml | 3 ++ substrate/utils/fork-tree/Cargo.toml | 3 ++ .../utils/frame/benchmarking-cli/Cargo.toml | 3 ++ .../frame/frame-utilities-cli/Cargo.toml | 3 ++ .../utils/frame/generate-bags/Cargo.toml | 3 ++ .../generate-bags/node-runtime/Cargo.toml | 3 ++ .../frame/remote-externalities/Cargo.toml | 3 ++ substrate/utils/frame/rpc/client/Cargo.toml | 3 ++ .../rpc/state-trie-migration-rpc/Cargo.toml | 3 ++ substrate/utils/frame/rpc/support/Cargo.toml | 3 ++ substrate/utils/frame/rpc/system/Cargo.toml | 3 ++ .../utils/frame/try-runtime/cli/Cargo.toml | 3 ++ substrate/utils/prometheus/Cargo.toml | 3 ++ substrate/utils/wasm-builder/Cargo.toml | 3 ++ 471 files changed, 1430 insertions(+), 37 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 8bbf7cdb4d9..f113e9114ac 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -4,40 +4,6 @@ rustdocflags = [ "-Arustdoc::redundant_explicit_links", # stylistic ] -# An auto defined `clippy` feature was introduced, -# but it was found to clash with user defined features, -# so was renamed to `cargo-clippy`. -# -# If you want standard clippy run: -# RUSTFLAGS= cargo clippy -[target.'cfg(feature = "cargo-clippy")'] -rustflags = [ - "-Aclippy::all", - "-Dclippy::correctness", - "-Aclippy::if-same-then-else", - "-Asuspicious_double_ref_op", - "-Dclippy::complexity", - "-Aclippy::zero-prefixed-literal", # 00_1000_000 - "-Aclippy::type_complexity", # raison d'etre - "-Aclippy::nonminimal-bool", # maybe - "-Aclippy::borrowed-box", # Reasonable to fix this one - "-Aclippy::too-many-arguments", # (Turning this on would lead to) - "-Aclippy::unnecessary_cast", # Types may change - "-Aclippy::identity-op", # One case where we do 0 + - "-Aclippy::useless_conversion", # Types may change - "-Aclippy::unit_arg", # styalistic. - "-Aclippy::option-map-unit-fn", # styalistic - "-Aclippy::bind_instead_of_map", # styalistic - "-Aclippy::erasing_op", # E.g. 0 * DOLLARS - "-Aclippy::eq_op", # In tests we test equality. - "-Aclippy::while_immutable_condition", # false positives - "-Aclippy::needless_option_as_deref", # false positives - "-Aclippy::derivable_impls", # false positives - "-Aclippy::stable_sort_primitive", # prefer stable sort - "-Aclippy::extra-unused-type-parameters", # stylistic - "-Aclippy::default_constructed_unit_structs", # stylistic -] - [env] # Needed for musl builds so user doesn't have to install musl-tools. CC_x86_64_unknown_linux_musl = { value = ".cargo/musl-gcc", force = true, relative = true } diff --git a/.config/taplo.toml b/.config/taplo.toml index ffe0417e42b..f5d0b7021ba 100644 --- a/.config/taplo.toml +++ b/.config/taplo.toml @@ -27,7 +27,7 @@ reorder_arrays = false # don't re-order order-dependent rustflags [[rule]] include = [".cargo/config.toml"] -keys = ["build", "target.'cfg(feature = \"cargo-clippy\")'"] +keys = ["build"] [rule.formatting] reorder_arrays = false diff --git a/.gitlab/pipeline/check.yml b/.gitlab/pipeline/check.yml index 7d98b9cc71c..3b14034a110 100644 --- a/.gitlab/pipeline/check.yml +++ b/.gitlab/pipeline/check.yml @@ -4,8 +4,10 @@ cargo-clippy: - .docker-env - .common-refs - .pipeline-stopper-artifacts + variables: + RUSTFLAGS: "-D warnings" script: - - SKIP_WASM_BUILD=1 env -u RUSTFLAGS cargo clippy --all-targets --locked --workspace + - SKIP_WASM_BUILD=1 cargo clippy --all-targets --locked --workspace check-try-runtime: stage: check diff --git a/Cargo.toml b/Cargo.toml index 1c791b6118f..0091c2d7c8b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -476,6 +476,34 @@ members = [ ] default-members = ["polkadot", "substrate/bin/node/cli"] +[workspace.lints.rust] +suspicious_double_ref_op = { level = "allow", priority = 2 } + +[workspace.lints.clippy] +all = { level = "allow", priority = 0 } +correctness = { level = "deny", priority = 1 } +if-same-then-else = { level = "allow", priority = 2 } +complexity = { level = "deny", priority = 1 } +zero-prefixed-literal = { level = "allow", priority = 2 } # 00_1000_000 +type_complexity = { level = "allow", priority = 2 } # raison d'etre +nonminimal-bool = { level = "allow", priority = 2 } # maybe +borrowed-box = { level = "allow", priority = 2 } # Reasonable to fix this one +too-many-arguments = { level = "allow", priority = 2 } # (Turning this on would lead to) +unnecessary_cast = { level = "allow", priority = 2 } # Types may change +identity-op = { level = "allow", priority = 2 } # One case where we do 0 + +useless_conversion = { level = "allow", priority = 2 } # Types may change +unit_arg = { level = "allow", priority = 2 } # styalistic. +option-map-unit-fn = { level = "allow", priority = 2 } # styalistic +bind_instead_of_map = { level = "allow", priority = 2 } # styalistic +erasing_op = { level = "allow", priority = 2 } # E.g. 0 * DOLLARS +eq_op = { level = "allow", priority = 2 } # In tests we test equality. +while_immutable_condition = { level = "allow", priority = 2 } # false positives +needless_option_as_deref = { level = "allow", priority = 2 } # false positives +derivable_impls = { level = "allow", priority = 2 } # false positives +stable_sort_primitive = { level = "allow", priority = 2 } # prefer stable sort +extra-unused-type-parameters = { level = "allow", priority = 2 } # stylistic +default_constructed_unit_structs = { level = "allow", priority = 2 } # stylistic + [profile.release] # Polkadot runtime requires unwinding. panic = "unwind" diff --git a/bridges/bin/runtime-common/Cargo.toml b/bridges/bin/runtime-common/Cargo.toml index bac54a0a7a2..8c3e8c989db 100644 --- a/bridges/bin/runtime-common/Cargo.toml +++ b/bridges/bin/runtime-common/Cargo.toml @@ -7,6 +7,9 @@ edition.workspace = true repository.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } hash-db = { version = "0.16.0", default-features = false } diff --git a/bridges/modules/grandpa/Cargo.toml b/bridges/modules/grandpa/Cargo.toml index 573edbf5a65..e346f2061e2 100644 --- a/bridges/modules/grandpa/Cargo.toml +++ b/bridges/modules/grandpa/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] diff --git a/bridges/modules/messages/Cargo.toml b/bridges/modules/messages/Cargo.toml index 751ef45168d..4d9371448df 100644 --- a/bridges/modules/messages/Cargo.toml +++ b/bridges/modules/messages/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } log = { version = "0.4.20", default-features = false } diff --git a/bridges/modules/parachains/Cargo.toml b/bridges/modules/parachains/Cargo.toml index 4af8997c5f3..77a5366c78d 100644 --- a/bridges/modules/parachains/Cargo.toml +++ b/bridges/modules/parachains/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } log = { version = "0.4.20", default-features = false } diff --git a/bridges/modules/relayers/Cargo.toml b/bridges/modules/relayers/Cargo.toml index 3011a11db5c..8c8305ef64c 100644 --- a/bridges/modules/relayers/Cargo.toml +++ b/bridges/modules/relayers/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } log = { version = "0.4.20", default-features = false } diff --git a/bridges/modules/xcm-bridge-hub-router/Cargo.toml b/bridges/modules/xcm-bridge-hub-router/Cargo.toml index e4d25fae9d3..1d84f723ee9 100644 --- a/bridges/modules/xcm-bridge-hub-router/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub-router/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } log = { version = "0.4.20", default-features = false } diff --git a/bridges/modules/xcm-bridge-hub/Cargo.toml b/bridges/modules/xcm-bridge-hub/Cargo.toml index 03ef18170ae..061d4b7ced8 100644 --- a/bridges/modules/xcm-bridge-hub/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } log = { version = "0.4.20", default-features = false } diff --git a/bridges/primitives/chain-asset-hub-rococo/Cargo.toml b/bridges/primitives/chain-asset-hub-rococo/Cargo.toml index 889475840b3..d5f724e581f 100644 --- a/bridges/primitives/chain-asset-hub-rococo/Cargo.toml +++ b/bridges/primitives/chain-asset-hub-rococo/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } diff --git a/bridges/primitives/chain-asset-hub-westend/Cargo.toml b/bridges/primitives/chain-asset-hub-westend/Cargo.toml index 84b9604a61b..d309e50bfbf 100644 --- a/bridges/primitives/chain-asset-hub-westend/Cargo.toml +++ b/bridges/primitives/chain-asset-hub-westend/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } diff --git a/bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml b/bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml index dab1b065f6f..73aaa53269f 100644 --- a/bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml +++ b/bridges/primitives/chain-bridge-hub-cumulus/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] # Bridge Dependencies diff --git a/bridges/primitives/chain-bridge-hub-kusama/Cargo.toml b/bridges/primitives/chain-bridge-hub-kusama/Cargo.toml index 8e6364101f2..ea09712ae30 100644 --- a/bridges/primitives/chain-bridge-hub-kusama/Cargo.toml +++ b/bridges/primitives/chain-bridge-hub-kusama/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] # Bridge Dependencies diff --git a/bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml b/bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml index 961d4aeb2e2..de208895fb4 100644 --- a/bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml +++ b/bridges/primitives/chain-bridge-hub-polkadot/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] # Bridge Dependencies diff --git a/bridges/primitives/chain-bridge-hub-rococo/Cargo.toml b/bridges/primitives/chain-bridge-hub-rococo/Cargo.toml index 28fe3c283bc..281e1f74261 100644 --- a/bridges/primitives/chain-bridge-hub-rococo/Cargo.toml +++ b/bridges/primitives/chain-bridge-hub-rococo/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] # Bridge Dependencies diff --git a/bridges/primitives/chain-bridge-hub-westend/Cargo.toml b/bridges/primitives/chain-bridge-hub-westend/Cargo.toml index 409f84840a8..beebfa8f1a0 100644 --- a/bridges/primitives/chain-bridge-hub-westend/Cargo.toml +++ b/bridges/primitives/chain-bridge-hub-westend/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] # Bridge Dependencies diff --git a/bridges/primitives/chain-kusama/Cargo.toml b/bridges/primitives/chain-kusama/Cargo.toml index 41570d4f9bc..6ca4f051f1c 100644 --- a/bridges/primitives/chain-kusama/Cargo.toml +++ b/bridges/primitives/chain-kusama/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] # Bridge Dependencies diff --git a/bridges/primitives/chain-polkadot-bulletin/Cargo.toml b/bridges/primitives/chain-polkadot-bulletin/Cargo.toml index 3be056dd0a7..98633847462 100644 --- a/bridges/primitives/chain-polkadot-bulletin/Cargo.toml +++ b/bridges/primitives/chain-polkadot-bulletin/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } diff --git a/bridges/primitives/chain-polkadot/Cargo.toml b/bridges/primitives/chain-polkadot/Cargo.toml index 579e997e0ab..361901b7ae0 100644 --- a/bridges/primitives/chain-polkadot/Cargo.toml +++ b/bridges/primitives/chain-polkadot/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] # Bridge Dependencies diff --git a/bridges/primitives/chain-rococo/Cargo.toml b/bridges/primitives/chain-rococo/Cargo.toml index dc7c482a4cc..d59a00cfd14 100644 --- a/bridges/primitives/chain-rococo/Cargo.toml +++ b/bridges/primitives/chain-rococo/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] # Bridge Dependencies diff --git a/bridges/primitives/chain-westend/Cargo.toml b/bridges/primitives/chain-westend/Cargo.toml index 7c74cb1361b..6b6d2748aff 100644 --- a/bridges/primitives/chain-westend/Cargo.toml +++ b/bridges/primitives/chain-westend/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] # Bridge Dependencies diff --git a/bridges/primitives/header-chain/Cargo.toml b/bridges/primitives/header-chain/Cargo.toml index bc92054e5dc..7338996d69f 100644 --- a/bridges/primitives/header-chain/Cargo.toml +++ b/bridges/primitives/header-chain/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } finality-grandpa = { version = "0.16.2", default-features = false } diff --git a/bridges/primitives/messages/Cargo.toml b/bridges/primitives/messages/Cargo.toml index c2f43523aaf..6333000a71a 100644 --- a/bridges/primitives/messages/Cargo.toml +++ b/bridges/primitives/messages/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["bit-vec", "derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["bit-vec", "derive"] } diff --git a/bridges/primitives/parachains/Cargo.toml b/bridges/primitives/parachains/Cargo.toml index a339203fd66..99b447f6c0a 100644 --- a/bridges/primitives/parachains/Cargo.toml +++ b/bridges/primitives/parachains/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2" diff --git a/bridges/primitives/polkadot-core/Cargo.toml b/bridges/primitives/polkadot-core/Cargo.toml index 67fb9af8b21..80382b3289f 100644 --- a/bridges/primitives/polkadot-core/Cargo.toml +++ b/bridges/primitives/polkadot-core/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } parity-util-mem = { version = "0.12.0", optional = true } diff --git a/bridges/primitives/relayers/Cargo.toml b/bridges/primitives/relayers/Cargo.toml index cf94ca44d00..563d27c91c9 100644 --- a/bridges/primitives/relayers/Cargo.toml +++ b/bridges/primitives/relayers/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["bit-vec", "derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["bit-vec", "derive"] } diff --git a/bridges/primitives/runtime/Cargo.toml b/bridges/primitives/runtime/Cargo.toml index a713f636bb8..779030b5278 100644 --- a/bridges/primitives/runtime/Cargo.toml +++ b/bridges/primitives/runtime/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } hash-db = { version = "0.16.0", default-features = false } diff --git a/bridges/primitives/test-utils/Cargo.toml b/bridges/primitives/test-utils/Cargo.toml index 050c879c6a7..3ccec9d9033 100644 --- a/bridges/primitives/test-utils/Cargo.toml +++ b/bridges/primitives/test-utils/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] bp-header-chain = { path = "../header-chain", default-features = false } bp-parachains = { path = "../parachains", default-features = false } diff --git a/bridges/primitives/xcm-bridge-hub-router/Cargo.toml b/bridges/primitives/xcm-bridge-hub-router/Cargo.toml index 5a49db62fec..fa537bda960 100644 --- a/bridges/primitives/xcm-bridge-hub-router/Cargo.toml +++ b/bridges/primitives/xcm-bridge-hub-router/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["bit-vec", "derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["bit-vec", "derive"] } diff --git a/bridges/primitives/xcm-bridge-hub/Cargo.toml b/bridges/primitives/xcm-bridge-hub/Cargo.toml index 212b7b2642f..f9f44fd0f8d 100644 --- a/bridges/primitives/xcm-bridge-hub/Cargo.toml +++ b/bridges/primitives/xcm-bridge-hub/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] # Substrate Dependencies diff --git a/cumulus/client/cli/Cargo.toml b/cumulus/client/cli/Cargo.toml index af4912e2b2d..e57e7a44a56 100644 --- a/cumulus/client/cli/Cargo.toml +++ b/cumulus/client/cli/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true description = "Parachain node CLI utilities." license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] clap = { version = "4.4.11", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } diff --git a/cumulus/client/collator/Cargo.toml b/cumulus/client/collator/Cargo.toml index 7ac0bbfe6f1..7392934f4c9 100644 --- a/cumulus/client/collator/Cargo.toml +++ b/cumulus/client/collator/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true description = "Common node-side functionality and glue code to collate parachain blocks." license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] parking_lot = "0.12.1" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } diff --git a/cumulus/client/consensus/aura/Cargo.toml b/cumulus/client/consensus/aura/Cargo.toml index e07f10d6090..cd77504a2a2 100644 --- a/cumulus/client/consensus/aura/Cargo.toml +++ b/cumulus/client/consensus/aura/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] async-trait = "0.1.73" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } diff --git a/cumulus/client/consensus/common/Cargo.toml b/cumulus/client/consensus/common/Cargo.toml index 92918cd7b5b..770e5c01e8b 100644 --- a/cumulus/client/consensus/common/Cargo.toml +++ b/cumulus/client/consensus/common/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] async-trait = "0.1.73" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } diff --git a/cumulus/client/consensus/proposer/Cargo.toml b/cumulus/client/consensus/proposer/Cargo.toml index 4cfba66cec3..2006eac5bf1 100644 --- a/cumulus/client/consensus/proposer/Cargo.toml +++ b/cumulus/client/consensus/proposer/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] anyhow = "1.0" async-trait = "0.1.73" diff --git a/cumulus/client/consensus/relay-chain/Cargo.toml b/cumulus/client/consensus/relay-chain/Cargo.toml index de280e6e9a8..76b1c9a422f 100644 --- a/cumulus/client/consensus/relay-chain/Cargo.toml +++ b/cumulus/client/consensus/relay-chain/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] async-trait = "0.1.73" futures = "0.3.28" diff --git a/cumulus/client/network/Cargo.toml b/cumulus/client/network/Cargo.toml index 3893647e7c5..5e0d478f5ac 100644 --- a/cumulus/client/network/Cargo.toml +++ b/cumulus/client/network/Cargo.toml @@ -6,6 +6,9 @@ description = "Cumulus-specific networking protocol" edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] async-trait = "0.1.73" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } diff --git a/cumulus/client/pov-recovery/Cargo.toml b/cumulus/client/pov-recovery/Cargo.toml index 29f793c7328..93d65016530 100644 --- a/cumulus/client/pov-recovery/Cargo.toml +++ b/cumulus/client/pov-recovery/Cargo.toml @@ -6,6 +6,9 @@ description = "Cumulus-specific networking protocol" edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } futures = "0.3.28" diff --git a/cumulus/client/relay-chain-inprocess-interface/Cargo.toml b/cumulus/client/relay-chain-inprocess-interface/Cargo.toml index 1d414736503..15063d09bca 100644 --- a/cumulus/client/relay-chain-inprocess-interface/Cargo.toml +++ b/cumulus/client/relay-chain-inprocess-interface/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true description = "Implementation of the RelayChainInterface trait for Polkadot full-nodes." license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] async-trait = "0.1.73" futures = "0.3.28" diff --git a/cumulus/client/relay-chain-interface/Cargo.toml b/cumulus/client/relay-chain-interface/Cargo.toml index c9d50afe8fa..98893a398fb 100644 --- a/cumulus/client/relay-chain-interface/Cargo.toml +++ b/cumulus/client/relay-chain-interface/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true description = "Common interface for different relay chain datasources." license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] polkadot-overseer = { path = "../../../polkadot/node/overseer" } diff --git a/cumulus/client/relay-chain-minimal-node/Cargo.toml b/cumulus/client/relay-chain-minimal-node/Cargo.toml index acaed5a4f6c..b22731b3a6d 100644 --- a/cumulus/client/relay-chain-minimal-node/Cargo.toml +++ b/cumulus/client/relay-chain-minimal-node/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true description = "Minimal node implementation to be used in tandem with RPC or light-client mode." license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] # polkadot deps polkadot-primitives = { path = "../../../polkadot/primitives" } diff --git a/cumulus/client/relay-chain-rpc-interface/Cargo.toml b/cumulus/client/relay-chain-rpc-interface/Cargo.toml index 11d8bc9b4df..050bea08f0f 100644 --- a/cumulus/client/relay-chain-rpc-interface/Cargo.toml +++ b/cumulus/client/relay-chain-rpc-interface/Cargo.toml @@ -6,6 +6,8 @@ edition.workspace = true description = "Implementation of the RelayChainInterface trait that connects to a remote RPC-node." license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true [dependencies] polkadot-overseer = { path = "../../../polkadot/node/overseer" } diff --git a/cumulus/client/service/Cargo.toml b/cumulus/client/service/Cargo.toml index 55623276eaf..997413ad0da 100644 --- a/cumulus/client/service/Cargo.toml +++ b/cumulus/client/service/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true description = "Common functions used to assemble the components of a parachain node." license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +[lints] +workspace = true + [dependencies] futures = "0.3.28" diff --git a/cumulus/pallets/aura-ext/Cargo.toml b/cumulus/pallets/aura-ext/Cargo.toml index 16f73aa540e..14dcd10ddfc 100644 --- a/cumulus/pallets/aura-ext/Cargo.toml +++ b/cumulus/pallets/aura-ext/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true description = "AURA consensus extension pallet for parachains" license = "Apache-2.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } diff --git a/cumulus/pallets/collator-selection/Cargo.toml b/cumulus/pallets/collator-selection/Cargo.toml index 76efbf1caf6..9c2af8893ca 100644 --- a/cumulus/pallets/collator-selection/Cargo.toml +++ b/cumulus/pallets/collator-selection/Cargo.toml @@ -9,6 +9,9 @@ readme = "README.md" repository.workspace = true version = "3.0.0" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/cumulus/pallets/dmp-queue/Cargo.toml b/cumulus/pallets/dmp-queue/Cargo.toml index 0b64410433f..bdcee0f5ff8 100644 --- a/cumulus/pallets/dmp-queue/Cargo.toml +++ b/cumulus/pallets/dmp-queue/Cargo.toml @@ -7,6 +7,9 @@ repository.workspace = true description = "Migrates messages from the old DMP queue pallet." license = "Apache-2.0" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/cumulus/pallets/parachain-system/Cargo.toml b/cumulus/pallets/parachain-system/Cargo.toml index 187cf21cea6..d24fdfe101e 100644 --- a/cumulus/pallets/parachain-system/Cargo.toml +++ b/cumulus/pallets/parachain-system/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true description = "Base pallet for cumulus-based parachains" license = "Apache-2.0" +[lints] +workspace = true + [dependencies] bytes = { version = "1.4.0", default-features = false } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } diff --git a/cumulus/pallets/parachain-system/proc-macro/Cargo.toml b/cumulus/pallets/parachain-system/proc-macro/Cargo.toml index fe960f716de..11a2ae01374 100644 --- a/cumulus/pallets/parachain-system/proc-macro/Cargo.toml +++ b/cumulus/pallets/parachain-system/proc-macro/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true description = "Proc macros provided by the parachain-system pallet" license = "Apache-2.0" +[lints] +workspace = true + [lib] proc-macro = true diff --git a/cumulus/pallets/session-benchmarking/Cargo.toml b/cumulus/pallets/session-benchmarking/Cargo.toml index 4c85b3d7171..af2dc2300d7 100644 --- a/cumulus/pallets/session-benchmarking/Cargo.toml +++ b/cumulus/pallets/session-benchmarking/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME sessions pallet benchmarking" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/cumulus/pallets/solo-to-para/Cargo.toml b/cumulus/pallets/solo-to-para/Cargo.toml index dc79d287d4d..e1c94cbfde9 100644 --- a/cumulus/pallets/solo-to-para/Cargo.toml +++ b/cumulus/pallets/solo-to-para/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true description = "Adds functionality to migrate from a Solo to a Parachain" license = "Apache-2.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } diff --git a/cumulus/pallets/xcm/Cargo.toml b/cumulus/pallets/xcm/Cargo.toml index f36d0aa52de..9bbc281154c 100644 --- a/cumulus/pallets/xcm/Cargo.toml +++ b/cumulus/pallets/xcm/Cargo.toml @@ -6,6 +6,9 @@ version = "0.1.0" license = "Apache-2.0" description = "Pallet for stuff specific to parachains' usage of XCM" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } diff --git a/cumulus/pallets/xcmp-queue/Cargo.toml b/cumulus/pallets/xcmp-queue/Cargo.toml index 1bc21bbbb58..50ec5cacb2e 100644 --- a/cumulus/pallets/xcmp-queue/Cargo.toml +++ b/cumulus/pallets/xcmp-queue/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true description = "Pallet to queue outbound and inbound XCMP messages." license = "Apache-2.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"], default-features = false } log = { version = "0.4.20", default-features = false } diff --git a/cumulus/parachain-template/node/Cargo.toml b/cumulus/parachain-template/node/Cargo.toml index a83b4e21ac5..4be848f4d2d 100644 --- a/cumulus/parachain-template/node/Cargo.toml +++ b/cumulus/parachain-template/node/Cargo.toml @@ -10,6 +10,9 @@ edition.workspace = true build = "build.rs" publish = false +[lints] +workspace = true + [dependencies] clap = { version = "4.4.11", features = ["derive"] } log = "0.4.20" diff --git a/cumulus/parachain-template/pallets/template/Cargo.toml b/cumulus/parachain-template/pallets/template/Cargo.toml index 71b78a7175c..bd7f926d039 100644 --- a/cumulus/parachain-template/pallets/template/Cargo.toml +++ b/cumulus/parachain-template/pallets/template/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true edition.workspace = true +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/cumulus/parachain-template/runtime/Cargo.toml b/cumulus/parachain-template/runtime/Cargo.toml index d83867a9c7c..3944ff4ca08 100644 --- a/cumulus/parachain-template/runtime/Cargo.toml +++ b/cumulus/parachain-template/runtime/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true edition.workspace = true +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/cumulus/parachains/common/Cargo.toml b/cumulus/parachains/common/Cargo.toml index 5475fd2aa26..dcaea40d2da 100644 --- a/cumulus/parachains/common/Cargo.toml +++ b/cumulus/parachains/common/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true description = "Logic which is common to all parachain runtimes" license = "Apache-2.0" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/Cargo.toml index dbf7e9c9a70..1596169efbe 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/Cargo.toml @@ -7,6 +7,9 @@ license = "Apache-2.0" description = "Asset Hub Rococo emulated chain" publish = false +[lints] +workspace = true + [dependencies] serde_json = "1.0.104" diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/Cargo.toml index 0ff817b6b96..ff5a70628db 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/Cargo.toml @@ -7,6 +7,9 @@ license = "Apache-2.0" description = "Asset Hub Westend emulated chain" publish = false +[lints] +workspace = true + [dependencies] serde_json = "1.0.104" diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/Cargo.toml index 43c0f5fd14c..8a56bb7b27f 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/Cargo.toml @@ -7,6 +7,9 @@ license = "Apache-2.0" description = "Bridge Hub Rococo emulated chain" publish = false +[lints] +workspace = true + [dependencies] serde_json = "1.0.104" diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/Cargo.toml index e5e6fd70739..a2268f3b17a 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/Cargo.toml @@ -7,6 +7,9 @@ license = "Apache-2.0" description = "Bridge Hub Westend emulated chain" publish = false +[lints] +workspace = true + [dependencies] serde_json = "1.0.104" diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/Cargo.toml index 5dcf139bdb7..54d2d9b6b98 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend/Cargo.toml @@ -7,6 +7,9 @@ license = "Apache-2.0" description = "Collectives Westend emulated chain" publish = false +[lints] +workspace = true + [dependencies] serde_json = "1.0.104" diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml index 5886158c263..d325b78fa66 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml @@ -7,6 +7,9 @@ license = "Apache-2.0" description = "Penpal emulated chain" publish = false +[lints] +workspace = true + [dependencies] serde_json = "1.0.104" diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/Cargo.toml index 325c7229517..d2e54367de2 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/Cargo.toml @@ -7,6 +7,9 @@ license = "Apache-2.0" description = "Rococo emulated chain" publish = false +[lints] +workspace = true + [dependencies] serde_json = "1.0.104" diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/Cargo.toml index 20b9737735f..b073bbb94f9 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/westend/Cargo.toml @@ -7,6 +7,9 @@ license = "Apache-2.0" description = "Westend emulated chain" publish = false +[lints] +workspace = true + [dependencies] serde_json = "1.0.104" diff --git a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml index 92716083d69..f2e799df810 100644 --- a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true license = "Apache-2.0" description = "Common resources for integration testing with xcm-emulator" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } paste = "1.0.14" diff --git a/cumulus/parachains/integration-tests/emulated/networks/rococo-system/Cargo.toml b/cumulus/parachains/integration-tests/emulated/networks/rococo-system/Cargo.toml index 713cc2ecdbb..bb31f8e467d 100644 --- a/cumulus/parachains/integration-tests/emulated/networks/rococo-system/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/networks/rococo-system/Cargo.toml @@ -7,6 +7,9 @@ license = "Apache-2.0" description = "Rococo System emulated network" publish = false +[lints] +workspace = true + [dependencies] # Cumulus emulated-integration-tests-common = { path = "../../common", default-features = false } diff --git a/cumulus/parachains/integration-tests/emulated/networks/rococo-westend-system/Cargo.toml b/cumulus/parachains/integration-tests/emulated/networks/rococo-westend-system/Cargo.toml index 34713f5b48e..2a538b8e28c 100644 --- a/cumulus/parachains/integration-tests/emulated/networks/rococo-westend-system/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/networks/rococo-westend-system/Cargo.toml @@ -7,6 +7,9 @@ license = "Apache-2.0" description = "Rococo<>Westend emulated bridged network" publish = false +[lints] +workspace = true + [dependencies] # Cumulus emulated-integration-tests-common = { path = "../../common", default-features = false } diff --git a/cumulus/parachains/integration-tests/emulated/networks/westend-system/Cargo.toml b/cumulus/parachains/integration-tests/emulated/networks/westend-system/Cargo.toml index 634111bc381..80ffb9cfd6c 100644 --- a/cumulus/parachains/integration-tests/emulated/networks/westend-system/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/networks/westend-system/Cargo.toml @@ -7,6 +7,9 @@ license = "Apache-2.0" description = "Westend System emulated network" publish = false +[lints] +workspace = true + [dependencies] # Cumulus emulated-integration-tests-common = { path = "../../common", default-features = false } diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml index bc4e7cfe376..445395fc783 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/Cargo.toml @@ -7,6 +7,9 @@ license = "Apache-2.0" description = "Asset Hub Rococo runtime integration tests with xcm-emulator" publish = false +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } assert_matches = "1.5.0" diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml index a0861b49955..3b2d3367d40 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml @@ -7,6 +7,9 @@ license = "Apache-2.0" description = "Asset Hub Westend runtime integration tests with xcm-emulator" publish = false +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } assert_matches = "1.5.0" diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml index 4f33505f9a7..ce6b8c24a44 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml @@ -7,6 +7,9 @@ license = "Apache-2.0" description = "Bridge Hub Rococo runtime integration tests with xcm-emulator" publish = false +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml index 00cf54b6541..6dcb57f4161 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/Cargo.toml @@ -7,6 +7,9 @@ license = "Apache-2.0" description = "Bridge Hub Westend runtime integration tests with xcm-emulator" publish = false +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } diff --git a/cumulus/parachains/pallets/collective-content/Cargo.toml b/cumulus/parachains/pallets/collective-content/Cargo.toml index 26899a9e774..9ed2822fa30 100644 --- a/cumulus/parachains/pallets/collective-content/Cargo.toml +++ b/cumulus/parachains/pallets/collective-content/Cargo.toml @@ -6,6 +6,9 @@ edition = "2021" description = "Managed content" license = "Apache-2.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } diff --git a/cumulus/parachains/pallets/parachain-info/Cargo.toml b/cumulus/parachains/pallets/parachain-info/Cargo.toml index b5b6ec304df..31f7b8aef39 100644 --- a/cumulus/parachains/pallets/parachain-info/Cargo.toml +++ b/cumulus/parachains/pallets/parachain-info/Cargo.toml @@ -6,6 +6,9 @@ version = "0.1.0" license = "Apache-2.0" description = "Pallet to store the parachain ID" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } diff --git a/cumulus/parachains/pallets/ping/Cargo.toml b/cumulus/parachains/pallets/ping/Cargo.toml index c661e4260c6..5c1099a110a 100644 --- a/cumulus/parachains/pallets/ping/Cargo.toml +++ b/cumulus/parachains/pallets/ping/Cargo.toml @@ -6,6 +6,9 @@ version = "0.1.0" license = "Apache-2.0" description = "Ping Pallet for Cumulus XCM/UMP testing." +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml index 15166de15ae..47af627d6b2 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true description = "Rococo variant of Asset Hub parachain runtime" license = "Apache-2.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } hex-literal = { version = "0.4.1" } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index 2eb8e9a55d7..1a1ed0465a3 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true description = "Westend variant of Asset Hub parachain runtime" license = "Apache-2.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } hex-literal = { version = "0.4.1", optional = true } diff --git a/cumulus/parachains/runtimes/assets/common/Cargo.toml b/cumulus/parachains/runtimes/assets/common/Cargo.toml index e78d8331039..22729df5ed5 100644 --- a/cumulus/parachains/runtimes/assets/common/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/common/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true description = "Assets common utilities" license = "Apache-2.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } diff --git a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml index c8ea4490d10..a3ed3759600 100644 --- a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true description = "Test utils for Asset Hub runtimes." license = "Apache-2.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml index 551615e155c..7902ca76b16 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true description = "Rococo's BridgeHub parachain runtime" license = "Apache-2.0" +[lints] +workspace = true + [build-dependencies] substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml index dd713987ffb..07c1a328285 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true description = "Westend's BridgeHub parachain runtime" license = "Apache-2.0" +[lints] +workspace = true + [build-dependencies] substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", optional = true } diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml index 35cab04fcc4..3049182cd4e 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true description = "Utils for BridgeHub testing" license = "Apache-2.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } impl-trait-for-tuples = "0.2" diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml index 433e55c6ea9..dd526a9e044 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true license = "Apache-2.0" description = "Westend Collectives Parachain Runtime" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } hex-literal = { version = "0.4.1" } diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml index ca45f4760d0..54af73c3d03 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "Apache-2.0" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml b/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml index b8efc4fbbcf..831e3242766 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true license = "Apache-2.0" description = "Glutton parachain runtime." +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } diff --git a/cumulus/parachains/runtimes/starters/seedling/Cargo.toml b/cumulus/parachains/runtimes/starters/seedling/Cargo.toml index 23312172bd7..37a3bb4ca26 100644 --- a/cumulus/parachains/runtimes/starters/seedling/Cargo.toml +++ b/cumulus/parachains/runtimes/starters/seedling/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "Apache-2.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } diff --git a/cumulus/parachains/runtimes/starters/shell/Cargo.toml b/cumulus/parachains/runtimes/starters/shell/Cargo.toml index a285d3d977e..3d7042ecd49 100644 --- a/cumulus/parachains/runtimes/starters/shell/Cargo.toml +++ b/cumulus/parachains/runtimes/starters/shell/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "Apache-2.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } diff --git a/cumulus/parachains/runtimes/test-utils/Cargo.toml b/cumulus/parachains/runtimes/test-utils/Cargo.toml index b4453e7f1a6..cd100c472ce 100644 --- a/cumulus/parachains/runtimes/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/test-utils/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true description = "Utils for Runtimes testing" license = "Apache-2.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } diff --git a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml index 6e044319d2e..4e2d145feb4 100644 --- a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true edition.workspace = true +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml index 3903bbbe31e..a23b7558bce 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true description = "Simple runtime used by the rococo parachain(s)" license = "Apache-2.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index 860c420d45b..b8c1508da09 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -7,6 +7,9 @@ edition.workspace = true description = "Runs a polkadot parachain node which could be a collator." license = "Apache-2.0" +[lints] +workspace = true + [[bin]] name = "polkadot-parachain" path = "src/main.rs" diff --git a/cumulus/primitives/aura/Cargo.toml b/cumulus/primitives/aura/Cargo.toml index 096ae0a9620..6d917eea270 100644 --- a/cumulus/primitives/aura/Cargo.toml +++ b/cumulus/primitives/aura/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true license = "Apache-2.0" description = "Core primitives for Aura in Cumulus" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } diff --git a/cumulus/primitives/core/Cargo.toml b/cumulus/primitives/core/Cargo.toml index 5f68a3546e6..98c3e8ab567 100644 --- a/cumulus/primitives/core/Cargo.toml +++ b/cumulus/primitives/core/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true license = "Apache-2.0" description = "Cumulus related core primitive types and traits" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } diff --git a/cumulus/primitives/parachain-inherent/Cargo.toml b/cumulus/primitives/parachain-inherent/Cargo.toml index 5d3c72a59f9..bfb101a43f4 100644 --- a/cumulus/primitives/parachain-inherent/Cargo.toml +++ b/cumulus/primitives/parachain-inherent/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true description = "Inherent that needs to be present in every parachain block. Contains messages and a relay chain storage-proof." license = "Apache-2.0" +[lints] +workspace = true + [dependencies] async-trait = { version = "0.1.73", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } diff --git a/cumulus/primitives/proof-size-hostfunction/Cargo.toml b/cumulus/primitives/proof-size-hostfunction/Cargo.toml index 576f7f5ae99..06797f86863 100644 --- a/cumulus/primitives/proof-size-hostfunction/Cargo.toml +++ b/cumulus/primitives/proof-size-hostfunction/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true description = "Hostfunction exposing storage proof size to the runtime." license = "Apache-2.0" +[lints] +workspace = true + [dependencies] sp-runtime-interface = { path = "../../../substrate/primitives/runtime-interface", default-features = false } sp-externalities = { path = "../../../substrate/primitives/externalities", default-features = false } diff --git a/cumulus/primitives/timestamp/Cargo.toml b/cumulus/primitives/timestamp/Cargo.toml index ec5cb57419a..b07a907154d 100644 --- a/cumulus/primitives/timestamp/Cargo.toml +++ b/cumulus/primitives/timestamp/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true description = "Provides timestamp related functionality for parachains." license = "Apache-2.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } futures = "0.3.28" diff --git a/cumulus/primitives/utility/Cargo.toml b/cumulus/primitives/utility/Cargo.toml index 5f756c1e361..56b6b928417 100644 --- a/cumulus/primitives/utility/Cargo.toml +++ b/cumulus/primitives/utility/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true license = "Apache-2.0" description = "Helper datatypes for Cumulus" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } log = { version = "0.4.20", default-features = false } diff --git a/cumulus/test/client/Cargo.toml b/cumulus/test/client/Cargo.toml index 037b8600db6..7190172101c 100644 --- a/cumulus/test/client/Cargo.toml +++ b/cumulus/test/client/Cargo.toml @@ -5,6 +5,9 @@ authors.workspace = true edition.workspace = true publish = false +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } diff --git a/cumulus/test/relay-sproof-builder/Cargo.toml b/cumulus/test/relay-sproof-builder/Cargo.toml index 262a4ff92b5..02a9750d78e 100644 --- a/cumulus/test/relay-sproof-builder/Cargo.toml +++ b/cumulus/test/relay-sproof-builder/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true license = "Apache-2.0" description = "Mocked relay state proof builder for testing Cumulus." +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } diff --git a/cumulus/test/runtime/Cargo.toml b/cumulus/test/runtime/Cargo.toml index 7bdb69df2c2..5902a62512b 100644 --- a/cumulus/test/runtime/Cargo.toml +++ b/cumulus/test/runtime/Cargo.toml @@ -5,6 +5,9 @@ authors.workspace = true edition.workspace = true publish = false +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } diff --git a/cumulus/test/service/Cargo.toml b/cumulus/test/service/Cargo.toml index cc25c80d4bf..c4e7f7401b0 100644 --- a/cumulus/test/service/Cargo.toml +++ b/cumulus/test/service/Cargo.toml @@ -5,6 +5,9 @@ authors.workspace = true edition.workspace = true publish = false +[lints] +workspace = true + [[bin]] name = "test-parachain" path = "src/main.rs" diff --git a/cumulus/xcm/xcm-emulator/Cargo.toml b/cumulus/xcm/xcm-emulator/Cargo.toml index 2f851f1bcde..0f10221d600 100644 --- a/cumulus/xcm/xcm-emulator/Cargo.toml +++ b/cumulus/xcm/xcm-emulator/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license = "Apache-2.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } paste = "1.0.14" diff --git a/docs/sdk/Cargo.toml b/docs/sdk/Cargo.toml index 14b4747d558..c58c3402f6a 100644 --- a/docs/sdk/Cargo.toml +++ b/docs/sdk/Cargo.toml @@ -10,6 +10,9 @@ edition.workspace = true publish = false version = "0.0.1" +[lints] +workspace = true + [dependencies] # Needed for all FRAME-based code parity-scale-codec = { version = "3.0.0", default-features = false } diff --git a/polkadot/Cargo.toml b/polkadot/Cargo.toml index d8c6cc51bea..d769957490e 100644 --- a/polkadot/Cargo.toml +++ b/polkadot/Cargo.toml @@ -21,6 +21,9 @@ edition.workspace = true version = "1.5.0" default-run = "polkadot" +[lints] +workspace = true + [dependencies] color-eyre = { version = "0.6.1", default-features = false } tikv-jemallocator = { version = "0.5.0", optional = true, features = ["unprefixed_malloc_on_supported_platforms"] } diff --git a/polkadot/cli/Cargo.toml b/polkadot/cli/Cargo.toml index 95b63913ccb..ed90b2d58a4 100644 --- a/polkadot/cli/Cargo.toml +++ b/polkadot/cli/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [package.metadata.wasm-pack.profile.release] # `wasm-opt` has some problems on Linux, see # https://github.com/rustwasm/wasm-pack/issues/781 etc. diff --git a/polkadot/core-primitives/Cargo.toml b/polkadot/core-primitives/Cargo.toml index 1b8da759c15..32ee8d3ff3f 100644 --- a/polkadot/core-primitives/Cargo.toml +++ b/polkadot/core-primitives/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] sp-core = { path = "../../substrate/primitives/core", default-features = false } sp-std = { path = "../../substrate/primitives/std", default-features = false } diff --git a/polkadot/erasure-coding/Cargo.toml b/polkadot/erasure-coding/Cargo.toml index c965f5d70aa..f174f8ad0cf 100644 --- a/polkadot/erasure-coding/Cargo.toml +++ b/polkadot/erasure-coding/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] polkadot-primitives = { path = "../primitives" } polkadot-node-primitives = { package = "polkadot-node-primitives", path = "../node/primitives" } diff --git a/polkadot/erasure-coding/fuzzer/Cargo.toml b/polkadot/erasure-coding/fuzzer/Cargo.toml index 862b148cc5b..4e5ef9d229d 100644 --- a/polkadot/erasure-coding/fuzzer/Cargo.toml +++ b/polkadot/erasure-coding/fuzzer/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true license.workspace = true publish = false +[lints] +workspace = true + [dependencies] polkadot-erasure-coding = { path = ".." } honggfuzz = "0.5" diff --git a/polkadot/node/collation-generation/Cargo.toml b/polkadot/node/collation-generation/Cargo.toml index e0c86d233f9..366c08a6c67 100644 --- a/polkadot/node/collation-generation/Cargo.toml +++ b/polkadot/node/collation-generation/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true license.workspace = true description = "Collator-side subsystem that handles incoming candidate submissions from the parachain." +[lints] +workspace = true + [dependencies] futures = "0.3.21" gum = { package = "tracing-gum", path = "../gum" } diff --git a/polkadot/node/core/approval-voting/Cargo.toml b/polkadot/node/core/approval-voting/Cargo.toml index 9516dc52a30..61a1e84dd6f 100644 --- a/polkadot/node/core/approval-voting/Cargo.toml +++ b/polkadot/node/core/approval-voting/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true license.workspace = true description = "Approval Voting Subsystem of the Polkadot node" +[lints] +workspace = true + [dependencies] futures = "0.3.21" futures-timer = "3.0.2" diff --git a/polkadot/node/core/av-store/Cargo.toml b/polkadot/node/core/av-store/Cargo.toml index 3fa81d064a8..4b2baf3fc55 100644 --- a/polkadot/node/core/av-store/Cargo.toml +++ b/polkadot/node/core/av-store/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] futures = "0.3.21" futures-timer = "3.0.2" diff --git a/polkadot/node/core/backing/Cargo.toml b/polkadot/node/core/backing/Cargo.toml index 7a6ce5de8cb..16ed11e7eec 100644 --- a/polkadot/node/core/backing/Cargo.toml +++ b/polkadot/node/core/backing/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true license.workspace = true description = "The Candidate Backing Subsystem. Tracks parachain candidates that can be backed, as well as the issuance of statements about candidates." +[lints] +workspace = true + [dependencies] futures = "0.3.21" sp-keystore = { path = "../../../../substrate/primitives/keystore" } diff --git a/polkadot/node/core/bitfield-signing/Cargo.toml b/polkadot/node/core/bitfield-signing/Cargo.toml index 712a01b46b1..880273c0e7f 100644 --- a/polkadot/node/core/bitfield-signing/Cargo.toml +++ b/polkadot/node/core/bitfield-signing/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true license.workspace = true description = "Bitfield signing subsystem for the Polkadot node" +[lints] +workspace = true + [dependencies] futures = "0.3.21" gum = { package = "tracing-gum", path = "../../gum" } diff --git a/polkadot/node/core/candidate-validation/Cargo.toml b/polkadot/node/core/candidate-validation/Cargo.toml index a2e88778532..9ded9e58a16 100644 --- a/polkadot/node/core/candidate-validation/Cargo.toml +++ b/polkadot/node/core/candidate-validation/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] async-trait = "0.1.57" futures = "0.3.21" diff --git a/polkadot/node/core/chain-api/Cargo.toml b/polkadot/node/core/chain-api/Cargo.toml index fa824e78ffe..32962c9bda4 100644 --- a/polkadot/node/core/chain-api/Cargo.toml +++ b/polkadot/node/core/chain-api/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true license.workspace = true description = "The Chain API subsystem provides access to chain related utility functions like block number to hash conversions." +[lints] +workspace = true + [dependencies] futures = "0.3.21" gum = { package = "tracing-gum", path = "../../gum" } diff --git a/polkadot/node/core/chain-selection/Cargo.toml b/polkadot/node/core/chain-selection/Cargo.toml index 7678379870e..6056ddd41cd 100644 --- a/polkadot/node/core/chain-selection/Cargo.toml +++ b/polkadot/node/core/chain-selection/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] futures = "0.3.21" futures-timer = "3" diff --git a/polkadot/node/core/dispute-coordinator/Cargo.toml b/polkadot/node/core/dispute-coordinator/Cargo.toml index e2086db708f..8ec9bcbe070 100644 --- a/polkadot/node/core/dispute-coordinator/Cargo.toml +++ b/polkadot/node/core/dispute-coordinator/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] futures = "0.3.21" gum = { package = "tracing-gum", path = "../../gum" } diff --git a/polkadot/node/core/parachains-inherent/Cargo.toml b/polkadot/node/core/parachains-inherent/Cargo.toml index c783f21e24d..8d84b586a30 100644 --- a/polkadot/node/core/parachains-inherent/Cargo.toml +++ b/polkadot/node/core/parachains-inherent/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true license.workspace = true description = "Parachains inherent data provider for Polkadot node" +[lints] +workspace = true + [dependencies] futures = "0.3.21" futures-timer = "3.0.2" diff --git a/polkadot/node/core/prospective-parachains/Cargo.toml b/polkadot/node/core/prospective-parachains/Cargo.toml index 9db1259e61d..e6b6aa5e15d 100644 --- a/polkadot/node/core/prospective-parachains/Cargo.toml +++ b/polkadot/node/core/prospective-parachains/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true license.workspace = true description = "The Prospective Parachains subsystem. Tracks and handles prospective parachain fragments." +[lints] +workspace = true + [dependencies] futures = "0.3.19" gum = { package = "tracing-gum", path = "../../gum" } diff --git a/polkadot/node/core/provisioner/Cargo.toml b/polkadot/node/core/provisioner/Cargo.toml index d27e2343925..2d18bd29c1c 100644 --- a/polkadot/node/core/provisioner/Cargo.toml +++ b/polkadot/node/core/provisioner/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } futures = "0.3.21" diff --git a/polkadot/node/core/pvf-checker/Cargo.toml b/polkadot/node/core/pvf-checker/Cargo.toml index 0326a20e5a5..274d8ee43bf 100644 --- a/polkadot/node/core/pvf-checker/Cargo.toml +++ b/polkadot/node/core/pvf-checker/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] futures = "0.3.21" thiserror = "1.0.48" diff --git a/polkadot/node/core/pvf/Cargo.toml b/polkadot/node/core/pvf/Cargo.toml index a1e70eabc0e..2642377b6e6 100644 --- a/polkadot/node/core/pvf/Cargo.toml +++ b/polkadot/node/core/pvf/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] always-assert = "0.1" blake3 = "1.5" diff --git a/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs b/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs index 368649a8d71..2aea21361a3 100644 --- a/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs +++ b/polkadot/node/core/pvf/benches/host_prepare_rococo_runtime.rs @@ -28,7 +28,8 @@ use tokio::{runtime::Handle, sync::Mutex}; const TEST_PREPARATION_TIMEOUT: Duration = Duration::from_secs(30); struct TestHost { - // Keep a reference to the tempdir as it gets deleted on drop. + // Keep a reference to the tempdir otherwise it gets deleted on drop. + #[allow(dead_code)] cache_dir: tempfile::TempDir, host: Mutex, } diff --git a/polkadot/node/core/pvf/common/Cargo.toml b/polkadot/node/core/pvf/common/Cargo.toml index bfe1be9156f..c5c09300e8a 100644 --- a/polkadot/node/core/pvf/common/Cargo.toml +++ b/polkadot/node/core/pvf/common/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] cfg-if = "1.0" cpu-time = "1.0.0" diff --git a/polkadot/node/core/pvf/execute-worker/Cargo.toml b/polkadot/node/core/pvf/execute-worker/Cargo.toml index 6e6206cf1b9..97dde59ebc2 100644 --- a/polkadot/node/core/pvf/execute-worker/Cargo.toml +++ b/polkadot/node/core/pvf/execute-worker/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] cpu-time = "1.0.0" gum = { package = "tracing-gum", path = "../../../gum" } diff --git a/polkadot/node/core/pvf/prepare-worker/Cargo.toml b/polkadot/node/core/pvf/prepare-worker/Cargo.toml index 4e53f7f46ca..81e887afe4d 100644 --- a/polkadot/node/core/pvf/prepare-worker/Cargo.toml +++ b/polkadot/node/core/pvf/prepare-worker/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] blake3 = "1.5" cfg-if = "1.0" diff --git a/polkadot/node/core/runtime-api/Cargo.toml b/polkadot/node/core/runtime-api/Cargo.toml index 965b280a747..547431b45b2 100644 --- a/polkadot/node/core/runtime-api/Cargo.toml +++ b/polkadot/node/core/runtime-api/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] futures = "0.3.21" gum = { package = "tracing-gum", path = "../../gum" } diff --git a/polkadot/node/gum/Cargo.toml b/polkadot/node/gum/Cargo.toml index acee9efd0e0..ccb21f64e63 100644 --- a/polkadot/node/gum/Cargo.toml +++ b/polkadot/node/gum/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true license.workspace = true description = "Stick logs together with the TraceID as provided by tempo" +[lints] +workspace = true + [dependencies] coarsetime = "0.1.22" tracing = "0.1.35" diff --git a/polkadot/node/gum/proc-macro/Cargo.toml b/polkadot/node/gum/proc-macro/Cargo.toml index e260cf1f929..f7880bfd2f9 100644 --- a/polkadot/node/gum/proc-macro/Cargo.toml +++ b/polkadot/node/gum/proc-macro/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true license.workspace = true description = "Generate an overseer including builder pattern and message wrapper from a single annotated struct definition." +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/polkadot/node/jaeger/Cargo.toml b/polkadot/node/jaeger/Cargo.toml index fcfbbaec611..81947f4f6a4 100644 --- a/polkadot/node/jaeger/Cargo.toml +++ b/polkadot/node/jaeger/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true license.workspace = true description = "Polkadot Jaeger primitives, but equally useful for Grafana/Tempo" +[lints] +workspace = true + [dependencies] mick-jaeger = "0.1.8" lazy_static = "1.4" diff --git a/polkadot/node/malus/Cargo.toml b/polkadot/node/malus/Cargo.toml index 2955bfbee18..d0a9b65f720 100644 --- a/polkadot/node/malus/Cargo.toml +++ b/polkadot/node/malus/Cargo.toml @@ -8,6 +8,9 @@ license.workspace = true readme = "README.md" publish = false +[lints] +workspace = true + [[bin]] name = "malus" path = "src/malus.rs" diff --git a/polkadot/node/metrics/Cargo.toml b/polkadot/node/metrics/Cargo.toml index e8e00a64c05..e9a4d463f4d 100644 --- a/polkadot/node/metrics/Cargo.toml +++ b/polkadot/node/metrics/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] futures = "0.3.21" futures-timer = "3.0.2" diff --git a/polkadot/node/network/approval-distribution/Cargo.toml b/polkadot/node/network/approval-distribution/Cargo.toml index 7db4aa77b7a..7291c1309e1 100644 --- a/polkadot/node/network/approval-distribution/Cargo.toml +++ b/polkadot/node/network/approval-distribution/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] polkadot-node-metrics = { path = "../../metrics" } polkadot-node-network-protocol = { path = "../protocol" } diff --git a/polkadot/node/network/availability-distribution/Cargo.toml b/polkadot/node/network/availability-distribution/Cargo.toml index 91ed1026e41..0d52c013a33 100644 --- a/polkadot/node/network/availability-distribution/Cargo.toml +++ b/polkadot/node/network/availability-distribution/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] futures = "0.3.21" gum = { package = "tracing-gum", path = "../../gum" } diff --git a/polkadot/node/network/availability-recovery/Cargo.toml b/polkadot/node/network/availability-recovery/Cargo.toml index 6048e6323cb..b97572181b0 100644 --- a/polkadot/node/network/availability-recovery/Cargo.toml +++ b/polkadot/node/network/availability-recovery/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] futures = "0.3.21" schnellru = "0.2.1" diff --git a/polkadot/node/network/bitfield-distribution/Cargo.toml b/polkadot/node/network/bitfield-distribution/Cargo.toml index 0e61e9cf620..5c5bd875a96 100644 --- a/polkadot/node/network/bitfield-distribution/Cargo.toml +++ b/polkadot/node/network/bitfield-distribution/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] always-assert = "0.1" futures = "0.3.21" diff --git a/polkadot/node/network/bridge/Cargo.toml b/polkadot/node/network/bridge/Cargo.toml index 6ae765c252f..d6b9a0a5e76 100644 --- a/polkadot/node/network/bridge/Cargo.toml +++ b/polkadot/node/network/bridge/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] always-assert = "0.1" async-trait = "0.1.57" diff --git a/polkadot/node/network/collator-protocol/Cargo.toml b/polkadot/node/network/collator-protocol/Cargo.toml index 367a97f35d9..bcf4f74132f 100644 --- a/polkadot/node/network/collator-protocol/Cargo.toml +++ b/polkadot/node/network/collator-protocol/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] bitvec = { version = "1.0.1", default-features = false, features = ["alloc"] } futures = "0.3.21" diff --git a/polkadot/node/network/dispute-distribution/Cargo.toml b/polkadot/node/network/dispute-distribution/Cargo.toml index f4ea358c41b..15a0edd3661 100644 --- a/polkadot/node/network/dispute-distribution/Cargo.toml +++ b/polkadot/node/network/dispute-distribution/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] futures = "0.3.21" futures-timer = "3.0.2" diff --git a/polkadot/node/network/gossip-support/Cargo.toml b/polkadot/node/network/gossip-support/Cargo.toml index 64a9743d1db..e4d6ac601c3 100644 --- a/polkadot/node/network/gossip-support/Cargo.toml +++ b/polkadot/node/network/gossip-support/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] sp-application-crypto = { path = "../../../../substrate/primitives/application-crypto" } sp-keystore = { path = "../../../../substrate/primitives/keystore" } diff --git a/polkadot/node/network/protocol/Cargo.toml b/polkadot/node/network/protocol/Cargo.toml index 379334ded24..1aded1f3c07 100644 --- a/polkadot/node/network/protocol/Cargo.toml +++ b/polkadot/node/network/protocol/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true license.workspace = true description = "Primitives types for the Node-side" +[lints] +workspace = true + [dependencies] async-channel = "1.8.0" async-trait = "0.1.57" diff --git a/polkadot/node/network/statement-distribution/Cargo.toml b/polkadot/node/network/statement-distribution/Cargo.toml index e251abc445d..85d2c75aa79 100644 --- a/polkadot/node/network/statement-distribution/Cargo.toml +++ b/polkadot/node/network/statement-distribution/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] futures = "0.3.21" futures-timer = "3.0.2" diff --git a/polkadot/node/overseer/Cargo.toml b/polkadot/node/overseer/Cargo.toml index d9266055a39..ec1849404b0 100644 --- a/polkadot/node/overseer/Cargo.toml +++ b/polkadot/node/overseer/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true license.workspace = true description = "System overseer of the Polkadot node" +[lints] +workspace = true + [dependencies] client = { package = "sc-client-api", path = "../../../substrate/client/api" } sp-api = { path = "../../../substrate/primitives/api" } diff --git a/polkadot/node/primitives/Cargo.toml b/polkadot/node/primitives/Cargo.toml index 6c37ebb986f..802a830f3ab 100644 --- a/polkadot/node/primitives/Cargo.toml +++ b/polkadot/node/primitives/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] bounded-vec = "0.7" futures = "0.3.21" diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index 81eff49ee30..85accff9e29 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -7,6 +7,9 @@ edition.workspace = true license.workspace = true description = "Utils to tie different Polkadot components together and allow instantiation of a node." +[lints] +workspace = true + [dependencies] # Substrate Client sc-authority-discovery = { path = "../../../substrate/client/authority-discovery" } diff --git a/polkadot/node/subsystem-test-helpers/Cargo.toml b/polkadot/node/subsystem-test-helpers/Cargo.toml index 9087ca11f5d..eb6e10559c2 100644 --- a/polkadot/node/subsystem-test-helpers/Cargo.toml +++ b/polkadot/node/subsystem-test-helpers/Cargo.toml @@ -7,6 +7,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] async-trait = "0.1.57" futures = "0.3.21" diff --git a/polkadot/node/subsystem-types/Cargo.toml b/polkadot/node/subsystem-types/Cargo.toml index dfda6c1b3c5..5518e9d080c 100644 --- a/polkadot/node/subsystem-types/Cargo.toml +++ b/polkadot/node/subsystem-types/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] derive_more = "0.99.17" futures = "0.3.21" diff --git a/polkadot/node/subsystem-util/Cargo.toml b/polkadot/node/subsystem-util/Cargo.toml index 9150fddc2bb..d6df3fbe3e2 100644 --- a/polkadot/node/subsystem-util/Cargo.toml +++ b/polkadot/node/subsystem-util/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] async-trait = "0.1.57" futures = "0.3.21" diff --git a/polkadot/node/subsystem/Cargo.toml b/polkadot/node/subsystem/Cargo.toml index 9b77359517c..b0b396d7f62 100644 --- a/polkadot/node/subsystem/Cargo.toml +++ b/polkadot/node/subsystem/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] polkadot-overseer = { path = "../overseer" } polkadot-node-subsystem-types = { path = "../subsystem-types" } diff --git a/polkadot/node/test/client/Cargo.toml b/polkadot/node/test/client/Cargo.toml index 646f1ea9732..36748c3b455 100644 --- a/polkadot/node/test/client/Cargo.toml +++ b/polkadot/node/test/client/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } diff --git a/polkadot/node/test/service/Cargo.toml b/polkadot/node/test/service/Cargo.toml index aa143f40300..3199dc262bb 100644 --- a/polkadot/node/test/service/Cargo.toml +++ b/polkadot/node/test/service/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] futures = "0.3.21" hex = "0.4.3" diff --git a/polkadot/node/tracking-allocator/Cargo.toml b/polkadot/node/tracking-allocator/Cargo.toml index b1b33091344..486346e1fe1 100644 --- a/polkadot/node/tracking-allocator/Cargo.toml +++ b/polkadot/node/tracking-allocator/Cargo.toml @@ -5,3 +5,6 @@ version = "1.0.0" authors.workspace = true edition.workspace = true license.workspace = true + +[lints] +workspace = true diff --git a/polkadot/node/zombienet-backchannel/Cargo.toml b/polkadot/node/zombienet-backchannel/Cargo.toml index c1b08b4a2bb..e81ab2db14b 100644 --- a/polkadot/node/zombienet-backchannel/Cargo.toml +++ b/polkadot/node/zombienet-backchannel/Cargo.toml @@ -8,6 +8,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] tokio = { version = "1.24.2", default-features = false, features = ["macros", "net", "rt-multi-thread", "sync"] } url = "2.3.1" diff --git a/polkadot/parachain/Cargo.toml b/polkadot/parachain/Cargo.toml index 7c8935d987e..0521af3bf2d 100644 --- a/polkadot/parachain/Cargo.toml +++ b/polkadot/parachain/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true license.workspace = true version = "1.0.0" +[lints] +workspace = true + [dependencies] # note: special care is taken to avoid inclusion of `sp-io` externals when compiling # this crate for WASM. This is critical to avoid forcing all parachain WASM into implementing diff --git a/polkadot/parachain/test-parachains/Cargo.toml b/polkadot/parachain/test-parachains/Cargo.toml index 7bbeda4893b..6acdedf67ff 100644 --- a/polkadot/parachain/test-parachains/Cargo.toml +++ b/polkadot/parachain/test-parachains/Cargo.toml @@ -7,6 +7,9 @@ edition.workspace = true license.workspace = true publish = false +[lints] +workspace = true + [dependencies] tiny-keccak = { version = "2.0.2", features = ["keccak"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } diff --git a/polkadot/parachain/test-parachains/adder/Cargo.toml b/polkadot/parachain/test-parachains/adder/Cargo.toml index ee0f6f551af..eec19ef788a 100644 --- a/polkadot/parachain/test-parachains/adder/Cargo.toml +++ b/polkadot/parachain/test-parachains/adder/Cargo.toml @@ -8,6 +8,9 @@ version = "1.0.0" authors.workspace = true publish = false +[lints] +workspace = true + [dependencies] parachain = { package = "polkadot-parachain-primitives", path = "../..", default-features = false, features = ["wasm-api"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } diff --git a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml index 8a018e330ba..b8f0c579b8b 100644 --- a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml @@ -7,6 +7,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [[bin]] name = "adder-collator" path = "src/main.rs" diff --git a/polkadot/parachain/test-parachains/halt/Cargo.toml b/polkadot/parachain/test-parachains/halt/Cargo.toml index 428f33f730e..1bdd4392ad3 100644 --- a/polkadot/parachain/test-parachains/halt/Cargo.toml +++ b/polkadot/parachain/test-parachains/halt/Cargo.toml @@ -8,6 +8,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] [build-dependencies] diff --git a/polkadot/parachain/test-parachains/undying/Cargo.toml b/polkadot/parachain/test-parachains/undying/Cargo.toml index e763b65cfdd..19e1261db1e 100644 --- a/polkadot/parachain/test-parachains/undying/Cargo.toml +++ b/polkadot/parachain/test-parachains/undying/Cargo.toml @@ -8,6 +8,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] parachain = { package = "polkadot-parachain-primitives", path = "../..", default-features = false, features = ["wasm-api"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } diff --git a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml index 29d36452eee..4ef24ca83dc 100644 --- a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml @@ -7,6 +7,9 @@ version = "1.0.0" authors.workspace = true publish = false +[lints] +workspace = true + [[bin]] name = "undying-collator" path = "src/main.rs" diff --git a/polkadot/primitives/Cargo.toml b/polkadot/primitives/Cargo.toml index 5e746c622cf..de6df85051a 100644 --- a/polkadot/primitives/Cargo.toml +++ b/polkadot/primitives/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true license.workspace = true description = "Shared primitives used by Polkadot runtime" +[lints] +workspace = true + [dependencies] bitvec = { version = "1.0.0", default-features = false, features = ["alloc", "serde"] } hex-literal = "0.4.1" diff --git a/polkadot/primitives/test-helpers/Cargo.toml b/polkadot/primitives/test-helpers/Cargo.toml index 8215b842ba4..fab9480cfde 100644 --- a/polkadot/primitives/test-helpers/Cargo.toml +++ b/polkadot/primitives/test-helpers/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] sp-keyring = { path = "../../../substrate/primitives/keyring" } sp-application-crypto = { package = "sp-application-crypto", path = "../../../substrate/primitives/application-crypto", default-features = false } diff --git a/polkadot/rpc/Cargo.toml b/polkadot/rpc/Cargo.toml index ce11b26e554..8c582c623ba 100644 --- a/polkadot/rpc/Cargo.toml +++ b/polkadot/rpc/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true license.workspace = true description = "Polkadot specific RPC functionality." +[lints] +workspace = true + [dependencies] jsonrpsee = { version = "0.16.2", features = ["server"] } polkadot-primitives = { path = "../primitives" } diff --git a/polkadot/runtime/common/Cargo.toml b/polkadot/runtime/common/Cargo.toml index 7e8461c73ef..1af29be0ae8 100644 --- a/polkadot/runtime/common/Cargo.toml +++ b/polkadot/runtime/common/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] impl-trait-for-tuples = "0.2.2" bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } diff --git a/polkadot/runtime/common/slot_range_helper/Cargo.toml b/polkadot/runtime/common/slot_range_helper/Cargo.toml index f31811c1272..3a402d01196 100644 --- a/polkadot/runtime/common/slot_range_helper/Cargo.toml +++ b/polkadot/runtime/common/slot_range_helper/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true license.workspace = true description = "Helper crate for generating slot ranges for the Polkadot runtime." +[lints] +workspace = true + [dependencies] paste = "1.0" enumn = "0.1.12" diff --git a/polkadot/runtime/metrics/Cargo.toml b/polkadot/runtime/metrics/Cargo.toml index ad4a2fa9207..9a16749bf60 100644 --- a/polkadot/runtime/metrics/Cargo.toml +++ b/polkadot/runtime/metrics/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true license.workspace = true description = "Runtime metric interface for the Polkadot node" +[lints] +workspace = true + [dependencies] sp-std = { package = "sp-std", path = "../../../substrate/primitives/std", default-features = false } sp-tracing = { path = "../../../substrate/primitives/tracing", default-features = false } diff --git a/polkadot/runtime/parachains/Cargo.toml b/polkadot/runtime/parachains/Cargo.toml index 2627bc9ef49..0bcf5c04c34 100644 --- a/polkadot/runtime/parachains/Cargo.toml +++ b/polkadot/runtime/parachains/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] impl-trait-for-tuples = "0.2.2" bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index 1edce2aa44d..c7236572ed7 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -7,6 +7,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } diff --git a/polkadot/runtime/rococo/constants/Cargo.toml b/polkadot/runtime/rococo/constants/Cargo.toml index a383ca65476..1e6b0a5f903 100644 --- a/polkadot/runtime/rococo/constants/Cargo.toml +++ b/polkadot/runtime/rococo/constants/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] smallvec = "1.8.0" diff --git a/polkadot/runtime/test-runtime/Cargo.toml b/polkadot/runtime/test-runtime/Cargo.toml index 850047c83bc..585f16ac86f 100644 --- a/polkadot/runtime/test-runtime/Cargo.toml +++ b/polkadot/runtime/test-runtime/Cargo.toml @@ -7,6 +7,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } diff --git a/polkadot/runtime/test-runtime/constants/Cargo.toml b/polkadot/runtime/test-runtime/constants/Cargo.toml index 88cd441f73b..2b387bbd307 100644 --- a/polkadot/runtime/test-runtime/constants/Cargo.toml +++ b/polkadot/runtime/test-runtime/constants/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] smallvec = "1.8.0" diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index d8402ff39ee..335ac14d47a 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -7,6 +7,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } diff --git a/polkadot/runtime/westend/constants/Cargo.toml b/polkadot/runtime/westend/constants/Cargo.toml index d2fa4158200..d2e86970e50 100644 --- a/polkadot/runtime/westend/constants/Cargo.toml +++ b/polkadot/runtime/westend/constants/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] smallvec = "1.8.0" diff --git a/polkadot/statement-table/Cargo.toml b/polkadot/statement-table/Cargo.toml index d2518591d26..9a313882da7 100644 --- a/polkadot/statement-table/Cargo.toml +++ b/polkadot/statement-table/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true license.workspace = true description = "Stores messages other authorities issue about candidates in Polkadot." +[lints] +workspace = true + [dependencies] parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } sp-core = { path = "../../substrate/primitives/core" } diff --git a/polkadot/utils/generate-bags/Cargo.toml b/polkadot/utils/generate-bags/Cargo.toml index 361c6af71bc..97f15f02e35 100644 --- a/polkadot/utils/generate-bags/Cargo.toml +++ b/polkadot/utils/generate-bags/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true license.workspace = true description = "CLI to generate voter bags for Polkadot runtimes" +[lints] +workspace = true + [dependencies] clap = { version = "4.4.11", features = ["derive"] } diff --git a/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml b/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml index 4a75142d00c..6b8c4be38a1 100644 --- a/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml +++ b/polkadot/utils/remote-ext-tests/bags-list/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] westend-runtime = { path = "../../../runtime/westend" } westend-runtime-constants = { path = "../../../runtime/westend/constants" } diff --git a/polkadot/xcm/Cargo.toml b/polkadot/xcm/Cargo.toml index 3d05957a3fe..235a4b204c9 100644 --- a/polkadot/xcm/Cargo.toml +++ b/polkadot/xcm/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] bounded-collections = { version = "0.1.9", default-features = false, features = ["serde"] } derivative = { version = "2.2.0", default-features = false, features = ["use_core"] } diff --git a/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml b/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml index 5438279c673..d9cc7e34c06 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml +++ b/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml @@ -6,6 +6,9 @@ license.workspace = true version = "1.0.0" description = "Benchmarks for the XCM pallet" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/polkadot/xcm/pallet-xcm/Cargo.toml b/polkadot/xcm/pallet-xcm/Cargo.toml index 645ac8f9941..220aad01398 100644 --- a/polkadot/xcm/pallet-xcm/Cargo.toml +++ b/polkadot/xcm/pallet-xcm/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] bounded-collections = { version = "0.1.8", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } diff --git a/polkadot/xcm/procedural/Cargo.toml b/polkadot/xcm/procedural/Cargo.toml index bb67bf0d1b0..8467016070a 100644 --- a/polkadot/xcm/procedural/Cargo.toml +++ b/polkadot/xcm/procedural/Cargo.toml @@ -7,6 +7,9 @@ license.workspace = true version = "1.0.0" publish = true +[lints] +workspace = true + [lib] proc-macro = true diff --git a/polkadot/xcm/xcm-builder/Cargo.toml b/polkadot/xcm/xcm-builder/Cargo.toml index 53743066720..ff528d7d075 100644 --- a/polkadot/xcm/xcm-builder/Cargo.toml +++ b/polkadot/xcm/xcm-builder/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true license.workspace = true version = "1.0.0" +[lints] +workspace = true + [dependencies] impl-trait-for-tuples = "0.2.1" parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } diff --git a/polkadot/xcm/xcm-executor/Cargo.toml b/polkadot/xcm/xcm-executor/Cargo.toml index b435c2d510a..32fa6669c0a 100644 --- a/polkadot/xcm/xcm-executor/Cargo.toml +++ b/polkadot/xcm/xcm-executor/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true license.workspace = true version = "1.0.0" +[lints] +workspace = true + [dependencies] impl-trait-for-tuples = "0.2.2" environmental = { version = "1.1.4", default-features = false } diff --git a/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml b/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml index 0818d16a262..cafe12dc587 100644 --- a/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml +++ b/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml @@ -7,6 +7,9 @@ license.workspace = true version = "1.0.0" publish = false +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } frame-support = { path = "../../../../substrate/frame/support", default-features = false } diff --git a/polkadot/xcm/xcm-simulator/Cargo.toml b/polkadot/xcm/xcm-simulator/Cargo.toml index eedcfa0032a..051e9752f6e 100644 --- a/polkadot/xcm/xcm-simulator/Cargo.toml +++ b/polkadot/xcm/xcm-simulator/Cargo.toml @@ -6,6 +6,9 @@ authors.workspace = true edition.workspace = true license.workspace = true +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } paste = "1.0.7" diff --git a/polkadot/xcm/xcm-simulator/example/Cargo.toml b/polkadot/xcm/xcm-simulator/example/Cargo.toml index f0caa5ab48e..522b7855837 100644 --- a/polkadot/xcm/xcm-simulator/example/Cargo.toml +++ b/polkadot/xcm/xcm-simulator/example/Cargo.toml @@ -6,6 +6,9 @@ edition.workspace = true license.workspace = true version = "1.0.0" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } scale-info = { version = "2.10.0", features = ["derive"] } diff --git a/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml b/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml index acf28bec4f1..1d13c76f171 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml +++ b/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml @@ -7,6 +7,9 @@ edition.workspace = true license.workspace = true publish = false +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } honggfuzz = "0.5.55" diff --git a/substrate/bin/minimal/node/Cargo.toml b/substrate/bin/minimal/node/Cargo.toml index 4358009057a..532cded68de 100644 --- a/substrate/bin/minimal/node/Cargo.toml +++ b/substrate/bin/minimal/node/Cargo.toml @@ -10,6 +10,9 @@ publish = false repository = "https://github.com/substrate-developer-hub/substrate-node-template/" build = "build.rs" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/bin/minimal/runtime/Cargo.toml b/substrate/bin/minimal/runtime/Cargo.toml index f7685642d27..296106544bb 100644 --- a/substrate/bin/minimal/runtime/Cargo.toml +++ b/substrate/bin/minimal/runtime/Cargo.toml @@ -8,6 +8,9 @@ repository.workspace = true license.workspace = true publish = false +[lints] +workspace = true + [dependencies] parity-scale-codec = { version = "3.0.0", default-features = false } scale-info = { version = "2.6.0", default-features = false } diff --git a/substrate/bin/node-template/node/Cargo.toml b/substrate/bin/node-template/node/Cargo.toml index 1541ffec27f..9d8c4430c21 100644 --- a/substrate/bin/node-template/node/Cargo.toml +++ b/substrate/bin/node-template/node/Cargo.toml @@ -10,6 +10,9 @@ publish = false repository = "https://github.com/substrate-developer-hub/substrate-node-template/" build = "build.rs" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/bin/node-template/pallets/template/Cargo.toml b/substrate/bin/node-template/pallets/template/Cargo.toml index 405d9c229f8..51410a71c7b 100644 --- a/substrate/bin/node-template/pallets/template/Cargo.toml +++ b/substrate/bin/node-template/pallets/template/Cargo.toml @@ -9,6 +9,9 @@ license = "MIT-0" publish = false repository = "https://github.com/substrate-developer-hub/substrate-node-template/" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/bin/node-template/runtime/Cargo.toml b/substrate/bin/node-template/runtime/Cargo.toml index 55fb03159ab..14a64948c0b 100644 --- a/substrate/bin/node-template/runtime/Cargo.toml +++ b/substrate/bin/node-template/runtime/Cargo.toml @@ -9,6 +9,9 @@ license = "MIT-0" publish = false repository = "https://github.com/substrate-developer-hub/substrate-node-template/" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/bin/node/bench/Cargo.toml b/substrate/bin/node/bench/Cargo.toml index 1d9ce149d4f..48b3ef1b67e 100644 --- a/substrate/bin/node/bench/Cargo.toml +++ b/substrate/bin/node/bench/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true publish = false +[lints] +workspace = true + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] diff --git a/substrate/bin/node/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml index 307aae1189e..4f78bd65e8f 100644 --- a/substrate/bin/node/cli/Cargo.toml +++ b/substrate/bin/node/cli/Cargo.toml @@ -11,6 +11,9 @@ homepage = "https://substrate.io" repository.workspace = true publish = false +[lints] +workspace = true + [package.metadata.wasm-pack.profile.release] # `wasm-opt` has some problems on linux, see # https://github.com/rustwasm/wasm-pack/issues/781 etc. diff --git a/substrate/bin/node/inspect/Cargo.toml b/substrate/bin/node/inspect/Cargo.toml index 0457fd54cab..44de013483e 100644 --- a/substrate/bin/node/inspect/Cargo.toml +++ b/substrate/bin/node/inspect/Cargo.toml @@ -8,6 +8,9 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" repository.workspace = true +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/bin/node/primitives/Cargo.toml b/substrate/bin/node/primitives/Cargo.toml index 40735ff21d4..24279ad09c3 100644 --- a/substrate/bin/node/primitives/Cargo.toml +++ b/substrate/bin/node/primitives/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true publish = false +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/bin/node/rpc/Cargo.toml b/substrate/bin/node/rpc/Cargo.toml index 43db4ab9d34..a4a361fadbc 100644 --- a/substrate/bin/node/rpc/Cargo.toml +++ b/substrate/bin/node/rpc/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true publish = false +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index 8ea2988bee0..1d3f71f3436 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -10,6 +10,9 @@ homepage = "https://substrate.io" repository.workspace = true publish = false +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/bin/node/testing/Cargo.toml b/substrate/bin/node/testing/Cargo.toml index 513cb22b6a2..76188ed446c 100644 --- a/substrate/bin/node/testing/Cargo.toml +++ b/substrate/bin/node/testing/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true publish = false +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/bin/utils/chain-spec-builder/Cargo.toml b/substrate/bin/utils/chain-spec-builder/Cargo.toml index 110c1b6ce02..dcbe26f6a8f 100644 --- a/substrate/bin/utils/chain-spec-builder/Cargo.toml +++ b/substrate/bin/utils/chain-spec-builder/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true publish = false +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/bin/utils/subkey/Cargo.toml b/substrate/bin/utils/subkey/Cargo.toml index 37eba299cb2..58aa036a631 100644 --- a/substrate/bin/utils/subkey/Cargo.toml +++ b/substrate/bin/utils/subkey/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/allocator/Cargo.toml b/substrate/client/allocator/Cargo.toml index 31c714180ce..ef13c1a4573 100644 --- a/substrate/client/allocator/Cargo.toml +++ b/substrate/client/allocator/Cargo.toml @@ -10,6 +10,9 @@ description = "Collection of allocator implementations." documentation = "https://docs.rs/sc-allocator" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/api/Cargo.toml b/substrate/client/api/Cargo.toml index 57a364e791f..8c50b872914 100644 --- a/substrate/client/api/Cargo.toml +++ b/substrate/client/api/Cargo.toml @@ -10,6 +10,9 @@ description = "Substrate client interfaces." documentation = "https://docs.rs/sc-client-api" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/authority-discovery/Cargo.toml b/substrate/client/authority-discovery/Cargo.toml index 40c2162c799..33db0c156eb 100644 --- a/substrate/client/authority-discovery/Cargo.toml +++ b/substrate/client/authority-discovery/Cargo.toml @@ -10,6 +10,9 @@ repository.workspace = true description = "Substrate authority discovery." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/basic-authorship/Cargo.toml b/substrate/client/basic-authorship/Cargo.toml index 1d60fc7f53e..926909ec7b7 100644 --- a/substrate/client/basic-authorship/Cargo.toml +++ b/substrate/client/basic-authorship/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Basic implementation of block-authoring logic." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/block-builder/Cargo.toml b/substrate/client/block-builder/Cargo.toml index 852ee84f89b..4477f5f1d77 100644 --- a/substrate/client/block-builder/Cargo.toml +++ b/substrate/client/block-builder/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Substrate block builder" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/chain-spec/Cargo.toml b/substrate/client/chain-spec/Cargo.toml index d041d5bfd2b..c870ff19b2a 100644 --- a/substrate/client/chain-spec/Cargo.toml +++ b/substrate/client/chain-spec/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Substrate chain configurations." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/chain-spec/derive/Cargo.toml b/substrate/client/chain-spec/derive/Cargo.toml index 0fbe1074d27..b5a2bdc09b3 100644 --- a/substrate/client/chain-spec/derive/Cargo.toml +++ b/substrate/client/chain-spec/derive/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "Macros to derive chain spec extension traits implementation." +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index de303975031..82362e35ea6 100644 --- a/substrate/client/cli/Cargo.toml +++ b/substrate/client/cli/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/consensus/aura/Cargo.toml b/substrate/client/consensus/aura/Cargo.toml index bc9648f683a..a323a1dda47 100644 --- a/substrate/client/consensus/aura/Cargo.toml +++ b/substrate/client/consensus/aura/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/consensus/babe/Cargo.toml b/substrate/client/consensus/babe/Cargo.toml index 6008a5a99f8..996063cef1b 100644 --- a/substrate/client/consensus/babe/Cargo.toml +++ b/substrate/client/consensus/babe/Cargo.toml @@ -10,6 +10,9 @@ repository.workspace = true documentation = "https://docs.rs/sc-consensus-babe" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/consensus/babe/rpc/Cargo.toml b/substrate/client/consensus/babe/rpc/Cargo.toml index 913dd990fd3..b23f3f81d43 100644 --- a/substrate/client/consensus/babe/rpc/Cargo.toml +++ b/substrate/client/consensus/babe/rpc/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/consensus/beefy/Cargo.toml b/substrate/client/consensus/beefy/Cargo.toml index 6ee70b523bc..8ffa6b24be8 100644 --- a/substrate/client/consensus/beefy/Cargo.toml +++ b/substrate/client/consensus/beefy/Cargo.toml @@ -8,6 +8,9 @@ repository.workspace = true description = "BEEFY Client gadget for substrate" homepage = "https://substrate.io" +[lints] +workspace = true + [dependencies] array-bytes = "6.1" async-channel = "1.8.0" diff --git a/substrate/client/consensus/beefy/rpc/Cargo.toml b/substrate/client/consensus/beefy/rpc/Cargo.toml index 35041a1208f..157b0cc87fc 100644 --- a/substrate/client/consensus/beefy/rpc/Cargo.toml +++ b/substrate/client/consensus/beefy/rpc/Cargo.toml @@ -8,6 +8,9 @@ repository.workspace = true description = "RPC for the BEEFY Client gadget for substrate" homepage = "https://substrate.io" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } futures = "0.3.21" diff --git a/substrate/client/consensus/common/Cargo.toml b/substrate/client/consensus/common/Cargo.toml index 95ee02a9262..9c0305bb8c9 100644 --- a/substrate/client/consensus/common/Cargo.toml +++ b/substrate/client/consensus/common/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Collection of common consensus specific imlementations for Substrate (client)" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/consensus/epochs/Cargo.toml b/substrate/client/consensus/epochs/Cargo.toml index 07de83980bc..76e4c05a673 100644 --- a/substrate/client/consensus/epochs/Cargo.toml +++ b/substrate/client/consensus/epochs/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/consensus/grandpa/Cargo.toml b/substrate/client/consensus/grandpa/Cargo.toml index e1baff3bbf2..14ce52f2729 100644 --- a/substrate/client/consensus/grandpa/Cargo.toml +++ b/substrate/client/consensus/grandpa/Cargo.toml @@ -10,6 +10,9 @@ description = "Integration of the GRANDPA finality gadget into substrate." documentation = "https://docs.rs/sc-consensus-grandpa" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/consensus/grandpa/rpc/Cargo.toml b/substrate/client/consensus/grandpa/rpc/Cargo.toml index 2a0d51dd616..983f7a4339b 100644 --- a/substrate/client/consensus/grandpa/rpc/Cargo.toml +++ b/substrate/client/consensus/grandpa/rpc/Cargo.toml @@ -9,6 +9,9 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" readme = "README.md" homepage = "https://substrate.io" +[lints] +workspace = true + [dependencies] finality-grandpa = { version = "0.16.2", features = ["derive-codec"] } futures = "0.3.16" diff --git a/substrate/client/consensus/manual-seal/Cargo.toml b/substrate/client/consensus/manual-seal/Cargo.toml index b0b9c1ee6eb..c111f0494de 100644 --- a/substrate/client/consensus/manual-seal/Cargo.toml +++ b/substrate/client/consensus/manual-seal/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/consensus/pow/Cargo.toml b/substrate/client/consensus/pow/Cargo.toml index ef32425685b..d5eebb23e13 100644 --- a/substrate/client/consensus/pow/Cargo.toml +++ b/substrate/client/consensus/pow/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/consensus/slots/Cargo.toml b/substrate/client/consensus/slots/Cargo.toml index 52c528c3028..29206004c23 100644 --- a/substrate/client/consensus/slots/Cargo.toml +++ b/substrate/client/consensus/slots/Cargo.toml @@ -10,6 +10,9 @@ homepage = "https://substrate.io" repository.workspace = true readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/db/Cargo.toml b/substrate/client/db/Cargo.toml index bb22ff4c6c1..e833b90b3ed 100644 --- a/substrate/client/db/Cargo.toml +++ b/substrate/client/db/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Client backend that uses RocksDB database as storage." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/executor/Cargo.toml b/substrate/client/executor/Cargo.toml index 50aedf8a348..aa8e8c9abf2 100644 --- a/substrate/client/executor/Cargo.toml +++ b/substrate/client/executor/Cargo.toml @@ -10,6 +10,9 @@ description = "A crate that provides means of executing/dispatching calls into t documentation = "https://docs.rs/sc-executor" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/executor/common/Cargo.toml b/substrate/client/executor/common/Cargo.toml index 5118279b43b..b3db6a86a20 100644 --- a/substrate/client/executor/common/Cargo.toml +++ b/substrate/client/executor/common/Cargo.toml @@ -10,6 +10,9 @@ description = "A set of common definitions that are needed for defining executio documentation = "https://docs.rs/sc-executor-common/" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/executor/runtime-test/Cargo.toml b/substrate/client/executor/runtime-test/Cargo.toml index 84ed458fb1c..82610c4f50c 100644 --- a/substrate/client/executor/runtime-test/Cargo.toml +++ b/substrate/client/executor/runtime-test/Cargo.toml @@ -9,6 +9,9 @@ publish = false homepage = "https://substrate.io" repository.workspace = true +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/executor/wasmtime/Cargo.toml b/substrate/client/executor/wasmtime/Cargo.toml index b1434ef7c52..f8df23a026e 100644 --- a/substrate/client/executor/wasmtime/Cargo.toml +++ b/substrate/client/executor/wasmtime/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Defines a `WasmRuntime` that uses the Wasmtime JIT to execute." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/informant/Cargo.toml b/substrate/client/informant/Cargo.toml index 47e65df3cc1..8373e5a54c1 100644 --- a/substrate/client/informant/Cargo.toml +++ b/substrate/client/informant/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/keystore/Cargo.toml b/substrate/client/keystore/Cargo.toml index 3fd88ae8b87..7671aac0bd7 100644 --- a/substrate/client/keystore/Cargo.toml +++ b/substrate/client/keystore/Cargo.toml @@ -10,6 +10,9 @@ description = "Keystore (and session key management) for ed25519 based chains li documentation = "https://docs.rs/sc-keystore" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/merkle-mountain-range/Cargo.toml b/substrate/client/merkle-mountain-range/Cargo.toml index ae60fd1ce89..f6dbaf86c51 100644 --- a/substrate/client/merkle-mountain-range/Cargo.toml +++ b/substrate/client/merkle-mountain-range/Cargo.toml @@ -8,6 +8,9 @@ repository.workspace = true description = "MMR Client gadget for substrate" homepage = "https://substrate.io" +[lints] +workspace = true + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] diff --git a/substrate/client/merkle-mountain-range/rpc/Cargo.toml b/substrate/client/merkle-mountain-range/rpc/Cargo.toml index d978d3cd2ed..d4ee0b48522 100644 --- a/substrate/client/merkle-mountain-range/rpc/Cargo.toml +++ b/substrate/client/merkle-mountain-range/rpc/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "Node-specific RPC methods for interaction with Merkle Mountain Range pallet." +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/mixnet/Cargo.toml b/substrate/client/mixnet/Cargo.toml index d11cb1805ff..e8543b5bdf2 100644 --- a/substrate/client/mixnet/Cargo.toml +++ b/substrate/client/mixnet/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/network-gossip/Cargo.toml b/substrate/client/network-gossip/Cargo.toml index 0ad9dec4651..d4fb416a4a0 100644 --- a/substrate/client/network-gossip/Cargo.toml +++ b/substrate/client/network-gossip/Cargo.toml @@ -10,6 +10,9 @@ repository.workspace = true documentation = "https://docs.rs/sc-network-gossip" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/network/Cargo.toml b/substrate/client/network/Cargo.toml index ff8046868d5..abad2c80917 100644 --- a/substrate/client/network/Cargo.toml +++ b/substrate/client/network/Cargo.toml @@ -10,6 +10,9 @@ repository.workspace = true documentation = "https://docs.rs/sc-network" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/network/bitswap/Cargo.toml b/substrate/client/network/bitswap/Cargo.toml index f4ad4b3a0e9..cc919d2977e 100644 --- a/substrate/client/network/bitswap/Cargo.toml +++ b/substrate/client/network/bitswap/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true documentation = "https://docs.rs/sc-network-bitswap" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/network/common/Cargo.toml b/substrate/client/network/common/Cargo.toml index 65c8e1d71c7..5b0eb5510a5 100644 --- a/substrate/client/network/common/Cargo.toml +++ b/substrate/client/network/common/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true documentation = "https://docs.rs/sc-network-sync" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/network/light/Cargo.toml b/substrate/client/network/light/Cargo.toml index 17b21432811..c75d14f0deb 100644 --- a/substrate/client/network/light/Cargo.toml +++ b/substrate/client/network/light/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true documentation = "https://docs.rs/sc-network-light" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/network/statement/Cargo.toml b/substrate/client/network/statement/Cargo.toml index ef974b4f33f..e07eb939ea3 100644 --- a/substrate/client/network/statement/Cargo.toml +++ b/substrate/client/network/statement/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true documentation = "https://docs.rs/sc-network-statement" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/network/sync/Cargo.toml b/substrate/client/network/sync/Cargo.toml index a9b8ec577e3..f20592d5f25 100644 --- a/substrate/client/network/sync/Cargo.toml +++ b/substrate/client/network/sync/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true documentation = "https://docs.rs/sc-network-sync" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/network/test/Cargo.toml b/substrate/client/network/test/Cargo.toml index a11ed2a3ec8..cd66c701660 100644 --- a/substrate/client/network/test/Cargo.toml +++ b/substrate/client/network/test/Cargo.toml @@ -9,6 +9,9 @@ publish = false homepage = "https://substrate.io" repository.workspace = true +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/network/transactions/Cargo.toml b/substrate/client/network/transactions/Cargo.toml index 2a6aa4b3a40..8acd4531de8 100644 --- a/substrate/client/network/transactions/Cargo.toml +++ b/substrate/client/network/transactions/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true documentation = "https://docs.rs/sc-network-transactions" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/offchain/Cargo.toml b/substrate/client/offchain/Cargo.toml index 01deb322134..9f9731ba8de 100644 --- a/substrate/client/offchain/Cargo.toml +++ b/substrate/client/offchain/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/proposer-metrics/Cargo.toml b/substrate/client/proposer-metrics/Cargo.toml index b6b4452ecc6..664b72764a3 100644 --- a/substrate/client/proposer-metrics/Cargo.toml +++ b/substrate/client/proposer-metrics/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Basic metrics for block production." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/rpc-api/Cargo.toml b/substrate/client/rpc-api/Cargo.toml index b5c0f70d94c..6b1270fc370 100644 --- a/substrate/client/rpc-api/Cargo.toml +++ b/substrate/client/rpc-api/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Substrate RPC interfaces." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/rpc-servers/Cargo.toml b/substrate/client/rpc-servers/Cargo.toml index a7cc374f97a..5bb7317264c 100644 --- a/substrate/client/rpc-servers/Cargo.toml +++ b/substrate/client/rpc-servers/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Substrate RPC servers." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/rpc-spec-v2/Cargo.toml b/substrate/client/rpc-spec-v2/Cargo.toml index 45a1d862f04..b5fb8b5b204 100644 --- a/substrate/client/rpc-spec-v2/Cargo.toml +++ b/substrate/client/rpc-spec-v2/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Substrate RPC interface v2." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/rpc/Cargo.toml b/substrate/client/rpc/Cargo.toml index 1cedcb3a6d0..361d98a6b10 100644 --- a/substrate/client/rpc/Cargo.toml +++ b/substrate/client/rpc/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Substrate Client RPC" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/service/Cargo.toml b/substrate/client/service/Cargo.toml index ae03a5dab36..4c03b59a663 100644 --- a/substrate/client/service/Cargo.toml +++ b/substrate/client/service/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Substrate service. Starts a thread that spins up the network, client, and extrinsic pool. Manages communication between them." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/service/test/Cargo.toml b/substrate/client/service/test/Cargo.toml index 93576be9b59..625d8286396 100644 --- a/substrate/client/service/test/Cargo.toml +++ b/substrate/client/service/test/Cargo.toml @@ -8,6 +8,9 @@ publish = false homepage = "https://substrate.io" repository.workspace = true +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/state-db/Cargo.toml b/substrate/client/state-db/Cargo.toml index c5e8272637d..001ada02ef2 100644 --- a/substrate/client/state-db/Cargo.toml +++ b/substrate/client/state-db/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "State database maintenance. Handles canonicalization and pruning in the database." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/statement-store/Cargo.toml b/substrate/client/statement-store/Cargo.toml index e7bfd544afe..adfd27a1705 100644 --- a/substrate/client/statement-store/Cargo.toml +++ b/substrate/client/statement-store/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Substrate statement store." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/storage-monitor/Cargo.toml b/substrate/client/storage-monitor/Cargo.toml index f7c62f44af4..1c4a136ade6 100644 --- a/substrate/client/storage-monitor/Cargo.toml +++ b/substrate/client/storage-monitor/Cargo.toml @@ -8,6 +8,9 @@ repository.workspace = true description = "Storage monitor service for substrate" homepage = "https://substrate.io" +[lints] +workspace = true + [dependencies] clap = { version = "4.4.11", features = ["derive", "string"] } log = "0.4.17" diff --git a/substrate/client/sync-state-rpc/Cargo.toml b/substrate/client/sync-state-rpc/Cargo.toml index 746f1c754f9..c839a4210e4 100644 --- a/substrate/client/sync-state-rpc/Cargo.toml +++ b/substrate/client/sync-state-rpc/Cargo.toml @@ -8,6 +8,9 @@ license = "Apache-2.0" homepage = "https://substrate.io" repository.workspace = true +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/sysinfo/Cargo.toml b/substrate/client/sysinfo/Cargo.toml index 4cd1b222bc6..e5d5987c90e 100644 --- a/substrate/client/sysinfo/Cargo.toml +++ b/substrate/client/sysinfo/Cargo.toml @@ -10,6 +10,9 @@ description = "A crate that provides basic hardware and software telemetry infor documentation = "https://docs.rs/sc-sysinfo" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/telemetry/Cargo.toml b/substrate/client/telemetry/Cargo.toml index 71119df1153..0f7f8ab33ee 100644 --- a/substrate/client/telemetry/Cargo.toml +++ b/substrate/client/telemetry/Cargo.toml @@ -10,6 +10,9 @@ repository.workspace = true documentation = "https://docs.rs/sc-telemetry" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/tracing/Cargo.toml b/substrate/client/tracing/Cargo.toml index 844969c5ce2..94dd6e89231 100644 --- a/substrate/client/tracing/Cargo.toml +++ b/substrate/client/tracing/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Instrumentation implementation for substrate." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/tracing/proc-macro/Cargo.toml b/substrate/client/tracing/proc-macro/Cargo.toml index 509e87174da..d85a4a7468a 100644 --- a/substrate/client/tracing/proc-macro/Cargo.toml +++ b/substrate/client/tracing/proc-macro/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "Helper macros for Substrate's client CLI" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/transaction-pool/Cargo.toml b/substrate/client/transaction-pool/Cargo.toml index 3e90304497f..493f6680c4c 100644 --- a/substrate/client/transaction-pool/Cargo.toml +++ b/substrate/client/transaction-pool/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Substrate transaction pool implementation." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/client/transaction-pool/api/Cargo.toml b/substrate/client/transaction-pool/api/Cargo.toml index 89981c27511..29e402c34f8 100644 --- a/substrate/client/transaction-pool/api/Cargo.toml +++ b/substrate/client/transaction-pool/api/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "Transaction pool client facing API." +[lints] +workspace = true + [dependencies] async-trait = "0.1.57" codec = { package = "parity-scale-codec", version = "3.6.1" } diff --git a/substrate/client/utils/Cargo.toml b/substrate/client/utils/Cargo.toml index da618b0259e..a19457ac3d0 100644 --- a/substrate/client/utils/Cargo.toml +++ b/substrate/client/utils/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "I/O for Substrate runtimes" readme = "README.md" +[lints] +workspace = true + [dependencies] async-channel = "1.8.0" futures = "0.3.21" diff --git a/substrate/frame/Cargo.toml b/substrate/frame/Cargo.toml index d6953dac7b8..083d098b22a 100644 --- a/substrate/frame/Cargo.toml +++ b/substrate/frame/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "The single package to get you started with building frame pallets and runtimes" publish = false +[lints] +workspace = true + [package.metadata.docs.rs] # enable `experimental` feature for docs features = ["experimental"] diff --git a/substrate/frame/alliance/Cargo.toml b/substrate/frame/alliance/Cargo.toml index 1afff8ad43e..39f5a6ceb75 100644 --- a/substrate/frame/alliance/Cargo.toml +++ b/substrate/frame/alliance/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "The Alliance pallet provides a collective for standard-setting industry collaboration." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/asset-conversion/Cargo.toml b/substrate/frame/asset-conversion/Cargo.toml index 5df86d402e0..0c7b06abf55 100644 --- a/substrate/frame/asset-conversion/Cargo.toml +++ b/substrate/frame/asset-conversion/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME asset conversion pallet" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/asset-rate/Cargo.toml b/substrate/frame/asset-rate/Cargo.toml index af2776bba5f..835a15e8c55 100644 --- a/substrate/frame/asset-rate/Cargo.toml +++ b/substrate/frame/asset-rate/Cargo.toml @@ -8,6 +8,9 @@ edition.workspace = true license = "Apache-2.0" repository.workspace = true +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/assets/Cargo.toml b/substrate/frame/assets/Cargo.toml index 87709af2727..7b0af2421ea 100644 --- a/substrate/frame/assets/Cargo.toml +++ b/substrate/frame/assets/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME asset management pallet" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/atomic-swap/Cargo.toml b/substrate/frame/atomic-swap/Cargo.toml index 0a0f20eb8e8..d34779d8bc0 100644 --- a/substrate/frame/atomic-swap/Cargo.toml +++ b/substrate/frame/atomic-swap/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME atomic swap pallet" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/aura/Cargo.toml b/substrate/frame/aura/Cargo.toml index 321a19f74f9..e2419933a20 100644 --- a/substrate/frame/aura/Cargo.toml +++ b/substrate/frame/aura/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME AURA consensus pallet" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/authority-discovery/Cargo.toml b/substrate/frame/authority-discovery/Cargo.toml index 7051276ad88..a1819965744 100644 --- a/substrate/frame/authority-discovery/Cargo.toml +++ b/substrate/frame/authority-discovery/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME pallet for authority discovery" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/authorship/Cargo.toml b/substrate/frame/authorship/Cargo.toml index 737c8da1361..41d4cf13972 100644 --- a/substrate/frame/authorship/Cargo.toml +++ b/substrate/frame/authorship/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/babe/Cargo.toml b/substrate/frame/babe/Cargo.toml index defa89b4f28..639b9544b0c 100644 --- a/substrate/frame/babe/Cargo.toml +++ b/substrate/frame/babe/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Consensus extension module for BABE consensus. Collects on-chain randomness from VRF outputs and manages epoch transitions." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/bags-list/Cargo.toml b/substrate/frame/bags-list/Cargo.toml index b99726ebf2d..198af21be81 100644 --- a/substrate/frame/bags-list/Cargo.toml +++ b/substrate/frame/bags-list/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "FRAME pallet bags list" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/bags-list/fuzzer/Cargo.toml b/substrate/frame/bags-list/fuzzer/Cargo.toml index f3785dd1bef..20760141b23 100644 --- a/substrate/frame/bags-list/fuzzer/Cargo.toml +++ b/substrate/frame/bags-list/fuzzer/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Fuzzer for FRAME pallet bags list" publish = false +[lints] +workspace = true + [dependencies] honggfuzz = "0.5" rand = { version = "0.8", features = ["small_rng", "std"] } diff --git a/substrate/frame/bags-list/remote-tests/Cargo.toml b/substrate/frame/bags-list/remote-tests/Cargo.toml index 169dd19db9a..fb61a986778 100644 --- a/substrate/frame/bags-list/remote-tests/Cargo.toml +++ b/substrate/frame/bags-list/remote-tests/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME pallet bags list remote test" publish = false +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/balances/Cargo.toml b/substrate/frame/balances/Cargo.toml index a148684e1fb..23fe6e58322 100644 --- a/substrate/frame/balances/Cargo.toml +++ b/substrate/frame/balances/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME pallet to manage balances" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/beefy-mmr/Cargo.toml b/substrate/frame/beefy-mmr/Cargo.toml index ee336def85c..7f647305456 100644 --- a/substrate/frame/beefy-mmr/Cargo.toml +++ b/substrate/frame/beefy-mmr/Cargo.toml @@ -8,6 +8,9 @@ description = "BEEFY + MMR runtime utilities" repository.workspace = true homepage = "https://substrate.io" +[lints] +workspace = true + [dependencies] array-bytes = { version = "6.1", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } diff --git a/substrate/frame/beefy/Cargo.toml b/substrate/frame/beefy/Cargo.toml index 4a77dd0e2ff..185e5487414 100644 --- a/substrate/frame/beefy/Cargo.toml +++ b/substrate/frame/beefy/Cargo.toml @@ -8,6 +8,9 @@ repository.workspace = true description = "BEEFY FRAME pallet" homepage = "https://substrate.io" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } diff --git a/substrate/frame/benchmarking/Cargo.toml b/substrate/frame/benchmarking/Cargo.toml index 9cfaac1abfd..980f70a5774 100644 --- a/substrate/frame/benchmarking/Cargo.toml +++ b/substrate/frame/benchmarking/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Macro for benchmarking a FRAME runtime." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/benchmarking/pov/Cargo.toml b/substrate/frame/benchmarking/pov/Cargo.toml index 1ec02828558..7c36b2f8eec 100644 --- a/substrate/frame/benchmarking/pov/Cargo.toml +++ b/substrate/frame/benchmarking/pov/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "Pallet for testing FRAME PoV benchmarking" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/bounties/Cargo.toml b/substrate/frame/bounties/Cargo.toml index 3b77a8448e3..16da862d488 100644 --- a/substrate/frame/bounties/Cargo.toml +++ b/substrate/frame/bounties/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME pallet to manage bounties" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/broker/Cargo.toml b/substrate/frame/broker/Cargo.toml index 3470cf55b78..77757c30463 100644 --- a/substrate/frame/broker/Cargo.toml +++ b/substrate/frame/broker/Cargo.toml @@ -8,6 +8,9 @@ edition.workspace = true license = "Apache-2.0" repository.workspace = true +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/child-bounties/Cargo.toml b/substrate/frame/child-bounties/Cargo.toml index 8e9d9c17238..6c1c362dc56 100644 --- a/substrate/frame/child-bounties/Cargo.toml +++ b/substrate/frame/child-bounties/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME pallet to manage child bounties" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/collective/Cargo.toml b/substrate/frame/collective/Cargo.toml index 672468450c2..fb0bace740c 100644 --- a/substrate/frame/collective/Cargo.toml +++ b/substrate/frame/collective/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Collective system: Members of a set of account IDs can make their collective feelings known through dispatched calls from one of two specialized origins." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/contracts/Cargo.toml b/substrate/frame/contracts/Cargo.toml index 29c39c047a3..4c6ca41ed56 100644 --- a/substrate/frame/contracts/Cargo.toml +++ b/substrate/frame/contracts/Cargo.toml @@ -11,6 +11,9 @@ description = "FRAME pallet for WASM contracts" readme = "README.md" include = ["CHANGELOG.md", "README.md", "benchmarks/**", "build.rs", "src/**/*"] +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/contracts/fixtures/Cargo.toml b/substrate/frame/contracts/fixtures/Cargo.toml index 1c247bf22c0..97606479f25 100644 --- a/substrate/frame/contracts/fixtures/Cargo.toml +++ b/substrate/frame/contracts/fixtures/Cargo.toml @@ -7,6 +7,9 @@ edition.workspace = true license.workspace = true description = "Fixtures for testing contracts pallet." +[lints] +workspace = true + [dependencies] wat = "1" frame-system = { path = "../../system" } diff --git a/substrate/frame/contracts/fixtures/contracts/common/Cargo.toml b/substrate/frame/contracts/fixtures/contracts/common/Cargo.toml index 127bb575088..377e8bc9dd5 100644 --- a/substrate/frame/contracts/fixtures/contracts/common/Cargo.toml +++ b/substrate/frame/contracts/fixtures/contracts/common/Cargo.toml @@ -6,3 +6,6 @@ authors.workspace = true edition.workspace = true license.workspace = true description = "Common utilities for pallet-contracts-fixtures." + +[lints] +workspace = true diff --git a/substrate/frame/contracts/mock-network/Cargo.toml b/substrate/frame/contracts/mock-network/Cargo.toml index 9c6231a783a..7b570eed155 100644 --- a/substrate/frame/contracts/mock-network/Cargo.toml +++ b/substrate/frame/contracts/mock-network/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "A mock network for testing pallet-contracts" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } diff --git a/substrate/frame/contracts/primitives/Cargo.toml b/substrate/frame/contracts/primitives/Cargo.toml index f821797c923..d1db766ce81 100644 --- a/substrate/frame/contracts/primitives/Cargo.toml +++ b/substrate/frame/contracts/primitives/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "A crate that hosts a common definitions that are relevant for the pallet-contracts." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/contracts/proc-macro/Cargo.toml b/substrate/frame/contracts/proc-macro/Cargo.toml index f05df18954c..573cd96d3ab 100644 --- a/substrate/frame/contracts/proc-macro/Cargo.toml +++ b/substrate/frame/contracts/proc-macro/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "Procedural macros used in pallet_contracts" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/contracts/uapi/Cargo.toml b/substrate/frame/contracts/uapi/Cargo.toml index df45872349d..f2901427282 100644 --- a/substrate/frame/contracts/uapi/Cargo.toml +++ b/substrate/frame/contracts/uapi/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "Exposes all the host functions that a contract can import." +[lints] +workspace = true + [dependencies] paste = { version = "1.0", default-features = false } bitflags = "1.0" diff --git a/substrate/frame/conviction-voting/Cargo.toml b/substrate/frame/conviction-voting/Cargo.toml index 19eb6d09fc1..6d96dde1aaa 100644 --- a/substrate/frame/conviction-voting/Cargo.toml +++ b/substrate/frame/conviction-voting/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME pallet for conviction voting in referenda" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/core-fellowship/Cargo.toml b/substrate/frame/core-fellowship/Cargo.toml index c6f99cdaab2..d223ecd4f24 100644 --- a/substrate/frame/core-fellowship/Cargo.toml +++ b/substrate/frame/core-fellowship/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Logic as per the description of The Fellowship for core Polkadot technology" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/democracy/Cargo.toml b/substrate/frame/democracy/Cargo.toml index 061eee106d4..7bfc8c6903b 100644 --- a/substrate/frame/democracy/Cargo.toml +++ b/substrate/frame/democracy/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME pallet for democracy" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/election-provider-multi-phase/Cargo.toml b/substrate/frame/election-provider-multi-phase/Cargo.toml index f1640f7cc70..be3a77065b4 100644 --- a/substrate/frame/election-provider-multi-phase/Cargo.toml +++ b/substrate/frame/election-provider-multi-phase/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "PALLET two phase election providers" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml b/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml index 44295d5e20d..05c6a6d4046 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME election provider multi phase pallet tests with staking pallet, bags-list and session pallets" publish = false +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/election-provider-support/Cargo.toml b/substrate/frame/election-provider-support/Cargo.toml index 7062e54cdbc..8182863d796 100644 --- a/substrate/frame/election-provider-support/Cargo.toml +++ b/substrate/frame/election-provider-support/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "election provider supporting traits" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/election-provider-support/benchmarking/Cargo.toml b/substrate/frame/election-provider-support/benchmarking/Cargo.toml index b1e3564b4d4..7a2ad5cafb4 100644 --- a/substrate/frame/election-provider-support/benchmarking/Cargo.toml +++ b/substrate/frame/election-provider-support/benchmarking/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "Benchmarking for election provider support onchain config trait" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/election-provider-support/solution-type/Cargo.toml b/substrate/frame/election-provider-support/solution-type/Cargo.toml index f81b366a5ec..ba36daebec3 100644 --- a/substrate/frame/election-provider-support/solution-type/Cargo.toml +++ b/substrate/frame/election-provider-support/solution-type/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "NPoS Solution Type" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml b/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml index 1f0261571a5..a7a84b91dba 100644 --- a/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml +++ b/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Fuzzer for phragmén solution type implementation." publish = false +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/elections-phragmen/Cargo.toml b/substrate/frame/elections-phragmen/Cargo.toml index ffb939fa4d2..3c0bc56a1d0 100644 --- a/substrate/frame/elections-phragmen/Cargo.toml +++ b/substrate/frame/elections-phragmen/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME pallet based on seq-Phragmén election method." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/examples/Cargo.toml b/substrate/frame/examples/Cargo.toml index b272a15dd63..eb6355edd31 100644 --- a/substrate/frame/examples/Cargo.toml +++ b/substrate/frame/examples/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "The single package with examples of various types of FRAME pallets" publish = false +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/examples/basic/Cargo.toml b/substrate/frame/examples/basic/Cargo.toml index 53da9ac2eba..3be1a2e558d 100644 --- a/substrate/frame/examples/basic/Cargo.toml +++ b/substrate/frame/examples/basic/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME example pallet" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/examples/default-config/Cargo.toml b/substrate/frame/examples/default-config/Cargo.toml index 0d80e6838f0..01ddf9d3834 100644 --- a/substrate/frame/examples/default-config/Cargo.toml +++ b/substrate/frame/examples/default-config/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME example pallet demonstrating derive_impl / default_config in action" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/examples/dev-mode/Cargo.toml b/substrate/frame/examples/dev-mode/Cargo.toml index ce558fe087b..f634d21cf2c 100644 --- a/substrate/frame/examples/dev-mode/Cargo.toml +++ b/substrate/frame/examples/dev-mode/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME example pallet" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/examples/frame-crate/Cargo.toml b/substrate/frame/examples/frame-crate/Cargo.toml index 586b6c0216e..93a46ba7b24 100644 --- a/substrate/frame/examples/frame-crate/Cargo.toml +++ b/substrate/frame/examples/frame-crate/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME example pallet with umbrella crate" publish = false +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/examples/kitchensink/Cargo.toml b/substrate/frame/examples/kitchensink/Cargo.toml index 3b3b7a3761a..4255ebb66b6 100644 --- a/substrate/frame/examples/kitchensink/Cargo.toml +++ b/substrate/frame/examples/kitchensink/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME example kitchensink pallet" publish = false +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/examples/offchain-worker/Cargo.toml b/substrate/frame/examples/offchain-worker/Cargo.toml index 9d0b682ee02..464719375c6 100644 --- a/substrate/frame/examples/offchain-worker/Cargo.toml +++ b/substrate/frame/examples/offchain-worker/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME example pallet for offchain worker" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/examples/split/Cargo.toml b/substrate/frame/examples/split/Cargo.toml index b6b9ea86dfe..97f9062f181 100644 --- a/substrate/frame/examples/split/Cargo.toml +++ b/substrate/frame/examples/split/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME example splitted pallet" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/examples/tasks/Cargo.toml b/substrate/frame/examples/tasks/Cargo.toml index e26e822e40f..046bad908d1 100644 --- a/substrate/frame/examples/tasks/Cargo.toml +++ b/substrate/frame/examples/tasks/Cargo.toml @@ -7,6 +7,9 @@ license.workspace = true repository.workspace = true description = "Pallet to demonstrate the usage of Tasks to recongnize and execute service work" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/executive/Cargo.toml b/substrate/frame/executive/Cargo.toml index c2a92ad3d72..b98ceb0ba9a 100644 --- a/substrate/frame/executive/Cargo.toml +++ b/substrate/frame/executive/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME executives engine" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/fast-unstake/Cargo.toml b/substrate/frame/fast-unstake/Cargo.toml index 4440a0c0f64..673a2f71d6c 100644 --- a/substrate/frame/fast-unstake/Cargo.toml +++ b/substrate/frame/fast-unstake/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "FRAME fast unstake pallet" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/glutton/Cargo.toml b/substrate/frame/glutton/Cargo.toml index 81388d0e0f5..068fb4e821c 100644 --- a/substrate/frame/glutton/Cargo.toml +++ b/substrate/frame/glutton/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME pallet for pushing a chain to its weight limits" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/grandpa/Cargo.toml b/substrate/frame/grandpa/Cargo.toml index b4444d4580c..b4f51d88c6d 100644 --- a/substrate/frame/grandpa/Cargo.toml +++ b/substrate/frame/grandpa/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME pallet for GRANDPA finality gadget" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/identity/Cargo.toml b/substrate/frame/identity/Cargo.toml index 894365748ce..a562d7607b4 100644 --- a/substrate/frame/identity/Cargo.toml +++ b/substrate/frame/identity/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME identity management pallet" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/im-online/Cargo.toml b/substrate/frame/im-online/Cargo.toml index 5ec260c9b5b..b5b01858c89 100644 --- a/substrate/frame/im-online/Cargo.toml +++ b/substrate/frame/im-online/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME's I'm online pallet" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/indices/Cargo.toml b/substrate/frame/indices/Cargo.toml index 4f12ecfcce3..4f0c780c6af 100644 --- a/substrate/frame/indices/Cargo.toml +++ b/substrate/frame/indices/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME indices management pallet" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/insecure-randomness-collective-flip/Cargo.toml b/substrate/frame/insecure-randomness-collective-flip/Cargo.toml index f7afbb95397..fb1447d1045 100644 --- a/substrate/frame/insecure-randomness-collective-flip/Cargo.toml +++ b/substrate/frame/insecure-randomness-collective-flip/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Insecure do not use in production: FRAME randomness collective flip pallet" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/lottery/Cargo.toml b/substrate/frame/lottery/Cargo.toml index bba17d2718c..49f84b04b25 100644 --- a/substrate/frame/lottery/Cargo.toml +++ b/substrate/frame/lottery/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "FRAME Participation Lottery Pallet" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/membership/Cargo.toml b/substrate/frame/membership/Cargo.toml index f90d70e911d..c4c94e202a4 100644 --- a/substrate/frame/membership/Cargo.toml +++ b/substrate/frame/membership/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME membership management pallet" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/merkle-mountain-range/Cargo.toml b/substrate/frame/merkle-mountain-range/Cargo.toml index 1f31e704928..eaa17d88e99 100644 --- a/substrate/frame/merkle-mountain-range/Cargo.toml +++ b/substrate/frame/merkle-mountain-range/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "FRAME Merkle Mountain Range pallet." +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/message-queue/Cargo.toml b/substrate/frame/message-queue/Cargo.toml index 614e5885b4b..b5162d70ccb 100644 --- a/substrate/frame/message-queue/Cargo.toml +++ b/substrate/frame/message-queue/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "FRAME pallet to queue and process messages" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } diff --git a/substrate/frame/mixnet/Cargo.toml b/substrate/frame/mixnet/Cargo.toml index de5f7411015..949003864a2 100644 --- a/substrate/frame/mixnet/Cargo.toml +++ b/substrate/frame/mixnet/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/multisig/Cargo.toml b/substrate/frame/multisig/Cargo.toml index f1ff19c0e34..40b0f4973a8 100644 --- a/substrate/frame/multisig/Cargo.toml +++ b/substrate/frame/multisig/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME multi-signature dispatch pallet" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/nft-fractionalization/Cargo.toml b/substrate/frame/nft-fractionalization/Cargo.toml index 19814d67d79..355bb2a5d3e 100644 --- a/substrate/frame/nft-fractionalization/Cargo.toml +++ b/substrate/frame/nft-fractionalization/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME pallet to convert non-fungible to fungible tokens." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/nfts/Cargo.toml b/substrate/frame/nfts/Cargo.toml index a70b55bc45e..0d3f542c552 100644 --- a/substrate/frame/nfts/Cargo.toml +++ b/substrate/frame/nfts/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME NFTs pallet" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/nfts/runtime-api/Cargo.toml b/substrate/frame/nfts/runtime-api/Cargo.toml index 8e1424a588a..8eb6726552b 100644 --- a/substrate/frame/nfts/runtime-api/Cargo.toml +++ b/substrate/frame/nfts/runtime-api/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Runtime API for the FRAME NFTs pallet." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/nicks/Cargo.toml b/substrate/frame/nicks/Cargo.toml index 8636ac34a13..7d43f64cfe2 100644 --- a/substrate/frame/nicks/Cargo.toml +++ b/substrate/frame/nicks/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME pallet for nick management" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/nis/Cargo.toml b/substrate/frame/nis/Cargo.toml index ec251ef6536..f95ebc5864c 100644 --- a/substrate/frame/nis/Cargo.toml +++ b/substrate/frame/nis/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME pallet for rewarding account freezing." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/node-authorization/Cargo.toml b/substrate/frame/node-authorization/Cargo.toml index abc03a8b0f4..46fc0b34514 100644 --- a/substrate/frame/node-authorization/Cargo.toml +++ b/substrate/frame/node-authorization/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "FRAME pallet for node authorization" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/nomination-pools/Cargo.toml b/substrate/frame/nomination-pools/Cargo.toml index bc24deb6f15..00c90b414de 100644 --- a/substrate/frame/nomination-pools/Cargo.toml +++ b/substrate/frame/nomination-pools/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "FRAME nomination pools pallet" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/nomination-pools/benchmarking/Cargo.toml b/substrate/frame/nomination-pools/benchmarking/Cargo.toml index d522dff82ba..8a4ee07dd74 100644 --- a/substrate/frame/nomination-pools/benchmarking/Cargo.toml +++ b/substrate/frame/nomination-pools/benchmarking/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME nomination pools pallet benchmarking" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/nomination-pools/fuzzer/Cargo.toml b/substrate/frame/nomination-pools/fuzzer/Cargo.toml index b9d0a6197f8..52f49b28457 100644 --- a/substrate/frame/nomination-pools/fuzzer/Cargo.toml +++ b/substrate/frame/nomination-pools/fuzzer/Cargo.toml @@ -10,6 +10,9 @@ description = "Fuzzer for fixed point arithmetic primitives." documentation = "https://docs.rs/sp-arithmetic-fuzzer" publish = false +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/nomination-pools/runtime-api/Cargo.toml b/substrate/frame/nomination-pools/runtime-api/Cargo.toml index 86d1496a41b..12a897cc6b6 100644 --- a/substrate/frame/nomination-pools/runtime-api/Cargo.toml +++ b/substrate/frame/nomination-pools/runtime-api/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Runtime API for nomination-pools FRAME pallet" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/nomination-pools/test-staking/Cargo.toml b/substrate/frame/nomination-pools/test-staking/Cargo.toml index f0558f83142..845535ae04f 100644 --- a/substrate/frame/nomination-pools/test-staking/Cargo.toml +++ b/substrate/frame/nomination-pools/test-staking/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME nomination pools pallet tests with the staking pallet" publish = false +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/offences/Cargo.toml b/substrate/frame/offences/Cargo.toml index 0f153d9eca6..df0fb015e95 100644 --- a/substrate/frame/offences/Cargo.toml +++ b/substrate/frame/offences/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME offences pallet" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/offences/benchmarking/Cargo.toml b/substrate/frame/offences/benchmarking/Cargo.toml index 4de239296a9..cddbd6aa4d5 100644 --- a/substrate/frame/offences/benchmarking/Cargo.toml +++ b/substrate/frame/offences/benchmarking/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME offences pallet benchmarking" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/paged-list/Cargo.toml b/substrate/frame/paged-list/Cargo.toml index 676e1866a43..2370f84898b 100644 --- a/substrate/frame/paged-list/Cargo.toml +++ b/substrate/frame/paged-list/Cargo.toml @@ -8,6 +8,9 @@ edition.workspace = true license = "Apache-2.0" repository.workspace = true +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/paged-list/fuzzer/Cargo.toml b/substrate/frame/paged-list/fuzzer/Cargo.toml index d6590373813..5c245cc72c7 100644 --- a/substrate/frame/paged-list/fuzzer/Cargo.toml +++ b/substrate/frame/paged-list/fuzzer/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Fuzz storage types of pallet-paged-list" publish = false +[lints] +workspace = true + [[bin]] name = "pallet-paged-list-fuzzer" path = "src/paged_list.rs" diff --git a/substrate/frame/preimage/Cargo.toml b/substrate/frame/preimage/Cargo.toml index 1806976ac96..2aa21d2a713 100644 --- a/substrate/frame/preimage/Cargo.toml +++ b/substrate/frame/preimage/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "FRAME pallet for storing preimages of hashes" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } diff --git a/substrate/frame/proxy/Cargo.toml b/substrate/frame/proxy/Cargo.toml index 00a2692a820..fd163e71bc1 100644 --- a/substrate/frame/proxy/Cargo.toml +++ b/substrate/frame/proxy/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME proxying pallet" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/ranked-collective/Cargo.toml b/substrate/frame/ranked-collective/Cargo.toml index 145eff3b0ee..39075b2abf9 100644 --- a/substrate/frame/ranked-collective/Cargo.toml +++ b/substrate/frame/ranked-collective/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Ranked collective system: Members of a set of account IDs can make their collective feelings known through dispatched calls from one of two specialized origins." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/recovery/Cargo.toml b/substrate/frame/recovery/Cargo.toml index d2cd2d1a4ca..6afd494bf7e 100644 --- a/substrate/frame/recovery/Cargo.toml +++ b/substrate/frame/recovery/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME account recovery pallet" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/referenda/Cargo.toml b/substrate/frame/referenda/Cargo.toml index 1747d0ac22b..f76dbece303 100644 --- a/substrate/frame/referenda/Cargo.toml +++ b/substrate/frame/referenda/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME pallet for inclusive on-chain decisions" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/remark/Cargo.toml b/substrate/frame/remark/Cargo.toml index 9b0c6870d05..646563bdb08 100644 --- a/substrate/frame/remark/Cargo.toml +++ b/substrate/frame/remark/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Remark storage pallet" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/root-offences/Cargo.toml b/substrate/frame/root-offences/Cargo.toml index a17bd51684e..0f3d3a2883d 100644 --- a/substrate/frame/root-offences/Cargo.toml +++ b/substrate/frame/root-offences/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME root offences pallet" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/root-testing/Cargo.toml b/substrate/frame/root-testing/Cargo.toml index f4e914c86b1..78aed99a56d 100644 --- a/substrate/frame/root-testing/Cargo.toml +++ b/substrate/frame/root-testing/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME root testing pallet" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/safe-mode/Cargo.toml b/substrate/frame/safe-mode/Cargo.toml index d33e0b7144a..f86332483c4 100644 --- a/substrate/frame/safe-mode/Cargo.toml +++ b/substrate/frame/safe-mode/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "FRAME safe-mode pallet" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/salary/Cargo.toml b/substrate/frame/salary/Cargo.toml index 18636a60cdb..929151a9c20 100644 --- a/substrate/frame/salary/Cargo.toml +++ b/substrate/frame/salary/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Paymaster" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/sassafras/Cargo.toml b/substrate/frame/sassafras/Cargo.toml index 745297bd416..ad4c0ba12f0 100644 --- a/substrate/frame/sassafras/Cargo.toml +++ b/substrate/frame/sassafras/Cargo.toml @@ -10,6 +10,9 @@ description = "Consensus extension module for Sassafras consensus." readme = "README.md" publish = false +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/scheduler/Cargo.toml b/substrate/frame/scheduler/Cargo.toml index 1dd2e53d054..c27276c607e 100644 --- a/substrate/frame/scheduler/Cargo.toml +++ b/substrate/frame/scheduler/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME Scheduler pallet" readme = "README.md" +[lints] +workspace = true + [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } diff --git a/substrate/frame/scored-pool/Cargo.toml b/substrate/frame/scored-pool/Cargo.toml index 8293c81f590..7a534ddd79d 100644 --- a/substrate/frame/scored-pool/Cargo.toml +++ b/substrate/frame/scored-pool/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME pallet for scored pools" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/session/Cargo.toml b/substrate/frame/session/Cargo.toml index 0a997f6ddb3..4589dbb427a 100644 --- a/substrate/frame/session/Cargo.toml +++ b/substrate/frame/session/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME sessions pallet" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/session/benchmarking/Cargo.toml b/substrate/frame/session/benchmarking/Cargo.toml index db2b8b72209..16f85048d8d 100644 --- a/substrate/frame/session/benchmarking/Cargo.toml +++ b/substrate/frame/session/benchmarking/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME sessions pallet benchmarking" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/society/Cargo.toml b/substrate/frame/society/Cargo.toml index 045993290af..46b4f7a7d66 100644 --- a/substrate/frame/society/Cargo.toml +++ b/substrate/frame/society/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME society pallet" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/staking/Cargo.toml b/substrate/frame/staking/Cargo.toml index 1510d90ed58..31831fd7ed2 100644 --- a/substrate/frame/staking/Cargo.toml +++ b/substrate/frame/staking/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME pallet staking" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/staking/reward-curve/Cargo.toml b/substrate/frame/staking/reward-curve/Cargo.toml index 136cdd7d1b0..e33fd255fa8 100644 --- a/substrate/frame/staking/reward-curve/Cargo.toml +++ b/substrate/frame/staking/reward-curve/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "Reward Curve for FRAME staking pallet" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/staking/reward-fn/Cargo.toml b/substrate/frame/staking/reward-fn/Cargo.toml index 001c2b62656..80a27cc0f53 100644 --- a/substrate/frame/staking/reward-fn/Cargo.toml +++ b/substrate/frame/staking/reward-fn/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "Reward function for FRAME staking pallet" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/staking/runtime-api/Cargo.toml b/substrate/frame/staking/runtime-api/Cargo.toml index 061124fd184..b3fd4cfda01 100644 --- a/substrate/frame/staking/runtime-api/Cargo.toml +++ b/substrate/frame/staking/runtime-api/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "RPC runtime API for transaction payment FRAME pallet" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/state-trie-migration/Cargo.toml b/substrate/frame/state-trie-migration/Cargo.toml index a3e6edd5aee..46f86d203c3 100644 --- a/substrate/frame/state-trie-migration/Cargo.toml +++ b/substrate/frame/state-trie-migration/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "FRAME pallet migration of trie" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/statement/Cargo.toml b/substrate/frame/statement/Cargo.toml index e4caf241233..d41afc3244b 100644 --- a/substrate/frame/statement/Cargo.toml +++ b/substrate/frame/statement/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "FRAME pallet for statement store" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/sudo/Cargo.toml b/substrate/frame/sudo/Cargo.toml index 70323590085..027716ce317 100644 --- a/substrate/frame/sudo/Cargo.toml +++ b/substrate/frame/sudo/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME pallet for sudo" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/support/Cargo.toml b/substrate/frame/support/Cargo.toml index 6d253f29c3f..07f9075c82b 100644 --- a/substrate/frame/support/Cargo.toml +++ b/substrate/frame/support/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Support code for the runtime." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/support/procedural/Cargo.toml b/substrate/frame/support/procedural/Cargo.toml index 769cb9f1cfb..08995c578c5 100644 --- a/substrate/frame/support/procedural/Cargo.toml +++ b/substrate/frame/support/procedural/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "Proc macro of Support code for the runtime." +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/support/procedural/tools/Cargo.toml b/substrate/frame/support/procedural/tools/Cargo.toml index 9be7a029ef9..5fffe3eeced 100644 --- a/substrate/frame/support/procedural/tools/Cargo.toml +++ b/substrate/frame/support/procedural/tools/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "Proc macro helpers for procedural macros" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/support/procedural/tools/derive/Cargo.toml b/substrate/frame/support/procedural/tools/derive/Cargo.toml index dc2774cb177..9b6122b26fd 100644 --- a/substrate/frame/support/procedural/tools/derive/Cargo.toml +++ b/substrate/frame/support/procedural/tools/derive/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "Use to derive parsing for parsing struct." +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/support/test/Cargo.toml b/substrate/frame/support/test/Cargo.toml index b88a459d92f..8ee1b4b2918 100644 --- a/substrate/frame/support/test/Cargo.toml +++ b/substrate/frame/support/test/Cargo.toml @@ -8,6 +8,9 @@ publish = false homepage = "https://substrate.io" repository.workspace = true +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/support/test/compile_pass/Cargo.toml b/substrate/frame/support/test/compile_pass/Cargo.toml index 916771bd471..0617aa105a2 100644 --- a/substrate/frame/support/test/compile_pass/Cargo.toml +++ b/substrate/frame/support/test/compile_pass/Cargo.toml @@ -8,6 +8,9 @@ publish = false homepage = "https://substrate.io" repository.workspace = true +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/support/test/pallet/Cargo.toml b/substrate/frame/support/test/pallet/Cargo.toml index e1136d5bc02..493c305cb20 100644 --- a/substrate/frame/support/test/pallet/Cargo.toml +++ b/substrate/frame/support/test/pallet/Cargo.toml @@ -8,6 +8,9 @@ publish = false homepage = "https://substrate.io" repository.workspace = true +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/support/test/stg_frame_crate/Cargo.toml b/substrate/frame/support/test/stg_frame_crate/Cargo.toml index 0b3b584910a..632ea4e794f 100644 --- a/substrate/frame/support/test/stg_frame_crate/Cargo.toml +++ b/substrate/frame/support/test/stg_frame_crate/Cargo.toml @@ -8,6 +8,9 @@ publish = false homepage = "https://substrate.io" repository.workspace = true +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/system/Cargo.toml b/substrate/frame/system/Cargo.toml index 3b454ac18f9..2491ccd220c 100644 --- a/substrate/frame/system/Cargo.toml +++ b/substrate/frame/system/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME system module" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/system/benchmarking/Cargo.toml b/substrate/frame/system/benchmarking/Cargo.toml index 3e92c56408e..8b9873f44b8 100644 --- a/substrate/frame/system/benchmarking/Cargo.toml +++ b/substrate/frame/system/benchmarking/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME System benchmarking" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/system/rpc/runtime-api/Cargo.toml b/substrate/frame/system/rpc/runtime-api/Cargo.toml index 68dc7fc9905..8cec5de8d1e 100644 --- a/substrate/frame/system/rpc/runtime-api/Cargo.toml +++ b/substrate/frame/system/rpc/runtime-api/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Runtime API definition required by System RPC extensions." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/timestamp/Cargo.toml b/substrate/frame/timestamp/Cargo.toml index fd14216bdb3..bcf26d622b0 100644 --- a/substrate/frame/timestamp/Cargo.toml +++ b/substrate/frame/timestamp/Cargo.toml @@ -10,6 +10,9 @@ description = "FRAME Timestamp Module" documentation = "https://docs.rs/pallet-timestamp" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/tips/Cargo.toml b/substrate/frame/tips/Cargo.toml index a86034d92f5..fbd6404d785 100644 --- a/substrate/frame/tips/Cargo.toml +++ b/substrate/frame/tips/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME pallet to manage tips" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/transaction-payment/Cargo.toml b/substrate/frame/transaction-payment/Cargo.toml index c431f7f8243..5ebaa8c98ad 100644 --- a/substrate/frame/transaction-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME pallet to manage transaction payments" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml b/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml index 7d15740e824..0bfe37a5267 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Pallet to manage transaction payments in assets by converting them to native assets." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml b/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml index 9a614316e53..be1bd36231c 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "pallet to manage transaction payments in assets" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/transaction-payment/rpc/Cargo.toml b/substrate/frame/transaction-payment/rpc/Cargo.toml index 048b7da63f6..5a574a944d8 100644 --- a/substrate/frame/transaction-payment/rpc/Cargo.toml +++ b/substrate/frame/transaction-payment/rpc/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "RPC interface for the transaction payment pallet." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/transaction-payment/rpc/runtime-api/Cargo.toml b/substrate/frame/transaction-payment/rpc/runtime-api/Cargo.toml index 17213392e1c..e384fcef692 100644 --- a/substrate/frame/transaction-payment/rpc/runtime-api/Cargo.toml +++ b/substrate/frame/transaction-payment/rpc/runtime-api/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "RPC runtime API for transaction payment FRAME pallet" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/transaction-payment/skip-feeless-payment/Cargo.toml b/substrate/frame/transaction-payment/skip-feeless-payment/Cargo.toml index 25a708d69de..0e3744626d3 100644 --- a/substrate/frame/transaction-payment/skip-feeless-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/skip-feeless-payment/Cargo.toml @@ -7,6 +7,9 @@ license.workspace = true repository.workspace = true description = "Pallet to skip payments for calls annotated with `feeless_if` if the respective conditions are satisfied." +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/transaction-storage/Cargo.toml b/substrate/frame/transaction-storage/Cargo.toml index a2df1a3ce2a..f2c65e3b8a5 100644 --- a/substrate/frame/transaction-storage/Cargo.toml +++ b/substrate/frame/transaction-storage/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Storage chain pallet" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/treasury/Cargo.toml b/substrate/frame/treasury/Cargo.toml index 298c52d0e48..3286f4d7f34 100644 --- a/substrate/frame/treasury/Cargo.toml +++ b/substrate/frame/treasury/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME pallet to manage treasury" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/try-runtime/Cargo.toml b/substrate/frame/try-runtime/Cargo.toml index 4dd51647174..1d036e00447 100644 --- a/substrate/frame/try-runtime/Cargo.toml +++ b/substrate/frame/try-runtime/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "FRAME pallet for democracy" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/tx-pause/Cargo.toml b/substrate/frame/tx-pause/Cargo.toml index 60623bb9d38..5958dcc2c30 100644 --- a/substrate/frame/tx-pause/Cargo.toml +++ b/substrate/frame/tx-pause/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "FRAME transaction pause pallet" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/uniques/Cargo.toml b/substrate/frame/uniques/Cargo.toml index 300b319ede0..218b4ffe4c0 100644 --- a/substrate/frame/uniques/Cargo.toml +++ b/substrate/frame/uniques/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME NFT asset management pallet" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/utility/Cargo.toml b/substrate/frame/utility/Cargo.toml index 73c25a60daf..4aa75f9f616 100644 --- a/substrate/frame/utility/Cargo.toml +++ b/substrate/frame/utility/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME utilities pallet" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/vesting/Cargo.toml b/substrate/frame/vesting/Cargo.toml index 37339d87aea..3b5252d6181 100644 --- a/substrate/frame/vesting/Cargo.toml +++ b/substrate/frame/vesting/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME pallet for manage vesting" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/frame/whitelist/Cargo.toml b/substrate/frame/whitelist/Cargo.toml index 0d7ab6c2967..5d9a362f9aa 100644 --- a/substrate/frame/whitelist/Cargo.toml +++ b/substrate/frame/whitelist/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "FRAME pallet for whitelisting call, and dispatch from specific origin" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/api/Cargo.toml b/substrate/primitives/api/Cargo.toml index 1be131a7b4f..345647cec25 100644 --- a/substrate/primitives/api/Cargo.toml +++ b/substrate/primitives/api/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Substrate runtime api primitives" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/api/proc-macro/Cargo.toml b/substrate/primitives/api/proc-macro/Cargo.toml index c66a7c65d11..544a48062d7 100644 --- a/substrate/primitives/api/proc-macro/Cargo.toml +++ b/substrate/primitives/api/proc-macro/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Macros for declaring and implementing runtime apis." documentation = "https://docs.rs/sp-api-proc-macro" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/api/test/Cargo.toml b/substrate/primitives/api/test/Cargo.toml index f207f5ff02d..0346ad270ab 100644 --- a/substrate/primitives/api/test/Cargo.toml +++ b/substrate/primitives/api/test/Cargo.toml @@ -8,6 +8,9 @@ publish = false homepage = "https://substrate.io" repository.workspace = true +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/application-crypto/Cargo.toml b/substrate/primitives/application-crypto/Cargo.toml index a6c937a3469..33bc22ed84f 100644 --- a/substrate/primitives/application-crypto/Cargo.toml +++ b/substrate/primitives/application-crypto/Cargo.toml @@ -10,6 +10,9 @@ repository.workspace = true documentation = "https://docs.rs/sp-application-crypto" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/application-crypto/test/Cargo.toml b/substrate/primitives/application-crypto/test/Cargo.toml index d9fb743e8cd..0057606b38e 100644 --- a/substrate/primitives/application-crypto/test/Cargo.toml +++ b/substrate/primitives/application-crypto/test/Cargo.toml @@ -9,6 +9,9 @@ publish = false homepage = "https://substrate.io" repository.workspace = true +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/arithmetic/Cargo.toml b/substrate/primitives/arithmetic/Cargo.toml index ecd3d9585bc..f7f1da6a913 100644 --- a/substrate/primitives/arithmetic/Cargo.toml +++ b/substrate/primitives/arithmetic/Cargo.toml @@ -10,6 +10,9 @@ description = "Minimal fixed point arithmetic primitives and types for runtime." documentation = "https://docs.rs/sp-arithmetic" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/arithmetic/fuzzer/Cargo.toml b/substrate/primitives/arithmetic/fuzzer/Cargo.toml index eded5a954c5..b881e8d46db 100644 --- a/substrate/primitives/arithmetic/fuzzer/Cargo.toml +++ b/substrate/primitives/arithmetic/fuzzer/Cargo.toml @@ -10,6 +10,9 @@ description = "Fuzzer for fixed point arithmetic primitives." documentation = "https://docs.rs/sp-arithmetic-fuzzer" publish = false +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/authority-discovery/Cargo.toml b/substrate/primitives/authority-discovery/Cargo.toml index c8a93980be2..82ec5a3eb9a 100644 --- a/substrate/primitives/authority-discovery/Cargo.toml +++ b/substrate/primitives/authority-discovery/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/block-builder/Cargo.toml b/substrate/primitives/block-builder/Cargo.toml index a574689811b..de1ffd9d9e6 100644 --- a/substrate/primitives/block-builder/Cargo.toml +++ b/substrate/primitives/block-builder/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "The block builder runtime api." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/blockchain/Cargo.toml b/substrate/primitives/blockchain/Cargo.toml index 33db09ce0ac..38b3b2030dc 100644 --- a/substrate/primitives/blockchain/Cargo.toml +++ b/substrate/primitives/blockchain/Cargo.toml @@ -10,6 +10,9 @@ description = "Substrate blockchain traits and primitives." documentation = "https://docs.rs/sp-blockchain" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/consensus/aura/Cargo.toml b/substrate/primitives/consensus/aura/Cargo.toml index 4a19999a469..15159f62611 100644 --- a/substrate/primitives/consensus/aura/Cargo.toml +++ b/substrate/primitives/consensus/aura/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/consensus/babe/Cargo.toml b/substrate/primitives/consensus/babe/Cargo.toml index 6ec50ea022b..72cee3604d5 100644 --- a/substrate/primitives/consensus/babe/Cargo.toml +++ b/substrate/primitives/consensus/babe/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/consensus/beefy/Cargo.toml b/substrate/primitives/consensus/beefy/Cargo.toml index 916125d783d..42383cf14a8 100644 --- a/substrate/primitives/consensus/beefy/Cargo.toml +++ b/substrate/primitives/consensus/beefy/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "Primitives for BEEFY protocol." +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/consensus/common/Cargo.toml b/substrate/primitives/consensus/common/Cargo.toml index e8f6b806f8c..066578406b6 100644 --- a/substrate/primitives/consensus/common/Cargo.toml +++ b/substrate/primitives/consensus/common/Cargo.toml @@ -10,6 +10,9 @@ description = "Common utilities for building and using consensus engines in subs documentation = "https://docs.rs/sp-consensus/" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/consensus/grandpa/Cargo.toml b/substrate/primitives/consensus/grandpa/Cargo.toml index 1ddc89df983..238c9868664 100644 --- a/substrate/primitives/consensus/grandpa/Cargo.toml +++ b/substrate/primitives/consensus/grandpa/Cargo.toml @@ -10,6 +10,9 @@ description = "Primitives for GRANDPA integration, suitable for WASM compilation documentation = "https://docs.rs/sp-consensus-grandpa" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/consensus/pow/Cargo.toml b/substrate/primitives/consensus/pow/Cargo.toml index 5e134eb2a29..e528d8365ce 100644 --- a/substrate/primitives/consensus/pow/Cargo.toml +++ b/substrate/primitives/consensus/pow/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/consensus/sassafras/Cargo.toml b/substrate/primitives/consensus/sassafras/Cargo.toml index e71f82b4382..41385e9d1e9 100644 --- a/substrate/primitives/consensus/sassafras/Cargo.toml +++ b/substrate/primitives/consensus/sassafras/Cargo.toml @@ -11,6 +11,9 @@ documentation = "https://docs.rs/sp-consensus-sassafras" readme = "README.md" publish = false +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/consensus/slots/Cargo.toml b/substrate/primitives/consensus/slots/Cargo.toml index 12940583757..91bbd1663a9 100644 --- a/substrate/primitives/consensus/slots/Cargo.toml +++ b/substrate/primitives/consensus/slots/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index a7c4b49fcb8..cb36d7bb6b4 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Shareable Substrate types." documentation = "https://docs.rs/sp-core" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/core/fuzz/Cargo.toml b/substrate/primitives/core/fuzz/Cargo.toml index 9a094b07d4a..c6b5a065b6d 100644 --- a/substrate/primitives/core/fuzz/Cargo.toml +++ b/substrate/primitives/core/fuzz/Cargo.toml @@ -3,6 +3,9 @@ name = "sp-core-fuzz" version = "0.0.0" publish = false +[lints] +workspace = true + [package.metadata] cargo-fuzz = true diff --git a/substrate/primitives/core/hashing/Cargo.toml b/substrate/primitives/core/hashing/Cargo.toml index 7b4f4bc7438..011d312ba90 100644 --- a/substrate/primitives/core/hashing/Cargo.toml +++ b/substrate/primitives/core/hashing/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Primitive core crate hashing implementation." documentation = "https://docs.rs/sp-core-hashing" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/core/hashing/proc-macro/Cargo.toml b/substrate/primitives/core/hashing/proc-macro/Cargo.toml index a16bec5a2a1..312edd85044 100644 --- a/substrate/primitives/core/hashing/proc-macro/Cargo.toml +++ b/substrate/primitives/core/hashing/proc-macro/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "This crate provides procedural macros for calculating static hash." documentation = "https://docs.rs/sp-core-hashing-proc-macro" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/crypto/ec-utils/Cargo.toml b/substrate/primitives/crypto/ec-utils/Cargo.toml index 7519fa5fc68..3baa8ea5b78 100644 --- a/substrate/primitives/crypto/ec-utils/Cargo.toml +++ b/substrate/primitives/crypto/ec-utils/Cargo.toml @@ -8,6 +8,9 @@ license = "Apache-2.0" homepage = "https://substrate.io" repository.workspace = true +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/database/Cargo.toml b/substrate/primitives/database/Cargo.toml index 430895236d4..00ccf97c83e 100644 --- a/substrate/primitives/database/Cargo.toml +++ b/substrate/primitives/database/Cargo.toml @@ -10,6 +10,9 @@ description = "Substrate database trait." documentation = "https://docs.rs/sp-database" readme = "README.md" +[lints] +workspace = true + [dependencies] kvdb = "0.13.0" parking_lot = "0.12.1" diff --git a/substrate/primitives/debug-derive/Cargo.toml b/substrate/primitives/debug-derive/Cargo.toml index 0662cd309ed..acf281f306a 100644 --- a/substrate/primitives/debug-derive/Cargo.toml +++ b/substrate/primitives/debug-derive/Cargo.toml @@ -9,6 +9,8 @@ repository.workspace = true description = "Macros to derive runtime debug implementation." documentation = "https://docs.rs/sp-debug-derive" +[lints] +workspace = true [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/externalities/Cargo.toml b/substrate/primitives/externalities/Cargo.toml index 86d31c31cba..4c7afc38b81 100644 --- a/substrate/primitives/externalities/Cargo.toml +++ b/substrate/primitives/externalities/Cargo.toml @@ -10,6 +10,9 @@ description = "Substrate externalities abstraction" documentation = "https://docs.rs/sp-externalities" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/genesis-builder/Cargo.toml b/substrate/primitives/genesis-builder/Cargo.toml index 00b3bc876ac..b376055d605 100644 --- a/substrate/primitives/genesis-builder/Cargo.toml +++ b/substrate/primitives/genesis-builder/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Substrate GenesisConfig builder API" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/inherents/Cargo.toml b/substrate/primitives/inherents/Cargo.toml index 2b5bad5d746..e011e9ce9b8 100644 --- a/substrate/primitives/inherents/Cargo.toml +++ b/substrate/primitives/inherents/Cargo.toml @@ -10,6 +10,9 @@ description = "Provides types and traits for creating and checking inherents." documentation = "https://docs.rs/sp-inherents" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/io/Cargo.toml b/substrate/primitives/io/Cargo.toml index 5239860c710..9671880069a 100644 --- a/substrate/primitives/io/Cargo.toml +++ b/substrate/primitives/io/Cargo.toml @@ -11,6 +11,9 @@ documentation = "https://docs.rs/sp-io" readme = "README.md" build = "build.rs" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/keyring/Cargo.toml b/substrate/primitives/keyring/Cargo.toml index 5b58a4f97ca..80d773b452a 100644 --- a/substrate/primitives/keyring/Cargo.toml +++ b/substrate/primitives/keyring/Cargo.toml @@ -10,6 +10,9 @@ description = "Keyring support code for the runtime. A set of test accounts." documentation = "https://docs.rs/sp-keyring" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/keystore/Cargo.toml b/substrate/primitives/keystore/Cargo.toml index dcfb272c11a..d60f5d6c568 100644 --- a/substrate/primitives/keystore/Cargo.toml +++ b/substrate/primitives/keystore/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Keystore primitives." documentation = "https://docs.rs/sp-core" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/maybe-compressed-blob/Cargo.toml b/substrate/primitives/maybe-compressed-blob/Cargo.toml index c6fa7103672..86f73626c0a 100644 --- a/substrate/primitives/maybe-compressed-blob/Cargo.toml +++ b/substrate/primitives/maybe-compressed-blob/Cargo.toml @@ -10,6 +10,9 @@ description = "Handling of blobs, usually Wasm code, which may be compresed" documentation = "https://docs.rs/sp-maybe-compressed-blob" readme = "README.md" +[lints] +workspace = true + [dependencies] thiserror = "1.0" zstd = { version = "0.12.4", default-features = false } diff --git a/substrate/primitives/merkle-mountain-range/Cargo.toml b/substrate/primitives/merkle-mountain-range/Cargo.toml index 82a00935b30..dec55a5c8f3 100644 --- a/substrate/primitives/merkle-mountain-range/Cargo.toml +++ b/substrate/primitives/merkle-mountain-range/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "Merkle Mountain Range primitives." +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/metadata-ir/Cargo.toml b/substrate/primitives/metadata-ir/Cargo.toml index f73a1d7b380..0dc496bab53 100644 --- a/substrate/primitives/metadata-ir/Cargo.toml +++ b/substrate/primitives/metadata-ir/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Intermediate representation of the runtime metadata." documentation = "https://docs.rs/sp-metadata-ir" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/mixnet/Cargo.toml b/substrate/primitives/mixnet/Cargo.toml index a03fdab8741..6ea7a6cbe8c 100644 --- a/substrate/primitives/mixnet/Cargo.toml +++ b/substrate/primitives/mixnet/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/npos-elections/Cargo.toml b/substrate/primitives/npos-elections/Cargo.toml index 1ab6c2adf82..dcd03e7e5e0 100644 --- a/substrate/primitives/npos-elections/Cargo.toml +++ b/substrate/primitives/npos-elections/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "NPoS election algorithm primitives" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/npos-elections/fuzzer/Cargo.toml b/substrate/primitives/npos-elections/fuzzer/Cargo.toml index 591ef412363..37eaeea2b82 100644 --- a/substrate/primitives/npos-elections/fuzzer/Cargo.toml +++ b/substrate/primitives/npos-elections/fuzzer/Cargo.toml @@ -10,6 +10,9 @@ description = "Fuzzer for phragmén implementation." documentation = "https://docs.rs/sp-npos-elections-fuzzer" publish = false +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/offchain/Cargo.toml b/substrate/primitives/offchain/Cargo.toml index 201e75802cf..19d66ae31e9 100644 --- a/substrate/primitives/offchain/Cargo.toml +++ b/substrate/primitives/offchain/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/panic-handler/Cargo.toml b/substrate/primitives/panic-handler/Cargo.toml index 428062757c1..a0df527f56e 100644 --- a/substrate/primitives/panic-handler/Cargo.toml +++ b/substrate/primitives/panic-handler/Cargo.toml @@ -10,6 +10,9 @@ description = "Custom panic hook with bug report link" documentation = "https://docs.rs/sp-panic-handler" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/rpc/Cargo.toml b/substrate/primitives/rpc/Cargo.toml index cf10af31977..a542b65cdc9 100644 --- a/substrate/primitives/rpc/Cargo.toml +++ b/substrate/primitives/rpc/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Substrate RPC primitives and utilities." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/runtime-interface/Cargo.toml b/substrate/primitives/runtime-interface/Cargo.toml index 80565420f6b..a4c8457b598 100644 --- a/substrate/primitives/runtime-interface/Cargo.toml +++ b/substrate/primitives/runtime-interface/Cargo.toml @@ -10,6 +10,9 @@ description = "Substrate runtime interface" documentation = "https://docs.rs/sp-runtime-interface/" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/runtime-interface/proc-macro/Cargo.toml b/substrate/primitives/runtime-interface/proc-macro/Cargo.toml index f94f568c913..7cf1abf8048 100644 --- a/substrate/primitives/runtime-interface/proc-macro/Cargo.toml +++ b/substrate/primitives/runtime-interface/proc-macro/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "This crate provides procedural macros for usage within the context of the Substrate runtime interface." documentation = "https://docs.rs/sp-runtime-interface-proc-macro" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml b/substrate/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml index 07c820c0601..f663c6d4726 100644 --- a/substrate/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml +++ b/substrate/primitives/runtime-interface/test-wasm-deprecated/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true publish = false +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/runtime-interface/test-wasm/Cargo.toml b/substrate/primitives/runtime-interface/test-wasm/Cargo.toml index 79e79857341..ecb3c7f8732 100644 --- a/substrate/primitives/runtime-interface/test-wasm/Cargo.toml +++ b/substrate/primitives/runtime-interface/test-wasm/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true publish = false +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/runtime-interface/test/Cargo.toml b/substrate/primitives/runtime-interface/test/Cargo.toml index 661af1fa391..55d70960989 100644 --- a/substrate/primitives/runtime-interface/test/Cargo.toml +++ b/substrate/primitives/runtime-interface/test/Cargo.toml @@ -8,6 +8,9 @@ publish = false homepage = "https://substrate.io" repository.workspace = true +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/runtime/Cargo.toml b/substrate/primitives/runtime/Cargo.toml index 827ccdbddbb..97100b88a11 100644 --- a/substrate/primitives/runtime/Cargo.toml +++ b/substrate/primitives/runtime/Cargo.toml @@ -10,6 +10,9 @@ description = "Runtime Modules shared primitive types." documentation = "https://docs.rs/sp-runtime" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/session/Cargo.toml b/substrate/primitives/session/Cargo.toml index b7e43f97300..25700210fee 100644 --- a/substrate/primitives/session/Cargo.toml +++ b/substrate/primitives/session/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Primitives for sessions" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/staking/Cargo.toml b/substrate/primitives/staking/Cargo.toml index f52bf3316db..2c721265142 100644 --- a/substrate/primitives/staking/Cargo.toml +++ b/substrate/primitives/staking/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "A crate which contains primitives that are useful for implementation that uses staking approaches in general. Definitions related to sessions, slashing, etc go here." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/state-machine/Cargo.toml b/substrate/primitives/state-machine/Cargo.toml index ab07d83af6a..f891a74dbf4 100644 --- a/substrate/primitives/state-machine/Cargo.toml +++ b/substrate/primitives/state-machine/Cargo.toml @@ -10,6 +10,9 @@ repository.workspace = true documentation = "https://docs.rs/sp-state-machine" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/statement-store/Cargo.toml b/substrate/primitives/statement-store/Cargo.toml index 089af92f062..f4a80eb0c38 100644 --- a/substrate/primitives/statement-store/Cargo.toml +++ b/substrate/primitives/statement-store/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "A crate which contains primitives related to the statement store" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/std/Cargo.toml b/substrate/primitives/std/Cargo.toml index eae37c6dfe3..f349a7b1196 100644 --- a/substrate/primitives/std/Cargo.toml +++ b/substrate/primitives/std/Cargo.toml @@ -10,6 +10,9 @@ description = "Lowest-abstraction level for the Substrate runtime: just exports documentation = "https://docs.rs/sp-std" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/storage/Cargo.toml b/substrate/primitives/storage/Cargo.toml index b7ff48cdd63..429c17fde50 100644 --- a/substrate/primitives/storage/Cargo.toml +++ b/substrate/primitives/storage/Cargo.toml @@ -10,6 +10,9 @@ repository.workspace = true documentation = "https://docs.rs/sp-storage/" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/test-primitives/Cargo.toml b/substrate/primitives/test-primitives/Cargo.toml index 0f2a399bffb..536cca334dd 100644 --- a/substrate/primitives/test-primitives/Cargo.toml +++ b/substrate/primitives/test-primitives/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true publish = false +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/timestamp/Cargo.toml b/substrate/primitives/timestamp/Cargo.toml index 41afab0dcc2..ea1e4ebbee3 100644 --- a/substrate/primitives/timestamp/Cargo.toml +++ b/substrate/primitives/timestamp/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Substrate core types and inherents for timestamps." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/tracing/Cargo.toml b/substrate/primitives/tracing/Cargo.toml index 964dbbca144..0ad3cd0705b 100644 --- a/substrate/primitives/tracing/Cargo.toml +++ b/substrate/primitives/tracing/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Instrumentation primitives and macros for Substrate." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] # let's default to wasm32 default-target = "wasm32-unknown-unknown" diff --git a/substrate/primitives/transaction-pool/Cargo.toml b/substrate/primitives/transaction-pool/Cargo.toml index 136d3200202..6e66910ac38 100644 --- a/substrate/primitives/transaction-pool/Cargo.toml +++ b/substrate/primitives/transaction-pool/Cargo.toml @@ -10,6 +10,9 @@ description = "Transaction pool runtime facing API." documentation = "https://docs.rs/sp-transaction-pool" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/transaction-storage-proof/Cargo.toml b/substrate/primitives/transaction-storage-proof/Cargo.toml index e3bb80b2562..f8c3ded2ef7 100644 --- a/substrate/primitives/transaction-storage-proof/Cargo.toml +++ b/substrate/primitives/transaction-storage-proof/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/trie/Cargo.toml b/substrate/primitives/trie/Cargo.toml index 5da1594e5d4..79ed5c20000 100644 --- a/substrate/primitives/trie/Cargo.toml +++ b/substrate/primitives/trie/Cargo.toml @@ -10,6 +10,9 @@ homepage = "https://substrate.io" documentation = "https://docs.rs/sp-trie" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/version/Cargo.toml b/substrate/primitives/version/Cargo.toml index 9860ef54c2d..ed056f7ac36 100644 --- a/substrate/primitives/version/Cargo.toml +++ b/substrate/primitives/version/Cargo.toml @@ -10,6 +10,9 @@ description = "Version module for the Substrate runtime; Provides a function tha documentation = "https://docs.rs/sp-version" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/version/proc-macro/Cargo.toml b/substrate/primitives/version/proc-macro/Cargo.toml index 05a3dcb2e27..f7df8ec113f 100644 --- a/substrate/primitives/version/proc-macro/Cargo.toml +++ b/substrate/primitives/version/proc-macro/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Macro for defining a runtime version." documentation = "https://docs.rs/sp-api-proc-macro" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/wasm-interface/Cargo.toml b/substrate/primitives/wasm-interface/Cargo.toml index e997f558c9d..9fe5cc1f2d0 100644 --- a/substrate/primitives/wasm-interface/Cargo.toml +++ b/substrate/primitives/wasm-interface/Cargo.toml @@ -10,6 +10,9 @@ description = "Types and traits for interfacing between the host and the wasm ru documentation = "https://docs.rs/sp-wasm-interface" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/primitives/weights/Cargo.toml b/substrate/primitives/weights/Cargo.toml index fb2e2ae8cb1..c01e1a5a07f 100644 --- a/substrate/primitives/weights/Cargo.toml +++ b/substrate/primitives/weights/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Types and traits for interfacing between the host and the wasm runtime." documentation = "https://docs.rs/sp-wasm-interface" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/scripts/ci/node-template-release/Cargo.toml b/substrate/scripts/ci/node-template-release/Cargo.toml index beb0e0852de..ca9759d5963 100644 --- a/substrate/scripts/ci/node-template-release/Cargo.toml +++ b/substrate/scripts/ci/node-template-release/Cargo.toml @@ -7,6 +7,9 @@ license = "GPL-3.0 WITH Classpath-exception-2.0" homepage = "https://substrate.io" publish = false +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/test-utils/Cargo.toml b/substrate/test-utils/Cargo.toml index 17696e8229c..526ed7c049c 100644 --- a/substrate/test-utils/Cargo.toml +++ b/substrate/test-utils/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Substrate test utilities" publish = false +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/test-utils/cli/Cargo.toml b/substrate/test-utils/cli/Cargo.toml index 4f20e9e2ce5..d654a3aaa72 100644 --- a/substrate/test-utils/cli/Cargo.toml +++ b/substrate/test-utils/cli/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true publish = false +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/test-utils/client/Cargo.toml b/substrate/test-utils/client/Cargo.toml index 9829ae531fe..a137e7b17fc 100644 --- a/substrate/test-utils/client/Cargo.toml +++ b/substrate/test-utils/client/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true publish = false +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/test-utils/runtime/Cargo.toml b/substrate/test-utils/runtime/Cargo.toml index 655c7f0fec1..881a77f1f92 100644 --- a/substrate/test-utils/runtime/Cargo.toml +++ b/substrate/test-utils/runtime/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true publish = false +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/test-utils/runtime/client/Cargo.toml b/substrate/test-utils/runtime/client/Cargo.toml index 40cfa8ab1b7..cbb964f6785 100644 --- a/substrate/test-utils/runtime/client/Cargo.toml +++ b/substrate/test-utils/runtime/client/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true publish = false +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/test-utils/runtime/transaction-pool/Cargo.toml b/substrate/test-utils/runtime/transaction-pool/Cargo.toml index cb6ee6d79f4..b52a897438b 100644 --- a/substrate/test-utils/runtime/transaction-pool/Cargo.toml +++ b/substrate/test-utils/runtime/transaction-pool/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true publish = false +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/utils/binary-merkle-tree/Cargo.toml b/substrate/utils/binary-merkle-tree/Cargo.toml index f36e4f4e0b6..441f89b790f 100644 --- a/substrate/utils/binary-merkle-tree/Cargo.toml +++ b/substrate/utils/binary-merkle-tree/Cargo.toml @@ -8,6 +8,9 @@ repository.workspace = true description = "A no-std/Substrate compatible library to construct binary merkle tree." homepage = "https://substrate.io" +[lints] +workspace = true + [dependencies] array-bytes = { version = "6.1", optional = true } log = { version = "0.4", default-features = false, optional = true } diff --git a/substrate/utils/build-script-utils/Cargo.toml b/substrate/utils/build-script-utils/Cargo.toml index ab15d5552c2..464647ea723 100644 --- a/substrate/utils/build-script-utils/Cargo.toml +++ b/substrate/utils/build-script-utils/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Crate with utility functions for `build.rs` scripts." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/utils/fork-tree/Cargo.toml b/substrate/utils/fork-tree/Cargo.toml index eea500641fe..27bb908986f 100644 --- a/substrate/utils/fork-tree/Cargo.toml +++ b/substrate/utils/fork-tree/Cargo.toml @@ -10,6 +10,9 @@ description = "Utility library for managing tree-like ordered data with logic fo documentation = "https://docs.rs/fork-tree" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/utils/frame/benchmarking-cli/Cargo.toml b/substrate/utils/frame/benchmarking-cli/Cargo.toml index 8fb2c731520..b9495fa46c2 100644 --- a/substrate/utils/frame/benchmarking-cli/Cargo.toml +++ b/substrate/utils/frame/benchmarking-cli/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "CLI for benchmarking FRAME" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/utils/frame/frame-utilities-cli/Cargo.toml b/substrate/utils/frame/frame-utilities-cli/Cargo.toml index 5dc974cf89b..7e0c0241947 100644 --- a/substrate/utils/frame/frame-utilities-cli/Cargo.toml +++ b/substrate/utils/frame/frame-utilities-cli/Cargo.toml @@ -10,6 +10,9 @@ description = "cli interface for FRAME" documentation = "https://docs.rs/substrate-frame-cli" readme = "README.md" +[lints] +workspace = true + [dependencies] clap = { version = "4.4.11", features = ["derive"] } frame-support = { path = "../../../frame/support" } diff --git a/substrate/utils/frame/generate-bags/Cargo.toml b/substrate/utils/frame/generate-bags/Cargo.toml index ac22197c5ac..f075452f4c6 100644 --- a/substrate/utils/frame/generate-bags/Cargo.toml +++ b/substrate/utils/frame/generate-bags/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "Bag threshold generation script for pallet-bag-list" +[lints] +workspace = true + [dependencies] # FRAME frame-support = { path = "../../../frame/support" } diff --git a/substrate/utils/frame/generate-bags/node-runtime/Cargo.toml b/substrate/utils/frame/generate-bags/node-runtime/Cargo.toml index 8dfc78c63ca..4614caa7f7b 100644 --- a/substrate/utils/frame/generate-bags/node-runtime/Cargo.toml +++ b/substrate/utils/frame/generate-bags/node-runtime/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Bag threshold generation script for pallet-bag-list and kitchensink-runtime." publish = false +[lints] +workspace = true + [dependencies] kitchensink-runtime = { path = "../../../../bin/node/runtime" } generate-bags = { path = ".." } diff --git a/substrate/utils/frame/remote-externalities/Cargo.toml b/substrate/utils/frame/remote-externalities/Cargo.toml index 88071f7d634..bd5a51eeec6 100644 --- a/substrate/utils/frame/remote-externalities/Cargo.toml +++ b/substrate/utils/frame/remote-externalities/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "An externalities provided environment that can load itself from remote nodes or cached files" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/utils/frame/rpc/client/Cargo.toml b/substrate/utils/frame/rpc/client/Cargo.toml index d0f323c096f..986f9f3943c 100644 --- a/substrate/utils/frame/rpc/client/Cargo.toml +++ b/substrate/utils/frame/rpc/client/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "Shared JSON-RPC client" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml b/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml index 6d3cb545efb..368273d609f 100644 --- a/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml +++ b/substrate/utils/frame/rpc/state-trie-migration-rpc/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "Node-specific RPC methods for interaction with state trie migration." readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/utils/frame/rpc/support/Cargo.toml b/substrate/utils/frame/rpc/support/Cargo.toml index da56297c82f..1cc6d8e98b3 100644 --- a/substrate/utils/frame/rpc/support/Cargo.toml +++ b/substrate/utils/frame/rpc/support/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "Substrate RPC for FRAME's support" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/utils/frame/rpc/system/Cargo.toml b/substrate/utils/frame/rpc/system/Cargo.toml index 636f2cd0485..84c3265c93d 100644 --- a/substrate/utils/frame/rpc/system/Cargo.toml +++ b/substrate/utils/frame/rpc/system/Cargo.toml @@ -9,6 +9,9 @@ repository.workspace = true description = "FRAME's system exposed over Substrate RPC" readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/utils/frame/try-runtime/cli/Cargo.toml b/substrate/utils/frame/try-runtime/cli/Cargo.toml index 3745198db31..9f560ab3271 100644 --- a/substrate/utils/frame/try-runtime/cli/Cargo.toml +++ b/substrate/utils/frame/try-runtime/cli/Cargo.toml @@ -8,6 +8,9 @@ homepage = "https://substrate.io" repository.workspace = true description = "Cli command runtime testing and dry-running" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/utils/prometheus/Cargo.toml b/substrate/utils/prometheus/Cargo.toml index bf999a66111..252998d94bd 100644 --- a/substrate/utils/prometheus/Cargo.toml +++ b/substrate/utils/prometheus/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://substrate.io" repository.workspace = true readme = "README.md" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/substrate/utils/wasm-builder/Cargo.toml b/substrate/utils/wasm-builder/Cargo.toml index fc3f6450fd7..d0787e680e8 100644 --- a/substrate/utils/wasm-builder/Cargo.toml +++ b/substrate/utils/wasm-builder/Cargo.toml @@ -8,6 +8,9 @@ repository.workspace = true license = "Apache-2.0" homepage = "https://substrate.io" +[lints] +workspace = true + [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] -- GitLab From 6ff50526a76d37ce1118031938a1bd5e7b18a648 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Dec 2023 14:29:14 +0000 Subject: [PATCH 56/59] Bump toml from 0.7.6 to 0.8.2 (#2685) Bumps [toml](https://github.com/toml-rs/toml) from 0.7.6 to 0.8.2.

Commits
  • fe65b2b chore: Release
  • ed597eb chore: Release
  • 257a0fd docs: Update changelog
  • 4b44f53 Merge pull request #617 from epage/update
  • 7eaf286 fix(parser): Failed on mixed inline tables
  • e1f2037 test: Verify with latest data
  • 2f9253c chore: Update toml-test
  • c9b481c test(toml): Ensure tables are used for validation
  • 43d7f29 Merge pull request #615 from toml-rs/renovate/actions-checkout-4.x
  • ef9b837 chore(deps): update actions/checkout action to v4
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=toml&package-manager=cargo&previous-version=0.7.6&new-version=0.8.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 18 +++++++++--------- substrate/utils/wasm-builder/Cargo.toml | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9e17e6803d9..6d976452e4c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4584,7 +4584,7 @@ dependencies = [ "regex", "syn 2.0.40", "termcolor", - "toml 0.7.6", + "toml 0.7.8", "walkdir", ] @@ -8607,7 +8607,7 @@ dependencies = [ "itertools 0.10.5", "tar", "tempfile", - "toml_edit 0.19.14", + "toml_edit 0.19.15", ] [[package]] @@ -13667,7 +13667,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ "once_cell", - "toml_edit 0.19.14", + "toml_edit 0.19.15", ] [[package]] @@ -18877,7 +18877,7 @@ dependencies = [ "sp-maybe-compressed-blob", "strum", "tempfile", - "toml 0.7.6", + "toml 0.8.2", "walkdir", "wasm-opt", ] @@ -19529,14 +19529,14 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.6" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" +checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.19.14", + "toml_edit 0.19.15", ] [[package]] @@ -19562,9 +19562,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.19.14" +version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ "indexmap 2.0.0", "serde", diff --git a/substrate/utils/wasm-builder/Cargo.toml b/substrate/utils/wasm-builder/Cargo.toml index d0787e680e8..2154cfca177 100644 --- a/substrate/utils/wasm-builder/Cargo.toml +++ b/substrate/utils/wasm-builder/Cargo.toml @@ -20,7 +20,7 @@ build-helper = "0.1.1" cargo_metadata = "0.15.4" strum = { version = "0.24.1", features = ["derive"] } tempfile = "3.1.0" -toml = "0.7.3" +toml = "0.8.2" walkdir = "2.3.2" sp-maybe-compressed-blob = { path = "../../primitives/maybe-compressed-blob" } filetime = "0.2.16" -- GitLab From cc846cc296b6d5ffaaf67f53475c70e4d6769ee7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 13 Dec 2023 17:49:43 +0100 Subject: [PATCH 57/59] [Staking] Adds a round check at signed solution submission (#2690) This PR adds a round check to the `Call::submit` extrinsic to make sure that the solution submission has been prepared for the current election round and avoid penalties for delayed submissions. Related to https://github.com/paritytech-secops/srlabs_findings/issues/329 --------- Co-authored-by: command-bot <> --- .../election-provider-multi-phase/src/lib.rs | 3 ++ .../election-provider-multi-phase/src/mock.rs | 9 +++++ .../src/signed.rs | 34 +++++++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs index 05f9b24f8f9..41284f6c78b 100644 --- a/substrate/frame/election-provider-multi-phase/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/src/lib.rs @@ -1024,6 +1024,7 @@ pub mod pallet { // ensure solution is timely. ensure!(Self::current_phase().is_signed(), Error::::PreDispatchEarlySubmission); + ensure!(raw_solution.round == Self::round(), Error::::PreDispatchDifferentRound); // NOTE: this is the only case where having separate snapshot would have been better // because could do just decode_len. But we can create abstractions to do this. @@ -1197,6 +1198,8 @@ pub mod pallet { BoundNotMet, /// Submitted solution has too many winners TooManyWinners, + /// Sumission was prepared for a different round. + PreDispatchDifferentRound, } #[pallet::validate_unsigned] diff --git a/substrate/frame/election-provider-multi-phase/src/mock.rs b/substrate/frame/election-provider-multi-phase/src/mock.rs index 7bdd329d9b0..abad7db037e 100644 --- a/substrate/frame/election-provider-multi-phase/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/src/mock.rs @@ -112,6 +112,15 @@ pub fn roll_to_with_ocw(n: BlockNumber) { } } +pub fn roll_to_round(n: u32) { + assert!(MultiPhase::round() <= n); + + while MultiPhase::round() != n { + roll_to_signed(); + assert_ok!(MultiPhase::elect()); + } +} + pub struct TrimHelpers { pub voters: Vec>, pub assignments: Vec>, diff --git a/substrate/frame/election-provider-multi-phase/src/signed.rs b/substrate/frame/election-provider-multi-phase/src/signed.rs index 7e4b029ff8c..ae830ed0382 100644 --- a/substrate/frame/election-provider-multi-phase/src/signed.rs +++ b/substrate/frame/election-provider-multi-phase/src/signed.rs @@ -571,6 +571,40 @@ mod tests { use frame_support::{assert_noop, assert_ok, assert_storage_noop}; use sp_runtime::Percent; + #[test] + fn cannot_submit_on_different_round() { + ExtBuilder::default().build_and_execute(|| { + // roll to a few rounds ahead. + roll_to_round(5); + assert_eq!(MultiPhase::round(), 5); + + roll_to_signed(); + assert_eq!(MultiPhase::current_phase(), Phase::Signed); + + // create a temp snapshot only for this test. + MultiPhase::create_snapshot().unwrap(); + let mut solution = raw_solution(); + + // try a solution prepared in a previous round. + solution.round = MultiPhase::round() - 1; + + assert_noop!( + MultiPhase::submit(RuntimeOrigin::signed(10), Box::new(solution)), + Error::::PreDispatchDifferentRound, + ); + + // try a solution prepared in a later round (not expected to happen, but in any case). + MultiPhase::create_snapshot().unwrap(); + let mut solution = raw_solution(); + solution.round = MultiPhase::round() + 1; + + assert_noop!( + MultiPhase::submit(RuntimeOrigin::signed(10), Box::new(solution)), + Error::::PreDispatchDifferentRound, + ); + }) + } + #[test] fn cannot_submit_too_early() { ExtBuilder::default().build_and_execute(|| { -- GitLab From 30151bd357ad3db57f00db1291d1eb4843831091 Mon Sep 17 00:00:00 2001 From: Egor_P Date: Wed, 13 Dec 2023 20:07:16 +0100 Subject: [PATCH 58/59] fix docker tag for polkadot image (#2702) This PR has a tiny fix for the proper creation of the tag for the pokadot's docker tag. --- .github/workflows/release-50_publish-docker.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release-50_publish-docker.yml b/.github/workflows/release-50_publish-docker.yml index 567e996b8fd..f74fb6a0ad1 100644 --- a/.github/workflows/release-50_publish-docker.yml +++ b/.github/workflows/release-50_publish-docker.yml @@ -220,6 +220,7 @@ jobs: runs-on: ubuntu-latest outputs: polkadot_apt_version: ${{ steps.fetch-latest-apt.outputs.polkadot_apt_version }} + polkadot_container_tag: ${{ steps.fetch-latest-apt.outputs.polkadot_container_tag }} container: image: paritytech/parity-keyring options: --user root @@ -230,7 +231,9 @@ jobs: apt update apt show polkadot version=$(apt show polkadot 2>/dev/null | grep "Version:" | awk '{print $2}') + tag=$(echo $version | sed 's/-.*//') echo "polkadot_apt_version=v$version" >> $GITHUB_OUTPUT + echo "polkadot_container_tag=v$tag" >> $GITHUB_OUTPUT echo "You passed ${{ inputs.version }} but this is ignored" echo "We use the version from the Debian Package: $version" @@ -276,7 +279,7 @@ jobs: # TODO: It would be good to get rid of this GHA that we don't really need. tags: | parity/polkadot:latest - parity/polkadot:${{ needs.fetch-latest-debian-package-version.outputs.polkadot_apt_version }} + parity/polkadot:${{ needs.fetch-latest-debian-package-version.outputs.polkadot_container_tag }} build-args: | VCS_REF=${{ github.ref }} POLKADOT_VERSION=${{ needs.fetch-latest-debian-package-version.outputs.polkadot_apt_version }} -- GitLab From c5cf3959639f070fcd9b68dae3f8680d39990366 Mon Sep 17 00:00:00 2001 From: Marcin S Date: Wed, 13 Dec 2023 21:38:27 +0100 Subject: [PATCH 59/59] PVF: fix unshare "could not create temporary directory"; refactor (#2663) Co-authored-by: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> --- polkadot/node/core/pvf/src/artifacts.rs | 103 +++++++----------- polkadot/node/core/pvf/src/host.rs | 5 +- polkadot/node/core/pvf/tests/it/main.rs | 18 +++ ...-could-not-create-temporary-drectory.prdoc | 17 +++ 4 files changed, 78 insertions(+), 65 deletions(-) create mode 100644 prdoc/pr_2663-fix-could-not-create-temporary-drectory.prdoc diff --git a/polkadot/node/core/pvf/src/artifacts.rs b/polkadot/node/core/pvf/src/artifacts.rs index 710e266841f..17ce5b443e3 100644 --- a/polkadot/node/core/pvf/src/artifacts.rs +++ b/polkadot/node/core/pvf/src/artifacts.rs @@ -201,13 +201,20 @@ impl Artifacts { /// Create an empty table and populate it with valid artifacts as [`ArtifactState::Prepared`], /// if any. The existing caches will be checked by their file name to determine whether they are /// valid, e.g., matching the current node version. The ones deemed invalid will be pruned. + /// + /// Create the cache directory on-disk if it doesn't exist. pub async fn new_and_prune(cache_path: &Path) -> Self { let mut artifacts = Self { inner: HashMap::new() }; - artifacts.insert_and_prune(cache_path).await; + let _ = artifacts.insert_and_prune(cache_path).await.map_err(|err| { + gum::error!( + target: LOG_TARGET, + "could not initialize artifacts cache: {err}", + ) + }); artifacts } - async fn insert_and_prune(&mut self, cache_path: &Path) { + async fn insert_and_prune(&mut self, cache_path: &Path) -> Result<(), String> { async fn is_corrupted(path: &Path) -> bool { let checksum = match tokio::fs::read(path).await { Ok(bytes) => blake3::hash(&bytes), @@ -237,24 +244,16 @@ impl Artifacts { artifacts: &mut Artifacts, entry: &tokio::fs::DirEntry, cache_path: &Path, - ) { + ) -> Result<(), String> { let file_type = entry.file_type().await; let file_name = entry.file_name(); match file_type { Ok(file_type) => if !file_type.is_file() { - return + return Ok(()) }, - Err(err) => { - gum::warn!( - target: LOG_TARGET, - ?err, - "unable to get file type for {:?}", - file_name, - ); - return - }, + Err(err) => return Err(format!("unable to get file type for {file_name:?}: {err}")), } if let Some(file_name) = file_name.to_str() { @@ -262,73 +261,51 @@ impl Artifacts { let path = cache_path.join(file_name); if id.is_none() || is_corrupted(&path).await { - gum::warn!( - target: LOG_TARGET, - "discarding invalid artifact {:?}", - &path, - ); let _ = tokio::fs::remove_file(&path).await; - return + return Err(format!("invalid artifact {path:?}, file deleted")) } - if let Some(id) = id { - gum::debug!( - target: LOG_TARGET, - "reusing existing {:?} for node version v{}", - &path, - NODE_VERSION, - ); - artifacts.insert_prepared(id, path, SystemTime::now(), Default::default()); - } - } else { - gum::warn!( + let id = id.expect("checked is_none() above; qed"); + gum::debug!( target: LOG_TARGET, - "non-Unicode file name {:?} found in {:?}", - file_name, - cache_path, + "reusing existing {:?} for node version v{}", + &path, + NODE_VERSION, ); + artifacts.insert_prepared(id, path, SystemTime::now(), Default::default()); + + Ok(()) + } else { + Err(format!("non-Unicode file name {file_name:?} found in {cache_path:?}")) } } // Make sure that the cache path directory and all its parents are created. if let Err(err) = tokio::fs::create_dir_all(cache_path).await { if err.kind() != io::ErrorKind::AlreadyExists { - gum::error!( - target: LOG_TARGET, - ?err, - "failed to create dir {:?}", - cache_path, - ); - return + return Err(format!("failed to create dir {cache_path:?}: {err}")) } } - let mut dir = match tokio::fs::read_dir(cache_path).await { - Ok(dir) => dir, - Err(err) => { - gum::error!( - target: LOG_TARGET, - ?err, - "failed to read dir {:?}", - cache_path, - ); - return - }, - }; + let mut dir = tokio::fs::read_dir(cache_path) + .await + .map_err(|err| format!("failed to read dir {cache_path:?}: {err}"))?; loop { match dir.next_entry().await { - Ok(Some(entry)) => insert_or_prune(self, &entry, cache_path).await, - Ok(None) => break, - Err(err) => { - gum::warn!( - target: LOG_TARGET, - ?err, - "error processing artifacts in {:?}", - cache_path, - ); - break - }, + Ok(Some(entry)) => + if let Err(err) = insert_or_prune(self, &entry, cache_path).await { + gum::warn!( + target: LOG_TARGET, + ?cache_path, + "could not insert entry {:?} into the artifact cache: {}", + entry, + err, + ) + }, + Ok(None) => return Ok(()), + Err(err) => + return Err(format!("error processing artifacts in {cache_path:?}: {err}")), } } } diff --git a/polkadot/node/core/pvf/src/host.rs b/polkadot/node/core/pvf/src/host.rs index f7817853dd1..d17a4d918e0 100644 --- a/polkadot/node/core/pvf/src/host.rs +++ b/polkadot/node/core/pvf/src/host.rs @@ -217,6 +217,9 @@ pub async fn start( ) -> SubsystemResult<(ValidationHost, impl Future)> { gum::debug!(target: LOG_TARGET, ?config, "starting PVF validation host"); + // Make sure the cache is initialized before doing anything else. + let artifacts = Artifacts::new_and_prune(&config.cache_path).await; + // Run checks for supported security features once per host startup. If some checks fail, warn // if Secure Validator Mode is disabled and return an error otherwise. let security_status = match security::check_security_status(&config).await { @@ -260,8 +263,6 @@ pub async fn start( let run_sweeper = sweeper_task(to_sweeper_rx); let run_host = async move { - let artifacts = Artifacts::new_and_prune(&config.cache_path).await; - run(Inner { cleanup_pulse_interval: Duration::from_secs(3600), artifact_ttl: Duration::from_secs(3600 * 24), diff --git a/polkadot/node/core/pvf/tests/it/main.rs b/polkadot/node/core/pvf/tests/it/main.rs index e82ade5edfa..09f975b706d 100644 --- a/polkadot/node/core/pvf/tests/it/main.rs +++ b/polkadot/node/core/pvf/tests/it/main.rs @@ -445,3 +445,21 @@ async fn all_security_features_work() { } ); } + +// Regression test to make sure the unshare-pivot-root capability does not depend on the PVF +// artifacts cache existing. +#[cfg(all(feature = "ci-only-tests", target_os = "linux"))] +#[tokio::test] +async fn nonexistant_cache_dir() { + let host = TestHost::new_with_config(|cfg| { + cfg.cache_path = cfg.cache_path.join("nonexistant_cache_dir"); + }) + .await; + + assert!(host.security_status().await.can_unshare_user_namespace_and_change_root); + + let _stats = host + .precheck_pvf(::adder::wasm_binary_unwrap(), Default::default()) + .await + .unwrap(); +} diff --git a/prdoc/pr_2663-fix-could-not-create-temporary-drectory.prdoc b/prdoc/pr_2663-fix-could-not-create-temporary-drectory.prdoc new file mode 100644 index 00000000000..2119599fce1 --- /dev/null +++ b/prdoc/pr_2663-fix-could-not-create-temporary-drectory.prdoc @@ -0,0 +1,17 @@ +title: "PVF: fix unshare 'could not create temporary directory'" + +doc: + - audience: Node Operator + description: | + For validators: fixes the potential warning/error: + "Cannot unshare user namespace and change root, which are Linux-specific kernel security features: could not create a temporary directory in "/tmp/.tmpIcLriO". + +migrations: + db: [] + + runtime: [] + +crates: + - name: polkadot-node-core-pvf + +host_functions: [] -- GitLab