Oracles and the Block Store
An oracle in Skyhook is a participant that keeps Zcash blocks on the chain. Its only job is to watch for the latest Zcash block and submit it to the Skyhook contracts, where its Equihash proof-of-work is verified once and the block is stored. Because blocks are already on-chain, validators building rollups don’t need to upload blocks or pay to verify their solutions: they reference blocks by hash, which makes validation very cheap. In return, every rollup pays the oracles whose blocks it reuses a share of its validator fee. Oracles are what make Skyhook’s default, full FlyClient sampling affordable: a rollup that needs dozens of sampled blocks only references them.
Skyhook’s oracles are trustless. Unlike the price oracles of other systems, they report nothing that has to be believed: a block either carries a valid proof-of-work, or the contract rejects it. An oracle can make blocks available sooner, but it can’t make an invalid block acceptable.
Submitting blocks
Zcash produces blocks one after another, but they can reach the contract in any order, from any oracle. The contract stores them in a modified key-value block store, designed to categorize blocks cleanly even when they arrive as orphans, without their predecessors.
An oracle submits a block in one of two ways:
- If the block’s predecessor isn’t on-chain, the oracle submits it as an orphan with
submitOrphan. - If the predecessor is already on-chain, the oracle submits it as a subsequent block:
submitOrphanfollowed bylinkOrphan(prevBlockHash), wrapped in a single multicall.
Linking is what tells the contract that one block directly follows another. That is how a rollup can show that its head blocks are the blocks that follow its main block, rather than unrelated blocks of the same height range.
linkOrphan. Validators later reference these blocks by hash instead of uploading them, and pay the
submitting oracles a share of their fee for each block reused. Heights are illustrative.
Each submission verifies the block’s Equihash solution in full, about 950k gas per block; the details are in Proof-of-Work Verification on the EVM. That cost is paid once, by the submitting oracle, and every later rollup that uses the block avoids it.
Rewards
A rollup pays part of its total validator fee to the oracles that submitted the blocks it reuses, split by block. With full sampling a rollup can reuse dozens or hundreds of blocks, so a flat rate per block would eventually hand oracles more than the whole fee. The default curve therefore pays 1.75% per block for a rollup of eight blocks (14% in total) and shrinks the per-block share as rollups grow, so that the oracles’ total approaches but never exceeds half of the fee: a 154-block rollup, typical for a 1,000-block gap, pays about 0.29% per block, 44% in total. The exact curve is an implementation decision for each deployment. This lets honest oracles recover what they spend on gas, and rewards them in proportion to how useful their blocks turn out to be. According to the grant application, a trustless oracle that publishes every block costs about $40 a day to run.
There is no registration to become an oracle, unless a particular deployment chooses to require it. A validator that finds a block missing can simply submit it itself, acting as its own oracle, and keep that block’s share of the fee.
Bounded by the alternative
Oracles can’t hold rollups hostage. A root-anchored rollup can always finalize in a single transaction, about 5–13M gas, without any oracle at all, and it pays oracles nothing for samples it proves under its own root. Oracles therefore compete with that alternative: one that withholds blocks, or whose blocks cost more than proving them under a root, is simply routed around. While oracles are running, though, reading a stored block costs 2,100 gas against 36,500 for proving it under a root, so stored blocks remain by far the cheapest way to build a rollup.
Near misses
The block store also makes it cheap to finalize a transaction that just missed a rollup. Instead of waiting for the next one, the transaction can initiate its own rollup. The gap between the last finalized block, the previous rollup’s main block, and the current block is very short, and most of the blocks it needs to sample there have probably already been uploaded by oracles or by the previous rollup, so referencing them costs little. A short gap needs only a couple of sampling runs, and the blocks it samples are the most likely to be stored already.