Expand description
Fork-local utilities for pallet offchain workers (OCWs).
This module does not provide canonical chain selection or consensus.
Instead, it runs on top of a pallet’s OCW execution and maintains a deterministic local fork graph so the pallet can answer:
"what was my local state on this branch?"A Branch represents a continuous stream of blocks extending on top
of each other along the same path.
A -> B -> C -> D
same branchAs long as blocks continue as direct children, the same branch is reused and only the branch head moves forward.
When a division occurs (a sibling block appears at the same ancestry), a new fork branch is created.
A -> B -> C
|-- D
|-- D'Here:
Dis the original branch continuationD'is the new sibling branchA -> B -> Cis the parent branch of both paths
Each branch carries its own fork-local scope through ForkScopes.
When a new sibling branch is created, it inherits from the parent branch
using Accrete:
scope(D') = scope(C).accrete()This allows each fork path to maintain isolated local state while still preserving inherited lineage state.
§Usage
Every pallet using this system should begin its OCW execution with
ForksHandler::start:
fn offchain_worker(block_number: BlockNumberFor<T>) {
<Self as ForksHandler<T, MyForkScope>>::start(
Some("my-pallet"),
Some(LogFormatter::default()),
|| {
// pallet-specific OCW logic here
}
);
}ForksHandler::start handles:
- longest-chain extension vs sibling fork creation
- missing branch recovery (during client inactivity)
- safe branch resolution before OCW logic executes
The OCW closure (main logic) runs only after branch state is valid and ready to map the fork graph.
§Navigation
Since fork resolution is delayed by one block:
block N executes
-> block N - 1 is resolved and persistedthe current executing block is not yet inserted into the local fork graph.
For normal OCW access, use ForksHandler::get_prev_block_branch
to retrieve the previous block’s (N - 1) resolved branch.
From that branch, navigation can continue using ForkAction and
ForksHandler::transition, or helpers like:
This allows movement across:
- parent branches
- child branches
- sibling branches
- root ancestry
This provides deterministic branch-local traversal without relying on canonical consensus routing.
The system is intentionally fork-aware, scope-first, and best-effort: it tracks local execution branches, not global consensus finality.
Structs§
- Branch
- Fork branch details pertaining to a block and the specialized scope state defined by the pallet/module for which the local fork graph exists.
Enums§
- Fork
Action - Deterministic branch traversal and navigation actions for moving across the local fork graph.
Constants§
- HEAD_
BLOCK - Highest known longest-chain head used for fork detection.
Traits§
- Fork
Scopes - A scope is an abstract area for storing branch-local state and anything logically related to that fork, such as:
- Forks
Handler - Fork-aware local branch collection framework for pallet/module state.
Functions§
- block_
key 🔒 - Block routing identity key
- branch_
key 🔒 - Deterministic branch identity key
- divider_
key 🔒 - Divider identity key
- load_
value 🔒 - Load and decode a value from Persistent Node-Local storage.
- make_
hash 🔒 - Deterministic storage hash builder.
- store_
encoded 🔒 - Persist an encoded value into Persistent Node-Local storage.