SkyhookChain Finality

Chain Finality

Chain finality is the point at which a Zcash block can be treated as permanent. A Skyhook contract needs that guarantee before it releases funds: rebuilding a transaction ID proves that a transaction is in some block, but not that the block belongs to the real Zcash chain or that it will stay there. Skyhook establishes both facts on Ethereum through rollups: bundles of Zcash blocks, built by anyone, that prove a chosen block is on the main chain (using FlyClient samples of the history behind it) and buried under enough work (using the blocks that follow it).

By default Skyhook uses full FlyClient sampling, which is secure even if no participant checks anything off-chain. That takes many samples, about 150 for a 1,000-block stretch of history, but oracles keep blocks on-chain, so a rollup only reads them from storage, and initiating one costs about 1.4M gas for a 1,000-block gap (1.1M for the main block (about 950k to verify its Equihash, plus the storage writes that create the rollup) plus 2,100 gas to read each stored sample). Without any oracles or validators, a swap can still finalize itself by submitting every block it needs, over several transactions. Rollups can also be root-anchored: participants who check the chain themselves agree on a trusted root, and the rollup then finalizes in a single transaction whether or not any oracle is running.

There are no stakers, committees or votes in any of these modes: a rollup is either valid, in which case anyone can check it, or it is never joined and its builder has wasted gas.

Why finality is needed

Zcash, like other proof-of-work blockchains, provides only probabilistic finality. Two miners occasionally find competing blocks at the same height, the network resolves the tie as further blocks arrive, and transactions in the abandoned branch return to the mempool unconfirmed. Each block built on top of a given block makes its displacement less likely. A contract that pays out against a freshly mined block is therefore exposed to reorganization, and an Ethereum contract can’t see Zcash’s peer-to-peer network or its fork-choice rule. It needs evidence, submitted to it, that the block is both on the main chain and deep enough to stay there.

That evidence also has to defeat a stronger adversary: someone who mines a private fork under exactly Zcash’s rules, with genuine proof-of-work. Every block they show would look valid. What they can’t fake cheaply is the accumulated work of the real chain, which is what FlyClient sampling tests; see Proving Chain Identity.

Oracles

Main article: Oracles and the Block Store

Zcash blocks reach the chain through oracles, which watch for each new block and submit it, as an orphan or linked to its predecessor. Each block’s Equihash proof-of-work is verified once, at submission, for about 950k gas, and the block is stored, so everything built later references it by hash. Oracles are trustless, because an invalid block is simply rejected, and anyone can run one. Each rollup pays oracles a share of its fee for the blocks it reuses, at most half of the fee in total.

Rollups

Main article: Rollups

A rollup targets one Zcash block, the main block. Its builder, called a validator though no stake is involved, references the main block and the three blocks after it (the head), and the rollup requires tail samples: blocks from the history between the last finalized block and the main block, chosen by FlyClient sampling. The number of samples grows logarithmically with that gap: about 30 for 100 blocks, 150 for 1,000, 200 for 10,000 and 250 for 100,000. Each verification performs several independent FlyClient sampling runs of about 5 × log₁₀(gap) samples each: ten runs for a gap of 1,000 blocks or more, five below 1,000, three below 500 and two below 100. Anyone can supply a sample, and each must carry a valid Equihash solution and a valid difficulty, or already be in the block store. Once every sample is satisfied, the rollup is valid and can be finalized, which opens the locks of the transactions that joined it and pays their fees to the validator.

StageWhat happensGas, oracle-stored blocks
InitiateChoose the main block, aggregate transactions waiting for finality, reference the blocks1.1M + 2,100 per sample (~1.4M for a 1,000-block gap)
CementSatisfy the tail samples (anyone may supply them)1.3–1.5M (an Equihash verification plus bookkeeping)
FinalizeOpen the joined transactions’ locks and pay the validatorGrows with the number of transactions it notifies

With every sample already in the block store, initiation costs 1.1M gas for the main block (about 950k to verify its Equihash, plus the storage writes that create the rollup) plus 2,100 gas to read each sample: about 1.16M for a 100-block gap, 1.42M for 1,000 blocks and 1.63M for 100,000.

One-shot finality

Main article: One-Shot Finality

A swap doesn’t have to wait for someone else’s rollup. It can initiate, cement and finalize a rollup itself in one transaction; when oracles have stored the blocks it needs, initiation costs about 1.4M gas for a 1,000-block gap (1.1M for the main block (about 950k to verify its Equihash, plus the storage writes that create the rollup) plus 2,100 gas to read each stored sample) and cementing 1.3–1.5M (another Equihash verification plus bookkeeping), so a one-shot costs about 2.7–2.9M gas plus finalizing its own transaction, roughly four cents on Base. This is no more or less trustworthy than joining a shared rollup; it simply suits a swap that is its own only client. The rollup it creates stays on-chain, so later swaps can reference it too.

The worst case

If no oracle has submitted the blocks and no validator has built a rollup, a swap can still reach full finality on its own by submitting every block it needs and verifying each one’s Equihash solution, at about 950k gas per block. For a 1,000-block gap that is 154 blocks, about 146M gas; because a single Ethereum transaction is capped at about 16.8M gas, it takes nine transactions, a little under two dollars on Base. A 100,000-block gap needs about 254 blocks, around 15 transactions and about three dollars. The swap’s safety doesn’t depend on anyone else showing up; only its cost does.

Root-anchored rollups

Main articles: Rollups § Two modes, Proving Chain Identity § Online-offline finality

Every rollup is either fully sampled, the default described above, or root-anchored. A root-anchored rollup is for participants who are willing to check the chain themselves; they agree on the root when they agree the quote. The quote includes the root of the counterparty’s Merkle Mountain Range at the last block it knows. Any block proven to lie under that root is one the counterparty already trusts, so instead of verifying its proof-of-work the contract checks an MMR proof, about 21,500 gas plus 15,000 for its calldata. A 100-block gap then costs about 1.1M gas for its samples and a 100,000-block gap about 9.1M, plus a constant 4M for the rollup’s blocks after the main block: about 5.1M and 13.1M gas in total, so even three months without an oracle fits in a single transaction under Ethereum’s 16.8M cap. The party whose escrow is at risk has to check the root against its own view of the chain before agreeing to it.

Root-anchored rollups are not cheaper than fully sampled ones while oracles are running, but they make the bridge independent of oracles: whatever oracles do, a swap can finalize in one transaction, which also caps what oracles can charge. The contract records each rollup’s mode, and a root-anchored rollup never becomes the starting point for a fully sampled one, so the default guarantee is never weakened by someone else’s root.

Cost

On Base, Skyhook’s home network, gas costs around 0.005 gwei, so finality is cheap in absolute terms: initiating a rollup from stored blocks costs about two cents at an ETH price of $2,500, online-offline finality costs about six to seventeen cents, and even the worst case costs a few dollars.

What finality costsInteractive
Default, with oracles
+ 1.3–1.5M to cement, + finalizing
No oracles, no validators
Root-anchored, opt-in

The default rollup uses full FlyClient sampling: tail samples plus the main block and 3 head blocks. With oracles having stored those blocks, initiating the rollup costs 1.1M gas for the main block (its Equihash plus the storage writes that create the rollup) plus 2,100 per stored sample, shared by the transactions that join it. With no oracles or validators, a swap submits every block itself at about 950k gas each, split into transactions of at most about 16.8M gas. Online-offline finality proves each sample under a root both parties agreed at quote time, at about 36.5k gas each, plus a constant 4M for the rollup's blocks after the main block; it always fits in one transaction. Sample counts follow the approximate schedule on the Rollups page; the ETH price starts at Coinbase's spot price when this site was built.

Supporting machinery

Main articles: The Merkle Mountain Range, Proof-of-Work Verification on the EVM, What Lives On-Chain, Proving Chain Identity

Header history is recorded in a Merkle Mountain Range, an append-only structure whose proofs stay short however long the chain grows. Equihash proof-of-work is verified directly on the EVM, including for headers whose parent the contract has never seen. Once a rollup is final, the anchor contract keeps only what later claims need: header hashes, the MMR peaks that summarize them, and inclusion roots. The one configurable parameter, a per-bridge difficulty floor, is explained on the chain identity page.

The design draws on the FlyClient protocol of Bünz, Kiayias and Leonardos for its sampling arguments, and on the Merkle Mountain Range literature beneath it.1 Zcash already commits to FlyClient-compatible history in every block header.2

See also

References

  1. Bünz, Kiayias and Leonardos, FlyClient: Super-Light Clients for Cryptocurrencies, IEEE S&P 2020. ↩

  2. ZIP 221: FlyClient and history commitments in block headers. ↩