head_policy: local for protection on each running instance with
automatic progress sharing across connected peers, or
head_policy: global with its shared journal for the fleet-wide contract. See
Block regression protection for the scope and freshness bound.
1. Choose a block once
Send this standard JSON-RPC request to your profile endpoint:result.number and result.hash. A null result or error means the query
cannot start. If you already have a target, select it as follows:
Resolve a number only once per query. Resolving it separately for each read
can select different hashes across a reorg. An explicit historical target
remains valid even when it is below the profile’s latest floor.
2. Reuse the hash for every read
Pass this object in the method’s existing block parameter:request({ method, params })
operation. Addresses, calldata, and decoding functions belong to your
application. block is the block object selected in step 1.
eth_call, eth_getBalance, eth_getCode,
eth_getStorageAt, eth_getTransactionCount, and eth_getProof. Storage and
proof reads take the selector as their third parameter; the others take it
as their second. See EIP-1898.
Apply the selector before any discovery starts. Carry it into direct-call
fallbacks, every Multicall chunk, and background workers. Scope cached state
and proxy-resolution results to the chain and block hash. A JSON-RPC batch,
connection, or shared API key cannot supply that query boundary for you.
For a simpler account view, use the same selector for eth_getBalance and
eth_getCode. For a historical query, use the hash resolved from your chosen
number; the pool must include a provider with the required state history.
3. Return results with evidence
Use your usual profile URL with header metadata enabled:
A successful protected latest choice’s
head_policy includes the number, hash, age,
scope and serving instance. Local adds its application generation, captured floor
and best-effort recovery hint. Global can include attributed chain-change
observations; its retained block responses have no executing upstream provider.
State responses record routing evidence, but their scalar results do not
independently attest which block executed. Explicit-number/hash selection can
legitimately have no head_policy object. See routing evidence.
Retain service_profile_id to check that responses belong to the same service
profile. profile_id records the effective routing profile. Core currently uses the
same file-profile identity for both fields. Both IDs are opaque.
Aggregate the records in your application. For example, your query API can
return this shape while each underlying Ethereum response stays standard:
Handle an interrupted query
A restarted query must not reuse state-derived discovery or cached values
from the abandoned block. Never combine partial results from different hashes.
Applications that need finality should choose a finalized block before reading;
a successful tip query can still be affected by a later reorg.