很多时候我们需要先对链下的数据作查询或处理，然后才将其提交到链上。 常规的做法是通过预言机（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.
- 一个功能齐全的 HTTP 客户端，使链下工作机可访问和获取到外部数据。
- 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.
值得注意的是，链下工作机的交易不会受到常规交易验证的约束。 所以需要另外实现一套交易验证机制 (例如投票，取平均值，检查提交人签名或简单地 "信任")，以确定哪些信息能够记录在链上。
想要了解更多如何在你下一个 runtime 开发项目中使用到链下工作机，请参考我们的 开发指南。
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.