Skip to content

Commit ac3f14d

Browse files
sam0x17gupnikkianenigmagavofyorkggwpez
authored
Tasks: general system for recognizing and executing service work (#1343)
`polkadot-sdk` version of original tasks PR located here: paritytech/substrate#14329 Fixes #206 ## Status - [x] Generic `Task` trait - [x] `RuntimeTask` aggregated enum, compatible with `construct_runtime!` - [x] Casting between `Task` and `RuntimeTask` without needing `dyn` or `Box` - [x] Tasks Example pallet - [x] Runtime tests for Tasks example pallet - [x] Parsing for task-related macros - [x] Retrofit parsing to make macros optional - [x] Expansion for task-related macros - [x] Adds support for args in tasks - [x] Retrofit tasks example pallet to use macros instead of manual syntax - [x] Weights - [x] Cleanup - [x] UI tests - [x] Docs ## Target Syntax Adapted from #206 (comment) ```rust // NOTE: this enum is optional and is auto-generated by the other macros if not present #[pallet::task] pub enum Task<T: Config> { AddNumberIntoTotal { i: u32, } } /// Some running total. #[pallet::storage] pub(super) type Total<T: Config<I>, I: 'static = ()> = StorageValue<_, (u32, u32), ValueQuery>; /// Numbers to be added into the total. #[pallet::storage] pub(super) type Numbers<T: Config<I>, I: 'static = ()> = StorageMap<_, Twox64Concat, u32, u32, OptionQuery>; #[pallet::tasks_experimental] impl<T: Config<I>, I: 'static> Pallet<T, I> { /// Add a pair of numbers into the totals and remove them. #[pallet::task_list(Numbers::<T, I>::iter_keys())] #[pallet::task_condition(|i| Numbers::<T, I>::contains_key(i))] #[pallet::task_index(0)] pub fn add_number_into_total(i: u32) -> DispatchResult { let v = Numbers::<T, I>::take(i).ok_or(Error::<T, I>::NotFound)?; Total::<T, I>::mutate(|(total_keys, total_values)| { *total_keys += i; *total_values += v; }); Ok(()) } } ``` --------- Co-authored-by: Nikhil Gupta <[email protected]> Co-authored-by: kianenigma <[email protected]> Co-authored-by: Nikhil Gupta <> Co-authored-by: Gavin Wood <[email protected]> Co-authored-by: Oliver Tale-Yazdi <[email protected]> Co-authored-by: gupnik <[email protected]>
1 parent 34c991e commit ac3f14d

File tree

75 files changed

+3516
-24
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+3516
-24
lines changed

Cargo.lock

Lines changed: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ members = [
308308
"substrate/frame/examples/kitchensink",
309309
"substrate/frame/examples/offchain-worker",
310310
"substrate/frame/examples/split",
311+
"substrate/frame/examples/tasks",
311312
"substrate/frame/executive",
312313
"substrate/frame/fast-unstake",
313314
"substrate/frame/glutton",

cumulus/pallets/collator-selection/src/mock.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
use super::*;
1717
use crate as collator_selection;
1818
use frame_support::{
19-
ord_parameter_types, parameter_types,
19+
derive_impl, ord_parameter_types, parameter_types,
2020
traits::{ConstBool, ConstU32, ConstU64, FindAuthor, ValidatorRegistration},
2121
PalletId,
2222
};
@@ -50,6 +50,7 @@ parameter_types! {
5050
pub const SS58Prefix: u8 = 42;
5151
}
5252

53+
#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)]
5354
impl system::Config for Test {
5455
type BaseCallFilter = frame_support::traits::Everything;
5556
type BlockWeights = ();

cumulus/parachain-template/pallets/template/src/mock.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use frame_support::{parameter_types, traits::Everything};
1+
use frame_support::{derive_impl, parameter_types, traits::Everything};
22
use frame_system as system;
33
use sp_core::H256;
44
use sp_runtime::{
@@ -22,6 +22,7 @@ parameter_types! {
2222
pub const SS58Prefix: u8 = 42;
2323
}
2424

25+
#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)]
2526
impl system::Config for Test {
2627
type BaseCallFilter = Everything;
2728
type BlockWeights = ();

prdoc/pr_1343.prdoc

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
title: Tasks API - A general system for recognizing and executing service work
2+
3+
doc:
4+
- audience: Runtime Dev
5+
description: |
6+
The Tasks API allows you to define some service work that can be recognized by a script or an off-chain worker.
7+
Such a script can then create and submit all such work items at any given time.
8+
`#[pallet:tasks_experimental]` provides a convenient way to define such work items. It can be attached to an
9+
`impl` block inside a pallet, whose functions can then be annotated by the following attributes:
10+
1. `#[pallet::task_list]`: Define an iterator over the available work items for a task
11+
2. `#[pallet::task_condition]`: Define the conditions for a given work item to be valid
12+
3. `#[pallet::task_weight]`: Define the weight of a given work item
13+
4. `#[pallet::task_index]`: Define the index of a given work item
14+
Each such function becomes a variant of the autogenerated enum `Task<T>` for this pallet.
15+
All such enums are aggregated into a `RuntimeTask` by `construct_runtime`.
16+
An example pallet that uses the Tasks API is available at `substrate/frame/example/tasks`.
17+
18+
migrations:
19+
db: []
20+
21+
runtime: []
22+
23+
crates:
24+
- name: frame-system
25+
- name: frame-support
26+
- name: frame-support-procedural
27+
- name: pallet-example-tasks
28+
29+
host_functions: []

substrate/bin/node/runtime/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ pallet-democracy = { path = "../../../frame/democracy", default-features = false
8080
pallet-election-provider-multi-phase = { path = "../../../frame/election-provider-multi-phase", default-features = false }
8181
pallet-election-provider-support-benchmarking = { path = "../../../frame/election-provider-support/benchmarking", default-features = false, optional = true }
8282
pallet-elections-phragmen = { path = "../../../frame/elections-phragmen", default-features = false }
83+
pallet-example-tasks = { path = "../../../frame/examples/tasks", default-features = false }
8384
pallet-fast-unstake = { path = "../../../frame/fast-unstake", default-features = false }
8485
pallet-nis = { path = "../../../frame/nis", default-features = false }
8586
pallet-grandpa = { path = "../../../frame/grandpa", default-features = false }
@@ -177,6 +178,7 @@ std = [
177178
"pallet-election-provider-multi-phase/std",
178179
"pallet-election-provider-support-benchmarking?/std",
179180
"pallet-elections-phragmen/std",
181+
"pallet-example-tasks/std",
180182
"pallet-fast-unstake/std",
181183
"pallet-glutton/std",
182184
"pallet-grandpa/std",
@@ -279,6 +281,7 @@ runtime-benchmarks = [
279281
"pallet-election-provider-multi-phase/runtime-benchmarks",
280282
"pallet-election-provider-support-benchmarking/runtime-benchmarks",
281283
"pallet-elections-phragmen/runtime-benchmarks",
284+
"pallet-example-tasks/runtime-benchmarks",
282285
"pallet-fast-unstake/runtime-benchmarks",
283286
"pallet-glutton/runtime-benchmarks",
284287
"pallet-grandpa/runtime-benchmarks",
@@ -353,6 +356,7 @@ try-runtime = [
353356
"pallet-democracy/try-runtime",
354357
"pallet-election-provider-multi-phase/try-runtime",
355358
"pallet-elections-phragmen/try-runtime",
359+
"pallet-example-tasks/try-runtime",
356360
"pallet-fast-unstake/try-runtime",
357361
"pallet-glutton/try-runtime",
358362
"pallet-grandpa/try-runtime",

substrate/bin/node/runtime/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,11 @@ impl frame_system::Config for Runtime {
304304

305305
impl pallet_insecure_randomness_collective_flip::Config for Runtime {}
306306

307+
impl pallet_example_tasks::Config for Runtime {
308+
type RuntimeTask = RuntimeTask;
309+
type WeightInfo = pallet_example_tasks::weights::SubstrateWeight<Runtime>;
310+
}
311+
307312
impl pallet_utility::Config for Runtime {
308313
type RuntimeEvent = RuntimeEvent;
309314
type RuntimeCall = RuntimeCall;
@@ -2135,6 +2140,7 @@ construct_runtime!(
21352140
SafeMode: pallet_safe_mode,
21362141
Statement: pallet_statement,
21372142
Broker: pallet_broker,
2143+
TasksExample: pallet_example_tasks,
21382144
Mixnet: pallet_mixnet,
21392145
SkipFeelessPayment: pallet_skip_feeless_payment,
21402146
}
@@ -2227,6 +2233,7 @@ mod benches {
22272233
[pallet_conviction_voting, ConvictionVoting]
22282234
[pallet_contracts, Contracts]
22292235
[pallet_core_fellowship, CoreFellowship]
2236+
[tasks_example, TasksExample]
22302237
[pallet_democracy, Democracy]
22312238
[pallet_asset_conversion, AssetConversion]
22322239
[pallet_election_provider_multi_phase, ElectionProviderMultiPhase]

substrate/frame/examples/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pallet-example-frame-crate = { path = "frame-crate", default-features = false }
2020
pallet-example-kitchensink = { path = "kitchensink", default-features = false }
2121
pallet-example-offchain-worker = { path = "offchain-worker", default-features = false }
2222
pallet-example-split = { path = "split", default-features = false }
23+
pallet-example-tasks = { path = "tasks", default-features = false }
2324

2425
[features]
2526
default = ["std"]
@@ -31,6 +32,7 @@ std = [
3132
"pallet-example-kitchensink/std",
3233
"pallet-example-offchain-worker/std",
3334
"pallet-example-split/std",
35+
"pallet-example-tasks/std",
3436
]
3537
try-runtime = [
3638
"pallet-default-config-example/try-runtime",
@@ -39,4 +41,5 @@ try-runtime = [
3941
"pallet-example-kitchensink/try-runtime",
4042
"pallet-example-offchain-worker/try-runtime",
4143
"pallet-example-split/try-runtime",
44+
"pallet-example-tasks/try-runtime",
4245
]

substrate/frame/examples/default-config/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ pub mod pallet {
4747
#[pallet::no_default] // optional. `RuntimeEvent` is automatically excluded as well.
4848
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
4949

50+
/// The overarching task type.
51+
#[pallet::no_default]
52+
type RuntimeTask: Task;
53+
5054
/// An input parameter to this pallet. This value can have a default, because it is not
5155
/// reliant on `frame_system::Config` or the overarching runtime in any way.
5256
type WithDefaultValue: Get<u32>;
@@ -193,6 +197,7 @@ pub mod tests {
193197
impl pallet_default_config_example::Config for Runtime {
194198
// These two both cannot have defaults.
195199
type RuntimeEvent = RuntimeEvent;
200+
type RuntimeTask = RuntimeTask;
196201

197202
type HasNoDefault = frame_support::traits::ConstU32<1>;
198203
type CannotHaveDefault = SomeCall;

substrate/frame/examples/kitchensink/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ license = "MIT-0"
77
homepage = "https://substrate.io"
88
repository.workspace = true
99
description = "FRAME example kitchensink pallet"
10+
publish = false
1011

1112
[package.metadata.docs.rs]
1213
targets = ["x86_64-unknown-linux-gnu"]

substrate/frame/examples/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,6 @@
4343
//! - [`pallet_example_frame_crate`]: Example pallet showcasing how one can be
4444
//! built using only the `frame` umbrella crate.
4545
//!
46+
//! - [`pallet_example_tasks`]: This pallet demonstrates the use of `Tasks` to execute service work.
47+
//!
4648
//! **Tip**: Use `cargo doc --package <pallet-name> --open` to view each pallet's documentation.
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
[package]
2+
name = "pallet-example-tasks"
3+
version = "1.0.0-dev"
4+
authors.workspace = true
5+
edition.workspace = true
6+
license.workspace = true
7+
repository.workspace = true
8+
description = "Pallet to demonstrate the usage of Tasks to recongnize and execute service work"
9+
10+
[package.metadata.docs.rs]
11+
targets = ["x86_64-unknown-linux-gnu"]
12+
13+
[dependencies]
14+
codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false }
15+
log = { version = "0.4.17", default-features = false }
16+
scale-info = { version = "2.10.0", default-features = false, features = ["derive"] }
17+
18+
frame-support = { path = "../../support", default-features = false }
19+
frame-system = { path = "../../system", default-features = false }
20+
21+
sp-io = { path = "../../../primitives/io", default-features = false }
22+
sp-runtime = { path = "../../../primitives/runtime", default-features = false }
23+
sp-std = { path = "../../../primitives/std", default-features = false }
24+
sp-core = { version = "21.0.0", default-features = false, path = "../../../primitives/core" }
25+
26+
frame-benchmarking = { path = "../../benchmarking", default-features = false, optional = true }
27+
28+
[features]
29+
default = ["std"]
30+
std = [
31+
"codec/std",
32+
"frame-benchmarking?/std",
33+
"frame-support/std",
34+
"frame-system/std",
35+
"log/std",
36+
"scale-info/std",
37+
"sp-core/std",
38+
"sp-io/std",
39+
"sp-runtime/std",
40+
"sp-std/std",
41+
]
42+
runtime-benchmarks = [
43+
"frame-benchmarking/runtime-benchmarks",
44+
"frame-support/runtime-benchmarks",
45+
"frame-system/runtime-benchmarks",
46+
"sp-runtime/runtime-benchmarks",
47+
]
48+
try-runtime = [
49+
"frame-support/try-runtime",
50+
"frame-system/try-runtime",
51+
"sp-runtime/try-runtime",
52+
]
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// This file is part of Substrate.
2+
3+
// Copyright (C) Parity Technologies (UK) Ltd.
4+
// SPDX-License-Identifier: Apache-2.0
5+
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
18+
//! Benchmarking for `pallet-example-tasks`.
19+
20+
#![cfg(feature = "runtime-benchmarks")]
21+
22+
use crate::*;
23+
use frame_benchmarking::v2::*;
24+
25+
#[benchmarks]
26+
mod benchmarks {
27+
use super::*;
28+
29+
#[benchmark]
30+
fn add_number_into_total() {
31+
Numbers::<T>::insert(0, 1);
32+
33+
#[block]
34+
{
35+
Task::<T>::add_number_into_total(0).unwrap();
36+
}
37+
38+
assert_eq!(Numbers::<T>::get(0), None);
39+
}
40+
41+
impl_benchmark_test_suite!(Pallet, crate::tests::new_test_ext(), crate::mock::Runtime);
42+
}

0 commit comments

Comments
 (0)