#
pezkuwi_sdk_docs/reference_docs/
frame_offchain_workers.rs

    1//! # Offchain Workers
    2//!
    3//! This reference document explains how offchain workers work in Bizinikiwi and FRAME. The main
    4//! focus is upon FRAME's implementation of this functionality. Nonetheless, offchain workers are a
    5//! Bizinikiwi-provided feature and can be used with possible alternatives to [`frame`] as well.
    6//!
    7//! Offchain workers are a commonly misunderstood topic, therefore we explain them bottom-up,
    8//! starting at the fundamentals and then describing the developer interface.
    9//!
    10//! ## Context
    11//!
    12//! Recall from [`crate::reference_docs::wasm_meta_protocol`] that the node and the runtime
    13//! communicate with one another via host functions and runtime APIs. Many of these interactions
    14//! contribute to the actual state transition of the blockchain. For example [`pezsp_api::Core`] is
    15//! the main runtime API that is called to execute new blocks.
    16//!
    17//! Offchain workers are in principle not different in any way: It is a runtime API exposed by the
    18//! wasm blob ([`pezsp_offchain::OffchainWorkerApi`]), and the node software calls into it when it
    19//! deems fit. But, crucially, this API call is different in that:
    20//!
    21//! 1. It can have no impact on the state ie. it is _OFF (the) CHAIN_. If any state is altered
    22//!    during the execution of this API call, it is discarded.
    23//! 2. It has access to an extended set of host functions that allow the wasm blob to do more. For
    24//!    example, call into HTTP requests.
    25//!
    26//! > The main way through which an offchain worker can interact with the state is by submitting an
    27//! > extrinsic to the chain. This is the ONLY way to alter the state from an offchain worker.
    28//! > [`pezpallet_example_offchain_worker`] provides an example of this.
    29//!
    30//!
    31//! Given the "Off Chain" nature of this API, it is important to remember that calling this API is
    32//! entirely optional. Some nodes might call into it, some might not, and it would have no impact on
    33//! the execution of your blockchain because no state is altered no matter the execution of the
    34//! offchain worker API.
    35//!
    36//! Bizinikiwi's CLI allows some degree of configuration about this, allowing node operators to
    37//! specify when they want to run the offchain worker API. See
    38//! [`pezsc_cli::RunCmd::offchain_worker_params`].
    39//!
    40//! ## Nondeterministic Execution
    41//!
    42//! Needless to say, given the above description, the code in your offchain worker API can be
    43//! nondeterministic, as it is not part of the blockchain's STF, so it can be executed at unknown
    44//! times, by unknown nodes, and has no impact on the state. This is why an HTTP
    45//! ([`pezsp_runtime::offchain::http`]) API is readily provided to the offchain worker APIs. Because
    46//! there is no need for determinism in this context.
    47//!
    48//! > A common mistake here is for novice developers to see this HTTP API, and imagine that
    49//! > `pezkuwi-sdk` somehow magically solved the determinism in blockchains, and now a blockchain
    50//! > can make HTTP calls and it will all work. This is absolutely NOT the case. An HTTP call made
    51//! > by the offchain worker is non-deterministic by design. Blockchains can't and always won't be
    52//! > able to perform non-deterministic operations such as making HTTP calls to a foreign server.
    53//!
    54//! ## FRAME's API
    55//!
    56//! [`frame`] provides a simple API through which pallets can define offchain worker functions. This
    57//! is part of [`pezframe::traits::Hooks`], which is implemented as a part of
    58//! [`pezframe::pezpallet_macros::hooks`].
    59//!
    60//! ```
    61//! #[pezframe::pezpallet]
    62//! pub mod pezpallet {
    63//! 	use pezframe::prelude::*;
    64//!
    65//! 	#[pezpallet::config]
    66//! 	pub trait Config: pezframe_system::Config {}
    67//!
    68//! 	#[pezpallet::pezpallet]
    69//! 	pub struct Pezpallet<T>(_);
    70//!
    71//! 	#[pezpallet::hooks]
    72//! 	impl<T: Config> Hooks<BlockNumberFor<T>> for Pezpallet<T> {
    73//! 		fn offchain_worker(block_number: BlockNumberFor<T>) {
    74//! 			// ...
    75//! 		}
    76//! 	}
    77//! }
    78//! ```
    79//!
    80//! Additionally, [`pezsp_runtime::offchain`] provides a set of utilities that can be used to
    81//! moderate the execution of offchain workers.
    82//!
    83//! ## Think Twice: Why Use Bizinikiwi's Offchain Workers?
    84//!
    85//! Consider the fact that in principle, an offchain worker code written using the above API is no
    86//! different than an equivalent written with an _actual offchain interaction library_, such as
    87//! [Pezkuwi-JS](https://pezkuwi.js.org/docs/), or any of the other ones listed [here](https://github.com/substrate-developer-hub/awesome-substrate?tab=readme-ov-file#client-libraries).
    88//!
    89//! They can both read from the state, and have no means of updating the state, other than the route
    90//! of submitting an extrinsic to the chain. Therefore, it is worth thinking twice before embedding
    91//! a logic as a part of Bizinikiwi's offchain worker API. Does it have to be there? Can it not be a
    92//! simple, actual offchain application that lives outside of the chain's WASM blob?
    93//!
    94//! Some of the reasons why you might want to do the opposite, and actually embed an offchain worker
    95//! API into the WASM blob are:
    96//!
    97//! * Accessing the state is easier within the `offchain_worker` function, as it is already a part
    98//!   of the runtime, and [`pezframe::pezpallet_macros::storage`] provides all the tools needed to read
    99//!   the state. Other client libraries might provide varying degrees of capability here.
    100//! * It will be updated in synchrony with the runtime. A Bizinikiwi's offchain application is part
    101//!   of the same WASM blob, and is therefore guaranteed to be up to date.
    102//!
    103//! For example, imagine you have modified a storage item to have a new type. This will possibly
    104//! require a [`crate::reference_docs::frame_runtime_upgrades_and_migrations`], and any offchain
    105//! code, such as a Pezkuwi-JS application, will have to be updated to reflect this change. Whereas
    106//! the WASM offchain worker code is guaranteed to already be updated, or else the runtime code will
    107//! not even compile.
    108//!
    109//!
    110//! ## Further References
    111//!
    112//! - <https://forum.network.pezkuwichain.io/t/offchain-workers-design-assumptions-vulnerabilities/2548>
    113//! - <https://exchange.pezkuwichain.app/questions/11058/how-can-i-create-ocw-that-wont-activates-every-block-but-will-activates-only-w/11060#11060>
    114//! - [Offchain worker example](https://github.com/pezkuwichain/pezkuwi-sdk/tree/main/bizinikiwi/pezframe/examples/offchain-worker)
    115//!
    116//! [`frame`]: crate::pezkuwi_sdk::frame_runtime