很多时候我们需要先对链下的数据作查询或处理，然后才将其提交到链上。 常规的做法是通过预言机（Oracles）。 预言机是一种外部服务，通常用于监听区块链事件，并根据条件触发任务。 当这些任务执行完毕，执行结果会以交易的形式提交至区块链上。 虽然这种方法可行，但在安全性、可扩展性，和基本效率方面仍然存在一些缺陷。
To make the off-chain data integration secure and more efficient, Substrate provides off-chain features:
Off-Chain Worker (OCW) subsystem allows execution of long-running and possibly non- deterministic tasks (e.g. web requests, encryption/decryption and signing of data, random number generation, CPU-intensive computations, enumeration/aggregation of on-chain data, etc.) that could otherwise require longer than the block execution time.
Off-Chain Storage offers storage that is local to a Substrate node that can be accessed both by off-chain workers (both read and write access) and on-chain logic (write access via off-chain indexing but not read access). This is great for different worker threads to communicate to each others and for storing user- / node-specific data that does not require consensus over the whole network.
Off-Chain Indexing allows the runtime, if opted-in, to write directly to the off-chain storage independently from OCWs. This serves as a local/temporary storage for on-chain logic and complement to its on-chain state.
Off-chain features run in their own Wasm execution environment outside of the Substrate runtime. This separation of concerns makes sure that block production is not impacted by long-running off-chain tasks. However, as the off-chain features are declared in the same code as the runtime, they can easily access on-chain state for their computations.
Off-chain workers have access to extended APIs for communicating with the external world:
- Ability to submit transactions (either signed or unsigned) to the chain to publish computation results .
- A fully-featured HTTP client allowing the worker to access and fetch data from external services .
- An additional, local key-value database shared between all off-chain workers .
- Access to the node's precise local time.
- The ability to sleep and resume work.
OCWs can be initiated from within a special function in your runtime implementation,
fn offchain_worker(block: T::BlockNumber). communicate results back to the chain, off-chain workers can submit signed or unsigned transactions to be included in subsequent blocks.
值得注意的是，链下工作机的交易不会受到常规交易验证的约束。 所以需要另外实现一套交易验证机制 (例如投票，取平均值，检查提交人签名或简单地 "信任")，以确定哪些信息能够记录在链上。
As its name indicated, the storage is not stored on-chain. It can be accessed by off-chain worker threads (both read and write access) and on-chain logic (write only, refer to off-chain indexing below). This storage is not populated among the blockchain network and does not need to have consensus computation over it.
As an off-chain worker thread is being spawned off during each block import, there could be more than one off-chain worker thread running at any given time. So, similar to any multi-threaded programming environment, there are also utilities to mutex lock the storage when accessing them for data consistency.
Off-chain storage serves as a bridge for various off-chain worker threads to communicate to each others and between off-chain and on-chain logics. It can also be read using remote procedure calls (RPC) so it fits the use case of storing indefinitely growing data without over-consuming the on-chain storage.
Storage in the context of blockchain is mostly about on-chain state. But it is expensive (as it is populated to each node in the network) and not recommended for historical or user-generated data which grow indefinitely over time.
We have off-chain storage for this purpose. In addition of being accessible by OCWs, Substrate also includes a feature called "off-chain indexing" allowing the runtime to write directly to the off-chain storage independently from OCWs. Nodes have to opt-in for persistency of this data via
--enable-offchain-indexing flag when starting up the Substrate node.
Unlike OCWs, which are not executed during initial blockchain synchronization, off-chain indexing is populating the storage every time a block is processed, so the data is always consistent and will be exactly the same for every node with indexing enabled.
To look at concrete examples of off-chain workers and how to use them in runtime development, refer to the following sections in Substrate Recipes: