Proofs
A proof allows data served by Willow to be verified independently. Willow provides two kinds of proof:
- Log proofs (
willow_getLogsProof) establish that aneth_getLogsresult is complete and that every log in it is included in its block. They are built from SP1 proofs of the chain’s blocks and support any filter. - Transaction and receipt proofs (
willow_getTransactionProof,willow_getReceiptProof,willow_getBlockReceiptsProof) establish that a transaction, a receipt, or a block’s receipts match the block’s contents exactly. They are Merkle proofs against the block hash and are returned immediately. See Transaction and receipt proofs.
Proofs are optional. Every block is verified before Willow serves it regardless; a proof enables independent verification.
Scope of a log proof
Section titled “Scope of a log proof”For a filter and a block range, a log proof establishes two properties of the logs it yields:
- Inclusion. Every log is included in its block, with the values given.
- Completeness. No log in those blocks that matches the filter is omitted.
The following fields of each log are proven: address, topics, data,
blockNumber, transactionIndex, and logIndex. None of them can be altered,
and no log can be added or removed, without the proof failing.
The following are not covered by the proof: transactionHash,
blockTimestamp, the removed flag, and the blockHash of any block other
than the last of each part (the proof fixes the hash of the last block of each
part). Values computed from logs, such as prices, volumes, or balances, are out
of scope. Willow nonetheless verifies transactionHash, blockTimestamp, and
blockHash against the block hash before serving them.
A log proof commits every log in its blocks, not only those matching the request, so a proof can be requested with any filter.
Trust assumptions
Section titled “Trust assumptions”- One block hash. The proofs link every block in the range by hash, so the result applies to the chain that ends at the last proven block. That block’s hash is confirmed with a node of the chain selected by the verifying party, or the browser verifier verifies it against Ethereum.
- The soundness of SP1.
- The proving programs. A proof is accepted only if it was produced by a program whose verifying key the verifier has pinned. One block program and one segment program serve all seven chains, and the verifier confirms the chain to which each proof applies.
For the proven fields, no other dependency on Willow’s server exists: its
eth_getLogs response and all data sent with the proof are verified. The
browser verifier’s source is public in
willow-verify (MIT), with
the program keys it pins and a script that verifies that the page Willow serves
is built from it. The proving programs’ source is not yet public.
Proofs on request
Section titled “Proofs on request”Blocks are proven when a proof of them is first requested. Once a block is proven, its proof is retained permanently and reused for all accounts, so subsequent requests over it are served immediately.
willow_getLogsProof responds immediately over blocks that are already proven.
When the range contains blocks without a proof, Willow charges for the range,
queues a proof job for the missing blocks, and responds with -32000. The
message states when to retry, and error.data identifies the job:
{ "error": { "code": -32000, "data": { "estimatedSeconds": 171, "from": 26111374, "jobId": "j-1791025283-51e16463", "jobIds": ["j-1791025283-51e16463"], "retryAfterSeconds": 171, "status": "queued", "to": 26111377 }, "message": "proof not available yet: queued for blocks 26111374-26111377; retry in about 3 minutes" }, "id": 1, "jsonrpc": "2.0"}status: the stage of the job expected to finish last,queuedorrunning.jobId,jobIds: that job, and every job on which the request waits. A request queues one job per run of consecutive blocks without a proof.from,to: the first and last block on which the request waits.estimatedSeconds,retryAfterSeconds: when the proofs are expected to be ready, and when to retry (the same estimate, at most 600 seconds).
Call willow_getLogsProof again after retryAfterSeconds. A repeated request
while the job is open does not queue (or charge for) another job; the response
refers to the open job. Once the job is complete, the same call returns the
proof. A job can also be tracked with
willow_getProofJob.
Job duration depends on whether a prover is already running. On Ethereum, in testing, jobs of 4 to 20 blocks finished 5 to 8 minutes after the request, a 37-block job about 11 minutes after, and a complete 64-block window about 20 minutes after.
On chains proven in leaves of many blocks (every chain except Ethereum; see
Proof construction), a block whose
leaf is not yet complete cannot be proven until the chain produces the leaf’s
last block. Such a request is refused with -32000 and
{"status": "waiting", "from": N, "segmentEnd": E, "retryAfterSeconds": T} in
error.data.
Quotes and acceptance
Section titled “Quotes and acceptance”willow_quoteLogsProof takes the same filter as willow_getLogsProof and
reports, without charging or queuing anything, how much of the range is
proven, the cost, and the time required for the remainder:
{ "chainId": 1, "fromBlock": 26111374, "toBlock": 26111377, "blocks": 4, "provenBlocks": 0, "pendingBlocks": 0, "freshBlocks": 4, "proveBlocks": 4, "priceMicrosPerBlock": 20000, "amountMicros": 80000, "freshAmountMicros": 80000, "estimatedSeconds": 171, "acceptRequired": false, …}blocks,provenBlocks,pendingBlocks,freshBlocks: the number of blocks in the range, the number already proven, the number being proven by open jobs, and the number in neither state.proveBlocks: the blocks new jobs would prove. On chains with leaves of many blocks, these are the whole leaves containing the fresh blocks.priceMicrosPerBlock,amountMicros: the chain’s flat price, and the maximum cost of the range at that price. Blocks the account has already paid for are not charged again, so the charge can be lower.estimatedSeconds: the time until every block of the range has a proof.waitingFor: present when the range extends into a leaf the chain has not completed: the leaf’s last block.gpuSecondsPerBlock,gpuSeconds: the prover time the new jobs require.acceptRequired: whether a proof request for this range requires acceptance.unavailable: present when a proof request for the range would currently be refused, with the reason.
A request whose range costs more than $10 at the chain’s price requires
explicit acceptance. The cost includes every block of the range, proven or not,
so on Ethereum this applies to ranges of more than 500 blocks. Without
acceptance, the request is refused with -32602, error.data.status is
"quote", and error.data.quote contains the quote above. No charge is made:
proof needs an accept: N of this range's M blocks have no proof yet (ready in about T minutes); the range costs up to $X; send the request again with "acceptQuote": true to go aheadWhen every block of the range is already proven, the message states that instead.
Resend the request with "acceptQuote": true, either in the filter object or
in an options object following it:
{"jsonrpc":"2.0","id":1,"method":"willow_getLogsProof","params":[ {"fromBlock":"0x18e6400","toBlock":"0x18e647f","address":"0x…"}, {"acceptQuote": true}]}Proof pricing
Section titled “Proof pricing”Each proven block has one flat price per chain, from $0.00025 to $0.020 (see Units and pricing). The following rules apply:
- An already-proven block costs the same as an unproven one.
- An account never pays twice for the same block. Retrieving the same proof again, the parts of a proof already paid for, or the completed result of a job incurs no further charge.
- A request for unproven blocks is charged for the entire requested range before the job is queued, and refunded if the job fails permanently.
- Proof credit from Builder or Scale is applied first, then the balance.
- If the balance cannot cover a proof, the request is refused with HTTP 402 and no charge is made.
- The Free plan does not include log proofs: their methods return
-32601.
Proof retention
Section titled “Proof retention”Every proof is retained, and every customer’s request reuses it. Proofs of older blocks are held in long-term storage, so the first request for them can take a few seconds longer while they are retrieved. The response is byte-for-byte identical.
Further reading
Section titled “Further reading”- Log proof methods: methods, fields, encoding, and limits.
- Verifying proofs: verification in a browser or on a local machine.