Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Commit 91eff0b

Browse files
committed
replace offchain worker example
1 parent 44d3a8d commit 91eff0b

File tree

3 files changed

+140
-126
lines changed

3 files changed

+140
-126
lines changed

frame/example-offchain-worker/src/lib.rs

Lines changed: 135 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -42,27 +42,19 @@
4242
#![cfg_attr(not(feature = "std"), no_std)]
4343

4444
use frame_system::{
45-
self as system,
46-
ensure_signed,
47-
ensure_none,
4845
offchain::{
4946
AppCrypto, CreateSignedTransaction, SendUnsignedTransaction, SendSignedTransaction,
5047
SignedPayload, SigningTypes, Signer, SubmitTransaction,
5148
}
5249
};
53-
use frame_support::{
54-
debug,
55-
dispatch::DispatchResult, decl_module, decl_storage, decl_event,
56-
traits::Get,
57-
};
50+
use frame_support::{debug, storage::StorageValue, traits::Get};
5851
use sp_core::crypto::KeyTypeId;
5952
use sp_runtime::{
6053
RuntimeDebug,
6154
offchain::{http, Duration, storage::StorageValueRef},
6255
traits::Zero,
6356
transaction_validity::{
6457
InvalidTransaction, ValidTransaction, TransactionValidity, TransactionSource,
65-
TransactionPriority,
6658
},
6759
};
6860
use codec::{Encode, Decode};
@@ -101,37 +93,6 @@ pub mod crypto {
10193
}
10294
}
10395

104-
/// This pallet's configuration trait
105-
pub trait Trait: CreateSignedTransaction<Call<Self>> {
106-
/// The identifier type for an offchain worker.
107-
type AuthorityId: AppCrypto<Self::Public, Self::Signature>;
108-
109-
/// The overarching event type.
110-
type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;
111-
/// The overarching dispatch call type.
112-
type Call: From<Call<Self>>;
113-
114-
// Configuration parameters
115-
116-
/// A grace period after we send transaction.
117-
///
118-
/// To avoid sending too many transactions, we only attempt to send one
119-
/// every `GRACE_PERIOD` blocks. We use Local Storage to coordinate
120-
/// sending between distinct runs of this offchain worker.
121-
type GracePeriod: Get<Self::BlockNumber>;
122-
123-
/// Number of blocks of cooldown after unsigned transaction is included.
124-
///
125-
/// This ensures that we only accept unsigned transactions once, every `UnsignedInterval` blocks.
126-
type UnsignedInterval: Get<Self::BlockNumber>;
127-
128-
/// A configuration for base priority of unsigned transactions.
129-
///
130-
/// This is exposed so that it can be tuned for particular runtime, when
131-
/// multiple pallets send unsigned transactions.
132-
type UnsignedPriority: Get<TransactionPriority>;
133-
}
134-
13596
/// Payload used by this example crate to hold price
13697
/// data required to submit a transaction.
13798
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]
@@ -147,35 +108,131 @@ impl<T: SigningTypes> SignedPayload<T> for PricePayload<T::Public, T::BlockNumbe
147108
}
148109
}
149110

150-
decl_storage! {
151-
trait Store for Module<T: Trait> as ExampleOffchainWorker {
152-
/// A vector of recently submitted prices.
111+
pub use pallet::*;
112+
#[frame_support::pallet(ExampleOffchainWorker)]
113+
mod pallet {
114+
use super::{CreateSignedTransaction, AppCrypto, PricePayload, TransactionType};
115+
use frame_support::{pallet_prelude::*, debug};
116+
use frame_system::pallet_prelude::*;
117+
118+
/// This pallet's configuration trait
119+
#[pallet::trait_]
120+
pub trait Trait: CreateSignedTransaction<Call<Self>> + frame_system::Trait {
121+
/// The identifier type for an offchain worker.
122+
type AuthorityId: AppCrypto<Self::Public, Self::Signature>;
123+
124+
/// The overarching event type.
125+
type Event: From<Event<Self>> + IsType<<Self as frame_system::Trait>::Event>;
126+
/// The overarching dispatch call type.
127+
type Call: From<Call<Self>>;
128+
129+
// Configuration parameters
130+
131+
/// A grace period after we send transaction.
153132
///
154-
/// This is used to calculate average price, should have bounded size.
155-
Prices get(fn prices): Vec<u32>;
156-
/// Defines the block when next unsigned transaction will be accepted.
133+
/// To avoid sending too many transactions, we only attempt to send one
134+
/// every `GRACE_PERIOD` blocks. We use Local Storage to coordinate
135+
/// sending between distinct runs of this offchain worker.
136+
type GracePeriod: Get<Self::BlockNumber>;
137+
138+
/// Number of blocks of cooldown after unsigned transaction is included.
157139
///
158-
/// To prevent spam of unsigned (and unpayed!) transactions on the network,
159-
/// we only allow one transaction every `T::UnsignedInterval` blocks.
160-
/// This storage entry defines when new transaction is going to be accepted.
161-
NextUnsignedAt get(fn next_unsigned_at): T::BlockNumber;
140+
/// This ensures that we only accept unsigned transactions once, every `UnsignedInterval`
141+
/// blocks.
142+
type UnsignedInterval: Get<Self::BlockNumber>;
143+
144+
/// A configuration for base priority of unsigned transactions.
145+
///
146+
/// This is exposed so that it can be tuned for particular runtime, when
147+
/// multiple pallets send unsigned transactions.
148+
type UnsignedPriority: Get<TransactionPriority>;
162149
}
163-
}
164150

165-
decl_event!(
151+
/// A vector of recently submitted prices.
152+
///
153+
/// This is used to calculate average price, should have bounded size.
154+
#[pallet::storage]
155+
#[pallet::generate_getter(fn prices)]
156+
pub(crate) type Prices = StorageValueType<_, Vec<u32>, ValueQuery>;
157+
158+
/// Defines the block when next unsigned transaction will be accepted.
159+
///
160+
/// To prevent spam of unsigned (and unpayed!) transactions on the network,
161+
/// we only allow one transaction every `T::UnsignedInterval` blocks.
162+
/// This storage entry defines when new transaction is going to be accepted.
163+
#[pallet::storage]
164+
#[pallet::generate_getter(fn next_unsigned_at)]
165+
pub(crate) type NextUnsignedAt<T: Trait> = StorageValueType<_, T::BlockNumber, ValueQuery>;
166+
166167
/// Events generated by the module.
167-
pub enum Event<T> where AccountId = <T as frame_system::Trait>::AccountId {
168-
/// Event generated when new price is accepted to contribute to the average.
168+
#[pallet::event]
169+
#[pallet::metadata(<T as frame_system::Trait>::AccountId = AccountId)]
170+
pub enum Event<T: Trait> {
171+
/// Event generated when new price is accepted to contribute to the average.
169172
/// [price, who]
170-
NewPrice(u32, AccountId),
173+
NewPrice(u32, <T as frame_system::Trait>::AccountId),
171174
}
172-
);
173175

174-
decl_module! {
175-
/// A public part of the pallet.
176-
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
177-
fn deposit_event() = default;
176+
#[pallet::module]
177+
#[pallet::generate(fn deposit_event)]
178+
pub struct Module<T>(PhantomData<T>);
179+
180+
#[pallet::module_interface]
181+
impl<T: Trait> ModuleInterface<BlockNumberFor<T>> for Module<T> {
182+
/// Offchain Worker entry point.
183+
///
184+
/// By implementing `fn offchain_worker` within `decl_module!` you declare a new offchain
185+
/// worker.
186+
/// This function will be called when the node is fully synced and a new best block is
187+
/// succesfuly imported.
188+
/// Note that it's not guaranteed for offchain workers to run on EVERY block, there might
189+
/// be cases where some blocks are skipped, or for some the worker runs twice (re-orgs),
190+
/// so the code should be able to handle that.
191+
/// You can use `Local Storage` API to coordinate runs of the worker.
192+
fn offchain_worker(block_number: T::BlockNumber) {
193+
// It's a good idea to add logs to your offchain workers.
194+
// Using the `frame_support::debug` module you have access to the same API exposed by
195+
// the `log` crate.
196+
// Note that having logs compiled to WASM may cause the size of the blob to increase
197+
// significantly. You can use `RuntimeDebug` custom derive to hide details of the types
198+
// in WASM or use `debug::native` namespace to produce logs only when the worker is
199+
// running natively.
200+
debug::native::info!("Hello World from offchain workers!");
201+
202+
// Since off-chain workers are just part of the runtime code, they have direct access
203+
// to the storage and other included pallets.
204+
//
205+
// We can easily import `frame_system` and retrieve a block hash of the parent block.
206+
let parent_hash = <frame_system::Module<T>>::block_hash(block_number - 1.into());
207+
debug::debug!("Current block: {:?} (parent hash: {:?})", block_number, parent_hash);
208+
209+
// It's a good practice to keep `fn offchain_worker()` function minimal, and move most
210+
// of the code to separate `impl` block.
211+
// Here we call a helper function to calculate current average price.
212+
// This function reads storage entries of the current state.
213+
let average: Option<u32> = Self::average_price();
214+
debug::debug!("Current price: {:?}", average);
215+
216+
// For this example we are going to send both signed and unsigned transactions
217+
// depending on the block number.
218+
// Usually it's enough to choose one or the other.
219+
let should_send = Self::choose_transaction_type(block_number);
220+
let res = match should_send {
221+
TransactionType::Signed => Self::fetch_price_and_send_signed(),
222+
TransactionType::UnsignedForAny => Self::fetch_price_and_send_unsigned_for_any_account(block_number),
223+
TransactionType::UnsignedForAll => Self::fetch_price_and_send_unsigned_for_all_accounts(block_number),
224+
TransactionType::Raw => Self::fetch_price_and_send_raw_unsigned(block_number),
225+
TransactionType::None => Ok(()),
226+
};
227+
if let Err(e) = res {
228+
debug::error!("Error: {}", e);
229+
}
230+
}
231+
}
178232

233+
/// A public part of the pallet.
234+
#[pallet::call]
235+
impl<T: Trait> Call for Module<T> {
179236
/// Submit new price to the list.
180237
///
181238
/// This method is a public function of the module and can be called from within
@@ -190,13 +247,13 @@ decl_module! {
190247
/// working and receives (and provides) meaningful data.
191248
/// This example is not focused on correctness of the oracle itself, but rather its
192249
/// purpose is to showcase offchain worker capabilities.
193-
#[weight = 0]
194-
pub fn submit_price(origin, price: u32) -> DispatchResult {
250+
#[pallet::weight(0)]
251+
pub fn submit_price(origin: OriginFor<T>, price: u32) -> DispatchResultWithPostInfo {
195252
// Retrieve sender of the transaction.
196253
let who = ensure_signed(origin)?;
197254
// Add the price to the on-chain list.
198255
Self::add_price(who, price);
199-
Ok(())
256+
Ok(().into())
200257
}
201258

202259
/// Submit new price to the list via unsigned transaction.
@@ -215,84 +272,37 @@ decl_module! {
215272
///
216273
/// This example is not focused on correctness of the oracle itself, but rather its
217274
/// purpose is to showcase offchain worker capabilities.
218-
#[weight = 0]
219-
pub fn submit_price_unsigned(origin, _block_number: T::BlockNumber, price: u32)
220-
-> DispatchResult
275+
#[pallet::weight(0)]
276+
pub fn submit_price_unsigned(
277+
origin: OriginFor<T>,
278+
_block_number: T::BlockNumber,
279+
price: u32
280+
) -> DispatchResultWithPostInfo
221281
{
222282
// This ensures that the function can only be called via unsigned transaction.
223283
ensure_none(origin)?;
224284
// Add the price to the on-chain list, but mark it as coming from an empty address.
225285
Self::add_price(Default::default(), price);
226286
// now increment the block number at which we expect next unsigned transaction.
227-
let current_block = <system::Module<T>>::block_number();
287+
let current_block = <frame_system::Module<T>>::block_number();
228288
<NextUnsignedAt<T>>::put(current_block + T::UnsignedInterval::get());
229-
Ok(())
289+
Ok(().into())
230290
}
231291

232-
#[weight = 0]
292+
#[pallet::weight(0)]
233293
pub fn submit_price_unsigned_with_signed_payload(
234-
origin,
294+
origin: OriginFor<T>,
235295
price_payload: PricePayload<T::Public, T::BlockNumber>,
236296
_signature: T::Signature,
237-
) -> DispatchResult {
297+
) -> DispatchResultWithPostInfo {
238298
// This ensures that the function can only be called via unsigned transaction.
239299
ensure_none(origin)?;
240300
// Add the price to the on-chain list, but mark it as coming from an empty address.
241301
Self::add_price(Default::default(), price_payload.price);
242302
// now increment the block number at which we expect next unsigned transaction.
243-
let current_block = <system::Module<T>>::block_number();
303+
let current_block = <frame_system::Module<T>>::block_number();
244304
<NextUnsignedAt<T>>::put(current_block + T::UnsignedInterval::get());
245-
Ok(())
246-
}
247-
248-
/// Offchain Worker entry point.
249-
///
250-
/// By implementing `fn offchain_worker` within `decl_module!` you declare a new offchain
251-
/// worker.
252-
/// This function will be called when the node is fully synced and a new best block is
253-
/// succesfuly imported.
254-
/// Note that it's not guaranteed for offchain workers to run on EVERY block, there might
255-
/// be cases where some blocks are skipped, or for some the worker runs twice (re-orgs),
256-
/// so the code should be able to handle that.
257-
/// You can use `Local Storage` API to coordinate runs of the worker.
258-
fn offchain_worker(block_number: T::BlockNumber) {
259-
// It's a good idea to add logs to your offchain workers.
260-
// Using the `frame_support::debug` module you have access to the same API exposed by
261-
// the `log` crate.
262-
// Note that having logs compiled to WASM may cause the size of the blob to increase
263-
// significantly. You can use `RuntimeDebug` custom derive to hide details of the types
264-
// in WASM or use `debug::native` namespace to produce logs only when the worker is
265-
// running natively.
266-
debug::native::info!("Hello World from offchain workers!");
267-
268-
// Since off-chain workers are just part of the runtime code, they have direct access
269-
// to the storage and other included pallets.
270-
//
271-
// We can easily import `frame_system` and retrieve a block hash of the parent block.
272-
let parent_hash = <system::Module<T>>::block_hash(block_number - 1.into());
273-
debug::debug!("Current block: {:?} (parent hash: {:?})", block_number, parent_hash);
274-
275-
// It's a good practice to keep `fn offchain_worker()` function minimal, and move most
276-
// of the code to separate `impl` block.
277-
// Here we call a helper function to calculate current average price.
278-
// This function reads storage entries of the current state.
279-
let average: Option<u32> = Self::average_price();
280-
debug::debug!("Current price: {:?}", average);
281-
282-
// For this example we are going to send both signed and unsigned transactions
283-
// depending on the block number.
284-
// Usually it's enough to choose one or the other.
285-
let should_send = Self::choose_transaction_type(block_number);
286-
let res = match should_send {
287-
TransactionType::Signed => Self::fetch_price_and_send_signed(),
288-
TransactionType::UnsignedForAny => Self::fetch_price_and_send_unsigned_for_any_account(block_number),
289-
TransactionType::UnsignedForAll => Self::fetch_price_and_send_unsigned_for_all_accounts(block_number),
290-
TransactionType::Raw => Self::fetch_price_and_send_raw_unsigned(block_number),
291-
TransactionType::None => Ok(()),
292-
};
293-
if let Err(e) = res {
294-
debug::error!("Error: {}", e);
295-
}
305+
Ok(().into())
296306
}
297307
}
298308
}
@@ -631,7 +641,7 @@ impl<T: Trait> Module<T> {
631641
.expect("The average is not empty, because it was just mutated; qed");
632642
debug::info!("Current average price is: {}", average);
633643
// here we are raising the NewPrice event
634-
Self::deposit_event(RawEvent::NewPrice(price, who));
644+
Self::deposit_event(Event::NewPrice(price, who));
635645
}
636646

637647
/// Calculate current average price.
@@ -654,7 +664,7 @@ impl<T: Trait> Module<T> {
654664
return InvalidTransaction::Stale.into();
655665
}
656666
// Let's make sure to reject transactions from the future.
657-
let current_block = <system::Module<T>>::block_number();
667+
let current_block = <frame_system::Module<T>>::block_number();
658668
if &current_block < block_number {
659669
return InvalidTransaction::Future.into();
660670
}

frame/support/procedural/src/pallet/parse/storage.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,8 @@ impl StorageDef {
197197

198198
if query_kind.is_none() && getter.is_some() {
199199
let msg = "Invalid pallet::storage, cannot generate getter because QueryKind is not \
200-
identifiable. QueryKind must be `OptionQuery` or `ValueQuery` to be identifiable.";
200+
identifiable. QueryKind must be `OptionQuery`, `ValueQuery`, or default one to be \
201+
identifiable.";
201202
return Err(syn::Error::new(getter.unwrap().span(), msg));
202203
}
203204

frame/system/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1360,6 +1360,9 @@ impl<T: Trait> Lookup for ChainContext<T> {
13601360
}
13611361

13621362
pub mod pallet_prelude {
1363+
pub use crate::ensure_signed;
1364+
pub use crate::ensure_none;
1365+
pub use crate::ensure_root;
13631366
pub type OriginFor<T> = <T as crate::Trait>::Origin;
13641367
pub type BlockNumberFor<T> = <T as crate::Trait>::BlockNumber;
13651368
}

0 commit comments

Comments
 (0)