From dbdde2c619ce926214662c6ac847c20fbe2d4fe0 Mon Sep 17 00:00:00 2001 From: bdhimes Date: Wed, 8 Oct 2025 22:35:33 +0200 Subject: [PATCH 01/15] Updates the type hint on ws_shutdown_timer in RetryAsyncSubstrate to match that of AsyncSubstrateInterface. --- async_substrate_interface/substrate_addons.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/async_substrate_interface/substrate_addons.py b/async_substrate_interface/substrate_addons.py index 4f2412f..3b0f0ba 100644 --- a/async_substrate_interface/substrate_addons.py +++ b/async_substrate_interface/substrate_addons.py @@ -264,7 +264,7 @@ def __init__( _mock: bool = False, _log_raw_websockets: bool = False, archive_nodes: Optional[list[str]] = None, - ws_shutdown_timer: float = 5.0, + ws_shutdown_timer: Optional[float] = 5.0, ): fallback_chains = fallback_chains or [] archive_nodes = archive_nodes or [] From 9f08c70c99d00e2399ce5744dcf2f9b7ccf91e0c Mon Sep 17 00:00:00 2001 From: bdhimes Date: Fri, 10 Oct 2025 16:24:47 +0200 Subject: [PATCH 02/15] Another missed type hint change --- async_substrate_interface/async_substrate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/async_substrate_interface/async_substrate.py b/async_substrate_interface/async_substrate.py index a93af0c..0fe3969 100644 --- a/async_substrate_interface/async_substrate.py +++ b/async_substrate_interface/async_substrate.py @@ -874,7 +874,7 @@ def __init__( retry_timeout: float = 60.0, _mock: bool = False, _log_raw_websockets: bool = False, - ws_shutdown_timer: float = 5.0, + ws_shutdown_timer: Optional[float] = 5.0, decode_ss58: bool = False, ): """ From 42fb3a189e5db984046d8aaf33302cd294cd3012 Mon Sep 17 00:00:00 2001 From: bdhimes Date: Fri, 10 Oct 2025 23:36:05 +0200 Subject: [PATCH 03/15] The asyncio queue needs to have its tasks marked done or they grow forever. --- async_substrate_interface/async_substrate.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/async_substrate_interface/async_substrate.py b/async_substrate_interface/async_substrate.py index 0fe3969..105b93a 100644 --- a/async_substrate_interface/async_substrate.py +++ b/async_substrate_interface/async_substrate.py @@ -755,6 +755,7 @@ async def _start_sending(self, ws) -> Exception: try: while True: to_send_ = await self._sending.get() + self._sending.task_done() send_id = to_send_["id"] to_send = json.dumps(to_send_) async with self._lock: @@ -848,7 +849,9 @@ async def retrieve(self, item_id: str) -> Optional[dict]: return res else: try: - return self._received_subscriptions[item_id].get_nowait() + subscription = self._received_subscriptions[item_id].get_nowait() + self._received_subscriptions[item_id].task_done() + return subscription except asyncio.QueueEmpty: pass if self._send_recv_task is not None and self._send_recv_task.done(): From 207ea244d7ed2145a1f2e35bc857862d41faf265 Mon Sep 17 00:00:00 2001 From: bdhimes Date: Sat, 11 Oct 2025 00:32:16 +0200 Subject: [PATCH 04/15] Finally! --- async_substrate_interface/async_substrate.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/async_substrate_interface/async_substrate.py b/async_substrate_interface/async_substrate.py index 105b93a..4c8509f 100644 --- a/async_substrate_interface/async_substrate.py +++ b/async_substrate_interface/async_substrate.py @@ -561,7 +561,7 @@ def __init__( self._received: dict[str, asyncio.Future] = {} self._received_subscriptions: dict[str, asyncio.Queue] = {} self._sending: Optional[asyncio.Queue] = None - self._send_recv_task = None + self._send_recv_task: Optional[asyncio.Task] = None self._inflight: dict[str, str] = {} self._attempts = 0 self._lock = asyncio.Lock() @@ -747,7 +747,7 @@ async def _start_receiving(self, ws: ClientConnection) -> Exception: elif isinstance(e, websockets.exceptions.ConnectionClosedOK): logger.debug("Websocket connection closed.") else: - logger.debug(f"Timeout occurred. Reconnecting.") + logger.debug(f"Timeout occurred.") return e async def _start_sending(self, ws) -> Exception: @@ -780,7 +780,7 @@ async def _start_sending(self, ws) -> Exception: elif isinstance(e, websockets.exceptions.ConnectionClosedOK): logger.debug("Websocket connection closed.") else: - logger.debug("Timeout occurred. Reconnecting.") + logger.debug("Timeout occurred.") return e async def send(self, payload: dict) -> str: @@ -856,7 +856,10 @@ async def retrieve(self, item_id: str) -> Optional[dict]: pass if self._send_recv_task is not None and self._send_recv_task.done(): if not self._send_recv_task.cancelled(): - if isinstance((e := self._send_recv_task.exception()), Exception): + if isinstance((e := self._send_recv_task.result()), Exception): + logger.exception(f"Websocket sending exception: {e}") + raise e + elif isinstance((e := self._send_recv_task.result()), Exception): logger.exception(f"Websocket sending exception: {e}") raise e await asyncio.sleep(0.1) From 06da1924ba9e0c12e9a48f387f3aeb8e6960c8f3 Mon Sep 17 00:00:00 2001 From: bdhimes Date: Sat, 11 Oct 2025 01:02:16 +0200 Subject: [PATCH 05/15] Thank you Abe --- async_substrate_interface/async_substrate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/async_substrate_interface/async_substrate.py b/async_substrate_interface/async_substrate.py index 4c8509f..7f5cb71 100644 --- a/async_substrate_interface/async_substrate.py +++ b/async_substrate_interface/async_substrate.py @@ -856,7 +856,7 @@ async def retrieve(self, item_id: str) -> Optional[dict]: pass if self._send_recv_task is not None and self._send_recv_task.done(): if not self._send_recv_task.cancelled(): - if isinstance((e := self._send_recv_task.result()), Exception): + if isinstance((e := self._send_recv_task.exception()), Exception): logger.exception(f"Websocket sending exception: {e}") raise e elif isinstance((e := self._send_recv_task.result()), Exception): From e7e77ab1cd887241f939233287ff905120f78c94 Mon Sep 17 00:00:00 2001 From: Roman Chkhaidze Date: Fri, 10 Oct 2025 16:31:24 -0700 Subject: [PATCH 06/15] update workflows --- .github/workflows/check-sdk-tests.yml | 41 +++++++++++++++++++++------ .github/workflows/e2e-tests.yml | 2 +- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/.github/workflows/check-sdk-tests.yml b/.github/workflows/check-sdk-tests.yml index 1e2e295..1e68fd3 100644 --- a/.github/workflows/check-sdk-tests.yml +++ b/.github/workflows/check-sdk-tests.yml @@ -15,9 +15,17 @@ on: - staging types: [opened, synchronize, reopened, labeled, unlabeled] + workflow_dispatch: + inputs: + bittensor_branch: + description: "Optional: Bittensor branch to use instead of staging" + required: false + default: "staging" + env: CARGO_TERM_COLOR: always VERBOSE: ${{ github.event.inputs.verbose }} + BITTENSOR_BRANCH: ${{ github.event.inputs.bittensor_branch || 'staging' }} jobs: apply-label-to-new-pr: @@ -79,9 +87,15 @@ jobs: working-directory: ${{ github.workspace }} run: git clone https://github.com/opentensor/bittensor.git - - name: Checkout + - name: Verify and checkout Bittensor branch working-directory: ${{ github.workspace }}/bittensor - run: git checkout staging + run: | + if ! git fetch origin $BITTENSOR_BRANCH; then + echo "❌ Error: Branch '$BITTENSOR_BRANCH' does not exist in opentensor/bittensor." + exit 1 + fi + git checkout FETCH_HEAD + echo "✅ Using Bittensor branch: $BITTENSOR_BRANCH" - name: Install dependencies run: sudo apt-get install -y jq @@ -90,11 +104,14 @@ jobs: id: get-tests run: | test_files=$(find ${{ github.workspace }}/bittensor/tests/e2e_tests -name "test*.py" | jq -R -s -c 'split("\n") | map(select(. != ""))') - echo "::set-output name=test-files::$test_files" + echo "test-files=$test_files" >> $GITHUB_OUTPUT shell: bash pull-docker-image: - needs: check-labels + needs: + - check-labels + - find-e2e-tests + runs-on: ubuntu-latest if: always() && needs.check-labels.outputs.run-sdk-tests == 'true' steps: @@ -163,8 +180,12 @@ jobs: working-directory: ${{ github.workspace }}/bittensor run: | source ${{ github.workspace }}/venv/bin/activate - git checkout staging - git fetch origin staging + if ! git fetch origin $BITTENSOR_BRANCH; then + echo "❌ Error: Branch '$BITTENSOR_BRANCH' does not exist in opentensor/bittensor." + exit 1 + fi + git checkout FETCH_HEAD + echo "✅ Using Bittensor branch: $BITTENSOR_BRANCH" python3 -m pip install --upgrade pip python3 -m pip install '.[dev]' @@ -225,8 +246,12 @@ jobs: working-directory: ${{ github.workspace }}/bittensor run: | source ${{ github.workspace }}/venv/bin/activate - git checkout staging - git fetch origin staging + if ! git fetch origin $BITTENSOR_BRANCH; then + echo "❌ Error: Branch '$BITTENSOR_BRANCH' does not exist in opentensor/bittensor." + exit 1 + fi + git checkout FETCH_HEAD + echo "✅ Using Bittensor branch: $BITTENSOR_BRANCH" python3 -m pip install --upgrade pip python3 -m pip install '.[dev]' diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index f87dff4..4bd819b 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -1,4 +1,4 @@ -name: E2E Tests +name: ASI E2E Tests concurrency: group: e2e-${{ github.event.pull_request.number || github.ref }} From 28a5b54a908581e6aac7f02897e80531fe9f3e84 Mon Sep 17 00:00:00 2001 From: Roman Chkhaidze Date: Fri, 10 Oct 2025 17:14:13 -0700 Subject: [PATCH 07/15] add logic for manual run --- .github/workflows/check-sdk-tests.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/check-sdk-tests.yml b/.github/workflows/check-sdk-tests.yml index 1e68fd3..9e40b61 100644 --- a/.github/workflows/check-sdk-tests.yml +++ b/.github/workflows/check-sdk-tests.yml @@ -62,8 +62,16 @@ jobs: - name: Check out repository uses: actions/checkout@v4 - - name: Get labels from PR + - name: Skip label check for manual runs id: get-labels + if: ${{ github.event_name == 'workflow_dispatch' }} + run: | + echo "Manual workflow dispatch detected, skipping PR label check." + echo "run-sdk-tests=true" >> $GITHUB_OUTPUT + + - name: Get labels from PR + id: get-labels-pr + if: ${{ github.event_name == 'pull_request' }} run: | sleep 5 LABELS=$(gh api repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/labels --jq '.[].name') From d28ea7d37eebf6da5aef0a0ab2e1d18a4641ac4e Mon Sep 17 00:00:00 2001 From: bdhimes Date: Tue, 14 Oct 2025 18:41:40 +0200 Subject: [PATCH 08/15] Typing annotations --- async_substrate_interface/async_substrate.py | 3 ++- async_substrate_interface/sync_substrate.py | 3 ++- async_substrate_interface/types.py | 5 +++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/async_substrate_interface/async_substrate.py b/async_substrate_interface/async_substrate.py index 7f5cb71..d5b8216 100644 --- a/async_substrate_interface/async_substrate.py +++ b/async_substrate_interface/async_substrate.py @@ -55,6 +55,7 @@ RuntimeCache, SubstrateMixin, Preprocessed, + RequestResults, ) from async_substrate_interface.utils import ( hex_to_bytes, @@ -2391,7 +2392,7 @@ async def _make_rpc_request( attempt: int = 1, runtime: Optional[Runtime] = None, force_legacy_decode: bool = False, - ) -> RequestManager.RequestResults: + ) -> RequestResults: request_manager = RequestManager(payloads) subscription_added = False diff --git a/async_substrate_interface/sync_substrate.py b/async_substrate_interface/sync_substrate.py index 1575a8e..9d743c9 100644 --- a/async_substrate_interface/sync_substrate.py +++ b/async_substrate_interface/sync_substrate.py @@ -34,6 +34,7 @@ RequestManager, Preprocessed, ScaleObj, + RequestResults, ) from async_substrate_interface.utils import ( hex_to_bytes, @@ -1892,7 +1893,7 @@ def _make_rpc_request( result_handler: Optional[ResultHandler] = None, attempt: int = 1, force_legacy_decode: bool = False, - ) -> RequestManager.RequestResults: + ) -> RequestResults: request_manager = RequestManager(payloads) _received = {} subscription_added = False diff --git a/async_substrate_interface/types.py b/async_substrate_interface/types.py index a5cac00..52cf69b 100644 --- a/async_substrate_interface/types.py +++ b/async_substrate_interface/types.py @@ -369,9 +369,10 @@ def resolve_type_definition(type_id_): self.type_id_to_name = type_id_to_name -class RequestManager: - RequestResults = dict[Union[str, int], list[Union[ScaleType, dict]]] +RequestResults = dict[Union[str, int], list[Union[ScaleType, dict]]] + +class RequestManager: def __init__(self, payloads): self.response_map = {} self.responses = defaultdict( From 3aa45fa4f5815bc57cf193875afeb29ea7bbc580 Mon Sep 17 00:00:00 2001 From: bdhimes Date: Tue, 14 Oct 2025 18:42:19 +0200 Subject: [PATCH 09/15] Improved logic for async fully-exhaust query map --- async_substrate_interface/async_substrate.py | 48 +++++++++++--------- async_substrate_interface/utils/decoding.py | 4 +- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/async_substrate_interface/async_substrate.py b/async_substrate_interface/async_substrate.py index d5b8216..f0c4a92 100644 --- a/async_substrate_interface/async_substrate.py +++ b/async_substrate_interface/async_substrate.py @@ -3670,34 +3670,40 @@ async def query_map( self.decode_ss58, ) else: - all_responses = [] page_batches = [ result_keys[i : i + page_size] for i in range(0, len(result_keys), page_size) ] changes = [] - for batch_group in [ - # run five concurrent batch pulls; could go higher, but it's good to be a good citizens - # of the ecosystem - page_batches[i : i + 5] - for i in range(0, len(page_batches), 5) - ]: - all_responses.extend( - await asyncio.gather( - *[ - self.rpc_request( - method="state_queryStorageAt", - params=[batch_keys, block_hash], - runtime=runtime, - ) - for batch_keys in batch_group - ] + payloads = [] + for idx, page_batch in enumerate(page_batches): + payloads.append( + self.make_payload( + str(idx), "state_queryStorageAt", [page_batch, block_hash] ) ) - for response in all_responses: - for result_group in response["result"]: - changes.extend(result_group["changes"]) - + results: RequestResults = await self._make_rpc_request( + payloads, runtime=runtime + ) + for result in results.values(): + res = result[0] + if "error" in res: + err_msg = res["error"]["message"] + if ( + "Client error: Api called for an unknown Block: State already discarded" + in err_msg + ): + bh = err_msg.split("State already discarded for ")[ + 1 + ].strip() + raise StateDiscardedError(bh) + else: + raise SubstrateRequestException(err_msg) + elif "result" not in res: + raise SubstrateRequestException(res) + else: + for result_group in res["result"]: + changes.extend(result_group["changes"]) result = decode_query_map( changes, prefix, diff --git a/async_substrate_interface/utils/decoding.py b/async_substrate_interface/utils/decoding.py index 9557159..1f695d5 100644 --- a/async_substrate_interface/utils/decoding.py +++ b/async_substrate_interface/utils/decoding.py @@ -113,7 +113,9 @@ def concat_hash_len(key_hasher: str) -> int: for item in result_group_changes: pre_decoded_keys.append(bytes.fromhex(item[0][len(prefix) :])) - pre_decoded_values.append(hex_to_bytes_(item[1])) + pre_decoded_values.append( + hex_to_bytes_(item[1]) if item[1] is not None else b"" + ) all_decoded = _decode_scale_list_with_runtime( pre_decoded_key_types + pre_decoded_value_types, pre_decoded_keys + pre_decoded_values, From 2cda33e1c1afa33050517df077ff6182b221cbc2 Mon Sep 17 00:00:00 2001 From: bdhimes Date: Wed, 15 Oct 2025 15:58:41 +0200 Subject: [PATCH 10/15] Ensures `_make_rpc_request` request manager keys are unique to prevent possible lockups. --- async_substrate_interface/async_substrate.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/async_substrate_interface/async_substrate.py b/async_substrate_interface/async_substrate.py index f0c4a92..d7df725 100644 --- a/async_substrate_interface/async_substrate.py +++ b/async_substrate_interface/async_substrate.py @@ -2395,6 +2395,9 @@ async def _make_rpc_request( ) -> RequestResults: request_manager = RequestManager(payloads) + if len(set(x["id"] for x in payloads)) != len(payloads): + raise ValueError("Payloads must have unique ids") + subscription_added = False async with self.ws as ws: @@ -3670,6 +3673,7 @@ async def query_map( self.decode_ss58, ) else: + # storage item and value scale type are not included here because this is batch-decoded in rust page_batches = [ result_keys[i : i + page_size] for i in range(0, len(result_keys), page_size) From c642732d2bdf2f548178e2aec0839f3d4ca88d1c Mon Sep 17 00:00:00 2001 From: bdhimes Date: Wed, 15 Oct 2025 16:00:21 +0200 Subject: [PATCH 11/15] Do the same for sync --- async_substrate_interface/sync_substrate.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/async_substrate_interface/sync_substrate.py b/async_substrate_interface/sync_substrate.py index 9d743c9..5349b31 100644 --- a/async_substrate_interface/sync_substrate.py +++ b/async_substrate_interface/sync_substrate.py @@ -1896,6 +1896,10 @@ def _make_rpc_request( ) -> RequestResults: request_manager = RequestManager(payloads) _received = {} + + if len(set(x["id"] for x in payloads)) != len(payloads): + raise ValueError("Payloads must have unique ids") + subscription_added = False ws = self.connect(init=False if attempt == 1 else True) From 1d7d9ecfbf65cc0fdbe05e28efe69e25e4259339 Mon Sep 17 00:00:00 2001 From: bdhimes Date: Wed, 15 Oct 2025 19:46:14 +0200 Subject: [PATCH 12/15] Edge case where passing decode_ss58 = True to decode query map but old old blocks are encoded already as str --- async_substrate_interface/utils/decoding.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/async_substrate_interface/utils/decoding.py b/async_substrate_interface/utils/decoding.py index 1f695d5..8b191b3 100644 --- a/async_substrate_interface/utils/decoding.py +++ b/async_substrate_interface/utils/decoding.py @@ -135,7 +135,10 @@ def concat_hash_len(key_hasher: str) -> int: if len(param_types) - len(params) == 1: item_key = dk[1] if decode_ss58: - if kts[kts.index(", ") + 2 : kts.index(")")] == "scale_info::0": + if ( + isinstance(item_key[0], (tuple, list)) + and kts[kts.index(", ") + 2 : kts.index(")")] == "scale_info::0" + ): item_key = ss58_encode(bytes(item_key[0]), runtime.ss58_format) else: try: From 413f3c2e0188ea65b66d1737b5caf71d88efe9f7 Mon Sep 17 00:00:00 2001 From: bdhimes Date: Wed, 15 Oct 2025 22:44:32 +0200 Subject: [PATCH 13/15] Adds type annotations for Runtime --- async_substrate_interface/types.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/async_substrate_interface/types.py b/async_substrate_interface/types.py index 52cf69b..f1b4917 100644 --- a/async_substrate_interface/types.py +++ b/async_substrate_interface/types.py @@ -6,7 +6,9 @@ from datetime import datetime from typing import Optional, Union, Any +import scalecodec.types from bt_decode import PortableRegistry, encode as encode_by_type_string +from bt_decode.bt_decode import MetadataV15 from scalecodec import ss58_encode, ss58_decode, is_valid_ss58_address from scalecodec.base import RuntimeConfigurationObject, ScaleBytes from scalecodec.type_registry import load_type_registry_preset @@ -121,13 +123,13 @@ class Runtime: def __init__( self, chain: str, - metadata, - type_registry, + metadata: scalecodec.types.GenericMetadataVersioned, + type_registry: dict, runtime_config: Optional[RuntimeConfigurationObject] = None, - metadata_v15=None, - runtime_info=None, - registry=None, - ss58_format=SS58_FORMAT, + metadata_v15: Optional[MetadataV15] = None, + runtime_info: Optional[dict] = None, + registry: Optional[PortableRegistry] = None, + ss58_format: int = SS58_FORMAT, ): self.ss58_format = ss58_format self.config = {} From 9f74a8aeb14e5f532d99450ebfb934d145ccaf55 Mon Sep 17 00:00:00 2001 From: bdhimes Date: Wed, 15 Oct 2025 18:35:04 +0200 Subject: [PATCH 14/15] Updates changelog + version --- CHANGELOG.md | 11 +++++++++++ pyproject.toml | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bab699d..ea5ec37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,15 @@ # Changelog +## 1.5.7 /2025-10-15 +* Updates the type hint on ws_shutdown_timer in RetryAsyncSubstrate by @thewhaleking in https://github.com/opentensor/async-substrate-interface/pull/203 +* correct type hint by @thewhaleking in https://github.com/opentensor/async-substrate-interface/pull/204 +* Clear asyncio.Queue after retrieval by @thewhaleking in https://github.com/opentensor/async-substrate-interface/pull/206 +* Add the option to manually specify the Bittensor branch when running with `workflow_dispatch` by @basfroman in https://github.com/opentensor/async-substrate-interface/pull/208 +* Subscription Exception Handling by @thewhaleking in https://github.com/opentensor/async-substrate-interface/pull/207 +* more efficient query map by @thewhaleking in https://github.com/opentensor/async-substrate-interface/pull/211 +* Unique keys in request manager by @thewhaleking in https://github.com/opentensor/async-substrate-interface/pull/212 + +**Full Changelog**: https://github.com/opentensor/async-substrate-interface/compare/v1.5.6...v1.5.7 + ## 1.5.6 /2025-10-08 * Clean Up Error Handling by @thewhaleking in https://github.com/opentensor/async-substrate-interface/pull/193 * Avoids ID of 'None' in queries by @thewhaleking in https://github.com/opentensor/async-substrate-interface/pull/196 diff --git a/pyproject.toml b/pyproject.toml index 2fd3b5b..f194af7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "async-substrate-interface" -version = "1.5.6" +version = "1.5.7" description = "Asyncio library for interacting with substrate. Mostly API-compatible with py-substrate-interface" readme = "README.md" license = { file = "LICENSE" } From 06287d9eccf33c5db553753a1bb7b8021a042c2e Mon Sep 17 00:00:00 2001 From: bdhimes Date: Wed, 15 Oct 2025 23:11:27 +0200 Subject: [PATCH 15/15] Updates changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea5ec37..4bd1e14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ * Subscription Exception Handling by @thewhaleking in https://github.com/opentensor/async-substrate-interface/pull/207 * more efficient query map by @thewhaleking in https://github.com/opentensor/async-substrate-interface/pull/211 * Unique keys in request manager by @thewhaleking in https://github.com/opentensor/async-substrate-interface/pull/212 +* Adds type annotations for Runtime by @thewhaleking in https://github.com/opentensor/async-substrate-interface/pull/214 +* Edge case ss58 decoding in decode_query_map by @thewhaleking in https://github.com/opentensor/async-substrate-interface/pull/213 **Full Changelog**: https://github.com/opentensor/async-substrate-interface/compare/v1.5.6...v1.5.7