mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 01:11:10 +00:00
Migrate examples to use pallet macro (#8138)
This commit is contained in:
committed by
GitHub
parent
1b2dd6117b
commit
ecf4404903
@@ -18,7 +18,7 @@
|
||||
//! Autogenerated weights for pallet_balances
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.0
|
||||
//! DATE: 2021-01-06, STEPS: [50, ], REPEAT: 20, LOW RANGE: [], HIGH RANGE: []
|
||||
//! DATE: 2021-01-06, STEPS: \[50, \], REPEAT: 20, LOW RANGE: [], HIGH RANGE: []
|
||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128
|
||||
|
||||
// Executed Command:
|
||||
|
||||
@@ -930,7 +930,7 @@ macro_rules! impl_benchmark_test {
|
||||
|
||||
/// This creates a test suite which runs the module's benchmarks.
|
||||
///
|
||||
/// When called in [`pallet_example`] as
|
||||
/// When called in `pallet_example` as
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// impl_benchmark_test_suite!(Module, crate::tests::new_test_ext(), crate::tests::Test);
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
//! <!-- markdown-link-check-disable -->
|
||||
//! # Offchain Worker Example Module
|
||||
//! # Offchain Worker Example Pallet
|
||||
//!
|
||||
//! The Offchain Worker Example: A simple pallet demonstrating
|
||||
//! concepts, APIs and structures common to most offchain workers.
|
||||
@@ -24,9 +24,9 @@
|
||||
//! Run `cargo doc --package pallet-example-offchain-worker --open` to view this module's
|
||||
//! documentation.
|
||||
//!
|
||||
//! - [`pallet_example_offchain_worker::Config`](./trait.Config.html)
|
||||
//! - [`Call`](./enum.Call.html)
|
||||
//! - [`Module`](./struct.Module.html)
|
||||
//! - [`Config`]
|
||||
//! - [`Call`]
|
||||
//! - [`Pallet`]
|
||||
//!
|
||||
//!
|
||||
//! ## Overview
|
||||
@@ -44,27 +44,18 @@
|
||||
|
||||
use frame_system::{
|
||||
self as system,
|
||||
ensure_signed,
|
||||
ensure_none,
|
||||
offchain::{
|
||||
AppCrypto, CreateSignedTransaction, SendUnsignedTransaction, SendSignedTransaction,
|
||||
SignedPayload, SigningTypes, Signer, SubmitTransaction,
|
||||
}
|
||||
};
|
||||
use frame_support::{
|
||||
debug,
|
||||
dispatch::DispatchResult, decl_module, decl_storage, decl_event,
|
||||
traits::Get,
|
||||
};
|
||||
use frame_support::{debug, traits::Get};
|
||||
use sp_core::crypto::KeyTypeId;
|
||||
use sp_runtime::{
|
||||
RuntimeDebug,
|
||||
offchain::{http, Duration, storage::StorageValueRef},
|
||||
traits::Zero,
|
||||
transaction_validity::{
|
||||
InvalidTransaction, ValidTransaction, TransactionValidity, TransactionSource,
|
||||
TransactionPriority,
|
||||
},
|
||||
transaction_validity::{InvalidTransaction, ValidTransaction, TransactionValidity},
|
||||
};
|
||||
use codec::{Encode, Decode};
|
||||
use sp_std::vec::Vec;
|
||||
@@ -102,154 +93,59 @@ pub mod crypto {
|
||||
}
|
||||
}
|
||||
|
||||
/// This pallet's configuration trait
|
||||
pub trait Config: CreateSignedTransaction<Call<Self>> {
|
||||
/// The identifier type for an offchain worker.
|
||||
type AuthorityId: AppCrypto<Self::Public, Self::Signature>;
|
||||
pub use pallet::*;
|
||||
|
||||
/// The overarching event type.
|
||||
type Event: From<Event<Self>> + Into<<Self as frame_system::Config>::Event>;
|
||||
/// The overarching dispatch call type.
|
||||
type Call: From<Call<Self>>;
|
||||
#[frame_support::pallet]
|
||||
pub mod pallet {
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
use super::*;
|
||||
|
||||
// Configuration parameters
|
||||
/// This pallet's configuration trait
|
||||
#[pallet::config]
|
||||
pub trait Config: CreateSignedTransaction<Call<Self>> + frame_system::Config {
|
||||
/// The identifier type for an offchain worker.
|
||||
type AuthorityId: AppCrypto<Self::Public, Self::Signature>;
|
||||
|
||||
/// A grace period after we send transaction.
|
||||
///
|
||||
/// To avoid sending too many transactions, we only attempt to send one
|
||||
/// every `GRACE_PERIOD` blocks. We use Local Storage to coordinate
|
||||
/// sending between distinct runs of this offchain worker.
|
||||
type GracePeriod: Get<Self::BlockNumber>;
|
||||
/// The overarching event type.
|
||||
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
|
||||
|
||||
/// Number of blocks of cooldown after unsigned transaction is included.
|
||||
///
|
||||
/// This ensures that we only accept unsigned transactions once, every `UnsignedInterval` blocks.
|
||||
type UnsignedInterval: Get<Self::BlockNumber>;
|
||||
/// The overarching dispatch call type.
|
||||
type Call: From<Call<Self>>;
|
||||
|
||||
/// A configuration for base priority of unsigned transactions.
|
||||
///
|
||||
/// This is exposed so that it can be tuned for particular runtime, when
|
||||
/// multiple pallets send unsigned transactions.
|
||||
type UnsignedPriority: Get<TransactionPriority>;
|
||||
}
|
||||
// Configuration parameters
|
||||
|
||||
/// Payload used by this example crate to hold price
|
||||
/// data required to submit a transaction.
|
||||
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]
|
||||
pub struct PricePayload<Public, BlockNumber> {
|
||||
block_number: BlockNumber,
|
||||
price: u32,
|
||||
public: Public,
|
||||
}
|
||||
/// A grace period after we send transaction.
|
||||
///
|
||||
/// To avoid sending too many transactions, we only attempt to send one
|
||||
/// every `GRACE_PERIOD` blocks. We use Local Storage to coordinate
|
||||
/// sending between distinct runs of this offchain worker.
|
||||
#[pallet::constant]
|
||||
type GracePeriod: Get<Self::BlockNumber>;
|
||||
|
||||
impl<T: SigningTypes> SignedPayload<T> for PricePayload<T::Public, T::BlockNumber> {
|
||||
fn public(&self) -> T::Public {
|
||||
self.public.clone()
|
||||
/// Number of blocks of cooldown after unsigned transaction is included.
|
||||
///
|
||||
/// This ensures that we only accept unsigned transactions once, every `UnsignedInterval` blocks.
|
||||
#[pallet::constant]
|
||||
type UnsignedInterval: Get<Self::BlockNumber>;
|
||||
|
||||
/// A configuration for base priority of unsigned transactions.
|
||||
///
|
||||
/// This is exposed so that it can be tuned for particular runtime, when
|
||||
/// multiple pallets send unsigned transactions.
|
||||
#[pallet::constant]
|
||||
type UnsignedPriority: Get<TransactionPriority>;
|
||||
}
|
||||
}
|
||||
|
||||
decl_storage! {
|
||||
trait Store for Module<T: Config> as ExampleOffchainWorker {
|
||||
/// A vector of recently submitted prices.
|
||||
///
|
||||
/// This is used to calculate average price, should have bounded size.
|
||||
Prices get(fn prices): Vec<u32>;
|
||||
/// Defines the block when next unsigned transaction will be accepted.
|
||||
///
|
||||
/// To prevent spam of unsigned (and unpayed!) transactions on the network,
|
||||
/// we only allow one transaction every `T::UnsignedInterval` blocks.
|
||||
/// This storage entry defines when new transaction is going to be accepted.
|
||||
NextUnsignedAt get(fn next_unsigned_at): T::BlockNumber;
|
||||
}
|
||||
}
|
||||
|
||||
decl_event!(
|
||||
/// Events generated by the module.
|
||||
pub enum Event<T> where AccountId = <T as frame_system::Config>::AccountId {
|
||||
/// Event generated when new price is accepted to contribute to the average.
|
||||
/// \[price, who\]
|
||||
NewPrice(u32, AccountId),
|
||||
}
|
||||
);
|
||||
|
||||
decl_module! {
|
||||
/// A public part of the pallet.
|
||||
pub struct Module<T: Config> for enum Call where origin: T::Origin {
|
||||
fn deposit_event() = default;
|
||||
|
||||
/// Submit new price to the list.
|
||||
///
|
||||
/// This method is a public function of the module and can be called from within
|
||||
/// a transaction. It appends given `price` to current list of prices.
|
||||
/// In our example the `offchain worker` will create, sign & submit a transaction that
|
||||
/// calls this function passing the price.
|
||||
///
|
||||
/// The transaction needs to be signed (see `ensure_signed`) check, so that the caller
|
||||
/// pays a fee to execute it.
|
||||
/// This makes sure that it's not easy (or rather cheap) to attack the chain by submitting
|
||||
/// excesive transactions, but note that it doesn't ensure the price oracle is actually
|
||||
/// working and receives (and provides) meaningful data.
|
||||
/// This example is not focused on correctness of the oracle itself, but rather its
|
||||
/// purpose is to showcase offchain worker capabilities.
|
||||
#[weight = 0]
|
||||
pub fn submit_price(origin, price: u32) -> DispatchResult {
|
||||
// Retrieve sender of the transaction.
|
||||
let who = ensure_signed(origin)?;
|
||||
// Add the price to the on-chain list.
|
||||
Self::add_price(who, price);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Submit new price to the list via unsigned transaction.
|
||||
///
|
||||
/// Works exactly like the `submit_price` function, but since we allow sending the
|
||||
/// transaction without a signature, and hence without paying any fees,
|
||||
/// we need a way to make sure that only some transactions are accepted.
|
||||
/// This function can be called only once every `T::UnsignedInterval` blocks.
|
||||
/// Transactions that call that function are de-duplicated on the pool level
|
||||
/// via `validate_unsigned` implementation and also are rendered invalid if
|
||||
/// the function has already been called in current "session".
|
||||
///
|
||||
/// It's important to specify `weight` for unsigned calls as well, because even though
|
||||
/// they don't charge fees, we still don't want a single block to contain unlimited
|
||||
/// number of such transactions.
|
||||
///
|
||||
/// This example is not focused on correctness of the oracle itself, but rather its
|
||||
/// purpose is to showcase offchain worker capabilities.
|
||||
#[weight = 0]
|
||||
pub fn submit_price_unsigned(origin, _block_number: T::BlockNumber, price: u32)
|
||||
-> DispatchResult
|
||||
{
|
||||
// This ensures that the function can only be called via unsigned transaction.
|
||||
ensure_none(origin)?;
|
||||
// Add the price to the on-chain list, but mark it as coming from an empty address.
|
||||
Self::add_price(Default::default(), price);
|
||||
// now increment the block number at which we expect next unsigned transaction.
|
||||
let current_block = <system::Module<T>>::block_number();
|
||||
<NextUnsignedAt<T>>::put(current_block + T::UnsignedInterval::get());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[weight = 0]
|
||||
pub fn submit_price_unsigned_with_signed_payload(
|
||||
origin,
|
||||
price_payload: PricePayload<T::Public, T::BlockNumber>,
|
||||
_signature: T::Signature,
|
||||
) -> DispatchResult {
|
||||
// This ensures that the function can only be called via unsigned transaction.
|
||||
ensure_none(origin)?;
|
||||
// Add the price to the on-chain list, but mark it as coming from an empty address.
|
||||
Self::add_price(Default::default(), price_payload.price);
|
||||
// now increment the block number at which we expect next unsigned transaction.
|
||||
let current_block = <system::Module<T>>::block_number();
|
||||
<NextUnsignedAt<T>>::put(current_block + T::UnsignedInterval::get());
|
||||
Ok(())
|
||||
}
|
||||
#[pallet::pallet]
|
||||
#[pallet::generate_store(pub(super) trait Store)]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
#[pallet::hooks]
|
||||
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
|
||||
/// Offchain Worker entry point.
|
||||
///
|
||||
/// By implementing `fn offchain_worker` within `decl_module!` you declare a new offchain
|
||||
/// worker.
|
||||
/// By implementing `fn offchain_worker` you declare a new offchain worker.
|
||||
/// This function will be called when the node is fully synced and a new best block is
|
||||
/// succesfuly imported.
|
||||
/// Note that it's not guaranteed for offchain workers to run on EVERY block, there might
|
||||
@@ -270,7 +166,7 @@ decl_module! {
|
||||
// to the storage and other included pallets.
|
||||
//
|
||||
// We can easily import `frame_system` and retrieve a block hash of the parent block.
|
||||
let parent_hash = <system::Module<T>>::block_hash(block_number - 1u32.into());
|
||||
let parent_hash = <system::Pallet<T>>::block_hash(block_number - 1u32.into());
|
||||
debug::debug!("Current block: {:?} (parent hash: {:?})", block_number, parent_hash);
|
||||
|
||||
// It's a good practice to keep `fn offchain_worker()` function minimal, and move most
|
||||
@@ -296,6 +192,151 @@ decl_module! {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A public part of the pallet.
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// Submit new price to the list.
|
||||
///
|
||||
/// This method is a public function of the module and can be called from within
|
||||
/// a transaction. It appends given `price` to current list of prices.
|
||||
/// In our example the `offchain worker` will create, sign & submit a transaction that
|
||||
/// calls this function passing the price.
|
||||
///
|
||||
/// The transaction needs to be signed (see `ensure_signed`) check, so that the caller
|
||||
/// pays a fee to execute it.
|
||||
/// This makes sure that it's not easy (or rather cheap) to attack the chain by submitting
|
||||
/// excesive transactions, but note that it doesn't ensure the price oracle is actually
|
||||
/// working and receives (and provides) meaningful data.
|
||||
/// This example is not focused on correctness of the oracle itself, but rather its
|
||||
/// purpose is to showcase offchain worker capabilities.
|
||||
#[pallet::weight(0)]
|
||||
pub fn submit_price(origin: OriginFor<T>, price: u32) -> DispatchResultWithPostInfo {
|
||||
// Retrieve sender of the transaction.
|
||||
let who = ensure_signed(origin)?;
|
||||
// Add the price to the on-chain list.
|
||||
Self::add_price(who, price);
|
||||
Ok(().into())
|
||||
}
|
||||
|
||||
/// Submit new price to the list via unsigned transaction.
|
||||
///
|
||||
/// Works exactly like the `submit_price` function, but since we allow sending the
|
||||
/// transaction without a signature, and hence without paying any fees,
|
||||
/// we need a way to make sure that only some transactions are accepted.
|
||||
/// This function can be called only once every `T::UnsignedInterval` blocks.
|
||||
/// Transactions that call that function are de-duplicated on the pool level
|
||||
/// via `validate_unsigned` implementation and also are rendered invalid if
|
||||
/// the function has already been called in current "session".
|
||||
///
|
||||
/// It's important to specify `weight` for unsigned calls as well, because even though
|
||||
/// they don't charge fees, we still don't want a single block to contain unlimited
|
||||
/// number of such transactions.
|
||||
///
|
||||
/// This example is not focused on correctness of the oracle itself, but rather its
|
||||
/// purpose is to showcase offchain worker capabilities.
|
||||
#[pallet::weight(0)]
|
||||
pub fn submit_price_unsigned(
|
||||
origin: OriginFor<T>,
|
||||
_block_number: T::BlockNumber,
|
||||
price: u32
|
||||
) -> DispatchResultWithPostInfo {
|
||||
// This ensures that the function can only be called via unsigned transaction.
|
||||
ensure_none(origin)?;
|
||||
// Add the price to the on-chain list, but mark it as coming from an empty address.
|
||||
Self::add_price(Default::default(), price);
|
||||
// now increment the block number at which we expect next unsigned transaction.
|
||||
let current_block = <system::Pallet<T>>::block_number();
|
||||
<NextUnsignedAt<T>>::put(current_block + T::UnsignedInterval::get());
|
||||
Ok(().into())
|
||||
}
|
||||
|
||||
#[pallet::weight(0)]
|
||||
pub fn submit_price_unsigned_with_signed_payload(
|
||||
origin: OriginFor<T>,
|
||||
price_payload: PricePayload<T::Public, T::BlockNumber>,
|
||||
_signature: T::Signature,
|
||||
) -> DispatchResultWithPostInfo {
|
||||
// This ensures that the function can only be called via unsigned transaction.
|
||||
ensure_none(origin)?;
|
||||
// Add the price to the on-chain list, but mark it as coming from an empty address.
|
||||
Self::add_price(Default::default(), price_payload.price);
|
||||
// now increment the block number at which we expect next unsigned transaction.
|
||||
let current_block = <system::Pallet<T>>::block_number();
|
||||
<NextUnsignedAt<T>>::put(current_block + T::UnsignedInterval::get());
|
||||
Ok(().into())
|
||||
}
|
||||
}
|
||||
|
||||
/// Events for the pallet.
|
||||
#[pallet::event]
|
||||
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
||||
pub enum Event<T: Config> {
|
||||
/// Event generated when new price is accepted to contribute to the average.
|
||||
/// \[price, who\]
|
||||
NewPrice(u32, T::AccountId),
|
||||
}
|
||||
|
||||
#[pallet::validate_unsigned]
|
||||
impl<T: Config> ValidateUnsigned for Pallet<T> {
|
||||
type Call = Call<T>;
|
||||
|
||||
/// Validate unsigned call to this module.
|
||||
///
|
||||
/// By default unsigned transactions are disallowed, but implementing the validator
|
||||
/// here we make sure that some particular calls (the ones produced by offchain worker)
|
||||
/// are being whitelisted and marked as valid.
|
||||
fn validate_unsigned(
|
||||
_source: TransactionSource,
|
||||
call: &Self::Call,
|
||||
) -> TransactionValidity {
|
||||
// Firstly let's check that we call the right function.
|
||||
if let Call::submit_price_unsigned_with_signed_payload(
|
||||
ref payload, ref signature
|
||||
) = call {
|
||||
let signature_valid = SignedPayload::<T>::verify::<T::AuthorityId>(payload, signature.clone());
|
||||
if !signature_valid {
|
||||
return InvalidTransaction::BadProof.into();
|
||||
}
|
||||
Self::validate_transaction_parameters(&payload.block_number, &payload.price)
|
||||
} else if let Call::submit_price_unsigned(block_number, new_price) = call {
|
||||
Self::validate_transaction_parameters(block_number, new_price)
|
||||
} else {
|
||||
InvalidTransaction::Call.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A vector of recently submitted prices.
|
||||
///
|
||||
/// This is used to calculate average price, should have bounded size.
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn prices)]
|
||||
pub(super) type Prices<T: Config> = StorageValue<_, Vec<u32>, ValueQuery>;
|
||||
|
||||
/// Defines the block when next unsigned transaction will be accepted.
|
||||
///
|
||||
/// To prevent spam of unsigned (and unpayed!) transactions on the network,
|
||||
/// we only allow one transaction every `T::UnsignedInterval` blocks.
|
||||
/// This storage entry defines when new transaction is going to be accepted.
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn next_unsigned_at)]
|
||||
pub(super) type NextUnsignedAt<T: Config> = StorageValue<_, T::BlockNumber, ValueQuery>;
|
||||
}
|
||||
|
||||
/// Payload used by this example crate to hold price
|
||||
/// data required to submit a transaction.
|
||||
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]
|
||||
pub struct PricePayload<Public, BlockNumber> {
|
||||
block_number: BlockNumber,
|
||||
price: u32,
|
||||
public: Public,
|
||||
}
|
||||
|
||||
impl<T: SigningTypes> SignedPayload<T> for PricePayload<T::Public, T::BlockNumber> {
|
||||
fn public(&self) -> T::Public {
|
||||
self.public.clone()
|
||||
}
|
||||
}
|
||||
|
||||
enum TransactionType {
|
||||
@@ -306,11 +347,7 @@ enum TransactionType {
|
||||
None,
|
||||
}
|
||||
|
||||
/// Most of the functions are moved outside of the `decl_module!` macro.
|
||||
///
|
||||
/// This greatly helps with error messages, as the ones inside the macro
|
||||
/// can sometimes be hard to debug.
|
||||
impl<T: Config> Module<T> {
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// Chooses which transaction type to send.
|
||||
///
|
||||
/// This function serves mostly to showcase `StorageValue` helper
|
||||
@@ -598,7 +635,7 @@ impl<T: Config> Module<T> {
|
||||
/// Add new price to the list.
|
||||
fn add_price(who: T::AccountId, price: u32) {
|
||||
debug::info!("Adding to the average: {}", price);
|
||||
Prices::mutate(|prices| {
|
||||
<Prices<T>>::mutate(|prices| {
|
||||
const MAX_LEN: usize = 64;
|
||||
|
||||
if prices.len() < MAX_LEN {
|
||||
@@ -612,12 +649,12 @@ impl<T: Config> Module<T> {
|
||||
.expect("The average is not empty, because it was just mutated; qed");
|
||||
debug::info!("Current average price is: {}", average);
|
||||
// here we are raising the NewPrice event
|
||||
Self::deposit_event(RawEvent::NewPrice(price, who));
|
||||
Self::deposit_event(Event::NewPrice(price, who));
|
||||
}
|
||||
|
||||
/// Calculate current average price.
|
||||
fn average_price() -> Option<u32> {
|
||||
let prices = Prices::get();
|
||||
let prices = <Prices<T>>::get();
|
||||
if prices.is_empty() {
|
||||
None
|
||||
} else {
|
||||
@@ -635,7 +672,7 @@ impl<T: Config> Module<T> {
|
||||
return InvalidTransaction::Stale.into();
|
||||
}
|
||||
// Let's make sure to reject transactions from the future.
|
||||
let current_block = <system::Module<T>>::block_number();
|
||||
let current_block = <system::Pallet<T>>::block_number();
|
||||
if ¤t_block < block_number {
|
||||
return InvalidTransaction::Future.into();
|
||||
}
|
||||
@@ -677,33 +714,3 @@ impl<T: Config> Module<T> {
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)] // ValidateUnsigned
|
||||
impl<T: Config> frame_support::unsigned::ValidateUnsigned for Module<T> {
|
||||
type Call = Call<T>;
|
||||
|
||||
/// Validate unsigned call to this module.
|
||||
///
|
||||
/// By default unsigned transactions are disallowed, but implementing the validator
|
||||
/// here we make sure that some particular calls (the ones produced by offchain worker)
|
||||
/// are being whitelisted and marked as valid.
|
||||
fn validate_unsigned(
|
||||
_source: TransactionSource,
|
||||
call: &Self::Call,
|
||||
) -> TransactionValidity {
|
||||
// Firstly let's check that we call the right function.
|
||||
if let Call::submit_price_unsigned_with_signed_payload(
|
||||
ref payload, ref signature
|
||||
) = call {
|
||||
let signature_valid = SignedPayload::<T>::verify::<T::AuthorityId>(payload, signature.clone());
|
||||
if !signature_valid {
|
||||
return InvalidTransaction::BadProof.into();
|
||||
}
|
||||
Self::validate_transaction_parameters(&payload.block_number, &payload.price)
|
||||
} else if let Call::submit_price_unsigned(block_number, new_price) = call {
|
||||
Self::validate_transaction_parameters(block_number, new_price)
|
||||
} else {
|
||||
InvalidTransaction::Call.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,10 +22,6 @@
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use frame_system::ensure_signed;
|
||||
use frame_support::{
|
||||
dispatch::DispatchResult, decl_module, decl_storage, decl_event,
|
||||
};
|
||||
use sp_runtime::RuntimeDebug;
|
||||
|
||||
use codec::{Encode, Decode};
|
||||
@@ -34,34 +30,72 @@ use sp_std::vec::Vec;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub trait Config: frame_system::Config {
|
||||
/// The overarching event type.
|
||||
type Event: From<Event> + Into<<Self as frame_system::Config>::Event>;
|
||||
/// The overarching dispatch call type.
|
||||
type Call: From<Call<Self>>;
|
||||
}
|
||||
pub use pallet::*;
|
||||
|
||||
decl_storage! {
|
||||
trait Store for Module<T: Config> as ExampleOffchainWorker {
|
||||
/// A vector of current participants
|
||||
#[frame_support::pallet]
|
||||
pub mod pallet {
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
use super::*;
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {
|
||||
/// The overarching dispatch call type.
|
||||
type Call: From<Call<Self>>;
|
||||
}
|
||||
|
||||
#[pallet::pallet]
|
||||
#[pallet::generate_store(pub(super) trait Store)]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
#[pallet::hooks]
|
||||
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {}
|
||||
|
||||
/// A public part of the pallet.
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// Get the new event running.
|
||||
#[pallet::weight(0)]
|
||||
pub fn run_event(origin: OriginFor<T>, id: Vec<u8>) -> DispatchResultWithPostInfo {
|
||||
let _ = ensure_signed(origin)?;
|
||||
<Participants<T>>::kill();
|
||||
<CurrentEventId<T>>::mutate(move |event_id| *event_id = id);
|
||||
Ok(().into())
|
||||
}
|
||||
|
||||
/// Submit list of participants to the current event.
|
||||
///
|
||||
/// To enlist someone to participate, signed payload should be
|
||||
/// sent to `enlist`.
|
||||
Participants get(fn participants): Vec<Vec<u8>>;
|
||||
/// The example utilizes parallel execution by checking half of the
|
||||
/// signatures in spawned task.
|
||||
#[pallet::weight(0)]
|
||||
pub fn enlist_participants(origin: OriginFor<T>, participants: Vec<EnlistedParticipant>)
|
||||
-> DispatchResultWithPostInfo
|
||||
{
|
||||
let _ = ensure_signed(origin)?;
|
||||
|
||||
/// Current event id to enlist participants to.
|
||||
CurrentEventId get(fn get_current_event_id): Vec<u8>;
|
||||
if validate_participants_parallel(&<CurrentEventId<T>>::get(), &participants[..]) {
|
||||
for participant in participants {
|
||||
<Participants<T>>::append(participant.account);
|
||||
}
|
||||
}
|
||||
Ok(().into())
|
||||
}
|
||||
}
|
||||
|
||||
/// A vector of current participants
|
||||
///
|
||||
/// To enlist someone to participate, signed payload should be
|
||||
/// sent to `enlist`.
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn participants)]
|
||||
pub(super) type Participants<T: Config> = StorageValue<_, Vec<Vec<u8>>, ValueQuery>;
|
||||
|
||||
/// Current event id to enlist participants to.
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn get_current_event_id)]
|
||||
pub(super) type CurrentEventId<T: Config> = StorageValue<_, Vec<u8>, ValueQuery>;
|
||||
}
|
||||
|
||||
decl_event!(
|
||||
/// Events generated by the module.
|
||||
pub enum Event {
|
||||
/// When new event is drafted.
|
||||
NewEventDrafted(Vec<u8>),
|
||||
}
|
||||
);
|
||||
|
||||
/// Request to enlist participant.
|
||||
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]
|
||||
pub struct EnlistedParticipant {
|
||||
@@ -85,40 +119,6 @@ impl EnlistedParticipant {
|
||||
}
|
||||
}
|
||||
|
||||
decl_module! {
|
||||
/// A public part of the pallet.
|
||||
pub struct Module<T: Config> for enum Call where origin: T::Origin {
|
||||
fn deposit_event() = default;
|
||||
|
||||
/// Get the new event running.
|
||||
#[weight = 0]
|
||||
pub fn run_event(origin, id: Vec<u8>) -> DispatchResult {
|
||||
let _ = ensure_signed(origin)?;
|
||||
Participants::kill();
|
||||
CurrentEventId::mutate(move |event_id| *event_id = id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Submit list of participants to the current event.
|
||||
///
|
||||
/// The example utilizes parallel execution by checking half of the
|
||||
/// signatures in spawned task.
|
||||
#[weight = 0]
|
||||
pub fn enlist_participants(origin, participants: Vec<EnlistedParticipant>)
|
||||
-> DispatchResult
|
||||
{
|
||||
let _ = ensure_signed(origin)?;
|
||||
|
||||
if validate_participants_parallel(&CurrentEventId::get(), &participants[..]) {
|
||||
for participant in participants {
|
||||
Participants::append(participant.account);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_participants_parallel(event_id: &[u8], participants: &[EnlistedParticipant]) -> bool {
|
||||
|
||||
fn spawn_verify(data: Vec<u8>) -> Vec<u8> {
|
||||
|
||||
@@ -34,7 +34,7 @@ frame_support::construct_runtime!(
|
||||
UncheckedExtrinsic = UncheckedExtrinsic,
|
||||
{
|
||||
System: frame_system::{Module, Call, Config, Storage, Event<T>},
|
||||
Example: pallet_example_parallel::{Module, Call, Storage, Event},
|
||||
Example: pallet_example_parallel::{Module, Call, Storage},
|
||||
}
|
||||
);
|
||||
|
||||
@@ -75,7 +75,6 @@ parameter_types! {
|
||||
}
|
||||
|
||||
impl Config for Test {
|
||||
type Event = Event;
|
||||
type Call = Call;
|
||||
}
|
||||
|
||||
|
||||
+190
-147
@@ -63,9 +63,9 @@
|
||||
//! // Include the following links that shows what trait needs to be implemented to use the pallet
|
||||
//! // and the supported dispatchables that are documented in the Call enum.
|
||||
//!
|
||||
//! - \[`<INSERT_CUSTOM_PALLET_NAME>::Config`](./trait.Config.html)
|
||||
//! - \[`Call`](./enum.Call.html)
|
||||
//! - \[`Module`](./struct.Module.html)
|
||||
//! - \[`Config`]
|
||||
//! - \[`Call`]
|
||||
//! - \[`Pallet`]
|
||||
//!
|
||||
//! \## Overview
|
||||
//!
|
||||
@@ -257,11 +257,11 @@
|
||||
|
||||
use sp_std::marker::PhantomData;
|
||||
use frame_support::{
|
||||
dispatch::DispatchResult, decl_module, decl_storage, decl_event, traits::IsSubType,
|
||||
dispatch::DispatchResult, traits::IsSubType,
|
||||
weights::{DispatchClass, ClassifyDispatch, WeighData, Weight, PaysFee, Pays},
|
||||
};
|
||||
use sp_std::prelude::*;
|
||||
use frame_system::{ensure_signed, ensure_root};
|
||||
use frame_system::{ensure_signed};
|
||||
use codec::{Encode, Decode};
|
||||
use sp_runtime::{
|
||||
traits::{
|
||||
@@ -278,7 +278,7 @@ use sp_runtime::{
|
||||
// The `WeightData<T>` trait has access to the arguments of the dispatch that it wants to assign a
|
||||
// weight to. Nonetheless, the trait itself can not make any assumptions about what the generic type
|
||||
// of the arguments (`T`) is. Based on our needs, we could replace `T` with a more concrete type
|
||||
// while implementing the trait. The `decl_module!` expects whatever implements `WeighData<T>` to
|
||||
// while implementing the trait. The `pallet::weight` expects whatever implements `WeighData<T>` to
|
||||
// replace `T` with a tuple of the dispatch arguments. This is exactly how we will craft the
|
||||
// implementation below.
|
||||
//
|
||||
@@ -315,111 +315,97 @@ impl<T: pallet_balances::Config> PaysFee<(&BalanceOf<T>,)> for WeightForSetDummy
|
||||
/// A type alias for the balance type from this pallet's point of view.
|
||||
type BalanceOf<T> = <T as pallet_balances::Config>::Balance;
|
||||
|
||||
/// Our pallet's configuration trait. All our types and constants go in here. If the
|
||||
/// pallet is dependent on specific other pallets, then their configuration traits
|
||||
/// should be added to our implied traits list.
|
||||
///
|
||||
/// `frame_system::Config` should always be included in our implied traits.
|
||||
pub trait Config: pallet_balances::Config {
|
||||
/// The overarching event type.
|
||||
type Event: From<Event<Self>> + Into<<Self as frame_system::Config>::Event>;
|
||||
}
|
||||
// Re-export pallet items so that they can be accessed from the crate namespace.
|
||||
pub use pallet::*;
|
||||
|
||||
decl_storage! {
|
||||
// A macro for the Storage trait, and its implementation, for this pallet.
|
||||
// This allows for type-safe usage of the Substrate storage database, so you can
|
||||
// keep things around between blocks.
|
||||
// Definition of the pallet logic, to be aggregated at runtime definition through
|
||||
// `construct_runtime`.
|
||||
#[frame_support::pallet]
|
||||
pub mod pallet {
|
||||
// Import various types used to declare pallet in scope.
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
use super::*;
|
||||
|
||||
/// Our pallet's configuration trait. All our types and constants go in here. If the
|
||||
/// pallet is dependent on specific other pallets, then their configuration traits
|
||||
/// should be added to our implied traits list.
|
||||
///
|
||||
/// `frame_system::Config` should always be included.
|
||||
#[pallet::config]
|
||||
pub trait Config: pallet_balances::Config + frame_system::Config {
|
||||
/// The overarching event type.
|
||||
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
|
||||
}
|
||||
|
||||
// Simple declaration of the `Pallet` type. It is placeholder we use to implement traits and
|
||||
// method.
|
||||
#[pallet::pallet]
|
||||
#[pallet::generate_store(pub(super) trait Store)]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
// Pallet implements [`Hooks`] trait to define some logic to execute in some context.
|
||||
#[pallet::hooks]
|
||||
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
|
||||
// `on_initialize` is executed at the beginning of the block before any extrinsic are
|
||||
// dispatched.
|
||||
//
|
||||
// This function must return the weight consumed by `on_initialize` and `on_finalize`.
|
||||
fn on_initialize(_n: T::BlockNumber) -> Weight {
|
||||
// Anything that needs to be done at the start of the block.
|
||||
// We don't do anything here.
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
// `on_finalize` is executed at the end of block after all extrinsic are dispatched.
|
||||
fn on_finalize(_n: T::BlockNumber) {
|
||||
// We just kill our dummy storage item.
|
||||
<Dummy<T>>::kill();
|
||||
}
|
||||
|
||||
// A runtime code run after every block and have access to extended set of APIs.
|
||||
//
|
||||
// For instance you can generate extrinsics for the upcoming produced block.
|
||||
fn offchain_worker(_n: T::BlockNumber) {
|
||||
// We don't do anything here.
|
||||
// but we could dispatch extrinsic (transaction/unsigned/inherent) using
|
||||
// sp_io::submit_extrinsic
|
||||
}
|
||||
}
|
||||
|
||||
// The call declaration. This states the entry points that we handle. The
|
||||
// macro takes care of the marshalling of arguments and dispatch.
|
||||
//
|
||||
// It is important to update your storage name so that your pallet's
|
||||
// storage items are isolated from other pallets.
|
||||
// ---------------------------------vvvvvvv
|
||||
trait Store for Module<T: Config> as Example {
|
||||
// Any storage declarations of the form:
|
||||
// `pub? Name get(fn getter_name)? [config()|config(myname)] [build(|_| {...})] : <type> (= <new_default_value>)?;`
|
||||
// where `<type>` is either:
|
||||
// - `Type` (a basic value item); or
|
||||
// - `map hasher(HasherKind) KeyType => ValueType` (a map item).
|
||||
//
|
||||
// Note that there are two optional modifiers for the storage type declaration.
|
||||
// - `Foo: Option<u32>`:
|
||||
// - `Foo::put(1); Foo::get()` returns `Some(1)`;
|
||||
// - `Foo::kill(); Foo::get()` returns `None`.
|
||||
// - `Foo: u32`:
|
||||
// - `Foo::put(1); Foo::get()` returns `1`;
|
||||
// - `Foo::kill(); Foo::get()` returns `0` (u32::default()).
|
||||
// e.g. Foo: u32;
|
||||
// e.g. pub Bar get(fn bar): map hasher(blake2_128_concat) T::AccountId => Vec<(T::Balance, u64)>;
|
||||
//
|
||||
// For basic value items, you'll get a type which implements
|
||||
// `frame_support::StorageValue`. For map items, you'll get a type which
|
||||
// implements `frame_support::StorageMap`.
|
||||
//
|
||||
// If they have a getter (`get(getter_name)`), then your pallet will come
|
||||
// equipped with `fn getter_name() -> Type` for basic value items or
|
||||
// `fn getter_name(key: KeyType) -> ValueType` for map items.
|
||||
Dummy get(fn dummy) config(): Option<T::Balance>;
|
||||
|
||||
// A map that has enumerable entries.
|
||||
Bar get(fn bar) config(): map hasher(blake2_128_concat) T::AccountId => T::Balance;
|
||||
|
||||
// this one uses the default, we'll demonstrate the usage of 'mutate' API.
|
||||
Foo get(fn foo) config(): T::Balance;
|
||||
}
|
||||
}
|
||||
|
||||
decl_event!(
|
||||
/// Events are a simple means of reporting specific conditions and
|
||||
/// circumstances that have happened that users, Dapps and/or chain explorers would find
|
||||
/// interesting and otherwise difficult to detect.
|
||||
pub enum Event<T> where B = <T as pallet_balances::Config>::Balance {
|
||||
// Just a normal `enum`, here's a dummy event to ensure it compiles.
|
||||
/// Dummy event, just here so there's a generic type that's used.
|
||||
Dummy(B),
|
||||
}
|
||||
);
|
||||
|
||||
// The module declaration. This states the entry points that we handle. The
|
||||
// macro takes care of the marshalling of arguments and dispatch.
|
||||
//
|
||||
// Anyone can have these functions execute by signing and submitting
|
||||
// an extrinsic. Ensure that calls into each of these execute in a time, memory and
|
||||
// using storage space proportional to any costs paid for by the caller or otherwise the
|
||||
// difficulty of forcing the call to happen.
|
||||
//
|
||||
// Generally you'll want to split these into three groups:
|
||||
// - Public calls that are signed by an external account.
|
||||
// - Root calls that are allowed to be made only by the governance system.
|
||||
// - Unsigned calls that can be of two kinds:
|
||||
// * "Inherent extrinsics" that are opinions generally held by the block
|
||||
// authors that build child blocks.
|
||||
// * Unsigned Transactions that are of intrinsic recognizable utility to the
|
||||
// network, and are validated by the runtime.
|
||||
//
|
||||
// Information about where this dispatch initiated from is provided as the first argument
|
||||
// "origin". As such functions must always look like:
|
||||
//
|
||||
// `fn foo(origin, bar: Bar, baz: Baz) -> Result;`
|
||||
//
|
||||
// The `Result` is required as part of the syntax (and expands to the conventional dispatch
|
||||
// result of `Result<(), &'static str>`).
|
||||
//
|
||||
// When you come to `impl` them later in the pallet, you must specify the full type for `origin`:
|
||||
//
|
||||
// `fn foo(origin: T::Origin, bar: Bar, baz: Baz) { ... }`
|
||||
//
|
||||
// There are three entries in the `frame_system::Origin` enum that correspond
|
||||
// to the above bullets: `::Signed(AccountId)`, `::Root` and `::None`. You should always match
|
||||
// against them as the first thing you do in your function. There are three convenience calls
|
||||
// in system that do the matching for you and return a convenient result: `ensure_signed`,
|
||||
// `ensure_root` and `ensure_none`.
|
||||
decl_module! {
|
||||
// Simple declaration of the `Module` type. Lets the macro know what its working on.
|
||||
pub struct Module<T: Config> for enum Call where origin: T::Origin {
|
||||
/// Deposit one of this pallet's events by using the default implementation.
|
||||
/// It is also possible to provide a custom implementation.
|
||||
/// For non-generic events, the generic parameter just needs to be dropped, so that it
|
||||
/// looks like: `fn deposit_event() = default;`.
|
||||
fn deposit_event() = default;
|
||||
// Anyone can have these functions execute by signing and submitting
|
||||
// an extrinsic. Ensure that calls into each of these execute in a time, memory and
|
||||
// using storage space proportional to any costs paid for by the caller or otherwise the
|
||||
// difficulty of forcing the call to happen.
|
||||
//
|
||||
// Generally you'll want to split these into three groups:
|
||||
// - Public calls that are signed by an external account.
|
||||
// - Root calls that are allowed to be made only by the governance system.
|
||||
// - Unsigned calls that can be of two kinds:
|
||||
// * "Inherent extrinsics" that are opinions generally held by the block
|
||||
// authors that build child blocks.
|
||||
// * Unsigned Transactions that are of intrinsic recognizable utility to the
|
||||
// network, and are validated by the runtime.
|
||||
//
|
||||
// Information about where this dispatch initiated from is provided as the first argument
|
||||
// "origin". As such functions must always look like:
|
||||
//
|
||||
// `fn foo(origin: OriginFor<T>, bar: Bar, baz: Baz) -> DispatchResultWithPostInfo { ... }`
|
||||
//
|
||||
// The `DispatchResultWithPostInfo` is required as part of the syntax (and can be found at
|
||||
// `pallet_prelude::DispatchResultWithPostInfo`).
|
||||
//
|
||||
// There are three entries in the `frame_system::Origin` enum that correspond
|
||||
// to the above bullets: `::Signed(AccountId)`, `::Root` and `::None`. You should always match
|
||||
// against them as the first thing you do in your function. There are three convenience calls
|
||||
// in system that do the matching for you and return a convenient result: `ensure_signed`,
|
||||
// `ensure_root` and `ensure_none`.
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// This is your public interface. Be extremely careful.
|
||||
/// This is just a simple example of how to interact with the pallet from the external
|
||||
/// world.
|
||||
@@ -458,18 +444,22 @@ decl_module! {
|
||||
//
|
||||
// If you don't respect these rules, it is likely that your chain will be attackable.
|
||||
//
|
||||
// Each transaction can define an optional `#[weight]` attribute to convey a set of static
|
||||
// Each transaction must define a `#[pallet::weight(..)]` attribute to convey a set of static
|
||||
// information about its dispatch. FRAME System and FRAME Executive pallet then use this
|
||||
// information to properly execute the transaction, whilst keeping the total load of the
|
||||
// chain in a moderate rate.
|
||||
//
|
||||
// The _right-hand-side_ value of the `#[weight]` attribute can be any type that implements
|
||||
// a set of traits, namely [`WeighData`] and [`ClassifyDispatch`]. The former conveys the
|
||||
// weight (a numeric representation of pure execution time and difficulty) of the
|
||||
// transaction and the latter demonstrates the [`DispatchClass`] of the call. A higher
|
||||
// weight means a larger transaction (less of which can be placed in a single block).
|
||||
#[weight = 0]
|
||||
fn accumulate_dummy(origin, increase_by: T::Balance) -> DispatchResult {
|
||||
// The parenthesized value of the `#[pallet::weight(..)]` attribute can be any type that
|
||||
// implements a set of traits, namely [`WeighData`] and [`ClassifyDispatch`].
|
||||
// The former conveys the weight (a numeric representation of pure execution time and
|
||||
// difficulty) of the transaction and the latter demonstrates the [`DispatchClass`] of the
|
||||
// call. A higher weight means a larger transaction (less of which can be placed in a
|
||||
// single block).
|
||||
#[pallet::weight(0)]
|
||||
pub(super) fn accumulate_dummy(
|
||||
origin: OriginFor<T>,
|
||||
increase_by: T::Balance
|
||||
) -> DispatchResultWithPostInfo {
|
||||
// This is a public call, so we ensure that the origin is some signed account.
|
||||
let _sender = ensure_signed(origin)?;
|
||||
|
||||
@@ -493,10 +483,10 @@ decl_module! {
|
||||
});
|
||||
|
||||
// Let's deposit an event to let the outside world know this happened.
|
||||
Self::deposit_event(RawEvent::Dummy(increase_by));
|
||||
Self::deposit_event(Event::Dummy(increase_by));
|
||||
|
||||
// All good.
|
||||
Ok(())
|
||||
// All good, no refund.
|
||||
Ok(().into())
|
||||
}
|
||||
|
||||
/// A privileged call; in this case it resets our dummy value to something new.
|
||||
@@ -506,39 +496,92 @@ decl_module! {
|
||||
// calls to be executed - we don't need to care why. Because it's privileged, we can
|
||||
// assume it's a one-off operation and substantial processing/storage/memory can be used
|
||||
// without worrying about gameability or attack scenarios.
|
||||
// If you do not specify `Result` explicitly as return value, it will be added automatically
|
||||
// for you and `Ok(())` will be returned.
|
||||
#[weight = WeightForSetDummy::<T>(<BalanceOf<T>>::from(100u32))]
|
||||
fn set_dummy(origin, #[compact] new_value: T::Balance) {
|
||||
#[pallet::weight(WeightForSetDummy::<T>(<BalanceOf<T>>::from(100u32)))]
|
||||
fn set_dummy(
|
||||
origin: OriginFor<T>,
|
||||
#[pallet::compact] new_value: T::Balance,
|
||||
) -> DispatchResultWithPostInfo {
|
||||
ensure_root(origin)?;
|
||||
// Put the new value into storage.
|
||||
<Dummy<T>>::put(new_value);
|
||||
|
||||
// All good, no refund.
|
||||
Ok(().into())
|
||||
}
|
||||
}
|
||||
|
||||
// The signature could also look like: `fn on_initialize()`.
|
||||
// This function could also very well have a weight annotation, similar to any other. The
|
||||
// only difference is that it mut be returned, not annotated.
|
||||
fn on_initialize(_n: T::BlockNumber) -> Weight {
|
||||
// Anything that needs to be done at the start of the block.
|
||||
// We don't do anything here.
|
||||
/// Events are a simple means of reporting specific conditions and
|
||||
/// circumstances that have happened that users, Dapps and/or chain explorers would find
|
||||
/// interesting and otherwise difficult to detect.
|
||||
#[pallet::event]
|
||||
/// This attribute generate the function `deposit_event` to deposit one of this pallet event,
|
||||
/// it is optional, it is also possible to provide a custom implementation.
|
||||
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
||||
pub enum Event<T: Config> {
|
||||
// Just a normal `enum`, here's a dummy event to ensure it compiles.
|
||||
/// Dummy event, just here so there's a generic type that's used.
|
||||
Dummy(BalanceOf<T>),
|
||||
}
|
||||
|
||||
0
|
||||
// pallet::storage attributes allow for type-safe usage of the Substrate storage database,
|
||||
// so you can keep things around between blocks.
|
||||
//
|
||||
// Any storage must be one of `StorageValue`, `StorageMap` or `StorageDoubleMap`.
|
||||
// The first generic holds the prefix to use and is generated by the macro.
|
||||
// The query kind is either `OptionQuery` (the default) or `ValueQuery`.
|
||||
// - for `type Foo<T> = StorageValue<_, u32, OptionQuery>`:
|
||||
// - `Foo::put(1); Foo::get()` returns `Some(1)`;
|
||||
// - `Foo::kill(); Foo::get()` returns `None`.
|
||||
// - for `type Foo<T> = StorageValue<_, u32, ValueQuery>`:
|
||||
// - `Foo::put(1); Foo::get()` returns `1`;
|
||||
// - `Foo::kill(); Foo::get()` returns `0` (u32::default()).
|
||||
#[pallet::storage]
|
||||
// The getter attribute generate a function on `Pallet` placeholder:
|
||||
// `fn getter_name() -> Type` for basic value items or
|
||||
// `fn getter_name(key: KeyType) -> ValueType` for map items.
|
||||
#[pallet::getter(fn dummy)]
|
||||
pub(super) type Dummy<T: Config> = StorageValue<_, T::Balance>;
|
||||
|
||||
// A map that has enumerable entries.
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn bar)]
|
||||
pub(super) type Bar<T: Config> = StorageMap<_, Blake2_128Concat, T::AccountId, T::Balance, ValueQuery>;
|
||||
|
||||
// this one uses the query kind: `ValueQuery`, we'll demonstrate the usage of 'mutate' API.
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn foo)]
|
||||
pub(super) type Foo<T: Config> = StorageValue<_, T::Balance, ValueQuery>;
|
||||
|
||||
|
||||
// The genesis config type.
|
||||
#[pallet::genesis_config]
|
||||
pub struct GenesisConfig<T: Config> {
|
||||
pub dummy: T::Balance,
|
||||
pub bar: Vec<(T::AccountId, T::Balance)>,
|
||||
pub foo: T::Balance,
|
||||
}
|
||||
|
||||
// The default value for the genesis config type.
|
||||
#[cfg(feature = "std")]
|
||||
impl<T: Config> Default for GenesisConfig<T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
dummy: Default::default(),
|
||||
bar: Default::default(),
|
||||
foo: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The signature could also look like: `fn on_finalize()`
|
||||
fn on_finalize(_n: T::BlockNumber) {
|
||||
// Anything that needs to be done at the end of the block.
|
||||
// We just kill our dummy storage item.
|
||||
<Dummy<T>>::kill();
|
||||
}
|
||||
|
||||
// A runtime code run after every block and have access to extended set of APIs.
|
||||
//
|
||||
// For instance you can generate extrinsics for the upcoming produced block.
|
||||
fn offchain_worker(_n: T::BlockNumber) {
|
||||
// We don't do anything here.
|
||||
// but we could dispatch extrinsic (transaction/unsigned/inherent) using
|
||||
// sp_io::submit_extrinsic
|
||||
// The build of genesis for the pallet.
|
||||
#[pallet::genesis_build]
|
||||
impl<T: Config> GenesisBuild<T> for GenesisConfig<T> {
|
||||
fn build(&self) {
|
||||
<Dummy<T>>::put(&self.dummy);
|
||||
for (a, b) in &self.bar {
|
||||
<Bar<T>>::insert(a, b);
|
||||
}
|
||||
<Foo<T>>::put(&self.foo);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -548,7 +591,7 @@ decl_module! {
|
||||
// - Public interface. These are functions that are `pub` and generally fall into inspector
|
||||
// functions that do not write to storage and operation functions that do.
|
||||
// - Private functions. These are your usual private utilities unavailable to other pallets.
|
||||
impl<T: Config> Module<T> {
|
||||
impl<T: Config> Pallet<T> {
|
||||
// Add public immutables and private mutables.
|
||||
#[allow(dead_code)]
|
||||
fn accumulate_foo(origin: T::Origin, increase_by: T::Balance) -> DispatchResult {
|
||||
@@ -684,7 +727,7 @@ mod benchmarking {
|
||||
}
|
||||
}
|
||||
|
||||
impl_benchmark_test_suite!(Module, crate::tests::new_test_ext(), crate::tests::Test);
|
||||
impl_benchmark_test_suite!(Pallet, crate::tests::new_test_ext(), crate::tests::Test);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -2034,9 +2034,9 @@ pub mod pallet_prelude {
|
||||
/// * `add_extra_genesis` fields are converted to `GenesisConfig` field with their correct
|
||||
/// default if specified
|
||||
/// * `add_extra_genesis` build is written into `GenesisBuild::build`
|
||||
/// * storage items defined with [`pallet`] use the name of the pallet provided by [`PalletInfo::name`]
|
||||
/// as `pallet_prefix` (in `decl_storage`, storage items used the `pallet_prefix` given as input of
|
||||
/// `decl_storage` with the syntax `as Example`).
|
||||
/// * storage items defined with [`pallet`] use the name of the pallet provided by
|
||||
/// [`traits::PalletInfo::name`] as `pallet_prefix` (in `decl_storage`, storage items used the
|
||||
/// `pallet_prefix` given as input of `decl_storage` with the syntax `as Example`).
|
||||
/// Thus a runtime using the pallet must be careful with this change.
|
||||
/// To handle this change:
|
||||
/// * either ensure that the name of the pallet given to `construct_runtime!` is the same
|
||||
|
||||
@@ -16,8 +16,9 @@
|
||||
// limitations under the License.
|
||||
|
||||
//! Weights for frame_system
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.0
|
||||
//! DATE: 2020-10-28, STEPS: [50, ], REPEAT: 20, LOW RANGE: [], HIGH RANGE: []
|
||||
//! DATE: 2020-10-28, STEPS: \[50, \], REPEAT: 20, LOW RANGE: [], HIGH RANGE: []
|
||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128
|
||||
|
||||
// Executed Command:
|
||||
|
||||
Reference in New Issue
Block a user