-
Notifications
You must be signed in to change notification settings - Fork 710
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add documentation around FRAME Offchain workers #3463
Merged
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
0e034eb
add reference docs for offchain workers
kianenigma 125054d
Merge branch 'master' of github.com:paritytech/polkadot-sdk into kiz-…
kianenigma 20b8f38
add example
kianenigma 03c1aeb
add example
kianenigma c61dcd4
Update docs/sdk/src/reference_docs/frame_offchain_workers.rs
kianenigma 1489c50
Merge branch 'master' into kiz-ocw-docs
kianenigma 4b83176
Master.into()
kianenigma d2a307c
Merge branch 'kiz-ocw-docs' of github.com:paritytech/polkadot-sdk int…
kianenigma 1ab6202
fmt
kianenigma 6ba1737
fix
kianenigma ab654bd
Merge branch 'master' of github.com:paritytech/polkadot-sdk into kiz-…
kianenigma e410d9c
fix again
kianenigma 175e2fe
Merge branch 'master' into kiz-ocw-docs
kianenigma File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
//! # Offchain Workers | ||
//! | ||
//! This reference document explains how offchain workers work in Substrate and FRAME. The main | ||
//! focus is upon FRAME's implementation of this functionality. Nonetheless, offchain workers are a | ||
//! Substrate-provided feature and can be used with possible alternatives to [`frame`] as well. | ||
//! | ||
//! Offchain workers are a commonly misunderstood topic, therefore we explain them bottom-up, | ||
//! starting at the fundamentals and then describing the developer interface. | ||
//! | ||
//! ## Context | ||
//! | ||
//! Recall from [`crate::reference_docs::wasm_meta_protocol`] that the node and the runtime | ||
//! communicate with one another via host functions and runtime APIs. Many of these interactions | ||
//! contribute to the actual state transition of the blockchain. For example [`sp_api::Core`] is the | ||
//! main runtime API that is called to execute new blocks. | ||
//! | ||
//! Offchain workers are in principle not different in any way: It is a runtime API exposed by the | ||
//! wasm blob ([`sp_offchain::OffchainWorkerApi`]), and the node software calls into it when it | ||
//! deems fit. But, crucially, this API call is different in that: | ||
//! | ||
//! 1. It can have no impact on the state ie. it is _OFF (the) CHAIN_. If any state is altered | ||
//! during the execution of this API call, it is discarded. | ||
//! 2. It has access to an extended set of host functions that allow the wasm blob to do more. For | ||
//! example, call into HTTP requests. | ||
//! | ||
//! > The main way through which an offchain worker can interact with the state is by submitting an | ||
//! > extrinsic to the chain. This is the ONLY way to alter the state from an offchain worker. | ||
//! > [`pallet_example_offchain_worker`] provides an example of this. | ||
//! | ||
//! | ||
//! Given the "Off Chain" nature of this API, it is important to remember that calling this API is | ||
//! entirely optional. Some nodes might call into it, some might not, and it would have no impact on | ||
//! the execution of your blockchain because no state is altered no matter the execution of the | ||
//! offchain worker API. | ||
//! | ||
//! Substrate's CLI allows some degree of configuration about this, allowing node operators to | ||
//! specify when they want to run the offchain worker API. See | ||
//! [`sc_cli::RunCmd::offchain_worker_params`]. | ||
//! | ||
//! ## Nondeterministic Execution | ||
//! | ||
//! Needless to say, given the above description, the code in your offchain worker API can be | ||
//! nondeterministic, as it is not part of the blockchain's STF, so it can be executed at unknown | ||
//! times, by unknown nodes, and has no impact on the state. This is why an HTTP | ||
//! ([`sp_runtime::offchain::http`]) API is readily provided to the offchain worker APIs. Because | ||
//! there is no need for determinism in this context. | ||
//! | ||
//! > A common mistake here is for novice developers to see this HTTP API, and imagine that | ||
//! > `polkadot-sdk` somehow magically solved the determinism in blockchains, and now a blockchain | ||
//! > can make HTTP calls and it will all work. This is absolutely NOT the case. An HTTP call made | ||
//! > by the offchain worker is non-deterministic by design. Blockchains can't and always won't be | ||
//! > able to perform non-deterministic operations such as making HTTP calls to a foreign server. | ||
//! | ||
//! ## FRAME's API | ||
//! | ||
//! [`frame`] provides a simple API through which pallets can define offchain worker functions. This | ||
//! is part of [`frame::traits::Hooks`], which is implemented as a part of | ||
//! [`frame::pallet_macros::hooks`]. | ||
//! | ||
//! ``` | ||
//! | ||
//! #[frame::pallet] | ||
//! pub mod pallet { | ||
//! use frame::prelude::*; | ||
//! | ||
//! #[pallet::config] | ||
//! pub trait Config: frame_system::Config {} | ||
//! | ||
//! #[pallet::pallet] | ||
//! pub struct Pallet<T>(_); | ||
//! | ||
//! #[pallet::hooks] | ||
//! impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> { | ||
//! fn offchain_worker(block_number: BlockNumberFor<T>) { | ||
//! // ... | ||
//! } | ||
//! } | ||
//! } | ||
//! ``` | ||
//! | ||
//! Additionally, [`sp_runtime::offchain`] provides a set of utilities that can be used to moderate | ||
//! the execution of offchain workers. | ||
//! | ||
//! ## Think Twice: Why Use Substrate's Offchain Workers? | ||
//! | ||
//! Consider the fact that in principle, an offchain worker code written using the above API is no | ||
//! different than an equivalent written with an _actual offchain interaction library_, such as | ||
//! [Polkadot-JS](https://polkadot.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). | ||
//! | ||
//! They can both read from the state, and have no means of updating the state, other than the route | ||
//! of submitting an extrinsic to the chain. Therefore, it is worth thinking twice before embedding | ||
//! a logic as a part of Substrate's offchain worker API. Does it have to be there? can it not be a | ||
//! simple, actual offchain application that lives outside of the chain's WASM blob? | ||
//! | ||
//! Some of the reasons why you might want to do the opposite, and actually embed an offchain worker | ||
//! API into the WASM blob are: | ||
//! | ||
//! * Accessing the state is easier within the `offchain_worker` function, as it is already a part | ||
//! of the runtime, and [`frame::pallet_macros::storage`] provides all the tools needed to read | ||
//! the state. Other client libraries might provide varying degrees of capability here. | ||
//! * It will be updated in synchrony with the runtime. A Substrate's offchain application is part | ||
//! of the same WASM blob, and is therefore guaranteed to be up to date. | ||
//! | ||
//! For example, imagine you have modified a storage item to have a new type. This will possibly | ||
//! require a [`crate::reference_docs::frame_runtime_upgrades_and_migrations`], and any offchain | ||
//! code, such as a Polkadot-JS application, will have to be updated to reflect this change. Whereas | ||
//! the WASM offchain worker code is guaranteed to already be updated, or else the runtime code will | ||
//! not even compile. | ||
//! | ||
//! | ||
//! ## Further References | ||
//! | ||
//! - <https://forum.polkadot.network/t/offchain-workers-design-assumptions-vulnerabilities/2548> | ||
//! - <https://substrate.stackexchange.com/questions/11058/how-can-i-create-ocw-that-wont-activates-every-block-but-will-activates-only-w/11060#11060> | ||
//! - [Offchain worker example](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/examples/offchain-worker) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One of the notable properties, as you mentioned, is that OCW is part of the runtime API, making it more accessible. If your chain is operational, it implies that your OCW can be triggered by users. There should be use cases for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interestingly, this is exactly what the user in https://substrate.stackexchange.com/questions/11058/how-can-i-create-ocw-that-wont-activates-every-block-but-will-activates-only-w/11060#11060 asked for, but there is no easy way to do this yet, right? I suppose the best you can do is to link it to
state_call
, and trigger it.