# Solana integration

## Overview

{% hint style="warning" %}
The integration is still experimental, and some breaking changes may occur.
{% endhint %}

Hashi’s core functionality is to propagate block headers across multiple chains, enabling cross-chain state verification. On EVM-based chains, this can be done in a trustless manner because the EVM exposes the last 256 block headers. However, this approach is not feasible on Solana, as the Solana VM only provides slot hashes, which do not include commitments that would allow verification of account states (as opposed to the state\_root on Ethereum).

Nevertheless, Solana’s VM does allow reading account states (such as data, address, lamports, owner, and rent\_epoch). To make use of this capability, we developed a program called [Snapshotter](https://github.com/gnosis/hashi/blob/feat/solana/packages/solana/programs/snapshotter/src/lib.rs). Snapshotter allows the propagation of the hash of each subscribed account’s state to other chains via Hashi reporters.

Technically, whenever the `subscribe` function is called, the hash of the specified account’s state is added to a Merkle tree. Once a predefined batch size is reached (i.e., a certain number of subscriptions have occurred), anyone can call `calculate_root` to compute and store the Merkle root on-chain (AKA `accounts_root`). At that point, any Hashi-compatible reporter ([This](https://github.com/gnosis/hashi/blob/feat/solana/packages/solana/programs/wormhole-reporter/src/lib.rs) is an example of a Hashi-compatible reporter) can invoke `dispatch_root` to propagate the root to other blockchains, thereby synchronizing the account state across multiple ecosystems. Finally, on the destination chain, you can verify an account simply by verifying a Merkle proof.

## How to read a Solana account from an EVM chain

Suppose you need to read the Solana [System Program](https://explorer.solana.com/address/11111111111111111111111111111111) account data from Base. The first step is to let the Snapshotter know that you want the System Program account’s hash to be included in the next `accounts_root`. To do this, simply call `subscribe`. Full example [here](https://github.com/gnosis/hashi/blob/feat/solana/packages/solana/tests/snapshotter.ts#L32).

```typescript
const [configKey] = PublicKey.findProgramAddressSync([Buffer.from("config", "utf-8")], snapshotter.programId)
const systemProgram = new PublicKey("11111111111111111111111111111111")
await snapshotter.methods
    .subscribe(systemProgram)
    .accounts({
        config: configKey,
     } as any)
    .rpc()
```

Once the number of subscribed accounts reaches [**BATCH\_SIZE**](https://github.com/gnosis/hashi/blob/feat/solana/packages/solana/programs/snapshotter/src/lib.rs#L36), anyone can call `calculate_root`, which computes the Merkle root of the new batch and stores it so reporters can easily retrieve it when broadcasting to other chains. Because each new batch’s root (`batch_accounts_root`) must be combined with the existing `accounts_root` (to preserve previously included accounts), we implemented a custom “[Batch Merkle Tree](https://github.com/gnosis/hashi/blob/feat/solana/packages/solana/shared/batch-merkle-tree/src/lib.rs).” This specialized Merkle tree allows us to merge all `batch_accounts_root` values into a single `accounts_root` without losing any historical data. Full example [here](https://github.com/gnosis/hashi/blob/feat/solana/packages/solana/tests/snapshotter.ts#L65).

```typescript
const [configKey] = PublicKey.findProgramAddressSync([Buffer.from("config", "utf-8")], snapshotter.programId)
const batch = new anchor.BN(0) // must be equal to the current batch
await snapshotter.methods
  .calculateRoot(batch)
  .accounts({
    config: configKey,
  } as any)
  .remainingAccounts(batchAccounts)
  .rpc()
```

Once the `accounts_root` is updated, you can transmit it to other chains simply by calling `dispatch_root`. In this example, the [Wormhole reporter](https://github.com/gnosis/hashi/blob/feat/solana/packages/solana/programs/wormhole-reporter/src/lib.rs) is used to dispatch the root, but any compatible reporter will work. Full example [here](https://github.com/gnosis/hashi/blob/feat/solana/packages/solana/tests/wormhole-reporter.ts#L112).

```typescript
const tracker = await getProgramSequenceTracker(provider.connection, reporter.programId, CORE_BRIDGE_PID)
const message = deriveWormholeMessageKey(reporter.programId, tracker.sequence + 1n)
const wormholeAccounts = getPostMessageCpiAccounts(
  reporter.programId,
  CORE_BRIDGE_PID,
  provider.publicKey,
  message,
)
const [configKey] = PublicKey.findProgramAddressSync([Buffer.from("config", "utf-8")], reporter.programId)
const [snapshotterConfigkey] = PublicKey.findProgramAddressSync(
  [Buffer.from("config", "utf-8")],
  snapshotter.programId,
)

await reporter.methods
  .dispatchRoot()
  .accounts({
    config: configKey,
    wormholeProgram: new PublicKey(CORE_BRIDGE_PID),
    snapshotterConfig: snapshotterConfigkey,
    ...wormholeAccounts,
  } as any)
  .rpc()
```

Once the `accounts_root` is successfully stored in the corresponding adapter(s) on Base, you can read the account data by calling `HashiProver.verifyForeignSolanaAccount` from any contract.

```solidity
pragma solidity ^0.8.20;

import { HashiProver } from "../prover/HashiProver.sol";
import "../prover/HashiProverStructs.sol";

contract SolanaAccountReader is HashiProver {
    constructor(address shoyuBashi) HashiProver(shoyuBashi) {}

    function getSolanaAccount(SolanaAccountProof calldata proof) external view returns (bytes memory) {
        return verifyForeignSolanaAccount(proof);
    }
}
```

For a complete example of how to read a Solana account data, refer to this [example](https://github.com/gnosis/hashi/blob/feat/solana/packages/evm/test/05_HashiProver.spec.ts#L225).
