|
| 1 | +--- |
| 2 | +id: iterate-keys |
| 3 | +title: Iterate keys |
| 4 | +--- |
| 5 | + |
| 6 | +[comment]: # (mx-abstract) |
| 7 | + |
| 8 | +## Overview |
| 9 | + |
| 10 | +Retrieving all storage keys for an account can be resource-intensive if the account has many entries. The `/address/iterate-keys` endpoint allows clients to efficiently iterate through all key-value pairs in an account's data trie, fetching them in batches and resuming from a checkpoint using an iterator state. This is especially useful for large accounts or when paginating through storage. |
| 11 | + |
| 12 | +If you need to ensure consistency across multiple requests (e.g., if the account might change), use the `?blockNonce={blockNonce}` query parameter to lock iteration to a specific trie root. |
| 13 | + |
| 14 | +:::warning |
| 15 | +This endpoint will only work if the node's `config.toml` file has the following setting enabled: |
| 16 | + |
| 17 | +``` |
| 18 | +[TrieLeavesRetrieverConfig] |
| 19 | + Enabled = true |
| 20 | +``` |
| 21 | +::: |
| 22 | + |
| 23 | +[comment]: # (mx-context-auto) |
| 24 | + |
| 25 | +## Endpoint details |
| 26 | + |
| 27 | +- **Method:** POST |
| 28 | +- **Path:** `/address/iterate-keys` |
| 29 | +- **Optional:** `/address/iterate-keys?blockNonce={blockNonce}` |
| 30 | + |
| 31 | +### Request body |
| 32 | + |
| 33 | +| Field | Type | Description | |
| 34 | +| -------------- | ------ | --------------------------------------------------------------------------------------------------| |
| 35 | +| `address` | string | Address of the account whose storage keys you want to iterate. | |
| 36 | +| `numKeys` | int | Number of keys to retrieve in this batch. If 0, retrieves as many as possible until timeout. | |
| 37 | +| `iteratorState`| array | Set to empty array for the first request, or use the value from the previous response to resume. | |
| 38 | + |
| 39 | +#### Example - First request |
| 40 | + |
| 41 | +```json |
| 42 | +{ |
| 43 | + "address": "erd1...", |
| 44 | + "numKeys": 100, |
| 45 | + "iteratorState": [] |
| 46 | +} |
| 47 | +``` |
| 48 | + |
| 49 | +#### Example - Subsequent request |
| 50 | + |
| 51 | +```json |
| 52 | +{ |
| 53 | + "address": "erd1...", |
| 54 | + "numKeys": 100, |
| 55 | + "iteratorState": [ |
| 56 | + "QTyP0ZbUPao3dJiNhdduVDc2GlJO5XNSljRJS2lpF00EBg==", |
| 57 | + "F6Wc4zEhjoS2cpcmb4h4tH+8hNHwbez/mskIzpKr7ooF", |
| 58 | + "qE7Onkq+OYx9bCx2OPRl5GUIE3iqqA0I+hC7E35+2EwG", |
| 59 | + "eNu9LmbWHS5cjjaONCn3oc22+9H/hc2rvjHdJVLb9p8H", |
| 60 | + "9ikE6F470N3x4UxfSnXpqM6ATHUpdAAk7TwNEziXD5QI", |
| 61 | + "pymZnCzkTZ91cKFLTUlY0S5du5deg3CJXcR/jZR9gDUJ", |
| 62 | + "dK7SeJcCggBlkhKoQpfLbbQ1RkwRgDENK8YhjUu71HcK", |
| 63 | + "pYbrJttg/Cqzxko2IyqVWLeEiY1ScLYjPiVdqNX1PFcL", |
| 64 | + "vTuXGEd5YBqLX/bwG9rOhb+Ect25N5IIEgHR8TMklL4M", |
| 65 | + "MXbChMP5migm07zByj85+h3EZorzDwj4A0lRcNBIV1QO", |
| 66 | + "wq+g7t7WX/6bEcxZhGvQlIfgJxzY/gK2BR/IDjBVYw8P" |
| 67 | + ] |
| 68 | +} |
| 69 | +``` |
| 70 | + |
| 71 | + |
| 72 | +### Response body |
| 73 | + |
| 74 | +| Field | Type | Description | |
| 75 | +|-------------------------|---------------------|-----------------------------------------------------------------------------| |
| 76 | +| `data.blockInfo` | object | Information about the block (nonce, hash, rootHash). | |
| 77 | +| `data.newIteratorState` | array \| null | Array of strings if more data remains, or null if iteration is complete. | |
| 78 | +| `data.pairs` | object | Key-value pairs (hex-encoded) retrieved in this batch. | |
| 79 | +| `error` | string | Error message, if any. | |
| 80 | +| `code` | string | Status code, e.g., "successful". | |
| 81 | + |
| 82 | +#### Example response (more data to fetch) |
| 83 | + |
| 84 | +```json |
| 85 | +{ |
| 86 | + "data": { |
| 87 | + "blockInfo": { |
| 88 | + "nonce": 141738, |
| 89 | + "hash": "f7fd9ee6a3a24ab63c30f2a7c9df360d8e1d367aed52b43ec527bfd6aa8eae35", |
| 90 | + "rootHash": "96bb085e08cec47a45df37ed07abd6ed2e22fdeeb5192a6a2bb624cb8c18b3e1" |
| 91 | + }, |
| 92 | + "newIteratorState": [ |
| 93 | + "JZWO0TF7sEredrzrZQ3aSj40w29valylR4GHv65qiBoADw==", |
| 94 | + "WrN0877/4OOj2muLRNNhXbSB7wBpSKVqHJRhiinqOuQB", |
| 95 | + "4WECDX5h4NSKqdG4KOJgOdlbmbKMOYDc0GmUPH7ALoUC", |
| 96 | + "j+j5EIMbiE6VXkRRarus5AMImhC4eo6HIb7SBNga9VMD", |
| 97 | + "kR1nAJ1HXgc1OKnuJOu2U4qlGVx90zTiiFzvvyTBZ2AE", |
| 98 | + "F6Wc4zEhjoS2cpcmb4h4tH+8hNHwbez/mskIzpKr7ooF", |
| 99 | + "qE7Onkq+OYx9bCx2OPRl5GUIE3iqqA0I+hC7E35+2EwG", |
| 100 | + "eNu9LmbWHS5cjjaONCn3oc22+9H/hc2rvjHdJVLb9p8H", |
| 101 | + "9ikE6F470N3x4UxfSnXpqM6ATHUpdAAk7TwNEziXD5QI", |
| 102 | + "pymZnCzkTZ91cKFLTUlY0S5du5deg3CJXcR/jZR9gDUJ", |
| 103 | + "dK7SeJcCggBlkhKoQpfLbbQ1RkwRgDENK8YhjUu71HcK", |
| 104 | + "pYbrJttg/Cqzxko2IyqVWLeEiY1ScLYjPiVdqNX1PFcL", |
| 105 | + "vTuXGEd5YBqLX/bwG9rOhb+Ect25N5IIEgHR8TMklL4M", |
| 106 | + "MXbChMP5migm07zByj85+h3EZorzDwj4A0lRcNBIV1QO", |
| 107 | + "wq+g7t7WX/6bEcxZhGvQlIfgJxzY/gK2BR/IDjBVYw8P" |
| 108 | + ], |
| 109 | + "pairs": { |
| 110 | + "454c524f4e4465736474415745534f4d452d313632623032": "0403", |
| 111 | + "454c524f4e4465736474415745534f4d452d383831343636": "0403" |
| 112 | + // ... more key-value pairs ... |
| 113 | + } |
| 114 | + }, |
| 115 | + "error": "", |
| 116 | + "code": "successful" |
| 117 | +} |
| 118 | +``` |
| 119 | + |
| 120 | +#### Example response (iteration complete) |
| 121 | + |
| 122 | +```json |
| 123 | +{ |
| 124 | + "data": { |
| 125 | + "blockInfo": { |
| 126 | + "nonce": 112594, |
| 127 | + "hash": "f26e9d8c00d7a56c071989d14544e0c3431eb33956854ce780374d8c08b4aa9f", |
| 128 | + "rootHash": "75c50f6913d4badb9635235f9dafc7eb14ce14406f8c59d05838ff25021c009f" |
| 129 | + }, |
| 130 | + "newIteratorState": null, |
| 131 | + "pairs": { |
| 132 | + "454c524f4e446573647446554e4749424c452d326562313837": "0401" |
| 133 | + } |
| 134 | + }, |
| 135 | + "error": "", |
| 136 | + "code": "successful" |
| 137 | +} |
| 138 | +``` |
| 139 | + |
| 140 | +[comment]: # (mx-context-auto) |
| 141 | + |
| 142 | +## Usage notes |
| 143 | + |
| 144 | +- The `pairs` object contains hex-encoded keys and values. Decode as needed. |
| 145 | +- Always pass `newIteratorState` as-is in your next request's `iteratorState` field to continue iteration. |
| 146 | +- When `newIteratorState` is null, all keys have been retrieved. |
| 147 | +- If `iteratorState` is an empty array (`[]`) in the request, iteration starts from the beginning of the trie. |
| 148 | +- If `numKeys` is 0, the server will return as many keys as possible until all are retrieved or until the `TrieOperationsDeadlineMilliseconds` timeout is reached. |
| 149 | +- If retrieving `numKeys` takes more time than the configured timeout, the request will return the keys collected up to that point. |
| 150 | +- Use `?blockNonce={blockNonce}` to ensure all requests iterate the same trie root, even if the account changes between requests. |
| 151 | + |
| 152 | +[comment]: # (mx-context-auto) |
| 153 | + |
| 154 | +## Example usage |
| 155 | + |
| 156 | +1. **Initial request:** |
| 157 | + - Send a POST with `iteratorState` as an empty array and desired `numKeys` (or 0 for maximum batch). |
| 158 | +2. **Subsequent requests:** |
| 159 | + - Use the `newIteratorState` from the previous response to fetch the next batch. Pass it as-is. |
| 160 | + - Optionally, provide `blockNonce` to ensure consistency if the account may change. |
| 161 | +3. **Finish:** |
| 162 | + - When `newIteratorState` is null, you have retrieved all keys. |
0 commit comments