Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
ab3bad1
remove miniupnpc
ifrit98 Aug 23, 2023
2834cc3
add try/except and timeout to version checking with exception handles
ifrit98 Jul 26, 2023
57dfd32
update CONTRIBUTING.md and DEVELOPMENT_WORKFLOW.md (#1475)
avatarjohn Aug 7, 2023
f3bde5e
add checks (#1484)
ifrit98 Aug 16, 2023
d4cb893
only run check_requirements job when an actual requirement changes
ifrit98 Aug 18, 2023
d3ef182
log bittensor pipaddress for version_checking
ifrit98 Aug 18, 2023
a29a455
add newline
ifrit98 Aug 18, 2023
5a9ede7
add newline to contrib
ifrit98 Aug 18, 2023
d612d2b
fix formatting to 1 newline
ifrit98 Aug 18, 2023
e96cc81
add perms to checK-compat script
ifrit98 Aug 18, 2023
68d0a09
fix check_reqs ci
ifrit98 Aug 18, 2023
e51a545
Update contrib/CODE_REVIEW_DOCS.md
ifrit98 Aug 18, 2023
3b56873
manually add 69df50cf885616c7169e304d24ed18a931b98dd3
ifrit98 Aug 23, 2023
5d2889d
Revert "manually add 69df50cf885616c7169e304d24ed18a931b98dd3"
ifrit98 Aug 23, 2023
89e715b
Merge branch 'revolution' into revolutoin_master_merge
ifrit98 Aug 23, 2023
685f3c5
remove compat check for dropped py3.8
ifrit98 Aug 23, 2023
e7aa986
run black
ifrit98 Aug 23, 2023
49b43ae
manual add of f267fb7f17ec9e9dcdbfc2bfac75952171a75236
ifrit98 Aug 23, 2023
c7de0b6
faster overview manual add: be31c4921fc4a70e369008f53041ca20a33a96a1
ifrit98 Aug 24, 2023
3234ba8
remove duplicate weights
ifrit98 Aug 24, 2023
3c5ab07
Merge branch 'revolution' into revolutoin_master_merge
ifrit98 Aug 24, 2023
e802a2c
run black
ifrit98 Aug 24, 2023
71e1a1c
Merge branch 'revolution' into revolution-master-merge
ifrit98 Aug 25, 2023
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
34 changes: 34 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,28 @@ jobs:
. env/bin/activate
python -m black --exclude '(env|venv|.eggs)' --check .

check_compatibility:
parameters:
python_version:
type: string
docker:
- image: cimg/python:3.10
steps:
- checkout
- run:
name: Check if requirements files have changed
command: ./scripts/check_requirements_changes.sh
- run:
name: Install dependencies and Check compatibility
command: |
if [ "$REQUIREMENTS_CHANGED" == "true" ]; then
sudo apt-get update
sudo apt-get install -y jq curl
./scripts/check_compatibility.sh << parameters.python_version >>
else
echo "Skipping compatibility checks..."
fi

build-and-test:
resource_class: medium
parallelism: 2
Expand Down Expand Up @@ -204,6 +226,18 @@ jobs:


workflows:
compatibility_checks:
jobs:
- check_compatibility:
python_version: "3.9"
name: check-compatibility-3.9
- check_compatibility:
python_version: "3.10"
name: check-compatibility-3.10
- check_compatibility:
python_version: "3.11"
name: check-compatibility-3.11

pr-requirements:
jobs:
- black:
Expand Down
73 changes: 56 additions & 17 deletions bittensor/commands/overview.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@
import argparse
import bittensor
from tqdm import tqdm
from concurrent.futures import ProcessPoolExecutor
from fuzzywuzzy import fuzz
from rich.align import Align
from rich.table import Table
from rich.prompt import Prompt
from typing import List, Optional, Dict
from typing import List, Optional, Dict, Tuple
from .utils import (
get_hotkey_wallets_for_wallet,
get_coldkey_wallets_for_path,
Expand Down Expand Up @@ -95,7 +96,7 @@ def run(cli):
return

# Pull neuron info for all keys.
neurons: Dict[str, List[bittensor.NeuronInfoLite, bittensor.wallet]] = {}
neurons: Dict[str, List[bittensor.NeuronInfoLite, str]] = {}
block = subtensor.block

netuids = subtensor.get_all_subnet_netuids()
Expand All @@ -110,21 +111,32 @@ def run(cli):
cli.config.subtensor.get("network", defaults.subtensor.network)
)
):
for netuid in tqdm(netuids_copy, desc="Checking each subnet"):
all_neurons: List[bittensor.NeuronInfoLite] = subtensor.neurons_lite(
netuid=netuid
hotkey_addr_to_wallet = {
hotkey.hotkey.ss58_address: hotkey for hotkey in all_hotkeys
}
all_hotkey_addresses = list(hotkey_addr_to_wallet.keys())

# Pull neuron info for all keys.
## Max len(netuids) or 5 threads.
with ProcessPoolExecutor(max_workers=max(len(netuids), 5)) as executor:
results = executor.map(
OverviewCommand._get_neurons_for_netuid,
[(cli.config, netuid, all_hotkey_addresses) for netuid in netuids],
)
# Map the hotkeys to uids
hotkey_to_neurons = {n.hotkey: n.uid for n in all_neurons}
for hot_wallet in all_hotkeys:
uid = hotkey_to_neurons.get(hot_wallet.hotkey.ss58_address)
if uid is not None:
nn = all_neurons[uid]
neurons[str(netuid)].append((nn, hot_wallet))

if len(neurons[str(netuid)]) == 0:
# Remove netuid from overview if no neurons are found.
netuids.remove(netuid)
executor.shutdown(wait=True) # wait for all complete

for result in results:
netuid, neurons_result, err_msg = result
if err_msg is not None:
console.print(err_msg)

if len(neurons_result) == 0:
# Remove netuid from overview if no neurons are found.
netuids.remove(netuid)
del neurons[str(netuid)]
else:
# Add neurons to overview.
neurons[str(netuid)] = neurons_result

# Setup outer table.
grid = Table.grid(pad_edge=False)
Expand Down Expand Up @@ -156,7 +168,8 @@ def run(cli):
total_dividends = 0.0
total_emission = 0

for nn, hotwallet in neurons[str(netuid)]:
for nn, hotwallet_addr in neurons[str(netuid)]:
hotwallet = hotkey_addr_to_wallet[hotwallet_addr]
nn: bittensor.NeuronInfoLite
uid = nn.uid
active = nn.active
Expand Down Expand Up @@ -373,6 +386,32 @@ def overview_sort_function(row):
# Print the entire table/grid
console.print(grid, width=cli.config.get("width", None))

@staticmethod
def _get_neurons_for_netuid(
args_tuple: Tuple["bittensor.Config", int, List[str]]
) -> Tuple[int, List[Tuple["bittensor.NeuronInfoLite", str]], Optional[str]]:
subtensor_config, netuid, hot_wallets = args_tuple

result: List[Tuple["bittensor.NeuronInfoLite", str]] = []

try:
subtensor = bittensor.subtensor(config=subtensor_config)

all_neurons: List["bittensor.NeuronInfoLite"] = subtensor.neurons_lite(
netuid=netuid
)
# Map the hotkeys to uids
hotkey_to_neurons = {n.hotkey: n.uid for n in all_neurons}
for hot_wallet_addr in hot_wallets:
uid = hotkey_to_neurons.get(hot_wallet_addr)
if uid is not None:
nn = all_neurons[uid]
result.append((nn, hot_wallet_addr))
except Exception as e:
return netuid, [], "Error: {}".format(e)

return netuid, result, None

@staticmethod
def add_args(parser: argparse.ArgumentParser):
overview_parser = parser.add_parser(
Expand Down
29 changes: 1 addition & 28 deletions bittensor/extrinsics/serving.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,6 @@ def serve_axon_extrinsic(
subtensor: "bittensor.subtensor",
netuid: int,
axon: "bittensor.Axon",
use_upnpc: bool = False,
wait_for_inclusion: bool = False,
wait_for_finalization: bool = True,
prompt: bool = False,
Expand All @@ -154,9 +153,6 @@ def serve_axon_extrinsic(
The netuid being served on.
axon (bittensor.Axon):
Axon to serve.
use_upnpc (:type:bool, `optional`):
If true, the axon attempts port forward through your router before
subscribing.
wait_for_inclusion (bool):
If set, waits for the extrinsic to enter a block before returning true,
or returns false if the extrinsic fails to enter the block within the timeout.
Expand All @@ -172,30 +168,7 @@ def serve_axon_extrinsic(
"""
axon.wallet.hotkey
axon.wallet.coldkeypub

# ---- Setup UPNPC ----
if use_upnpc:
if prompt:
if not Confirm.ask("Attempt port forwarding with upnpc?"):
return False
try:
external_port = net.upnpc_create_port_map(port=axon.port)
bittensor.__console__.print(
":white_heavy_check_mark: [green]Forwarded port: {}[/green]".format(
axon.port
)
)
bittensor.logging.success(
prefix="Forwarded port", sufix="<blue>{}</blue>".format(axon.port)
)
except net.UPNPCException as upnpc_exception:
raise RuntimeError(
"Failed to hole-punch with upnpc with exception {}".format(
upnpc_exception
)
) from upnpc_exception
else:
external_port = axon.external_port
external_port = axon.external_port

# ---- Get external ip ----
if axon.external_ip == None:
Expand Down
2 changes: 1 addition & 1 deletion bittensor/mock/subtensor_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -671,7 +671,7 @@ def query_constant(
if state_at_block is not None:
return SimpleNamespace(value=state_at_block)

return state_at_block # Can be None
return state_at_block["data"]["free"] # Can be None
else:
return None

Expand Down
29 changes: 1 addition & 28 deletions bittensor/subtensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -716,13 +716,12 @@ def serve_axon(
self,
netuid: int,
axon: "bittensor.Axon",
use_upnpc: bool = False,
wait_for_inclusion: bool = False,
wait_for_finalization: bool = True,
prompt: bool = False,
) -> bool:
return serve_axon_extrinsic(
self, netuid, axon, use_upnpc, wait_for_inclusion, wait_for_finalization
self, netuid, axon, wait_for_inclusion, wait_for_finalization
)

def _do_serve_axon(
Expand Down Expand Up @@ -2225,32 +2224,6 @@ def _do_nominate(
else:
raise NominationError(response.error_message)

def weights(
self, netuid: int, block: Optional[int] = None
) -> List[Tuple[int, List[Tuple[int, int]]]]:
w_map = []
w_map_encoded = self.query_map_subtensor(
name="Weights", block=block, params=[netuid]
)
if w_map_encoded.records:
for uid, w in w_map_encoded:
w_map.append((uid.serialize(), w.serialize()))

return w_map

def bonds(
self, netuid: int, block: Optional[int] = None
) -> List[Tuple[int, List[Tuple[int, int]]]]:
b_map = []
b_map_encoded = self.query_map_subtensor(
name="Bonds", block=block, params=[netuid]
)
if b_map_encoded.records:
for uid, b in b_map_encoded:
b_map.append((uid.serialize(), b.serialize()))

return b_map

################
#### Legacy ####
################
Expand Down
37 changes: 23 additions & 14 deletions bittensor/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,22 +60,31 @@ def unbiased_topk(values, k, dim=0, sorted=True, largest=True):
return topk, permutation[indices]


def version_checking():
response = requests.get(bittensor.__pipaddress__)
latest_version = response.json()["info"]["version"]
version_split = latest_version.split(".")
latest_version_as_int = (
(100 * int(version_split[0]))
+ (10 * int(version_split[1]))
+ (1 * int(version_split[2]))
)
def version_checking(timeout: int = 15):
try:
bittensor.logging.info(
f"Checking latest Bittensor version at: {bittensor.__pipaddress__}"
)
response = requests.get(bittensor.__pipaddress__, timeout=timeout)
latest_version = response.json()["info"]["version"]
version_split = latest_version.split(".")
latest_version_as_int = (
(100 * int(version_split[0]))
+ (10 * int(version_split[1]))
+ (1 * int(version_split[2]))
)

if latest_version_as_int > bittensor.__version_as_int__:
print(
"\u001b[33mBittensor Version: Current {}/Latest {}\nPlease update to the latest version at your earliest convenience\u001b[0m".format(
bittensor.__version__, latest_version
if latest_version_as_int > bittensor.__version_as_int__:
print(
"\u001b[33mBittensor Version: Current {}/Latest {}\nPlease update to the latest version at your earliest convenience\u001b[0m".format(
bittensor.__version__, latest_version
)
)
)

except requests.exceptions.Timeout:
bittensor.logging.error("Version check failed due to timeout")
except requests.exceptions.RequestException as e:
bittensor.logging.error(f"Version check failed due to request failure: {e}")


def strtobool_with_default(
Expand Down
68 changes: 0 additions & 68 deletions bittensor/utils/networking.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import json
import netaddr
import requests
import miniupnpc

from loguru import logger

Expand Down Expand Up @@ -156,73 +155,6 @@ def get_external_ip() -> str:
raise ExternalIPNotFound


class UPNPCException(Exception):
"""Raised when trying to perform a port mapping on your router."""


def upnpc_create_port_map(port: int):
r"""Creates a upnpc port map on your router from passed external_port to local port.

Args:
port (int, `required`):
The local machine port to map from your external port.

Return:
external_port (int, `required`):
The external port mapped to the local port on your machine.

Raises:
UPNPCException (Exception):
Raised if UPNPC port mapping fails, for instance, if upnpc is not enabled on your router.
"""
try:
upnp = miniupnpc.UPnP()
upnp.discoverdelay = 200
logger.debug("UPNPC: Using UPnP to open a port on your router ...")
logger.debug("UPNPC: Discovering... delay={}ms", upnp.discoverdelay)
ndevices = upnp.discover()
upnp.selectigd()
logger.debug("UPNPC: " + str(ndevices) + " device(s) detected")

ip = upnp.lanaddr
external_ip = upnp.externalipaddress()

logger.debug("UPNPC: your local ip address: " + str(ip))
logger.debug("UPNPC: your external ip address: " + str(external_ip))
logger.debug(
"UPNPC: status = "
+ str(upnp.statusinfo())
+ " connection type = "
+ str(upnp.connectiontype())
)

# find a free port for the redirection
external_port = port
rc = upnp.getspecificportmapping(external_port, "TCP")
while rc != None and external_port < 65536:
external_port += 1
rc = upnp.getspecificportmapping(external_port, "TCP")
if rc != None:
raise UPNPCException("UPNPC: No available external ports for port mapping.")

logger.info(
"UPNPC: trying to redirect remote: {}:{} => local: {}:{} over TCP",
external_ip,
external_port,
ip,
port,
)
upnp.addportmapping(
external_port, "TCP", ip, port, "Bittensor: %u" % external_port, ""
)
logger.info("UPNPC: Create Success")

return external_port

except Exception as e:
raise UPNPCException(e) from e


def get_formatted_ws_endpoint_url(endpoint_url: str) -> str:
"""
Returns a formatted websocket endpoint url.
Expand Down
Loading