# state_getKeys - JSON-RPC Method

## Description

Returns storage keys that match a given prefix. This JSON-RPC method is useful for discovering all storage entries under a specific module or querying multiple related storage items. Be cautious with broad prefixes as they may return large result sets.

## Request Parameters

- `prefix` (`string, required`): Hex-encoded storage key prefix to match
- `blockHash` (`string, optional`): Block hash to query at. If omitted, uses the latest block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeys",
  "params": [
    "<prefix>",
    "<blockHash>"
  ],
  "id": 1
}
```

## Response Fields

- `result` (`array, required`): Array of hex-encoded storage keys matching the prefix

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "result": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d",
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da94f9aea1afa791265fae359272badc1cf8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48"
  ],
  "id": 1
}
```

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "state_getKeys",
  "params": [
    "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9"
  ],
  "id": 1
}
```

## Code Examples

Python
JavaScript
TypeScript (@polkadot/api)

```python
import requests
import json
from substrateinterface import SubstrateInterface

def get_storage_keys(prefix, block_hash=None):
    url = "https://api-kusama.n.dwellir.com/YOUR_API_KEY/YOUR_API_KEY"
    headers = {
        "Content-Type": "application/json"
    }
    
    params = [prefix, block_hash] if block_hash else [prefix]
    
    payload = {
        "jsonrpc": "2.0",
        "method": "state_getKeys",
        "params": params,
        "id": 1
    }
    
    response = requests.post(url, headers=headers, data=json.dumps(payload))
    return response.json()["result"]

# Example: Get all validator preferences keys
def get_validator_keys():
    # Staking.Validators storage prefix
    prefix = "0x5f3e4907f716ac89b6347d15ececedca9320c2dc4f5d7af5b320b04e2d1a3ff3"
    keys = get_storage_keys(prefix)
    
    print(f"Found {len(keys)} validator preference entries")
    
    for key in keys:
        # Extract validator account from key
        validator_account = key[-64:]
        print(f"Validator: 0x{validator_account}")
    
    return keys

# Example: Query all keys under a module
def get_module_keys(module_prefix):
    keys = get_storage_keys(module_prefix)
    
    # Group keys by storage item
    storage_items = {}
    for key in keys:
        # Storage keys typically have a fixed prefix per item
        item_prefix = key[:66]  # First 33 bytes (66 hex chars)
        if item_prefix not in storage_items:
            storage_items[item_prefix] = []
        storage_items[item_prefix].append(key)
    
    return storage_items
```

```javascript
const getStorageKeys = async (prefix, blockHash = null) => {
  const params = blockHash ? [prefix, blockHash] : [prefix];
  
  const response = await fetch('https://api-kusama.n.dwellir.com/YOUR_API_KEY/YOUR_API_KEY', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      jsonrpc: '2.0',
      method: 'state_getKeys',
      params: params,
      id: 1
    })
  });
  
  const data = await response.json();
  return data.result;
};

// Get all account keys (System.Account storage)
const accountPrefix = '0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9';
const accountKeys = await getStorageKeys(accountPrefix);
console.log(`Found ${accountKeys.length} accounts`);

// Extract account addresses from keys
accountKeys.forEach(key => {
  // The account address is the last 32 bytes of the key
  const addressHex = key.slice(-64);
  console.log('Account key:', key);
  console.log('Address portion:', addressHex);
});
```

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

async function queryStorageKeys() {
  const provider = new WsProvider('wss://api-kusama.n.dwellir.com/YOUR_API_KEY/YOUR_API_KEY');
  const api = await ApiPromise.create({ provider });
  
  // Method 1: Using high-level API to get keys
  const accountKeys = await api.query.system.account.keys();
  console.log('Account addresses:', accountKeys.map(k => k.toHuman()));
  
  // Method 2: Using low-level RPC for custom prefixes
  const prefix = api.query.system.account.keyPrefix();
  const keys = await api.rpc.state.getKeys(prefix);
  console.log(`Found ${keys.length} account storage keys`);
  
  // Method 3: Get keys for a specific map entry
  const validatorKeys = await api.query.staking.validators.keys();
  console.log('Active validators:', validatorKeys.length);
  
  // Process keys to extract data
  for (const key of keys) {
    // Decode the storage key
    const keyHex = key.toHex();
    console.log('Storage key:', keyHex);
    
    // Get the value for this key
    const value = await api.rpc.state.getStorage(key);
    console.log('Storage value:', value.toHex());
  }
  
  await api.disconnect();
}

// Advanced: Query keys with pagination
async function getKeysPagedExample() {
  const api = await ApiPromise.create({ 
    provider: new WsProvider('wss://api-kusama.n.dwellir.com/YOUR_API_KEY/YOUR_API_KEY') 
  });
  
  const prefix = api.query.system.account.keyPrefix();
  const pageSize = 100;
  let startKey = prefix;
  let allKeys = [];
  
  while (true) {
    // Note: state_getKeysPaged is used for pagination
    const keys = await api.rpc.state.getKeysPaged(prefix, pageSize, startKey);
    
    if (keys.length === 0) break;
    
    allKeys = allKeys.concat(keys);
    startKey = keys[keys.length - 1];
    
    console.log(`Fetched ${keys.length} keys, total: ${allKeys.length}`);
    
    if (keys.length < pageSize) break;
  }
  
  console.log(`Total keys found: ${allKeys.length}`);
  await api.disconnect();
}
```

## Common Storage Prefixes

| Module   | Storage Item  | Prefix (example)                                                     |
| -------- | ------------- | -------------------------------------------------------------------- |
| System   | Account       | `0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9` |
| Balances | TotalIssuance | `0xc2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80` |
| Staking  | Validators    | `0x5f3e4907f716ac89b6347d15ececedca9320c2dc4f5d7af5b320b04e2d1a3ff3` |
| Session  | NextKeys      | `0xcec5070d609dd3497f72bde07fc96ba0e0cdd062e6eaf24295ad4ccfc41d4609` |

## Batch Query Example

```javascript
// Efficiently query multiple storage values
async function batchQueryStorage(api, keys) {
  // Get all values in a single call
  const values = await api.rpc.state.queryStorageAt(keys);
  
  const results = {};
  keys.forEach((key, index) => {
    results[key.toString()] = values[index];
  });
  
  return results;
}

// Example usage
const keys = await getStorageKeys(accountPrefix);
const values = await batchQueryStorage(api, keys.slice(0, 10));
console.log('Batch query results:', values);
```

## Use Cases

1. **Account Discovery**: Find all accounts with balances
2. **Validator Enumeration**: List all validators in the network
3. **Storage Analysis**: Analyze storage usage by module
4. **Migration Scripts**: Iterate over storage for upgrades
5. **Indexing**: Build indexes of on-chain data

## Notes

- Large prefixes may return many keys - use pagination when available
- Keys are returned in lexicographical order
- The prefix must be hex-encoded
- Consider using `state_getKeysPaged` for large datasets
- Storage keys include both the storage prefix and the key data

## Related Methods

- [`state_getKeysPaged`](https://www.dwellir.com/docs/kusama/state_getKeysPaged) - Get keys with pagination
- [`state_getStorage`](https://www.dwellir.com/docs/kusama/state_getStorage) - Get storage value
- [`state_getMetadata`](https://www.dwellir.com/docs/kusama/state_getMetadata) - Get metadata to decode keys
