Use Message Queue pallet for UMP dispatch (#6271)

* Add ProcessXcmMessage struct

* Migrate away from weights in host config

* New well-known key to report UMPQ capacity

* Add missing file

* Fixes

* Remove original UMP files

* Docs

* Update runtime/parachains/src/inclusion/mod.rs

Co-authored-by: asynchronous rob <rphmeier@gmail.com>

* Add benchmarking

* Benchmarks

* Mock example of using the QueueChangeHandler to update the WKK

* Use master Cargo.lock

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Merge remote-tracking branch 'origin/master' into gav-message-queue

* Update Cargo.lock

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Update remove-weight migration

The migration got touched on master; just resolving conflicts here.

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Add message- to dispatch-origin conversion for XCM processing

Just using the `impl Into<MultiLocation>` was a bit inflexible.
Like this, the Relaychain can convert `UMP(para)` to a MultiLocation `para`.

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* DNM: Temporarily comment code since XCMv3 is not merged yet

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Use u64 for queue-wide limits on UmpAcceptanceCheckErr

Using u32 here was one audit finding for the queue pallet.

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Define one sub-queue per *MP queue

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Harden check_upward_messages

Using safe math and casts.

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Add type-safe well_known_keys

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Add message-queue weights

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Deploy MessageQueue to Polkadot

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Update Cargo.toml

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Migrate to parachain config V5

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Update UMP tests

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Cleanup

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* fmt

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Revert messed up merge 🤦

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Update remove-weight migration

The migration got touched on master; just resolving conflicts here.

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Add message- to dispatch-origin conversion for XCM processing

Just using the `impl Into<MultiLocation>` was a bit inflexible.
Like this, the Relaychain can convert `UMP(para)` to a MultiLocation `para`.

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* DNM: Temporarily comment code since XCMv3 is not merged yet

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Use u64 for queue-wide limits on UmpAcceptanceCheckErr

Using u32 here was one audit finding for the queue pallet.

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Define one sub-queue per *MP queue

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Harden check_upward_messages

Using safe math and casts.

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Add type-safe well_known_keys

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Add message-queue weights

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Deploy MessageQueue to Polkadot

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Update Cargo.toml

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Migrate to parachain config V5

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Update UMP tests

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Cleanup

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* fmt

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Make stuff compile

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Move DMP and HRMP messages to the MessageQueue

It currently does not compile in the CIbecause of some local
tweaks to Substrate.

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Diener for CI

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* diener update cargo.lock

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Cleanup

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Revert wrong changes

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Revert "DNM: Temporarily comment code since XCMv3 is not merged yet"

This reverts commit 820aa235cb21dd1d2621843607f7682bf035434e.

* Make compile

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fixup runtimes

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* fmt

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Define benchmarks

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Cleanup

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix migration

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Use master Cargo.lock

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Lockfile

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix test

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Add AggregateMessageOrigin

This enum currently only holds one value, but having it will make
it easier in the future to extend.

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Forbid UMP for off-boarding paras

- Reject candidates with UMP messages for off-boarding paras
- Forbid scheduling off-boarding when a para has unprocess UMPs

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Delete stupid test

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Use BoundedVec for upward messages

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Add weights and fix MessageProcessor

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Bound receive_upward_messages and check bound in configuration pallet

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Bound Debug impl

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* fmt

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* clippy

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix test runtime

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix xcm-simulator

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Properly fix xcm-simulator and fuzzer

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix tests

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* fmt

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* cargo update -p sp-io

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Adapt to upstream Substrate changes

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix ProcesseMessage impls

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Some tests

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Use master Cargo.lock

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* cargo update -p sp-io

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Use new MQ API

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix test

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix migration

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Update Cargo.lock

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Add UMP while Para offboarding tests

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* fmt

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Use Mocked message processor for benchmarking

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Use variables for constants

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Add MQ pallet weights

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Use MQ pallet weights

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Configure QueueChangeHandler

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* fmt

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Add config test

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix MQ serive weight

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Cleanup

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Cleanup outgoing UMP dispatch queues

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Use Master Cargo.lock

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Update Cargo.lock

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Weight mul is not const

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Clippy

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Remove merge marker

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Update runtime/parachains/src/inclusion/mod.rs

Co-authored-by: Gavin Wood <gavin@parity.io>

* Update runtime/kusama/src/lib.rs

Co-authored-by: Gavin Wood <gavin@parity.io>

* Use lowercase UMP

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Clarify comment

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Use Weight::from_parts

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix test

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix doc

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Emit event after the fact

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Add defensive_proof to receive_upward_messages

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Reapply "Remove original UMP files"

Looks like they came back from the dead. Re-apply commit cf6d316f0

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Remove old files

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Rename MaxUmpMessageLen -> MaxUmpMessageLenOf

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Test defensive message dropping of receive_upward_messages

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fixup imports

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Update implementors guide

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix tests

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Remove FAIL-CI mark

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Delete unused code

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Add another test for MQ change hook

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Imports

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Keep Kusama runtime formatting

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Revert "Delete unused code"

This reverts commit dd76bca5025b7e1ef846a9539c3607eed185f16a.

* Feature gate mock functions

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Review: Use saturating_add

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Test RelayDispatchQueueSize storage key

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Move migration to own file to avoid merge conflicts

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Migration in own file

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fixup migration

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Rococo: configure MQ pallet

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fixup tests

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Revert "Rococo: configure MQ pallet"

Going to do this as follow up, since it needs Substrate changes
and i dont want to stall this MR any longer.

This reverts commit b9c15e8a8339c4e877d654ee3f09903af4210736.

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Revert "Fixup tests"

This reverts commit 88f1cbe20774d20e5e1e554e798960ae39437af1.

* Fixup migration

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix migration

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* fmt

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix CI

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix migration

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix other migration

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Bump MAX_CODE_SIZE to 10MiB

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Add ForceUpdateUmpLimits migration

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* fmt

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* clippy

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* clippy

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* imports

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Use defensive instead of defensive_proof

'defensive_proof' also prints the 'self', which spams the console
too much when running the tests. Just the length is enough.

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Rename to ScheduleConfigUpdate

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fixup migration checks

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Add MAX_CODE_SIZE to ScheduleConfigUpdate

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Set MAX_CODE_SIZE to 4MiB

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix benchmark

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix formatting

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Revert "Add MAX_CODE_SIZE to ScheduleConfigUpdate"

This reverts commit 7caffb09e83083b57affd548215e45b25c3d64dc.

* Revert "Set MAX_CODE_SIZE to 4MiB"

This reverts commit 103ffbaf686487d2fbe0082a16826af17cacc1a1.

* Revert "Bump MAX_CODE_SIZE to 10MiB"

This reverts commit 530734b7b0da5b7680054e0242348fcc79a666fe.

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Remove consistency check from migration

Re-addig these checks is blocked on https://github.com/paritytech/polkadot/issues/7108

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix constants

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Bump MAX_UPWARD_MESSAGE_SIZE_BOUND for Westend

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix migrations

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Use old nightly for fmt

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fixes

* cargo fmt

* Fix tests

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix tests

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fixes

* Add MQ pallet to fuzzer

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fmt

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix XMC simulator example

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Remove runtime-benchmarks from fuzzers

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Revert "Remove runtime-benchmarks from fuzzers"

This reverts commit e1f2bb01b6dea2dd465539d3658719895b58b557.

* Fix example simulator

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Add V6 migration and remove old ones

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Actually make old migrations reusable

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Dont delete old migrations

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Future proof AggregateMessageOrigin and review fixes

There are indications that Loopback and Bridged will be needed soon.

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* More cleanup

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* fmt

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* fix benchmarks

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix fuzzer build

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Review

Co-authored-by: muharem <ismailov.m.h@gmail.com>

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Remove old migration

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Set MQ service weight to 20%

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix tabs in Markdown

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

---------

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Co-authored-by: asynchronous rob <rphmeier@gmail.com>
Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>
This commit is contained in:
Gavin Wood
2023-05-19 18:14:13 +02:00
committed by GitHub
parent 9e4bca6895
commit 400864c352
74 changed files with 4034 additions and 2536 deletions
+29
View File
@@ -3922,6 +3922,7 @@ dependencies = [
"pallet-im-online", "pallet-im-online",
"pallet-indices", "pallet-indices",
"pallet-membership", "pallet-membership",
"pallet-message-queue",
"pallet-multisig", "pallet-multisig",
"pallet-nis", "pallet-nis",
"pallet-nomination-pools", "pallet-nomination-pools",
@@ -5963,6 +5964,25 @@ dependencies = [
"sp-std", "sp-std",
] ]
[[package]]
name = "pallet-message-queue"
version = "7.0.0-dev"
source = "git+https://github.com/paritytech/substrate?branch=master#b7e0518966b145f22c16137da5c9796fcdb43b73"
dependencies = [
"frame-benchmarking",
"frame-support",
"frame-system",
"log",
"parity-scale-codec",
"scale-info",
"sp-arithmetic",
"sp-core",
"sp-io",
"sp-runtime",
"sp-std",
"sp-weights",
]
[[package]] [[package]]
name = "pallet-mmr" name = "pallet-mmr"
version = "4.0.0-dev" version = "4.0.0-dev"
@@ -7884,6 +7904,7 @@ dependencies = [
"pallet-im-online", "pallet-im-online",
"pallet-indices", "pallet-indices",
"pallet-membership", "pallet-membership",
"pallet-message-queue",
"pallet-multisig", "pallet-multisig",
"pallet-nomination-pools", "pallet-nomination-pools",
"pallet-nomination-pools-benchmarking", "pallet-nomination-pools-benchmarking",
@@ -8045,6 +8066,7 @@ dependencies = [
"pallet-authorship", "pallet-authorship",
"pallet-babe", "pallet-babe",
"pallet-balances", "pallet-balances",
"pallet-message-queue",
"pallet-session", "pallet-session",
"pallet-staking", "pallet-staking",
"pallet-timestamp", "pallet-timestamp",
@@ -9276,6 +9298,7 @@ dependencies = [
"pallet-im-online", "pallet-im-online",
"pallet-indices", "pallet-indices",
"pallet-membership", "pallet-membership",
"pallet-message-queue",
"pallet-mmr", "pallet-mmr",
"pallet-multisig", "pallet-multisig",
"pallet-nis", "pallet-nis",
@@ -14092,6 +14115,7 @@ dependencies = [
"pallet-im-online", "pallet-im-online",
"pallet-indices", "pallet-indices",
"pallet-membership", "pallet-membership",
"pallet-message-queue",
"pallet-multisig", "pallet-multisig",
"pallet-nomination-pools", "pallet-nomination-pools",
"pallet-nomination-pools-benchmarking", "pallet-nomination-pools-benchmarking",
@@ -14565,12 +14589,14 @@ dependencies = [
"parity-scale-codec", "parity-scale-codec",
"polkadot-parachain", "polkadot-parachain",
"polkadot-runtime-parachains", "polkadot-runtime-parachains",
"polkadot-test-runtime",
"primitive-types", "primitive-types",
"scale-info", "scale-info",
"sp-arithmetic", "sp-arithmetic",
"sp-io", "sp-io",
"sp-runtime", "sp-runtime",
"sp-std", "sp-std",
"sp-weights",
"xcm", "xcm",
"xcm-executor", "xcm-executor",
] ]
@@ -14637,6 +14663,7 @@ dependencies = [
"sp-io", "sp-io",
"sp-std", "sp-std",
"xcm", "xcm",
"xcm-builder",
"xcm-executor", "xcm-executor",
] ]
@@ -14648,6 +14675,7 @@ dependencies = [
"frame-system", "frame-system",
"log", "log",
"pallet-balances", "pallet-balances",
"pallet-message-queue",
"pallet-uniques", "pallet-uniques",
"pallet-xcm", "pallet-xcm",
"parity-scale-codec", "parity-scale-codec",
@@ -14675,6 +14703,7 @@ dependencies = [
"frame-system", "frame-system",
"honggfuzz", "honggfuzz",
"pallet-balances", "pallet-balances",
"pallet-message-queue",
"pallet-xcm", "pallet-xcm",
"parity-scale-codec", "parity-scale-codec",
"polkadot-core-primitives", "polkadot-core-primitives",
-2
View File
@@ -17,7 +17,6 @@
//! Polkadot chain configurations. //! Polkadot chain configurations.
use beefy_primitives::crypto::AuthorityId as BeefyId; use beefy_primitives::crypto::AuthorityId as BeefyId;
use frame_support::weights::Weight;
use grandpa::AuthorityId as GrandpaId; use grandpa::AuthorityId as GrandpaId;
#[cfg(feature = "kusama-native")] #[cfg(feature = "kusama-native")]
use kusama_runtime as kusama; use kusama_runtime as kusama;
@@ -189,7 +188,6 @@ fn default_parachains_host_configuration(
max_upward_queue_count: 8, max_upward_queue_count: 8,
max_upward_queue_size: 1024 * 1024, max_upward_queue_size: 1024 * 1024,
max_downward_message_size: 1024 * 1024, max_downward_message_size: 1024 * 1024,
ump_service_total_weight: Weight::from_parts(100_000_000_000, MAX_POV_SIZE as u64),
max_upward_message_size: 50 * 1024, max_upward_message_size: 50 * 1024,
max_upward_message_num_per_candidate: 5, max_upward_message_num_per_candidate: 5,
hrmp_sender_deposit: 0, hrmp_sender_deposit: 0,
+56 -1
View File
@@ -133,7 +133,7 @@ pub type ValidatorSignature = validator_app::Signature;
/// A declarations of storage keys where an external observer can find some interesting data. /// A declarations of storage keys where an external observer can find some interesting data.
pub mod well_known_keys { pub mod well_known_keys {
use super::{HrmpChannelId, Id}; use super::{HrmpChannelId, Id, WellKnownKey};
use hex_literal::hex; use hex_literal::hex;
use parity_scale_codec::Encode as _; use parity_scale_codec::Encode as _;
use sp_io::hashing::twox_64; use sp_io::hashing::twox_64;
@@ -210,6 +210,7 @@ pub mod well_known_keys {
/// ///
/// - `count: u32`, the number of messages currently in the queue for given para, /// - `count: u32`, the number of messages currently in the queue for given para,
/// - `total_size: u32`, the total size of all messages in the queue. /// - `total_size: u32`, the total size of all messages in the queue.
#[deprecated = "Use `relay_dispatch_queue_remaining_capacity` instead"]
pub fn relay_dispatch_queue_size(para_id: Id) -> Vec<u8> { pub fn relay_dispatch_queue_size(para_id: Id) -> Vec<u8> {
let prefix = hex!["f5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e"]; let prefix = hex!["f5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e"];
@@ -224,6 +225,24 @@ pub mod well_known_keys {
}) })
} }
/// Type safe version of `relay_dispatch_queue_size`.
#[deprecated = "Use `relay_dispatch_queue_remaining_capacity` instead"]
pub fn relay_dispatch_queue_size_typed(para: Id) -> WellKnownKey<(u32, u32)> {
#[allow(deprecated)]
relay_dispatch_queue_size(para).into()
}
/// The upward message dispatch queue remaining capacity for the given para id.
///
/// The storage entry stores a tuple of two values:
///
/// - `count: u32`, the number of additional messages which may be enqueued for the given para,
/// - `total_size: u32`, the total size of additional messages which may be enqueued for the
/// given para.
pub fn relay_dispatch_queue_remaining_capacity(para_id: Id) -> WellKnownKey<(u32, u32)> {
(b":relay_dispatch_queue_remaining_capacity", para_id).encode().into()
}
/// The HRMP channel for the given identifier. /// The HRMP channel for the given identifier.
/// ///
/// The storage entry should be accessed as an `AbridgedHrmpChannel` encoded value. /// The storage entry should be accessed as an `AbridgedHrmpChannel` encoded value.
@@ -1706,6 +1725,42 @@ impl PvfCheckStatement {
} }
} }
/// A well-known and typed storage key.
///
/// Allows for type-safe access to raw well-known storage keys.
pub struct WellKnownKey<T> {
/// The raw storage key.
pub key: Vec<u8>,
_p: sp_std::marker::PhantomData<T>,
}
impl<T> From<Vec<u8>> for WellKnownKey<T> {
fn from(key: Vec<u8>) -> Self {
Self { key, _p: Default::default() }
}
}
impl<T> AsRef<[u8]> for WellKnownKey<T> {
fn as_ref(&self) -> &[u8] {
self.key.as_ref()
}
}
impl<T: Decode> WellKnownKey<T> {
/// Gets the value or `None` if it does not exist or decoding failed.
pub fn get(&self) -> Option<T> {
sp_io::storage::get(&self.key)
.and_then(|raw| parity_scale_codec::DecodeAll::decode_all(&mut raw.as_ref()).ok())
}
}
impl<T: Encode> WellKnownKey<T> {
/// Sets the value.
pub fn set(&self, value: T) {
sp_io::storage::set(&self.key, &value.encode());
}
}
/// Type discriminator for PVF preparation timeouts /// Type discriminator for PVF preparation timeouts
#[derive(Encode, Decode, TypeInfo, Clone, Copy, Debug, PartialEq, Eq)] #[derive(Encode, Decode, TypeInfo, Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
@@ -1,6 +1,6 @@
# Inclusion Module # Inclusion Module
The inclusion module is responsible for inclusion and availability of scheduled parachains and parathreads. The inclusion module is responsible for inclusion and availability of scheduled parachains and parathreads. It also manages the UMP dispatch queue of each parachain/thread.
## Storage ## Storage
@@ -35,11 +35,27 @@ PendingAvailability: map ParaId => CandidatePendingAvailability;
PendingAvailabilityCommitments: map ParaId => CandidateCommitments; PendingAvailabilityCommitments: map ParaId => CandidateCommitments;
``` ```
## Config Dependencies
* `MessageQueue`:
The message queue provides general queueing and processing functionality. Currently it
replaces the old `UMP` dispatch queue. Other use-cases can be implemented as well by
adding new variants to `AggregateMessageOrigin`. Normally it should be set to an instance
of the `MessageQueue` pallet.
## Session Change ## Session Change
1. Clear out all candidates pending availability. 1. Clear out all candidates pending availability.
1. Clear out all validator bitfields. 1. Clear out all validator bitfields.
Optional:
1. The UMP queue of all outgoing paras can be "swept". This would prevent the dispatch queue from automatically being serviced. It is a consideration for the chain and specific behaviour is not defined.
## Initialization
No initialization routine runs for this module. However, the initialization of the `MessageQueue` pallet will attempt to process any pending UMP messages.
## Routines ## Routines
All failed checks should lead to an unrecoverable error making the block invalid. All failed checks should lead to an unrecoverable error making the block invalid.
@@ -88,7 +104,7 @@ All failed checks should lead to an unrecoverable error making the block invalid
1. Ensure that any code upgrade scheduled by the candidate does not happen within `config.validation_upgrade_cooldown` of `Paras::last_code_upgrade(para_id, true)`, if any, comparing against the value of `Paras::FutureCodeUpgrades` for the given para ID. 1. Ensure that any code upgrade scheduled by the candidate does not happen within `config.validation_upgrade_cooldown` of `Paras::last_code_upgrade(para_id, true)`, if any, comparing against the value of `Paras::FutureCodeUpgrades` for the given para ID.
1. Check the collator's signature on the candidate data. 1. Check the collator's signature on the candidate data.
1. check the backing of the candidate using the signatures and the bitfields, comparing against the validators assigned to the groups, fetched with the `group_validators` lookup. 1. check the backing of the candidate using the signatures and the bitfields, comparing against the validators assigned to the groups, fetched with the `group_validators` lookup.
1. call `Ump::check_upward_messages(para, commitments.upward_messages)` to check that the upward messages are valid. 1. call `check_upward_messages(config, para, commitments.upward_messages)` to check that the upward messages are valid.
1. call `Dmp::check_processed_downward_messages(para, commitments.processed_downward_messages)` to check that the DMQ is properly drained. 1. call `Dmp::check_processed_downward_messages(para, commitments.processed_downward_messages)` to check that the DMQ is properly drained.
1. call `Hrmp::check_hrmp_watermark(para, commitments.hrmp_watermark)` for each candidate to check rules of processing the HRMP watermark. 1. call `Hrmp::check_hrmp_watermark(para, commitments.hrmp_watermark)` for each candidate to check rules of processing the HRMP watermark.
1. using `Hrmp::check_outbound_hrmp(sender, commitments.horizontal_messages)` ensure that the each candidate sent a valid set of horizontal messages 1. using `Hrmp::check_outbound_hrmp(sender, commitments.horizontal_messages)` ensure that the each candidate sent a valid set of horizontal messages
@@ -99,7 +115,7 @@ All failed checks should lead to an unrecoverable error making the block invalid
1. If the receipt contains a code upgrade, Call `Paras::schedule_code_upgrade(para_id, code, relay_parent_number, config)`. 1. If the receipt contains a code upgrade, Call `Paras::schedule_code_upgrade(para_id, code, relay_parent_number, config)`.
> TODO: Note that this is safe as long as we never enact candidates where the relay parent is across a session boundary. In that case, which we should be careful to avoid with contextual execution, the configuration might have changed and the para may de-sync from the host's understanding of it. > TODO: Note that this is safe as long as we never enact candidates where the relay parent is across a session boundary. In that case, which we should be careful to avoid with contextual execution, the configuration might have changed and the para may de-sync from the host's understanding of it.
1. Reward all backing validators of each candidate, contained within the `backers` field. 1. Reward all backing validators of each candidate, contained within the `backers` field.
1. call `Ump::receive_upward_messages` for each backed candidate, using the [`UpwardMessage`s](../types/messages.md#upward-message) from the [`CandidateCommitments`](../types/candidate.md#candidate-commitments). 1. call `receive_upward_messages` for each backed candidate, using the [`UpwardMessage`s](../types/messages.md#upward-message) from the [`CandidateCommitments`](../types/candidate.md#candidate-commitments).
1. call `Dmp::prune_dmq` with the para id of the candidate and the candidate's `processed_downward_messages`. 1. call `Dmp::prune_dmq` with the para id of the candidate and the candidate's `processed_downward_messages`.
1. call `Hrmp::prune_hrmp` with the para id of the candiate and the candidate's `hrmp_watermark`. 1. call `Hrmp::prune_hrmp` with the para id of the candiate and the candidate's `hrmp_watermark`.
1. call `Hrmp::queue_outbound_hrmp` with the para id of the candidate and the list of horizontal messages taken from the commitment, 1. call `Hrmp::queue_outbound_hrmp` with the para id of the candidate and the list of horizontal messages taken from the commitment,
@@ -118,3 +134,20 @@ All failed checks should lead to an unrecoverable error making the block invalid
* `candidate_pending_availability(ParaId) -> Option<CommittedCandidateReceipt>`: returns the `CommittedCandidateReceipt` pending availability for the para provided, if any. * `candidate_pending_availability(ParaId) -> Option<CommittedCandidateReceipt>`: returns the `CommittedCandidateReceipt` pending availability for the para provided, if any.
* `pending_availability(ParaId) -> Option<CandidatePendingAvailability>`: returns the metadata around the candidate pending availability for the para, if any. * `pending_availability(ParaId) -> Option<CandidatePendingAvailability>`: returns the metadata around the candidate pending availability for the para, if any.
* `collect_disputed(disputed: Vec<CandidateHash>) -> Vec<CoreIndex>`: Sweeps through all paras pending availability. If the candidate hash is one of the disputed candidates, then clean up the corresponding storage for that candidate and the commitments. Return a vector of cleaned-up core IDs. * `collect_disputed(disputed: Vec<CandidateHash>) -> Vec<CoreIndex>`: Sweeps through all paras pending availability. If the candidate hash is one of the disputed candidates, then clean up the corresponding storage for that candidate and the commitments. Return a vector of cleaned-up core IDs.
These functions were formerly part of the UMP pallet:
* `check_upward_messages(P: ParaId, Vec<UpwardMessage>)`:
1. Checks that the parachain is not currently offboarding and error otherwise.
1. Checks that there are at most `config.max_upward_message_num_per_candidate` messages to be enqueued.
1. Checks that no message exceeds `config.max_upward_message_size`.
1. Checks that the total resulting queue size would not exceed `co`.
1. Verify that queuing up the messages could not result in exceeding the queue's footprint
according to the config items `config.max_upward_queue_count` and `config.max_upward_queue_size`. The queue's current footprint is provided in `well_known_keys`
in order to facilitate oraclisation on to the para.
Candidate Enactment:
* `receive_upward_messages(P: ParaId, Vec<UpwardMessage>)`:
1. Process each upward message `M` in order:
1. Place in the dispatch queue according to its para ID (or handle it immediately).
@@ -1,87 +0,0 @@
# UMP Module
A module responsible for Upward Message Passing (UMP). See [Messaging Overview](../messaging.md) for more details.
## Storage
Storage related to UMP
```rust
/// The messages waiting to be handled by the relay-chain originating from a certain parachain.
///
/// Note that some upward messages might have been already processed by the inclusion logic. E.g.
/// channel management messages.
///
/// The messages are processed in FIFO order.
RelayDispatchQueues: map ParaId => Vec<UpwardMessage>;
/// Size of the dispatch queues. Caches sizes of the queues in `RelayDispatchQueue`.
///
/// First item in the tuple is the count of messages and second
/// is the total length (in bytes) of the message payloads.
///
/// Note that this is an auxilary mapping: it's possible to tell the byte size and the number of
/// messages only looking at `RelayDispatchQueues`. This mapping is separate to avoid the cost of
/// loading the whole message queue if only the total size and count are required.
///
/// Invariant:
/// - The set of keys should exactly match the set of keys of `RelayDispatchQueues`.
RelayDispatchQueueSize: map ParaId => (u32, u32); // (num_messages, total_bytes)
/// The ordered list of `ParaId`s that have a `RelayDispatchQueue` entry.
///
/// Invariant:
/// - The set of items from this vector should be exactly the set of the keys in
/// `RelayDispatchQueues` and `RelayDispatchQueueSize`.
NeedsDispatch: Vec<ParaId>;
/// This is the para that gets dispatched first during the next upward dispatchable queue
/// execution round.
///
/// Invariant:
/// - If `Some(para)`, then `para` must be present in `NeedsDispatch`.
NextDispatchRoundStartWith: Option<ParaId>;
```
## Initialization
No initialization routine runs for this module.
## Routines
Candidate Acceptance Function:
* `check_upward_messages(P: ParaId, Vec<UpwardMessage>`):
1. Checks that there are at most `config.max_upward_message_num_per_candidate` messages.
1. Checks that no message exceeds `config.max_upward_message_size`.
1. Verify that `RelayDispatchQueueSize` for `P` has enough capacity for the messages
Candidate Enactment:
* `receive_upward_messages(P: ParaId, Vec<UpwardMessage>)`:
1. Process each upward message `M` in order:
1. Append the message to `RelayDispatchQueues` for `P`
1. Increment the size and the count in `RelayDispatchQueueSize` for `P`.
1. Ensure that `P` is present in `NeedsDispatch`.
The following routine is meant to execute pending entries in upward message queues. This function doesn't fail, even if
dispatching any of individual upward messages returns an error.
`process_pending_upward_messages()`:
1. Initialize a cumulative weight counter `T` to 0
1. Iterate over items in `NeedsDispatch` cyclically, starting with `NextDispatchRoundStartWith`. If the item specified is `None` start from the beginning. For each `P` encountered:
1. Dequeue the first upward message `D` from `RelayDispatchQueues` for `P`
1. Decrement the size of the message from `RelayDispatchQueueSize` for `P`
1. Delegate processing of the message to the runtime. The weight consumed is added to `T`.
1. If `T >= config.ump_service_total_weight`, set `NextDispatchRoundStartWith` to `P` and finish processing.
1. If `RelayDispatchQueues` for `P` became empty, remove `P` from `NeedsDispatch`.
1. If `NeedsDispatch` became empty then finish processing and set `NextDispatchRoundStartWith` to `None`.
> NOTE that in practice we would need to approach the weight calculation more thoroughly, i.e. incorporate all operations
> that could take place on the course of handling these upward messages.
## Session Change
1. For each `P` in `outgoing_paras` (generated by `Paras::on_new_session`):
1. Remove `RelayDispatchQueueSize` of `P`.
1. Remove `RelayDispatchQueues` of `P`.
1. Remove `P` if it exists in `NeedsDispatch`.
1. If `P` is in `NextDispatchRoundStartWith`, then reset it to `None`
- Note that if we don't remove the open/close requests since they are going to die out naturally at the end of the session.
@@ -63,11 +63,6 @@ struct HostConfiguration {
/// no further messages may be added to it. If it exceeds this then the queue may contain only /// no further messages may be added to it. If it exceeds this then the queue may contain only
/// a single message. /// a single message.
pub max_upward_queue_size: u32, pub max_upward_queue_size: u32,
/// The amount of weight we wish to devote to the processing the dispatchable upward messages
/// stage.
///
/// NOTE that this is a soft limit and could be exceeded.
pub ump_service_total_weight: Weight,
/// The maximum size of an upward message that can be sent by a candidate. /// The maximum size of an upward message that can be sent by a candidate.
/// ///
/// This parameter affects the upper bound of size of `CandidateCommitments`. /// This parameter affects the upper bound of size of `CandidateCommitments`.
@@ -649,6 +649,7 @@ mod tests {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type WeightInfo = parachains_paras::TestWeightInfo; type WeightInfo = parachains_paras::TestWeightInfo;
type UnsignedPriority = ParasUnsignedPriority; type UnsignedPriority = ParasUnsignedPriority;
type QueueFootprinter = ();
type NextSessionRotation = crate::mock::TestNextSessionRotation; type NextSessionRotation = crate::mock::TestNextSessionRotation;
} }
@@ -205,6 +205,7 @@ impl paras::Config for Test {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type WeightInfo = paras::TestWeightInfo; type WeightInfo = paras::TestWeightInfo;
type UnsignedPriority = ParasUnsignedPriority; type UnsignedPriority = ParasUnsignedPriority;
type QueueFootprinter = ();
type NextSessionRotation = crate::mock::TestNextSessionRotation; type NextSessionRotation = crate::mock::TestNextSessionRotation;
} }
@@ -773,6 +773,7 @@ mod tests {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type WeightInfo = paras::TestWeightInfo; type WeightInfo = paras::TestWeightInfo;
type UnsignedPriority = ParasUnsignedPriority; type UnsignedPriority = ParasUnsignedPriority;
type QueueFootprinter = ();
type NextSessionRotation = crate::mock::TestNextSessionRotation; type NextSessionRotation = crate::mock::TestNextSessionRotation;
} }
@@ -24,7 +24,7 @@ use primitives::Id as ParaId;
use runtime_parachains::{ use runtime_parachains::{
configuration, dmp, hrmp, configuration, dmp, hrmp,
paras::{self, ParaGenesisArgs}, paras::{self, ParaGenesisArgs},
ump, ParaLifecycle, ParaLifecycle,
}; };
use sp_std::boxed::Box; use sp_std::boxed::Box;
@@ -37,10 +37,7 @@ pub mod pallet {
#[pallet::config] #[pallet::config]
#[pallet::disable_frame_system_supertrait_check] #[pallet::disable_frame_system_supertrait_check]
pub trait Config: pub trait Config: configuration::Config + paras::Config + dmp::Config + hrmp::Config {}
configuration::Config + paras::Config + dmp::Config + ump::Config + hrmp::Config
{
}
#[pallet::error] #[pallet::error]
pub enum Error<T> { pub enum Error<T> {
+4
View File
@@ -59,6 +59,7 @@ pallet-identity = { git = "https://github.com/paritytech/substrate", branch = "m
pallet-im-online = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-im-online = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-indices = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-indices = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-membership = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-membership = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-message-queue = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-multisig = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-multisig = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-nomination-pools = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-nomination-pools = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-offences = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-offences = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
@@ -158,6 +159,7 @@ std = [
"pallet-im-online/std", "pallet-im-online/std",
"pallet-indices/std", "pallet-indices/std",
"pallet-membership/std", "pallet-membership/std",
"pallet-message-queue/std",
"pallet-multisig/std", "pallet-multisig/std",
"pallet-nomination-pools/std", "pallet-nomination-pools/std",
"pallet-nomination-pools-runtime-api/std", "pallet-nomination-pools-runtime-api/std",
@@ -225,6 +227,7 @@ runtime-benchmarks = [
"pallet-im-online/runtime-benchmarks", "pallet-im-online/runtime-benchmarks",
"pallet-indices/runtime-benchmarks", "pallet-indices/runtime-benchmarks",
"pallet-membership/runtime-benchmarks", "pallet-membership/runtime-benchmarks",
"pallet-message-queue/runtime-benchmarks",
"pallet-multisig/runtime-benchmarks", "pallet-multisig/runtime-benchmarks",
"pallet-nomination-pools/runtime-benchmarks", "pallet-nomination-pools/runtime-benchmarks",
"pallet-nomination-pools-benchmarking/runtime-benchmarks", "pallet-nomination-pools-benchmarking/runtime-benchmarks",
@@ -276,6 +279,7 @@ try-runtime = [
"pallet-im-online/try-runtime", "pallet-im-online/try-runtime",
"pallet-indices/try-runtime", "pallet-indices/try-runtime",
"pallet-membership/try-runtime", "pallet-membership/try-runtime",
"pallet-message-queue/try-runtime",
"pallet-multisig/try-runtime", "pallet-multisig/try-runtime",
"pallet-nomination-pools/try-runtime", "pallet-nomination-pools/try-runtime",
"pallet-offences/try-runtime", "pallet-offences/try-runtime",
+84 -22
View File
@@ -39,12 +39,14 @@ use sp_std::{cmp::Ordering, collections::btree_map::BTreeMap, prelude::*};
use runtime_parachains::{ use runtime_parachains::{
configuration as parachains_configuration, disputes as parachains_disputes, configuration as parachains_configuration, disputes as parachains_disputes,
disputes::slashing as parachains_slashing, dmp as parachains_dmp, hrmp as parachains_hrmp, disputes::slashing as parachains_slashing,
inclusion as parachains_inclusion, initializer as parachains_initializer, dmp as parachains_dmp, hrmp as parachains_hrmp, inclusion as parachains_inclusion,
origin as parachains_origin, paras as parachains_paras, inclusion::{AggregateMessageOrigin, UmpQueueId},
initializer as parachains_initializer, origin as parachains_origin, paras as parachains_paras,
paras_inherent as parachains_paras_inherent, reward_points as parachains_reward_points, paras_inherent as parachains_paras_inherent, reward_points as parachains_reward_points,
runtime_api_impl::v4 as parachains_runtime_api_impl, scheduler as parachains_scheduler, runtime_api_impl::v4 as parachains_runtime_api_impl,
session_info as parachains_session_info, shared as parachains_shared, ump as parachains_ump, scheduler as parachains_scheduler, session_info as parachains_session_info,
shared as parachains_shared,
}; };
use authority_discovery_primitives::AuthorityId as AuthorityDiscoveryId; use authority_discovery_primitives::AuthorityId as AuthorityDiscoveryId;
@@ -56,9 +58,9 @@ use frame_support::{
construct_runtime, parameter_types, construct_runtime, parameter_types,
traits::{ traits::{
ConstU32, Contains, EitherOf, EitherOfDiverse, InstanceFilter, KeyOwnerProofSystem, ConstU32, Contains, EitherOf, EitherOfDiverse, InstanceFilter, KeyOwnerProofSystem,
PrivilegeCmp, StorageMapShim, WithdrawReasons, PrivilegeCmp, ProcessMessage, ProcessMessageError, StorageMapShim, WithdrawReasons,
}, },
weights::ConstantMultiplier, weights::{ConstantMultiplier, WeightMeter},
PalletId, RuntimeDebug, PalletId, RuntimeDebug,
}; };
use frame_system::EnsureRoot; use frame_system::EnsureRoot;
@@ -81,6 +83,7 @@ use sp_staking::SessionIndex;
#[cfg(any(feature = "std", test))] #[cfg(any(feature = "std", test))]
use sp_version::NativeVersion; use sp_version::NativeVersion;
use sp_version::RuntimeVersion; use sp_version::RuntimeVersion;
use xcm::latest::Junction;
pub use frame_system::Call as SystemCall; pub use frame_system::Call as SystemCall;
pub use pallet_balances::Call as BalancesCall; pub use pallet_balances::Call as BalancesCall;
@@ -1088,6 +1091,8 @@ impl parachains_inclusion::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type DisputesHandler = ParasDisputes; type DisputesHandler = ParasDisputes;
type RewardValidators = parachains_reward_points::RewardValidatorsWithEraPoints<Runtime>; type RewardValidators = parachains_reward_points::RewardValidatorsWithEraPoints<Runtime>;
type MessageQueue = MessageQueue;
type WeightInfo = weights::runtime_parachains_inclusion::WeightInfo<Runtime>;
} }
parameter_types! { parameter_types! {
@@ -1098,20 +1103,55 @@ impl parachains_paras::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type WeightInfo = weights::runtime_parachains_paras::WeightInfo<Runtime>; type WeightInfo = weights::runtime_parachains_paras::WeightInfo<Runtime>;
type UnsignedPriority = ParasUnsignedPriority; type UnsignedPriority = ParasUnsignedPriority;
type QueueFootprinter = ParaInclusion;
type NextSessionRotation = Babe; type NextSessionRotation = Babe;
} }
parameter_types! { parameter_types! {
pub const FirstMessageFactorPercent: u64 = 100; /// Amount of weight that can be spent per block to service messages.
///
/// # WARNING
///
/// This is not a good value for para-chains since the `Scheduler` already uses up to 80% block weight.
pub MessageQueueServiceWeight: Weight = Perbill::from_percent(20) * BlockWeights::get().max_block;
pub const MessageQueueHeapSize: u32 = 65_536;
pub const MessageQueueMaxStale: u32 = 16;
} }
impl parachains_ump::Config for Runtime { /// Message processor to handle any messages that were enqueued into the `MessageQueue` pallet.
pub struct MessageProcessor;
impl ProcessMessage for MessageProcessor {
type Origin = AggregateMessageOrigin;
fn process_message(
message: &[u8],
origin: Self::Origin,
meter: &mut WeightMeter,
) -> Result<bool, ProcessMessageError> {
let para = match origin {
AggregateMessageOrigin::Ump(UmpQueueId::Para(para)) => para,
};
xcm_builder::ProcessXcmMessage::<
Junction,
xcm_executor::XcmExecutor<xcm_config::XcmConfig>,
RuntimeCall,
>::process_message(message, Junction::Parachain(para.into()), meter)
}
}
impl pallet_message_queue::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type UmpSink = type Size = u32;
crate::parachains_ump::XcmSink<xcm_executor::XcmExecutor<xcm_config::XcmConfig>, Runtime>; type HeapSize = MessageQueueHeapSize;
type FirstMessageFactorPercent = FirstMessageFactorPercent; type MaxStale = MessageQueueMaxStale;
type ExecuteOverweightOrigin = EnsureRoot<AccountId>; type ServiceWeight = MessageQueueServiceWeight;
type WeightInfo = weights::runtime_parachains_ump::WeightInfo<Runtime>; #[cfg(not(feature = "runtime-benchmarks"))]
type MessageProcessor = MessageProcessor;
#[cfg(feature = "runtime-benchmarks")]
type MessageProcessor =
pallet_message_queue::mock_helpers::NoopMessageProcessor<AggregateMessageOrigin>;
type QueueChangeHandler = ParaInclusion;
type WeightInfo = weights::pallet_message_queue::WeightInfo<Runtime>;
} }
impl parachains_dmp::Config for Runtime {} impl parachains_dmp::Config for Runtime {}
@@ -1411,7 +1451,6 @@ construct_runtime! {
Paras: parachains_paras::{Pallet, Call, Storage, Event, Config, ValidateUnsigned} = 56, Paras: parachains_paras::{Pallet, Call, Storage, Event, Config, ValidateUnsigned} = 56,
Initializer: parachains_initializer::{Pallet, Call, Storage} = 57, Initializer: parachains_initializer::{Pallet, Call, Storage} = 57,
Dmp: parachains_dmp::{Pallet, Storage} = 58, Dmp: parachains_dmp::{Pallet, Storage} = 58,
Ump: parachains_ump::{Pallet, Call, Storage, Event} = 59,
Hrmp: parachains_hrmp::{Pallet, Call, Storage, Event<T>, Config} = 60, Hrmp: parachains_hrmp::{Pallet, Call, Storage, Event<T>, Config} = 60,
ParaSessionInfo: parachains_session_info::{Pallet, Storage} = 61, ParaSessionInfo: parachains_session_info::{Pallet, Storage} = 61,
ParasDisputes: parachains_disputes::{Pallet, Call, Storage, Event<T>} = 62, ParasDisputes: parachains_disputes::{Pallet, Call, Storage, Event<T>} = 62,
@@ -1425,6 +1464,9 @@ construct_runtime! {
// Pallet for sending XCM. // Pallet for sending XCM.
XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event<T>, Origin, Config} = 99, XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event<T>, Origin, Config} = 99,
// Generalized message queue
MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event<T>} = 100,
} }
} }
@@ -1485,7 +1527,12 @@ pub mod migrations {
); );
/// Unreleased migrations. Add new ones here: /// Unreleased migrations. Add new ones here:
pub type Unreleased = SetStorageVersions; pub type Unreleased = (
SetStorageVersions,
// Remove UMP dispatch queue <https://github.com/paritytech/polkadot/pull/6271>
parachains_configuration::migration::v6::MigrateToV6<Runtime>,
ump_migrations::UpdateUmpLimits,
);
/// Migrations that set `StorageVersion`s we missed to set. /// Migrations that set `StorageVersion`s we missed to set.
pub struct SetStorageVersions; pub struct SetStorageVersions;
@@ -1510,6 +1557,24 @@ pub mod migrations {
} }
} }
/// Helpers to configure the ump migrations.
pub mod ump_migrations {
use runtime_parachains::configuration::migration_ump;
pub const MAX_UPWARD_QUEUE_SIZE: u32 = 4 * 1024 * 1024;
pub const MAX_UPWARD_QUEUE_COUNT: u32 = 699050;
pub const MAX_UPWARD_MESSAGE_SIZE: u32 = (1 << 16) - 5; // Checked in test `max_upward_message_size`.
pub const MAX_UPWARD_MESSAGE_NUM_PER_CANDIDATE: u32 = 128;
pub type UpdateUmpLimits = migration_ump::latest::ScheduleConfigUpdate<
super::Runtime,
MAX_UPWARD_QUEUE_SIZE,
MAX_UPWARD_QUEUE_COUNT,
MAX_UPWARD_MESSAGE_SIZE,
MAX_UPWARD_MESSAGE_NUM_PER_CANDIDATE,
>;
}
/// Unchecked extrinsic type as expected by this runtime. /// Unchecked extrinsic type as expected by this runtime.
pub type UncheckedExtrinsic = pub type UncheckedExtrinsic =
generic::UncheckedExtrinsic<Address, RuntimeCall, Signature, SignedExtra>; generic::UncheckedExtrinsic<Address, RuntimeCall, Signature, SignedExtra>;
@@ -1525,13 +1590,9 @@ pub type Executive = frame_executive::Executive<
/// The payload being signed in the transactions. /// The payload being signed in the transactions.
pub type SignedPayload = generic::SignedPayload<RuntimeCall, SignedExtra>; pub type SignedPayload = generic::SignedPayload<RuntimeCall, SignedExtra>;
#[cfg(feature = "runtime-benchmarks")]
#[macro_use]
extern crate frame_benchmarking;
#[cfg(feature = "runtime-benchmarks")] #[cfg(feature = "runtime-benchmarks")]
mod benches { mod benches {
define_benchmarks!( frame_benchmarking::define_benchmarks!(
// Polkadot // Polkadot
// NOTE: Make sure to prefix these with `runtime_common::` so // NOTE: Make sure to prefix these with `runtime_common::` so
// that the path resolves correctly in the generated file. // that the path resolves correctly in the generated file.
@@ -1544,10 +1605,10 @@ mod benches {
[runtime_parachains::hrmp, Hrmp] [runtime_parachains::hrmp, Hrmp]
[runtime_parachains::disputes, ParasDisputes] [runtime_parachains::disputes, ParasDisputes]
[runtime_parachains::disputes::slashing, ParasSlashing] [runtime_parachains::disputes::slashing, ParasSlashing]
[runtime_parachains::inclusion, ParaInclusion]
[runtime_parachains::initializer, Initializer] [runtime_parachains::initializer, Initializer]
[runtime_parachains::paras_inherent, ParaInherent] [runtime_parachains::paras_inherent, ParaInherent]
[runtime_parachains::paras, Paras] [runtime_parachains::paras, Paras]
[runtime_parachains::ump, Ump]
// Substrate // Substrate
[pallet_balances, Balances] [pallet_balances, Balances]
[pallet_balances, NisCounterpartBalances] [pallet_balances, NisCounterpartBalances]
@@ -1563,6 +1624,7 @@ mod benches {
[pallet_identity, Identity] [pallet_identity, Identity]
[pallet_im_online, ImOnline] [pallet_im_online, ImOnline]
[pallet_indices, Indices] [pallet_indices, Indices]
[pallet_message_queue, MessageQueue]
[pallet_multisig, Multisig] [pallet_multisig, Multisig]
[pallet_nomination_pools, NominationPoolsBench::<Runtime>] [pallet_nomination_pools, NominationPoolsBench::<Runtime>]
[pallet_offences, OffencesBench::<Runtime>] [pallet_offences, OffencesBench::<Runtime>]
+8
View File
@@ -146,3 +146,11 @@ fn nominator_limit() {
fn call_size() { fn call_size() {
RuntimeCall::assert_size_under(230); RuntimeCall::assert_size_under(230);
} }
#[test]
fn max_upward_message_size() {
assert_eq!(
ump_migrations::MAX_UPWARD_MESSAGE_SIZE,
pallet_message_queue::MaxMessageLenOf::<Runtime>::get()
);
}
+2 -1
View File
@@ -33,6 +33,7 @@ pub mod pallet_identity;
pub mod pallet_im_online; pub mod pallet_im_online;
pub mod pallet_indices; pub mod pallet_indices;
pub mod pallet_membership; pub mod pallet_membership;
pub mod pallet_message_queue;
pub mod pallet_multisig; pub mod pallet_multisig;
pub mod pallet_nis; pub mod pallet_nis;
pub mod pallet_nomination_pools; pub mod pallet_nomination_pools;
@@ -60,8 +61,8 @@ pub mod runtime_parachains_configuration;
pub mod runtime_parachains_disputes; pub mod runtime_parachains_disputes;
pub mod runtime_parachains_disputes_slashing; pub mod runtime_parachains_disputes_slashing;
pub mod runtime_parachains_hrmp; pub mod runtime_parachains_hrmp;
pub mod runtime_parachains_inclusion;
pub mod runtime_parachains_initializer; pub mod runtime_parachains_initializer;
pub mod runtime_parachains_paras; pub mod runtime_parachains_paras;
pub mod runtime_parachains_paras_inherent; pub mod runtime_parachains_paras_inherent;
pub mod runtime_parachains_ump;
pub mod xcm; pub mod xcm;
@@ -0,0 +1,176 @@
// Copyright 2017-2022 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 <http://www.gnu.org/licenses/>.
//! Autogenerated weights for `pallet_message_queue`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2023-02-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K`
//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024
// Executed Command:
// ./target/release/polkadot
// benchmark
// pallet
// --chain=kusama-dev
// --steps=50
// --repeat=20
// --pallet=pallet-message-queue
// --extrinsic=*
// --heap-pages=4096
// --header=file_header.txt
// --output
// runtime/kusama/src/weights/pallet_message_queue.rs
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
#![allow(unused_imports)]
use frame_support::{traits::Get, weights::Weight};
use sp_std::marker::PhantomData;
/// Weight functions for `pallet_message_queue`.
pub struct WeightInfo<T>(PhantomData<T>);
impl<T: frame_system::Config> pallet_message_queue::WeightInfo for WeightInfo<T> {
/// Storage: MessageQueue ServiceHead (r:1 w:0)
/// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen)
/// Storage: MessageQueue BookStateFor (r:2 w:2)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
fn ready_ring_knit() -> Weight {
// Proof Size summary in bytes:
// Measured: `837`
// Estimated: `5554`
// Minimum execution time: 5_669 nanoseconds.
Weight::from_parts(5_925_000, 0)
.saturating_add(Weight::from_parts(0, 5554))
.saturating_add(T::DbWeight::get().reads(3))
.saturating_add(T::DbWeight::get().writes(2))
}
/// Storage: MessageQueue BookStateFor (r:2 w:2)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
/// Storage: MessageQueue ServiceHead (r:1 w:1)
/// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen)
fn ready_ring_unknit() -> Weight {
// Proof Size summary in bytes:
// Measured: `837`
// Estimated: `5554`
// Minimum execution time: 5_604 nanoseconds.
Weight::from_parts(5_993_000, 0)
.saturating_add(Weight::from_parts(0, 5554))
.saturating_add(T::DbWeight::get().reads(3))
.saturating_add(T::DbWeight::get().writes(3))
}
/// Storage: MessageQueue BookStateFor (r:1 w:1)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
fn service_queue_base() -> Weight {
// Proof Size summary in bytes:
// Measured: `576`
// Estimated: `2527`
// Minimum execution time: 2_104 nanoseconds.
Weight::from_parts(2_241_000, 0)
.saturating_add(Weight::from_parts(0, 2527))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
/// Storage: MessageQueue Pages (r:1 w:1)
/// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen)
fn service_page_base_completion() -> Weight {
// Proof Size summary in bytes:
// Measured: `648`
// Estimated: `68060`
// Minimum execution time: 3_175 nanoseconds.
Weight::from_parts(3_289_000, 0)
.saturating_add(Weight::from_parts(0, 68060))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
/// Storage: MessageQueue Pages (r:1 w:1)
/// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen)
fn service_page_base_no_completion() -> Weight {
// Proof Size summary in bytes:
// Measured: `648`
// Estimated: `68060`
// Minimum execution time: 3_198 nanoseconds.
Weight::from_parts(3_308_000, 0)
.saturating_add(Weight::from_parts(0, 68060))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
fn service_page_item() -> Weight {
// Proof Size summary in bytes:
// Measured: `969`
// Estimated: `0`
// Minimum execution time: 46_864 nanoseconds.
Weight::from_parts(47_073_000, 0)
.saturating_add(Weight::from_parts(0, 0))
}
/// Storage: MessageQueue ServiceHead (r:1 w:1)
/// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen)
/// Storage: MessageQueue BookStateFor (r:1 w:0)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
fn bump_service_head() -> Weight {
// Proof Size summary in bytes:
// Measured: `712`
// Estimated: `3027`
// Minimum execution time: 3_552 nanoseconds.
Weight::from_parts(3_710_000, 0)
.saturating_add(Weight::from_parts(0, 3027))
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(1))
}
/// Storage: MessageQueue BookStateFor (r:1 w:1)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
/// Storage: MessageQueue Pages (r:1 w:1)
/// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen)
fn reap_page() -> Weight {
// Proof Size summary in bytes:
// Measured: `66857`
// Estimated: `70587`
// Minimum execution time: 38_491 nanoseconds.
Weight::from_parts(46_983_000, 0)
.saturating_add(Weight::from_parts(0, 70587))
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(2))
}
/// Storage: MessageQueue BookStateFor (r:1 w:1)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
/// Storage: MessageQueue Pages (r:1 w:1)
/// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen)
fn execute_overweight_page_removed() -> Weight {
// Proof Size summary in bytes:
// Measured: `66857`
// Estimated: `70587`
// Minimum execution time: 88_529 nanoseconds.
Weight::from_parts(144_649_000, 0)
.saturating_add(Weight::from_parts(0, 70587))
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(2))
}
/// Storage: MessageQueue BookStateFor (r:1 w:1)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
/// Storage: MessageQueue Pages (r:1 w:1)
/// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen)
fn execute_overweight_page_updated() -> Weight {
// Proof Size summary in bytes:
// Measured: `66857`
// Estimated: `70587`
// Minimum execution time: 79_494 nanoseconds.
Weight::from_parts(84_895_000, 0)
.saturating_add(Weight::from_parts(0, 70587))
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(2))
}
}
@@ -0,0 +1,66 @@
// Copyright 2017-2022 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 <http://www.gnu.org/licenses/>.
//! Autogenerated weights for `runtime_parachains::inclusion`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K`
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024
// Executed Command:
// ./target/release/polkadot
// benchmark
// pallet
// --chain=kusama-dev
// --steps=50
// --repeat=20
// --pallet=runtime_parachains::inclusion
// --extrinsic=*
// --execution=wasm
// --wasm-execution=compiled
// --header=./file_header.txt
// --output=./runtime/kusama/src/weights
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
#![allow(unused_imports)]
use frame_support::{traits::Get, weights::Weight};
use sp_std::marker::PhantomData;
/// Weight functions for `runtime_parachains::inclusion`.
pub struct WeightInfo<T>(PhantomData<T>);
impl<T: frame_system::Config> runtime_parachains::inclusion::WeightInfo for WeightInfo<T> {
/// Storage: MessageQueue BookStateFor (r:1 w:1)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
/// Storage: MessageQueue Pages (r:1 w:999)
/// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen)
/// The range of component `i` is `[1, 1000]`.
fn receive_upward_messages(i: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `51490`
// Estimated: `70587`
// Minimum execution time: 47_556 nanoseconds.
Weight::from_parts(48_839_000, 0)
.saturating_add(Weight::from_parts(0, 70587))
// Standard Error: 49_019
.saturating_add(Weight::from_parts(43_136_059, 0).saturating_mul(i.into()))
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(1))
.saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into())))
}
}
@@ -1,93 +0,0 @@
// 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 <http://www.gnu.org/licenses/>.
//! Autogenerated weights for `runtime_parachains::ump`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2023-04-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024
// Executed Command:
// ./target/production/polkadot
// benchmark
// pallet
// --chain=kusama-dev
// --steps=50
// --repeat=20
// --pallet=runtime_parachains::ump
// --extrinsic=*
// --execution=wasm
// --wasm-execution=compiled
// --header=./file_header.txt
// --output=./runtime/kusama/src/weights/runtime_parachains_ump.rs
#![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 `runtime_parachains::ump`.
pub struct WeightInfo<T>(PhantomData<T>);
impl<T: frame_system::Config> runtime_parachains::ump::WeightInfo for WeightInfo<T> {
/// The range of component `s` is `[0, 51200]`.
fn process_upward_message(s: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 5_945_000 picoseconds.
Weight::from_parts(6_047_000, 0)
.saturating_add(Weight::from_parts(0, 0))
// Standard Error: 8
.saturating_add(Weight::from_parts(1_364, 0).saturating_mul(s.into()))
}
/// Storage: Ump NeedsDispatch (r:1 w:1)
/// Proof Skipped: Ump NeedsDispatch (max_values: Some(1), max_size: None, mode: Measured)
/// Storage: Ump NextDispatchRoundStartWith (r:1 w:1)
/// Proof Skipped: Ump NextDispatchRoundStartWith (max_values: Some(1), max_size: None, mode: Measured)
/// Storage: Ump RelayDispatchQueues (r:0 w:1)
/// Proof Skipped: Ump RelayDispatchQueues (max_values: None, max_size: None, mode: Measured)
/// Storage: Ump RelayDispatchQueueSize (r:0 w:1)
/// Proof Skipped: Ump RelayDispatchQueueSize (max_values: None, max_size: None, mode: Measured)
fn clean_ump_after_outgoing() -> Weight {
// Proof Size summary in bytes:
// Measured: `206`
// Estimated: `1691`
// Minimum execution time: 9_308_000 picoseconds.
Weight::from_parts(9_501_000, 0)
.saturating_add(Weight::from_parts(0, 1691))
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(4))
}
/// Storage: Ump Overweight (r:1 w:1)
/// Proof Skipped: Ump Overweight (max_values: None, max_size: None, mode: Measured)
/// Storage: Ump CounterForOverweight (r:1 w:1)
/// Proof: Ump CounterForOverweight (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
fn service_overweight() -> Weight {
// Proof Size summary in bytes:
// Measured: `223`
// Estimated: `3688`
// Minimum execution time: 23_650_000 picoseconds.
Weight::from_parts(23_963_000, 0)
.saturating_add(Weight::from_parts(0, 3688))
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(2))
}
}
+11
View File
@@ -30,6 +30,7 @@ pallet-authority-discovery = { git = "https://github.com/paritytech/substrate",
pallet-authorship = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-authorship = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-babe = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-babe = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-message-queue = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-session = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-session = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-staking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-staking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
@@ -80,9 +81,11 @@ std = [
"sp-runtime/std", "sp-runtime/std",
"sp-session/std", "sp-session/std",
"sp-staking/std", "sp-staking/std",
"pallet-authority-discovery/std",
"pallet-authorship/std", "pallet-authorship/std",
"pallet-babe/std", "pallet-babe/std",
"pallet-balances/std", "pallet-balances/std",
"pallet-message-queue/std",
"pallet-session/std", "pallet-session/std",
"pallet-staking/std", "pallet-staking/std",
"pallet-timestamp/std", "pallet-timestamp/std",
@@ -97,15 +100,23 @@ runtime-benchmarks = [
"frame-benchmarking/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks",
"frame-support/runtime-benchmarks", "frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks", "frame-system/runtime-benchmarks",
"pallet-babe/runtime-benchmarks",
"pallet-balances/runtime-benchmarks",
"pallet-message-queue/runtime-benchmarks",
"pallet-staking/runtime-benchmarks", "pallet-staking/runtime-benchmarks",
"pallet-timestamp/runtime-benchmarks",
"pallet-vesting/runtime-benchmarks",
"primitives/runtime-benchmarks", "primitives/runtime-benchmarks",
"static_assertions", "static_assertions",
"sp-application-crypto", "sp-application-crypto",
] ]
try-runtime = [ try-runtime = [
"frame-support/try-runtime", "frame-support/try-runtime",
"pallet-authority-discovery/try-runtime",
"pallet-authorship/try-runtime", "pallet-authorship/try-runtime",
"pallet-babe/try-runtime",
"pallet-balances/try-runtime", "pallet-balances/try-runtime",
"pallet-message-queue/try-runtime",
"pallet-session/try-runtime", "pallet-session/try-runtime",
"pallet-staking/try-runtime", "pallet-staking/try-runtime",
"pallet-timestamp/try-runtime", "pallet-timestamp/try-runtime",
@@ -18,8 +18,8 @@
//! //!
//! Configuration can change only at session boundaries and is buffered until then. //! Configuration can change only at session boundaries and is buffered until then.
use crate::shared; use crate::{inclusion::MAX_UPWARD_MESSAGE_SIZE_BOUND, shared};
use frame_support::{pallet_prelude::*, weights::constants::WEIGHT_REF_TIME_PER_MILLIS}; use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*; use frame_system::pallet_prelude::*;
use parity_scale_codec::{Decode, Encode}; use parity_scale_codec::{Decode, Encode};
use polkadot_parachain::primitives::{MAX_HORIZONTAL_MESSAGE_NUM, MAX_UPWARD_MESSAGE_NUM}; use polkadot_parachain::primitives::{MAX_HORIZONTAL_MESSAGE_NUM, MAX_UPWARD_MESSAGE_NUM};
@@ -36,9 +36,10 @@ mod tests;
#[cfg(feature = "runtime-benchmarks")] #[cfg(feature = "runtime-benchmarks")]
mod benchmarking; mod benchmarking;
pub use pallet::*;
pub mod migration; pub mod migration;
pub mod migration_ump;
pub use pallet::*;
const LOG_TARGET: &str = "runtime::configuration"; const LOG_TARGET: &str = "runtime::configuration";
@@ -132,11 +133,6 @@ pub struct HostConfiguration<BlockNumber> {
/// decide to do with its PoV so this value in practice will be picked as a fraction of the PoV /// decide to do with its PoV so this value in practice will be picked as a fraction of the PoV
/// size. /// size.
pub max_downward_message_size: u32, pub max_downward_message_size: u32,
/// The amount of weight we wish to devote to the processing the dispatchable upward messages
/// stage.
///
/// NOTE that this is a soft limit and could be exceeded.
pub ump_service_total_weight: Weight,
/// The maximum number of outbound HRMP channels a parachain is allowed to open. /// The maximum number of outbound HRMP channels a parachain is allowed to open.
pub hrmp_max_parachain_outbound_channels: u32, pub hrmp_max_parachain_outbound_channels: u32,
/// The maximum number of outbound HRMP channels a parathread is allowed to open. /// The maximum number of outbound HRMP channels a parathread is allowed to open.
@@ -214,9 +210,6 @@ pub struct HostConfiguration<BlockNumber> {
pub needed_approvals: u32, pub needed_approvals: u32,
/// The number of samples to do of the `RelayVRFModulo` approval assignment criterion. /// The number of samples to do of the `RelayVRFModulo` approval assignment criterion.
pub relay_vrf_modulo_samples: u32, pub relay_vrf_modulo_samples: u32,
/// The maximum amount of weight any individual upward message may consume. Messages above this
/// weight go into the overweight queue and may only be serviced explicitly.
pub ump_max_individual_weight: Weight,
/// This flag controls whether PVF pre-checking is enabled. /// This flag controls whether PVF pre-checking is enabled.
/// ///
/// If the flag is false, the behavior should be exactly the same as prior. Specifically, the /// If the flag is false, the behavior should be exactly the same as prior. Specifically, the
@@ -278,7 +271,6 @@ impl<BlockNumber: Default + From<u32>> Default for HostConfiguration<BlockNumber
max_upward_queue_count: Default::default(), max_upward_queue_count: Default::default(),
max_upward_queue_size: Default::default(), max_upward_queue_size: Default::default(),
max_downward_message_size: Default::default(), max_downward_message_size: Default::default(),
ump_service_total_weight: Default::default(),
max_upward_message_size: Default::default(), max_upward_message_size: Default::default(),
max_upward_message_num_per_candidate: Default::default(), max_upward_message_num_per_candidate: Default::default(),
hrmp_sender_deposit: Default::default(), hrmp_sender_deposit: Default::default(),
@@ -291,10 +283,6 @@ impl<BlockNumber: Default + From<u32>> Default for HostConfiguration<BlockNumber
hrmp_max_parachain_outbound_channels: Default::default(), hrmp_max_parachain_outbound_channels: Default::default(),
hrmp_max_parathread_outbound_channels: Default::default(), hrmp_max_parathread_outbound_channels: Default::default(),
hrmp_max_message_num_per_candidate: Default::default(), hrmp_max_message_num_per_candidate: Default::default(),
ump_max_individual_weight: Weight::from_parts(
20u64 * WEIGHT_REF_TIME_PER_MILLIS,
MAX_POV_SIZE as u64,
),
pvf_checking_enabled: false, pvf_checking_enabled: false,
pvf_voting_ttl: 2u32.into(), pvf_voting_ttl: 2u32.into(),
minimum_validation_upgrade_delay: 2.into(), minimum_validation_upgrade_delay: 2.into(),
@@ -404,7 +392,7 @@ where
}) })
} }
if self.max_upward_message_size > crate::ump::MAX_UPWARD_MESSAGE_SIZE_BOUND { if self.max_upward_message_size > crate::inclusion::MAX_UPWARD_MESSAGE_SIZE_BOUND {
return Err(MaxUpwardMessageSizeExceeded { return Err(MaxUpwardMessageSizeExceeded {
max_message_size: self.max_upward_message_size, max_message_size: self.max_upward_message_size,
}) })
@@ -441,7 +429,7 @@ where
/// This function panics if the configuration is inconsistent. /// This function panics if the configuration is inconsistent.
pub fn panic_if_not_consistent(&self) { pub fn panic_if_not_consistent(&self) {
if let Err(err) = self.check_consistency() { if let Err(err) = self.check_consistency() {
panic!("Host configuration is inconsistent: {:?}", err); panic!("Host configuration is inconsistent: {:?}\nCfg:\n{:#?}", err, self);
} }
} }
} }
@@ -865,6 +853,8 @@ pub mod pallet {
))] ))]
pub fn set_max_upward_queue_size(origin: OriginFor<T>, new: u32) -> DispatchResult { pub fn set_max_upward_queue_size(origin: OriginFor<T>, new: u32) -> DispatchResult {
ensure_root(origin)?; ensure_root(origin)?;
ensure!(new <= MAX_UPWARD_MESSAGE_SIZE_BOUND, Error::<T>::InvalidNewValue);
Self::schedule_config_update(|config| { Self::schedule_config_update(|config| {
config.max_upward_queue_size = new; config.max_upward_queue_size = new;
}) })
@@ -883,19 +873,6 @@ pub mod pallet {
}) })
} }
/// Sets the soft limit for the phase of dispatching dispatchable upward messages.
#[pallet::call_index(26)]
#[pallet::weight((
T::WeightInfo::set_config_with_weight(),
DispatchClass::Operational,
))]
pub fn set_ump_service_total_weight(origin: OriginFor<T>, new: Weight) -> DispatchResult {
ensure_root(origin)?;
Self::schedule_config_update(|config| {
config.ump_service_total_weight = new;
})
}
/// Sets the maximum size of an upward message that can be sent by a candidate. /// Sets the maximum size of an upward message that can be sent by a candidate.
#[pallet::call_index(27)] #[pallet::call_index(27)]
#[pallet::weight(( #[pallet::weight((
@@ -1083,19 +1060,6 @@ pub mod pallet {
}) })
} }
/// Sets the maximum amount of weight any individual upward message may consume.
#[pallet::call_index(40)]
#[pallet::weight((
T::WeightInfo::set_config_with_weight(),
DispatchClass::Operational,
))]
pub fn set_ump_max_individual_weight(origin: OriginFor<T>, new: Weight) -> DispatchResult {
ensure_root(origin)?;
Self::schedule_config_update(|config| {
config.ump_max_individual_weight = new;
})
}
/// Enable or disable PVF pre-checking. Consult the field documentation prior executing. /// Enable or disable PVF pre-checking. Consult the field documentation prior executing.
#[pallet::call_index(41)] #[pallet::call_index(41)]
#[pallet::weight(( #[pallet::weight((
@@ -1283,7 +1247,7 @@ impl<T: Config> Pallet<T> {
// duplicated code (making this function to show up in the top of heaviest functions) only for // duplicated code (making this function to show up in the top of heaviest functions) only for
// the sake of essentially avoiding an indirect call. Doesn't worth it. // the sake of essentially avoiding an indirect call. Doesn't worth it.
#[inline(never)] #[inline(never)]
fn schedule_config_update( pub(crate) fn schedule_config_update(
updater: impl FnOnce(&mut HostConfiguration<T::BlockNumber>), updater: impl FnOnce(&mut HostConfiguration<T::BlockNumber>),
) -> DispatchResult { ) -> DispatchResult {
let mut pending_configs = <PendingConfigs<T>>::get(); let mut pending_configs = <PendingConfigs<T>>::get();
@@ -27,8 +27,6 @@ benchmarks! {
set_config_with_option_u32 {}: set_max_validators(RawOrigin::Root, Some(10)) set_config_with_option_u32 {}: set_max_validators(RawOrigin::Root, Some(10))
set_config_with_weight {}: set_ump_service_total_weight(RawOrigin::Root, Weight::from_parts(3_000_000, 0))
set_hrmp_open_request_ttl {}: { set_hrmp_open_request_ttl {}: {
Err(BenchmarkError::Override( Err(BenchmarkError::Override(
BenchmarkResult::from_weight(T::BlockWeights::get().max_block) BenchmarkResult::from_weight(T::BlockWeights::get().max_block)
@@ -16,11 +16,8 @@
//! A module that is responsible for migration of storage. //! A module that is responsible for migration of storage.
use crate::configuration::{self, ActiveConfig, Config, Pallet, PendingConfigs, MAX_POV_SIZE}; use frame_support::traits::StorageVersion;
use frame_support::{pallet_prelude::*, traits::StorageVersion, weights::Weight}; use primitives::ExecutorParams;
use frame_system::pallet_prelude::BlockNumberFor;
use primitives::vstaging::AsyncBackingParams;
use sp_std::vec::Vec;
/// The current storage version. /// The current storage version.
/// ///
@@ -31,374 +28,8 @@ use sp_std::vec::Vec;
/// v4-v5: <https://github.com/paritytech/polkadot/pull/6937> /// v4-v5: <https://github.com/paritytech/polkadot/pull/6937>
/// + <https://github.com/paritytech/polkadot/pull/6961> /// + <https://github.com/paritytech/polkadot/pull/6961>
/// + <https://github.com/paritytech/polkadot/pull/6934> /// + <https://github.com/paritytech/polkadot/pull/6934>
pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(5); /// v5-v6: <https://github.com/paritytech/polkadot/pull/6271> (remove UMP dispatch queue)
pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(6);
pub mod v5 { pub mod v5;
use super::*; pub mod v6;
use frame_support::{traits::OnRuntimeUpgrade, weights::constants::WEIGHT_REF_TIME_PER_MILLIS};
use primitives::{Balance, SessionIndex};
#[cfg(feature = "try-runtime")]
use sp_std::prelude::*;
// Copied over from configuration.rs @ de9e147695b9f1be8bd44e07861a31e483c8343a and removed
// all the comments, and changed the Weight struct to OldWeight
#[derive(parity_scale_codec::Encode, parity_scale_codec::Decode, Debug, Clone)]
pub struct OldHostConfiguration<BlockNumber> {
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 max_pov_size: u32,
pub max_downward_message_size: u32,
pub ump_service_total_weight: Weight,
pub hrmp_max_parachain_outbound_channels: u32,
pub hrmp_max_parathread_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_max_parathread_inbound_channels: u32,
pub hrmp_channel_max_message_size: u32,
pub code_retention_period: BlockNumber,
pub parathread_cores: u32,
pub parathread_retries: u32,
pub group_rotation_frequency: BlockNumber,
pub chain_availability_period: BlockNumber,
pub thread_availability_period: BlockNumber,
pub scheduling_lookahead: u32,
pub max_validators_per_core: Option<u32>,
pub max_validators: Option<u32>,
pub dispute_period: SessionIndex,
pub dispute_post_conclusion_acceptance_period: BlockNumber,
pub dispute_conclusion_by_time_out_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 ump_max_individual_weight: Weight,
pub pvf_checking_enabled: bool,
pub pvf_voting_ttl: SessionIndex,
pub minimum_validation_upgrade_delay: BlockNumber,
}
impl<BlockNumber: Default + From<u32>> Default for OldHostConfiguration<BlockNumber> {
fn default() -> Self {
Self {
group_rotation_frequency: 1u32.into(),
chain_availability_period: 1u32.into(),
thread_availability_period: 1u32.into(),
no_show_slots: 1u32.into(),
validation_upgrade_cooldown: Default::default(),
validation_upgrade_delay: Default::default(),
code_retention_period: Default::default(),
max_code_size: Default::default(),
max_pov_size: Default::default(),
max_head_data_size: Default::default(),
parathread_cores: Default::default(),
parathread_retries: Default::default(),
scheduling_lookahead: Default::default(),
max_validators_per_core: Default::default(),
max_validators: None,
dispute_period: 6,
dispute_post_conclusion_acceptance_period: 100.into(),
dispute_conclusion_by_time_out_period: 200.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(),
ump_service_total_weight: 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_max_parathread_inbound_channels: Default::default(),
hrmp_channel_max_message_size: Default::default(),
hrmp_max_parachain_outbound_channels: Default::default(),
hrmp_max_parathread_outbound_channels: Default::default(),
hrmp_max_message_num_per_candidate: Default::default(),
ump_max_individual_weight: Weight::from_parts(
20u64 * WEIGHT_REF_TIME_PER_MILLIS,
MAX_POV_SIZE as u64,
),
pvf_checking_enabled: false,
pvf_voting_ttl: 2u32.into(),
minimum_validation_upgrade_delay: 2.into(),
}
}
}
pub struct MigrateToV5<T>(sp_std::marker::PhantomData<T>);
impl<T: Config> OnRuntimeUpgrade for MigrateToV5<T> {
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
log::trace!(target: crate::configuration::LOG_TARGET, "Running pre_upgrade()");
ensure!(StorageVersion::get::<Pallet<T>>() == 4, "The migration requires version 4");
Ok(Vec::new())
}
fn on_runtime_upgrade() -> Weight {
if StorageVersion::get::<Pallet<T>>() == 4 {
let weight_consumed = migrate_to_v5::<T>();
log::info!(target: configuration::LOG_TARGET, "MigrateToV5 executed successfully");
STORAGE_VERSION.put::<Pallet<T>>();
weight_consumed
} else {
log::warn!(target: configuration::LOG_TARGET, "MigrateToV5 should be removed.");
T::DbWeight::get().reads(1)
}
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(_state: Vec<u8>) -> Result<(), &'static str> {
log::trace!(target: crate::configuration::LOG_TARGET, "Running post_upgrade()");
ensure!(
StorageVersion::get::<Pallet<T>>() == STORAGE_VERSION,
"Storage version should be 5 after the migration"
);
Ok(())
}
}
}
fn migrate_to_v5<T: Config>() -> 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: v5::OldHostConfiguration<BlockNumberFor<T>>| ->
configuration::HostConfiguration<BlockNumberFor<T>>
{
super::HostConfiguration {
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,
ump_service_total_weight : pre.ump_service_total_weight,
hrmp_max_parachain_outbound_channels : pre.hrmp_max_parachain_outbound_channels,
hrmp_max_parathread_outbound_channels : pre.hrmp_max_parathread_outbound_channels,
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_parathread_inbound_channels : pre.hrmp_max_parathread_inbound_channels,
hrmp_channel_max_message_size : pre.hrmp_channel_max_message_size,
code_retention_period : pre.code_retention_period,
parathread_cores : pre.parathread_cores,
parathread_retries : pre.parathread_retries,
group_rotation_frequency : pre.group_rotation_frequency,
chain_availability_period : pre.chain_availability_period,
thread_availability_period : pre.thread_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,
ump_max_individual_weight : pre.ump_max_individual_weight,
pvf_checking_enabled : pre.pvf_checking_enabled,
pvf_voting_ttl : pre.pvf_voting_ttl,
minimum_validation_upgrade_delay : pre.minimum_validation_upgrade_delay,
// Default values are zeroes, thus it's ensured allowed ancestry never crosses the upgrade block.
async_backing_params : AsyncBackingParams { max_candidate_depth: 0, allowed_ancestry_len: 0 },
// Default executor parameters set is empty
executor_params : Default::default(),
}
};
if let Err(_) = ActiveConfig::<T>::translate(|pre| pre.map(translate)) {
// `Err` is returned when the pre-migration type cannot be deserialized. This
// cannot happen if the migration runs correctly, i.e. against the expected version.
//
// This happening almost surely will lead to a panic somewhere else. Corruption seems
// to be unlikely to be caused by this. So we just log. Maybe it'll work out still?
log::error!(
target: configuration::LOG_TARGET,
"unexpected error when performing translation of the active configuration during storage upgrade to v5."
);
}
if let Err(_) = PendingConfigs::<T>::translate(|pre| {
pre.map(
|v: Vec<(primitives::SessionIndex, v5::OldHostConfiguration<BlockNumberFor<T>>)>| {
v.into_iter()
.map(|(session, config)| (session, translate(config)))
.collect::<Vec<_>>()
},
)
}) {
log::error!(
target: configuration::LOG_TARGET,
"unexpected error when performing translation of the pending configuration during storage upgrade to v5."
);
}
let num_configs = (PendingConfigs::<T>::get().len() + 1) as u64;
T::DbWeight::get().reads_writes(num_configs, num_configs)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::mock::{new_test_ext, Test};
use primitives::ExecutorParams;
#[test]
fn v4_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!["0000a000005000000a00000000c8000000c800000a0000000a000000100e0000580200000000500000c800000700e8764817020040011e00000000000000005039278c0400000000000000000000005039278c0400000000000000000000e8030000009001001e00000000000000009001008070000000000000000000000a0000000a0000000a00000001000000010500000001c80000000600000058020000580200000200000059000000000000001e000000280000000700c817a80402004001010200000014000000"];
let v4 = v5::OldHostConfiguration::<primitives::BlockNumber>::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!(v4.max_code_size, 10_485_760);
assert_eq!(v4.validation_upgrade_cooldown, 3600);
assert_eq!(v4.max_pov_size, 5_242_880);
assert_eq!(v4.hrmp_channel_max_message_size, 102_400);
assert_eq!(v4.n_delay_tranches, 89);
assert_eq!(v4.ump_max_individual_weight, Weight::from_parts(20_000_000_000, 5_242_880));
assert_eq!(v4.minimum_validation_upgrade_delay, 20);
}
#[test]
fn test_migrate_to_v5() {
// Host configuration has lots of fields. However, in this migration we only remove 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 v4 = v5::OldHostConfiguration::<primitives::BlockNumber> {
ump_max_individual_weight: Weight::from_parts(0x71616e6f6e0au64, 0x71616e6f6e0au64),
needed_approvals: 69,
thread_availability_period: 55,
hrmp_recipient_deposit: 1337,
max_pov_size: 1111,
chain_availability_period: 33,
minimum_validation_upgrade_delay: 20,
..Default::default()
};
let mut pending_configs = Vec::new();
pending_configs.push((100, v4.clone()));
pending_configs.push((300, v4.clone()));
new_test_ext(Default::default()).execute_with(|| {
// Implant the v4 version in the state.
frame_support::storage::unhashed::put_raw(
&configuration::ActiveConfig::<Test>::hashed_key(),
&v4.encode(),
);
frame_support::storage::unhashed::put_raw(
&configuration::PendingConfigs::<Test>::hashed_key(),
&pending_configs.encode(),
);
migrate_to_v5::<Test>();
let v5 = configuration::ActiveConfig::<Test>::get();
let mut configs_to_check = configuration::PendingConfigs::<Test>::get();
configs_to_check.push((0, v5.clone()));
for (_, v4) in configs_to_check {
#[rustfmt::skip]
{
assert_eq!(v4.max_code_size , v5.max_code_size);
assert_eq!(v4.max_head_data_size , v5.max_head_data_size);
assert_eq!(v4.max_upward_queue_count , v5.max_upward_queue_count);
assert_eq!(v4.max_upward_queue_size , v5.max_upward_queue_size);
assert_eq!(v4.max_upward_message_size , v5.max_upward_message_size);
assert_eq!(v4.max_upward_message_num_per_candidate , v5.max_upward_message_num_per_candidate);
assert_eq!(v4.hrmp_max_message_num_per_candidate , v5.hrmp_max_message_num_per_candidate);
assert_eq!(v4.validation_upgrade_cooldown , v5.validation_upgrade_cooldown);
assert_eq!(v4.validation_upgrade_delay , v5.validation_upgrade_delay);
assert_eq!(v4.max_pov_size , v5.max_pov_size);
assert_eq!(v4.max_downward_message_size , v5.max_downward_message_size);
assert_eq!(v4.ump_service_total_weight , v5.ump_service_total_weight);
assert_eq!(v4.hrmp_max_parachain_outbound_channels , v5.hrmp_max_parachain_outbound_channels);
assert_eq!(v4.hrmp_max_parathread_outbound_channels , v5.hrmp_max_parathread_outbound_channels);
assert_eq!(v4.hrmp_sender_deposit , v5.hrmp_sender_deposit);
assert_eq!(v4.hrmp_recipient_deposit , v5.hrmp_recipient_deposit);
assert_eq!(v4.hrmp_channel_max_capacity , v5.hrmp_channel_max_capacity);
assert_eq!(v4.hrmp_channel_max_total_size , v5.hrmp_channel_max_total_size);
assert_eq!(v4.hrmp_max_parachain_inbound_channels , v5.hrmp_max_parachain_inbound_channels);
assert_eq!(v4.hrmp_max_parathread_inbound_channels , v5.hrmp_max_parathread_inbound_channels);
assert_eq!(v4.hrmp_channel_max_message_size , v5.hrmp_channel_max_message_size);
assert_eq!(v4.code_retention_period , v5.code_retention_period);
assert_eq!(v4.parathread_cores , v5.parathread_cores);
assert_eq!(v4.parathread_retries , v5.parathread_retries);
assert_eq!(v4.group_rotation_frequency , v5.group_rotation_frequency);
assert_eq!(v4.chain_availability_period , v5.chain_availability_period);
assert_eq!(v4.thread_availability_period , v5.thread_availability_period);
assert_eq!(v4.scheduling_lookahead , v5.scheduling_lookahead);
assert_eq!(v4.max_validators_per_core , v5.max_validators_per_core);
assert_eq!(v4.max_validators , v5.max_validators);
assert_eq!(v4.dispute_period , v5.dispute_period);
assert_eq!(v4.no_show_slots , v5.no_show_slots);
assert_eq!(v4.n_delay_tranches , v5.n_delay_tranches);
assert_eq!(v4.zeroth_delay_tranche_width , v5.zeroth_delay_tranche_width);
assert_eq!(v4.needed_approvals , v5.needed_approvals);
assert_eq!(v4.relay_vrf_modulo_samples , v5.relay_vrf_modulo_samples);
assert_eq!(v4.ump_max_individual_weight , v5.ump_max_individual_weight);
assert_eq!(v4.pvf_checking_enabled , v5.pvf_checking_enabled);
assert_eq!(v4.pvf_voting_ttl , v5.pvf_voting_ttl);
assert_eq!(v4.minimum_validation_upgrade_delay , v5.minimum_validation_upgrade_delay);
}; // ; makes this a statement. `rustfmt::skip` cannot be put on an expression.
// additional checks for async backing.
assert_eq!(v5.async_backing_params.allowed_ancestry_len, 0);
assert_eq!(v5.async_backing_params.max_candidate_depth, 0);
assert_eq!(v5.executor_params, ExecutorParams::new());
}
});
}
}
@@ -0,0 +1,504 @@
// 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 <http://www.gnu.org/licenses/>.
//! A module that is responsible for migration of storage.
use crate::configuration::{self, Config, Pallet, MAX_POV_SIZE};
use frame_support::{
pallet_prelude::*,
traits::{Defensive, StorageVersion},
weights::Weight,
};
use frame_system::pallet_prelude::BlockNumberFor;
use primitives::vstaging::AsyncBackingParams;
use sp_std::vec::Vec;
use super::*;
use frame_support::{traits::OnRuntimeUpgrade, weights::constants::WEIGHT_REF_TIME_PER_MILLIS};
use primitives::{Balance, SessionIndex};
#[cfg(feature = "try-runtime")]
use sp_std::prelude::*;
// Copied over from configuration.rs @ de9e147695b9f1be8bd44e07861a31e483c8343a and removed
// all the comments, and changed the Weight struct to OldWeight
#[derive(parity_scale_codec::Encode, parity_scale_codec::Decode, Debug, Clone)]
pub struct V4HostConfiguration<BlockNumber> {
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 max_pov_size: u32,
pub max_downward_message_size: u32,
pub ump_service_total_weight: Weight,
pub hrmp_max_parachain_outbound_channels: u32,
pub hrmp_max_parathread_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_max_parathread_inbound_channels: u32,
pub hrmp_channel_max_message_size: u32,
pub code_retention_period: BlockNumber,
pub parathread_cores: u32,
pub parathread_retries: u32,
pub group_rotation_frequency: BlockNumber,
pub chain_availability_period: BlockNumber,
pub thread_availability_period: BlockNumber,
pub scheduling_lookahead: u32,
pub max_validators_per_core: Option<u32>,
pub max_validators: Option<u32>,
pub dispute_period: SessionIndex,
pub dispute_post_conclusion_acceptance_period: BlockNumber,
pub dispute_conclusion_by_time_out_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 ump_max_individual_weight: Weight,
pub pvf_checking_enabled: bool,
pub pvf_voting_ttl: SessionIndex,
pub minimum_validation_upgrade_delay: BlockNumber,
}
#[derive(parity_scale_codec::Encode, parity_scale_codec::Decode, Debug, Clone)]
pub struct V5HostConfiguration<BlockNumber> {
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 ump_service_total_weight: Weight,
pub hrmp_max_parachain_outbound_channels: u32,
pub hrmp_max_parathread_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_max_parathread_inbound_channels: u32,
pub hrmp_channel_max_message_size: u32,
pub executor_params: ExecutorParams,
pub code_retention_period: BlockNumber,
pub parathread_cores: u32,
pub parathread_retries: u32,
pub group_rotation_frequency: BlockNumber,
pub chain_availability_period: BlockNumber,
pub thread_availability_period: BlockNumber,
pub scheduling_lookahead: u32,
pub max_validators_per_core: Option<u32>,
pub max_validators: Option<u32>,
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 ump_max_individual_weight: Weight,
pub pvf_checking_enabled: bool,
pub pvf_voting_ttl: SessionIndex,
pub minimum_validation_upgrade_delay: BlockNumber,
}
#[frame_support::storage_alias]
pub(crate) type V4ActiveConfig<T: Config> =
StorageValue<Pallet<T>, V4HostConfiguration<BlockNumberFor<T>>, OptionQuery>;
#[frame_support::storage_alias]
pub(crate) type V4PendingConfigs<T: Config> = StorageValue<
Pallet<T>,
Vec<(SessionIndex, V4HostConfiguration<BlockNumberFor<T>>)>,
OptionQuery,
>;
#[frame_support::storage_alias]
pub(crate) type V5ActiveConfig<T: Config> =
StorageValue<Pallet<T>, V5HostConfiguration<BlockNumberFor<T>>, OptionQuery>;
#[frame_support::storage_alias]
pub(crate) type V5PendingConfigs<T: Config> = StorageValue<
Pallet<T>,
Vec<(SessionIndex, V5HostConfiguration<BlockNumberFor<T>>)>,
OptionQuery,
>;
impl<BlockNumber: Default + From<u32>> Default for V4HostConfiguration<BlockNumber> {
fn default() -> Self {
Self {
group_rotation_frequency: 1u32.into(),
chain_availability_period: 1u32.into(),
thread_availability_period: 1u32.into(),
no_show_slots: 1u32.into(),
validation_upgrade_cooldown: Default::default(),
validation_upgrade_delay: Default::default(),
code_retention_period: Default::default(),
max_code_size: Default::default(),
max_pov_size: Default::default(),
max_head_data_size: Default::default(),
parathread_cores: Default::default(),
parathread_retries: Default::default(),
scheduling_lookahead: Default::default(),
max_validators_per_core: Default::default(),
max_validators: None,
dispute_period: 6,
dispute_post_conclusion_acceptance_period: 100.into(),
dispute_conclusion_by_time_out_period: 200.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(),
ump_service_total_weight: 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_max_parathread_inbound_channels: Default::default(),
hrmp_channel_max_message_size: Default::default(),
hrmp_max_parachain_outbound_channels: Default::default(),
hrmp_max_parathread_outbound_channels: Default::default(),
hrmp_max_message_num_per_candidate: Default::default(),
ump_max_individual_weight: Weight::from_parts(
20u64 * WEIGHT_REF_TIME_PER_MILLIS,
MAX_POV_SIZE as u64,
),
pvf_checking_enabled: false,
pvf_voting_ttl: 2u32.into(),
minimum_validation_upgrade_delay: 2.into(),
}
}
}
impl<BlockNumber: Default + From<u32>> Default for V5HostConfiguration<BlockNumber> {
fn default() -> Self {
Self {
group_rotation_frequency: 1u32.into(),
chain_availability_period: 1u32.into(),
thread_availability_period: 1u32.into(),
no_show_slots: 1u32.into(),
validation_upgrade_cooldown: Default::default(),
validation_upgrade_delay: Default::default(),
code_retention_period: Default::default(),
max_code_size: Default::default(),
max_pov_size: Default::default(),
max_head_data_size: Default::default(),
parathread_cores: Default::default(),
parathread_retries: Default::default(),
scheduling_lookahead: Default::default(),
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(),
ump_service_total_weight: 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_max_parathread_inbound_channels: Default::default(),
hrmp_channel_max_message_size: Default::default(),
hrmp_max_parachain_outbound_channels: Default::default(),
hrmp_max_parathread_outbound_channels: Default::default(),
hrmp_max_message_num_per_candidate: Default::default(),
ump_max_individual_weight: Weight::from_parts(
20u64 * WEIGHT_REF_TIME_PER_MILLIS,
MAX_POV_SIZE as u64,
),
pvf_checking_enabled: false,
pvf_voting_ttl: 2u32.into(),
minimum_validation_upgrade_delay: 2.into(),
async_backing_params: AsyncBackingParams {
max_candidate_depth: 0,
allowed_ancestry_len: 0,
},
executor_params: Default::default(),
}
}
}
pub struct MigrateToV5<T>(sp_std::marker::PhantomData<T>);
impl<T: Config> OnRuntimeUpgrade for MigrateToV5<T> {
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
log::trace!(target: crate::configuration::LOG_TARGET, "Running pre_upgrade()");
ensure!(StorageVersion::get::<Pallet<T>>() == 4, "The migration requires version 4");
Ok(Vec::new())
}
fn on_runtime_upgrade() -> Weight {
if StorageVersion::get::<Pallet<T>>() == 4 {
let weight_consumed = migrate_to_v5::<T>();
log::info!(target: configuration::LOG_TARGET, "MigrateToV5 executed successfully");
StorageVersion::new(5).put::<Pallet<T>>();
weight_consumed
} else {
log::warn!(target: configuration::LOG_TARGET, "MigrateToV5 should be removed.");
T::DbWeight::get().reads(1)
}
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(_state: Vec<u8>) -> Result<(), &'static str> {
log::trace!(target: crate::configuration::LOG_TARGET, "Running post_upgrade()");
ensure!(
StorageVersion::get::<Pallet<T>>() == 5,
"Storage version should be 5 after the migration"
);
Ok(())
}
}
fn migrate_to_v5<T: Config>() -> 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: V4HostConfiguration<BlockNumberFor<T>>| ->
V5HostConfiguration<BlockNumberFor<T>>
{
V5HostConfiguration {
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,
ump_service_total_weight : pre.ump_service_total_weight,
hrmp_max_parachain_outbound_channels : pre.hrmp_max_parachain_outbound_channels,
hrmp_max_parathread_outbound_channels : pre.hrmp_max_parathread_outbound_channels,
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_parathread_inbound_channels : pre.hrmp_max_parathread_inbound_channels,
hrmp_channel_max_message_size : pre.hrmp_channel_max_message_size,
code_retention_period : pre.code_retention_period,
parathread_cores : pre.parathread_cores,
parathread_retries : pre.parathread_retries,
group_rotation_frequency : pre.group_rotation_frequency,
chain_availability_period : pre.chain_availability_period,
thread_availability_period : pre.thread_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,
ump_max_individual_weight : pre.ump_max_individual_weight,
pvf_checking_enabled : pre.pvf_checking_enabled,
pvf_voting_ttl : pre.pvf_voting_ttl,
minimum_validation_upgrade_delay : pre.minimum_validation_upgrade_delay,
// Default values are zeroes, thus it's ensured allowed ancestry never crosses the upgrade block.
async_backing_params : AsyncBackingParams { max_candidate_depth: 0, allowed_ancestry_len: 0 },
// Default executor parameters set is empty
executor_params : Default::default(),
}
};
let v4 = V4ActiveConfig::<T>::get()
.defensive_proof("Could not decode old config")
.unwrap_or_default();
let v5 = translate(v4);
V5ActiveConfig::<T>::set(Some(v5));
let pending_v4 = V4PendingConfigs::<T>::get()
.defensive_proof("Could not decode old pending")
.unwrap_or_default();
let mut pending_v5 = Vec::new();
for (session, v4) in pending_v4.into_iter() {
let v5 = translate(v4);
pending_v5.push((session, v5));
}
V5PendingConfigs::<T>::set(Some(pending_v5.clone()));
let num_configs = (pending_v5.len() + 1) as u64;
T::DbWeight::get().reads_writes(num_configs, num_configs)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::mock::{new_test_ext, Test};
use primitives::ExecutorParams;
#[test]
fn v4_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!["0000a000005000000a00000000c8000000c800000a0000000a000000100e0000580200000000500000c800000700e8764817020040011e00000000000000005039278c0400000000000000000000005039278c0400000000000000000000e8030000009001001e00000000000000009001008070000000000000000000000a0000000a0000000a00000001000000010500000001c80000000600000058020000580200000200000059000000000000001e000000280000000700c817a80402004001010200000014000000"];
let v4 = v5::V4HostConfiguration::<primitives::BlockNumber>::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!(v4.max_code_size, 10_485_760);
assert_eq!(v4.validation_upgrade_cooldown, 3600);
assert_eq!(v4.max_pov_size, 5_242_880);
assert_eq!(v4.hrmp_channel_max_message_size, 102_400);
assert_eq!(v4.n_delay_tranches, 89);
assert_eq!(v4.ump_max_individual_weight, Weight::from_parts(20_000_000_000, 5_242_880));
assert_eq!(v4.minimum_validation_upgrade_delay, 20);
}
#[test]
fn test_migrate_to_v5() {
// Host configuration has lots of fields. However, in this migration we only remove 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 v4 = v5::V4HostConfiguration::<primitives::BlockNumber> {
ump_max_individual_weight: Weight::from_parts(0x71616e6f6e0au64, 0x71616e6f6e0au64),
needed_approvals: 69,
thread_availability_period: 55,
hrmp_recipient_deposit: 1337,
max_pov_size: 1111,
chain_availability_period: 33,
minimum_validation_upgrade_delay: 20,
..Default::default()
};
let mut pending_configs = Vec::new();
pending_configs.push((100, v4.clone()));
pending_configs.push((300, v4.clone()));
new_test_ext(Default::default()).execute_with(|| {
// Implant the v4 version in the state.
V4ActiveConfig::<Test>::set(Some(v4));
V4PendingConfigs::<Test>::set(Some(pending_configs));
migrate_to_v5::<Test>();
let v5 = V5ActiveConfig::<Test>::get().unwrap();
let mut configs_to_check = V5PendingConfigs::<Test>::get().unwrap();
configs_to_check.push((0, v5.clone()));
for (_, v4) in configs_to_check {
#[rustfmt::skip]
{
assert_eq!(v4.max_code_size , v5.max_code_size);
assert_eq!(v4.max_head_data_size , v5.max_head_data_size);
assert_eq!(v4.max_upward_queue_count , v5.max_upward_queue_count);
assert_eq!(v4.max_upward_queue_size , v5.max_upward_queue_size);
assert_eq!(v4.max_upward_message_size , v5.max_upward_message_size);
assert_eq!(v4.max_upward_message_num_per_candidate , v5.max_upward_message_num_per_candidate);
assert_eq!(v4.hrmp_max_message_num_per_candidate , v5.hrmp_max_message_num_per_candidate);
assert_eq!(v4.validation_upgrade_cooldown , v5.validation_upgrade_cooldown);
assert_eq!(v4.validation_upgrade_delay , v5.validation_upgrade_delay);
assert_eq!(v4.max_pov_size , v5.max_pov_size);
assert_eq!(v4.max_downward_message_size , v5.max_downward_message_size);
assert_eq!(v4.ump_service_total_weight , v5.ump_service_total_weight);
assert_eq!(v4.hrmp_max_parachain_outbound_channels , v5.hrmp_max_parachain_outbound_channels);
assert_eq!(v4.hrmp_max_parathread_outbound_channels , v5.hrmp_max_parathread_outbound_channels);
assert_eq!(v4.hrmp_sender_deposit , v5.hrmp_sender_deposit);
assert_eq!(v4.hrmp_recipient_deposit , v5.hrmp_recipient_deposit);
assert_eq!(v4.hrmp_channel_max_capacity , v5.hrmp_channel_max_capacity);
assert_eq!(v4.hrmp_channel_max_total_size , v5.hrmp_channel_max_total_size);
assert_eq!(v4.hrmp_max_parachain_inbound_channels , v5.hrmp_max_parachain_inbound_channels);
assert_eq!(v4.hrmp_max_parathread_inbound_channels , v5.hrmp_max_parathread_inbound_channels);
assert_eq!(v4.hrmp_channel_max_message_size , v5.hrmp_channel_max_message_size);
assert_eq!(v4.code_retention_period , v5.code_retention_period);
assert_eq!(v4.parathread_cores , v5.parathread_cores);
assert_eq!(v4.parathread_retries , v5.parathread_retries);
assert_eq!(v4.group_rotation_frequency , v5.group_rotation_frequency);
assert_eq!(v4.chain_availability_period , v5.chain_availability_period);
assert_eq!(v4.thread_availability_period , v5.thread_availability_period);
assert_eq!(v4.scheduling_lookahead , v5.scheduling_lookahead);
assert_eq!(v4.max_validators_per_core , v5.max_validators_per_core);
assert_eq!(v4.max_validators , v5.max_validators);
assert_eq!(v4.dispute_period , v5.dispute_period);
assert_eq!(v4.no_show_slots , v5.no_show_slots);
assert_eq!(v4.n_delay_tranches , v5.n_delay_tranches);
assert_eq!(v4.zeroth_delay_tranche_width , v5.zeroth_delay_tranche_width);
assert_eq!(v4.needed_approvals , v5.needed_approvals);
assert_eq!(v4.relay_vrf_modulo_samples , v5.relay_vrf_modulo_samples);
assert_eq!(v4.ump_max_individual_weight , v5.ump_max_individual_weight);
assert_eq!(v4.pvf_checking_enabled , v5.pvf_checking_enabled);
assert_eq!(v4.pvf_voting_ttl , v5.pvf_voting_ttl);
assert_eq!(v4.minimum_validation_upgrade_delay , v5.minimum_validation_upgrade_delay);
}; // ; makes this a statement. `rustfmt::skip` cannot be put on an expression.
// additional checks for async backing.
assert_eq!(v5.async_backing_params.allowed_ancestry_len, 0);
assert_eq!(v5.async_backing_params.max_candidate_depth, 0);
assert_eq!(v5.executor_params, ExecutorParams::new());
}
});
}
}
@@ -0,0 +1,292 @@
// 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 <http://www.gnu.org/licenses/>.
//! A module that is responsible for migration of storage.
use crate::configuration::{self, Config, Pallet};
use frame_support::{
pallet_prelude::*,
traits::{Defensive, StorageVersion},
weights::Weight,
};
use frame_system::pallet_prelude::BlockNumberFor;
use sp_std::vec::Vec;
use frame_support::traits::OnRuntimeUpgrade;
use primitives::SessionIndex;
#[cfg(feature = "try-runtime")]
use sp_std::prelude::*;
use super::v5::V5HostConfiguration;
// Change this once there is V7.
type V6HostConfiguration<BlockNumber> = configuration::HostConfiguration<BlockNumber>;
#[frame_support::storage_alias]
pub(crate) type V5ActiveConfig<T: Config> =
StorageValue<Pallet<T>, V5HostConfiguration<BlockNumberFor<T>>, OptionQuery>;
#[frame_support::storage_alias]
pub(crate) type V5PendingConfigs<T: Config> = StorageValue<
Pallet<T>,
Vec<(SessionIndex, V5HostConfiguration<BlockNumberFor<T>>)>,
OptionQuery,
>;
#[frame_support::storage_alias]
pub(crate) type V6ActiveConfig<T: Config> =
StorageValue<Pallet<T>, V6HostConfiguration<BlockNumberFor<T>>, OptionQuery>;
#[frame_support::storage_alias]
pub(crate) type V6PendingConfigs<T: Config> = StorageValue<
Pallet<T>,
Vec<(SessionIndex, V6HostConfiguration<BlockNumberFor<T>>)>,
OptionQuery,
>;
pub struct MigrateToV6<T>(sp_std::marker::PhantomData<T>);
impl<T: Config> OnRuntimeUpgrade for MigrateToV6<T> {
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, &'static str> {
log::trace!(target: crate::configuration::LOG_TARGET, "Running pre_upgrade()");
ensure!(StorageVersion::get::<Pallet<T>>() == 5, "The migration requires version 4");
Ok(Vec::new())
}
fn on_runtime_upgrade() -> Weight {
if StorageVersion::get::<Pallet<T>>() == 5 {
let weight_consumed = migrate_to_v6::<T>();
log::info!(target: configuration::LOG_TARGET, "MigrateToV6 executed successfully");
StorageVersion::new(6).put::<Pallet<T>>();
weight_consumed
} else {
log::warn!(target: configuration::LOG_TARGET, "MigrateToV6 should be removed.");
T::DbWeight::get().reads(1)
}
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(_state: Vec<u8>) -> Result<(), &'static str> {
log::trace!(target: crate::configuration::LOG_TARGET, "Running post_upgrade()");
ensure!(
StorageVersion::get::<Pallet<T>>() == 6,
"Storage version should be 6 after the migration"
);
Ok(())
}
}
fn migrate_to_v6<T: Config>() -> 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: V5HostConfiguration<BlockNumberFor<T>>| ->
V6HostConfiguration<BlockNumberFor<T>>
{
V6HostConfiguration {
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_max_parachain_outbound_channels : pre.hrmp_max_parachain_outbound_channels,
hrmp_max_parathread_outbound_channels : pre.hrmp_max_parathread_outbound_channels,
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_parathread_inbound_channels : pre.hrmp_max_parathread_inbound_channels,
hrmp_channel_max_message_size : pre.hrmp_channel_max_message_size,
code_retention_period : pre.code_retention_period,
parathread_cores : pre.parathread_cores,
parathread_retries : pre.parathread_retries,
group_rotation_frequency : pre.group_rotation_frequency,
chain_availability_period : pre.chain_availability_period,
thread_availability_period : pre.thread_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_checking_enabled : pre.pvf_checking_enabled,
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,
}
};
let v5 = V5ActiveConfig::<T>::get()
.defensive_proof("Could not decode old config")
.unwrap_or_default();
let v6 = translate(v5);
V6ActiveConfig::<T>::set(Some(v6));
let pending_v4 = V5PendingConfigs::<T>::get()
.defensive_proof("Could not decode old pending")
.unwrap_or_default();
let mut pending_v5 = Vec::new();
for (session, v5) in pending_v4.into_iter() {
let v6 = translate(v5);
pending_v5.push((session, v6));
}
V6PendingConfigs::<T>::set(Some(pending_v5.clone()));
let num_configs = (pending_v5.len() + 1) as u64;
T::DbWeight::get().reads_writes(num_configs, num_configs)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::mock::{new_test_ext, Test};
#[test]
fn v5_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!["00005000005000000a00000000c8000000c800000a0000000a000000c80000006400000000000000000000000000500000c800000700e8764817020040010a0000000000000000c0220fca950300000000000000000000c0220fca9503000000000000000000e8030000009001000a0000000000000000900100008070000000000000000000000a000000050000000500000001000000010500000001c8000000060000005802000002000000280000000000000002000000010000000700c817a8040200400101020000000f000000"];
let v5 =
V5HostConfiguration::<primitives::BlockNumber>::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!(v5.max_code_size, 5242880);
assert_eq!(v5.validation_upgrade_cooldown, 200);
assert_eq!(v5.max_pov_size, 5_242_880);
assert_eq!(v5.hrmp_channel_max_message_size, 102_400);
assert_eq!(v5.n_delay_tranches, 40);
assert_eq!(v5.ump_max_individual_weight, Weight::from_parts(20_000_000_000, 5_242_880));
assert_eq!(v5.minimum_validation_upgrade_delay, 15); // This is the last field in the struct.
}
#[test]
fn test_migrate_to_v6() {
// Host configuration has lots of fields. However, in this migration we only remove 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 v5 = V5HostConfiguration::<primitives::BlockNumber> {
ump_max_individual_weight: Weight::from_parts(0x71616e6f6e0au64, 0x71616e6f6e0au64),
needed_approvals: 69,
thread_availability_period: 55,
hrmp_recipient_deposit: 1337,
max_pov_size: 1111,
chain_availability_period: 33,
minimum_validation_upgrade_delay: 20,
..Default::default()
};
let mut pending_configs = Vec::new();
pending_configs.push((100, v5.clone()));
pending_configs.push((300, v5.clone()));
new_test_ext(Default::default()).execute_with(|| {
// Implant the v5 version in the state.
V5ActiveConfig::<Test>::set(Some(v5));
V5PendingConfigs::<Test>::set(Some(pending_configs));
migrate_to_v6::<Test>();
let v6 = V6ActiveConfig::<Test>::get().unwrap();
let mut configs_to_check = V6PendingConfigs::<Test>::get().unwrap();
configs_to_check.push((0, v6.clone()));
for (_, v5) in configs_to_check {
#[rustfmt::skip]
{
assert_eq!(v5.max_code_size , v6.max_code_size);
assert_eq!(v5.max_head_data_size , v6.max_head_data_size);
assert_eq!(v5.max_upward_queue_count , v6.max_upward_queue_count);
assert_eq!(v5.max_upward_queue_size , v6.max_upward_queue_size);
assert_eq!(v5.max_upward_message_size , v6.max_upward_message_size);
assert_eq!(v5.max_upward_message_num_per_candidate , v6.max_upward_message_num_per_candidate);
assert_eq!(v5.hrmp_max_message_num_per_candidate , v6.hrmp_max_message_num_per_candidate);
assert_eq!(v5.validation_upgrade_cooldown , v6.validation_upgrade_cooldown);
assert_eq!(v5.validation_upgrade_delay , v6.validation_upgrade_delay);
assert_eq!(v5.max_pov_size , v6.max_pov_size);
assert_eq!(v5.max_downward_message_size , v6.max_downward_message_size);
assert_eq!(v5.hrmp_max_parachain_outbound_channels , v6.hrmp_max_parachain_outbound_channels);
assert_eq!(v5.hrmp_max_parathread_outbound_channels , v6.hrmp_max_parathread_outbound_channels);
assert_eq!(v5.hrmp_sender_deposit , v6.hrmp_sender_deposit);
assert_eq!(v5.hrmp_recipient_deposit , v6.hrmp_recipient_deposit);
assert_eq!(v5.hrmp_channel_max_capacity , v6.hrmp_channel_max_capacity);
assert_eq!(v5.hrmp_channel_max_total_size , v6.hrmp_channel_max_total_size);
assert_eq!(v5.hrmp_max_parachain_inbound_channels , v6.hrmp_max_parachain_inbound_channels);
assert_eq!(v5.hrmp_max_parathread_inbound_channels , v6.hrmp_max_parathread_inbound_channels);
assert_eq!(v5.hrmp_channel_max_message_size , v6.hrmp_channel_max_message_size);
assert_eq!(v5.code_retention_period , v6.code_retention_period);
assert_eq!(v5.parathread_cores , v6.parathread_cores);
assert_eq!(v5.parathread_retries , v6.parathread_retries);
assert_eq!(v5.group_rotation_frequency , v6.group_rotation_frequency);
assert_eq!(v5.chain_availability_period , v6.chain_availability_period);
assert_eq!(v5.thread_availability_period , v6.thread_availability_period);
assert_eq!(v5.scheduling_lookahead , v6.scheduling_lookahead);
assert_eq!(v5.max_validators_per_core , v6.max_validators_per_core);
assert_eq!(v5.max_validators , v6.max_validators);
assert_eq!(v5.dispute_period , v6.dispute_period);
assert_eq!(v5.no_show_slots , v6.no_show_slots);
assert_eq!(v5.n_delay_tranches , v6.n_delay_tranches);
assert_eq!(v5.zeroth_delay_tranche_width , v6.zeroth_delay_tranche_width);
assert_eq!(v5.needed_approvals , v6.needed_approvals);
assert_eq!(v5.relay_vrf_modulo_samples , v6.relay_vrf_modulo_samples);
assert_eq!(v5.pvf_checking_enabled , v6.pvf_checking_enabled);
assert_eq!(v5.pvf_voting_ttl , v6.pvf_voting_ttl);
assert_eq!(v5.minimum_validation_upgrade_delay , v6.minimum_validation_upgrade_delay);
assert_eq!(v5.async_backing_params.allowed_ancestry_len, v6.async_backing_params.allowed_ancestry_len);
assert_eq!(v5.async_backing_params.max_candidate_depth , v6.async_backing_params.max_candidate_depth);
assert_eq!(v5.executor_params , v6.executor_params);
}; // ; makes this a statement. `rustfmt::skip` cannot be put on an expression.
}
});
}
}
@@ -0,0 +1,111 @@
// Copyright 2021 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 <http://www.gnu.org/licenses/>.
//! A module that is responsible for migration of UMP storage.
#![allow(unused_imports)] // Since we use features.
use crate::configuration::{self, ActiveConfig, Config, PendingConfigs, WeightInfo, LOG_TARGET};
use parity_scale_codec::{Decode, Encode};
pub mod latest {
use super::*;
use frame_support::{pallet_prelude::Weight, traits::OnRuntimeUpgrade};
/// Force update the UMP limits in the parachain host config.
// NOTE: `OnRuntimeUpgrade` does not have a `self`, so everything must be compile time.
pub struct ScheduleConfigUpdate<
T,
const MAX_UPWARD_QUEUE_SIZE: u32,
const MAX_UPWARD_QUEUE_COUNT: u32,
const MAX_UPWARD_MESSAGE_SIZE: u32,
const MAX_UPWARD_MESSAGE_NUM_PER_CANDIDATE: u32,
>(core::marker::PhantomData<T>);
impl<
T: Config,
const MAX_UPWARD_QUEUE_SIZE: u32,
const MAX_UPWARD_QUEUE_COUNT: u32,
const MAX_UPWARD_MESSAGE_SIZE: u32,
const MAX_UPWARD_MESSAGE_NUM_PER_CANDIDATE: u32,
> OnRuntimeUpgrade
for ScheduleConfigUpdate<
T,
MAX_UPWARD_QUEUE_SIZE,
MAX_UPWARD_QUEUE_COUNT,
MAX_UPWARD_MESSAGE_SIZE,
MAX_UPWARD_MESSAGE_NUM_PER_CANDIDATE,
>
{
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<sp_std::vec::Vec<u8>, &'static str> {
log::info!(target: LOG_TARGET, "pre_upgrade");
let mut pending = PendingConfigs::<T>::get();
pending.sort_by_key(|(s, _)| *s);
log::info!(
target: LOG_TARGET,
"Active HostConfig:\n\n{:#?}\n",
ActiveConfig::<T>::get()
);
log::info!(
target: LOG_TARGET,
"Last pending HostConfig upgrade:\n\n{:#?}\n",
pending.last()
);
Ok((pending.len() as u32).encode())
}
fn on_runtime_upgrade() -> Weight {
if let Err(e) = configuration::Pallet::<T>::schedule_config_update(|cfg| {
cfg.max_upward_queue_size = MAX_UPWARD_QUEUE_SIZE;
cfg.max_upward_queue_count = MAX_UPWARD_QUEUE_COUNT;
cfg.max_upward_message_size = MAX_UPWARD_MESSAGE_SIZE;
cfg.max_upward_message_num_per_candidate = MAX_UPWARD_MESSAGE_NUM_PER_CANDIDATE;
}) {
log::error!(
target: LOG_TARGET,
"\n!!!!!!!!!!!!!!!!!!!!!!!!\nFailed to schedule HostConfig upgrade: {:?}\n!!!!!!!!!!!!!!!!!!!!!!!!\n",
e,
);
}
T::WeightInfo::set_config_with_block_number()
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(state: sp_std::vec::Vec<u8>) -> Result<(), &'static str> {
log::info!(target: LOG_TARGET, "post_upgrade");
let old_pending: u32 = Decode::decode(&mut &state[..]).expect("Known good");
let mut pending = PendingConfigs::<T>::get();
pending.sort_by_key(|(s, _)| *s);
log::info!(
target: LOG_TARGET,
"Last pending HostConfig upgrade:\n\n{:#?}\n",
pending.last()
);
assert_eq!(
pending.len(),
old_pending as usize + 1,
"There must be a new pending upgrade enqueued"
);
Ok(())
}
}
}
@@ -16,7 +16,7 @@
use super::*; use super::*;
use crate::mock::{new_test_ext, Configuration, ParasShared, RuntimeOrigin, Test}; use crate::mock::{new_test_ext, Configuration, ParasShared, RuntimeOrigin, Test};
use frame_support::{assert_err, assert_ok}; use frame_support::{assert_err, assert_noop, assert_ok};
fn on_new_session(session_index: SessionIndex) -> (HostConfiguration<u32>, HostConfiguration<u32>) { fn on_new_session(session_index: SessionIndex) -> (HostConfiguration<u32>, HostConfiguration<u32>) {
ParasShared::set_session_index(session_index); ParasShared::set_session_index(session_index);
@@ -309,7 +309,6 @@ fn setting_pending_config_members() {
max_upward_queue_count: 1337, max_upward_queue_count: 1337,
max_upward_queue_size: 228, max_upward_queue_size: 228,
max_downward_message_size: 2048, max_downward_message_size: 2048,
ump_service_total_weight: Weight::from_parts(20000, 20000),
max_upward_message_size: 448, max_upward_message_size: 448,
max_upward_message_num_per_candidate: 5, max_upward_message_num_per_candidate: 5,
hrmp_sender_deposit: 22, hrmp_sender_deposit: 22,
@@ -322,7 +321,6 @@ fn setting_pending_config_members() {
hrmp_max_parachain_outbound_channels: 10, hrmp_max_parachain_outbound_channels: 10,
hrmp_max_parathread_outbound_channels: 20, hrmp_max_parathread_outbound_channels: 20,
hrmp_max_message_num_per_candidate: 20, hrmp_max_message_num_per_candidate: 20,
ump_max_individual_weight: Weight::from_parts(909, 909),
pvf_checking_enabled: true, pvf_checking_enabled: true,
pvf_voting_ttl: 3, pvf_voting_ttl: 3,
minimum_validation_upgrade_delay: 20, minimum_validation_upgrade_delay: 20,
@@ -418,16 +416,18 @@ fn setting_pending_config_members() {
new_config.max_upward_queue_size, new_config.max_upward_queue_size,
) )
.unwrap(); .unwrap();
assert_noop!(
Configuration::set_max_upward_queue_size(
RuntimeOrigin::root(),
MAX_UPWARD_MESSAGE_SIZE_BOUND + 1,
),
Error::<Test>::InvalidNewValue
);
Configuration::set_max_downward_message_size( Configuration::set_max_downward_message_size(
RuntimeOrigin::root(), RuntimeOrigin::root(),
new_config.max_downward_message_size, new_config.max_downward_message_size,
) )
.unwrap(); .unwrap();
Configuration::set_ump_service_total_weight(
RuntimeOrigin::root(),
new_config.ump_service_total_weight,
)
.unwrap();
Configuration::set_max_upward_message_size( Configuration::set_max_upward_message_size(
RuntimeOrigin::root(), RuntimeOrigin::root(),
new_config.max_upward_message_size, new_config.max_upward_message_size,
@@ -488,11 +488,6 @@ fn setting_pending_config_members() {
new_config.hrmp_max_message_num_per_candidate, new_config.hrmp_max_message_num_per_candidate,
) )
.unwrap(); .unwrap();
Configuration::set_ump_max_individual_weight(
RuntimeOrigin::root(),
new_config.ump_max_individual_weight,
)
.unwrap();
Configuration::set_pvf_checking_enabled( Configuration::set_pvf_checking_enabled(
RuntimeOrigin::root(), RuntimeOrigin::root(),
new_config.pvf_checking_enabled, new_config.pvf_checking_enabled,
+7 -32
View File
@@ -15,18 +15,16 @@
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>. // along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
use super::*; use super::*;
use crate::{ use crate::mock::{
mock::{ deregister_parachain, new_test_ext, register_parachain, register_parachain_with_balance,
new_test_ext, Configuration, Hrmp, MockGenesisConfig, Paras, ParasShared, Configuration, Hrmp, MockGenesisConfig, Paras, ParasShared, RuntimeEvent as MockEvent,
RuntimeEvent as MockEvent, RuntimeOrigin, System, Test, RuntimeOrigin, System, Test,
},
paras::ParaKind,
}; };
use frame_support::{assert_noop, assert_ok, traits::Currency as _}; use frame_support::assert_noop;
use primitives::{BlockNumber, ValidationCode}; use primitives::BlockNumber;
use std::collections::BTreeMap; use std::collections::BTreeMap;
fn run_to_block(to: BlockNumber, new_session: Option<Vec<BlockNumber>>) { pub(crate) fn run_to_block(to: BlockNumber, new_session: Option<Vec<BlockNumber>>) {
let config = Configuration::config(); let config = Configuration::config();
while System::block_number() < to { while System::block_number() < to {
let b = System::block_number(); let b = System::block_number();
@@ -129,29 +127,6 @@ fn default_genesis_config() -> MockGenesisConfig {
} }
} }
fn register_parachain_with_balance(id: ParaId, balance: Balance) {
let validation_code: ValidationCode = vec![1].into();
assert_ok!(Paras::schedule_para_initialize(
id,
crate::paras::ParaGenesisArgs {
para_kind: ParaKind::Parachain,
genesis_head: vec![1].into(),
validation_code: validation_code.clone(),
},
));
assert_ok!(Paras::add_trusted_validation_code(RuntimeOrigin::root(), validation_code));
<Test as Config>::Currency::make_free_balance_be(&id.into_account_truncating(), balance);
}
fn register_parachain(id: ParaId) {
register_parachain_with_balance(id, 1000);
}
fn deregister_parachain(id: ParaId) {
assert_ok!(Paras::schedule_para_cleanup(id));
}
fn channel_exists(sender: ParaId, recipient: ParaId) -> bool { fn channel_exists(sender: ParaId, recipient: ParaId) -> bool {
HrmpChannels::<Test>::get(&HrmpChannelId { sender, recipient }).is_some() HrmpChannels::<Test>::get(&HrmpChannelId { sender, recipient }).is_some()
} }
@@ -0,0 +1,41 @@
// Copyright 2020 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 <http://www.gnu.org/licenses/>.
use super::*;
use frame_benchmarking::benchmarks;
use pallet_message_queue as mq;
benchmarks! {
where_clause {
where
T: mq::Config,
}
receive_upward_messages {
let i in 1 .. 1000;
let max_len = mq::MaxMessageLenOf::<T>::get() as usize;
let para = 42u32.into(); // not especially important.
let upward_messages = vec![vec![0; max_len]; i as usize];
Pallet::<T>::receive_upward_messages(para, vec![vec![0; max_len]; 1].as_slice());
}: { Pallet::<T>::receive_upward_messages(para, upward_messages.as_slice()) }
impl_benchmark_test_suite!(
Pallet,
crate::mock::new_test_ext(Default::default()),
crate::mock::Test
);
}
+331 -43
View File
@@ -21,20 +21,32 @@
//! to included. //! to included.
use crate::{ use crate::{
configuration, disputes, dmp, hrmp, paras, paras_inherent::DisputedBitfield, configuration::{self, HostConfiguration},
scheduler::CoreAssignment, shared, ump, disputes, dmp, hrmp, paras,
paras_inherent::DisputedBitfield,
scheduler::CoreAssignment,
shared,
}; };
use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec}; use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec};
use frame_support::pallet_prelude::*; use frame_support::{
defensive,
pallet_prelude::*,
traits::{Defensive, EnqueueMessage},
BoundedSlice,
};
use pallet_message_queue::OnQueueChanged;
use parity_scale_codec::{Decode, Encode}; use parity_scale_codec::{Decode, Encode};
use primitives::{ use primitives::{
supermajority_threshold, AvailabilityBitfield, BackedCandidate, CandidateCommitments, supermajority_threshold, well_known_keys, AvailabilityBitfield, BackedCandidate,
CandidateDescriptor, CandidateHash, CandidateReceipt, CommittedCandidateReceipt, CoreIndex, CandidateCommitments, CandidateDescriptor, CandidateHash, CandidateReceipt,
GroupIndex, Hash, HeadData, Id as ParaId, SigningContext, UncheckedSignedAvailabilityBitfields, CommittedCandidateReceipt, CoreIndex, GroupIndex, Hash, HeadData, Id as ParaId, SigningContext,
ValidatorId, ValidatorIndex, ValidityAttestation, UncheckedSignedAvailabilityBitfields, UpwardMessage, ValidatorId, ValidatorIndex,
ValidityAttestation,
}; };
use scale_info::TypeInfo; use scale_info::TypeInfo;
use sp_runtime::{traits::One, DispatchError}; use sp_runtime::{traits::One, DispatchError, SaturatedConversion, Saturating};
#[cfg(feature = "std")]
use sp_std::fmt;
use sp_std::{collections::btree_set::BTreeSet, prelude::*}; use sp_std::{collections::btree_set::BTreeSet, prelude::*};
pub use pallet::*; pub use pallet::*;
@@ -42,6 +54,32 @@ pub use pallet::*;
#[cfg(test)] #[cfg(test)]
pub(crate) mod tests; pub(crate) mod tests;
#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;
pub trait WeightInfo {
fn receive_upward_messages(i: u32) -> Weight;
}
pub struct TestWeightInfo;
impl WeightInfo for TestWeightInfo {
fn receive_upward_messages(_: u32) -> Weight {
Weight::MAX
}
}
impl WeightInfo for () {
fn receive_upward_messages(_: u32) -> Weight {
Weight::zero()
}
}
/// Maximum value that `config.max_upward_message_size` can be set to.
///
/// This is used for benchmarking sanely bounding relevant storage items. It is expected from the `configuration`
/// pallet to check these values before setting.
pub const MAX_UPWARD_MESSAGE_SIZE_BOUND: u32 = 128 * 1024;
/// A bitfield signed by a validator indicating that it is keeping its piece of the erasure-coding /// A bitfield signed by a validator indicating that it is keeping its piece of the erasure-coding
/// for any backed candidates referred to by a `1` bit available. /// for any backed candidates referred to by a `1` bit available.
/// ///
@@ -179,6 +217,55 @@ pub fn minimum_backing_votes(n_validators: usize) -> usize {
sp_std::cmp::min(n_validators, 2) sp_std::cmp::min(n_validators, 2)
} }
/// Reads the footprint of queues for a specific origin type.
pub trait QueueFootprinter {
type Origin;
fn message_count(origin: Self::Origin) -> u64;
}
impl QueueFootprinter for () {
type Origin = UmpQueueId;
fn message_count(_: Self::Origin) -> u64 {
0
}
}
/// Aggregate message origin for the `MessageQueue` pallet.
///
/// Can be extended to serve further use-cases besides just UMP. Is stored in storage, so any change
/// to existing values will require a migration.
#[derive(Encode, Decode, Clone, MaxEncodedLen, Eq, PartialEq, RuntimeDebug, TypeInfo)]
pub enum AggregateMessageOrigin {
/// Inbound upward message.
#[codec(index = 0)]
Ump(UmpQueueId),
}
/// Identifies a UMP queue inside the `MessageQueue` pallet.
///
/// It is written in verbose form since future variants like `Loopback` and `Bridged` are already
/// forseeable.
#[derive(Encode, Decode, Clone, MaxEncodedLen, Eq, PartialEq, RuntimeDebug, TypeInfo)]
pub enum UmpQueueId {
/// The message originated from this parachain.
#[codec(index = 0)]
Para(ParaId),
}
#[cfg(feature = "runtime-benchmarks")]
impl From<u32> for AggregateMessageOrigin {
fn from(n: u32) -> Self {
// Some dummy for the benchmarks.
Self::Ump(UmpQueueId::Para(n.into()))
}
}
/// The maximal length of a UMP message.
pub type MaxUmpMessageLenOf<T> =
<<T as Config>::MessageQueue as EnqueueMessage<AggregateMessageOrigin>>::MaxMessageLen;
#[frame_support::pallet] #[frame_support::pallet]
pub mod pallet { pub mod pallet {
use super::*; use super::*;
@@ -193,13 +280,22 @@ pub mod pallet {
+ shared::Config + shared::Config
+ paras::Config + paras::Config
+ dmp::Config + dmp::Config
+ ump::Config
+ hrmp::Config + hrmp::Config
+ configuration::Config + configuration::Config
{ {
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>; type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
type DisputesHandler: disputes::DisputesHandler<Self::BlockNumber>; type DisputesHandler: disputes::DisputesHandler<Self::BlockNumber>;
type RewardValidators: RewardValidators; type RewardValidators: RewardValidators;
/// The system message queue.
///
/// The message queue provides general queueing and processing functionality. Currently it
/// replaces the old `UMP` dispatch queue. Other use-cases can be implemented as well by
/// adding new variants to `AggregateMessageOrigin`.
type MessageQueue: EnqueueMessage<AggregateMessageOrigin>;
/// Weight info for the calls of this pallet.
type WeightInfo: WeightInfo;
} }
#[pallet::event] #[pallet::event]
@@ -211,6 +307,8 @@ pub mod pallet {
CandidateIncluded(CandidateReceipt<T::Hash>, HeadData, CoreIndex, GroupIndex), CandidateIncluded(CandidateReceipt<T::Hash>, HeadData, CoreIndex, GroupIndex),
/// A candidate timed out. `[candidate, head_data]` /// A candidate timed out. `[candidate, head_data]`
CandidateTimedOut(CandidateReceipt<T::Hash>, HeadData, CoreIndex), CandidateTimedOut(CandidateReceipt<T::Hash>, HeadData, CoreIndex),
/// Some upward messages have been received and will be processed.
UpwardMessagesReceived { from: ParaId, count: u32 },
} }
#[pallet::error] #[pallet::error]
@@ -299,6 +397,71 @@ pub mod pallet {
const LOG_TARGET: &str = "runtime::inclusion"; const LOG_TARGET: &str = "runtime::inclusion";
/// The reason that a candidate's outputs were rejected for.
#[derive(derive_more::From)]
#[cfg_attr(feature = "std", derive(Debug))]
enum AcceptanceCheckErr<BlockNumber> {
HeadDataTooLarge,
/// Code upgrades are not permitted at the current time.
PrematureCodeUpgrade,
/// The new runtime blob is too large.
NewCodeTooLarge,
/// The candidate violated this DMP acceptance criteria.
ProcessedDownwardMessages(dmp::ProcessedDownwardMessagesAcceptanceErr),
/// The candidate violated this UMP acceptance criteria.
UpwardMessages(UmpAcceptanceCheckErr),
/// The candidate violated this HRMP watermark acceptance criteria.
HrmpWatermark(hrmp::HrmpWatermarkAcceptanceErr<BlockNumber>),
/// The candidate violated this outbound HRMP acceptance criteria.
OutboundHrmp(hrmp::OutboundHrmpAcceptanceErr),
}
/// An error returned by [`check_upward_messages`] that indicates a violation of one of acceptance
/// criteria rules.
#[cfg_attr(test, derive(PartialEq))]
pub enum UmpAcceptanceCheckErr {
/// The maximal number of messages that can be submitted in one batch was exceeded.
MoreMessagesThanPermitted { sent: u32, permitted: u32 },
/// The maximal size of a single message was exceeded.
MessageSize { idx: u32, msg_size: u32, max_size: u32 },
/// The allowed number of messages in the queue was exceeded.
CapacityExceeded { count: u64, limit: u64 },
/// The allowed combined message size in the queue was exceeded.
TotalSizeExceeded { total_size: u64, limit: u64 },
/// A para-chain cannot send UMP messages while it is offboarding.
IsOffboarding,
}
#[cfg(feature = "std")]
impl fmt::Debug for UmpAcceptanceCheckErr {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match *self {
UmpAcceptanceCheckErr::MoreMessagesThanPermitted { sent, permitted } => write!(
fmt,
"more upward messages than permitted by config ({} > {})",
sent, permitted,
),
UmpAcceptanceCheckErr::MessageSize { idx, msg_size, max_size } => write!(
fmt,
"upward message idx {} larger than permitted by config ({} > {})",
idx, msg_size, max_size,
),
UmpAcceptanceCheckErr::CapacityExceeded { count, limit } => write!(
fmt,
"the ump queue would have more items than permitted by config ({} > {})",
count, limit,
),
UmpAcceptanceCheckErr::TotalSizeExceeded { total_size, limit } => write!(
fmt,
"the ump queue would have grown past the max size permitted by config ({} > {})",
total_size, limit,
),
UmpAcceptanceCheckErr::IsOffboarding =>
write!(fmt, "upward message rejected because the para is off-boarding",),
}
}
}
impl<T: Config> Pallet<T> { impl<T: Config> Pallet<T> {
/// Block initialization logic, called by initializer. /// Block initialization logic, called by initializer.
pub(crate) fn initializer_initialize(_now: T::BlockNumber) -> Weight { pub(crate) fn initializer_initialize(_now: T::BlockNumber) -> Weight {
@@ -311,12 +474,25 @@ impl<T: Config> Pallet<T> {
/// Handle an incoming session change. /// Handle an incoming session change.
pub(crate) fn initializer_on_new_session( pub(crate) fn initializer_on_new_session(
_notification: &crate::initializer::SessionChangeNotification<T::BlockNumber>, _notification: &crate::initializer::SessionChangeNotification<T::BlockNumber>,
outgoing_paras: &[ParaId],
) { ) {
// unlike most drain methods, drained elements are not cleared on `Drop` of the iterator // unlike most drain methods, drained elements are not cleared on `Drop` of the iterator
// and require consumption. // and require consumption.
for _ in <PendingAvailabilityCommitments<T>>::drain() {} for _ in <PendingAvailabilityCommitments<T>>::drain() {}
for _ in <PendingAvailability<T>>::drain() {} for _ in <PendingAvailability<T>>::drain() {}
for _ in <AvailabilityBitfields<T>>::drain() {} for _ in <AvailabilityBitfields<T>>::drain() {}
Self::cleanup_outgoing_ump_dispatch_queues(outgoing_paras);
}
pub(crate) fn cleanup_outgoing_ump_dispatch_queues(outgoing: &[ParaId]) {
for outgoing_para in outgoing {
Self::cleanup_outgoing_ump_dispatch_queue(*outgoing_para);
}
}
pub(crate) fn cleanup_outgoing_ump_dispatch_queue(para: ParaId) {
T::MessageQueue::sweep_queue(AggregateMessageOrigin::Ump(UmpQueueId::Para(para)));
} }
/// Extract the freed cores based on cores that became available. /// Extract the freed cores based on cores that became available.
@@ -698,7 +874,8 @@ impl<T: Config> Pallet<T> {
let relay_parent_number = now; let relay_parent_number = now;
let check_ctx = CandidateCheckContext::<T>::new(now, relay_parent_number); let check_ctx = CandidateCheckContext::<T>::new(now, relay_parent_number);
if let Err(err) = check_ctx.check_validation_outputs( if check_ctx
.check_validation_outputs(
para_id, para_id,
&validation_outputs.head_data, &validation_outputs.head_data,
&validation_outputs.new_validation_code, &validation_outputs.new_validation_code,
@@ -706,12 +883,13 @@ impl<T: Config> Pallet<T> {
&validation_outputs.upward_messages, &validation_outputs.upward_messages,
T::BlockNumber::from(validation_outputs.hrmp_watermark), T::BlockNumber::from(validation_outputs.hrmp_watermark),
&validation_outputs.horizontal_messages, &validation_outputs.horizontal_messages,
) { )
.is_err()
{
log::debug!( log::debug!(
target: LOG_TARGET, target: LOG_TARGET,
"Validation outputs checking for parachain `{}` failed: {:?}", "Validation outputs checking for parachain `{}` failed",
u32::from(para_id), u32::from(para_id),
err,
); );
false false
} else { } else {
@@ -750,31 +928,31 @@ impl<T: Config> Pallet<T> {
// initial weight is config read. // initial weight is config read.
let mut weight = T::DbWeight::get().reads_writes(1, 0); let mut weight = T::DbWeight::get().reads_writes(1, 0);
if let Some(new_code) = commitments.new_validation_code { if let Some(new_code) = commitments.new_validation_code {
weight += <paras::Pallet<T>>::schedule_code_upgrade( weight.saturating_add(<paras::Pallet<T>>::schedule_code_upgrade(
receipt.descriptor.para_id, receipt.descriptor.para_id,
new_code, new_code,
relay_parent_number, relay_parent_number,
&config, &config,
); ));
} }
// enact the messaging facet of the candidate. // enact the messaging facet of the candidate.
weight += <dmp::Pallet<T>>::prune_dmq( weight.saturating_accrue(<dmp::Pallet<T>>::prune_dmq(
receipt.descriptor.para_id, receipt.descriptor.para_id,
commitments.processed_downward_messages, commitments.processed_downward_messages,
); ));
weight += <ump::Pallet<T>>::receive_upward_messages( weight.saturating_accrue(Self::receive_upward_messages(
receipt.descriptor.para_id, receipt.descriptor.para_id,
commitments.upward_messages, commitments.upward_messages.as_slice(),
); ));
weight += <hrmp::Pallet<T>>::prune_hrmp( weight.saturating_accrue(<hrmp::Pallet<T>>::prune_hrmp(
receipt.descriptor.para_id, receipt.descriptor.para_id,
T::BlockNumber::from(commitments.hrmp_watermark), T::BlockNumber::from(commitments.hrmp_watermark),
); ));
weight += <hrmp::Pallet<T>>::queue_outbound_hrmp( weight.saturating_accrue(<hrmp::Pallet<T>>::queue_outbound_hrmp(
receipt.descriptor.para_id, receipt.descriptor.para_id,
commitments.horizontal_messages, commitments.horizontal_messages,
); ));
Self::deposit_event(Event::<T>::CandidateIncluded( Self::deposit_event(Event::<T>::CandidateIncluded(
plain, plain,
@@ -783,12 +961,105 @@ impl<T: Config> Pallet<T> {
backing_group, backing_group,
)); ));
weight + weight.saturating_add(<paras::Pallet<T>>::note_new_head(
<paras::Pallet<T>>::note_new_head(
receipt.descriptor.para_id, receipt.descriptor.para_id,
commitments.head_data, commitments.head_data,
relay_parent_number, relay_parent_number,
) ))
}
/// Check that all the upward messages sent by a candidate pass the acceptance criteria.
pub(crate) fn check_upward_messages(
config: &HostConfiguration<T::BlockNumber>,
para: ParaId,
upward_messages: &[UpwardMessage],
) -> Result<(), UmpAcceptanceCheckErr> {
// Cannot send UMP messages while off-boarding.
if <paras::Pallet<T>>::is_offboarding(para) {
ensure!(upward_messages.is_empty(), UmpAcceptanceCheckErr::IsOffboarding);
}
let additional_msgs = upward_messages.len();
if additional_msgs > config.max_upward_message_num_per_candidate as usize {
return Err(UmpAcceptanceCheckErr::MoreMessagesThanPermitted {
sent: additional_msgs as u32,
permitted: config.max_upward_message_num_per_candidate,
})
}
let fp = T::MessageQueue::footprint(AggregateMessageOrigin::Ump(UmpQueueId::Para(para)));
let (para_queue_count, mut para_queue_size) = (fp.count, fp.size);
if para_queue_count.saturating_add(additional_msgs as u64) >
config.max_upward_queue_count as u64
{
return Err(UmpAcceptanceCheckErr::CapacityExceeded {
count: para_queue_count.saturating_add(additional_msgs as u64),
limit: config.max_upward_queue_count as u64,
})
}
for (idx, msg) in upward_messages.into_iter().enumerate() {
let msg_size = msg.len();
if msg_size > config.max_upward_message_size as usize {
return Err(UmpAcceptanceCheckErr::MessageSize {
idx: idx as u32,
msg_size: msg_size as u32,
max_size: config.max_upward_message_size,
})
}
// make sure that the queue is not overfilled.
// we do it here only once since returning false invalidates the whole relay-chain block.
if para_queue_size.saturating_add(msg_size as u64) > config.max_upward_queue_size as u64
{
return Err(UmpAcceptanceCheckErr::TotalSizeExceeded {
total_size: para_queue_size.saturating_add(msg_size as u64),
limit: config.max_upward_queue_size as u64,
})
}
para_queue_size.saturating_accrue(msg_size as u64);
}
Ok(())
}
/// Enqueues `upward_messages` from a `para`'s accepted candidate block.
///
/// This function is infallible since the candidate was already accepted and we therefore need
/// to deal with the messages as given. Messages that are too long will be ignored since such
/// candidates should have already been rejected in [`Self::check_upward_messages`].
pub(crate) fn receive_upward_messages(para: ParaId, upward_messages: &[Vec<u8>]) -> Weight {
let bounded = upward_messages
.iter()
.filter_map(|d| {
BoundedSlice::try_from(&d[..])
.map_err(|e| {
defensive!("Accepted candidate contains too long msg, len=", d.len());
e
})
.ok()
})
.collect();
Self::receive_bounded_upward_messages(para, bounded)
}
/// Enqueues storage-bounded `upward_messages` from a `para`'s accepted candidate block.
pub(crate) fn receive_bounded_upward_messages(
para: ParaId,
messages: Vec<BoundedSlice<'_, u8, MaxUmpMessageLenOf<T>>>,
) -> Weight {
let count = messages.len() as u32;
if count == 0 {
return Weight::zero()
}
T::MessageQueue::enqueue_messages(
messages.into_iter(),
AggregateMessageOrigin::Ump(UmpQueueId::Para(para)),
);
let weight = <T as Config>::WeightInfo::receive_upward_messages(count);
Self::deposit_event(Event::UpwardMessagesReceived { from: para, count });
weight
} }
/// Cleans up all paras pending availability that the predicate returns true for. /// Cleans up all paras pending availability that the predicate returns true for.
@@ -902,17 +1173,6 @@ const fn availability_threshold(n_validators: usize) -> usize {
supermajority_threshold(n_validators) supermajority_threshold(n_validators)
} }
#[derive(derive_more::From, Debug)]
enum AcceptanceCheckErr<BlockNumber> {
HeadDataTooLarge,
PrematureCodeUpgrade,
NewCodeTooLarge,
ProcessedDownwardMessages(dmp::ProcessedDownwardMessagesAcceptanceErr),
UpwardMessages(ump::AcceptanceCheckErr),
HrmpWatermark(hrmp::HrmpWatermarkAcceptanceErr<BlockNumber>),
OutboundHrmp(hrmp::OutboundHrmpAcceptanceErr),
}
impl<BlockNumber> AcceptanceCheckErr<BlockNumber> { impl<BlockNumber> AcceptanceCheckErr<BlockNumber> {
/// Returns the same error so that it can be threaded through a needle of `DispatchError` and /// Returns the same error so that it can be threaded through a needle of `DispatchError` and
/// ultimately returned from a `Dispatchable`. /// ultimately returned from a `Dispatchable`.
@@ -930,6 +1190,26 @@ impl<BlockNumber> AcceptanceCheckErr<BlockNumber> {
} }
} }
impl<T: Config> OnQueueChanged<AggregateMessageOrigin> for Pallet<T> {
// Write back the remaining queue capacity into `relay_dispatch_queue_remaining_capacity`.
fn on_queue_changed(origin: AggregateMessageOrigin, count: u64, size: u64) {
let para = match origin {
AggregateMessageOrigin::Ump(UmpQueueId::Para(p)) => p,
};
// TODO maybe migrate this to u64
let (count, size) = (count.saturated_into(), size.saturated_into());
// TODO paritytech/polkadot#6283: Remove all usages of `relay_dispatch_queue_size`
#[allow(deprecated)]
well_known_keys::relay_dispatch_queue_size_typed(para).set((count, size));
let config = <configuration::Pallet<T>>::config();
let remaining_count = config.max_upward_queue_count.saturating_sub(count);
let remaining_size = config.max_upward_queue_size.saturating_sub(size);
well_known_keys::relay_dispatch_queue_remaining_capacity(para)
.set((remaining_count, remaining_size));
}
}
/// A collection of data required for checking a candidate. /// A collection of data required for checking a candidate.
pub(crate) struct CandidateCheckContext<T: Config> { pub(crate) struct CandidateCheckContext<T: Config> {
config: configuration::HostConfiguration<T::BlockNumber>, config: configuration::HostConfiguration<T::BlockNumber>,
@@ -965,12 +1245,13 @@ impl<T: Config> CandidateCheckContext<T> {
let relay_parent_number = now - One::one(); let relay_parent_number = now - One::one();
{ {
// this should never fail because the para is registered
let persisted_validation_data = match crate::util::make_persisted_validation_data::<T>( let persisted_validation_data = match crate::util::make_persisted_validation_data::<T>(
para_id, para_id,
relay_parent_number, relay_parent_number,
parent_storage_root, parent_storage_root,
) { )
.defensive_proof("the para is registered")
{
Some(l) => l, Some(l) => l,
None => return Ok(Err(FailedToCreatePVD)), None => return Ok(Err(FailedToCreatePVD)),
}; };
@@ -1018,10 +1299,9 @@ impl<T: Config> CandidateCheckContext<T> {
) { ) {
log::debug!( log::debug!(
target: LOG_TARGET, target: LOG_TARGET,
"Validation outputs checking during inclusion of a candidate {} for parachain `{}` failed: {:?}", "Validation outputs checking during inclusion of a candidate {} for parachain `{}` failed",
candidate_idx, candidate_idx,
u32::from(para_id), u32::from(para_id),
err,
); );
Err(err.strip_into_dispatch_err::<T>())?; Err(err.strip_into_dispatch_err::<T>())?;
}; };
@@ -1059,10 +1339,18 @@ impl<T: Config> CandidateCheckContext<T> {
// check if the candidate passes the messaging acceptance criteria // check if the candidate passes the messaging acceptance criteria
<dmp::Pallet<T>>::check_processed_downward_messages(para_id, processed_downward_messages)?; <dmp::Pallet<T>>::check_processed_downward_messages(para_id, processed_downward_messages)?;
<ump::Pallet<T>>::check_upward_messages(&self.config, para_id, upward_messages)?; Pallet::<T>::check_upward_messages(&self.config, para_id, upward_messages)?;
<hrmp::Pallet<T>>::check_hrmp_watermark(para_id, self.relay_parent_number, hrmp_watermark)?; <hrmp::Pallet<T>>::check_hrmp_watermark(para_id, self.relay_parent_number, hrmp_watermark)?;
<hrmp::Pallet<T>>::check_outbound_hrmp(&self.config, para_id, horizontal_messages)?; <hrmp::Pallet<T>>::check_outbound_hrmp(&self.config, para_id, horizontal_messages)?;
Ok(()) Ok(())
} }
} }
impl<T: Config> QueueFootprinter for Pallet<T> {
type Origin = UmpQueueId;
fn message_count(origin: Self::Origin) -> u64 {
T::MessageQueue::footprint(AggregateMessageOrigin::Ump(origin)).count
}
}
@@ -29,6 +29,7 @@ use crate::{
use assert_matches::assert_matches; use assert_matches::assert_matches;
use frame_support::assert_noop; use frame_support::assert_noop;
use keyring::Sr25519Keyring; use keyring::Sr25519Keyring;
use parity_scale_codec::DecodeAll;
use primitives::{ use primitives::{
BlockNumber, CandidateCommitments, CandidateDescriptor, CollatorId, BlockNumber, CandidateCommitments, CandidateDescriptor, CollatorId,
CompactStatement as Statement, Hash, SignedAvailabilityBitfield, SignedStatement, CompactStatement as Statement, Hash, SignedAvailabilityBitfield, SignedStatement,
@@ -159,6 +160,17 @@ pub(crate) fn back_candidate(
backed backed
} }
pub(crate) fn run_to_block_default_notifications(to: BlockNumber, new_session: Vec<BlockNumber>) {
run_to_block(to, |b| {
new_session.contains(&b).then_some(SessionChangeNotification {
prev_config: Configuration::config(),
new_config: Configuration::config(),
session_index: ParasShared::session_index() + 1,
..Default::default()
})
});
}
pub(crate) fn run_to_block( pub(crate) fn run_to_block(
to: BlockNumber, to: BlockNumber,
new_session: impl Fn(BlockNumber) -> Option<SessionChangeNotification<BlockNumber>>, new_session: impl Fn(BlockNumber) -> Option<SessionChangeNotification<BlockNumber>>,
@@ -177,8 +189,8 @@ pub(crate) fn run_to_block(
&notification.new_config, &notification.new_config,
notification.validators.clone(), notification.validators.clone(),
); );
Paras::initializer_on_new_session(&notification); let outgoing = Paras::initializer_on_new_session(&notification);
ParaInclusion::initializer_on_new_session(&notification); ParaInclusion::initializer_on_new_session(&notification, &outgoing);
} }
System::on_finalize(b); System::on_finalize(b);
@@ -1972,3 +1984,12 @@ fn session_change_wipes() {
assert!(<PendingAvailabilityCommitments<Test>>::iter().collect::<Vec<_>>().is_empty()); assert!(<PendingAvailabilityCommitments<Test>>::iter().collect::<Vec<_>>().is_empty());
}); });
} }
/// Assert that the encoding of a known `AggregateMessageOrigin` did not change.
#[test]
fn aggregate_origin_decode_regression_check() {
let ump = AggregateMessageOrigin::Ump(UmpQueueId::Para(u32::MAX.into()));
let raw = (0u8, 0u8, u32::MAX).encode();
let decoded = AggregateMessageOrigin::decode_all(&mut &raw[..]);
assert_eq!(decoded, Ok(ump), "Migration needed for AggregateMessageOrigin");
}
@@ -22,7 +22,7 @@
use crate::{ use crate::{
configuration::{self, HostConfiguration}, configuration::{self, HostConfiguration},
disputes::{self, DisputesHandler as _, SlashingHandler as _}, disputes::{self, DisputesHandler as _, SlashingHandler as _},
dmp, hrmp, inclusion, paras, scheduler, session_info, shared, ump, dmp, hrmp, inclusion, paras, scheduler, session_info, shared,
}; };
use frame_support::{ use frame_support::{
traits::{OneSessionHandler, Randomness}, traits::{OneSessionHandler, Randomness},
@@ -113,7 +113,6 @@ pub mod pallet {
+ session_info::Config + session_info::Config
+ disputes::Config + disputes::Config
+ dmp::Config + dmp::Config
+ ump::Config
+ hrmp::Config + hrmp::Config
{ {
/// A randomness beacon. /// A randomness beacon.
@@ -168,7 +167,6 @@ pub mod pallet {
T::DisputesHandler::initializer_initialize(now) + T::DisputesHandler::initializer_initialize(now) +
T::SlashingHandler::initializer_initialize(now) + T::SlashingHandler::initializer_initialize(now) +
dmp::Pallet::<T>::initializer_initialize(now) + dmp::Pallet::<T>::initializer_initialize(now) +
ump::Pallet::<T>::initializer_initialize(now) +
hrmp::Pallet::<T>::initializer_initialize(now); hrmp::Pallet::<T>::initializer_initialize(now);
HasInitialized::<T>::set(Some(())); HasInitialized::<T>::set(Some(()));
@@ -179,7 +177,6 @@ pub mod pallet {
fn on_finalize(now: T::BlockNumber) { fn on_finalize(now: T::BlockNumber) {
// reverse initialization order. // reverse initialization order.
hrmp::Pallet::<T>::initializer_finalize(); hrmp::Pallet::<T>::initializer_finalize();
ump::Pallet::<T>::initializer_finalize();
dmp::Pallet::<T>::initializer_finalize(); dmp::Pallet::<T>::initializer_finalize();
T::SlashingHandler::initializer_finalize(); T::SlashingHandler::initializer_finalize();
T::DisputesHandler::initializer_finalize(); T::DisputesHandler::initializer_finalize();
@@ -263,12 +260,11 @@ impl<T: Config> Pallet<T> {
let outgoing_paras = paras::Pallet::<T>::initializer_on_new_session(&notification); let outgoing_paras = paras::Pallet::<T>::initializer_on_new_session(&notification);
scheduler::Pallet::<T>::initializer_on_new_session(&notification); scheduler::Pallet::<T>::initializer_on_new_session(&notification);
inclusion::Pallet::<T>::initializer_on_new_session(&notification); inclusion::Pallet::<T>::initializer_on_new_session(&notification, &outgoing_paras);
session_info::Pallet::<T>::initializer_on_new_session(&notification); session_info::Pallet::<T>::initializer_on_new_session(&notification);
T::DisputesHandler::initializer_on_new_session(&notification); T::DisputesHandler::initializer_on_new_session(&notification);
T::SlashingHandler::initializer_on_new_session(session_index); T::SlashingHandler::initializer_on_new_session(session_index);
dmp::Pallet::<T>::initializer_on_new_session(&notification, &outgoing_paras); dmp::Pallet::<T>::initializer_on_new_session(&notification, &outgoing_paras);
ump::Pallet::<T>::initializer_on_new_session(&notification, &outgoing_paras);
hrmp::Pallet::<T>::initializer_on_new_session(&notification, &outgoing_paras); hrmp::Pallet::<T>::initializer_on_new_session(&notification, &outgoing_paras);
} }
+2 -1
View File
@@ -37,7 +37,6 @@ pub mod reward_points;
pub mod scheduler; pub mod scheduler;
pub mod session_info; pub mod session_info;
pub mod shared; pub mod shared;
pub mod ump;
pub mod runtime_api_impl; pub mod runtime_api_impl;
@@ -47,6 +46,8 @@ mod util;
mod builder; mod builder;
#[cfg(test)] #[cfg(test)]
mod mock; mod mock;
#[cfg(test)]
mod ump_tests;
pub use origin::{ensure_parachain, Origin}; pub use origin::{ensure_parachain, Origin};
pub use paras::ParaLifecycle; pub use paras::ParaLifecycle;
+139 -48
View File
@@ -17,27 +17,31 @@
//! Mocks for all the traits. //! Mocks for all the traits.
use crate::{ use crate::{
configuration, disputes, dmp, hrmp, inclusion, initializer, origin, paras, paras_inherent, configuration, disputes, dmp, hrmp,
scheduler, session_info, shared, inclusion::{self, AggregateMessageOrigin, UmpQueueId},
ump::{self, MessageId, UmpSink}, initializer, origin, paras,
ParaId, paras::ParaKind,
paras_inherent, scheduler, session_info, shared, ParaId,
}; };
use frame_support::{ use frame_support::{
parameter_types, assert_ok, parameter_types,
traits::{ConstU32, GenesisBuild, ValidatorSet, ValidatorSetWithIdentification}, traits::{
weights::Weight, Currency, GenesisBuild, ProcessMessage, ProcessMessageError, ValidatorSet,
ValidatorSetWithIdentification,
},
weights::{Weight, WeightMeter},
}; };
use frame_support_test::TestRandomness; use frame_support_test::TestRandomness;
use parity_scale_codec::Decode; use parity_scale_codec::Decode;
use primitives::{ use primitives::{
AuthorityDiscoveryId, Balance, BlockNumber, CandidateHash, Header, Moment, SessionIndex, AuthorityDiscoveryId, Balance, BlockNumber, CandidateHash, Header, Moment, SessionIndex,
UpwardMessage, ValidatorIndex, UpwardMessage, ValidationCode, ValidatorIndex,
}; };
use sp_core::H256; use sp_core::{ConstU32, H256};
use sp_io::TestExternalities; use sp_io::TestExternalities;
use sp_runtime::{ use sp_runtime::{
traits::{BlakeTwo256, IdentityLookup}, traits::{AccountIdConversion, BlakeTwo256, IdentityLookup},
transaction_validity::TransactionPriority, transaction_validity::TransactionPriority,
Permill, Permill,
}; };
@@ -54,6 +58,7 @@ frame_support::construct_runtime!(
{ {
System: frame_system, System: frame_system,
Balances: pallet_balances, Balances: pallet_balances,
MessageQueue: pallet_message_queue,
Paras: paras, Paras: paras,
Configuration: configuration, Configuration: configuration,
ParasShared: shared, ParasShared: shared,
@@ -62,7 +67,6 @@ frame_support::construct_runtime!(
Scheduler: scheduler, Scheduler: scheduler,
Initializer: initializer, Initializer: initializer,
Dmp: dmp, Dmp: dmp,
Ump: ump,
Hrmp: hrmp, Hrmp: hrmp,
ParachainsOrigin: origin, ParachainsOrigin: origin,
SessionInfo: session_info, SessionInfo: session_info,
@@ -149,15 +153,10 @@ impl pallet_babe::Config for Test {
// session module is the trigger // session module is the trigger
type EpochChangeTrigger = pallet_babe::ExternalTrigger; type EpochChangeTrigger = pallet_babe::ExternalTrigger;
type DisabledValidators = (); type DisabledValidators = ();
type WeightInfo = (); type WeightInfo = ();
type MaxAuthorities = MaxAuthorities; type MaxAuthorities = MaxAuthorities;
type KeyOwnerProof = sp_core::Void; type KeyOwnerProof = sp_core::Void;
type EquivocationReportSystem = (); type EquivocationReportSystem = ();
} }
@@ -212,6 +211,7 @@ impl crate::paras::Config for Test {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type WeightInfo = crate::paras::TestWeightInfo; type WeightInfo = crate::paras::TestWeightInfo;
type UnsignedPriority = ParasUnsignedPriority; type UnsignedPriority = ParasUnsignedPriority;
type QueueFootprinter = ParaInclusion;
type NextSessionRotation = TestNextSessionRotation; type NextSessionRotation = TestNextSessionRotation;
} }
@@ -221,14 +221,6 @@ parameter_types! {
pub const FirstMessageFactorPercent: u64 = 100; pub const FirstMessageFactorPercent: u64 = 100;
} }
impl crate::ump::Config for Test {
type RuntimeEvent = RuntimeEvent;
type UmpSink = TestUmpSink;
type FirstMessageFactorPercent = FirstMessageFactorPercent;
type ExecuteOverweightOrigin = frame_system::EnsureRoot<AccountId>;
type WeightInfo = crate::ump::TestWeightInfo;
}
impl crate::hrmp::Config for Test { impl crate::hrmp::Config for Test {
type RuntimeOrigin = RuntimeOrigin; type RuntimeOrigin = RuntimeOrigin;
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
@@ -292,10 +284,62 @@ impl crate::disputes::SlashingHandler<BlockNumber> for Test {
impl crate::scheduler::Config for Test {} impl crate::scheduler::Config for Test {}
pub struct TestMessageQueueWeight;
impl pallet_message_queue::WeightInfo for TestMessageQueueWeight {
fn ready_ring_knit() -> Weight {
Weight::zero()
}
fn ready_ring_unknit() -> Weight {
Weight::zero()
}
fn service_queue_base() -> Weight {
Weight::zero()
}
fn service_page_base_completion() -> Weight {
Weight::zero()
}
fn service_page_base_no_completion() -> Weight {
Weight::zero()
}
fn service_page_item() -> Weight {
Weight::zero()
}
fn bump_service_head() -> Weight {
Weight::zero()
}
fn reap_page() -> Weight {
Weight::zero()
}
fn execute_overweight_page_removed() -> Weight {
Weight::zero()
}
fn execute_overweight_page_updated() -> Weight {
Weight::zero()
}
}
parameter_types! {
pub const MessageQueueServiceWeight: Weight = Weight::from_all(500);
}
pub type MessageQueueSize = u32;
impl pallet_message_queue::Config for Test {
type Size = MessageQueueSize;
type RuntimeEvent = RuntimeEvent;
type WeightInfo = TestMessageQueueWeight;
type MessageProcessor = TestProcessMessage;
type QueueChangeHandler = ParaInclusion;
type HeapSize = ConstU32<65536>;
type MaxStale = ConstU32<8>;
type ServiceWeight = MessageQueueServiceWeight;
}
impl crate::inclusion::Config for Test { impl crate::inclusion::Config for Test {
type WeightInfo = ();
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type DisputesHandler = Disputes; type DisputesHandler = Disputes;
type RewardValidators = TestRewardValidators; type RewardValidators = TestRewardValidators;
type MessageQueue = MessageQueue;
} }
impl crate::paras_inherent::Config for Test { impl crate::paras_inherent::Config for Test {
@@ -372,39 +416,39 @@ pub fn availability_rewards() -> HashMap<ValidatorIndex, usize> {
AVAILABILITY_REWARDS.with(|r| r.borrow().clone()) AVAILABILITY_REWARDS.with(|r| r.borrow().clone())
} }
std::thread_local! { parameter_types! {
static PROCESSED: RefCell<Vec<(ParaId, UpwardMessage)>> = RefCell::new(vec![]); pub static Processed: Vec<(ParaId, UpwardMessage)> = vec![];
}
/// Return which messages have been processed by `process_upward_message` and clear the buffer.
pub fn take_processed() -> Vec<(ParaId, UpwardMessage)> {
PROCESSED.with(|opt_hook| std::mem::take(&mut *opt_hook.borrow_mut()))
} }
/// An implementation of a UMP sink that just records which messages were processed. /// An implementation of a UMP sink that just records which messages were processed.
/// ///
/// A message's weight is defined by the first 4 bytes of its data, which we decode into a /// A message's weight is defined by the first 4 bytes of its data, which we decode into a
/// `u32`. /// `u32`.
pub struct TestUmpSink; pub struct TestProcessMessage;
impl UmpSink for TestUmpSink { impl ProcessMessage for TestProcessMessage {
fn process_upward_message( type Origin = AggregateMessageOrigin;
actual_origin: ParaId,
actual_msg: &[u8], fn process_message(
max_weight: Weight, message: &[u8],
) -> Result<Weight, (MessageId, Weight)> { origin: AggregateMessageOrigin,
let weight = match u32::decode(&mut &actual_msg[..]) { meter: &mut WeightMeter,
Ok(w) => Weight::from_parts(w as u64, w as u64), ) -> Result<bool, ProcessMessageError> {
Err(_) => return Ok(Weight::zero()), // same as the real `UmpSink` let para = match origin {
AggregateMessageOrigin::Ump(UmpQueueId::Para(p)) => p,
}; };
if weight.any_gt(max_weight) {
let id = sp_io::hashing::blake2_256(actual_msg); let required = match u32::decode(&mut &message[..]) {
return Err((id, weight)) Ok(w) => Weight::from_parts(w as u64, w as u64),
Err(_) => return Err(ProcessMessageError::Corrupt), // same as the real `ProcessMessage`
};
if !meter.check_accrue(required) {
return Err(ProcessMessageError::Overweight(required))
} }
PROCESSED.with(|opt_hook| { let mut processed = Processed::get();
opt_hook.borrow_mut().push((actual_origin, actual_msg.to_owned())); processed.push((para, message.to_vec()));
}); Processed::set(processed);
Ok(weight) Ok(true)
} }
} }
@@ -463,3 +507,50 @@ pub fn assert_last_event(generic_event: RuntimeEvent) {
let frame_system::EventRecord { event, .. } = &events[events.len() - 1]; let frame_system::EventRecord { event, .. } = &events[events.len() - 1];
assert_eq!(event, &system_event); assert_eq!(event, &system_event);
} }
pub fn assert_last_events<E>(generic_events: E)
where
E: DoubleEndedIterator<Item = RuntimeEvent> + ExactSizeIterator,
{
for (i, (got, want)) in frame_system::Pallet::<Test>::events()
.into_iter()
.rev()
.map(|e| e.event)
.zip(generic_events.rev().map(<Test as frame_system::Config>::RuntimeEvent::from))
.rev()
.enumerate()
{
assert_eq!((i, got), (i, want));
}
}
pub(crate) fn register_parachain_with_balance(id: ParaId, balance: Balance) {
let validation_code: ValidationCode = vec![1].into();
assert_ok!(Paras::schedule_para_initialize(
id,
crate::paras::ParaGenesisArgs {
para_kind: ParaKind::Parachain,
genesis_head: vec![1].into(),
validation_code: validation_code.clone(),
},
));
assert_ok!(Paras::add_trusted_validation_code(RuntimeOrigin::root(), validation_code));
<Test as crate::hrmp::Config>::Currency::make_free_balance_be(
&id.into_account_truncating(),
balance,
);
}
pub(crate) fn register_parachain(id: ParaId) {
register_parachain_with_balance(id, 1000);
}
pub(crate) fn deregister_parachain(id: ParaId) {
assert_ok!(Paras::schedule_para_cleanup(id));
}
/// Calls `schedule_para_cleanup` in a new storage transactions, since it assumes rollback on error.
pub(crate) fn try_deregister_parachain(id: ParaId) -> crate::DispatchResult {
frame_support::storage::transactional::with_storage_layer(|| Paras::schedule_para_cleanup(id))
}
+26 -3
View File
@@ -107,7 +107,12 @@
//! ``` //! ```
//! //!
use crate::{configuration, initializer::SessionChangeNotification, shared}; use crate::{
configuration,
inclusion::{QueueFootprinter, UmpQueueId},
initializer::SessionChangeNotification,
shared,
};
use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec}; use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec};
use frame_support::{pallet_prelude::*, traits::EstimateNextSessionRotation}; use frame_support::{pallet_prelude::*, traits::EstimateNextSessionRotation};
use frame_system::pallet_prelude::*; use frame_system::pallet_prelude::*;
@@ -551,6 +556,12 @@ pub mod pallet {
type NextSessionRotation: EstimateNextSessionRotation<Self::BlockNumber>; type NextSessionRotation: EstimateNextSessionRotation<Self::BlockNumber>;
/// Retrieve how many UMP messages are enqueued for this para-chain.
///
/// This is used to judge whether or not a para-chain can offboard. Per default this should
/// be set to the `ParaInclusion` pallet.
type QueueFootprinter: QueueFootprinter<Origin = UmpQueueId>;
/// Weight information for extrinsics in this pallet. /// Weight information for extrinsics in this pallet.
type WeightInfo: WeightInfo; type WeightInfo: WeightInfo;
} }
@@ -1653,12 +1664,13 @@ impl<T: Config> Pallet<T> {
/// ///
/// - para is not a stable parachain or parathread (i.e. [`ParaLifecycle::is_stable`] is `false`) /// - para is not a stable parachain or parathread (i.e. [`ParaLifecycle::is_stable`] is `false`)
/// - para has a pending upgrade. /// - para has a pending upgrade.
/// - para has unprocessed messages in its UMP queue.
/// ///
/// No-op if para is not registered at all. /// No-op if para is not registered at all.
pub(crate) fn schedule_para_cleanup(id: ParaId) -> DispatchResult { pub(crate) fn schedule_para_cleanup(id: ParaId) -> DispatchResult {
// Disallow offboarding in case there is a PVF pre-checking in progress. // Disallow offboarding in case there is a PVF pre-checking in progress.
// //
// This is not a fundamential limitation but rather simplification: it allows us to get // This is not a fundamental limitation but rather simplification: it allows us to get
// away without introducing additional logic for pruning and, more importantly, enacting // away without introducing additional logic for pruning and, more importantly, enacting
// ongoing PVF pre-checking votes. It also removes some nasty edge cases. // ongoing PVF pre-checking votes. It also removes some nasty edge cases.
// //
@@ -1683,7 +1695,7 @@ impl<T: Config> Pallet<T> {
Some(ParaLifecycle::Parachain) => { Some(ParaLifecycle::Parachain) => {
ParaLifecycles::<T>::insert(&id, ParaLifecycle::OffboardingParachain); ParaLifecycles::<T>::insert(&id, ParaLifecycle::OffboardingParachain);
}, },
_ => return Err(Error::<T>::CannotOffboard)?, _ => return Err(Error::<T>::CannotOffboard.into()),
} }
let scheduled_session = Self::scheduled_session(); let scheduled_session = Self::scheduled_session();
@@ -1693,6 +1705,10 @@ impl<T: Config> Pallet<T> {
} }
}); });
if <T as Config>::QueueFootprinter::message_count(UmpQueueId::Para(id)) != 0 {
return Err(Error::<T>::CannotOffboard.into())
}
Ok(()) Ok(())
} }
@@ -1986,6 +2002,13 @@ impl<T: Config> Pallet<T> {
} }
} }
/// Returns whether the given ID refers to a para that is offboarding.
///
/// An invalid or non-offboarding para ID will return `false`.
pub fn is_offboarding(id: ParaId) -> bool {
ParaLifecycles::<T>::get(&id).map_or(false, |state| state.is_offboarding())
}
/// Whether a para ID corresponds to any live parachain. /// Whether a para ID corresponds to any live parachain.
/// ///
/// Includes parachains which will downgrade to a parathread in the future. /// Includes parachains which will downgrade to a parathread in the future.
@@ -29,7 +29,7 @@ use crate::{
initializer, initializer,
metrics::METRICS, metrics::METRICS,
scheduler::{self, CoreAssignment, FreedReason}, scheduler::{self, CoreAssignment, FreedReason},
shared, ump, ParaId, shared, ParaId,
}; };
use bitvec::prelude::BitVec; use bitvec::prelude::BitVec;
use frame_support::{ use frame_support::{
@@ -531,10 +531,6 @@ impl<T: Config> Pallet<T> {
// Note which of the scheduled cores were actually occupied by a backed candidate. // Note which of the scheduled cores were actually occupied by a backed candidate.
<scheduler::Pallet<T>>::occupied(&occupied); <scheduler::Pallet<T>>::occupied(&occupied);
// Give some time slice to dispatch pending upward messages.
// this is max config.ump_service_total_weight
let _ump_weight = <ump::Pallet<T>>::process_pending_upward_messages();
METRICS.on_after_filter(total_consumed_weight.ref_time()); METRICS.on_after_filter(total_consumed_weight.ref_time());
Ok(Some(total_consumed_weight).into()) Ok(Some(total_consumed_weight).into())
@@ -331,15 +331,19 @@ where
<frame_system::Pallet<T>>::read_events_no_consensus() <frame_system::Pallet<T>>::read_events_no_consensus()
.into_iter() .into_iter()
.filter_map(|record| extract_event(record.event)) .filter_map(|record| extract_event(record.event))
.map(|event| match event { .filter_map(|event| {
Some(match event {
RawEvent::<T>::CandidateBacked(c, h, core, group) => RawEvent::<T>::CandidateBacked(c, h, core, group) =>
CandidateEvent::CandidateBacked(c, h, core, group), CandidateEvent::CandidateBacked(c, h, core, group),
RawEvent::<T>::CandidateIncluded(c, h, core, group) => RawEvent::<T>::CandidateIncluded(c, h, core, group) =>
CandidateEvent::CandidateIncluded(c, h, core, group), CandidateEvent::CandidateIncluded(c, h, core, group),
RawEvent::<T>::CandidateTimedOut(c, h, core) => RawEvent::<T>::CandidateTimedOut(c, h, core) =>
CandidateEvent::CandidateTimedOut(c, h, core), CandidateEvent::CandidateTimedOut(c, h, core),
// Not needed for candidate events.
RawEvent::<T>::UpwardMessagesReceived { .. } => return None,
RawEvent::<T>::__Ignore(_, _) => unreachable!("__Ignore cannot be used"), RawEvent::<T>::__Ignore(_, _) => unreachable!("__Ignore cannot be used"),
}) })
})
.collect() .collect()
} }
-765
View File
@@ -1,765 +0,0 @@
// 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 <http://www.gnu.org/licenses/>.
use crate::{
configuration::{self, HostConfiguration},
initializer,
};
use frame_support::{pallet_prelude::*, traits::EnsureOrigin};
use frame_system::pallet_prelude::*;
use polkadot_parachain::primitives::UpwardMessages;
use primitives::{Id as ParaId, UpwardMessage};
use sp_std::{collections::btree_map::BTreeMap, fmt, marker::PhantomData, mem, prelude::*};
use xcm::latest::Outcome;
pub use pallet::*;
/// Maximum value that `config.max_upward_message_size` can be set to
///
/// This is used for benchmarking sanely bounding relevant storage items. It is expected from the `configurations`
/// pallet to check these values before setting.
pub const MAX_UPWARD_MESSAGE_SIZE_BOUND: u32 = 50 * 1024;
/// Maximum amount of overweight messages that can exist in the queue at any given time.
pub const MAX_OVERWEIGHT_MESSAGES: u32 = 1000;
#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;
pub mod migration;
#[cfg(test)]
pub(crate) mod tests;
/// All upward messages coming from parachains will be funneled into an implementation of this trait.
///
/// The message is opaque from the perspective of UMP. The message size can range from 0 to
/// `config.max_upward_message_size`.
///
/// It's up to the implementation of this trait to decide what to do with a message as long as it
/// returns the amount of weight consumed in the process of handling. Ignoring a message is a valid
/// strategy.
///
/// There are no guarantees on how much time it takes for the message sent by a candidate to end up
/// in the sink after the candidate was enacted. That typically depends on the UMP traffic, the sizes
/// of upward messages and the configuration of UMP.
///
/// It is possible that by the time the message is sank the origin parachain was offboarded. It is
/// up to the implementer to check that if it cares.
pub trait UmpSink {
/// Process an incoming upward message and return the amount of weight it consumed, or `None` if
/// it did not begin processing a message since it would otherwise exceed `max_weight`.
///
/// See the trait docs for more details.
fn process_upward_message(
origin: ParaId,
msg: &[u8],
max_weight: Weight,
) -> Result<Weight, (MessageId, Weight)>;
}
/// An implementation of a sink that just swallows the message without consuming any weight. Returns
/// `Some(0)` indicating that no messages existed for it to process.
impl UmpSink for () {
fn process_upward_message(
_: ParaId,
_: &[u8],
_: Weight,
) -> Result<Weight, (MessageId, Weight)> {
Ok(Weight::zero())
}
}
/// Simple type used to identify messages for the purpose of reporting events. Secure if and only
/// if the message content is unique.
pub type MessageId = [u8; 32];
/// Index used to identify overweight messages.
pub type OverweightIndex = u64;
/// A specific implementation of a `UmpSink` where messages are in the XCM format
/// and will be forwarded to the XCM Executor.
pub struct XcmSink<XcmExecutor, Config>(PhantomData<(XcmExecutor, Config)>);
/// Returns a [`MessageId`] for the given upward message payload.
fn upward_message_id(data: &[u8]) -> MessageId {
sp_io::hashing::blake2_256(data)
}
impl<XcmExecutor: xcm::latest::ExecuteXcm<C::RuntimeCall>, C: Config> UmpSink
for XcmSink<XcmExecutor, C>
{
fn process_upward_message(
origin: ParaId,
mut data: &[u8],
max_weight: Weight,
) -> Result<Weight, (MessageId, Weight)> {
use parity_scale_codec::DecodeLimit;
use xcm::{
latest::{Error as XcmError, Junction, Xcm},
VersionedXcm,
};
let id = upward_message_id(data);
let maybe_msg_and_weight = VersionedXcm::<C::RuntimeCall>::decode_all_with_depth_limit(
xcm::MAX_XCM_DECODE_DEPTH,
&mut data,
)
.map(|xcm| {
(
Xcm::<C::RuntimeCall>::try_from(xcm),
// NOTE: We are overestimating slightly here.
// The benchmark is timing this whole function with different message sizes and a NOOP extrinsic to
// measure the size-dependent weight. But as we use the weight funtion **in** the benchmarked funtion we
// are taking call and control-flow overhead into account twice.
<C as Config>::WeightInfo::process_upward_message(data.len() as u32),
)
});
match maybe_msg_and_weight {
Err(_) => {
Pallet::<C>::deposit_event(Event::InvalidFormat(id));
Ok(Weight::zero())
},
Ok((Err(()), weight_used)) => {
Pallet::<C>::deposit_event(Event::UnsupportedVersion(id));
Ok(weight_used)
},
Ok((Ok(xcm_message), weight_used)) => {
let xcm_junction = Junction::Parachain(origin.into());
let outcome = XcmExecutor::execute_xcm(xcm_junction, xcm_message, id, max_weight);
match outcome {
Outcome::Error(XcmError::WeightLimitReached(required)) => Err((id, required)),
outcome => {
let outcome_weight = outcome.weight_used();
Pallet::<C>::deposit_event(Event::ExecutedUpward(id, outcome));
Ok(weight_used.saturating_add(outcome_weight))
},
}
},
}
}
}
/// An error returned by [`check_upward_messages`] that indicates a violation of one of acceptance
/// criteria rules.
pub enum AcceptanceCheckErr {
MoreMessagesThanPermitted { sent: u32, permitted: u32 },
MessageSize { idx: u32, msg_size: u32, max_size: u32 },
CapacityExceeded { count: u32, limit: u32 },
TotalSizeExceeded { total_size: u32, limit: u32 },
}
impl fmt::Debug for AcceptanceCheckErr {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match *self {
AcceptanceCheckErr::MoreMessagesThanPermitted { sent, permitted } => write!(
fmt,
"more upward messages than permitted by config ({} > {})",
sent, permitted,
),
AcceptanceCheckErr::MessageSize { idx, msg_size, max_size } => write!(
fmt,
"upward message idx {} larger than permitted by config ({} > {})",
idx, msg_size, max_size,
),
AcceptanceCheckErr::CapacityExceeded { count, limit } => write!(
fmt,
"the ump queue would have more items than permitted by config ({} > {})",
count, limit,
),
AcceptanceCheckErr::TotalSizeExceeded { total_size, limit } => write!(
fmt,
"the ump queue would have grown past the max size permitted by config ({} > {})",
total_size, limit,
),
}
}
}
/// Weight information of this pallet.
pub trait WeightInfo {
fn service_overweight() -> Weight;
fn process_upward_message(s: u32) -> Weight;
fn clean_ump_after_outgoing() -> Weight;
}
/// fallback implementation
pub struct TestWeightInfo;
impl WeightInfo for TestWeightInfo {
fn service_overweight() -> Weight {
Weight::MAX
}
fn process_upward_message(_msg_size: u32) -> Weight {
Weight::MAX
}
fn clean_ump_after_outgoing() -> Weight {
Weight::MAX
}
}
#[frame_support::pallet]
pub mod pallet {
use super::*;
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
#[pallet::pallet]
#[pallet::without_storage_info]
#[pallet::storage_version(STORAGE_VERSION)]
pub struct Pallet<T>(_);
#[pallet::config]
pub trait Config: frame_system::Config + configuration::Config {
/// The aggregate event.
type RuntimeEvent: From<Event> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
/// A place where all received upward messages are funneled.
type UmpSink: UmpSink;
/// The factor by which the weight limit it multiplied for the first UMP message to execute with.
///
/// An amount less than 100 keeps more available weight in the queue for messages after the first, and potentially
/// stalls the queue in doing so. More than 100 will provide additional weight for the first message only.
///
/// Generally you'll want this to be a bit more - 150 or 200 would be good values.
type FirstMessageFactorPercent: Get<u64>;
/// Origin which is allowed to execute overweight messages.
type ExecuteOverweightOrigin: EnsureOrigin<Self::RuntimeOrigin>;
/// Weight information for extrinsics in this pallet.
type WeightInfo: WeightInfo;
}
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event {
/// Upward message is invalid XCM.
/// \[ id \]
InvalidFormat(MessageId),
/// Upward message is unsupported version of XCM.
/// \[ id \]
UnsupportedVersion(MessageId),
/// Upward message executed with the given outcome.
/// \[ id, outcome \]
ExecutedUpward(MessageId, Outcome),
/// The weight limit for handling upward messages was reached.
/// \[ id, remaining, required \]
WeightExhausted(MessageId, Weight, Weight),
/// Some upward messages have been received and will be processed.
/// \[ para, count, size \]
UpwardMessagesReceived(ParaId, u32, u32),
/// The weight budget was exceeded for an individual upward message.
///
/// This message can be later dispatched manually using `service_overweight` dispatchable
/// using the assigned `overweight_index`.
///
/// \[ para, id, overweight_index, required \]
OverweightEnqueued(ParaId, MessageId, OverweightIndex, Weight),
/// Upward message from the overweight queue was executed with the given actual weight
/// used.
///
/// \[ overweight_index, used \]
OverweightServiced(OverweightIndex, Weight),
}
#[pallet::error]
pub enum Error<T> {
/// The message index given is unknown.
UnknownMessageIndex,
/// The amount of weight given is possibly not enough for executing the message.
WeightOverLimit,
}
/// The messages waiting to be handled by the relay-chain originating from a certain parachain.
///
/// Note that some upward messages might have been already processed by the inclusion logic. E.g.
/// channel management messages.
///
/// The messages are processed in FIFO order.
#[pallet::storage]
pub type RelayDispatchQueues<T: Config> =
StorageMap<_, Twox64Concat, ParaId, Vec<UpwardMessage>, ValueQuery>;
/// Size of the dispatch queues. Caches sizes of the queues in `RelayDispatchQueue`.
///
/// First item in the tuple is the count of messages and second
/// is the total length (in bytes) of the message payloads.
///
/// Note that this is an auxiliary mapping: it's possible to tell the byte size and the number of
/// messages only looking at `RelayDispatchQueues`. This mapping is separate to avoid the cost of
/// loading the whole message queue if only the total size and count are required.
///
/// Invariant:
/// - The set of keys should exactly match the set of keys of `RelayDispatchQueues`.
// NOTE that this field is used by parachains via merkle storage proofs, therefore changing
// the format will require migration of parachains.
#[pallet::storage]
pub type RelayDispatchQueueSize<T: Config> =
StorageMap<_, Twox64Concat, ParaId, (u32, u32), ValueQuery>;
/// The ordered list of `ParaId`s that have a `RelayDispatchQueue` entry.
///
/// Invariant:
/// - The set of items from this vector should be exactly the set of the keys in
/// `RelayDispatchQueues` and `RelayDispatchQueueSize`.
#[pallet::storage]
pub type NeedsDispatch<T: Config> = StorageValue<_, Vec<ParaId>, ValueQuery>;
/// This is the para that gets will get dispatched first during the next upward dispatchable queue
/// execution round.
///
/// Invariant:
/// - If `Some(para)`, then `para` must be present in `NeedsDispatch`.
#[pallet::storage]
pub type NextDispatchRoundStartWith<T: Config> = StorageValue<_, ParaId>;
/// The messages that exceeded max individual message weight budget.
///
/// These messages stay there until manually dispatched.
#[pallet::storage]
pub type Overweight<T: Config> =
CountedStorageMap<_, Twox64Concat, OverweightIndex, (ParaId, Vec<u8>), OptionQuery>;
/// The number of overweight messages ever recorded in `Overweight` (and thus the lowest free
/// index).
#[pallet::storage]
pub type OverweightCount<T: Config> = StorageValue<_, OverweightIndex, ValueQuery>;
#[pallet::call]
impl<T: Config> Pallet<T> {
/// Service a single overweight upward message.
///
/// - `origin`: Must pass `ExecuteOverweightOrigin`.
/// - `index`: The index of the overweight message to service.
/// - `weight_limit`: The amount of weight that message execution may take.
///
/// Errors:
/// - `UnknownMessageIndex`: Message of `index` is unknown.
/// - `WeightOverLimit`: Message execution may use greater than `weight_limit`.
///
/// Events:
/// - `OverweightServiced`: On success.
#[pallet::call_index(0)]
#[pallet::weight(weight_limit.saturating_add(<T as Config>::WeightInfo::service_overweight()))]
pub fn service_overweight(
origin: OriginFor<T>,
index: OverweightIndex,
weight_limit: Weight,
) -> DispatchResultWithPostInfo {
T::ExecuteOverweightOrigin::ensure_origin(origin)?;
let (sender, data) =
Overweight::<T>::get(index).ok_or(Error::<T>::UnknownMessageIndex)?;
let used = T::UmpSink::process_upward_message(sender, &data[..], weight_limit)
.map_err(|_| Error::<T>::WeightOverLimit)?;
Overweight::<T>::remove(index);
Self::deposit_event(Event::OverweightServiced(index, used));
Ok(Some(used.saturating_add(<T as Config>::WeightInfo::service_overweight())).into())
}
}
}
/// Routines related to the upward message passing.
impl<T: Config> Pallet<T> {
/// Block initialization logic, called by initializer.
pub(crate) fn initializer_initialize(_now: T::BlockNumber) -> Weight {
Weight::zero()
}
/// Block finalization logic, called by initializer.
pub(crate) fn initializer_finalize() {}
/// Called by the initializer to note that a new session has started.
pub(crate) fn initializer_on_new_session(
_notification: &initializer::SessionChangeNotification<T::BlockNumber>,
outgoing_paras: &[ParaId],
) -> Weight {
Self::perform_outgoing_para_cleanup(outgoing_paras)
}
/// Iterate over all paras that were noted for offboarding and remove all the data
/// associated with them.
fn perform_outgoing_para_cleanup(outgoing: &[ParaId]) -> Weight {
let mut weight: Weight = Weight::zero();
for outgoing_para in outgoing {
weight = weight.saturating_add(Self::clean_ump_after_outgoing(outgoing_para));
}
weight
}
/// Remove all relevant storage items for an outgoing parachain.
pub(crate) fn clean_ump_after_outgoing(outgoing_para: &ParaId) -> Weight {
RelayDispatchQueueSize::<T>::remove(outgoing_para);
RelayDispatchQueues::<T>::remove(outgoing_para);
// Remove the outgoing para from the `NeedsDispatch` list and from
// `NextDispatchRoundStartWith`.
//
// That's needed for maintaining invariant that `NextDispatchRoundStartWith` points to an
// existing item in `NeedsDispatch`.
NeedsDispatch::<T>::mutate(|v| {
if let Ok(i) = v.binary_search(outgoing_para) {
v.remove(i);
}
});
NextDispatchRoundStartWith::<T>::mutate(|v| *v = v.filter(|p| p == outgoing_para));
<T as Config>::WeightInfo::clean_ump_after_outgoing()
}
/// Check that all the upward messages sent by a candidate pass the acceptance criteria. Returns
/// false, if any of the messages doesn't pass.
pub(crate) fn check_upward_messages(
config: &HostConfiguration<T::BlockNumber>,
para: ParaId,
upward_messages: &[UpwardMessage],
) -> Result<(), AcceptanceCheckErr> {
if upward_messages.len() as u32 > config.max_upward_message_num_per_candidate {
return Err(AcceptanceCheckErr::MoreMessagesThanPermitted {
sent: upward_messages.len() as u32,
permitted: config.max_upward_message_num_per_candidate,
})
}
let (mut para_queue_count, mut para_queue_size) = RelayDispatchQueueSize::<T>::get(&para);
for (idx, msg) in upward_messages.into_iter().enumerate() {
let msg_size = msg.len() as u32;
if msg_size > config.max_upward_message_size {
return Err(AcceptanceCheckErr::MessageSize {
idx: idx as u32,
msg_size,
max_size: config.max_upward_message_size,
})
}
para_queue_count += 1;
para_queue_size += msg_size;
}
// make sure that the queue is not overfilled.
// we do it here only once since returning false invalidates the whole relay-chain block.
if para_queue_count > config.max_upward_queue_count {
return Err(AcceptanceCheckErr::CapacityExceeded {
count: para_queue_count,
limit: config.max_upward_queue_count,
})
}
if para_queue_size > config.max_upward_queue_size {
return Err(AcceptanceCheckErr::TotalSizeExceeded {
total_size: para_queue_size,
limit: config.max_upward_queue_size,
})
}
Ok(())
}
/// Enqueues `upward_messages` from a `para`'s accepted candidate block.
pub(crate) fn receive_upward_messages(para: ParaId, upward_messages: UpwardMessages) -> Weight {
let mut weight = Weight::zero();
if !upward_messages.is_empty() {
let (extra_count, extra_size) = upward_messages
.iter()
.fold((0, 0), |(cnt, size), d| (cnt + 1, size + d.len() as u32));
RelayDispatchQueues::<T>::mutate(&para, |v| v.extend(upward_messages.into_iter()));
RelayDispatchQueueSize::<T>::mutate(&para, |(ref mut cnt, ref mut size)| {
*cnt += extra_count;
*size += extra_size;
});
NeedsDispatch::<T>::mutate(|v| {
if let Err(i) = v.binary_search(&para) {
v.insert(i, para);
}
});
// NOTE: The actual computation is not accounted for. It should be benchmarked.
weight += T::DbWeight::get().reads_writes(3, 3);
Self::deposit_event(Event::UpwardMessagesReceived(para, extra_count, extra_size));
}
weight
}
/// Devote some time into dispatching pending upward messages.
pub(crate) fn process_pending_upward_messages() -> Weight {
const MAX_MESSAGES_PER_BLOCK: u8 = 10;
let mut messages_processed = 0;
let mut weight_used = Weight::zero();
let config = <configuration::Pallet<T>>::config();
let mut cursor = NeedsDispatchCursor::new::<T>();
let mut queue_cache = QueueCache::new();
while let Some(dispatchee) = cursor.peek() {
if weight_used.any_gte(config.ump_service_total_weight) ||
messages_processed >= MAX_MESSAGES_PER_BLOCK
{
// Temporarily allow for processing of a max of 10 messages per block, until we
// properly account for proof size weights.
//
// Then check whether we've reached or overshoot the
// preferred weight for the dispatching stage.
//
// if so - bail.
break
}
let max_weight = if weight_used == Weight::zero() {
// we increase the amount of weight that we're allowed to use on the first message to try to prevent
// the possibility of blockage of the queue.
config
.ump_service_total_weight
.saturating_mul(T::FirstMessageFactorPercent::get()) /
100
} else {
config.ump_service_total_weight - weight_used
};
// attempt to process the next message from the queue of the dispatchee; if not beyond
// our remaining weight limit, then consume it.
let maybe_next = queue_cache.peek_front::<T>(dispatchee);
if let Some(upward_message) = maybe_next {
messages_processed += 1;
match T::UmpSink::process_upward_message(dispatchee, upward_message, max_weight) {
Ok(used) => {
weight_used += used;
let _ = queue_cache.consume_front::<T>(dispatchee);
},
Err((id, required)) => {
let is_under_limit = Overweight::<T>::count() < MAX_OVERWEIGHT_MESSAGES;
weight_used.saturating_accrue(T::DbWeight::get().reads(1));
if required.any_gt(config.ump_max_individual_weight) && is_under_limit {
// overweight - add to overweight queue and continue with message
// execution consuming the message.
let upward_message = queue_cache.consume_front::<T>(dispatchee).expect(
"`consume_front` should return the same msg as `peek_front`;\
if we get into this branch then `peek_front` returned `Some`;\
thus `upward_message` cannot be `None`; qed",
);
let index = Self::stash_overweight(dispatchee, upward_message);
Self::deposit_event(Event::OverweightEnqueued(
dispatchee, id, index, required,
));
} else {
// we process messages in order and don't drop them if we run out of weight,
// so need to break here without calling `consume_front`.
Self::deposit_event(Event::WeightExhausted(id, max_weight, required));
break
}
},
}
}
if queue_cache.is_empty::<T>(dispatchee) {
// the queue is empty now - this para doesn't need attention anymore.
cursor.remove();
} else {
cursor.advance();
}
}
cursor.flush::<T>();
queue_cache.flush::<T>();
weight_used
}
/// Puts a given upward message into the list of overweight messages allowing it to be executed
/// later.
fn stash_overweight(sender: ParaId, upward_message: Vec<u8>) -> OverweightIndex {
let index = OverweightCount::<T>::mutate(|count| {
let index = *count;
*count += 1;
index
});
Overweight::<T>::insert(index, (sender, upward_message));
index
}
}
/// To avoid constant fetching, deserializing and serialization the queues are cached.
///
/// After an item dequeued from a queue for the first time, the queue is stored in this struct
/// rather than being serialized and persisted.
///
/// This implementation works best when:
///
/// 1. when the queues are shallow
/// 2. the dispatcher makes more than one cycle
///
/// if the queues are deep and there are many we would load and keep the queues for a long time,
/// thus increasing the peak memory consumption of the wasm runtime. Under such conditions persisting
/// queues might play better since it's unlikely that they are going to be requested once more.
///
/// On the other hand, the situation when deep queues exist and it takes more than one dispatcher
/// cycle to traverse the queues is already sub-optimal and better be avoided.
///
/// This struct is not supposed to be dropped but rather to be consumed by [`flush`].
struct QueueCache(BTreeMap<ParaId, QueueCacheEntry>);
struct QueueCacheEntry {
queue: Vec<UpwardMessage>,
total_size: u32,
consumed_count: usize,
consumed_size: usize,
}
impl QueueCache {
fn new() -> Self {
Self(BTreeMap::new())
}
fn ensure_cached<T: Config>(&mut self, para: ParaId) -> &mut QueueCacheEntry {
self.0.entry(para).or_insert_with(|| {
let queue = RelayDispatchQueues::<T>::get(&para);
let (_, total_size) = RelayDispatchQueueSize::<T>::get(&para);
QueueCacheEntry { queue, total_size, consumed_count: 0, consumed_size: 0 }
})
}
/// Returns the message at the front of `para`'s queue, or `None` if the queue is empty.
///
/// Does not mutate the queue.
fn peek_front<T: Config>(&mut self, para: ParaId) -> Option<&UpwardMessage> {
let entry = self.ensure_cached::<T>(para);
entry.queue.get(entry.consumed_count)
}
/// Attempts to remove one message from the front of `para`'s queue. If the queue is empty, then
/// does nothing.
fn consume_front<T: Config>(&mut self, para: ParaId) -> Option<UpwardMessage> {
let cache_entry = self.ensure_cached::<T>(para);
match cache_entry.queue.get_mut(cache_entry.consumed_count) {
Some(msg) => {
cache_entry.consumed_count += 1;
cache_entry.consumed_size += msg.len();
Some(mem::take(msg))
},
None => None,
}
}
/// Returns if the queue for the given para is empty.
///
/// That is, if this returns `true` then the next call to [`peek_front`] will return `None`.
///
/// Does not mutate the queue.
fn is_empty<T: Config>(&mut self, para: ParaId) -> bool {
let cache_entry = self.ensure_cached::<T>(para);
cache_entry.consumed_count >= cache_entry.queue.len()
}
/// Flushes the updated queues into the storage.
fn flush<T: Config>(self) {
// NOTE we use an explicit method here instead of Drop impl because it has unwanted semantics
// within runtime. It is dangerous to use because of double-panics and flushing on a panic
// is not necessary as well.
for (para, entry) in self.0 {
if entry.consumed_count >= entry.queue.len() {
// remove the entries altogether.
RelayDispatchQueues::<T>::remove(&para);
RelayDispatchQueueSize::<T>::remove(&para);
} else if entry.consumed_count > 0 {
RelayDispatchQueues::<T>::insert(&para, &entry.queue[entry.consumed_count..]);
let count = (entry.queue.len() - entry.consumed_count) as u32;
let size = entry.total_size.saturating_sub(entry.consumed_size as u32);
RelayDispatchQueueSize::<T>::insert(&para, (count, size));
}
}
}
}
/// A cursor that iterates over all entries in `NeedsDispatch`.
///
/// This cursor will start with the para indicated by `NextDispatchRoundStartWith` storage entry.
/// This cursor is cyclic meaning that after reaching the end it will jump to the beginning. Unlike
/// an iterator, this cursor allows removing items during the iteration.
///
/// Each iteration cycle *must be* concluded with a call to either `advance` or `remove`.
///
/// This struct is not supposed to be dropped but rather to be consumed by [`flush`].
#[derive(Debug)]
struct NeedsDispatchCursor {
needs_dispatch: Vec<ParaId>,
index: usize,
}
impl NeedsDispatchCursor {
fn new<T: Config>() -> Self {
let needs_dispatch: Vec<ParaId> = NeedsDispatch::<T>::get();
let start_with = NextDispatchRoundStartWith::<T>::get();
let initial_index = match start_with {
Some(para) => match needs_dispatch.binary_search(&para) {
Ok(found_index) => found_index,
Err(_supposed_index) => {
// well that's weird because we maintain an invariant that
// `NextDispatchRoundStartWith` must point into one of the items in
// `NeedsDispatch`.
//
// let's select 0 as the starting index as a safe bet.
debug_assert!(false);
0
},
},
None => 0,
};
Self { needs_dispatch, index: initial_index }
}
/// Returns the item the cursor points to.
fn peek(&self) -> Option<ParaId> {
self.needs_dispatch.get(self.index).cloned()
}
/// Moves the cursor to the next item.
fn advance(&mut self) {
if self.needs_dispatch.is_empty() {
return
}
self.index = (self.index + 1) % self.needs_dispatch.len();
}
/// Removes the item under the cursor.
fn remove(&mut self) {
if self.needs_dispatch.is_empty() {
return
}
let _ = self.needs_dispatch.remove(self.index);
// we might've removed the last element and that doesn't necessarily mean that `needs_dispatch`
// became empty. Reposition the cursor in this case to the beginning.
if self.needs_dispatch.get(self.index).is_none() {
self.index = 0;
}
}
/// Flushes the dispatcher state into the persistent storage.
fn flush<T: Config>(self) {
let next_one = self.peek();
NextDispatchRoundStartWith::<T>::set(next_one);
NeedsDispatch::<T>::put(self.needs_dispatch);
}
}
@@ -1,137 +0,0 @@
// 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 <http://www.gnu.org/licenses/>.
use super::{Pallet as Ump, *};
use frame_system::RawOrigin;
use xcm::prelude::*;
fn assert_last_event_type<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
let events = frame_system::Pallet::<T>::events();
let system_event: <T as frame_system::Config>::RuntimeEvent = generic_event.into();
// compare to the last event record
let frame_system::EventRecord { event, .. } = &events[events.len() - 1];
assert_eq!(sp_std::mem::discriminant(event), sp_std::mem::discriminant(&system_event));
}
fn queue_upward_msg<T: Config>(
host_conf: &HostConfiguration<T::BlockNumber>,
para: ParaId,
msg: UpwardMessage,
) {
let len = msg.len() as u32;
let msgs: UpwardMessages = vec![msg].try_into().unwrap();
Ump::<T>::check_upward_messages(host_conf, para, &msgs).unwrap();
let _ = Ump::<T>::receive_upward_messages(para, msgs);
assert_last_event_type::<T>(Event::UpwardMessagesReceived(para, 1, len).into());
}
// Create a message with at least `size` bytes encoded length
fn create_message_min_size<T: Config>(size: u32) -> Vec<u8> {
// Create a message with an empty remark call to determine the encoding overhead
let msg_size_empty_transact = VersionedXcm::<T>::from(Xcm::<T>(vec![Transact {
origin_kind: OriginKind::SovereignAccount,
require_weight_at_most: Weight::MAX,
call: frame_system::Call::<T>::remark_with_event { remark: vec![] }.encode().into(),
}]))
.encode()
.len();
// Create a message with a remark call of just the size required to make the whole encoded message the requested size
let size = size.saturating_sub(msg_size_empty_transact as u32) as usize;
let mut remark = Vec::new();
remark.resize(size, 0u8);
let msg = VersionedXcm::<T>::from(Xcm::<T>(vec![Transact {
origin_kind: OriginKind::SovereignAccount,
require_weight_at_most: Weight::MAX,
call: frame_system::Call::<T>::remark_with_event { remark }.encode().into(),
}]))
.encode();
assert!(msg.len() >= size);
msg
}
fn create_message_overweight<T: Config>() -> Vec<u8> {
// We use a `set_code` Call because it
let call = frame_system::Call::<T>::set_code { code: vec![] };
VersionedXcm::<T>::from(Xcm::<T>(vec![Transact {
origin_kind: OriginKind::Superuser,
require_weight_at_most: Weight::MAX / 2,
call: call.encode().into(),
}]))
.encode()
}
frame_benchmarking::benchmarks! {
// NOTE: We are overestimating slightly here.
// The benchmark is timing this whole function with different message sizes and a NOOP extrinsic to
// measure the size-dependent weight. But as we use the weight function **in** the benchmarked function we
// are taking call and control-flow overhead into account twice.
process_upward_message {
let s in 0..MAX_UPWARD_MESSAGE_SIZE_BOUND;
let para = ParaId::from(1978);
let data = create_message_min_size::<T>(s);
}: {
assert!(T::UmpSink::process_upward_message(para, &data[..], Weight::MAX).is_ok());
}
clean_ump_after_outgoing {
// max number of queued messages.
let count = configuration::ActiveConfig::<T>::get().max_upward_queue_count;
let host_conf = configuration::ActiveConfig::<T>::get();
let msg = create_message_min_size::<T>(0);
// Start with the block number 1. This is needed because should an event be
// emitted during the genesis block they will be implicitly wiped.
frame_system::Pallet::<T>::set_block_number(1u32.into());
// fill the queue, each message has it's own para-id.
for id in 0..count {
queue_upward_msg::<T>(&host_conf, ParaId::from(id), msg.clone());
}
}: {
Ump::<T>::clean_ump_after_outgoing(&ParaId::from(0));
}
service_overweight {
let host_conf = configuration::ActiveConfig::<T>::get();
let para = ParaId::from(1978);
// The message's weight does not really matter here, as we add service_overweight's
// max_weight parameter to the extrinsic's weight in the weight calculation.
// The size of the message influences decoding time, so we create a min-sized message here
// and take the decoding weight into account by adding it to the extrinsic execution weight
// in the process_upward_message function.
let msg = create_message_overweight::<T>();
// This just makes sure that 0 is not a valid index and we can use it later on.
let _ = Ump::<T>::service_overweight(RawOrigin::Root.into(), 0, Weight::from_parts(1000, 1000));
// Start with the block number 1. This is needed because should an event be
// emitted during the genesis block they will be implicitly wiped.
frame_system::Pallet::<T>::set_block_number(1u32.into());
queue_upward_msg::<T>(&host_conf, para, msg.clone());
Ump::<T>::process_pending_upward_messages();
assert_last_event_type::<T>(
Event::OverweightEnqueued(para, upward_message_id(&msg), 0, Weight::zero()).into()
);
}: _(RawOrigin::Root, 0, Weight::MAX)
verify {
assert_last_event_type::<T>(Event::OverweightServiced(0, Weight::zero()).into());
}
}
frame_benchmarking::impl_benchmark_test_suite!(
Ump,
crate::mock::new_test_ext(crate::ump::tests::GenesisConfigBuilder::default().build()),
crate::mock::Test
);
@@ -1,47 +0,0 @@
// 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 <http://www.gnu.org/licenses/>.
use crate::ump::{Config, Overweight, Pallet};
use frame_support::{
pallet_prelude::*,
traits::{OnRuntimeUpgrade, StorageVersion},
weights::Weight,
};
pub mod v1 {
use super::*;
pub struct MigrateToV1<T>(sp_std::marker::PhantomData<T>);
impl<T: Config> OnRuntimeUpgrade for MigrateToV1<T> {
fn on_runtime_upgrade() -> Weight {
if StorageVersion::get::<Pallet<T>>() == 0 {
let mut weight = T::DbWeight::get().reads(1);
let overweight_messages = Overweight::<T>::initialize_counter() as u64;
log::info!("Initialized Overweight to {}", overweight_messages);
weight.saturating_accrue(T::DbWeight::get().reads_writes(overweight_messages, 1));
StorageVersion::new(1).put::<Pallet<T>>();
weight.saturating_add(T::DbWeight::get().writes(1))
} else {
log::warn!("skipping v1, should be removed");
T::DbWeight::get().reads(1)
}
}
}
}
@@ -1,362 +0,0 @@
// 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 <http://www.gnu.org/licenses/>.
use super::*;
use crate::mock::{
assert_last_event, new_test_ext, take_processed, Configuration, MockGenesisConfig,
RuntimeOrigin, System, Test, Ump,
};
use frame_support::{assert_noop, assert_ok, weights::Weight};
use std::collections::HashSet;
pub(super) struct GenesisConfigBuilder {
max_upward_message_size: u32,
max_upward_message_num_per_candidate: u32,
max_upward_queue_count: u32,
max_upward_queue_size: u32,
ump_service_total_weight: Weight,
ump_max_individual_weight: Weight,
}
impl Default for GenesisConfigBuilder {
fn default() -> Self {
Self {
max_upward_message_size: 32,
max_upward_message_num_per_candidate: 2,
max_upward_queue_count: 4,
max_upward_queue_size: 64,
ump_service_total_weight: Weight::from_parts(1000, 1000),
ump_max_individual_weight: Weight::from_parts(100, 100),
}
}
}
impl GenesisConfigBuilder {
pub(super) fn build(self) -> crate::mock::MockGenesisConfig {
let mut genesis = default_genesis_config();
let config = &mut genesis.configuration.config;
config.max_upward_message_size = self.max_upward_message_size;
config.max_upward_message_num_per_candidate = self.max_upward_message_num_per_candidate;
config.max_upward_queue_count = self.max_upward_queue_count;
config.max_upward_queue_size = self.max_upward_queue_size;
config.ump_service_total_weight = self.ump_service_total_weight;
config.ump_max_individual_weight = self.ump_max_individual_weight;
genesis
}
}
fn default_genesis_config() -> MockGenesisConfig {
MockGenesisConfig {
configuration: crate::configuration::GenesisConfig {
config: crate::configuration::HostConfiguration {
max_downward_message_size: 1024,
..Default::default()
},
},
..Default::default()
}
}
fn queue_upward_msg(para: ParaId, msg: UpwardMessage) {
let msgs: UpwardMessages = vec![msg].try_into().unwrap();
assert!(Ump::check_upward_messages(&Configuration::config(), para, &msgs).is_ok());
let _ = Ump::receive_upward_messages(para, msgs);
}
fn assert_storage_consistency_exhaustive() {
// check that empty queues don't clutter the storage.
for (_para, queue) in RelayDispatchQueues::<Test>::iter() {
assert!(!queue.is_empty());
}
// actually count the counts and sizes in queues and compare them to the bookkept version.
for (para, queue) in RelayDispatchQueues::<Test>::iter() {
let (expected_count, expected_size) = RelayDispatchQueueSize::<Test>::get(para);
let (actual_count, actual_size) = queue
.into_iter()
.fold((0, 0), |(acc_count, acc_size), x| (acc_count + 1, acc_size + x.len() as u32));
assert_eq!(expected_count, actual_count);
assert_eq!(expected_size, actual_size);
}
// since we wipe the empty queues the sets of paras in queue contents, queue sizes and
// need dispatch set should all be equal.
let queue_contents_set =
RelayDispatchQueues::<Test>::iter().map(|(k, _)| k).collect::<HashSet<ParaId>>();
let queue_sizes_set = RelayDispatchQueueSize::<Test>::iter()
.map(|(k, _)| k)
.collect::<HashSet<ParaId>>();
let needs_dispatch_set = NeedsDispatch::<Test>::get().into_iter().collect::<HashSet<ParaId>>();
assert_eq!(queue_contents_set, queue_sizes_set);
assert_eq!(queue_contents_set, needs_dispatch_set);
// `NextDispatchRoundStartWith` should point into a para that is tracked.
if let Some(para) = NextDispatchRoundStartWith::<Test>::get() {
assert!(queue_contents_set.contains(&para));
}
// `NeedsDispatch` is always sorted.
assert!(NeedsDispatch::<Test>::get().windows(2).all(|xs| xs[0] <= xs[1]));
}
#[test]
fn dispatch_empty() {
new_test_ext(default_genesis_config()).execute_with(|| {
assert_storage_consistency_exhaustive();
// make sure that the case with empty queues is handled properly
Ump::process_pending_upward_messages();
assert_storage_consistency_exhaustive();
});
}
#[test]
fn dispatch_single_message() {
let a = ParaId::from(228);
let msg = 1000u32.encode();
new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| {
queue_upward_msg(a, msg.clone());
Ump::process_pending_upward_messages();
assert_eq!(take_processed(), vec![(a, msg)]);
assert_storage_consistency_exhaustive();
});
}
#[test]
fn dispatch_resume_after_exceeding_dispatch_stage_weight() {
let a = ParaId::from(128);
let c = ParaId::from(228);
let q = ParaId::from(911);
let a_msg_1 = (200u32, "a_msg_1").encode();
let a_msg_2 = (100u32, "a_msg_2").encode();
let c_msg_1 = (300u32, "c_msg_1").encode();
let c_msg_2 = (100u32, "c_msg_2").encode();
let q_msg = (500u32, "q_msg").encode();
new_test_ext(
GenesisConfigBuilder {
ump_service_total_weight: Weight::from_parts(500, 500),
..Default::default()
}
.build(),
)
.execute_with(|| {
queue_upward_msg(q, q_msg.clone());
queue_upward_msg(c, c_msg_1.clone());
queue_upward_msg(a, a_msg_1.clone());
queue_upward_msg(a, a_msg_2.clone());
assert_storage_consistency_exhaustive();
// we expect only two first messages to fit in the first iteration.
Ump::process_pending_upward_messages();
assert_eq!(take_processed(), vec![(a, a_msg_1), (c, c_msg_1)]);
assert_storage_consistency_exhaustive();
queue_upward_msg(c, c_msg_2.clone());
assert_storage_consistency_exhaustive();
// second iteration should process the second message.
Ump::process_pending_upward_messages();
assert_eq!(take_processed(), vec![(q, q_msg)]);
assert_storage_consistency_exhaustive();
// 3rd iteration.
Ump::process_pending_upward_messages();
assert_eq!(take_processed(), vec![(a, a_msg_2), (c, c_msg_2)]);
assert_storage_consistency_exhaustive();
// finally, make sure that the queue is empty.
Ump::process_pending_upward_messages();
assert_eq!(take_processed(), vec![]);
assert_storage_consistency_exhaustive();
});
}
#[test]
fn dispatch_keeps_message_after_weight_exhausted() {
let a = ParaId::from(128);
let a_msg_1 = (300u32, "a_msg_1").encode();
let a_msg_2 = (300u32, "a_msg_2").encode();
new_test_ext(
GenesisConfigBuilder {
ump_service_total_weight: Weight::from_parts(500, 500),
ump_max_individual_weight: Weight::from_parts(300, 300),
..Default::default()
}
.build(),
)
.execute_with(|| {
queue_upward_msg(a, a_msg_1.clone());
queue_upward_msg(a, a_msg_2.clone());
assert_storage_consistency_exhaustive();
// we expect only one message to fit in the first iteration.
Ump::process_pending_upward_messages();
assert_eq!(take_processed(), vec![(a, a_msg_1)]);
assert_storage_consistency_exhaustive();
// second iteration should process the remaining message.
Ump::process_pending_upward_messages();
assert_eq!(take_processed(), vec![(a, a_msg_2)]);
assert_storage_consistency_exhaustive();
// finally, make sure that the queue is empty.
Ump::process_pending_upward_messages();
assert_eq!(take_processed(), vec![]);
assert_storage_consistency_exhaustive();
});
}
#[test]
fn dispatch_correctly_handle_remove_of_latest() {
let a = ParaId::from(1991);
let b = ParaId::from(1999);
let a_msg_1 = (300u32, "a_msg_1").encode();
let a_msg_2 = (300u32, "a_msg_2").encode();
let b_msg_1 = (300u32, "b_msg_1").encode();
new_test_ext(
GenesisConfigBuilder {
ump_service_total_weight: Weight::from_parts(900, 900),
..Default::default()
}
.build(),
)
.execute_with(|| {
// We want to test here an edge case, where we remove the queue with the highest
// para id (i.e. last in the `needs_dispatch` order).
//
// If the last entry was removed we should proceed execution, assuming we still have
// weight available.
queue_upward_msg(a, a_msg_1.clone());
queue_upward_msg(a, a_msg_2.clone());
queue_upward_msg(b, b_msg_1.clone());
Ump::process_pending_upward_messages();
assert_eq!(take_processed(), vec![(a, a_msg_1), (b, b_msg_1), (a, a_msg_2)]);
});
}
#[test]
fn verify_relay_dispatch_queue_size_is_externally_accessible() {
// Make sure that the relay dispatch queue size storage entry is accessible via well known
// keys and is decodable into a (u32, u32).
use parity_scale_codec::Decode as _;
use primitives::well_known_keys;
let a = ParaId::from(228);
let msg = vec![1, 2, 3];
new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| {
queue_upward_msg(a, msg);
let raw_queue_size = sp_io::storage::get(&well_known_keys::relay_dispatch_queue_size(a))
.expect(
"enqueing a message should create the dispatch queue\
and it should be accessible via the well known keys",
);
let (cnt, size) = <(u32, u32)>::decode(&mut &raw_queue_size[..])
.expect("the dispatch queue size should be decodable into (u32, u32)");
assert_eq!(cnt, 1);
assert_eq!(size, 3);
});
}
#[test]
fn service_overweight_unknown() {
// This test just makes sure that 0 is not a valid index and we can use it not worrying in
// the next test.
new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| {
assert_noop!(
Ump::service_overweight(RuntimeOrigin::root(), 0, Weight::from_parts(1000, 1000)),
Error::<Test>::UnknownMessageIndex
);
});
}
#[test]
fn overweight_queue_works() {
let para_a = ParaId::from(2021);
let a_msg_1 = (301u32, "a_msg_1").encode();
let a_msg_2 = (500u32, "a_msg_2").encode();
let a_msg_3 = (500u32, "a_msg_3").encode();
new_test_ext(
GenesisConfigBuilder {
ump_service_total_weight: Weight::from_parts(900, 900),
ump_max_individual_weight: Weight::from_parts(300, 300),
..Default::default()
}
.build(),
)
.execute_with(|| {
// HACK: Start with the block number 1. This is needed because should an event be
// emitted during the genesis block they will be implicitly wiped.
System::set_block_number(1);
// This one is overweight. However, the weight is plenty and we can afford to execute
// this message, thus expect it.
queue_upward_msg(para_a, a_msg_1.clone());
Ump::process_pending_upward_messages();
assert_eq!(take_processed(), vec![(para_a, a_msg_1)]);
// This is overweight and this message cannot fit into the total weight budget.
queue_upward_msg(para_a, a_msg_2.clone());
queue_upward_msg(para_a, a_msg_3.clone());
Ump::process_pending_upward_messages();
assert_last_event(
Event::OverweightEnqueued(
para_a,
upward_message_id(&a_msg_3[..]),
0,
Weight::from_parts(500, 500),
)
.into(),
);
// Now verify that if we wanted to service this overweight message with less than enough
// weight it will fail.
assert_noop!(
Ump::service_overweight(RuntimeOrigin::root(), 0, Weight::from_parts(499, 499)),
Error::<Test>::WeightOverLimit
);
// ... and if we try to service it with just enough weight it will succeed as well.
assert_ok!(Ump::service_overweight(RuntimeOrigin::root(), 0, Weight::from_parts(500, 500)));
assert_last_event(Event::OverweightServiced(0, Weight::from_parts(500, 500)).into());
// ... and if we try to service a message with index that doesn't exist it will error
// out.
assert_noop!(
Ump::service_overweight(RuntimeOrigin::root(), 1, Weight::from_parts(1000, 1000)),
Error::<Test>::UnknownMessageIndex
);
});
}
@@ -0,0 +1,652 @@
// Copyright 2020 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 <http://www.gnu.org/licenses/>.
use crate::{
inclusion::{
tests::run_to_block_default_notifications as run_to_block, AggregateMessageOrigin,
AggregateMessageOrigin::Ump, UmpAcceptanceCheckErr, UmpQueueId,
},
mock::{
assert_last_event, assert_last_events, new_test_ext, Configuration, MessageQueue,
MessageQueueSize, MockGenesisConfig, ParaInclusion, Processed, System, Test, *,
},
};
use frame_support::{
assert_noop, assert_ok,
pallet_prelude::*,
traits::{EnqueueMessage, ExecuteOverweightError, ServiceQueues},
weights::Weight,
};
use primitives::v4::{well_known_keys, Id as ParaId, UpwardMessage};
use sp_core::twox_64;
use sp_runtime::traits::{Bounded, Hash};
use sp_std::prelude::*;
pub(super) struct GenesisConfigBuilder {
max_upward_message_size: u32,
max_upward_message_num_per_candidate: u32,
max_upward_queue_count: u32,
max_upward_queue_size: u32,
}
impl Default for GenesisConfigBuilder {
fn default() -> Self {
Self {
max_upward_message_size: 16,
max_upward_message_num_per_candidate: 2,
max_upward_queue_count: 4,
max_upward_queue_size: 64,
}
}
}
impl GenesisConfigBuilder {
pub(super) fn large_queue_count() -> Self {
Self { max_upward_queue_count: 128, ..Default::default() }
}
pub(super) fn build(self) -> crate::mock::MockGenesisConfig {
let mut genesis = default_genesis_config();
let config = &mut genesis.configuration.config;
config.max_upward_message_size = self.max_upward_message_size;
config.max_upward_message_num_per_candidate = self.max_upward_message_num_per_candidate;
config.max_upward_queue_count = self.max_upward_queue_count;
config.max_upward_queue_size = self.max_upward_queue_size;
genesis
}
}
fn default_genesis_config() -> MockGenesisConfig {
MockGenesisConfig {
configuration: crate::configuration::GenesisConfig {
config: crate::configuration::HostConfiguration {
max_downward_message_size: 1024,
..Default::default()
},
},
..Default::default()
}
}
fn queue_upward_msg(para: ParaId, msg: UpwardMessage) {
try_queue_upward_msg(para, msg).unwrap();
}
fn try_queue_upward_msg(para: ParaId, msg: UpwardMessage) -> Result<(), UmpAcceptanceCheckErr> {
let msgs = vec![msg];
ParaInclusion::check_upward_messages(&Configuration::config(), para, &msgs)?;
ParaInclusion::receive_upward_messages(para, msgs.as_slice());
Ok(())
}
mod check_upward_messages {
use super::*;
const P_0: ParaId = ParaId::new(0u32);
const P_1: ParaId = ParaId::new(1u32);
// Currently its trivial since unbounded, but this function will be handy when we bound it.
fn msg(data: &str) -> UpwardMessage {
data.as_bytes().to_vec()
}
/// Check that these messages *could* be queued.
fn check(para: ParaId, msgs: Vec<UpwardMessage>, err: Option<UmpAcceptanceCheckErr>) {
assert_eq!(
ParaInclusion::check_upward_messages(&Configuration::config(), para, &msgs[..]).err(),
err
);
}
/// Enqueue these upward messages.
fn queue(para: ParaId, msgs: Vec<UpwardMessage>) {
msgs.into_iter().for_each(|msg| super::queue_upward_msg(para, msg));
}
#[test]
fn basic_works() {
new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| {
let _g = frame_support::StorageNoopGuard::default();
check(P_0, vec![msg("p0m0")], None);
check(P_1, vec![msg("p1m0")], None);
check(P_0, vec![msg("p0m1")], None);
check(P_1, vec![msg("p1m1")], None);
});
}
#[test]
fn num_per_candidate_exceeded_error() {
new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| {
let _g = frame_support::StorageNoopGuard::default();
let permitted = Configuration::config().max_upward_message_num_per_candidate;
for sent in 0..permitted + 1 {
check(P_0, vec![msg(""); sent as usize], None);
}
for sent in permitted + 1..permitted + 10 {
check(
P_0,
vec![msg(""); sent as usize],
Some(UmpAcceptanceCheckErr::MoreMessagesThanPermitted { sent, permitted }),
);
}
});
}
#[test]
fn size_per_message_exceeded_error() {
new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| {
let _g = frame_support::StorageNoopGuard::default();
let max_size = Configuration::config().max_upward_message_size;
let max_per_candidate = Configuration::config().max_upward_message_num_per_candidate;
for msg_size in 0..=max_size {
check(P_0, vec![vec![0; msg_size as usize]], None);
}
for msg_size in max_size + 1..max_size + 10 {
for goods in 0..max_per_candidate {
let mut msgs = vec![vec![0; max_size as usize]; goods as usize];
msgs.push(vec![0; msg_size as usize]);
check(
P_0,
msgs,
Some(UmpAcceptanceCheckErr::MessageSize { idx: goods, msg_size, max_size }),
);
}
}
});
}
#[test]
fn queue_count_exceeded_error() {
new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| {
let limit = Configuration::config().max_upward_queue_count as u64;
for _ in 0..limit {
check(P_0, vec![msg("")], None);
queue(P_0, vec![msg("")]);
}
check(
P_0,
vec![msg("")],
Some(UmpAcceptanceCheckErr::CapacityExceeded { count: limit + 1, limit }),
);
check(
P_0,
vec![msg(""); 2],
Some(UmpAcceptanceCheckErr::CapacityExceeded { count: limit + 2, limit }),
);
});
}
#[test]
fn queue_size_exceeded_error() {
new_test_ext(GenesisConfigBuilder::large_queue_count().build()).execute_with(|| {
let limit = Configuration::config().max_upward_queue_size as u64;
assert_eq!(pallet_message_queue::ItemHeader::<MessageQueueSize>::max_encoded_len(), 5);
assert!(
Configuration::config().max_upward_queue_size <
crate::inclusion::MaxUmpMessageLenOf::<Test>::get(),
"Test will not work"
);
for _ in 0..limit {
check(P_0, vec![msg("1")], None);
queue(P_0, vec![msg("1")]);
}
check(
P_0,
vec![msg("1")],
Some(UmpAcceptanceCheckErr::TotalSizeExceeded { total_size: limit + 1, limit }),
);
check(
P_0,
vec![msg("123456")],
Some(UmpAcceptanceCheckErr::TotalSizeExceeded { total_size: limit + 6, limit }),
);
});
}
}
#[test]
fn dispatch_empty() {
new_test_ext(default_genesis_config()).execute_with(|| {
// make sure that the case with empty queues is handled properly
MessageQueue::service_queues(Weight::max_value());
});
}
#[test]
fn dispatch_single_message() {
let a = ParaId::from(228);
let msg = 1000u32.encode();
new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| {
queue_upward_msg(a, msg.clone());
MessageQueue::service_queues(Weight::max_value());
assert_eq!(Processed::take(), vec![(a, msg)]);
});
}
#[test]
fn dispatch_resume_after_exceeding_dispatch_stage_weight() {
let a = ParaId::from(128);
let c = ParaId::from(228);
let q = ParaId::from(911);
let a_msg_1 = (200u32, "a_msg_1").encode();
let a_msg_2 = (100u32, "a_msg_2").encode();
let c_msg_1 = (300u32, "c_msg_1").encode();
let c_msg_2 = (100u32, "c_msg_2").encode();
let q_msg = (500u32, "q_msg").encode();
new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| {
queue_upward_msg(q, q_msg.clone());
queue_upward_msg(c, c_msg_1.clone());
queue_upward_msg(a, a_msg_1.clone());
queue_upward_msg(a, a_msg_2.clone());
// we expect only two first messages to fit in the first iteration.
MessageQueue::service_queues(Weight::from_parts(500, 500));
assert_eq!(Processed::take(), vec![(q, q_msg)]);
queue_upward_msg(c, c_msg_2.clone());
// second iteration should process the second message.
MessageQueue::service_queues(Weight::from_parts(500, 500));
assert_eq!(Processed::take(), vec![(c, c_msg_1), (c, c_msg_2)]);
// 3rd iteration.
MessageQueue::service_queues(Weight::from_parts(500, 500));
assert_eq!(Processed::take(), vec![(a, a_msg_1), (a, a_msg_2)]);
// finally, make sure that the queue is empty.
MessageQueue::service_queues(Weight::from_parts(500, 500));
assert_eq!(Processed::take(), vec![]);
});
}
#[test]
fn dispatch_keeps_message_after_weight_exhausted() {
let a = ParaId::from(128);
let a_msg_1 = (300u32, "a_msg_1").encode();
let a_msg_2 = (300u32, "a_msg_2").encode();
new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| {
queue_upward_msg(a, a_msg_1.clone());
queue_upward_msg(a, a_msg_2.clone());
// we expect only one message to fit in the first iteration.
MessageQueue::service_queues(Weight::from_parts(500, 500));
assert_eq!(Processed::take(), vec![(a, a_msg_1)]);
// second iteration should process the remaining message.
MessageQueue::service_queues(Weight::from_parts(500, 500));
assert_eq!(Processed::take(), vec![(a, a_msg_2)]);
// finally, make sure that the queue is empty.
MessageQueue::service_queues(Weight::from_parts(500, 500));
assert_eq!(Processed::take(), vec![]);
});
}
#[test]
fn dispatch_correctly_handle_remove_of_latest() {
let a = ParaId::from(1991);
let b = ParaId::from(1999);
let a_msg_1 = (300u32, "a_msg_1").encode();
let a_msg_2 = (300u32, "a_msg_2").encode();
let b_msg_1 = (300u32, "b_msg_1").encode();
new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| {
// We want to test here an edge case, where we remove the queue with the highest
// para id (i.e. last in the `needs_dispatch` order).
//
// If the last entry was removed we should proceed execution, assuming we still have
// weight available.
queue_upward_msg(a, a_msg_1.clone());
queue_upward_msg(a, a_msg_2.clone());
queue_upward_msg(b, b_msg_1.clone());
MessageQueue::service_queues(Weight::from_parts(900, 900));
assert_eq!(Processed::take(), vec![(a, a_msg_1), (a, a_msg_2), (b, b_msg_1)]);
});
}
#[test]
#[cfg_attr(debug_assertions, should_panic = "Defensive failure has been triggered")]
fn queue_enact_too_long_ignored() {
const P_0: ParaId = ParaId::new(0u32);
new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| {
let max_enact = crate::inclusion::MaxUmpMessageLenOf::<Test>::get() as usize;
let m1 = (300u32, "a_msg_1").encode();
let m2 = vec![0u8; max_enact + 1];
let m3 = (300u32, "a_msg_3").encode();
// .. but the enact defensively ignores.
ParaInclusion::receive_upward_messages(P_0, &[m1.clone(), m2.clone(), m3.clone()]);
// There is one message in the queue now:
MessageQueue::service_queues(Weight::from_parts(900, 900));
assert_eq!(Processed::take(), vec![(P_0, m1), (P_0, m3)]);
});
}
/// Check that the Inclusion pallet correctly updates the well known keys in the MQ handler.
///
/// Also checks that it works in the presence of overweight messages.
#[test]
fn relay_dispatch_queue_size_is_updated() {
new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| {
let cfg = Configuration::config();
for p in 0..100 {
let para = p.into();
// Do some tricks with the weight such that the MQ pallet will process in order:
// Q0:0, Q1:0 … Q0:1, Q1:1 …
let m1 = (300u32 * (100 - p), "m1").encode();
let m2 = (300u32 * (100 - p), "m11").encode();
queue_upward_msg(para, m1);
queue_upward_msg(para, m2);
assert_queue_size(para, 2, 15);
assert_queue_remaining(
para,
cfg.max_upward_queue_count - 2,
cfg.max_upward_queue_size - 15,
);
// Now processing one message should also update the queue size.
MessageQueue::service_queues(Weight::from_all(300u64 * (100 - p) as u64));
assert_queue_remaining(
para,
cfg.max_upward_queue_count - 1,
cfg.max_upward_queue_size - 8,
);
}
// The messages of Q0…Q98 are overweight, so `service_queues` wont help.
for p in 0..98 {
let para = UmpQueueId::Para(p.into());
MessageQueue::service_queues(Weight::from_all(u64::MAX));
let fp = MessageQueue::footprint(AggregateMessageOrigin::Ump(para));
let (para_queue_count, para_queue_size) = (fp.count, fp.size);
assert_eq!(para_queue_count, 1, "count wrong for para: {}", p);
assert_eq!(para_queue_size, 8, "size wrong for para: {}", p);
}
// All queues are empty after processing overweight messages.
for p in 0..100 {
let para = UmpQueueId::Para(p.into());
let _ = <MessageQueue as ServiceQueues>::execute_overweight(
Weight::from_all(u64::MAX),
(AggregateMessageOrigin::Ump(para.clone()), 0, 1),
);
assert_queue_remaining(p.into(), cfg.max_upward_queue_count, cfg.max_upward_queue_size);
let fp = MessageQueue::footprint(AggregateMessageOrigin::Ump(para));
let (para_queue_count, para_queue_size) = (fp.count, fp.size);
assert_eq!(para_queue_count, 0, "count wrong for para: {}", p);
assert_eq!(para_queue_size, 0, "size wrong for para: {}", p);
}
});
}
/// Assert that the old and the new way of accessing `relay_dispatch_queue_size` is the same.
#[test]
fn relay_dispatch_queue_size_key_is_correct() {
#![allow(deprecated)]
// Storage alias to the old way of accessing the queue size.
#[frame_support::storage_alias]
type RelayDispatchQueueSize = StorageMap<Ump, Twox64Concat, ParaId, (u32, u32), ValueQuery>;
for i in 0..1024 {
// A "random" para id.
let para: ParaId = u32::from_ne_bytes(twox_64(&i.encode())[..4].try_into().unwrap()).into();
let well_known = primitives::well_known_keys::relay_dispatch_queue_size(para);
let aliased = RelayDispatchQueueSize::hashed_key_for(para);
assert_eq!(well_known, aliased, "Old and new key must match");
}
}
#[test]
fn verify_relay_dispatch_queue_size_is_externally_accessible() {
// Make sure that the relay dispatch queue size storage entry is accessible via well known
// keys and is decodable into a (u32, u32).
new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| {
let cfg = Configuration::config();
for para in 0..10 {
let para = para.into();
queue_upward_msg(para, vec![0u8; 3]);
assert_queue_size(para, 1, 3);
assert_queue_remaining(
para,
cfg.max_upward_queue_count - 1,
cfg.max_upward_queue_size - 3,
);
queue_upward_msg(para, vec![0u8; 3]);
assert_queue_size(para, 2, 6);
assert_queue_remaining(
para,
cfg.max_upward_queue_count - 2,
cfg.max_upward_queue_size - 6,
);
}
});
}
fn assert_queue_size(para: ParaId, count: u32, size: u32) {
#[allow(deprecated)]
let raw_queue_size = sp_io::storage::get(&well_known_keys::relay_dispatch_queue_size(para)).expect(
"enqueing a message should create the dispatch queue\
and it should be accessible via the well known keys",
);
let (c, s) = <(u32, u32)>::decode(&mut &raw_queue_size[..])
.expect("the dispatch queue size should be decodable into (u32, u32)");
assert_eq!((c, s), (count, size));
// Test the deprecated but at least type-safe `relay_dispatch_queue_size_typed`:
#[allow(deprecated)]
let (c, s) = well_known_keys::relay_dispatch_queue_size_typed(para).get().expect(
"enqueing a message should create the dispatch queue\
and it should be accessible via the well known keys",
);
assert_eq!((c, s), (count, size));
}
fn assert_queue_remaining(para: ParaId, count: u32, size: u32) {
let (remaining_cnt, remaining_size) =
well_known_keys::relay_dispatch_queue_remaining_capacity(para)
.get()
.expect("No storage value");
assert_eq!(remaining_cnt, count, "Wrong number of remaining messages in Q{}", para);
assert_eq!(remaining_size, size, "Wrong remaining size in Q{}", para);
}
#[test]
fn service_overweight_unknown() {
// This test just makes sure that 0 is not a valid index and we can use it not worrying in
// the next test.
new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| {
assert_noop!(
<MessageQueue as ServiceQueues>::execute_overweight(
Weight::MAX,
(Ump(UmpQueueId::Para(0u32.into())), 0, 0)
),
ExecuteOverweightError::NotFound,
);
});
}
#[test]
fn overweight_queue_works() {
let para_a = ParaId::from(2021);
let a_msg_1 = (301u32, "a_msg_1").encode();
let a_msg_2 = (501u32, "a_msg_2").encode();
let a_msg_3 = (501u32, "a_msg_3").encode();
new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| {
// HACK: Start with the block number 1. This is needed because should an event be
// emitted during the genesis block they will be implicitly wiped.
System::set_block_number(1);
// This one is overweight. However, the weight is plenty and we can afford to execute
// this message, thus expect it.
queue_upward_msg(para_a, a_msg_1.clone());
queue_upward_msg(para_a, a_msg_2.clone());
queue_upward_msg(para_a, a_msg_3.clone());
MessageQueue::service_queues(Weight::from_parts(500, 500));
let hash_1 = <<Test as frame_system::Config>::Hashing as Hash>::hash(&a_msg_1[..]);
let hash_2 = <<Test as frame_system::Config>::Hashing as Hash>::hash(&a_msg_2[..]);
let hash_3 = <<Test as frame_system::Config>::Hashing as Hash>::hash(&a_msg_3[..]);
assert_last_events(
[
pallet_message_queue::Event::<Test>::Processed {
hash: hash_1.clone(),
origin: Ump(UmpQueueId::Para(para_a)),
weight_used: Weight::from_parts(301, 301),
success: true,
}
.into(),
pallet_message_queue::Event::<Test>::OverweightEnqueued {
hash: hash_2.clone(),
origin: Ump(UmpQueueId::Para(para_a)),
page_index: 0,
message_index: 1,
}
.into(),
pallet_message_queue::Event::<Test>::OverweightEnqueued {
hash: hash_3.clone(),
origin: Ump(UmpQueueId::Para(para_a)),
page_index: 0,
message_index: 2,
}
.into(),
]
.into_iter(),
);
assert_eq!(Processed::take(), vec![(para_a, a_msg_1)]);
// Now verify that if we wanted to service this overweight message with less than enough
// weight it will fail.
assert_noop!(
<MessageQueue as ServiceQueues>::execute_overweight(
Weight::from_parts(500, 500),
(Ump(UmpQueueId::Para(para_a)), 0, 2)
),
ExecuteOverweightError::InsufficientWeight,
);
// ... and if we try to service it with just enough weight it will succeed as well.
assert_ok!(<MessageQueue as ServiceQueues>::execute_overweight(
Weight::from_parts(501, 501),
(Ump(UmpQueueId::Para(para_a)), 0, 2)
));
assert_last_event(
pallet_message_queue::Event::<Test>::Processed {
hash: hash_3,
origin: Ump(UmpQueueId::Para(para_a)),
weight_used: Weight::from_parts(501, 501),
success: true,
}
.into(),
);
// ... and if we try to service a message with index that doesn't exist it will error
// out.
assert_noop!(
<MessageQueue as ServiceQueues>::execute_overweight(
Weight::from_parts(501, 501),
(Ump(UmpQueueId::Para(para_a)), 0, 2)
),
ExecuteOverweightError::NotFound,
);
});
}
/// Tests that UMP messages in the dispatch queue of the relay prevents the parachain from being
/// scheduled for offboarding.
#[test]
fn cannot_offboard_while_ump_dispatch_queued() {
let para = 32.into();
let msg = (300u32, "something").encode();
new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| {
register_parachain(para);
run_to_block(5, vec![4, 5]);
queue_upward_msg(para, msg.clone());
queue_upward_msg(para, msg.clone());
// Cannot offboard since there are two UMP messages in the queue.
for i in 6..10 {
assert!(try_deregister_parachain(para).is_err());
run_to_block(i, vec![i]);
assert!(Paras::is_valid_para(para));
}
// Now let's process the first message.
MessageQueue::on_initialize(System::block_number());
assert_eq!(Processed::take().len(), 1);
// Cannot offboard since there is another one in the queue.
assert!(try_deregister_parachain(para).is_err());
// Now also process the second message ...
MessageQueue::on_initialize(System::block_number());
assert_eq!(Processed::take().len(), 1);
// ... and offboard.
run_to_block(10, vec![10]);
assert!(Paras::is_valid_para(para));
assert_ok!(try_deregister_parachain(para));
assert!(Paras::is_offboarding(para));
// Offboarding completed.
run_to_block(11, vec![11]);
assert!(!Paras::is_valid_para(para));
});
}
/// A para-chain cannot send an UMP to the relay chain while it is offboarding.
#[test]
fn cannot_enqueue_ump_while_offboarding() {
let para = 32.into();
let msg = (300u32, "something").encode();
new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| {
register_parachain(para);
run_to_block(5, vec![4, 5]);
// Start with an offboarding para.
assert_ok!(try_deregister_parachain(para));
assert!(Paras::is_offboarding(para));
// Cannot enqueue a message.
assert!(try_queue_upward_msg(para, msg.clone()).is_err());
run_to_block(6, vec![6]);
// Para is still there and still cannot enqueue a message.
assert!(Paras::is_offboarding(para));
assert!(try_queue_upward_msg(para, msg.clone()).is_err());
// Now offboarding is completed.
run_to_block(7, vec![7]);
assert!(!Paras::is_valid_para(para));
});
}
+4
View File
@@ -56,6 +56,7 @@ pallet-identity = { git = "https://github.com/paritytech/substrate", branch = "m
pallet-im-online = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-im-online = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-indices = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-indices = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-membership = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-membership = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-message-queue = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-multisig = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-multisig = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-nomination-pools = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-nomination-pools = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-nomination-pools-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-nomination-pools-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
@@ -154,6 +155,7 @@ std = [
"pallet-im-online/std", "pallet-im-online/std",
"pallet-indices/std", "pallet-indices/std",
"pallet-membership/std", "pallet-membership/std",
"pallet-message-queue/std",
"pallet-multisig/std", "pallet-multisig/std",
"pallet-nomination-pools/std", "pallet-nomination-pools/std",
"pallet-nomination-pools-runtime-api/std", "pallet-nomination-pools-runtime-api/std",
@@ -214,6 +216,7 @@ runtime-benchmarks = [
"pallet-im-online/runtime-benchmarks", "pallet-im-online/runtime-benchmarks",
"pallet-indices/runtime-benchmarks", "pallet-indices/runtime-benchmarks",
"pallet-membership/runtime-benchmarks", "pallet-membership/runtime-benchmarks",
"pallet-message-queue/runtime-benchmarks",
"pallet-multisig/runtime-benchmarks", "pallet-multisig/runtime-benchmarks",
"pallet-nomination-pools/runtime-benchmarks", "pallet-nomination-pools/runtime-benchmarks",
"pallet-nomination-pools-benchmarking/runtime-benchmarks", "pallet-nomination-pools-benchmarking/runtime-benchmarks",
@@ -262,6 +265,7 @@ try-runtime = [
"pallet-im-online/try-runtime", "pallet-im-online/try-runtime",
"pallet-indices/try-runtime", "pallet-indices/try-runtime",
"pallet-membership/try-runtime", "pallet-membership/try-runtime",
"pallet-message-queue/try-runtime",
"pallet-multisig/try-runtime", "pallet-multisig/try-runtime",
"pallet-nomination-pools/try-runtime", "pallet-nomination-pools/try-runtime",
"pallet-offences/try-runtime", "pallet-offences/try-runtime",
+95 -23
View File
@@ -28,12 +28,14 @@ use runtime_common::{
use runtime_parachains::{ use runtime_parachains::{
configuration as parachains_configuration, disputes as parachains_disputes, configuration as parachains_configuration, disputes as parachains_disputes,
disputes::slashing as parachains_slashing, dmp as parachains_dmp, hrmp as parachains_hrmp, disputes::slashing as parachains_slashing,
inclusion as parachains_inclusion, initializer as parachains_initializer, dmp as parachains_dmp, hrmp as parachains_hrmp, inclusion as parachains_inclusion,
origin as parachains_origin, paras as parachains_paras, inclusion::{AggregateMessageOrigin, UmpQueueId},
initializer as parachains_initializer, origin as parachains_origin, paras as parachains_paras,
paras_inherent as parachains_paras_inherent, reward_points as parachains_reward_points, paras_inherent as parachains_paras_inherent, reward_points as parachains_reward_points,
runtime_api_impl::v4 as parachains_runtime_api_impl, scheduler as parachains_scheduler, runtime_api_impl::v4 as parachains_runtime_api_impl,
session_info as parachains_session_info, shared as parachains_shared, ump as parachains_ump, scheduler as parachains_scheduler, session_info as parachains_session_info,
shared as parachains_shared,
}; };
use authority_discovery_primitives::AuthorityId as AuthorityDiscoveryId; use authority_discovery_primitives::AuthorityId as AuthorityDiscoveryId;
@@ -43,9 +45,9 @@ use frame_support::{
construct_runtime, parameter_types, construct_runtime, parameter_types,
traits::{ traits::{
ConstU32, EitherOf, EitherOfDiverse, InstanceFilter, KeyOwnerProofSystem, LockIdentifier, ConstU32, EitherOf, EitherOfDiverse, InstanceFilter, KeyOwnerProofSystem, LockIdentifier,
PrivilegeCmp, WithdrawReasons, PrivilegeCmp, ProcessMessage, ProcessMessageError, WithdrawReasons,
}, },
weights::ConstantMultiplier, weights::{ConstantMultiplier, WeightMeter},
PalletId, RuntimeDebug, PalletId, RuntimeDebug,
}; };
use frame_system::EnsureRoot; use frame_system::EnsureRoot;
@@ -80,6 +82,7 @@ use sp_std::{cmp::Ordering, collections::btree_map::BTreeMap, prelude::*};
use sp_version::NativeVersion; use sp_version::NativeVersion;
use sp_version::RuntimeVersion; use sp_version::RuntimeVersion;
use static_assertions::const_assert; use static_assertions::const_assert;
use xcm::latest::Junction;
pub use frame_system::Call as SystemCall; pub use frame_system::Call as SystemCall;
pub use pallet_balances::Call as BalancesCall; pub use pallet_balances::Call as BalancesCall;
@@ -1098,6 +1101,8 @@ impl parachains_inclusion::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type DisputesHandler = ParasDisputes; type DisputesHandler = ParasDisputes;
type RewardValidators = parachains_reward_points::RewardValidatorsWithEraPoints<Runtime>; type RewardValidators = parachains_reward_points::RewardValidatorsWithEraPoints<Runtime>;
type MessageQueue = MessageQueue;
type WeightInfo = weights::runtime_parachains_inclusion::WeightInfo<Runtime>;
} }
parameter_types! { parameter_types! {
@@ -1108,20 +1113,55 @@ impl parachains_paras::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type WeightInfo = weights::runtime_parachains_paras::WeightInfo<Runtime>; type WeightInfo = weights::runtime_parachains_paras::WeightInfo<Runtime>;
type UnsignedPriority = ParasUnsignedPriority; type UnsignedPriority = ParasUnsignedPriority;
type QueueFootprinter = ParaInclusion;
type NextSessionRotation = Babe; type NextSessionRotation = Babe;
} }
parameter_types! { parameter_types! {
pub const FirstMessageFactorPercent: u64 = 100; /// Amount of weight that can be spent per block to service messages.
///
/// # WARNING
///
/// This is not a good value for para-chains since the `Scheduler` already uses up to 80% block weight.
pub MessageQueueServiceWeight: Weight = Perbill::from_percent(20) * BlockWeights::get().max_block;
pub const MessageQueueHeapSize: u32 = 65_536;
pub const MessageQueueMaxStale: u32 = 8;
} }
impl parachains_ump::Config for Runtime { /// Message processor to handle any messages that were enqueued into the `MessageQueue` pallet.
pub struct MessageProcessor;
impl ProcessMessage for MessageProcessor {
type Origin = AggregateMessageOrigin;
fn process_message(
message: &[u8],
origin: Self::Origin,
meter: &mut WeightMeter,
) -> Result<bool, ProcessMessageError> {
let para = match origin {
AggregateMessageOrigin::Ump(UmpQueueId::Para(para)) => para,
};
xcm_builder::ProcessXcmMessage::<
Junction,
xcm_executor::XcmExecutor<xcm_config::XcmConfig>,
RuntimeCall,
>::process_message(message, Junction::Parachain(para.into()), meter)
}
}
impl pallet_message_queue::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type UmpSink = type Size = u32;
crate::parachains_ump::XcmSink<xcm_executor::XcmExecutor<xcm_config::XcmConfig>, Runtime>; type HeapSize = MessageQueueHeapSize;
type FirstMessageFactorPercent = FirstMessageFactorPercent; type MaxStale = MessageQueueMaxStale;
type ExecuteOverweightOrigin = EnsureRoot<AccountId>; type ServiceWeight = MessageQueueServiceWeight;
type WeightInfo = weights::runtime_parachains_ump::WeightInfo<Self>; #[cfg(not(feature = "runtime-benchmarks"))]
type MessageProcessor = MessageProcessor;
#[cfg(feature = "runtime-benchmarks")]
type MessageProcessor =
pallet_message_queue::mock_helpers::NoopMessageProcessor<AggregateMessageOrigin>;
type QueueChangeHandler = ParaInclusion;
type WeightInfo = weights::pallet_message_queue::WeightInfo<Runtime>;
} }
impl parachains_dmp::Config for Runtime {} impl parachains_dmp::Config for Runtime {}
@@ -1386,7 +1426,7 @@ construct_runtime! {
Paras: parachains_paras::{Pallet, Call, Storage, Event, Config, ValidateUnsigned} = 56, Paras: parachains_paras::{Pallet, Call, Storage, Event, Config, ValidateUnsigned} = 56,
Initializer: parachains_initializer::{Pallet, Call, Storage} = 57, Initializer: parachains_initializer::{Pallet, Call, Storage} = 57,
Dmp: parachains_dmp::{Pallet, Storage} = 58, Dmp: parachains_dmp::{Pallet, Storage} = 58,
Ump: parachains_ump::{Pallet, Call, Storage, Event} = 59, // Ump 59
Hrmp: parachains_hrmp::{Pallet, Call, Storage, Event<T>, Config} = 60, Hrmp: parachains_hrmp::{Pallet, Call, Storage, Event<T>, Config} = 60,
ParaSessionInfo: parachains_session_info::{Pallet, Storage} = 61, ParaSessionInfo: parachains_session_info::{Pallet, Storage} = 61,
ParasDisputes: parachains_disputes::{Pallet, Call, Storage, Event<T>} = 62, ParasDisputes: parachains_disputes::{Pallet, Call, Storage, Event<T>} = 62,
@@ -1400,6 +1440,9 @@ construct_runtime! {
// Pallet for sending XCM. // Pallet for sending XCM.
XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event<T>, Origin, Config} = 99, XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event<T>, Origin, Config} = 99,
// Generalized message queue
MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event<T>} = 100,
} }
} }
@@ -1453,7 +1496,8 @@ pub mod migrations {
pub type V0938 = ( pub type V0938 = (
pallet_xcm::migration::v1::MigrateToV1<Runtime>, pallet_xcm::migration::v1::MigrateToV1<Runtime>,
parachains_ump::migration::v1::MigrateToV1<Runtime>, // The UMP pallet got deleted in <https://github.com/paritytech/polkadot/pull/6271>
// parachains_ump::migration::v1::MigrateToV1<Runtime>,
); );
pub type V0940 = ( pub type V0940 = (
@@ -1471,7 +1515,12 @@ pub mod migrations {
); );
/// Unreleased migrations. Add new ones here: /// Unreleased migrations. Add new ones here:
pub type Unreleased = SetStorageVersions; pub type Unreleased = (
SetStorageVersions,
// Remove UMP dispatch queue <https://github.com/paritytech/polkadot/pull/6271>
parachains_configuration::migration::v6::MigrateToV6<Runtime>,
ump_migrations::UpdateUmpLimits,
);
/// Migrations that set `StorageVersion`s we missed to set. /// Migrations that set `StorageVersion`s we missed to set.
pub struct SetStorageVersions; pub struct SetStorageVersions;
@@ -1496,6 +1545,24 @@ pub mod migrations {
} }
} }
/// Helpers to configure all migrations.
pub mod ump_migrations {
use runtime_parachains::configuration::migration_ump;
pub const MAX_UPWARD_QUEUE_SIZE: u32 = 1 * 1024 * 1024;
pub const MAX_UPWARD_QUEUE_COUNT: u32 = 174762;
pub const MAX_UPWARD_MESSAGE_SIZE: u32 = (1 << 16) - 5; // Checked in test `max_upward_message_size`.
pub const MAX_UPWARD_MESSAGE_NUM_PER_CANDIDATE: u32 = 16;
pub type UpdateUmpLimits = migration_ump::latest::ScheduleConfigUpdate<
super::Runtime,
MAX_UPWARD_QUEUE_SIZE,
MAX_UPWARD_QUEUE_COUNT,
MAX_UPWARD_MESSAGE_SIZE,
MAX_UPWARD_MESSAGE_NUM_PER_CANDIDATE,
>;
}
/// Unchecked extrinsic type as expected by this runtime. /// Unchecked extrinsic type as expected by this runtime.
pub type UncheckedExtrinsic = pub type UncheckedExtrinsic =
generic::UncheckedExtrinsic<Address, RuntimeCall, Signature, SignedExtra>; generic::UncheckedExtrinsic<Address, RuntimeCall, Signature, SignedExtra>;
@@ -1512,13 +1579,9 @@ pub type Executive = frame_executive::Executive<
/// The payload being signed in transactions. /// The payload being signed in transactions.
pub type SignedPayload = generic::SignedPayload<RuntimeCall, SignedExtra>; pub type SignedPayload = generic::SignedPayload<RuntimeCall, SignedExtra>;
#[cfg(feature = "runtime-benchmarks")]
#[macro_use]
extern crate frame_benchmarking;
#[cfg(feature = "runtime-benchmarks")] #[cfg(feature = "runtime-benchmarks")]
mod benches { mod benches {
define_benchmarks!( frame_benchmarking::define_benchmarks!(
// Polkadot // Polkadot
// NOTE: Make sure to prefix these with `runtime_common::` so // NOTE: Make sure to prefix these with `runtime_common::` so
// the that path resolves correctly in the generated file. // the that path resolves correctly in the generated file.
@@ -1531,10 +1594,10 @@ mod benches {
[runtime_parachains::disputes, ParasDisputes] [runtime_parachains::disputes, ParasDisputes]
[runtime_parachains::disputes::slashing, ParasSlashing] [runtime_parachains::disputes::slashing, ParasSlashing]
[runtime_parachains::hrmp, Hrmp] [runtime_parachains::hrmp, Hrmp]
[runtime_parachains::inclusion, ParaInclusion]
[runtime_parachains::initializer, Initializer] [runtime_parachains::initializer, Initializer]
[runtime_parachains::paras, Paras] [runtime_parachains::paras, Paras]
[runtime_parachains::paras_inherent, ParaInherent] [runtime_parachains::paras_inherent, ParaInherent]
[runtime_parachains::ump, Ump]
// Substrate // Substrate
[pallet_bags_list, VoterList] [pallet_bags_list, VoterList]
[pallet_balances, Balances] [pallet_balances, Balances]
@@ -1552,6 +1615,7 @@ mod benches {
[pallet_im_online, ImOnline] [pallet_im_online, ImOnline]
[pallet_indices, Indices] [pallet_indices, Indices]
[pallet_membership, TechnicalMembership] [pallet_membership, TechnicalMembership]
[pallet_message_queue, MessageQueue]
[pallet_multisig, Multisig] [pallet_multisig, Multisig]
[pallet_nomination_pools, NominationPoolsBench::<Runtime>] [pallet_nomination_pools, NominationPoolsBench::<Runtime>]
[pallet_offences, OffencesBench::<Runtime>] [pallet_offences, OffencesBench::<Runtime>]
@@ -2258,6 +2322,14 @@ mod test {
If the limit is too strong, maybe consider increase the limit", If the limit is too strong, maybe consider increase the limit",
); );
} }
#[test]
fn max_upward_message_size() {
assert_eq!(
ump_migrations::MAX_UPWARD_MESSAGE_SIZE,
pallet_message_queue::MaxMessageLenOf::<Runtime>::get()
);
}
} }
#[cfg(test)] #[cfg(test)]
+2 -1
View File
@@ -32,6 +32,7 @@ pub mod pallet_identity;
pub mod pallet_im_online; pub mod pallet_im_online;
pub mod pallet_indices; pub mod pallet_indices;
pub mod pallet_membership; pub mod pallet_membership;
pub mod pallet_message_queue;
pub mod pallet_multisig; pub mod pallet_multisig;
pub mod pallet_nomination_pools; pub mod pallet_nomination_pools;
pub mod pallet_preimage; pub mod pallet_preimage;
@@ -56,7 +57,7 @@ pub mod runtime_parachains_configuration;
pub mod runtime_parachains_disputes; pub mod runtime_parachains_disputes;
pub mod runtime_parachains_disputes_slashing; pub mod runtime_parachains_disputes_slashing;
pub mod runtime_parachains_hrmp; pub mod runtime_parachains_hrmp;
pub mod runtime_parachains_inclusion;
pub mod runtime_parachains_initializer; pub mod runtime_parachains_initializer;
pub mod runtime_parachains_paras; pub mod runtime_parachains_paras;
pub mod runtime_parachains_paras_inherent; pub mod runtime_parachains_paras_inherent;
pub mod runtime_parachains_ump;
@@ -0,0 +1,176 @@
// Copyright 2017-2022 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 <http://www.gnu.org/licenses/>.
//! Autogenerated weights for `pallet_message_queue`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2023-02-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K`
//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024
// Executed Command:
// ./target/release/polkadot
// benchmark
// pallet
// --chain=dev
// --steps=50
// --repeat=20
// --pallet=pallet-message-queue
// --extrinsic=*
// --heap-pages=4096
// --header=file_header.txt
// --output
// runtime/polkadot/src/weights/pallet_message_queue.rs
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
#![allow(unused_imports)]
use frame_support::{traits::Get, weights::Weight};
use sp_std::marker::PhantomData;
/// Weight functions for `pallet_message_queue`.
pub struct WeightInfo<T>(PhantomData<T>);
impl<T: frame_system::Config> pallet_message_queue::WeightInfo for WeightInfo<T> {
/// Storage: MessageQueue ServiceHead (r:1 w:0)
/// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen)
/// Storage: MessageQueue BookStateFor (r:2 w:2)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
fn ready_ring_knit() -> Weight {
// Proof Size summary in bytes:
// Measured: `837`
// Estimated: `5554`
// Minimum execution time: 5_631 nanoseconds.
Weight::from_parts(6_182_000, 0)
.saturating_add(Weight::from_parts(0, 5554))
.saturating_add(T::DbWeight::get().reads(3))
.saturating_add(T::DbWeight::get().writes(2))
}
/// Storage: MessageQueue BookStateFor (r:2 w:2)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
/// Storage: MessageQueue ServiceHead (r:1 w:1)
/// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen)
fn ready_ring_unknit() -> Weight {
// Proof Size summary in bytes:
// Measured: `837`
// Estimated: `5554`
// Minimum execution time: 5_515 nanoseconds.
Weight::from_parts(5_775_000, 0)
.saturating_add(Weight::from_parts(0, 5554))
.saturating_add(T::DbWeight::get().reads(3))
.saturating_add(T::DbWeight::get().writes(3))
}
/// Storage: MessageQueue BookStateFor (r:1 w:1)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
fn service_queue_base() -> Weight {
// Proof Size summary in bytes:
// Measured: `576`
// Estimated: `2527`
// Minimum execution time: 2_098 nanoseconds.
Weight::from_parts(2_265_000, 0)
.saturating_add(Weight::from_parts(0, 2527))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
/// Storage: MessageQueue Pages (r:1 w:1)
/// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen)
fn service_page_base_completion() -> Weight {
// Proof Size summary in bytes:
// Measured: `648`
// Estimated: `68060`
// Minimum execution time: 3_194 nanoseconds.
Weight::from_parts(3_436_000, 0)
.saturating_add(Weight::from_parts(0, 68060))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
/// Storage: MessageQueue Pages (r:1 w:1)
/// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen)
fn service_page_base_no_completion() -> Weight {
// Proof Size summary in bytes:
// Measured: `648`
// Estimated: `68060`
// Minimum execution time: 3_409 nanoseconds.
Weight::from_parts(3_673_000, 0)
.saturating_add(Weight::from_parts(0, 68060))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
fn service_page_item() -> Weight {
// Proof Size summary in bytes:
// Measured: `971`
// Estimated: `0`
// Minimum execution time: 49_243 nanoseconds.
Weight::from_parts(50_380_000, 0)
.saturating_add(Weight::from_parts(0, 0))
}
/// Storage: MessageQueue ServiceHead (r:1 w:1)
/// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen)
/// Storage: MessageQueue BookStateFor (r:1 w:0)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
fn bump_service_head() -> Weight {
// Proof Size summary in bytes:
// Measured: `712`
// Estimated: `3027`
// Minimum execution time: 3_744 nanoseconds.
Weight::from_parts(3_922_000, 0)
.saturating_add(Weight::from_parts(0, 3027))
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(1))
}
/// Storage: MessageQueue BookStateFor (r:1 w:1)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
/// Storage: MessageQueue Pages (r:1 w:1)
/// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen)
fn reap_page() -> Weight {
// Proof Size summary in bytes:
// Measured: `66859`
// Estimated: `70587`
// Minimum execution time: 28_995 nanoseconds.
Weight::from_parts(30_370_000, 0)
.saturating_add(Weight::from_parts(0, 70587))
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(2))
}
/// Storage: MessageQueue BookStateFor (r:1 w:1)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
/// Storage: MessageQueue Pages (r:1 w:1)
/// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen)
fn execute_overweight_page_removed() -> Weight {
// Proof Size summary in bytes:
// Measured: `66859`
// Estimated: `70587`
// Minimum execution time: 76_268 nanoseconds.
Weight::from_parts(77_933_000, 0)
.saturating_add(Weight::from_parts(0, 70587))
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(2))
}
/// Storage: MessageQueue BookStateFor (r:1 w:1)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
/// Storage: MessageQueue Pages (r:1 w:1)
/// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen)
fn execute_overweight_page_updated() -> Weight {
// Proof Size summary in bytes:
// Measured: `66859`
// Estimated: `70587`
// Minimum execution time: 78_029 nanoseconds.
Weight::from_parts(80_632_000, 0)
.saturating_add(Weight::from_parts(0, 70587))
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(2))
}
}
@@ -0,0 +1,66 @@
// Copyright 2017-2022 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 <http://www.gnu.org/licenses/>.
//! Autogenerated weights for `runtime_parachains::inclusion`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K`
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024
// Executed Command:
// ./target/release/polkadot
// benchmark
// pallet
// --chain=polkadot-dev
// --steps=50
// --repeat=20
// --pallet=runtime_parachains::inclusion
// --extrinsic=*
// --execution=wasm
// --wasm-execution=compiled
// --header=./file_header.txt
// --output=./runtime/polkadot/src/weights
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
#![allow(unused_imports)]
use frame_support::{traits::Get, weights::Weight};
use sp_std::marker::PhantomData;
/// Weight functions for `runtime_parachains::inclusion`.
pub struct WeightInfo<T>(PhantomData<T>);
impl<T: frame_system::Config> runtime_parachains::inclusion::WeightInfo for WeightInfo<T> {
/// Storage: MessageQueue BookStateFor (r:1 w:1)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
/// Storage: MessageQueue Pages (r:1 w:999)
/// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen)
/// The range of component `i` is `[1, 1000]`.
fn receive_upward_messages(i: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `51490`
// Estimated: `70587`
// Minimum execution time: 50_423 nanoseconds.
Weight::from_parts(160_584_092, 0)
.saturating_add(Weight::from_parts(0, 70587))
// Standard Error: 75_127
.saturating_add(Weight::from_parts(41_929_458, 0).saturating_mul(i.into()))
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(1))
.saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into())))
}
}
@@ -1,93 +0,0 @@
// 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 <http://www.gnu.org/licenses/>.
//! Autogenerated weights for `runtime_parachains::ump`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2023-04-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024
// Executed Command:
// ./target/production/polkadot
// benchmark
// pallet
// --chain=polkadot-dev
// --steps=50
// --repeat=20
// --pallet=runtime_parachains::ump
// --extrinsic=*
// --execution=wasm
// --wasm-execution=compiled
// --header=./file_header.txt
// --output=./runtime/polkadot/src/weights/runtime_parachains_ump.rs
#![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 `runtime_parachains::ump`.
pub struct WeightInfo<T>(PhantomData<T>);
impl<T: frame_system::Config> runtime_parachains::ump::WeightInfo for WeightInfo<T> {
/// The range of component `s` is `[0, 51200]`.
fn process_upward_message(s: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 5_941_000 picoseconds.
Weight::from_parts(6_024_000, 0)
.saturating_add(Weight::from_parts(0, 0))
// Standard Error: 8
.saturating_add(Weight::from_parts(1_365, 0).saturating_mul(s.into()))
}
/// Storage: Ump NeedsDispatch (r:1 w:1)
/// Proof Skipped: Ump NeedsDispatch (max_values: Some(1), max_size: None, mode: Measured)
/// Storage: Ump NextDispatchRoundStartWith (r:1 w:1)
/// Proof Skipped: Ump NextDispatchRoundStartWith (max_values: Some(1), max_size: None, mode: Measured)
/// Storage: Ump RelayDispatchQueues (r:0 w:1)
/// Proof Skipped: Ump RelayDispatchQueues (max_values: None, max_size: None, mode: Measured)
/// Storage: Ump RelayDispatchQueueSize (r:0 w:1)
/// Proof Skipped: Ump RelayDispatchQueueSize (max_values: None, max_size: None, mode: Measured)
fn clean_ump_after_outgoing() -> Weight {
// Proof Size summary in bytes:
// Measured: `240`
// Estimated: `1725`
// Minimum execution time: 9_387_000 picoseconds.
Weight::from_parts(9_538_000, 0)
.saturating_add(Weight::from_parts(0, 1725))
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(4))
}
/// Storage: Ump Overweight (r:1 w:1)
/// Proof Skipped: Ump Overweight (max_values: None, max_size: None, mode: Measured)
/// Storage: Ump CounterForOverweight (r:1 w:1)
/// Proof: Ump CounterForOverweight (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
fn service_overweight() -> Weight {
// Proof Size summary in bytes:
// Measured: `257`
// Estimated: `3722`
// Minimum execution time: 23_382_000 picoseconds.
Weight::from_parts(23_808_000, 0)
.saturating_add(Weight::from_parts(0, 3722))
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(2))
}
}
+4
View File
@@ -53,6 +53,7 @@ pallet-identity = { git = "https://github.com/paritytech/substrate", branch = "m
pallet-im-online = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-im-online = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-indices = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-indices = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-membership = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-membership = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-message-queue = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-mmr = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-mmr = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-multisig = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-multisig = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-nis = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-nis = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
@@ -140,6 +141,7 @@ std = [
"pallet-im-online/std", "pallet-im-online/std",
"pallet-indices/std", "pallet-indices/std",
"pallet-membership/std", "pallet-membership/std",
"pallet-message-queue/std",
"pallet-mmr/std", "pallet-mmr/std",
"pallet-multisig/std", "pallet-multisig/std",
"pallet-offences/std", "pallet-offences/std",
@@ -199,6 +201,7 @@ runtime-benchmarks = [
"pallet-im-online/runtime-benchmarks", "pallet-im-online/runtime-benchmarks",
"pallet-indices/runtime-benchmarks", "pallet-indices/runtime-benchmarks",
"pallet-membership/runtime-benchmarks", "pallet-membership/runtime-benchmarks",
"pallet-message-queue/runtime-benchmarks",
"pallet-multisig/runtime-benchmarks", "pallet-multisig/runtime-benchmarks",
"pallet-preimage/runtime-benchmarks", "pallet-preimage/runtime-benchmarks",
"pallet-proxy/runtime-benchmarks", "pallet-proxy/runtime-benchmarks",
@@ -239,6 +242,7 @@ try-runtime = [
"pallet-im-online/try-runtime", "pallet-im-online/try-runtime",
"pallet-indices/try-runtime", "pallet-indices/try-runtime",
"pallet-membership/try-runtime", "pallet-membership/try-runtime",
"pallet-message-queue/try-runtime",
"pallet-mmr/try-runtime", "pallet-mmr/try-runtime",
"pallet-multisig/try-runtime", "pallet-multisig/try-runtime",
"pallet-nis/try-runtime", "pallet-nis/try-runtime",
+95 -22
View File
@@ -39,12 +39,14 @@ use sp_std::{cmp::Ordering, collections::btree_map::BTreeMap, prelude::*};
use runtime_parachains::{ use runtime_parachains::{
configuration as parachains_configuration, disputes as parachains_disputes, configuration as parachains_configuration, disputes as parachains_disputes,
disputes::slashing as parachains_slashing, dmp as parachains_dmp, hrmp as parachains_hrmp, disputes::slashing as parachains_slashing,
inclusion as parachains_inclusion, initializer as parachains_initializer, dmp as parachains_dmp, hrmp as parachains_hrmp, inclusion as parachains_inclusion,
origin as parachains_origin, paras as parachains_paras, inclusion::{AggregateMessageOrigin, UmpQueueId},
initializer as parachains_initializer, origin as parachains_origin, paras as parachains_paras,
paras_inherent as parachains_paras_inherent, paras_inherent as parachains_paras_inherent,
runtime_api_impl::v4 as parachains_runtime_api_impl, scheduler as parachains_scheduler, runtime_api_impl::v4 as parachains_runtime_api_impl,
session_info as parachains_session_info, shared as parachains_shared, ump as parachains_ump, scheduler as parachains_scheduler, session_info as parachains_session_info,
shared as parachains_shared,
}; };
use authority_discovery_primitives::AuthorityId as AuthorityDiscoveryId; use authority_discovery_primitives::AuthorityId as AuthorityDiscoveryId;
@@ -57,9 +59,9 @@ use frame_support::{
construct_runtime, parameter_types, construct_runtime, parameter_types,
traits::{ traits::{
Contains, EitherOfDiverse, InstanceFilter, KeyOwnerProofSystem, LockIdentifier, Contains, EitherOfDiverse, InstanceFilter, KeyOwnerProofSystem, LockIdentifier,
PrivilegeCmp, StorageMapShim, WithdrawReasons, PrivilegeCmp, ProcessMessage, ProcessMessageError, StorageMapShim, WithdrawReasons,
}, },
weights::ConstantMultiplier, weights::{ConstantMultiplier, WeightMeter},
PalletId, RuntimeDebug, PalletId, RuntimeDebug,
}; };
use frame_system::EnsureRoot; use frame_system::EnsureRoot;
@@ -83,6 +85,7 @@ use sp_staking::SessionIndex;
use sp_version::NativeVersion; use sp_version::NativeVersion;
use sp_version::RuntimeVersion; use sp_version::RuntimeVersion;
use static_assertions::const_assert; use static_assertions::const_assert;
use xcm::latest::Junction;
pub use frame_system::Call as SystemCall; pub use frame_system::Call as SystemCall;
pub use pallet_balances::Call as BalancesCall; pub use pallet_balances::Call as BalancesCall;
@@ -1025,6 +1028,8 @@ impl parachains_inclusion::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type DisputesHandler = ParasDisputes; type DisputesHandler = ParasDisputes;
type RewardValidators = RewardValidators; type RewardValidators = RewardValidators;
type MessageQueue = MessageQueue;
type WeightInfo = weights::runtime_parachains_inclusion::WeightInfo<Runtime>;
} }
parameter_types! { parameter_types! {
@@ -1035,20 +1040,55 @@ impl parachains_paras::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type WeightInfo = weights::runtime_parachains_paras::WeightInfo<Runtime>; type WeightInfo = weights::runtime_parachains_paras::WeightInfo<Runtime>;
type UnsignedPriority = ParasUnsignedPriority; type UnsignedPriority = ParasUnsignedPriority;
type QueueFootprinter = ParaInclusion;
type NextSessionRotation = Babe; type NextSessionRotation = Babe;
} }
parameter_types! { parameter_types! {
pub const FirstMessageFactorPercent: u64 = 100; /// Amount of weight that can be spent per block to service messages.
///
/// # WARNING
///
/// This is not a good value for para-chains since the `Scheduler` already uses up to 80% block weight.
pub MessageQueueServiceWeight: Weight = Perbill::from_percent(20) * BlockWeights::get().max_block;
pub const MessageQueueHeapSize: u32 = 32 * 1024;
pub const MessageQueueMaxStale: u32 = 96;
} }
impl parachains_ump::Config for Runtime { /// Message processor to handle any messages that were enqueued into the `MessageQueue` pallet.
pub struct MessageProcessor;
impl ProcessMessage for MessageProcessor {
type Origin = AggregateMessageOrigin;
fn process_message(
message: &[u8],
origin: Self::Origin,
meter: &mut WeightMeter,
) -> Result<bool, ProcessMessageError> {
let para = match origin {
AggregateMessageOrigin::Ump(UmpQueueId::Para(para)) => para,
};
xcm_builder::ProcessXcmMessage::<
Junction,
xcm_executor::XcmExecutor<xcm_config::XcmConfig>,
RuntimeCall,
>::process_message(message, Junction::Parachain(para.into()), meter)
}
}
impl pallet_message_queue::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type UmpSink = type Size = u32;
crate::parachains_ump::XcmSink<xcm_executor::XcmExecutor<xcm_config::XcmConfig>, Runtime>; type HeapSize = MessageQueueHeapSize;
type FirstMessageFactorPercent = FirstMessageFactorPercent; type MaxStale = MessageQueueMaxStale;
type ExecuteOverweightOrigin = EnsureRoot<AccountId>; type ServiceWeight = MessageQueueServiceWeight;
type WeightInfo = weights::runtime_parachains_ump::WeightInfo<Runtime>; #[cfg(not(feature = "runtime-benchmarks"))]
type MessageProcessor = MessageProcessor;
#[cfg(feature = "runtime-benchmarks")]
type MessageProcessor =
pallet_message_queue::mock_helpers::NoopMessageProcessor<AggregateMessageOrigin>;
type QueueChangeHandler = ParaInclusion;
type WeightInfo = weights::pallet_message_queue::WeightInfo<Runtime>;
} }
impl parachains_dmp::Config for Runtime {} impl parachains_dmp::Config for Runtime {}
@@ -1414,11 +1454,11 @@ construct_runtime! {
Paras: parachains_paras::{Pallet, Call, Storage, Event, Config, ValidateUnsigned} = 56, Paras: parachains_paras::{Pallet, Call, Storage, Event, Config, ValidateUnsigned} = 56,
Initializer: parachains_initializer::{Pallet, Call, Storage} = 57, Initializer: parachains_initializer::{Pallet, Call, Storage} = 57,
Dmp: parachains_dmp::{Pallet, Storage} = 58, Dmp: parachains_dmp::{Pallet, Storage} = 58,
Ump: parachains_ump::{Pallet, Call, Storage, Event} = 59,
Hrmp: parachains_hrmp::{Pallet, Call, Storage, Event<T>, Config} = 60, Hrmp: parachains_hrmp::{Pallet, Call, Storage, Event<T>, Config} = 60,
ParaSessionInfo: parachains_session_info::{Pallet, Storage} = 61, ParaSessionInfo: parachains_session_info::{Pallet, Storage} = 61,
ParasDisputes: parachains_disputes::{Pallet, Call, Storage, Event<T>} = 62, ParasDisputes: parachains_disputes::{Pallet, Call, Storage, Event<T>} = 62,
ParasSlashing: parachains_slashing::{Pallet, Call, Storage, ValidateUnsigned} = 63, ParasSlashing: parachains_slashing::{Pallet, Call, Storage, ValidateUnsigned} = 63,
MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event<T>} = 64,
// Parachain Onboarding Pallets. Start indices at 70 to leave room. // Parachain Onboarding Pallets. Start indices at 70 to leave room.
Registrar: paras_registrar::{Pallet, Call, Storage, Event<T>, Config} = 70, Registrar: paras_registrar::{Pallet, Call, Storage, Event<T>, Config} = 70,
@@ -1495,7 +1535,29 @@ pub mod migrations {
); );
/// Unreleased migrations. Add new ones here: /// Unreleased migrations. Add new ones here:
pub type Unreleased = (); pub type Unreleased = (
// Remove UMP dispatch queue <https://github.com/paritytech/polkadot/pull/6271>
parachains_configuration::migration::v6::MigrateToV6<Runtime>,
ump_migrations::UpdateUmpLimits,
);
}
/// Helpers to configure all migrations.
pub mod ump_migrations {
use runtime_parachains::configuration::migration_ump;
pub const MAX_UPWARD_QUEUE_SIZE: u32 = 8 * 1024 * 1024;
pub const MAX_UPWARD_QUEUE_COUNT: u32 = 1398101;
pub const MAX_UPWARD_MESSAGE_SIZE: u32 = (1 << 15) - 5; // Checked in test `max_upward_message_size`.
pub const MAX_UPWARD_MESSAGE_NUM_PER_CANDIDATE: u32 = 1024;
pub type UpdateUmpLimits = migration_ump::latest::ScheduleConfigUpdate<
super::Runtime,
MAX_UPWARD_QUEUE_SIZE,
MAX_UPWARD_QUEUE_COUNT,
MAX_UPWARD_MESSAGE_SIZE,
MAX_UPWARD_MESSAGE_NUM_PER_CANDIDATE,
>;
} }
/// Executive: handles dispatch to the various modules. /// Executive: handles dispatch to the various modules.
@@ -1535,13 +1597,9 @@ frame_support::ord_parameter_types! {
pub const MigController: AccountId = AccountId::from(hex_literal::hex!("52bc71c1eca5353749542dfdf0af97bf764f9c2f44e860cd485f1cd86400f649")); pub const MigController: AccountId = AccountId::from(hex_literal::hex!("52bc71c1eca5353749542dfdf0af97bf764f9c2f44e860cd485f1cd86400f649"));
} }
#[cfg(feature = "runtime-benchmarks")]
#[macro_use]
extern crate frame_benchmarking;
#[cfg(feature = "runtime-benchmarks")] #[cfg(feature = "runtime-benchmarks")]
mod benches { mod benches {
define_benchmarks!( frame_benchmarking::define_benchmarks!(
// Polkadot // Polkadot
// NOTE: Make sure to prefix these with `runtime_common::` so // NOTE: Make sure to prefix these with `runtime_common::` so
// the that path resolves correctly in the generated file. // the that path resolves correctly in the generated file.
@@ -1553,10 +1611,10 @@ mod benches {
[runtime_parachains::configuration, Configuration] [runtime_parachains::configuration, Configuration]
[runtime_parachains::hrmp, Hrmp] [runtime_parachains::hrmp, Hrmp]
[runtime_parachains::disputes, ParasDisputes] [runtime_parachains::disputes, ParasDisputes]
[runtime_parachains::inclusion, ParaInclusion]
[runtime_parachains::initializer, Initializer] [runtime_parachains::initializer, Initializer]
[runtime_parachains::paras_inherent, ParaInherent] [runtime_parachains::paras_inherent, ParaInherent]
[runtime_parachains::paras, Paras] [runtime_parachains::paras, Paras]
[runtime_parachains::ump, Ump]
// Substrate // Substrate
[pallet_balances, Balances] [pallet_balances, Balances]
[pallet_balances, NisCounterpartBalances] [pallet_balances, NisCounterpartBalances]
@@ -1572,6 +1630,7 @@ mod benches {
[pallet_im_online, ImOnline] [pallet_im_online, ImOnline]
[pallet_indices, Indices] [pallet_indices, Indices]
[pallet_membership, TechnicalMembership] [pallet_membership, TechnicalMembership]
[pallet_message_queue, MessageQueue]
[pallet_multisig, Multisig] [pallet_multisig, Multisig]
[pallet_preimage, Preimage] [pallet_preimage, Preimage]
[pallet_proxy, Proxy] [pallet_proxy, Proxy]
@@ -2164,6 +2223,20 @@ mod encoding_tests {
} }
} }
#[cfg(test)]
mod test {
use super::*;
#[test]
fn max_upward_message_size() {
use sp_core::Get;
assert_eq!(
ump_migrations::MAX_UPWARD_MESSAGE_SIZE,
pallet_message_queue::MaxMessageLenOf::<Runtime>::get()
);
}
}
#[cfg(all(test, feature = "try-runtime"))] #[cfg(all(test, feature = "try-runtime"))]
mod remote_tests { mod remote_tests {
use super::*; use super::*;
+2 -1
View File
@@ -28,6 +28,7 @@ pub mod pallet_identity;
pub mod pallet_im_online; pub mod pallet_im_online;
pub mod pallet_indices; pub mod pallet_indices;
pub mod pallet_membership; pub mod pallet_membership;
pub mod pallet_message_queue;
pub mod pallet_multisig; pub mod pallet_multisig;
pub mod pallet_nis; pub mod pallet_nis;
pub mod pallet_preimage; pub mod pallet_preimage;
@@ -49,8 +50,8 @@ pub mod runtime_common_slots;
pub mod runtime_parachains_configuration; pub mod runtime_parachains_configuration;
pub mod runtime_parachains_disputes; pub mod runtime_parachains_disputes;
pub mod runtime_parachains_hrmp; pub mod runtime_parachains_hrmp;
pub mod runtime_parachains_inclusion;
pub mod runtime_parachains_initializer; pub mod runtime_parachains_initializer;
pub mod runtime_parachains_paras; pub mod runtime_parachains_paras;
pub mod runtime_parachains_paras_inherent; pub mod runtime_parachains_paras_inherent;
pub mod runtime_parachains_ump;
pub mod xcm; pub mod xcm;
@@ -0,0 +1,176 @@
// Copyright 2017-2022 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 <http://www.gnu.org/licenses/>.
//! Autogenerated weights for `pallet_message_queue`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2023-02-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K`
//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024
// Executed Command:
// ./target/release/polkadot
// benchmark
// pallet
// --chain=rococo-dev
// --steps=50
// --repeat=20
// --pallet=pallet-message-queue
// --extrinsic=*
// --heap-pages=4096
// --header=file_header.txt
// --output
// runtime/rococo/src/weights/pallet_message_queue.rs
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
#![allow(unused_imports)]
use frame_support::{traits::Get, weights::Weight};
use sp_std::marker::PhantomData;
/// Weight functions for `pallet_message_queue`.
pub struct WeightInfo<T>(PhantomData<T>);
impl<T: frame_system::Config> pallet_message_queue::WeightInfo for WeightInfo<T> {
/// Storage: MessageQueue ServiceHead (r:1 w:0)
/// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen)
/// Storage: MessageQueue BookStateFor (r:2 w:2)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
fn ready_ring_knit() -> Weight {
// Proof Size summary in bytes:
// Measured: `837`
// Estimated: `5554`
// Minimum execution time: 9_427 nanoseconds.
Weight::from_parts(9_806_000, 0)
.saturating_add(Weight::from_parts(0, 5554))
.saturating_add(T::DbWeight::get().reads(3))
.saturating_add(T::DbWeight::get().writes(2))
}
/// Storage: MessageQueue BookStateFor (r:2 w:2)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
/// Storage: MessageQueue ServiceHead (r:1 w:1)
/// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen)
fn ready_ring_unknit() -> Weight {
// Proof Size summary in bytes:
// Measured: `837`
// Estimated: `5554`
// Minimum execution time: 20_178 nanoseconds.
Weight::from_parts(20_550_000, 0)
.saturating_add(Weight::from_parts(0, 5554))
.saturating_add(T::DbWeight::get().reads(3))
.saturating_add(T::DbWeight::get().writes(3))
}
/// Storage: MessageQueue BookStateFor (r:1 w:1)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
fn service_queue_base() -> Weight {
// Proof Size summary in bytes:
// Measured: `576`
// Estimated: `2527`
// Minimum execution time: 3_746 nanoseconds.
Weight::from_parts(3_885_000, 0)
.saturating_add(Weight::from_parts(0, 2527))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
/// Storage: MessageQueue Pages (r:1 w:1)
/// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen)
fn service_page_base_completion() -> Weight {
// Proof Size summary in bytes:
// Measured: `648`
// Estimated: `68060`
// Minimum execution time: 4_906 nanoseconds.
Weight::from_parts(5_060_000, 0)
.saturating_add(Weight::from_parts(0, 68060))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
/// Storage: MessageQueue Pages (r:1 w:1)
/// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen)
fn service_page_base_no_completion() -> Weight {
// Proof Size summary in bytes:
// Measured: `648`
// Estimated: `68060`
// Minimum execution time: 5_194 nanoseconds.
Weight::from_parts(5_361_000, 0)
.saturating_add(Weight::from_parts(0, 68060))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
fn service_page_item() -> Weight {
// Proof Size summary in bytes:
// Measured: `936`
// Estimated: `0`
// Minimum execution time: 62_021 nanoseconds.
Weight::from_parts(62_487_000, 0)
.saturating_add(Weight::from_parts(0, 0))
}
/// Storage: MessageQueue ServiceHead (r:1 w:1)
/// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen)
/// Storage: MessageQueue BookStateFor (r:1 w:0)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
fn bump_service_head() -> Weight {
// Proof Size summary in bytes:
// Measured: `712`
// Estimated: `3027`
// Minimum execution time: 6_989 nanoseconds.
Weight::from_parts(8_098_000, 0)
.saturating_add(Weight::from_parts(0, 3027))
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(1))
}
/// Storage: MessageQueue BookStateFor (r:1 w:1)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
/// Storage: MessageQueue Pages (r:1 w:1)
/// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen)
fn reap_page() -> Weight {
// Proof Size summary in bytes:
// Measured: `66846`
// Estimated: `70587`
// Minimum execution time: 38_177 nanoseconds.
Weight::from_parts(44_704_000, 0)
.saturating_add(Weight::from_parts(0, 70587))
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(2))
}
/// Storage: MessageQueue BookStateFor (r:1 w:1)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
/// Storage: MessageQueue Pages (r:1 w:1)
/// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen)
fn execute_overweight_page_removed() -> Weight {
// Proof Size summary in bytes:
// Measured: `66846`
// Estimated: `70587`
// Minimum execution time: 48_404 nanoseconds.
Weight::from_parts(55_066_000, 0)
.saturating_add(Weight::from_parts(0, 70587))
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(2))
}
/// Storage: MessageQueue BookStateFor (r:1 w:1)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
/// Storage: MessageQueue Pages (r:1 w:1)
/// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen)
fn execute_overweight_page_updated() -> Weight {
// Proof Size summary in bytes:
// Measured: `66846`
// Estimated: `70587`
// Minimum execution time: 66_523 nanoseconds.
Weight::from_parts(73_063_000, 0)
.saturating_add(Weight::from_parts(0, 70587))
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(2))
}
}
@@ -0,0 +1,66 @@
// Copyright 2017-2022 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 <http://www.gnu.org/licenses/>.
//! Autogenerated weights for `runtime_parachains::inclusion`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K`
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024
// Executed Command:
// ./target/release/polkadot
// benchmark
// pallet
// --chain=rococo-dev
// --steps=50
// --repeat=20
// --pallet=runtime_parachains::inclusion
// --extrinsic=*
// --execution=wasm
// --wasm-execution=compiled
// --header=./file_header.txt
// --output=./runtime/rococo/src/weights
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
#![allow(unused_imports)]
use frame_support::{traits::Get, weights::Weight};
use sp_std::marker::PhantomData;
/// Weight functions for `runtime_parachains::inclusion`.
pub struct WeightInfo<T>(PhantomData<T>);
impl<T: frame_system::Config> runtime_parachains::inclusion::WeightInfo for WeightInfo<T> {
/// Storage: MessageQueue BookStateFor (r:1 w:1)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
/// Storage: MessageQueue Pages (r:1 w:999)
/// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen)
/// The range of component `i` is `[1, 1000]`.
fn receive_upward_messages(i: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `51490`
// Estimated: `70587`
// Minimum execution time: 48_782 nanoseconds.
Weight::from_parts(49_384_000, 0)
.saturating_add(Weight::from_parts(0, 70587))
// Standard Error: 32_635
.saturating_add(Weight::from_parts(43_384_796, 0).saturating_mul(i.into()))
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(1))
.saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into())))
}
}
@@ -1,93 +0,0 @@
// 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 <http://www.gnu.org/licenses/>.
//! Autogenerated weights for `runtime_parachains::ump`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2023-04-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024
// Executed Command:
// ./target/production/polkadot
// benchmark
// pallet
// --chain=rococo-dev
// --steps=50
// --repeat=20
// --pallet=runtime_parachains::ump
// --extrinsic=*
// --execution=wasm
// --wasm-execution=compiled
// --header=./file_header.txt
// --output=./runtime/rococo/src/weights/runtime_parachains_ump.rs
#![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 `runtime_parachains::ump`.
pub struct WeightInfo<T>(PhantomData<T>);
impl<T: frame_system::Config> runtime_parachains::ump::WeightInfo for WeightInfo<T> {
/// The range of component `s` is `[0, 51200]`.
fn process_upward_message(s: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 6_036_000 picoseconds.
Weight::from_parts(6_133_000, 0)
.saturating_add(Weight::from_parts(0, 0))
// Standard Error: 8
.saturating_add(Weight::from_parts(1_360, 0).saturating_mul(s.into()))
}
/// Storage: Ump NeedsDispatch (r:1 w:1)
/// Proof Skipped: Ump NeedsDispatch (max_values: Some(1), max_size: None, mode: Measured)
/// Storage: Ump NextDispatchRoundStartWith (r:1 w:1)
/// Proof Skipped: Ump NextDispatchRoundStartWith (max_values: Some(1), max_size: None, mode: Measured)
/// Storage: Ump RelayDispatchQueues (r:0 w:1)
/// Proof Skipped: Ump RelayDispatchQueues (max_values: None, max_size: None, mode: Measured)
/// Storage: Ump RelayDispatchQueueSize (r:0 w:1)
/// Proof Skipped: Ump RelayDispatchQueueSize (max_values: None, max_size: None, mode: Measured)
fn clean_ump_after_outgoing() -> Weight {
// Proof Size summary in bytes:
// Measured: `202`
// Estimated: `1687`
// Minimum execution time: 8_630_000 picoseconds.
Weight::from_parts(8_883_000, 0)
.saturating_add(Weight::from_parts(0, 1687))
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(4))
}
/// Storage: Ump Overweight (r:1 w:1)
/// Proof Skipped: Ump Overweight (max_values: None, max_size: None, mode: Measured)
/// Storage: Ump CounterForOverweight (r:1 w:1)
/// Proof: Ump CounterForOverweight (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
fn service_overweight() -> Weight {
// Proof Size summary in bytes:
// Measured: `219`
// Estimated: `3684`
// Minimum execution time: 22_583_000 picoseconds.
Weight::from_parts(22_844_000, 0)
.saturating_add(Weight::from_parts(0, 3684))
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(2))
}
}
+4 -10
View File
@@ -30,7 +30,7 @@ use polkadot_runtime_parachains::{
initializer as parachains_initializer, origin as parachains_origin, paras as parachains_paras, initializer as parachains_initializer, origin as parachains_origin, paras as parachains_paras,
paras_inherent as parachains_paras_inherent, runtime_api_impl::v4 as runtime_impl, paras_inherent as parachains_paras_inherent, runtime_api_impl::v4 as runtime_impl,
scheduler as parachains_scheduler, session_info as parachains_session_info, scheduler as parachains_scheduler, session_info as parachains_session_info,
shared as parachains_shared, ump as parachains_ump, shared as parachains_shared,
}; };
use authority_discovery_primitives::AuthorityId as AuthorityDiscoveryId; use authority_discovery_primitives::AuthorityId as AuthorityDiscoveryId;
@@ -477,6 +477,8 @@ impl parachains_inclusion::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type DisputesHandler = ParasDisputes; type DisputesHandler = ParasDisputes;
type RewardValidators = RewardValidatorsWithEraPoints<Runtime>; type RewardValidators = RewardValidatorsWithEraPoints<Runtime>;
type MessageQueue = ();
type WeightInfo = ();
} }
impl parachains_disputes::Config for Runtime { impl parachains_disputes::Config for Runtime {
@@ -508,6 +510,7 @@ impl parachains_paras::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type WeightInfo = parachains_paras::TestWeightInfo; type WeightInfo = parachains_paras::TestWeightInfo;
type UnsignedPriority = ParasUnsignedPriority; type UnsignedPriority = ParasUnsignedPriority;
type QueueFootprinter = ParaInclusion;
type NextSessionRotation = Babe; type NextSessionRotation = Babe;
} }
@@ -517,14 +520,6 @@ parameter_types! {
pub const FirstMessageFactorPercent: u64 = 100; pub const FirstMessageFactorPercent: u64 = 100;
} }
impl parachains_ump::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type UmpSink = ();
type FirstMessageFactorPercent = FirstMessageFactorPercent;
type ExecuteOverweightOrigin = frame_system::EnsureRoot<AccountId>;
type WeightInfo = parachains_ump::TestWeightInfo;
}
impl parachains_hrmp::Config for Runtime { impl parachains_hrmp::Config for Runtime {
type RuntimeOrigin = RuntimeOrigin; type RuntimeOrigin = RuntimeOrigin;
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
@@ -672,7 +667,6 @@ construct_runtime! {
ParasOrigin: parachains_origin::{Pallet, Origin}, ParasOrigin: parachains_origin::{Pallet, Origin},
ParaSessionInfo: parachains_session_info::{Pallet, Storage}, ParaSessionInfo: parachains_session_info::{Pallet, Storage},
Hrmp: parachains_hrmp::{Pallet, Call, Storage, Event<T>}, Hrmp: parachains_hrmp::{Pallet, Call, Storage, Event<T>},
Ump: parachains_ump::{Pallet, Call, Storage, Event},
Dmp: parachains_dmp::{Pallet, Storage}, Dmp: parachains_dmp::{Pallet, Storage},
Xcm: pallet_xcm::{Pallet, Call, Event<T>, Origin}, Xcm: pallet_xcm::{Pallet, Call, Event<T>, Origin},
ParasDisputes: parachains_disputes::{Pallet, Storage, Event<T>}, ParasDisputes: parachains_disputes::{Pallet, Storage, Event<T>},
+5
View File
@@ -54,6 +54,7 @@ pallet-identity = { git = "https://github.com/paritytech/substrate", branch = "m
pallet-im-online = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-im-online = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-indices = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-indices = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-membership = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-membership = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-message-queue = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-multisig = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-multisig = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-nomination-pools = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-nomination-pools = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-offences = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-offences = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
@@ -144,6 +145,7 @@ std = [
"pallet-im-online/std", "pallet-im-online/std",
"pallet-indices/std", "pallet-indices/std",
"pallet-membership/std", "pallet-membership/std",
"pallet-message-queue/std",
"beefy-primitives/std", "beefy-primitives/std",
"pallet-multisig/std", "pallet-multisig/std",
"pallet-nomination-pools/std", "pallet-nomination-pools/std",
@@ -206,6 +208,8 @@ runtime-benchmarks = [
"pallet-identity/runtime-benchmarks", "pallet-identity/runtime-benchmarks",
"pallet-im-online/runtime-benchmarks", "pallet-im-online/runtime-benchmarks",
"pallet-indices/runtime-benchmarks", "pallet-indices/runtime-benchmarks",
"pallet-membership/runtime-benchmarks",
"pallet-message-queue/runtime-benchmarks",
"pallet-multisig/runtime-benchmarks", "pallet-multisig/runtime-benchmarks",
"pallet-nomination-pools-benchmarking/runtime-benchmarks", "pallet-nomination-pools-benchmarking/runtime-benchmarks",
"pallet-preimage/runtime-benchmarks", "pallet-preimage/runtime-benchmarks",
@@ -249,6 +253,7 @@ try-runtime = [
"pallet-im-online/try-runtime", "pallet-im-online/try-runtime",
"pallet-indices/try-runtime", "pallet-indices/try-runtime",
"pallet-membership/try-runtime", "pallet-membership/try-runtime",
"pallet-message-queue/try-runtime",
"pallet-multisig/try-runtime", "pallet-multisig/try-runtime",
"pallet-nomination-pools/try-runtime", "pallet-nomination-pools/try-runtime",
"pallet-offences/try-runtime", "pallet-offences/try-runtime",
+100 -22
View File
@@ -25,8 +25,11 @@ use beefy_primitives::crypto::{AuthorityId as BeefyId, Signature as BeefySignatu
use frame_election_provider_support::{onchain, SequentialPhragmen}; use frame_election_provider_support::{onchain, SequentialPhragmen};
use frame_support::{ use frame_support::{
construct_runtime, parameter_types, construct_runtime, parameter_types,
traits::{ConstU32, InstanceFilter, KeyOwnerProofSystem, WithdrawReasons}, traits::{
weights::ConstantMultiplier, ConstU32, InstanceFilter, KeyOwnerProofSystem, ProcessMessage, ProcessMessageError,
WithdrawReasons,
},
weights::{ConstantMultiplier, WeightMeter},
PalletId, PalletId,
}; };
use frame_system::EnsureRoot; use frame_system::EnsureRoot;
@@ -50,12 +53,14 @@ use runtime_common::{
}; };
use runtime_parachains::{ use runtime_parachains::{
configuration as parachains_configuration, disputes as parachains_disputes, configuration as parachains_configuration, disputes as parachains_disputes,
disputes::slashing as parachains_slashing, dmp as parachains_dmp, hrmp as parachains_hrmp, disputes::slashing as parachains_slashing,
inclusion as parachains_inclusion, initializer as parachains_initializer, dmp as parachains_dmp, hrmp as parachains_hrmp, inclusion as parachains_inclusion,
origin as parachains_origin, paras as parachains_paras, inclusion::{AggregateMessageOrigin, UmpQueueId},
initializer as parachains_initializer, origin as parachains_origin, paras as parachains_paras,
paras_inherent as parachains_paras_inherent, reward_points as parachains_reward_points, paras_inherent as parachains_paras_inherent, reward_points as parachains_reward_points,
runtime_api_impl::v4 as parachains_runtime_api_impl, scheduler as parachains_scheduler, runtime_api_impl::v4 as parachains_runtime_api_impl,
session_info as parachains_session_info, shared as parachains_shared, ump as parachains_ump, scheduler as parachains_scheduler, session_info as parachains_session_info,
shared as parachains_shared,
}; };
use scale_info::TypeInfo; use scale_info::TypeInfo;
use sp_core::{OpaqueMetadata, RuntimeDebug}; use sp_core::{OpaqueMetadata, RuntimeDebug};
@@ -76,6 +81,7 @@ use sp_std::{collections::btree_map::BTreeMap, prelude::*};
#[cfg(any(feature = "std", test))] #[cfg(any(feature = "std", test))]
use sp_version::NativeVersion; use sp_version::NativeVersion;
use sp_version::RuntimeVersion; use sp_version::RuntimeVersion;
use xcm::latest::Junction;
pub use frame_system::Call as SystemCall; pub use frame_system::Call as SystemCall;
pub use pallet_balances::Call as BalancesCall; pub use pallet_balances::Call as BalancesCall;
@@ -895,6 +901,8 @@ impl parachains_inclusion::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type DisputesHandler = ParasDisputes; type DisputesHandler = ParasDisputes;
type RewardValidators = parachains_reward_points::RewardValidatorsWithEraPoints<Runtime>; type RewardValidators = parachains_reward_points::RewardValidatorsWithEraPoints<Runtime>;
type MessageQueue = MessageQueue;
type WeightInfo = weights::runtime_parachains_inclusion::WeightInfo<Runtime>;
} }
parameter_types! { parameter_types! {
@@ -905,20 +913,55 @@ impl parachains_paras::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type WeightInfo = weights::runtime_parachains_paras::WeightInfo<Runtime>; type WeightInfo = weights::runtime_parachains_paras::WeightInfo<Runtime>;
type UnsignedPriority = ParasUnsignedPriority; type UnsignedPriority = ParasUnsignedPriority;
type QueueFootprinter = ParaInclusion;
type NextSessionRotation = Babe; type NextSessionRotation = Babe;
} }
parameter_types! { parameter_types! {
pub const FirstMessageFactorPercent: u64 = 100; /// Amount of weight that can be spent per block to service messages.
///
/// # WARNING
///
/// This is not a good value for para-chains since the `Scheduler` already uses up to 80% block weight.
pub MessageQueueServiceWeight: Weight = Perbill::from_percent(20) * BlockWeights::get().max_block;
pub const MessageQueueHeapSize: u32 = 128 * 1024;
pub const MessageQueueMaxStale: u32 = 48;
} }
impl parachains_ump::Config for Runtime { /// Message processor to handle any messages that were enqueued into the `MessageQueue` pallet.
pub struct MessageProcessor;
impl ProcessMessage for MessageProcessor {
type Origin = AggregateMessageOrigin;
fn process_message(
message: &[u8],
origin: Self::Origin,
meter: &mut WeightMeter,
) -> Result<bool, ProcessMessageError> {
let para = match origin {
AggregateMessageOrigin::Ump(UmpQueueId::Para(para)) => para,
};
xcm_builder::ProcessXcmMessage::<
Junction,
xcm_executor::XcmExecutor<xcm_config::XcmConfig>,
RuntimeCall,
>::process_message(message, Junction::Parachain(para.into()), meter)
}
}
impl pallet_message_queue::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type UmpSink = type Size = u32;
crate::parachains_ump::XcmSink<xcm_executor::XcmExecutor<xcm_config::XcmConfig>, Runtime>; type HeapSize = MessageQueueHeapSize;
type FirstMessageFactorPercent = FirstMessageFactorPercent; type MaxStale = MessageQueueMaxStale;
type ExecuteOverweightOrigin = EnsureRoot<AccountId>; type ServiceWeight = MessageQueueServiceWeight;
type WeightInfo = weights::runtime_parachains_ump::WeightInfo<Runtime>; #[cfg(not(feature = "runtime-benchmarks"))]
type MessageProcessor = MessageProcessor;
#[cfg(feature = "runtime-benchmarks")]
type MessageProcessor =
pallet_message_queue::mock_helpers::NoopMessageProcessor<AggregateMessageOrigin>;
type QueueChangeHandler = ParaInclusion;
type WeightInfo = weights::pallet_message_queue::WeightInfo<Runtime>;
} }
impl parachains_dmp::Config for Runtime {} impl parachains_dmp::Config for Runtime {}
@@ -1162,7 +1205,7 @@ construct_runtime! {
Paras: parachains_paras::{Pallet, Call, Storage, Event, Config, ValidateUnsigned} = 47, Paras: parachains_paras::{Pallet, Call, Storage, Event, Config, ValidateUnsigned} = 47,
Initializer: parachains_initializer::{Pallet, Call, Storage} = 48, Initializer: parachains_initializer::{Pallet, Call, Storage} = 48,
Dmp: parachains_dmp::{Pallet, Storage} = 49, Dmp: parachains_dmp::{Pallet, Storage} = 49,
Ump: parachains_ump::{Pallet, Call, Storage, Event} = 50, // RIP Ump 50
Hrmp: parachains_hrmp::{Pallet, Call, Storage, Event<T>, Config} = 51, Hrmp: parachains_hrmp::{Pallet, Call, Storage, Event<T>, Config} = 51,
ParaSessionInfo: parachains_session_info::{Pallet, Storage} = 52, ParaSessionInfo: parachains_session_info::{Pallet, Storage} = 52,
ParasDisputes: parachains_disputes::{Pallet, Call, Storage, Event<T>} = 53, ParasDisputes: parachains_disputes::{Pallet, Call, Storage, Event<T>} = 53,
@@ -1178,6 +1221,9 @@ construct_runtime! {
// Pallet for sending XCM. // Pallet for sending XCM.
XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event<T>, Origin, Config} = 99, XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event<T>, Origin, Config} = 99,
// Generalized message queue
MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event<T>} = 100,
} }
} }
@@ -1237,7 +1283,29 @@ pub mod migrations {
); );
/// Unreleased migrations. Add new ones here: /// Unreleased migrations. Add new ones here:
pub type Unreleased = (); pub type Unreleased = (
// Remove UMP dispatch queue <https://github.com/paritytech/polkadot/pull/6271>
parachains_configuration::migration::v6::MigrateToV6<Runtime>,
ump_migrations::UpdateUmpLimits,
);
}
/// Helpers to configure all migrations.
pub mod ump_migrations {
use runtime_parachains::configuration::migration_ump;
pub const MAX_UPWARD_QUEUE_SIZE: u32 = 8 * 1024 * 1024;
pub const MAX_UPWARD_QUEUE_COUNT: u32 = 1398101;
pub const MAX_UPWARD_MESSAGE_SIZE: u32 = (1 << 17) - 5; // Checked in test `max_upward_message_size`.
pub const MAX_UPWARD_MESSAGE_NUM_PER_CANDIDATE: u32 = 512;
pub type UpdateUmpLimits = migration_ump::latest::ScheduleConfigUpdate<
super::Runtime,
MAX_UPWARD_QUEUE_SIZE,
MAX_UPWARD_QUEUE_COUNT,
MAX_UPWARD_MESSAGE_SIZE,
MAX_UPWARD_MESSAGE_NUM_PER_CANDIDATE,
>;
} }
/// Unchecked extrinsic type as expected by this runtime. /// Unchecked extrinsic type as expected by this runtime.
@@ -1255,13 +1323,9 @@ pub type Executive = frame_executive::Executive<
/// The payload being signed in transactions. /// The payload being signed in transactions.
pub type SignedPayload = generic::SignedPayload<RuntimeCall, SignedExtra>; pub type SignedPayload = generic::SignedPayload<RuntimeCall, SignedExtra>;
#[cfg(feature = "runtime-benchmarks")]
#[macro_use]
extern crate frame_benchmarking;
#[cfg(feature = "runtime-benchmarks")] #[cfg(feature = "runtime-benchmarks")]
mod benches { mod benches {
define_benchmarks!( frame_benchmarking::define_benchmarks!(
// Polkadot // Polkadot
// NOTE: Make sure to prefix these with `runtime_common::` so // NOTE: Make sure to prefix these with `runtime_common::` so
// the that path resolves correctly in the generated file. // the that path resolves correctly in the generated file.
@@ -1273,10 +1337,10 @@ mod benches {
[runtime_parachains::disputes, ParasDisputes] [runtime_parachains::disputes, ParasDisputes]
[runtime_parachains::disputes::slashing, ParasSlashing] [runtime_parachains::disputes::slashing, ParasSlashing]
[runtime_parachains::hrmp, Hrmp] [runtime_parachains::hrmp, Hrmp]
[runtime_parachains::inclusion, ParaInclusion]
[runtime_parachains::initializer, Initializer] [runtime_parachains::initializer, Initializer]
[runtime_parachains::paras, Paras] [runtime_parachains::paras, Paras]
[runtime_parachains::paras_inherent, ParaInherent] [runtime_parachains::paras_inherent, ParaInherent]
[runtime_parachains::ump, Ump]
// Substrate // Substrate
[pallet_bags_list, VoterList] [pallet_bags_list, VoterList]
[pallet_balances, Balances] [pallet_balances, Balances]
@@ -1286,6 +1350,7 @@ mod benches {
[pallet_identity, Identity] [pallet_identity, Identity]
[pallet_im_online, ImOnline] [pallet_im_online, ImOnline]
[pallet_indices, Indices] [pallet_indices, Indices]
[pallet_message_queue, MessageQueue]
[pallet_multisig, Multisig] [pallet_multisig, Multisig]
[pallet_nomination_pools, NominationPoolsBench::<Runtime>] [pallet_nomination_pools, NominationPoolsBench::<Runtime>]
[pallet_offences, OffencesBench::<Runtime>] [pallet_offences, OffencesBench::<Runtime>]
@@ -1902,6 +1967,19 @@ sp_api::impl_runtime_apis! {
} }
} }
#[cfg(test)]
mod test {
use super::*;
#[test]
fn max_upward_message_size() {
assert_eq!(
ump_migrations::MAX_UPWARD_MESSAGE_SIZE,
pallet_message_queue::MaxMessageLenOf::<Runtime>::get()
);
}
}
#[cfg(all(test, feature = "try-runtime"))] #[cfg(all(test, feature = "try-runtime"))]
mod remote_tests { mod remote_tests {
use super::*; use super::*;
+8
View File
@@ -50,6 +50,14 @@ fn call_size() {
); );
} }
#[test]
fn max_upward_message_size() {
assert_eq!(
ump_migrations::MAX_UPWARD_MESSAGE_SIZE,
pallet_message_queue::MaxMessageLenOf::<Runtime>::get()
);
}
#[test] #[test]
fn sanity_check_teleport_assets_weight() { fn sanity_check_teleport_assets_weight() {
// This test sanity checks that at least 50 teleports can exist in a block. // This test sanity checks that at least 50 teleports can exist in a block.
+2 -1
View File
@@ -24,6 +24,7 @@ pub mod pallet_fast_unstake;
pub mod pallet_identity; pub mod pallet_identity;
pub mod pallet_im_online; pub mod pallet_im_online;
pub mod pallet_indices; pub mod pallet_indices;
pub mod pallet_message_queue;
pub mod pallet_multisig; pub mod pallet_multisig;
pub mod pallet_nomination_pools; pub mod pallet_nomination_pools;
pub mod pallet_preimage; pub mod pallet_preimage;
@@ -44,8 +45,8 @@ pub mod runtime_parachains_configuration;
pub mod runtime_parachains_disputes; pub mod runtime_parachains_disputes;
pub mod runtime_parachains_disputes_slashing; pub mod runtime_parachains_disputes_slashing;
pub mod runtime_parachains_hrmp; pub mod runtime_parachains_hrmp;
pub mod runtime_parachains_inclusion;
pub mod runtime_parachains_initializer; pub mod runtime_parachains_initializer;
pub mod runtime_parachains_paras; pub mod runtime_parachains_paras;
pub mod runtime_parachains_paras_inherent; pub mod runtime_parachains_paras_inherent;
pub mod runtime_parachains_ump;
pub mod xcm; pub mod xcm;
@@ -0,0 +1,176 @@
// Copyright 2017-2022 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 <http://www.gnu.org/licenses/>.
//! Autogenerated weights for `pallet_message_queue`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2023-02-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K`
//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("westend-dev"), DB CACHE: 1024
// Executed Command:
// ./target/release/polkadot
// benchmark
// pallet
// --chain=westend-dev
// --steps=50
// --repeat=20
// --pallet=pallet-message-queue
// --extrinsic=*
// --heap-pages=4096
// --header=file_header.txt
// --output
// runtime/westend/src/weights/pallet_message_queue.rs
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
#![allow(unused_imports)]
use frame_support::{traits::Get, weights::Weight};
use sp_std::marker::PhantomData;
/// Weight functions for `pallet_message_queue`.
pub struct WeightInfo<T>(PhantomData<T>);
impl<T: frame_system::Config> pallet_message_queue::WeightInfo for WeightInfo<T> {
/// Storage: MessageQueue ServiceHead (r:1 w:0)
/// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen)
/// Storage: MessageQueue BookStateFor (r:2 w:2)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
fn ready_ring_knit() -> Weight {
// Proof Size summary in bytes:
// Measured: `804`
// Estimated: `5554`
// Minimum execution time: 5_813 nanoseconds.
Weight::from_parts(5_980_000, 0)
.saturating_add(Weight::from_parts(0, 5554))
.saturating_add(T::DbWeight::get().reads(3))
.saturating_add(T::DbWeight::get().writes(2))
}
/// Storage: MessageQueue BookStateFor (r:2 w:2)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
/// Storage: MessageQueue ServiceHead (r:1 w:1)
/// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen)
fn ready_ring_unknit() -> Weight {
// Proof Size summary in bytes:
// Measured: `804`
// Estimated: `5554`
// Minimum execution time: 5_742 nanoseconds.
Weight::from_parts(5_986_000, 0)
.saturating_add(Weight::from_parts(0, 5554))
.saturating_add(T::DbWeight::get().reads(3))
.saturating_add(T::DbWeight::get().writes(3))
}
/// Storage: MessageQueue BookStateFor (r:1 w:1)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
fn service_queue_base() -> Weight {
// Proof Size summary in bytes:
// Measured: `543`
// Estimated: `2527`
// Minimum execution time: 2_118 nanoseconds.
Weight::from_parts(2_206_000, 0)
.saturating_add(Weight::from_parts(0, 2527))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
/// Storage: MessageQueue Pages (r:1 w:1)
/// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen)
fn service_page_base_completion() -> Weight {
// Proof Size summary in bytes:
// Measured: `615`
// Estimated: `68060`
// Minimum execution time: 3_153 nanoseconds.
Weight::from_parts(3_240_000, 0)
.saturating_add(Weight::from_parts(0, 68060))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
/// Storage: MessageQueue Pages (r:1 w:1)
/// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen)
fn service_page_base_no_completion() -> Weight {
// Proof Size summary in bytes:
// Measured: `615`
// Estimated: `68060`
// Minimum execution time: 3_191 nanoseconds.
Weight::from_parts(3_289_000, 0)
.saturating_add(Weight::from_parts(0, 68060))
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
fn service_page_item() -> Weight {
// Proof Size summary in bytes:
// Measured: `904`
// Estimated: `0`
// Minimum execution time: 47_975 nanoseconds.
Weight::from_parts(49_334_000, 0)
.saturating_add(Weight::from_parts(0, 0))
}
/// Storage: MessageQueue ServiceHead (r:1 w:1)
/// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(5), added: 500, mode: MaxEncodedLen)
/// Storage: MessageQueue BookStateFor (r:1 w:0)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
fn bump_service_head() -> Weight {
// Proof Size summary in bytes:
// Measured: `679`
// Estimated: `3027`
// Minimum execution time: 3_725 nanoseconds.
Weight::from_parts(4_074_000, 0)
.saturating_add(Weight::from_parts(0, 3027))
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(1))
}
/// Storage: MessageQueue BookStateFor (r:1 w:1)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
/// Storage: MessageQueue Pages (r:1 w:1)
/// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen)
fn reap_page() -> Weight {
// Proof Size summary in bytes:
// Measured: `66814`
// Estimated: `70587`
// Minimum execution time: 28_769 nanoseconds.
Weight::from_parts(29_450_000, 0)
.saturating_add(Weight::from_parts(0, 70587))
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(2))
}
/// Storage: MessageQueue BookStateFor (r:1 w:1)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
/// Storage: MessageQueue Pages (r:1 w:1)
/// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen)
fn execute_overweight_page_removed() -> Weight {
// Proof Size summary in bytes:
// Measured: `66814`
// Estimated: `70587`
// Minimum execution time: 74_422 nanoseconds.
Weight::from_parts(78_637_000, 0)
.saturating_add(Weight::from_parts(0, 70587))
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(2))
}
/// Storage: MessageQueue BookStateFor (r:1 w:1)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
/// Storage: MessageQueue Pages (r:1 w:1)
/// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen)
fn execute_overweight_page_updated() -> Weight {
// Proof Size summary in bytes:
// Measured: `66814`
// Estimated: `70587`
// Minimum execution time: 75_542 nanoseconds.
Weight::from_parts(80_545_000, 0)
.saturating_add(Weight::from_parts(0, 70587))
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(2))
}
}
@@ -0,0 +1,66 @@
// Copyright 2017-2022 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 <http://www.gnu.org/licenses/>.
//! Autogenerated weights for `runtime_parachains::inclusion`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `i9`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K`
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westend-dev"), DB CACHE: 1024
// Executed Command:
// ./target/release/polkadot
// benchmark
// pallet
// --chain=westend-dev
// --steps=50
// --repeat=20
// --pallet=runtime_parachains::inclusion
// --extrinsic=*
// --execution=wasm
// --wasm-execution=compiled
// --header=./file_header.txt
// --output=./runtime/westend/src/weights
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
#![allow(unused_imports)]
use frame_support::{traits::Get, weights::Weight};
use sp_std::marker::PhantomData;
/// Weight functions for `runtime_parachains::inclusion`.
pub struct WeightInfo<T>(PhantomData<T>);
impl<T: frame_system::Config> runtime_parachains::inclusion::WeightInfo for WeightInfo<T> {
/// Storage: MessageQueue BookStateFor (r:1 w:1)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen)
/// Storage: MessageQueue Pages (r:1 w:999)
/// Proof: MessageQueue Pages (max_values: None, max_size: Some(65585), added: 68060, mode: MaxEncodedLen)
/// The range of component `i` is `[1, 1000]`.
fn receive_upward_messages(i: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `51490`
// Estimated: `70587`
// Minimum execution time: 49_053 nanoseconds.
Weight::from_parts(49_506_000, 0)
.saturating_add(Weight::from_parts(0, 70587))
// Standard Error: 62_734
.saturating_add(Weight::from_parts(43_511_974, 0).saturating_mul(i.into()))
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(1))
.saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into())))
}
}
@@ -1,93 +0,0 @@
// 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 <http://www.gnu.org/licenses/>.
//! Autogenerated weights for `runtime_parachains::ump`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2023-04-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westend-dev"), DB CACHE: 1024
// Executed Command:
// ./target/production/polkadot
// benchmark
// pallet
// --chain=westend-dev
// --steps=50
// --repeat=20
// --pallet=runtime_parachains::ump
// --extrinsic=*
// --execution=wasm
// --wasm-execution=compiled
// --header=./file_header.txt
// --output=./runtime/westend/src/weights/runtime_parachains_ump.rs
#![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 `runtime_parachains::ump`.
pub struct WeightInfo<T>(PhantomData<T>);
impl<T: frame_system::Config> runtime_parachains::ump::WeightInfo for WeightInfo<T> {
/// The range of component `s` is `[0, 51200]`.
fn process_upward_message(s: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 6_172_000 picoseconds.
Weight::from_parts(6_259_000, 0)
.saturating_add(Weight::from_parts(0, 0))
// Standard Error: 8
.saturating_add(Weight::from_parts(1_359, 0).saturating_mul(s.into()))
}
/// Storage: Ump NeedsDispatch (r:1 w:1)
/// Proof Skipped: Ump NeedsDispatch (max_values: Some(1), max_size: None, mode: Measured)
/// Storage: Ump NextDispatchRoundStartWith (r:1 w:1)
/// Proof Skipped: Ump NextDispatchRoundStartWith (max_values: Some(1), max_size: None, mode: Measured)
/// Storage: Ump RelayDispatchQueues (r:0 w:1)
/// Proof Skipped: Ump RelayDispatchQueues (max_values: None, max_size: None, mode: Measured)
/// Storage: Ump RelayDispatchQueueSize (r:0 w:1)
/// Proof Skipped: Ump RelayDispatchQueueSize (max_values: None, max_size: None, mode: Measured)
fn clean_ump_after_outgoing() -> Weight {
// Proof Size summary in bytes:
// Measured: `206`
// Estimated: `1691`
// Minimum execution time: 9_533_000 picoseconds.
Weight::from_parts(9_765_000, 0)
.saturating_add(Weight::from_parts(0, 1691))
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(4))
}
/// Storage: Ump Overweight (r:1 w:1)
/// Proof Skipped: Ump Overweight (max_values: None, max_size: None, mode: Measured)
/// Storage: Ump CounterForOverweight (r:1 w:1)
/// Proof: Ump CounterForOverweight (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
fn service_overweight() -> Weight {
// Proof Size summary in bytes:
// Measured: `223`
// Estimated: `3688`
// Minimum execution time: 23_648_000 picoseconds.
Weight::from_parts(23_848_000, 0)
.saturating_add(Weight::from_parts(0, 3688))
.saturating_add(T::DbWeight::get().reads(2))
.saturating_add(T::DbWeight::get().writes(2))
}
}
@@ -27,7 +27,6 @@ use sp_core::H256;
use sp_runtime::{ use sp_runtime::{
testing::Header, testing::Header,
traits::{BlakeTwo256, IdentityLookup}, traits::{BlakeTwo256, IdentityLookup},
BuildStorage,
}; };
use xcm::latest::prelude::*; use xcm::latest::prelude::*;
use xcm_builder::{AllowUnpaidExecutionFrom, MintLocation}; use xcm_builder::{AllowUnpaidExecutionFrom, MintLocation};
@@ -206,7 +205,9 @@ impl xcm_balances_benchmark::Config for Test {
} }
} }
#[cfg(feature = "runtime-benchmarks")]
pub fn new_test_ext() -> sp_io::TestExternalities { pub fn new_test_ext() -> sp_io::TestExternalities {
use sp_runtime::BuildStorage;
let t = GenesisConfig { ..Default::default() }.build_storage().unwrap(); let t = GenesisConfig { ..Default::default() }.build_storage().unwrap();
sp_tracing::try_init_simple(); sp_tracing::try_init_simple();
t.into() t.into()
@@ -27,7 +27,6 @@ use sp_core::H256;
use sp_runtime::{ use sp_runtime::{
testing::Header, testing::Header,
traits::{BlakeTwo256, IdentityLookup, TrailingZeroInput}, traits::{BlakeTwo256, IdentityLookup, TrailingZeroInput},
BuildStorage,
}; };
use xcm_builder::{ use xcm_builder::{
test_utils::{ test_utils::{
@@ -194,7 +193,9 @@ impl generic::Config for Test {
} }
} }
#[cfg(feature = "runtime-benchmarks")]
pub fn new_test_ext() -> sp_io::TestExternalities { pub fn new_test_ext() -> sp_io::TestExternalities {
use sp_runtime::BuildStorage;
let t = GenesisConfig { ..Default::default() }.build_storage().unwrap(); let t = GenesisConfig { ..Default::default() }.build_storage().unwrap();
sp_tracing::try_init_simple(); sp_tracing::try_init_simple();
t.into() t.into()
+3
View File
@@ -15,6 +15,7 @@ sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", d
sp-arithmetic = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-arithmetic = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-weights = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
@@ -29,6 +30,7 @@ pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "m
pallet-xcm = { path = "../pallet-xcm" } pallet-xcm = { path = "../pallet-xcm" }
polkadot-runtime-parachains = { path = "../../runtime/parachains" } polkadot-runtime-parachains = { path = "../../runtime/parachains" }
assert_matches = "1.5.0" assert_matches = "1.5.0"
polkadot-test-runtime = { path = "../../runtime/test-runtime" }
[features] [features]
default = ["std"] default = ["std"]
@@ -46,6 +48,7 @@ std = [
"sp-arithmetic/std", "sp-arithmetic/std",
"sp-io/std", "sp-io/std",
"sp-runtime/std", "sp-runtime/std",
"sp-weights/std",
"frame-support/std", "frame-support/std",
"frame-system/std", "frame-system/std",
"polkadot-parachain/std", "polkadot-parachain/std",
+3
View File
@@ -54,6 +54,9 @@ pub use barriers::{
RespectSuspension, TakeWeightCredit, WithComputedOrigin, RespectSuspension, TakeWeightCredit, WithComputedOrigin,
}; };
mod process_xcm_message;
pub use process_xcm_message::ProcessXcmMessage;
mod currency_adapter; mod currency_adapter;
pub use currency_adapter::CurrencyAdapter; pub use currency_adapter::CurrencyAdapter;
@@ -0,0 +1,154 @@
// Copyright 2020 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 <http://www.gnu.org/licenses/>.
//! Implementation of `ProcessMessage` for an `ExecuteXcm` implementation.
use frame_support::{
ensure,
traits::{ProcessMessage, ProcessMessageError},
};
use parity_scale_codec::{Decode, FullCodec, MaxEncodedLen};
use scale_info::TypeInfo;
use sp_io::hashing::blake2_256;
use sp_std::{fmt::Debug, marker::PhantomData};
use sp_weights::{Weight, WeightMeter};
use xcm::prelude::*;
/// A message processor that delegates execution to an [XcmExecutor].
pub struct ProcessXcmMessage<MessageOrigin, XcmExecutor, Call>(
PhantomData<(MessageOrigin, XcmExecutor, Call)>,
);
impl<
MessageOrigin: Into<MultiLocation> + FullCodec + MaxEncodedLen + Clone + Eq + PartialEq + TypeInfo + Debug,
XcmExecutor: ExecuteXcm<Call>,
Call,
> ProcessMessage for ProcessXcmMessage<MessageOrigin, XcmExecutor, Call>
{
type Origin = MessageOrigin;
/// Process the given message, using no more than the remaining `weight` to do so.
fn process_message(
message: &[u8],
origin: Self::Origin,
meter: &mut WeightMeter,
) -> Result<bool, ProcessMessageError> {
let hash = blake2_256(message);
let versioned_message = VersionedXcm::<Call>::decode(&mut &message[..])
.map_err(|_| ProcessMessageError::Corrupt)?;
let message = Xcm::<Call>::try_from(versioned_message)
.map_err(|_| ProcessMessageError::Unsupported)?;
let pre = XcmExecutor::prepare(message).map_err(|_| ProcessMessageError::Unsupported)?;
let required = pre.weight_of();
ensure!(meter.can_accrue(required), ProcessMessageError::Overweight(required));
let (consumed, result) =
match XcmExecutor::execute(origin.into(), pre, hash, Weight::zero()) {
Outcome::Complete(w) => (w, Ok(true)),
Outcome::Incomplete(w, _) => (w, Ok(false)),
// In the error-case we assume the worst case and consume all possible weight.
Outcome::Error(_) => (required, Err(ProcessMessageError::Unsupported)),
};
meter.defensive_saturating_accrue(consumed);
result
}
}
#[cfg(test)]
mod tests {
use super::*;
use frame_support::{
assert_err, assert_ok,
traits::{ProcessMessageError, ProcessMessageError::*},
};
use parity_scale_codec::Encode;
use polkadot_test_runtime::*;
use xcm::{v2, v3, VersionedXcm};
const ORIGIN: Junction = Junction::OnlyChild;
/// The processor to use for tests.
type Processor =
ProcessXcmMessage<Junction, xcm_executor::XcmExecutor<xcm_config::XcmConfig>, RuntimeCall>;
#[test]
fn process_message_trivial_works() {
// ClearOrigin works.
assert!(process(v2_xcm(true)).unwrap());
assert!(process(v3_xcm(true)).unwrap());
}
#[test]
fn process_message_trivial_fails() {
// Trap makes it fail.
assert!(!process(v3_xcm(false)).unwrap());
assert!(!process(v3_xcm(false)).unwrap());
}
#[test]
fn process_message_corrupted_fails() {
let msgs: &[&[u8]] = &[&[], &[55, 66], &[123, 222, 233]];
for msg in msgs {
assert_err!(process_raw(msg), Corrupt);
}
}
#[test]
fn process_message_overweight_fails() {
for msg in [v3_xcm(true), v3_xcm(false), v3_xcm(false), v2_xcm(false)] {
let msg = &msg.encode()[..];
// Errors if we stay below a weight limit of 1000.
for i in 0..10 {
let meter = &mut WeightMeter::from_limit((i * 10).into());
assert_err!(
Processor::process_message(msg, ORIGIN, meter),
Overweight(1000.into())
);
assert_eq!(meter.consumed, 0.into());
}
// Works with a limit of 1000.
let meter = &mut WeightMeter::from_limit(1000.into());
assert_ok!(Processor::process_message(msg, ORIGIN, meter));
assert_eq!(meter.consumed, 1000.into());
}
}
fn v2_xcm(success: bool) -> VersionedXcm<RuntimeCall> {
let instr = if success {
v3::Instruction::<RuntimeCall>::ClearOrigin
} else {
v3::Instruction::<RuntimeCall>::Trap(1)
};
VersionedXcm::V3(v3::Xcm::<RuntimeCall>(vec![instr]))
}
fn v3_xcm(success: bool) -> VersionedXcm<RuntimeCall> {
let instr = if success {
v2::Instruction::<RuntimeCall>::ClearOrigin
} else {
v2::Instruction::<RuntimeCall>::Trap(1)
};
VersionedXcm::V2(v2::Xcm::<RuntimeCall>(vec![instr]))
}
fn process(msg: VersionedXcm<RuntimeCall>) -> Result<bool, ProcessMessageError> {
process_raw(msg.encode().as_slice())
}
fn process_raw(raw: &[u8]) -> Result<bool, ProcessMessageError> {
Processor::process_message(raw, ORIGIN, &mut WeightMeter::max_limit())
}
}
+1
View File
@@ -15,6 +15,7 @@ sp-std = { git = "https://github.com/paritytech/substrate", branch = "master" }
xcm = { path = "../" } xcm = { path = "../" }
xcm-executor = { path = "../xcm-executor" } xcm-executor = { path = "../xcm-executor" }
xcm-builder = { path = "../xcm-builder" }
polkadot-core-primitives = { path = "../../core-primitives"} polkadot-core-primitives = { path = "../../core-primitives"}
polkadot-parachain = { path = "../../parachain" } polkadot-parachain = { path = "../../parachain" }
polkadot-runtime-parachains = { path = "../../runtime/parachains" } polkadot-runtime-parachains = { path = "../../runtime/parachains" }
@@ -13,6 +13,7 @@ log = { version = "0.4.14", default-features = false }
frame-system = { git = "https://github.com/paritytech/substrate", branch = "master" } frame-system = { git = "https://github.com/paritytech/substrate", branch = "master" }
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" } frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" } pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-message-queue = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-uniques = { git = "https://github.com/paritytech/substrate", branch = "master" } pallet-uniques = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-std = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-std = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
@@ -35,6 +36,7 @@ runtime-benchmarks = [
"frame-system/runtime-benchmarks", "frame-system/runtime-benchmarks",
"frame-support/runtime-benchmarks", "frame-support/runtime-benchmarks",
"pallet-balances/runtime-benchmarks", "pallet-balances/runtime-benchmarks",
"pallet-message-queue/runtime-benchmarks",
"pallet-uniques/runtime-benchmarks", "pallet-uniques/runtime-benchmarks",
"pallet-xcm/runtime-benchmarks", "pallet-xcm/runtime-benchmarks",
"xcm-builder/runtime-benchmarks", "xcm-builder/runtime-benchmarks",
@@ -20,7 +20,7 @@ mod relay_chain;
use frame_support::sp_tracing; use frame_support::sp_tracing;
use xcm::prelude::*; use xcm::prelude::*;
use xcm_executor::traits::Convert; use xcm_executor::traits::Convert;
use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain}; use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain, TestExt};
pub const ALICE: sp_runtime::AccountId32 = sp_runtime::AccountId32::new([0u8; 32]); pub const ALICE: sp_runtime::AccountId32 = sp_runtime::AccountId32::new([0u8; 32]);
pub const INITIAL_BALANCE: u128 = 1_000_000_000; pub const INITIAL_BALANCE: u128 = 1_000_000_000;
@@ -46,7 +46,11 @@ decl_test_parachain! {
decl_test_relay_chain! { decl_test_relay_chain! {
pub struct Relay { pub struct Relay {
Runtime = relay_chain::Runtime, Runtime = relay_chain::Runtime,
RuntimeCall = relay_chain::RuntimeCall,
RuntimeEvent = relay_chain::RuntimeEvent,
XcmConfig = relay_chain::XcmConfig, XcmConfig = relay_chain::XcmConfig,
MessageQueue = relay_chain::MessageQueue,
System = relay_chain::System,
new_ext = relay_ext(), new_ext = relay_ext(),
} }
} }
@@ -18,8 +18,8 @@
use frame_support::{ use frame_support::{
construct_runtime, parameter_types, construct_runtime, parameter_types,
traits::{AsEnsureOriginWithArg, Everything, Nothing}, traits::{AsEnsureOriginWithArg, Everything, Nothing, ProcessMessage, ProcessMessageError},
weights::Weight, weights::{Weight, WeightMeter},
}; };
use frame_system::EnsureRoot; use frame_system::EnsureRoot;
@@ -27,7 +27,11 @@ use sp_core::{ConstU32, H256};
use sp_runtime::{testing::Header, traits::IdentityLookup, AccountId32}; use sp_runtime::{testing::Header, traits::IdentityLookup, AccountId32};
use polkadot_parachain::primitives::Id as ParaId; use polkadot_parachain::primitives::Id as ParaId;
use polkadot_runtime_parachains::{configuration, origin, shared, ump}; use polkadot_runtime_parachains::{
configuration,
inclusion::{AggregateMessageOrigin, UmpQueueId},
origin, shared,
};
use xcm::latest::prelude::*; use xcm::latest::prelude::*;
use xcm_builder::{ use xcm_builder::{
Account32Hash, AccountId32Aliases, AllowUnpaidExecutionFrom, AsPrefixedGeneralIndex, Account32Hash, AccountId32Aliases, AllowUnpaidExecutionFrom, AsPrefixedGeneralIndex,
@@ -232,19 +236,50 @@ parameter_types! {
pub const FirstMessageFactorPercent: u64 = 100; pub const FirstMessageFactorPercent: u64 = 100;
} }
impl ump::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type UmpSink = ump::XcmSink<XcmExecutor<XcmConfig>, Runtime>;
type FirstMessageFactorPercent = FirstMessageFactorPercent;
type ExecuteOverweightOrigin = frame_system::EnsureRoot<AccountId>;
type WeightInfo = ump::TestWeightInfo;
}
impl origin::Config for Runtime {} impl origin::Config for Runtime {}
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Runtime>; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Runtime>;
type Block = frame_system::mocking::MockBlock<Runtime>; type Block = frame_system::mocking::MockBlock<Runtime>;
parameter_types! {
/// Amount of weight that can be spent per block to service messages.
pub MessageQueueServiceWeight: Weight = Weight::from_parts(1_000_000_000, 1_000_000);
pub const MessageQueueHeapSize: u32 = 65_536;
pub const MessageQueueMaxStale: u32 = 16;
}
/// Message processor to handle any messages that were enqueued into the `MessageQueue` pallet.
pub struct MessageProcessor;
impl ProcessMessage for MessageProcessor {
type Origin = AggregateMessageOrigin;
fn process_message(
message: &[u8],
origin: Self::Origin,
meter: &mut WeightMeter,
) -> Result<bool, ProcessMessageError> {
let para = match origin {
AggregateMessageOrigin::Ump(UmpQueueId::Para(para)) => para,
};
xcm_builder::ProcessXcmMessage::<
Junction,
xcm_executor::XcmExecutor<XcmConfig>,
RuntimeCall,
>::process_message(message, Junction::Parachain(para.into()), meter)
}
}
impl pallet_message_queue::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type Size = u32;
type HeapSize = MessageQueueHeapSize;
type MaxStale = MessageQueueMaxStale;
type ServiceWeight = MessageQueueServiceWeight;
type MessageProcessor = MessageProcessor;
type QueueChangeHandler = ();
type WeightInfo = ();
}
construct_runtime!( construct_runtime!(
pub enum Runtime where pub enum Runtime where
Block = Block, Block = Block,
@@ -254,8 +289,8 @@ construct_runtime!(
System: frame_system::{Pallet, Call, Storage, Config, Event<T>}, System: frame_system::{Pallet, Call, Storage, Config, Event<T>},
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>}, Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
ParasOrigin: origin::{Pallet, Origin}, ParasOrigin: origin::{Pallet, Origin},
ParasUmp: ump::{Pallet, Call, Storage, Event},
XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event<T>, Origin}, XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event<T>, Origin},
Uniques: pallet_uniques::{Pallet, Call, Storage, Event<T>}, Uniques: pallet_uniques::{Pallet, Call, Storage, Event<T>},
MessageQueue: pallet_message_queue::{Pallet, Event<T>},
} }
); );
@@ -14,6 +14,7 @@ scale-info = { version = "2.5.0", features = ["derive"] }
frame-system = { git = "https://github.com/paritytech/substrate", branch = "master" } frame-system = { git = "https://github.com/paritytech/substrate", branch = "master" }
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" } frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" } pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-message-queue = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-std = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-std = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
@@ -31,6 +32,7 @@ polkadot-parachain = { path = "../../../parachain" }
[features] [features]
runtime-benchmarks = [ runtime-benchmarks = [
"pallet-xcm/runtime-benchmarks", "pallet-xcm/runtime-benchmarks",
"pallet-message-queue/runtime-benchmarks",
"xcm-builder/runtime-benchmarks", "xcm-builder/runtime-benchmarks",
"frame-support/runtime-benchmarks", "frame-support/runtime-benchmarks",
] ]
@@ -60,7 +60,11 @@ decl_test_parachain! {
decl_test_relay_chain! { decl_test_relay_chain! {
pub struct Relay { pub struct Relay {
Runtime = relay_chain::Runtime, Runtime = relay_chain::Runtime,
RuntimeCall = relay_chain::RuntimeCall,
RuntimeEvent = relay_chain::RuntimeEvent,
XcmConfig = relay_chain::XcmConfig, XcmConfig = relay_chain::XcmConfig,
MessageQueue = relay_chain::MessageQueue,
System = relay_chain::System,
new_ext = relay_ext(), new_ext = relay_ext(),
} }
} }
@@ -18,8 +18,8 @@
use frame_support::{ use frame_support::{
construct_runtime, parameter_types, construct_runtime, parameter_types,
traits::{Everything, Nothing}, traits::{Everything, Nothing, ProcessMessage, ProcessMessageError},
weights::Weight, weights::{Weight, WeightMeter},
}; };
use frame_system::EnsureRoot; use frame_system::EnsureRoot;
@@ -27,7 +27,11 @@ use sp_core::{ConstU32, H256};
use sp_runtime::{testing::Header, traits::IdentityLookup, AccountId32}; use sp_runtime::{testing::Header, traits::IdentityLookup, AccountId32};
use polkadot_parachain::primitives::Id as ParaId; use polkadot_parachain::primitives::Id as ParaId;
use polkadot_runtime_parachains::{configuration, origin, shared, ump}; use polkadot_runtime_parachains::{
configuration,
inclusion::{AggregateMessageOrigin, UmpQueueId},
origin, shared,
};
use xcm::latest::prelude::*; use xcm::latest::prelude::*;
use xcm_builder::{ use xcm_builder::{
AccountId32Aliases, AllowUnpaidExecutionFrom, ChildParachainAsNative, AccountId32Aliases, AllowUnpaidExecutionFrom, ChildParachainAsNative,
@@ -122,7 +126,7 @@ type LocalOriginConverter = (
parameter_types! { parameter_types! {
pub const BaseXcmWeight: Weight = Weight::from_parts(1_000, 1_000); pub const BaseXcmWeight: Weight = Weight::from_parts(1_000, 1_000);
pub KsmPerSecondPerByte: (AssetId, u128, u128) = (Concrete(TokenLocation::get()), 1, 1); pub KsmPerSecondPerByte: (AssetId, u128, u128) = (Concrete(TokenLocation::get()), 1, 1);
pub const MaxInstructions: u32 = 100; pub const MaxInstructions: u32 = u32::MAX;
pub const MaxAssetsIntoHolding: u32 = 64; pub const MaxAssetsIntoHolding: u32 = 64;
} }
@@ -196,19 +200,54 @@ parameter_types! {
pub const FirstMessageFactorPercent: u64 = 100; pub const FirstMessageFactorPercent: u64 = 100;
} }
impl ump::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type UmpSink = ump::XcmSink<XcmExecutor<XcmConfig>, Runtime>;
type FirstMessageFactorPercent = FirstMessageFactorPercent;
type ExecuteOverweightOrigin = frame_system::EnsureRoot<AccountId>;
type WeightInfo = ump::TestWeightInfo;
}
impl origin::Config for Runtime {} impl origin::Config for Runtime {}
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Runtime>; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Runtime>;
type Block = frame_system::mocking::MockBlock<Runtime>; type Block = frame_system::mocking::MockBlock<Runtime>;
parameter_types! {
/// Amount of weight that can be spent per block to service messages.
pub MessageQueueServiceWeight: Weight = Weight::from_parts(1_000_000_000, 1_000_000);
pub const MessageQueueHeapSize: u32 = 65_536;
pub const MessageQueueMaxStale: u32 = 16;
}
/// Message processor to handle any messages that were enqueued into the `MessageQueue` pallet.
pub struct MessageProcessor;
impl ProcessMessage for MessageProcessor {
type Origin = AggregateMessageOrigin;
fn process_message(
message: &[u8],
origin: Self::Origin,
meter: &mut WeightMeter,
) -> Result<bool, ProcessMessageError> {
let para = match origin {
AggregateMessageOrigin::Ump(UmpQueueId::Para(para)) => para,
};
xcm_builder::ProcessXcmMessage::<
Junction,
xcm_executor::XcmExecutor<XcmConfig>,
RuntimeCall,
>::process_message(message, Junction::Parachain(para.into()), meter)
}
}
impl pallet_message_queue::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type Size = u32;
type HeapSize = MessageQueueHeapSize;
type MaxStale = MessageQueueMaxStale;
type ServiceWeight = MessageQueueServiceWeight;
#[cfg(not(feature = "runtime-benchmarks"))]
type MessageProcessor = MessageProcessor;
#[cfg(feature = "runtime-benchmarks")]
type MessageProcessor =
pallet_message_queue::mock_helpers::NoopMessageProcessor<AggregateMessageOrigin>;
type QueueChangeHandler = ();
type WeightInfo = ();
}
construct_runtime!( construct_runtime!(
pub enum Runtime where pub enum Runtime where
Block = Block, Block = Block,
@@ -218,7 +257,7 @@ construct_runtime!(
System: frame_system::{Pallet, Call, Storage, Config, Event<T>}, System: frame_system::{Pallet, Call, Storage, Config, Event<T>},
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>}, Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
ParasOrigin: origin::{Pallet, Origin}, ParasOrigin: origin::{Pallet, Origin},
ParasUmp: ump::{Pallet, Call, Storage, Event},
XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event<T>, Origin}, XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event<T>, Origin},
MessageQueue: pallet_message_queue::{Pallet, Event<T>},
} }
); );
+49 -18
View File
@@ -19,7 +19,10 @@
pub use codec::Encode; pub use codec::Encode;
pub use paste; pub use paste;
pub use frame_support::{traits::Get, weights::Weight}; pub use frame_support::{
traits::{EnqueueMessage, Get, ProcessMessage, ProcessMessageError, ServiceQueues},
weights::{Weight, WeightMeter},
};
pub use sp_io::{hashing::blake2_256, TestExternalities}; pub use sp_io::{hashing::blake2_256, TestExternalities};
pub use sp_std::{cell::RefCell, collections::vec_deque::VecDeque, marker::PhantomData}; pub use sp_std::{cell::RefCell, collections::vec_deque::VecDeque, marker::PhantomData};
@@ -30,9 +33,10 @@ pub use polkadot_parachain::primitives::{
}; };
pub use polkadot_runtime_parachains::{ pub use polkadot_runtime_parachains::{
dmp, dmp,
ump::{self, MessageId, UmpSink, XcmSink}, inclusion::{AggregateMessageOrigin, UmpQueueId},
}; };
pub use xcm::{latest::prelude::*, VersionedXcm}; pub use xcm::{latest::prelude::*, VersionedXcm};
pub use xcm_builder::ProcessXcmMessage;
pub use xcm_executor::XcmExecutor; pub use xcm_executor::XcmExecutor;
pub trait TestExt { pub trait TestExt {
@@ -100,7 +104,11 @@ macro_rules! decl_test_relay_chain {
( (
pub struct $name:ident { pub struct $name:ident {
Runtime = $runtime:path, Runtime = $runtime:path,
RuntimeCall = $runtime_call:path,
RuntimeEvent = $runtime_event:path,
XcmConfig = $xcm_config:path, XcmConfig = $xcm_config:path,
MessageQueue = $mq:path,
System = $system:path,
new_ext = $new_ext:expr, new_ext = $new_ext:expr,
} }
) => { ) => {
@@ -108,18 +116,37 @@ macro_rules! decl_test_relay_chain {
$crate::__impl_ext!($name, $new_ext); $crate::__impl_ext!($name, $new_ext);
impl $crate::UmpSink for $name { impl $crate::ProcessMessage for $name {
fn process_upward_message( type Origin = $crate::ParaId;
origin: $crate::ParaId,
fn process_message(
msg: &[u8], msg: &[u8],
max_weight: $crate::Weight, para: Self::Origin,
) -> Result<$crate::Weight, ($crate::MessageId, $crate::Weight)> { meter: &mut $crate::WeightMeter,
use $crate::{ump::UmpSink, TestExt}; ) -> Result<bool, $crate::ProcessMessageError> {
use $crate::{Weight, AggregateMessageOrigin, UmpQueueId, ServiceQueues, EnqueueMessage};
use $mq as message_queue;
use $runtime_event as runtime_event;
Self::execute_with(|| { Self::execute_with(|| {
$crate::ump::XcmSink::<$crate::XcmExecutor<$xcm_config>, $runtime>::process_upward_message( <$mq as EnqueueMessage<AggregateMessageOrigin>>::enqueue_message(
origin, msg, max_weight, msg.try_into().expect("Message too long"),
) AggregateMessageOrigin::Ump(UmpQueueId::Para(para.clone()))
);
<$system>::reset_events();
<$mq as ServiceQueues>::service_queues(Weight::MAX);
let events = <$system>::events();
let event = events.last().expect("There must be at least one event");
match &event.event {
runtime_event::MessageQueue(
pallet_message_queue::Event::Processed {origin, ..}) => {
assert_eq!(origin, &AggregateMessageOrigin::Ump(UmpQueueId::Para(para)));
},
event => panic!("Unexpected event: {:#?}", event),
}
Ok(true)
}) })
} }
} }
@@ -286,19 +313,23 @@ macro_rules! decl_test_network {
/// Process all messages originating from parachains. /// Process all messages originating from parachains.
fn process_para_messages() -> $crate::XcmResult { fn process_para_messages() -> $crate::XcmResult {
use $crate::{UmpSink, XcmpMessageHandlerT}; use $crate::{ProcessMessage, XcmpMessageHandlerT};
while let Some((para_id, destination, message)) = $crate::PARA_MESSAGE_BUS.with( while let Some((para_id, destination, message)) = $crate::PARA_MESSAGE_BUS.with(
|b| b.borrow_mut().pop_front()) { |b| b.borrow_mut().pop_front()) {
match destination.interior() { match destination.interior() {
$crate::Junctions::Here if destination.parent_count() == 1 => { $crate::Junctions::Here if destination.parent_count() == 1 => {
let encoded = $crate::encode_xcm(message, $crate::MessageKind::Ump); let encoded = $crate::encode_xcm(message, $crate::MessageKind::Ump);
let r = <$relay_chain>::process_upward_message( let r = <$relay_chain>::process_message(
para_id, &encoded[..], encoded.as_slice(), para_id,
$crate::Weight::MAX, &mut $crate::WeightMeter::max_limit(),
); );
if let Err((id, required)) = r { match r {
return Err($crate::XcmError::WeightLimitReached(required)); Err($crate::ProcessMessageError::Overweight(required)) =>
return Err($crate::XcmError::WeightLimitReached(required)),
// Not really the correct error, but there is no "undecodable".
Err(_) => return Err($crate::XcmError::Unimplemented),
Ok(_) => (),
} }
}, },
$( $(
@@ -353,7 +384,7 @@ macro_rules! decl_test_network {
destination: &mut Option<$crate::MultiLocation>, destination: &mut Option<$crate::MultiLocation>,
message: &mut Option<$crate::Xcm<()>>, message: &mut Option<$crate::Xcm<()>>,
) -> $crate::SendResult<($crate::ParaId, $crate::MultiLocation, $crate::Xcm<()>)> { ) -> $crate::SendResult<($crate::ParaId, $crate::MultiLocation, $crate::Xcm<()>)> {
use $crate::{UmpSink, XcmpMessageHandlerT}; use $crate::XcmpMessageHandlerT;
let d = destination.take().ok_or($crate::SendError::MissingArgument)?; let d = destination.take().ok_or($crate::SendError::MissingArgument)?;
match (d.interior(), d.parent_count()) { match (d.interior(), d.parent_count()) {