History
Willow retains all data it serves, for every contract on every chain. No data expires. Ethereum is held from genesis. On the other six chains, blocks older than those Willow holds are fetched on the first request from a paying account, verified, and retained for all subsequent requests.
Recent blocks
Section titled “Recent blocks”Every new block is verified on arrival (see How Willow verifies data) and stored with its transactions, receipts, and logs. These blocks are retained, so a query over any range since then is served from Willow’s own store.
Ethereum from genesis
Section titled “Ethereum from genesis”Ethereum is held from block 0, with every transaction, receipt, and log, so an
Ethereum request never waits for a fetch. Receipts before the Byzantium fork
(block 4,370,000) contain root instead of status (see
Receipts and transactions).
Older blocks on the other chains
Section titled “Older blocks on the other chains”When a request covers blocks older than those Willow holds, Willow fetches them from archive providers and verifies them before storing them. Each block is verified against its hash, and canonicality is verified against the data the chain posted to Ethereum, or by parent hash from a block Willow already holds. A block that fails verification is never stored or served.
A fetch is initiated by the following methods, with blocks specified by number:
eth_getLogs over a block range, eth_getBlockByNumber,
eth_getBlockReceipts, eth_getBlockTransactionCountByNumber, and
eth_getTransactionByBlockNumberAndIndex. Methods that take a hash return only
blocks that are already held.
- Up to 128 missing blocks: the request waits up to 2 seconds for them, and is served if they arrive within that time.
- More than 128 blocks, or not within that time: the request is refused
immediately with
-32000, and the fetch continues. The refusal is a “not found” refusal, so a router queries another provider in the meantime. Repeat the request afterretryAfterSeconds. - Subsequent queries over these blocks, from any account, are served from Willow’s store.
- Responses are never partial. Willow responds only once it holds every block of the range.
{ "error": { "code": -32000, "message": "not found in this store: blocks 30000000-30000099 are older than the blocks held here and are being fetched from history, verified against the chain and kept; try again in about 30 s (willow_historyStatus reports progress, and willow_historyCancel ends a fetch); this account's fetch is 128 blocks, about 10313 units", "data": { "history": { "state": "fetching", "chain": 8453, "blocks": [[30000000, 30000099]], "ranges": 1, "fetches": [7], "retryAfterSeconds": 30, "quote": {"blocks": 128, "units": 10313} } } }, "id": 1, "jsonrpc": "2.0"}blocks,ranges: the missing block ranges, as[first, last](up to 64), and their count.fetches: the identifiers of the fetches on which these blocks wait.retryAfterSeconds: when to repeat the request (2 to 900 seconds).quote: the requesting account’s own fetches of these blocks, in blocks and units. It isnullwhen another account’s fetch already covers them; the request then waits on that fetch at no cost.
Limits
Section titled “Limits”| Limit | Value |
|---|---|
| Missing blocks one request may fetch | 100,000 |
| Separate gaps in one request’s range | 64 |
| Fetches open per account | 4 |
| Block data one account may fetch, per chain per UTC day | 5 GiB, before compression |
| New anchors on Ethereum per account per UTC day | 8 |
| New separate ranges per account per UTC day | 1,024 |
A fetch far from any block Willow holds requires a new anchor on Ethereum: the chain’s attestation that a block hash is canonical. Locating an anchor requires thousands of calls, so anchors are limited per day. Willow also applies daily limits per chain across all accounts, and stops accepting fetches when its disk usage is too high.
Eligibility
Section titled “Eligibility”Fetches are available to paying accounts: Pay as you go, Builder, and Scale. A Free account can read every block that is already held, but its requests for blocks that are not held receive the standard refusal, and no fetch is started:
{"error":{"code":-32000,"message":"not found in this store: blocks 16-16 are outside the indexed range 157846681-158624152"},"id":1,"jsonrpc":"2.0"}Fetch pricing
Section titled “Fetch pricing”A fetch is billed in units, as reads are: one unit per 4 KB of block data written, before compression, at the plan’s unit price. The quote is an estimate; billing reflects the actual size.
- Fetches are prepaid. A fetch starts only if the account can pay for it and still retain the larger of 10% of its spendable amount or 100,000 units for reads.
- On Builder and Scale, fetches draw on the plan’s included units first, then on the balance. On Pay as you go, they draw on the balance only, never on Free units remaining from the month of the upgrade.
- A fetch that starts a new separate range is rounded out to a whole chunk of about 8 MB of blocks, and can therefore cover more blocks than were requested. The additional blocks are also billed, and the refusal message states this.
- The portion of the balance reserved by a fetch cannot be spent on reads. Once reads require it, they are refused with HTTP 402 until the balance is topped up or the fetch ends.
Other refusals
Section titled “Other refusals”All of the following are -32000, except the two size limits, which are
-32002.
| Message contains | data.history.state | Meaning |
|---|---|---|
range too large: blocks … would fetch N blocks of history, more than 100000 per request | Narrow the range. | |
range too large: blocks … hold N gaps of history here, more than 64 per request | Narrow the range. | |
are not held, and … | The account cannot start this fetch at present. The remainder of the message states the reason: 4 fetches are open, the cost exceeds the spendable amount, a daily limit has been reached, or the server’s queue or disk is full. | |
are being checked again against the chain | reverifying | Willow is re-verifying blocks it already held, at its own cost. Retry in a few minutes. |
new history fetches of this chain are paused | paused | Fetches on this chain are suspended pending a server update. |
can't be fetched from history here | refused | The blocks cannot be verified: OP Mainnet before Bedrock (block 105,235,063), Arbitrum One before its Nitro genesis (block 22,207,817), or a fetch that failed 10 consecutive times. |
willow_historyStatus
Section titled “willow_historyStatus”Returns the account’s fetches and their progress on the chain in the URL. It
takes an optional {"fromBlock": …, "toBlock": …}, in which case it also
reports which blocks of that range are held and which are missing. An API key
is required.
{"jsonrpc":"2.0","id":1,"method":"willow_historyStatus","params":[{"fromBlock":"0x1c9c380","toBlock":"0x1c9c3e3"}]}fetches: the account’s open and recent fetches:id,blocks(its ranges),totalanddone(blocks),state(queued,fetching,waiting to retry,done, orrefused),createdAt(Unix seconds),blocksAhead(blocks queued ahead of it), anderror.account: the data fetched today and the daily allowance (bytesToday,bytesPerDay), the spendable amount (spendableUnits), and the open fetches and new anchors against their limits.held,missing,missingRanges: when a range is given, the held and missing block ranges within it (up to 64 of each).liveFrom: the first block of the contiguous run Willow follows at the chain head. Blocks below it are history.limits: the wait parameters (inlineMaxBlocks,inlineWaitMs) and the size limits above.
willow_historyCancel
Section titled “willow_historyCancel”Cancels one of the account’s fetches, identified by the id from fetches:
{"jsonrpc":"2.0","id":1,"method":"willow_historyCancel","params":[7]}{"id":1,"jsonrpc":"2.0","result":{"fetch":7,"state":"cancelled","note":"it ends after the segment under way, which is billed"}}Blocks already fetched are retained and billed. No further charges accrue. For
a fetch started by another account, cancellation only stops the request from
waiting on it ("state": "left"), and the fetch continues for that account.
Proofs of older blocks
Section titled “Proofs of older blocks”Transaction and receipt proofs are
available for every block Willow holds, whether fetched or not.
Log proofs are generated on request only for blocks from
verifiedFrom (below) onward. A log proof request over older blocks is refused
with -32000:
{"error":{"code":-32000,"message":"proof not found for block 16777216: no proof was made for it, and blocks before 26133199 are not proven on request"},"id":1,"jsonrpc":"2.0"}Every log proof is retained permanently and reused for all accounts. 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. See Proofs.
Start of history
Section titled “Start of history”/v1/rpc/health reports, for each chain:
verifiedFrom: the first block of the contiguous run Willow follows at the chain head. Blocks below it are history, held or fetched on request.fullBlocks.eventIndex.history: the history ranges held, as[first, last].fullBlocks.from: the first block of that run held in full. Blocks fromverifiedFromup to it are held with headers only, so the full-block methods and mosteth_getLogsfilters refuse them with-32000, and they are not fetched.