Reading Query Results
How to read query results from Axiom.
The
areResponsesValid
view function in the AxiomV1Query
contract allows users to read block, account, and storage data from verified query results. This function has the following signature:function areResponsesValid(
bytes32 keccakBlockResponse,
bytes32 keccakAccountResponse,
bytes32 keccakStorageResponse,
BlockResponse[] calldata blockResponses,
AccountResponse[] calldata accountResponses,
StorageResponse[] calldata storageResponses
) external view returns (bool);
The Axiom SDK provides an interface to help you read verified results from Axiom. To start reading query results, first use the
getResponseTreeForKeccakQueryResponse
function to look up the a responseTree
for the query which contains information about the result. This will require looking up the query by the keccakQueryResponse
from the build
function in QueryBuilder
: import { Axiom, AxiomConfig } from "@axiom-crypto/core";
const config: AxiomConfig = {
providerUri: <your provider uri (such as from Alchemy, Infura, etc)>,
version: "v1",
chainId: 5, // Goerli; defaults to 1 (Ethereum Mainnet)
mock: true, // builds proofs without utilizing actual Prover resources
}
const ax = new Axiom(config);
const responseTree = await ax.query.getResponseTreeForKeccakQueryResponse(
<keccakQueryResponse>
);
The
responseTree
contains blockTree
, accountTree
, and storageTree
, which encapsulate all information about blocks, accounts, and storage, respectively. The next step is to use getHexRoot()
on each of the trees to generate keccakBlockResponse
, keccakAccountResponse
, and keccakStorageResponse
, which encode the verified query result on-chain:const keccakBlockResponse = responseTree.blockTree.getHexRoot();
const keccakAccountResponse = responseTree.accountTree.getHexRoot();
const keccakStorageResponse = responseTree.storageTree.getHexRoot();
Finally, format the block, account, and storage information you wish to verify by calling
getValidationWitness
which will return a ValidationWitnessResponse
object with blockReponse
, accountResponse
, and storageResponse
fields. Depending on the type of data you are interested in querying (see table below), you can use the specific appropriate getValidationWitness function call.Block data | Account data | Storage data |
---|---|---|
|
|
|
In all cases, you will be passing in the data that you originally built the
Query
with.To get the
ValidationWitness
for any of the data in the Block data column of the table above (block number or block hash), add the blockNumber for the QueryRow
that you added to the QueryBuilder
.const blockWitness: ValidationWitnessResponse = ax.query.getValidationWitness(
responseTree, <blockNumber>
);
To get the
ValidationWitness
for any of the data in the Account data column of the table above (block number, address, nonce, balance, storage root, or code hash), add the blockNumber and address for the QueryRow
that you added to the QueryBuilder
.const accountWitness: ValidationWitnessResponse = ax.query.getValidationWitness(
responseTree, <blockNumber>, <address>
);
To get the
ValidationWitness
for any of the data in the Account data column of the table above (block number, address, slot number, slot value), add the blockNumber, address, and storage for the QueryRow
that you added to the QueryBuilder
.const storageWitness: ValidationWitnessResponse = ax.query.getValidationWitness(
responseTree, <blockNumber>, <address>, <storage slot>
);
The
ValidationWitnessResponse
contains a blockResponse
, an optional accountResponse
object, and an optional storageResponse
object. The type of data that you created the QueryRow
for is the same type that you will push to either the BlockResponse[]
, AccountResponse[]
, or StorageResponse[]
arrays that you will pass in to the areResponsesValid function.You are now ready to verify this data against the on-chain result by calling
areResponsesValid
:const axiomV1Query = new ethers.Contract(
ax.getAxiomQueryAddress() as string,
ax.getAxiomQueryAbi(),
wallet
);
const tx = await axiomV1Query.areResponsesValid(
keccakBlockResponse,
keccakAccountResponse,
keccakStorageResponse,
[blockWitness.blockResponse],
[accountWitness.accountResponse],
[storageWitness.storageResponse]
);
Information is available here on how to use the data in your own smart contract.
For more advanced users, we offer access to the raw Merkle-ized query results via
isKeccakResultValid
and isPoseidonResultValid
. These allow validation of Keccak and Poseidon encoded block, account, and storage data in the Axiom Query Format. The Poseidon format may be especially useful for ZK developers.function isKeccakResultValid(
bytes32 keccakBlockResponse,
bytes32 keccakAccountResponse,
bytes32 keccakStorageResponse
) external view returns (bool);
function isPoseidonResultValid(
bytes32 poseidonBlockResponse,
bytes32 poseidonAccountResponse,
bytes32 poseidonStorageResponse
) external view returns (bool);