referrerpolicy=no-referrer-when-downgrade

pallet_example_offchain_worker/
lib.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: MIT-0
5
6// Permission is hereby granted, free of charge, to any person obtaining a copy of
7// this software and associated documentation files (the "Software"), to deal in
8// the Software without restriction, including without limitation the rights to
9// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
10// of the Software, and to permit persons to whom the Software is furnished to do
11// so, subject to the following conditions:
12
13// The above copyright notice and this permission notice shall be included in all
14// copies or substantial portions of the Software.
15
16// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22// SOFTWARE.
23
24//! <!-- markdown-link-check-disable -->
25//! # Offchain Worker Example Pallet
26//!
27//! The Offchain Worker Example: A simple pallet demonstrating
28//! concepts, APIs and structures common to most offchain workers.
29//!
30//! Run `cargo doc --package pallet-example-offchain-worker --open` to view this module's
31//! documentation.
32//!
33//! - [`Config`]
34//! - [`Call`]
35//! - [`Pallet`]
36//!
37//! **This pallet serves as an example showcasing Substrate off-chain worker and is not meant to
38//! be used in production.**
39//!
40//! ## Overview
41//!
42//! In this example we are going to build a very simplistic, naive and definitely NOT
43//! production-ready oracle for BTC/USD price.
44//! Offchain Worker (OCW) will be triggered after every block, fetch the current price
45//! and prepare either signed or unsigned transaction to feed the result back on chain.
46//! The on-chain logic will simply aggregate the results and store last `64` values to compute
47//! the average price.
48//! Additional logic in OCW is put in place to prevent spamming the network with both signed
49//! and unsigned transactions, and custom `UnsignedValidator` makes sure that there is only
50//! one unsigned transaction floating in the network.
51
52#![cfg_attr(not(feature = "std"), no_std)]
53
54extern crate alloc;
55
56use alloc::vec::Vec;
57use codec::{Decode, DecodeWithMemTracking, Encode};
58use frame_support::traits::Get;
59use frame_system::{
60	self as system,
61	offchain::{
62		AppCrypto, CreateBare, CreateSignedTransaction, SendSignedTransaction,
63		SendUnsignedTransaction, SignedPayload, Signer, SigningTypes, SubmitTransaction,
64	},
65	pallet_prelude::BlockNumberFor,
66};
67use lite_json::json::JsonValue;
68use sp_core::crypto::KeyTypeId;
69use sp_runtime::{
70	offchain::{
71		http,
72		storage::{MutateStorageError, StorageRetrievalError, StorageValueRef},
73		Duration,
74	},
75	traits::Zero,
76	transaction_validity::{InvalidTransaction, TransactionValidity, ValidTransaction},
77	RuntimeDebug,
78};
79
80#[cfg(test)]
81mod tests;
82
83/// Defines application identifier for crypto keys of this module.
84///
85/// Every module that deals with signatures needs to declare its unique identifier for
86/// its crypto keys.
87/// When offchain worker is signing transactions it's going to request keys of type
88/// `KeyTypeId` from the keystore and use the ones it finds to sign the transaction.
89/// The keys can be inserted manually via RPC (see `author_insertKey`).
90pub const KEY_TYPE: KeyTypeId = KeyTypeId(*b"btc!");
91
92/// Based on the above `KeyTypeId` we need to generate a pallet-specific crypto type wrappers.
93/// We can use from supported crypto kinds (`sr25519`, `ed25519` and `ecdsa`) and augment
94/// the types with this pallet-specific identifier.
95pub mod crypto {
96	use super::KEY_TYPE;
97	use sp_core::sr25519::Signature as Sr25519Signature;
98	use sp_runtime::{
99		app_crypto::{app_crypto, sr25519},
100		traits::Verify,
101		MultiSignature, MultiSigner,
102	};
103	app_crypto!(sr25519, KEY_TYPE);
104
105	pub struct TestAuthId;
106
107	impl frame_system::offchain::AppCrypto<MultiSigner, MultiSignature> for TestAuthId {
108		type RuntimeAppPublic = Public;
109		type GenericSignature = sp_core::sr25519::Signature;
110		type GenericPublic = sp_core::sr25519::Public;
111	}
112
113	// implemented for mock runtime in test
114	impl frame_system::offchain::AppCrypto<<Sr25519Signature as Verify>::Signer, Sr25519Signature>
115		for TestAuthId
116	{
117		type RuntimeAppPublic = Public;
118		type GenericSignature = sp_core::sr25519::Signature;
119		type GenericPublic = sp_core::sr25519::Public;
120	}
121}
122
123pub use pallet::*;
124
125#[frame_support::pallet]
126pub mod pallet {
127	use super::*;
128	use frame_support::pallet_prelude::*;
129	use frame_system::pallet_prelude::*;
130
131	/// This pallet's configuration trait
132	#[pallet::config]
133	pub trait Config:
134		CreateSignedTransaction<Call<Self>> + CreateBare<Call<Self>> + frame_system::Config
135	{
136		/// The identifier type for an offchain worker.
137		type AuthorityId: AppCrypto<Self::Public, Self::Signature>;
138
139		// Configuration parameters
140
141		/// A grace period after we send transaction.
142		///
143		/// To avoid sending too many transactions, we only attempt to send one
144		/// every `GRACE_PERIOD` blocks. We use Local Storage to coordinate
145		/// sending between distinct runs of this offchain worker.
146		#[pallet::constant]
147		type GracePeriod: Get<BlockNumberFor<Self>>;
148
149		/// Number of blocks of cooldown after unsigned transaction is included.
150		///
151		/// This ensures that we only accept unsigned transactions once, every `UnsignedInterval`
152		/// blocks.
153		#[pallet::constant]
154		type UnsignedInterval: Get<BlockNumberFor<Self>>;
155
156		/// A configuration for base priority of unsigned transactions.
157		///
158		/// This is exposed so that it can be tuned for particular runtime, when
159		/// multiple pallets send unsigned transactions.
160		#[pallet::constant]
161		type UnsignedPriority: Get<TransactionPriority>;
162
163		/// Maximum number of prices.
164		#[pallet::constant]
165		type MaxPrices: Get<u32>;
166	}
167
168	#[pallet::pallet]
169	pub struct Pallet<T>(_);
170
171	#[pallet::hooks]
172	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
173		/// Offchain Worker entry point.
174		///
175		/// By implementing `fn offchain_worker` you declare a new offchain worker.
176		/// This function will be called when the node is fully synced and a new best block is
177		/// successfully imported.
178		/// Note that it's not guaranteed for offchain workers to run on EVERY block, there might
179		/// be cases where some blocks are skipped, or for some the worker runs twice (re-orgs),
180		/// so the code should be able to handle that.
181		/// You can use `Local Storage` API to coordinate runs of the worker.
182		fn offchain_worker(block_number: BlockNumberFor<T>) {
183			// Note that having logs compiled to WASM may cause the size of the blob to increase
184			// significantly. You can use `RuntimeDebug` custom derive to hide details of the types
185			// in WASM. The `sp-api` crate also provides a feature `disable-logging` to disable
186			// all logging and thus, remove any logging from the WASM.
187			log::info!("Hello World from offchain workers!");
188
189			// Since off-chain workers are just part of the runtime code, they have direct access
190			// to the storage and other included pallets.
191			//
192			// We can easily import `frame_system` and retrieve a block hash of the parent block.
193			let parent_hash = <system::Pallet<T>>::block_hash(block_number - 1u32.into());
194			log::debug!("Current block: {:?} (parent hash: {:?})", block_number, parent_hash);
195
196			// It's a good practice to keep `fn offchain_worker()` function minimal, and move most
197			// of the code to separate `impl` block.
198			// Here we call a helper function to calculate current average price.
199			// This function reads storage entries of the current state.
200			let average: Option<u32> = Self::average_price();
201			log::debug!("Current price: {:?}", average);
202
203			// For this example we are going to send both signed and unsigned transactions
204			// depending on the block number.
205			// Usually it's enough to choose one or the other.
206			let should_send = Self::choose_transaction_type(block_number);
207			let res = match should_send {
208				TransactionType::Signed => Self::fetch_price_and_send_signed(),
209				TransactionType::UnsignedForAny =>
210					Self::fetch_price_and_send_unsigned_for_any_account(block_number),
211				TransactionType::UnsignedForAll =>
212					Self::fetch_price_and_send_unsigned_for_all_accounts(block_number),
213				TransactionType::Raw => Self::fetch_price_and_send_raw_unsigned(block_number),
214				TransactionType::None => Ok(()),
215			};
216			if let Err(e) = res {
217				log::error!("Error: {}", e);
218			}
219		}
220	}
221
222	/// A public part of the pallet.
223	#[pallet::call]
224	impl<T: Config> Pallet<T> {
225		/// Submit new price to the list.
226		///
227		/// This method is a public function of the module and can be called from within
228		/// a transaction. It appends given `price` to current list of prices.
229		/// In our example the `offchain worker` will create, sign & submit a transaction that
230		/// calls this function passing the price.
231		///
232		/// The transaction needs to be signed (see `ensure_signed`) check, so that the caller
233		/// pays a fee to execute it.
234		/// This makes sure that it's not easy (or rather cheap) to attack the chain by submitting
235		/// excessive transactions, but note that it doesn't ensure the price oracle is actually
236		/// working and receives (and provides) meaningful data.
237		/// This example is not focused on correctness of the oracle itself, but rather its
238		/// purpose is to showcase offchain worker capabilities.
239		#[pallet::call_index(0)]
240		#[pallet::weight({0})]
241		pub fn submit_price(origin: OriginFor<T>, price: u32) -> DispatchResultWithPostInfo {
242			// Retrieve sender of the transaction.
243			let who = ensure_signed(origin)?;
244			// Add the price to the on-chain list.
245			Self::add_price(Some(who), price);
246			Ok(().into())
247		}
248
249		/// Submit new price to the list via unsigned transaction.
250		///
251		/// Works exactly like the `submit_price` function, but since we allow sending the
252		/// transaction without a signature, and hence without paying any fees,
253		/// we need a way to make sure that only some transactions are accepted.
254		/// This function can be called only once every `T::UnsignedInterval` blocks.
255		/// Transactions that call that function are de-duplicated on the pool level
256		/// via `validate_unsigned` implementation and also are rendered invalid if
257		/// the function has already been called in current "session".
258		///
259		/// It's important to specify `weight` for unsigned calls as well, because even though
260		/// they don't charge fees, we still don't want a single block to contain unlimited
261		/// number of such transactions.
262		///
263		/// This example is not focused on correctness of the oracle itself, but rather its
264		/// purpose is to showcase offchain worker capabilities.
265		#[pallet::call_index(1)]
266		#[pallet::weight({0})]
267		pub fn submit_price_unsigned(
268			origin: OriginFor<T>,
269			_block_number: BlockNumberFor<T>,
270			price: u32,
271		) -> DispatchResultWithPostInfo {
272			// This ensures that the function can only be called via unsigned transaction.
273			ensure_none(origin)?;
274			// Add the price to the on-chain list, but mark it as coming from an empty address.
275			Self::add_price(None, price);
276			// now increment the block number at which we expect next unsigned transaction.
277			let current_block = <system::Pallet<T>>::block_number();
278			<NextUnsignedAt<T>>::put(current_block + T::UnsignedInterval::get());
279			Ok(().into())
280		}
281
282		#[pallet::call_index(2)]
283		#[pallet::weight({0})]
284		pub fn submit_price_unsigned_with_signed_payload(
285			origin: OriginFor<T>,
286			price_payload: PricePayload<T::Public, BlockNumberFor<T>>,
287			_signature: T::Signature,
288		) -> DispatchResultWithPostInfo {
289			// This ensures that the function can only be called via unsigned transaction.
290			ensure_none(origin)?;
291			// Add the price to the on-chain list, but mark it as coming from an empty address.
292			Self::add_price(None, price_payload.price);
293			// now increment the block number at which we expect next unsigned transaction.
294			let current_block = <system::Pallet<T>>::block_number();
295			<NextUnsignedAt<T>>::put(current_block + T::UnsignedInterval::get());
296			Ok(().into())
297		}
298	}
299
300	/// Events for the pallet.
301	#[pallet::event]
302	#[pallet::generate_deposit(pub(super) fn deposit_event)]
303	pub enum Event<T: Config> {
304		/// Event generated when new price is accepted to contribute to the average.
305		NewPrice { price: u32, maybe_who: Option<T::AccountId> },
306	}
307
308	#[pallet::validate_unsigned]
309	impl<T: Config> ValidateUnsigned for Pallet<T> {
310		type Call = Call<T>;
311
312		/// Validate unsigned call to this module.
313		///
314		/// By default unsigned transactions are disallowed, but implementing the validator
315		/// here we make sure that some particular calls (the ones produced by offchain worker)
316		/// are being whitelisted and marked as valid.
317		fn validate_unsigned(_source: TransactionSource, call: &Self::Call) -> TransactionValidity {
318			// Firstly let's check that we call the right function.
319			if let Call::submit_price_unsigned_with_signed_payload {
320				price_payload: ref payload,
321				ref signature,
322			} = call
323			{
324				let signature_valid =
325					SignedPayload::<T>::verify::<T::AuthorityId>(payload, signature.clone());
326				if !signature_valid {
327					return InvalidTransaction::BadProof.into()
328				}
329				Self::validate_transaction_parameters(&payload.block_number, &payload.price)
330			} else if let Call::submit_price_unsigned { block_number, price: new_price } = call {
331				Self::validate_transaction_parameters(block_number, new_price)
332			} else {
333				InvalidTransaction::Call.into()
334			}
335		}
336	}
337
338	/// A vector of recently submitted prices.
339	///
340	/// This is used to calculate average price, should have bounded size.
341	#[pallet::storage]
342	pub(super) type Prices<T: Config> = StorageValue<_, BoundedVec<u32, T::MaxPrices>, ValueQuery>;
343
344	/// Defines the block when next unsigned transaction will be accepted.
345	///
346	/// To prevent spam of unsigned (and unpaid!) transactions on the network,
347	/// we only allow one transaction every `T::UnsignedInterval` blocks.
348	/// This storage entry defines when new transaction is going to be accepted.
349	#[pallet::storage]
350	pub(super) type NextUnsignedAt<T: Config> = StorageValue<_, BlockNumberFor<T>, ValueQuery>;
351}
352
353/// Payload used by this example crate to hold price
354/// data required to submit a transaction.
355#[derive(
356	Encode, Decode, DecodeWithMemTracking, Clone, PartialEq, Eq, RuntimeDebug, scale_info::TypeInfo,
357)]
358pub struct PricePayload<Public, BlockNumber> {
359	block_number: BlockNumber,
360	price: u32,
361	public: Public,
362}
363
364impl<T: SigningTypes> SignedPayload<T> for PricePayload<T::Public, BlockNumberFor<T>> {
365	fn public(&self) -> T::Public {
366		self.public.clone()
367	}
368}
369
370enum TransactionType {
371	Signed,
372	UnsignedForAny,
373	UnsignedForAll,
374	Raw,
375	None,
376}
377
378impl<T: Config> Pallet<T> {
379	/// Chooses which transaction type to send.
380	///
381	/// This function serves mostly to showcase `StorageValue` helper
382	/// and local storage usage.
383	///
384	/// Returns a type of transaction that should be produced in current run.
385	fn choose_transaction_type(block_number: BlockNumberFor<T>) -> TransactionType {
386		/// A friendlier name for the error that is going to be returned in case we are in the grace
387		/// period.
388		const RECENTLY_SENT: () = ();
389
390		// Start off by creating a reference to Local Storage value.
391		// Since the local storage is common for all offchain workers, it's a good practice
392		// to prepend your entry with the module name.
393		let val = StorageValueRef::persistent(b"example_ocw::last_send");
394		// The Local Storage is persisted and shared between runs of the offchain workers,
395		// and offchain workers may run concurrently. We can use the `mutate` function, to
396		// write a storage entry in an atomic fashion. Under the hood it uses `compare_and_set`
397		// low-level method of local storage API, which means that only one worker
398		// will be able to "acquire a lock" and send a transaction if multiple workers
399		// happen to be executed concurrently.
400		let res =
401			val.mutate(|last_send: Result<Option<BlockNumberFor<T>>, StorageRetrievalError>| {
402				match last_send {
403					// If we already have a value in storage and the block number is recent enough
404					// we avoid sending another transaction at this time.
405					Ok(Some(block)) if block_number < block + T::GracePeriod::get() =>
406						Err(RECENTLY_SENT),
407					// In every other case we attempt to acquire the lock and send a transaction.
408					_ => Ok(block_number),
409				}
410			});
411
412		// The result of `mutate` call will give us a nested `Result` type.
413		// The first one matches the return of the closure passed to `mutate`, i.e.
414		// if we return `Err` from the closure, we get an `Err` here.
415		// In case we return `Ok`, here we will have another (inner) `Result` that indicates
416		// if the value has been set to the storage correctly - i.e. if it wasn't
417		// written to in the meantime.
418		match res {
419			// The value has been set correctly, which means we can safely send a transaction now.
420			Ok(block_number) => {
421				// We will send different transactions based on a random number.
422				// Note that this logic doesn't really guarantee that the transactions will be sent
423				// in an alternating fashion (i.e. fairly distributed). Depending on the execution
424				// order and lock acquisition, we may end up for instance sending two `Signed`
425				// transactions in a row. If a strict order is desired, it's better to use
426				// the storage entry for that. (for instance store both block number and a flag
427				// indicating the type of next transaction to send).
428				let transaction_type = block_number % 4u32.into();
429				if transaction_type == Zero::zero() {
430					TransactionType::Signed
431				} else if transaction_type == BlockNumberFor::<T>::from(1u32) {
432					TransactionType::UnsignedForAny
433				} else if transaction_type == BlockNumberFor::<T>::from(2u32) {
434					TransactionType::UnsignedForAll
435				} else {
436					TransactionType::Raw
437				}
438			},
439			// We are in the grace period, we should not send a transaction this time.
440			Err(MutateStorageError::ValueFunctionFailed(RECENTLY_SENT)) => TransactionType::None,
441			// We wanted to send a transaction, but failed to write the block number (acquire a
442			// lock). This indicates that another offchain worker that was running concurrently
443			// most likely executed the same logic and succeeded at writing to storage.
444			// Thus we don't really want to send the transaction, knowing that the other run
445			// already did.
446			Err(MutateStorageError::ConcurrentModification(_)) => TransactionType::None,
447		}
448	}
449
450	/// A helper function to fetch the price and send signed transaction.
451	fn fetch_price_and_send_signed() -> Result<(), &'static str> {
452		let signer = Signer::<T, T::AuthorityId>::all_accounts();
453		if !signer.can_sign() {
454			return Err(
455				"No local accounts available. Consider adding one via `author_insertKey` RPC.",
456			)
457		}
458		// Make an external HTTP request to fetch the current price.
459		// Note this call will block until response is received.
460		let price = Self::fetch_price().map_err(|_| "Failed to fetch price")?;
461
462		// Using `send_signed_transaction` associated type we create and submit a transaction
463		// representing the call, we've just created.
464		// Submit signed will return a vector of results for all accounts that were found in the
465		// local keystore with expected `KEY_TYPE`.
466		let results = signer.send_signed_transaction(|_account| {
467			// Received price is wrapped into a call to `submit_price` public function of this
468			// pallet. This means that the transaction, when executed, will simply call that
469			// function passing `price` as an argument.
470			Call::submit_price { price }
471		});
472
473		for (acc, res) in &results {
474			match res {
475				Ok(()) => log::info!("[{:?}] Submitted price of {} cents", acc.id, price),
476				Err(e) => log::error!("[{:?}] Failed to submit transaction: {:?}", acc.id, e),
477			}
478		}
479
480		Ok(())
481	}
482
483	/// A helper function to fetch the price and send a raw unsigned transaction.
484	fn fetch_price_and_send_raw_unsigned(
485		block_number: BlockNumberFor<T>,
486	) -> Result<(), &'static str> {
487		// Make sure we don't fetch the price if unsigned transaction is going to be rejected
488		// anyway.
489		let next_unsigned_at = NextUnsignedAt::<T>::get();
490		if next_unsigned_at > block_number {
491			return Err("Too early to send unsigned transaction")
492		}
493
494		// Make an external HTTP request to fetch the current price.
495		// Note this call will block until response is received.
496		let price = Self::fetch_price().map_err(|_| "Failed to fetch price")?;
497
498		// Received price is wrapped into a call to `submit_price_unsigned` public function of this
499		// pallet. This means that the transaction, when executed, will simply call that function
500		// passing `price` as an argument.
501		let call = Call::submit_price_unsigned { block_number, price };
502
503		// Now let's create a transaction out of this call and submit it to the pool.
504		// Here we showcase two ways to send an unsigned transaction / unsigned payload (raw)
505		//
506		// By default unsigned transactions are disallowed, so we need to whitelist this case
507		// by writing `UnsignedValidator`. Note that it's EXTREMELY important to carefully
508		// implement unsigned validation logic, as any mistakes can lead to opening DoS or spam
509		// attack vectors. See validation logic docs for more details.
510		//
511		let xt = T::create_bare(call.into());
512		SubmitTransaction::<T, Call<T>>::submit_transaction(xt)
513			.map_err(|()| "Unable to submit unsigned transaction.")?;
514
515		Ok(())
516	}
517
518	/// A helper function to fetch the price, sign payload and send an unsigned transaction
519	fn fetch_price_and_send_unsigned_for_any_account(
520		block_number: BlockNumberFor<T>,
521	) -> Result<(), &'static str> {
522		// Make sure we don't fetch the price if unsigned transaction is going to be rejected
523		// anyway.
524		let next_unsigned_at = NextUnsignedAt::<T>::get();
525		if next_unsigned_at > block_number {
526			return Err("Too early to send unsigned transaction")
527		}
528
529		// Make an external HTTP request to fetch the current price.
530		// Note this call will block until response is received.
531		let price = Self::fetch_price().map_err(|_| "Failed to fetch price")?;
532
533		// -- Sign using any account
534		let (_, result) = Signer::<T, T::AuthorityId>::any_account()
535			.send_unsigned_transaction(
536				|account| PricePayload { price, block_number, public: account.public.clone() },
537				|payload, signature| Call::submit_price_unsigned_with_signed_payload {
538					price_payload: payload,
539					signature,
540				},
541			)
542			.ok_or("No local accounts accounts available.")?;
543		result.map_err(|()| "Unable to submit transaction")?;
544
545		Ok(())
546	}
547
548	/// A helper function to fetch the price, sign payload and send an unsigned transaction
549	fn fetch_price_and_send_unsigned_for_all_accounts(
550		block_number: BlockNumberFor<T>,
551	) -> Result<(), &'static str> {
552		// Make sure we don't fetch the price if unsigned transaction is going to be rejected
553		// anyway.
554		let next_unsigned_at = NextUnsignedAt::<T>::get();
555		if next_unsigned_at > block_number {
556			return Err("Too early to send unsigned transaction")
557		}
558
559		// Make an external HTTP request to fetch the current price.
560		// Note this call will block until response is received.
561		let price = Self::fetch_price().map_err(|_| "Failed to fetch price")?;
562
563		// -- Sign using all accounts
564		let transaction_results = Signer::<T, T::AuthorityId>::all_accounts()
565			.send_unsigned_transaction(
566				|account| PricePayload { price, block_number, public: account.public.clone() },
567				|payload, signature| Call::submit_price_unsigned_with_signed_payload {
568					price_payload: payload,
569					signature,
570				},
571			);
572		for (_account_id, result) in transaction_results.into_iter() {
573			if result.is_err() {
574				return Err("Unable to submit transaction")
575			}
576		}
577
578		Ok(())
579	}
580
581	/// Fetch current price and return the result in cents.
582	fn fetch_price() -> Result<u32, http::Error> {
583		// We want to keep the offchain worker execution time reasonable, so we set a hard-coded
584		// deadline to 2s to complete the external call.
585		// You can also wait indefinitely for the response, however you may still get a timeout
586		// coming from the host machine.
587		let deadline = sp_io::offchain::timestamp().add(Duration::from_millis(2_000));
588		// Initiate an external HTTP GET request.
589		// This is using high-level wrappers from `sp_runtime`, for the low-level calls that
590		// you can find in `sp_io`. The API is trying to be similar to `request`, but
591		// since we are running in a custom WASM execution environment we can't simply
592		// import the library here.
593		let request =
594			http::Request::get("https://min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=USD");
595		// We set the deadline for sending of the request, note that awaiting response can
596		// have a separate deadline. Next we send the request, before that it's also possible
597		// to alter request headers or stream body content in case of non-GET requests.
598		let pending = request.deadline(deadline).send().map_err(|_| http::Error::IoError)?;
599
600		// The request is already being processed by the host, we are free to do anything
601		// else in the worker (we can send multiple concurrent requests too).
602		// At some point however we probably want to check the response though,
603		// so we can block current thread and wait for it to finish.
604		// Note that since the request is being driven by the host, we don't have to wait
605		// for the request to have it complete, we will just not read the response.
606		let response = pending.try_wait(deadline).map_err(|_| http::Error::DeadlineReached)??;
607		// Let's check the status code before we proceed to reading the response.
608		if response.code != 200 {
609			log::warn!("Unexpected status code: {}", response.code);
610			return Err(http::Error::Unknown)
611		}
612
613		// Next we want to fully read the response body and collect it to a vector of bytes.
614		// Note that the return object allows you to read the body in chunks as well
615		// with a way to control the deadline.
616		let body = response.body().collect::<Vec<u8>>();
617
618		// Create a str slice from the body.
619		let body_str = alloc::str::from_utf8(&body).map_err(|_| {
620			log::warn!("No UTF8 body");
621			http::Error::Unknown
622		})?;
623
624		let price = match Self::parse_price(body_str) {
625			Some(price) => Ok(price),
626			None => {
627				log::warn!("Unable to extract price from the response: {:?}", body_str);
628				Err(http::Error::Unknown)
629			},
630		}?;
631
632		log::warn!("Got price: {} cents", price);
633
634		Ok(price)
635	}
636
637	/// Parse the price from the given JSON string using `lite-json`.
638	///
639	/// Returns `None` when parsing failed or `Some(price in cents)` when parsing is successful.
640	fn parse_price(price_str: &str) -> Option<u32> {
641		let val = lite_json::parse_json(price_str);
642		let price = match val.ok()? {
643			JsonValue::Object(obj) => {
644				let (_, v) = obj.into_iter().find(|(k, _)| k.iter().copied().eq("USD".chars()))?;
645				match v {
646					JsonValue::Number(number) => number,
647					_ => return None,
648				}
649			},
650			_ => return None,
651		};
652
653		let exp = price.fraction_length.saturating_sub(2);
654		Some(price.integer as u32 * 100 + (price.fraction / 10_u64.pow(exp)) as u32)
655	}
656
657	/// Add new price to the list.
658	fn add_price(maybe_who: Option<T::AccountId>, price: u32) {
659		log::info!("Adding to the average: {}", price);
660		<Prices<T>>::mutate(|prices| {
661			if prices.try_push(price).is_err() {
662				prices[(price % T::MaxPrices::get()) as usize] = price;
663			}
664		});
665
666		let average = Self::average_price()
667			.expect("The average is not empty, because it was just mutated; qed");
668		log::info!("Current average price is: {}", average);
669		// here we are raising the NewPrice event
670		Self::deposit_event(Event::NewPrice { price, maybe_who });
671	}
672
673	/// Calculate current average price.
674	fn average_price() -> Option<u32> {
675		let prices = Prices::<T>::get();
676		if prices.is_empty() {
677			None
678		} else {
679			Some(prices.iter().fold(0_u32, |a, b| a.saturating_add(*b)) / prices.len() as u32)
680		}
681	}
682
683	fn validate_transaction_parameters(
684		block_number: &BlockNumberFor<T>,
685		new_price: &u32,
686	) -> TransactionValidity {
687		// Now let's check if the transaction has any chance to succeed.
688		let next_unsigned_at = NextUnsignedAt::<T>::get();
689		if &next_unsigned_at > block_number {
690			return InvalidTransaction::Stale.into()
691		}
692		// Let's make sure to reject transactions from the future.
693		let current_block = <system::Pallet<T>>::block_number();
694		if &current_block < block_number {
695			return InvalidTransaction::Future.into()
696		}
697
698		// We prioritize transactions that are more far away from current average.
699		//
700		// Note this doesn't make much sense when building an actual oracle, but this example
701		// is here mostly to show off offchain workers capabilities, not about building an
702		// oracle.
703		let avg_price = Self::average_price()
704			.map(|price| if &price > new_price { price - new_price } else { new_price - price })
705			.unwrap_or(0);
706
707		ValidTransaction::with_tag_prefix("ExampleOffchainWorker")
708			// We set base priority to 2**20 and hope it's included before any other
709			// transactions in the pool. Next we tweak the priority depending on how much
710			// it differs from the current average. (the more it differs the more priority it
711			// has).
712			.priority(T::UnsignedPriority::get().saturating_add(avg_price as _))
713			// This transaction does not require anything else to go before into the pool.
714			// In theory we could require `previous_unsigned_at` transaction to go first,
715			// but it's not necessary in our case.
716			//.and_requires()
717			// We set the `provides` tag to be the same as `next_unsigned_at`. This makes
718			// sure only one transaction produced after `next_unsigned_at` will ever
719			// get to the transaction pool and will end up in the block.
720			// We can still have multiple transactions compete for the same "spot",
721			// and the one with higher priority will replace other one in the pool.
722			.and_provides(next_unsigned_at)
723			// The transaction is only valid for next 5 blocks. After that it's
724			// going to be revalidated by the pool.
725			.longevity(5)
726			// It's fine to propagate that transaction to other peers, which means it can be
727			// created even by nodes that don't produce blocks.
728			// Note that sometimes it's better to keep it for yourself (if you are the block
729			// producer), since for instance in some schemes others may copy your solution and
730			// claim a reward.
731			.propagate(true)
732			.build()
733	}
734}