state_getStorage - Mythos RPC Method
Read a storage value by key on Mythos. Query account balances, pallet state, and any on-chain data using SCALE-encoded storage keys for AAA gaming (FIFA Rivals, NFL Rivals, Pudgy Party), player-owned economies, and bot-resistant matchmaking.
Returns the SCALE-encoded storage value for a given key on Mythos. Storage keys are constructed by hashing the pallet name and storage item name (and any map keys) using the hashing algorithms specified in the runtime metadata. This is the fundamental method for reading any on-chain state.
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_getStorage is essential for game studios, player-driven economy builders, and teams requiring verified human-only gameplay:
- Low-Level State Access -- Read the raw SCALE-encoded value stored under a known key on Mythos
- Metadata-Aware Tooling -- Pair runtime metadata with raw storage reads when building custom indexers, explorers, or debugging tools
- Historical State Queries -- Read storage values at a specific block hash to analyze state changes over time
- Pallet Storage Inspection -- Inspect pallet state directly when higher-level client helpers are unavailable or too opinionated
Code Examples
Common Use Cases
1. Raw Storage Watcher
Query and track changes for a specific storage key over time:
import { ApiPromise, WsProvider } from '@polkadot/api';
async function monitorStorageKey(api, storageKey, intervalMs = 12000) {
let previousValue = null;
setInterval(async () => {
const current = await api.rpc.state.getStorage(storageKey);
const raw = current?.toHex() ?? null;
if (previousValue !== null && raw !== previousValue) {
console.log(`Storage value changed: ${previousValue} -> ${raw}`);
}
previousValue = raw;
}, intervalMs);
}2. Metadata-Aware Decode
Use a higher-level library to decode the value after you confirm the raw storage key:
async function decodeAccountStorage(api, address) {
const storageKey = api.query.system.account.key(address);
const raw = await api.rpc.state.getStorage(storageKey);
const decoded = await api.query.system.account(address);
return {
storageKey: storageKey.toHex(),
raw: raw?.toHex() ?? null,
decoded: decoded.toJSON()
};
}3. Historical State Comparison
Compare storage values between two blocks to detect state transitions:
async function compareStateAtBlocks(api, storageQuery, params, blockHashA, blockHashB) {
const [apiAtA, apiAtB] = await Promise.all([
api.at(blockHashA),
api.at(blockHashB)
]);
// Navigate the nested query path (e.g., 'system.account')
const parts = storageQuery.split('.');
let queryA = apiAtA.query;
let queryB = apiAtB.query;
for (const part of parts) {
queryA = queryA[part];
queryB = queryB[part];
}
const [valueA, valueB] = await Promise.all([
queryA(...params),
queryB(...params)
]);
const jsonA = valueA.toJSON();
const jsonB = valueB.toJSON();
console.log(`Block A: ${JSON.stringify(jsonA, null, 2)}`);
console.log(`Block B: ${JSON.stringify(jsonB, null, 2)}`);
return { before: jsonA, after: jsonB };
}
// Example: compare account state between two blocks
// compareStateAtBlocks(api, 'system.account', ['5GrwvaEF...'], blockHashOld, blockHashNew);Storage Key Construction
For developers who need to construct storage keys manually (without a high-level library):
| Storage Type | Key Structure | Example |
|---|---|---|
| Value | xxhash128(Pallet) + xxhash128(Item) | Timestamp.Now |
| Map | xxhash128(Pallet) + xxhash128(Item) + hasher(Key) | System.Account(accountId) |
| Double Map | xxhash128(Pallet) + xxhash128(Item) + hasher1(Key1) + hasher2(Key2) | Staking.ErasStakers(era, validatorId) |
Common hashers used in Substrate:
- Blake2_128Concat -- 16-byte Blake2b hash followed by the raw key (allows key enumeration)
- Twox64Concat -- 8-byte xxhash followed by the raw key (faster, for trusted keys)
- Identity -- Raw key with no hashing (used for already-unique keys)
Error Handling
Common errors and solutions:
| Error Code | Description | Solution |
|---|---|---|
| -32603 | State not available | The requested block's state may be pruned or unavailable on this node -- use an archive node for deep historical queries |
| -32602 | Invalid params | Verify the storage key is a valid hex string with 0x prefix |
| -32005 | Rate limit exceeded | Reduce request frequency or implement client-side rate limiting |
null result | No value at key | This is not an error -- the storage key has no value (default state). Verify the key is correctly constructed |
Important: Historical-state availability depends on the node's pruning configuration. Archive nodes retain full history, while pruned/full nodes may not serve older state.
Related Methods
state_getKeysPaged-- Enumerate storage keys matching a prefix (useful for iterating map entries)state_queryStorageAt-- Query multiple storage keys at a specific block in a single requeststate_getMetadata-- Get runtime metadata including storage definitions, types, and hashing algorithmsstate_call-- Call runtime APIs for computed state that is not directly in storagestate_subscribeStorage-- Subscribe to storage changes in real time via WebSocket
chain_subscribeFinalizedHeads
Subscribe to finalized block headers on Mythos. Real-time WebSocket notifications for blocks that have achieved GRANDPA finality — essential for exchanges, bridges, and applications requiring irreversibility on the gaming blockchain powering FIFA Rivals and NFL Rivals with World ID verification.
state_getMetadata
Get runtime metadata on Mythos. Essential for decoding storage, building extrinsics, and discovering available pallets and calls on the gaming blockchain powering FIFA Rivals and NFL Rivals with World ID verification.