Docs

state_queryStorageAt - Mythos RPC Method

Batch query multiple storage keys at a specific block on Mythos. Efficiently retrieve consistent multi-key state snapshots for indexers, dashboards, and analytics.

Queries multiple storage keys at a specific block on Mythos, returning all values in a single call. This is the preferred method for fetching consistent multi-key state snapshots, as all values are read from the same block.

Why Mythos? Build on the gaming blockchain powering FIFA Rivals and NFL Rivals with World ID verification with World ID proof-of-humanity, Polkadot security, Snowbridge cross-chain bridge, and 1M+ downloads per title.

When to Use This Method

state_queryStorageAt is essential for game studios, player-driven economy builders, and teams requiring verified human-only gameplay:

  • Consistent State Snapshots -- Fetch multiple storage values from the same block to ensure data consistency on Mythos
  • Batch Raw Storage Reads -- Retrieve several known storage keys in one RPC call
  • Indexer and Analytics -- Build efficient data pipelines by querying all required storage keys at once
  • Historical State Analysis -- Compare storage state across different blocks for auditing and data analysis

Code Examples

Common Use Cases

1. Multi-Key Snapshot

Read multiple storage keys from the same block:

JavaScript
import { ApiPromise, WsProvider } from '@polkadot/api';

async function getStorageSnapshot(api, addresses) {
  const keys = await Promise.all(addresses.map((address) => api.query.system.account.key(address)));
  const results = await api.rpc.state.queryStorageAt(keys);

  return results[0].changes.map(([key, value], idx) => ({
    address: addresses[idx],
    key: key.toHex(),
    raw: value?.toHex() ?? null
  }));
}

const snapshot = await getStorageSnapshot(api, [
  '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
  '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty'
]);

snapshot.forEach((entry) => {
  console.log(`${entry.address}: ${entry.raw}`);
});

2. Historical State Comparison

Compare storage state between two blocks for auditing:

JavaScript
async function compareStorageAtBlocks(api, keys, blockHash1, blockHash2) {
  const [result1, result2] = await Promise.all([
    api.rpc.state.queryStorageAt(keys, blockHash1),
    api.rpc.state.queryStorageAt(keys, blockHash2)
  ]);

  const changes1 = new Map(result1[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()]));
  const changes2 = new Map(result2[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()]));

  const diffs = [];
  for (const [key, val1] of changes1) {
    const val2 = changes2.get(key);
    if (val1 !== val2) {
      diffs.push({ key, before: val1, after: val2 });
    }
  }

  console.log(`Found ${diffs.length} storage changes between blocks`);
  return diffs;
}

3. Efficient Indexer State Fetching

Fetch all required storage in a single batch for indexer pipelines:

JavaScript
async function fetchBlockState(api, blockHash) {
  // Build storage keys for multiple storage items
  const keys = [
    api.query.system.number.key(),              // block number
    api.query.timestamp.now.key(),               // timestamp
    api.query.system.eventCount.key(),           // event count
    api.query.system.extrinsicCount.key()        // extrinsic count
  ];

  const result = await api.rpc.state.queryStorageAt(keys, blockHash);
  const changes = new Map(
    result[0].changes.map(([k, v]) => [k.toHex(), v?.toHex()])
  );

  return {
    block: blockHash,
    keyCount: changes.size,
    entries: Object.fromEntries(changes)
  };
}

Error Handling

Common errors and solutions:

Error CodeDescriptionSolution
-32603Internal errorVerify storage keys are correctly encoded hex strings with 0x prefix
-32602Invalid paramsEnsure keys is an array of hex strings and blockHash is a valid block hash
-32005Rate limit exceededReduce the number of keys per batch or implement rate limiting
State prunedHistorical state unavailableThe requested block may be pruned on this node -- use an archive node for deep historical queries