Skip to content

Query storage

In Substrate, any pallet can introduce new storage items that will become part of the blockchain state. These storage items can be simple single values, or more complex storage maps.

The runtime exposes several storage functions to query those storage items and are provided in the metadata. See the metadata documentation for more information of available storage functions for several Substrate runtimes.

Example

1
2
3
4
result = substrate.query('System', 'Account', ['F4xQKRUagnSGjFqafyhajLs94e7Vvzvr8ebwYJceKpr8R7T'])

print(result.value['nonce']) #  7695
print(result.value['data']['free']) # 635278638077956496

State at a specific block hash

1
2
3
4
5
6
7
8
9
account_info = substrate.query(
    module='System',
    storage_function='Account',
    params=['F4xQKRUagnSGjFqafyhajLs94e7Vvzvr8ebwYJceKpr8R7T'],
    block_hash='0x176e064454388fd78941a0bace38db424e71db9d5d5ed0272ead7003a02234fa'
)

print(account_info['nonce'].value) #  7673
print(account_info['data']['free'].value) # 637747267365404068

Type decomposition information

Some storage functions need parameters and some of those parameter types can be quite complex to compose.

To retrieve more information how to format those storage function parameters, the helper function get_param_info() is available:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
storage_function = substrate.get_metadata_storage_function("Tokens", "TotalIssuance")

print(storage_function.get_param_info())
# [{
#   'Token': ('ACA', 'AUSD', 'DOT', 'LDOT', 'RENBTC', 'CASH', 'KAR', 'KUSD', 'KSM', 'LKSM', 'TAI', 'BNC', 'VSKSM', 'PHA', 'KINT', 'KBTC'), 
#   'DexShare': ({'Token': ('ACA', 'AUSD', 'DOT', 'LDOT', 'RENBTC', 'CASH', 'KAR', 'KUSD', 'KSM', 'LKSM', 'TAI', 'BNC', 'VSKSM', 'PHA', 'KINT', 'KBTC'), 'Erc20': '[u8; 20]', 'LiquidCrowdloan': 'u32', 'ForeignAsset': 'u16'}, {'Token': ('ACA', 'AUSD', 'DOT', 'LDOT', 'RENBTC', 'CASH', 'KAR', 'KUSD', 'KSM', 'LKSM', 'TAI', 'BNC', 'VSKSM', 'PHA', 'KINT', 'KBTC'), 'Erc20': '[u8; 20]', 'LiquidCrowdloan': 'u32', 'ForeignAsset': 'u16'}), 
#   'Erc20': '[u8; 20]', 
#   'StableAssetPoolToken': 'u32', 
#   'LiquidCrowdloan': 'u32', 
#   'ForeignAsset': 'u16'
# }]

Querying multiple storage entries at once

When a large amount of storage entries is requested, the most efficient way is to use the query_multi() function. This will batch all the requested storage entries in one RPC request.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
storage_keys = [
    substrate.create_storage_key(
        "System", "Account", ["F4xQKRUagnSGjFqafyhajLs94e7Vvzvr8ebwYJceKpr8R7T"]
    ),
    substrate.create_storage_key(
        "System", "Account", ["GSEX8kR4Kz5UZGhvRUCJG93D5hhTAoVZ5tAe6Zne7V42DSi"]
    ),
    substrate.create_storage_key(
        "Staking", "Bonded", ["GSEX8kR4Kz5UZGhvRUCJG93D5hhTAoVZ5tAe6Zne7V42DSi"]
    )
]

result = substrate.query_multi(storage_keys)

for storage_key, value_obj in result:
    print(storage_key, value_obj)

Query a mapped storage function

Mapped storage functions can be iterated over all key/value pairs, for these type of storage functions query_map() can be used.

The result is a QueryMapResult object, which is an iterator:

1
2
3
4
5
# Retrieve the first 199 System.Account entries
result = substrate.query_map('System', 'Account', max_results=199)

for account, account_info in result:
    print(f"Free balance of account '{account.value}': {account_info.value['data']['free']}")

These results are transparently retrieved in batches capped by the page_size kwarg, currently the maximum page_size restricted by the RPC node is 1000

1
2
3
4
5
# Retrieve all System.Account entries in batches of 200 (automatically appended by `QueryMapResult` iterator)
result = substrate.query_map('System', 'Account', page_size=200, max_results=400)

for account, account_info in result:
    print(f"Free balance of account '{account.value}': {account_info.value['data']['free']}")

Querying a DoubleMap storage function:

1
2
3
4
5
era_stakers = substrate.query_map(
    module='Staking',
    storage_function='ErasStakers',
    params=[2100]
)