---
description: How the `AxiomV0` contract works and how to interact with it
---

# Caching block hashes

The `AxiomV0` smart contract caches blockhashes from the Ethereum history and allows smart contracts to verify them against this cache. We explain how this works below.&#x20;

### Caching blockhashes

`AxiomV0` caches the Keccak Merkle roots of consecutive length 1024 sequences of blocks with block numbers `[1024 * x, ..., 1024 * x + 1023]` for an index `x` in the mapping

```solidity
mapping(uint32 => bytes32) public historicalRoots;
```

Here `historicalRoots[startBlockNumber]` holds the hash `keccak(prevHash || root || numFinal)`, where `prevHash` is the block hash of block `startBlockNumber - 1`, `root` is the Merkle root of the block hashes with index in `[startBlockNumber, startBlockNumber + 1023]`, with block hashes after `startBlockNumber + numFinal - 1` replaced by `0`, and `numFinal` is the number of block hashes verified in this range of blocks.

Blockhashes are cached by calling the `updateRecent`, `updateOld`, or `updateHistorical` functions with the following function signatures:

```solidity
function updateRecent(bytes calldata proofData) external;
function updateOld(
        bytes32 nextRoot,
        uint32 nextNumFinal,
        bytes calldata proofData
) external;
function updateHistorical(
        bytes32 nextRoot,
        uint32 nextNumFinal,
        bytes32[HISTORICAL_NUM_ROOTS] calldata roots,
        bytes32[TREE_DEPTH + 1][HISTORICAL_NUM_ROOTS - 1] calldata endHashProofs,
        bytes calldata proofData
) external;
```

These functions verify a ZKP of the Keccak header chain and update `historicalRoots` accordingly:

* `updateRecent` and `updateOld` prove Keccak header chains of length up to `1024`.
* `updateHistorical` provides a recursive proof of the validity of Keccak header chains of length `128 * 1024` and then reads individual Merkle roots of 1024 blocks using the Merkle proofs in `endHashProofs`.

These functions emit the event

```solidity
event UpdateEvent(uint32 startBlockNumber, bytes32 prevHash, bytes32 root, uint32 numFinal);
```

for each update of a Merkle root.

### Reading from the cache

To read from the block hash cache, `AxiomV0` provides the `isBlockHashValid` method which takes in a witness that a block hash is included in the cache, formatted via

```solidity
struct BlockHashWitness {
    uint32 blockNumber;
    bytes32 claimedBlockHash;
    bytes32 prevHash;
    uint32 numFinal;
    bytes32[TREE_DEPTH] merkleProof;
}
```

This method verifies that `merkleProof` is a valid Merkle path for the relevant block hash and checks that the Merkle root lies in the cache.
