mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-29 04:27:57 +00:00
Adds ability to trigger tasks via unsigned transactions (#4075)
This PR updates the `validate_unsigned` hook for `frame_system` to allow valid tasks to be submitted as unsigned transactions. It also updates the task example to be able to submit such transactions via an off-chain worker. --------- Co-authored-by: Bastian Köcher <git@kchr.de>
This commit is contained in:
@@ -19,6 +19,9 @@
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use frame_support::dispatch::DispatchResult;
|
||||
use frame_system::offchain::SendTransactionTypes;
|
||||
#[cfg(feature = "experimental")]
|
||||
use frame_system::offchain::SubmitTransaction;
|
||||
// Re-export pallet items so that they can be accessed from the crate namespace.
|
||||
pub use pallet::*;
|
||||
|
||||
@@ -31,10 +34,14 @@ mod benchmarking;
|
||||
pub mod weights;
|
||||
pub use weights::*;
|
||||
|
||||
#[cfg(feature = "experimental")]
|
||||
const LOG_TARGET: &str = "pallet-example-tasks";
|
||||
|
||||
#[frame_support::pallet(dev_mode)]
|
||||
pub mod pallet {
|
||||
use super::*;
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
|
||||
#[pallet::error]
|
||||
pub enum Error<T> {
|
||||
@@ -59,9 +66,36 @@ pub mod pallet {
|
||||
}
|
||||
}
|
||||
|
||||
#[pallet::hooks]
|
||||
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
|
||||
#[cfg(feature = "experimental")]
|
||||
fn offchain_worker(_block_number: BlockNumberFor<T>) {
|
||||
if let Some(key) = Numbers::<T>::iter_keys().next() {
|
||||
// Create a valid task
|
||||
let task = Task::<T>::AddNumberIntoTotal { i: key };
|
||||
let runtime_task = <T as Config>::RuntimeTask::from(task);
|
||||
let call = frame_system::Call::<T>::do_task { task: runtime_task.into() };
|
||||
|
||||
// Submit the task as an unsigned transaction
|
||||
let res =
|
||||
SubmitTransaction::<T, frame_system::Call<T>>::submit_unsigned_transaction(
|
||||
call.into(),
|
||||
);
|
||||
match res {
|
||||
Ok(_) => log::info!(target: LOG_TARGET, "Submitted the task."),
|
||||
Err(e) => log::error!(target: LOG_TARGET, "Error submitting task: {:?}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {
|
||||
type RuntimeTask: frame_support::traits::Task;
|
||||
pub trait Config:
|
||||
SendTransactionTypes<frame_system::Call<Self>> + frame_system::Config
|
||||
{
|
||||
type RuntimeTask: frame_support::traits::Task
|
||||
+ IsType<<Self as frame_system::Config>::RuntimeTask>
|
||||
+ From<Task<Self>>;
|
||||
type WeightInfo: WeightInfo;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
use crate::{self as tasks_example};
|
||||
use frame_support::derive_impl;
|
||||
use sp_runtime::testing::TestXt;
|
||||
|
||||
pub type AccountId = u32;
|
||||
pub type Balance = u32;
|
||||
@@ -32,12 +33,32 @@ frame_support::construct_runtime!(
|
||||
}
|
||||
);
|
||||
|
||||
pub type Extrinsic = TestXt<RuntimeCall, ()>;
|
||||
|
||||
#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
|
||||
impl frame_system::Config for Runtime {
|
||||
type Block = Block;
|
||||
}
|
||||
|
||||
impl<LocalCall> frame_system::offchain::SendTransactionTypes<LocalCall> for Runtime
|
||||
where
|
||||
RuntimeCall: From<LocalCall>,
|
||||
{
|
||||
type OverarchingCall = RuntimeCall;
|
||||
type Extrinsic = Extrinsic;
|
||||
}
|
||||
|
||||
impl tasks_example::Config for Runtime {
|
||||
type RuntimeTask = RuntimeTask;
|
||||
type WeightInfo = ();
|
||||
}
|
||||
|
||||
pub fn advance_to(b: u64) {
|
||||
#[cfg(feature = "experimental")]
|
||||
use frame_support::traits::Hooks;
|
||||
while System::block_number() < b {
|
||||
System::set_block_number(System::block_number() + 1);
|
||||
#[cfg(feature = "experimental")]
|
||||
TasksExample::offchain_worker(System::block_number());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,11 @@
|
||||
#![cfg(test)]
|
||||
|
||||
use crate::{mock::*, Numbers};
|
||||
#[cfg(feature = "experimental")]
|
||||
use codec::Decode;
|
||||
use frame_support::traits::Task;
|
||||
#[cfg(feature = "experimental")]
|
||||
use sp_core::offchain::{testing, OffchainWorkerExt, TransactionPoolExt};
|
||||
use sp_runtime::BuildStorage;
|
||||
|
||||
#[cfg(feature = "experimental")]
|
||||
@@ -130,3 +134,29 @@ fn task_execution_fails_for_invalid_task() {
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(feature = "experimental")]
|
||||
#[test]
|
||||
fn task_with_offchain_worker() {
|
||||
let (offchain, _offchain_state) = testing::TestOffchainExt::new();
|
||||
let (pool, pool_state) = testing::TestTransactionPoolExt::new();
|
||||
|
||||
let mut t = sp_io::TestExternalities::default();
|
||||
t.register_extension(OffchainWorkerExt::new(offchain));
|
||||
t.register_extension(TransactionPoolExt::new(pool));
|
||||
|
||||
t.execute_with(|| {
|
||||
advance_to(1);
|
||||
assert!(pool_state.read().transactions.is_empty());
|
||||
|
||||
Numbers::<Runtime>::insert(0, 10);
|
||||
assert_eq!(crate::Total::<Runtime>::get(), (0, 0));
|
||||
|
||||
advance_to(2);
|
||||
|
||||
let tx = pool_state.write().transactions.pop().unwrap();
|
||||
assert!(pool_state.read().transactions.is_empty());
|
||||
let tx = Extrinsic::decode(&mut &*tx).unwrap();
|
||||
assert_eq!(tx.signature, None);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user