Skip to main content

Overview

This guide assumes you are familiar with transactions on Solana. If you aren’t, we recommend to read the Solana documentation on transactions.
Transactions to interact with compressed accounts are fully compatible with Solana’s Transaction and Versioned Transaction formats. There are few nuances to build transactions with compressed accounts as compared to regular accounts:
  • Instructions must specify the list of all compressed accounts being read or written to.
  • To read or write to a compressed account, the instruction must send the current account state on-chain and prove its validity.
  • Each unique state tree that gets read or written to (via any compressed account) needs to be specified as per Solana’s regular on-chain account access lists.

Reading Compressed Accounts

Reading compressed accounts follows a similar pattern to Solana accounts.
  • The main difference is that compressed account RPC methods query an indexer instead of the ledger directly.
  • The indexer, called Photon, reconstructs compressed account state from the Solana ledger by reading transaction logs.
The API exposed by the indexer closely mirrors existing RPC calls, with one-to-one mapping:
Solana RPCPhoton RPC Calls
getAccountInfogetCompressedAccount
getBalancegetCompressedBalance
getTokenAccountsByOwnergetCompressedTokenAccountsByOwner
getProgramAccountsgetCompressedAccountsByOwner
  • Clients
  • Programs
Clients read compressed accounts similar to Solana accounts:
  1. Fetch the compressed account data from your RPC provider using its address or hash
  2. Deserialize the account’s data field into the appropriate data structure.
// 1. Fetch compressed account from indexer
const compressedAccount = await rpc.getCompressedAccount(
  bn(address.toBytes())
);

// 2. Deserialize account data
const accountData = coder.types.decode(
  "AccountType",
  compressedAccount.data.data
);

Writing to Compressed Accounts

Writing to compressed accounts can be described more generally as:
(state, validityProof) -> state transition -> state'
Writing to a compressed account involves these steps:
  1. Fetch the compressed account data from your RPC provider using its address or hash
  2. Fetch a validity proof from your RPC provider using the account hash via getValidityProof() to prove the account hash exists in the state tree.
The Solana program executing the state transition Data** -> _Data’**_ requires its client to pack the instructions with:
  • address: persistent identifier of the compressed account (unchanged)
  • owner program: program ID that owns this account (unchanged)
  • data: current account data
  • data': updated account data
  • validity proof: 128-byte ZK proof that verifies the current account hash exists in the state tree

Simplified: Read and Write compressed accounts

On-chain Execution

To write compressed state, a program invokes the Light System Program via CPI. The system program then does the following:
  1. Runs relevant checks (sum check, etc.)
  2. Verifies the validity proof
  3. Nullifies the existing leaf of the compressed account that is being written to, to prevent double spending.
  4. Appends the new compressed account hash to the state tree and advances the tree’s state root
  5. Emits the new compressed account state onto the Solana ledger
An RPC node then parses the transaction and compressed state and provides the read state to clients via the ZK Compression RPC API.
  • Before Tx Execution
  • After Tx Execution

Next Steps

Take the last step and understand what the trade-offs for compressed accounts are.