Axiom Query Format
A technical specification for on-chain queries into Axiom.
A batch query into Axiom allows a user to access up to 64 pieces of historic on-chain information simultaneously in a smart contract. These queries allow on-chain applications to act based on the on-chain history of Ethereum in a fully trustless way.
Summary
Batch queries consist of up to 64 individual queries, which of which queries information from one of:
blockNumber
(uint32
, required) -- any block number up to the current blockaddress
(address
, optional) -- any address on Ethereumslot
(uint256
, optional) -- any storage slot in contract storage
Together, these specify historic data from historic blocks, accounts, and contract storage. Batch queries are identified by:
query
-- a serialized form of the querykeccakQueryResponse
-- a Merkle-ized form of the query
Note that keccakQueryResponse
can be uniquely determined from query
, but it contains additional information from the on-chain history. We describe both of these formats below.
Query format
The batch query is serialized as a list with entries:
versionIdx
(uint8
, required) -- a version byte allowing specification of the query typelength
(uint32
, required) -- the number of queries in the batchencodedQueries
(list
, required) -- a list of serialized individual queries
Here, encodedQueries
is a list which specifies the individual pieces of information from block headers, accounts, and storage slots being queried. The entries of encodedQueries
are length 4 lists containing:
length
(uint8
, required) -- the number of entries below which are not null, either 1, 2, or 3.blockNumber
(uint32
, required) -- the block numberaddress
(address
, optional) -- the addressslot
(uint256
, optional) -- the storage slot in local account storage foraddress
If slot
is non-empty, then address
must be non-empty.
Query response format
Axiom responds to queries by committing to them on-chain in a Merkle-ized format. This allows Axiom to fulfill queries into large amounts of data without paying to store each piece in contract storage. Axiom provides a keccakQueryResponse and poseidonQueryResponse for each query.
Keccak response format
The primary way to access results from Axiom is via the keccakQueryResponse
, which is determined by
where blockResponseRoot
, accountResponseRoot
, and storageResponseRoot
are Merkle roots of queries into block headers, accounts, and account storage. These are determined as
blockResponseRoot
-- the Keccak Merkle root of a tree with 64 leaves given bykeccak(blockHash . blockNumber)
. Empty leaves are padded withbytes32(0x0)
.accountResponseRoot
-- the Keccak Merkle root of a tree with 64 leaves given bykeccak(blockNumber . address . keccak(nonce . balance . storageRoot . codeHash))
. Empty leaves are padded withbytes32(0x0)
.storageResponseRoot
-- the Keccak Merkle root of a tree with 64 leaves given bykeccak(blockNumber . address . slot . value)
. Empty leaves are padded withbytes32(0x0)
.
In each of these data structures, the individual components and types are:
blockHash
(bytes32
) -- the block hashblockNumber
(uint32
) -- the block numberaddress
(address
) -- the Ethereum addressnonce
(uint64
) -- the account noncebalance
(uint96
) -- the account balancestorageRoot
(bytes32
) -- the storage root of the relevant accountcodeHash
(byte32
) -- the code hash of the relevant accountslot
(uint256
) -- the storage key in the account storagevalue
(uint256
) -- the value in the account storage
Poseidon response format
Axiom also provides an encoding of the response using the Poseidon hash function instead of Keccak. This encoding may be useful for applications that wish to use ZK proofs to read from the results. In particular, we define the poseidonBlockResponse
, poseidonAccountResponse
, and poseidonStorageResponse
by:
poseidonBlockResponse
-- the Poseidon Merkle root of a tree with 64 leaves given by
where poseidon_tree_root
denotes the Poseidon Merkle root of the parsed fields of the block header. Empty leaves are padded with 0
.
poseidonAccountResponse
-- the Poseidon Merkle root of a tree with 64 leaves given by
where poseidon_tree_root
denotes the Poseidon Merkle root of the parsed fields nonce
, balance
, storageRoot
, and codeHash
of the account. Empty leaves are padded with 0
.
poseidonStorageResponse
-- the Poseidon Merkle root of a tree with 64 leaves given by
Empty leaves are padded with 0
.
Last updated