State API
The State API is your gateway to querying blockchain state, including storage data, metadata, and runtime information. This API provides low-level access to the blockchain’s state trie and is available through the StateApi
class.
Quick Example
Section titled “Quick Example”import 'package:polkadart/apis/apis.dart';import 'package:polkadart/polkadart.dart' show Provider, StateApi;
void main() async { final provider = Provider.fromUri(Uri.parse('wss://rpc.polkadot.io')); final stateApi = StateApi(provider);
// Get current runtime version final runtimeVersion = await stateApi.getRuntimeVersion(); print(runtimeVersion.toJson());
// Get metadata final metadata = await stateApi.getMetadata(); print('Metadata version: ${metadata.version}');}
Expected Output
Section titled “Expected Output”{ specName: polkadot, implName: parity-polkadot, authoringVersion: 0, specVersion: 1003003, implVersion: 0, apis: [...], transactionVersion: 26, stateVersion: 1}
Core Methods
Section titled “Core Methods”The StateApi
class provides comprehensive methods for querying blockchain state:
Runtime Calls
Section titled “Runtime Calls”Future<Uint8List> call(String method, Uint8List bytes, {BlockHash? at})
Execute a runtime API call at a specific block’s state.
Use case: Call runtime APIs for specialized queries not exposed through standard RPC.
Storage Queries
Section titled “Storage Queries”getPairs
Section titled “getPairs”Future<List<KeyValue>> getPairs(StorageKey prefix, {BlockHash? at})
Retrieve all key-value pairs matching a prefix.
Example:
// Get all account balancesfinal pairs = await stateApi.getPairs( hex.decode('26aa394eea5630e07c48ae0c9558cef7'), // System.Account prefix);
getKeysPaged
Section titled “getKeysPaged”Future<List<StorageKey>> getKeysPaged({ required StorageKey key, required int count, StorageKey? startKey, BlockHash? at})
Query storage keys with pagination support.
Example:
// Get first 100 account keysfinal keys = await stateApi.getKeysPaged( key: accountPrefix, count: 100,);
// Get next 100 keysfinal nextKeys = await stateApi.getKeysPaged( key: accountPrefix, count: 100, startKey: keys.last,);
getStorage
Section titled “getStorage”Future<StorageData?> getStorage(StorageKey key, {BlockHash? at})
Retrieve raw storage data for a specific key.
Returns: Raw SCALE-encoded data or null
if the key doesn’t exist.
getStorageHash & getStorageSize
Section titled “getStorageHash & getStorageSize”Future<BlockHash?> getStorageHash(StorageKey key, {BlockHash? at})Future<int?> getStorageSize(StorageKey key, {BlockHash? at})
Get the hash or size of storage data without fetching the full value.
Use case: Efficiently check if storage has changed or estimate data size.
Historical Queries
Section titled “Historical Queries”queryStorage
Section titled “queryStorage”Future<List<StorageChangeSet>> queryStorage( List<StorageKey> keys, BlockHash fromBlock, {BlockHash? toBlock})
Query storage changes over a block range.
Example:
// Track balance changes over 100 blocksfinal changes = await stateApi.queryStorage( [balanceStorageKey], fromBlockHash, toBlock: toBlockHash,);
queryStorageAt
Section titled “queryStorageAt”Future<List<StorageChangeSet>> queryStorageAt( List<StorageKey> keys, {BlockHash? at})
Query multiple storage entries at a specific block.
getReadProof
Section titled “getReadProof”Future<ReadProof> getReadProof(List<StorageKey> keys, {BlockHash? at})
Generate a merkle proof for storage entries.
Use case: Prove storage values to light clients or cross-chain bridges.
Metadata & Runtime
Section titled “Metadata & Runtime”getMetadata
Section titled “getMetadata”Future<RuntimeMetadata> getMetadata({BlockHash? at})
Fetch the complete runtime metadata.
Contains:
- All pallets and their functions
- Storage layouts
- Types registry
- Runtime APIs
getRuntimeVersion
Section titled “getRuntimeVersion”Future<RuntimeVersion> getRuntimeVersion({BlockHash? at})
Get runtime version information.
Includes:
specVersion
: Runtime specification versionspecName
: Chain identifier (e.g., “polkadot”)implVersion
: Implementation versionapis
: Available runtime APIs
Real-time Subscriptions
Section titled “Real-time Subscriptions”subscribeRuntimeVersion
Section titled “subscribeRuntimeVersion”Future<StreamSubscription<RuntimeVersion>> subscribeRuntimeVersion( Function(RuntimeVersion) onData)
Subscribe to runtime version updates.
Example:
final subscription = await stateApi.subscribeRuntimeVersion((version) { print('Runtime upgraded to version ${version.specVersion}');});
// Don't forget to cancel when doneawait subscription.cancel();
subscribeStorage
Section titled “subscribeStorage”Future<StreamSubscription<StorageChangeSet>> subscribeStorage( List<Uint8List> storageKeys, Function(StorageChangeSet) onData)
Monitor storage changes in real-time.
Example:
// Watch balance changes for multiple accountsfinal subscription = await stateApi.subscribeStorage( [aliceBalanceKey, bobBalanceKey], (changes) { print('Storage updated at block ${changes.block}'); for (final change in changes.changes) { print('Key: ${hex.encode(change.$1)}'); print('New value: ${change.$2 != null ? hex.encode(change.$2!) : "deleted"}'); } },);
Best Practices
Section titled “Best Practices”- Use
getKeysPaged
for large datasets to avoid timeouts - Query specific blocks for consistent reads across multiple calls
- Use
getStorageHash
to detect changes before fetching full data
- Always cancel subscriptions when done to prevent memory leaks
- Handle reconnection logic for long-running subscriptions
- Use error handlers for subscription failures
- Limit block ranges in
queryStorage
to avoid overwhelming responses - Cache metadata for specific block heights when querying historical data
- Consider using archive nodes for deep historical queries
Next Steps
Section titled “Next Steps”- Learn about type-safe storage queries
- Explore transaction building
- Understand chain synchronization