SkyhookChain Finality

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: submitOrphan followed by linkOrphan(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.

Oracles filling the block storeInteractive

Zcash produces blocks in order, but they can reach the contract in any order. Submit blocks and watch how they're stored.

On-chain block store
Each submission verifies the block's Equihash solution once, paid for by the oracle that submits it. A block whose predecessor is missing is stored as an orphan; when the predecessor is present, the block is submitted and linked in one call, and an orphan whose predecessor arrives later can be linked with 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.

Who gets a rollup's feeInteractive
Other oracles
Validator, including its own blocks
Each oracle-submitted block earns
Oracles are paid per block a rollup reuses. Under the default curve, an 8-block rollup pays 1.75% per block (14% in total), and the per-block share shrinks as the rollup grows, so the oracles' total approaches but never exceeds 50%. A rollup for a 1,000-block gap reuses about 154 blocks; one for a 100,000-block gap about 254. A validator that submitted blocks itself is their oracle and keeps that share. The curve and the fee amounts are set by each deployment; these are illustrative.

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.

How much can oracles charge?Interactive
Most oracles can charge

Costs are for one rollup on Base at ~0.005 gwei, with ETH at Coinbase's spot price when this site was built. Fully sampled: 1.1M gas to initiate plus 2,100 gas per stored sample, plus the oracles' charge for every block reused (samples, main block and 3 head blocks). Root-anchored: about 36,500 gas per sample plus a constant 4M, always one transaction, nothing owed to oracles. Without oracles, a fully sampled rollup submits every block at about 950k gas each. Cement and finalize gas are the same in both modes and left out.

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.

See also