Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use bt decode in runtime call #188

Open
wants to merge 31 commits into
base: staging
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
d797295
use bt decode in runtime call
camfairchild Oct 15, 2024
f084774
add util and use decode_scale
camfairchild Oct 15, 2024
8acd33f
use dynamic runtime api info
camfairchild Oct 21, 2024
60cf8da
remove hard-coded type registry
camfairchild Oct 21, 2024
b5ba219
fix loading from rust type reg
camfairchild Oct 22, 2024
912a361
add new runtime call and query without decode
camfairchild Oct 22, 2024
8211f6d
fix impl for grab neurons multip
camfairchild Oct 22, 2024
de78d16
fix s list
camfairchild Oct 22, 2024
15eb5f2
typeidtoname is a staticmethod
camfairchild Oct 22, 2024
78a486b
put metadata_v15 attr in init
camfairchild Oct 22, 2024
44e019a
wip
camfairchild Oct 22, 2024
34c88ca
add catch for None result
camfairchild Nov 6, 2024
a9753df
bump bt deocde req
camfairchild Nov 13, 2024
0a7b613
add encode/decoded account id to utils
camfairchild Nov 13, 2024
82f846d
move decode account id to utils
camfairchild Nov 13, 2024
b5c4639
use btdecode encode and add encode as scale
camfairchild Nov 13, 2024
f88f84c
use encode as scale in runtime calls
camfairchild Nov 13, 2024
3f848df
Merge branch 'staging' into feat/use-bt-decode-in-runtime-call
camfairchild Nov 13, 2024
39ae665
Merge remote-tracking branch 'origin/staging' into feat/use-bt-decode…
thewhaleking Nov 22, 2024
bc2fb45
Merge branch 'staging' into feat/use-bt-decode-in-runtime-call
thewhaleking Dec 5, 2024
49ad893
Added note.
thewhaleking Dec 5, 2024
30ffb48
Merge branch 'staging' into feat/use-bt-decode-in-runtime-call
thewhaleking Dec 18, 2024
6d9e016
Fixed .value, ruff
thewhaleking Dec 18, 2024
4de9392
Fix catch for literal_eval
thewhaleking Dec 18, 2024
f41d839
change error colouring wrapping
camfairchild Dec 18, 2024
52a8951
extract value object where needed
camfairchild Dec 18, 2024
b3acffb
simplify get payment info
camfairchild Dec 18, 2024
7f0b991
dont try to encode scaletypes with encoded data
camfairchild Dec 18, 2024
9c0c268
Rename `'partialFee'` to `'partial_fee'`
thewhaleking Dec 18, 2024
e8341f2
Fixes type hint
thewhaleking Dec 19, 2024
b5ecad6
ruff
thewhaleking Dec 19, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 0 additions & 162 deletions bittensor_cli/src/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,168 +137,6 @@ class WalletValidationTypes(Enum):
"types": {
"Balance": "u64", # Need to override default u128
},
"runtime_api": {
"DelegateInfoRuntimeApi": {
"methods": {
"get_delegated": {
"params": [
{
"name": "coldkey",
"type": "Vec<u8>",
},
],
"type": "Vec<u8>",
},
"get_delegates": {
"params": [],
"type": "Vec<u8>",
},
}
},
"NeuronInfoRuntimeApi": {
"methods": {
"get_neuron_lite": {
"params": [
{
"name": "netuid",
"type": "u16",
},
{
"name": "uid",
"type": "u16",
},
],
"type": "Vec<u8>",
},
"get_neurons_lite": {
"params": [
{
"name": "netuid",
"type": "u16",
},
],
"type": "Vec<u8>",
},
"get_neuron": {
"params": [
{
"name": "netuid",
"type": "u16",
},
{
"name": "uid",
"type": "u16",
},
],
"type": "Vec<u8>",
},
"get_neurons": {
"params": [
{
"name": "netuid",
"type": "u16",
},
],
"type": "Vec<u8>",
},
}
},
"StakeInfoRuntimeApi": {
"methods": {
"get_stake_info_for_coldkey": {
"params": [
{
"name": "coldkey_account_vec",
"type": "Vec<u8>",
},
],
"type": "Vec<u8>",
},
"get_stake_info_for_coldkeys": {
"params": [
{
"name": "coldkey_account_vecs",
"type": "Vec<Vec<u8>>",
},
],
"type": "Vec<u8>",
},
},
},
"ValidatorIPRuntimeApi": {
"methods": {
"get_associated_validator_ip_info_for_subnet": {
"params": [
{
"name": "netuid",
"type": "u16",
},
],
"type": "Vec<u8>",
},
},
},
"SubnetInfoRuntimeApi": {
"methods": {
"get_subnet_hyperparams": {
"params": [
{
"name": "netuid",
"type": "u16",
},
],
"type": "Vec<u8>",
},
"get_subnet_info": {
"params": [
{
"name": "netuid",
"type": "u16",
},
],
"type": "Vec<u8>",
},
"get_subnets_info": {
"params": [],
"type": "Vec<u8>",
},
}
},
"SubnetRegistrationRuntimeApi": {
"methods": {"get_network_registration_cost": {"params": [], "type": "u64"}}
},
"ColdkeySwapRuntimeApi": {
"methods": {
"get_scheduled_coldkey_swap": {
"params": [
{
"name": "coldkey_account_vec",
"type": "Vec<u8>",
},
],
"type": "Vec<u8>",
},
"get_remaining_arbitration_period": {
"params": [
{
"name": "coldkey_account_vec",
"type": "Vec<u8>",
},
],
"type": "Vec<u8>",
},
"get_coldkey_swap_destinations": {
"params": [
{
"name": "coldkey_account_vec",
"type": "Vec<u8>",
},
],
"type": "Vec<u8>",
},
}
},
},
}

NETWORK_EXPLORER_MAP = {
Expand Down
143 changes: 130 additions & 13 deletions bittensor_cli/src/bittensor/async_substrate_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
from collections import defaultdict
from dataclasses import dataclass
from hashlib import blake2b
from munch import munchify, Munch
from typing import Optional, Any, Union, Callable, Awaitable, cast
from types import SimpleNamespace

from bt_decode import PortableRegistry, decode as decode_by_type_string, MetadataV15
from async_property import async_property
Expand All @@ -21,6 +23,8 @@
from substrateinterface.storage import StorageKey
import websockets

from .utils import bytes_from_hex_string_result

ResultHandler = Callable[[dict, Any], Awaitable[tuple[dict, bool]]]


Expand All @@ -32,6 +36,33 @@ def timeout_handler(signum, frame):
raise TimeoutException("Operation timed out")


class DictWithValue(dict):
value: Any

def __init__(self, value: Any = None):
super().__init__()
self.value = value

def __getitem__(self, key: Union[str, int]):
result = super().get(key)
if not result and isinstance(key, int):
# if the key is not found, return the key at the given index
return list(self.keys())[key]
return result

@classmethod
def from_dict(cls, dict_: dict):
inst = cls()
# recursively convert all values to DictWithValue
for key, value in dict_.items():
if isinstance(value, dict):
value = cls.from_dict(value)
inst[key] = value
inst.value = dict_

return inst


class ExtrinsicReceipt:
"""
Object containing information of submitted extrinsic. Block hash where extrinsic is included is required
Expand Down Expand Up @@ -818,6 +849,63 @@ async def initialize(self):
async def __aexit__(self, exc_type, exc_val, exc_tb):
pass

@staticmethod
def _type_registry_to_scale_info_types(
registry_types: list[dict[str, Any]],
) -> list[dict[str, Any]]:
scale_info_types = []
for type_entry in registry_types:
new_type_entry = DictWithValue(value=type_entry)
if (
"variant" in type_entry["type"]["def"]
and len(type_entry["type"]["def"]["variant"]) == 0
):
type_entry["type"]["def"]["variant"] = {
"variants": []
} # add empty variants field to variant type if empty

for key, value in type_entry.items():
if isinstance(value, dict):
entry = DictWithValue.from_dict(value)
else:
entry = SimpleNamespace(value=value)
new_type_entry[key] = entry

scale_info_types.append(new_type_entry)

return scale_info_types

def _type_id_to_name(self, ty_id: int) -> str:
type_string = f"scale_info::{ty_id}"

return type_string
camfairchild marked this conversation as resolved.
Show resolved Hide resolved

def _type_registry_apis_to_runtime_api(
self, apis: list[dict[str, Any]]
) -> dict[str, Any]:
runtime_api = {}
for api in apis:
api_name = api["name"]
methods = api["methods"]

runtime_api[api_name] = {
"methods": {
method["name"]: {
"description": "\n".join(method["docs"]),
"params": [
{
"name": input["name"],
"type": self._type_id_to_name(input["ty"]),
}
for input in method["inputs"]
],
"type": self._type_id_to_name(method["output"]),
}
for method in methods
}
}
return runtime_api

@property
def chain(self):
"""
Expand Down Expand Up @@ -852,6 +940,7 @@ async def load_registry(self):
metadata_option_bytes = bytes.fromhex(metadata_option_hex_str[2:])
metadata_v15 = MetadataV15.decode_from_metadata_option(metadata_option_bytes)
self.registry = PortableRegistry.from_metadata_v15(metadata_v15)
self.metadata_v15 = metadata_v15
camfairchild marked this conversation as resolved.
Show resolved Hide resolved

async def decode_scale(
self, type_string, scale_bytes: bytes, return_scale_obj=False
Expand Down Expand Up @@ -979,6 +1068,17 @@ async def get_runtime(block_hash, block_id) -> Runtime:
# self.debug_message('Add PortableRegistry from metadata to type registry')
self.runtime_config.add_portable_registry(self.metadata)

if self.metadata_v15:
metadata_v15 = self.metadata_v15.value()
self.runtime_config.update_from_scale_info_types(
self._type_registry_to_scale_info_types(
metadata_v15["types"]["types"]
)
)
self.runtime_config.type_registry["runtime_api"].update(
self._type_registry_apis_to_runtime_api(metadata_v15["apis"])
)

# Set active runtime version
self.runtime_config.set_active_spec_version_id(self.runtime_version)

Expand Down Expand Up @@ -1707,9 +1807,7 @@ async def rpc_request(
)
result = await self._make_rpc_request(payloads, runtime=runtime)
if "error" in result[payload_id][0]:
raise SubstrateRequestException(
result[payload_id][0]["error"]["message"]
)
raise SubstrateRequestException(result[payload_id][0]["error"]["message"])
if "result" in result[payload_id][0]:
return result[payload_id][0]
else:
Expand Down Expand Up @@ -2169,13 +2267,13 @@ async def get_chain_finalised_head(self):

return response.get("result")

async def runtime_call(
async def runtime_call_wait_to_decode(
self,
api: str,
method: str,
params: Optional[Union[list, dict]] = None,
block_hash: Optional[str] = None,
) -> ScaleType:
) -> tuple[str, bytes]:
"""
Calls a runtime API method

Expand All @@ -2184,7 +2282,7 @@ async def runtime_call(
:param params: List of parameters needed to call the runtime API
:param block_hash: Hash of the block at which to make the runtime API call

:return: ScaleType from the runtime call
:return: Tuple of the runtime call type and the result bytes
"""
await self.init_runtime()

Expand Down Expand Up @@ -2233,16 +2331,35 @@ async def runtime_call(
"state_call", [f"{api}_{method}", str(param_data), block_hash]
)

# Decode result
# TODO update this to use bt-decode
result_obj = runtime.runtime_config.create_scale_object(
runtime_call_def["type"]
return runtime_call_def["type"], bytes_from_hex_string_result(
result_data["result"]
)
result_obj.decode(
ScaleBytes(result_data["result"]),
check_remaining=self.config.get("strict_scale_decode"),

async def runtime_call(
self,
api: str,
method: str,
params: Optional[Union[list, dict]] = None,
block_hash: Optional[str] = None,
) -> ScaleType:
"""
Calls a runtime API method

:param api: Name of the runtime API e.g. 'TransactionPaymentApi'
:param method: Name of the method e.g. 'query_fee_details'
:param params: List of parameters needed to call the runtime API
:param block_hash: Hash of the block at which to make the runtime API call

:return: ScaleType from the runtime call
"""
# Get the runtime call type and result bytes
runtime_call_type, result_bytes = await self.runtime_call_wait_to_decode(
api, method, params, block_hash
)

# Decode the result bytes
result_obj = await self.decode_scale(runtime_call_type, result_bytes)

return result_obj

async def get_account_nonce(self, account_address: str) -> int:
Expand Down
Loading
Loading