Tasks: general system for recognizing and executing service work (#1343)

`polkadot-sdk` version of original tasks PR located here:
https://github.com/paritytech/substrate/pull/14329

Fixes #206

## Status
- [x] Generic `Task` trait
- [x] `RuntimeTask` aggregated enum, compatible with
`construct_runtime!`
- [x] Casting between `Task` and `RuntimeTask` without needing `dyn` or
`Box`
- [x] Tasks Example pallet
- [x] Runtime tests for Tasks example pallet
- [x] Parsing for task-related macros
- [x] Retrofit parsing to make macros optional
- [x] Expansion for task-related macros
- [x] Adds support for args in tasks
- [x] Retrofit tasks example pallet to use macros instead of manual
syntax
- [x] Weights
- [x] Cleanup
- [x] UI tests
- [x] Docs

## Target Syntax
Adapted from
https://github.com/paritytech/polkadot-sdk/issues/206#issue-1865172283

```rust
// NOTE: this enum is optional and is auto-generated by the other macros if not present
#[pallet::task]
pub enum Task<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 <17176722+gupnik@users.noreply.github.com>
Co-authored-by: kianenigma <kian@parity.io>
Co-authored-by: Nikhil Gupta <>
Co-authored-by: Gavin Wood <gavin@parity.io>
Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Co-authored-by: gupnik <nikhilgupta.iitk@gmail.com>
This commit is contained in:
Sam Johnson
2023-12-08 00:40:26 -05:00
committed by GitHub
parent 34c991e2cf
commit ac3f14d23b
75 changed files with 3516 additions and 24 deletions
+40
View File
@@ -241,6 +241,8 @@ pub mod pallet {
type RuntimeCall = ();
#[inject_runtime_type]
type PalletInfo = ();
#[inject_runtime_type]
type RuntimeTask = ();
type BaseCallFilter = frame_support::traits::Everything;
type BlockHashCount = frame_support::traits::ConstU64<10>;
type OnSetCode = ();
@@ -323,6 +325,8 @@ pub mod pallet {
/// Converts a module to the index of the module, injected by `construct_runtime!`.
#[inject_runtime_type]
type RuntimeTask = ();
#[inject_runtime_type]
type PalletInfo = ();
/// The basic call filter to use in dispatchable. Supports everything as the default.
@@ -400,6 +404,10 @@ pub mod pallet {
+ Debug
+ From<Call<Self>>;
/// The aggregated `RuntimeTask` type.
#[pallet::no_default_bounds]
type RuntimeTask: Task;
/// This stores the number of previous transactions associated with a sender account.
type Nonce: Parameter
+ Member
@@ -628,6 +636,28 @@ pub mod pallet {
Self::deposit_event(Event::Remarked { sender: who, hash });
Ok(().into())
}
#[pallet::call_index(8)]
#[pallet::weight(task.weight())]
pub fn do_task(origin: OriginFor<T>, task: T::RuntimeTask) -> DispatchResultWithPostInfo {
ensure_signed(origin)?;
if !task.is_valid() {
return Err(Error::<T>::InvalidTask.into())
}
Self::deposit_event(Event::TaskStarted { task: task.clone() });
if let Err(err) = task.run() {
Self::deposit_event(Event::TaskFailed { task, err });
return Err(Error::<T>::FailedTask.into())
}
// Emit a success event, if your design includes events for this pallet.
Self::deposit_event(Event::TaskCompleted { task });
// Return success.
Ok(().into())
}
}
/// Event for the System pallet.
@@ -645,6 +675,12 @@ pub mod pallet {
KilledAccount { account: T::AccountId },
/// On on-chain remark happened.
Remarked { sender: T::AccountId, hash: T::Hash },
/// A [`Task`] has started executing
TaskStarted { task: T::RuntimeTask },
/// A [`Task`] has finished executing.
TaskCompleted { task: T::RuntimeTask },
/// A [`Task`] failed during execution.
TaskFailed { task: T::RuntimeTask, err: DispatchError },
}
/// Error for the System pallet
@@ -666,6 +702,10 @@ pub mod pallet {
NonZeroRefCount,
/// The origin filter prevent the call to be dispatched.
CallFiltered,
/// The specified [`Task`] is not valid.
InvalidTask,
/// The specified [`Task`] failed during execution.
FailedTask,
}
/// Exposed trait-generic origin type.