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

Fix/only explorer if known network #1037

Merged
merged 10 commits into from
Jan 19, 2023
10 changes: 10 additions & 0 deletions bittensor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,16 @@ def turn_console_off():
__local_entrypoint__ = "ws://127.0.0.1:9945"


# Block Explorers map network to explorer url
## Must all be polkadotjs explorer urls
__network_explorer_map__ = {
'local': "https://explorer.nakamoto.opentensor.ai/#/explorer",
'nakamoto': "https://explorer.nakamoto.opentensor.ai/#/explorer",
'endpoint': "https://explorer.nakamoto.opentensor.ai/#/",
'nobunaga': "https://staging.opentensor.ai/#/explorer",
'finney': "https://polkadot.js.org/apps/?rpc=wss://staging.parachain.opentensor.ai#/explorer"
}

# Avoid collisions with other processes
from .utils.test_utils import get_random_unused_port
mock_subtensor_port = get_random_unused_port()
Expand Down
7 changes: 5 additions & 2 deletions bittensor/_subtensor/extrinsics/transfer.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,11 @@ def transfer_extrinsic(
bittensor.__console__.print(":white_heavy_check_mark: [green]Finalized[/green]")
block_hash = response.block_hash
bittensor.__console__.print("[green]Block Hash: {}[/green]".format( block_hash ))
explorer_url = "https://explorer.nakamoto.opentensor.ai/#/explorer/query/{block_hash}".format( block_hash = block_hash )
bittensor.__console__.print("[green]Explorer Link: {}[/green]".format( explorer_url ))

explorer_url = bittensor.utils.get_explorer_url_for_network( subtensor.network, block_hash )
if explorer_url is not None:
bittensor.__console__.print("[green]Explorer Link: {}[/green]".format( explorer_url ))

else:
bittensor.__console__.print(":cross_mark: [red]Failed[/red]: error:{}".format(response.error_message))

Expand Down
2 changes: 2 additions & 0 deletions bittensor/_subtensor/subtensor_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,8 @@ def unstake_multiple (
""" Removes stake from each hotkey_ss58 in the list, using each amount, to a common coldkey. """
return unstake_multiple_extrinsic( self, wallet, hotkey_ss58s, amounts, wait_for_inclusion, wait_for_finalization, prompt)



def unstake (
self,
wallet: 'bittensor.wallet',
Expand Down
43 changes: 42 additions & 1 deletion bittensor/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,48 @@ def strtobool(val: str) -> bool:
else:
raise ValueError("invalid truth value %r" % (val,))

def get_explorer_root_url_by_network_from_map(network: str, network_map: Dict[str, str]) -> Optional[str]:
r"""
Returns the explorer root url for the given network name from the given network map.

Args:
network(str): The network to get the explorer url for.
network_map(Dict[str, str]): The network map to get the explorer url from.

Returns:
The explorer url for the given network.
Or None if the network is not in the network map.
"""
explorer_url: Optional[str] = None
if network in network_map:
explorer_url = network_map[network]

return explorer_url


def get_explorer_url_for_network(network: str, block_hash: str) -> Optional[str]:
r"""
Returns the explorer url for the given block hash and network.

Args:
network(str): The network to get the explorer url for.
block_hash(str): The block hash to get the explorer url for.

Returns:
The explorer url for the given block hash and network.
Or None if the network is not known.
"""

explorer_url: Optional[str] = None
# Will be None if the network is not known. i.e. not in bittensor.__network_explorer_map__
explorer_root_url: Optional[str] = get_explorer_root_url_by_network_from_map(network, bittensor.__network_explorer_map__)

if explorer_root_url is not None:
# We are on a known network.
explorer_url = "{root_url}/query/{block_hash}".format( root_url=explorer_root_url, block_hash = block_hash )

return explorer_url

def ss58_address_to_bytes(ss58_address: str) -> bytes:
"""Converts a ss58 address to a bytes object."""
account_id_hex: str = scalecodec.ss58_decode(ss58_address, bittensor.__ss58_format__)
Expand All @@ -213,4 +255,3 @@ def u8_key_to_ss58(u8_key: List[int]) -> str:
"""
# First byte is length, then 32 bytes of key.
return scalecodec.ss58_encode( bytes(u8_key).hex(), bittensor.__ss58_format__)

3 changes: 2 additions & 1 deletion requirements/dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ pytest-xdist==3.0.2
pytest-rerunfailures==10.2
coveralls==3.3.1
pytest-cov==4.0.0
codecov==2.1.12
codecov==2.1.12
ddt==1.6.0
47 changes: 44 additions & 3 deletions tests/unit_tests/bittensor_tests/utils/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,21 @@
import unittest
from sys import platform
from types import SimpleNamespace
from typing import Dict
from unittest.mock import MagicMock, patch

import bittensor
import pytest
import torch
from _pytest.fixtures import fixture
from bittensor.utils import CUDASolver

from ddt import data, ddt, unpack

import torch
from loguru import logger
from substrateinterface.base import Keypair

import bittensor
from bittensor.utils import CUDASolver


@fixture(scope="function")
def setup_chain():
Expand Down Expand Up @@ -546,6 +551,42 @@ class MockException(Exception):
## Should incerase by the number of nonces tried == TPB * update_interval
self.assertEqual(nonce_start_after_iteration, (initial_nonce_start + update_interval * TPB) % nonce_limit, "nonce_start was not updated by the correct amount")

@ddt
class TestExplorerURL(unittest.TestCase):
network_map: Dict[str, str] = {
"nakamoto": "https://polkadot.js.org/apps/?rpc=wss://archivelb.nakamoto.opentensor.ai:9943#/explorer",
"example": "https://polkadot.js.org/apps/?rpc=wss://example.example.com#/explorer",
"nobunaga": "https://polkadot.js.org/apps/?rpc=wss://nobunaga.bittensor.com:9943#/explorer",
# "bad": None # no explorer for this network
camfairchild marked this conversation as resolved.
Show resolved Hide resolved
}

@data(
("nobunaga", "https://polkadot.js.org/apps/?rpc=wss://nobunaga.bittensor.com:9943#/explorer"),
("nakamoto", "https://polkadot.js.org/apps/?rpc=wss://archivelb.nakamoto.opentensor.ai:9943#/explorer"),
("example", "https://polkadot.js.org/apps/?rpc=wss://example.example.com#/explorer"),
("bad", None),
("", None),
("networknamewithoutexplorer", None)
)
@unpack
def test_get_explorer_root_url_by_network_from_map(self, network: str, expected: str) -> str:
self.assertEqual(bittensor.utils.get_explorer_root_url_by_network_from_map(network, self.network_map), expected)

@data(
("nobunaga", "0x123", "https://polkadot.js.org/apps/?rpc=wss://nobunaga.bittensor.com:9943#/explorer/query/0x123"),
("example", "0x123", "https://polkadot.js.org/apps/?rpc=wss://example.example.com#/explorer/query/0x123"),
("bad", "0x123", None),
("", "0x123", None),
("networknamewithoutexplorer", "0x123", None)
)
@unpack
def test_get_explorer_url_for_network_by_network_and_block_hash(self, network: str, block_hash: str, expected: str) -> str:
def override_map_func(network: str, _) -> str:
return self.network_map[network]

with patch('bittensor.utils.get_explorer_root_url_by_network_from_map', side_effect=override_map_func):
self.assertEqual(bittensor.utils.get_explorer_url_for_network(network, block_hash), expected)


if __name__ == "__main__":
unittest.main()