Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
654 changes: 219 additions & 435 deletions .test_durations

Large diffs are not rendered by default.

28 changes: 28 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,33 @@
# Changelog

## 4.0.1 / 2023-04-21

* Fix btcli my_delegates bug by @camfairchild in ef32a4da0d0827ab5977af1454d66ffe97cbc572
* Fix endpoint protocol check bug by @camfairchild and @Eugene-hu in https://github.com/opentensor/bittensor/pull/1296
* Fix changelog script and perms by @camfairchild in f5e7f1e9e9717d229fdec6875fdb9a3051c4bd6b and 1aed09a162ef0fe4d9def2faf261b15dc4c1fa8d

**Full Changelog**: https://github.com/opentensor/bittensor/compare/v4.0.0...v4.0.1


## 4.0.0 / 2023-04-20

## What's Changed
* add mnrv-ai to delegates.json by @SFuller4 in https://github.com/opentensor/bittensor/pull/1226
* Update delegates list by @adriansmares in https://github.com/opentensor/bittensor/pull/1225
* Update delegates.json by @whiterhinoTAO in https://github.com/opentensor/bittensor/pull/1230
* Hotfix - Cli unstake fix by @Eugene-hu in https://github.com/opentensor/bittensor/pull/1233
* Fix permissions for release github script by @eduardogr in https://github.com/opentensor/bittensor/pull/1224
* Staging into Release branch by @camfairchild in https://github.com/opentensor/bittensor/pull/1275
* Remove codecov by @camfairchild in https://github.com/opentensor/bittensor/pull/1282
* Use alt new preseal by @camfairchild in https://github.com/opentensor/bittensor/pull/1269

## New Contributors
* @SFuller4 made their first contribution in https://github.com/opentensor/bittensor/pull/1226
* @whiterhinoTAO made their first contribution in https://github.com/opentensor/bittensor/pull/1230

**Full Changelog**: https://github.com/opentensor/bittensor/compare/v3.7.0...v4.0.0


## 3.6.3 / 2023-01-21

## What's Changed
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.7.0
4.0.1
2 changes: 1 addition & 1 deletion bittensor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
nest_asyncio.apply()

# Bittensor code and protocol version.
__version__ = '3.7.0'
__version__ = '4.0.1'
version_split = __version__.split(".")
__version_as_int__ = (100 * int(version_split[0])) + (10 * int(version_split[1])) + (1 * int(version_split[2]))
__new_signature_version__ = 360
Expand Down
6 changes: 3 additions & 3 deletions bittensor/_cli/commands/delegates.py
Original file line number Diff line number Diff line change
Expand Up @@ -471,9 +471,9 @@ def run( cli ):
bittensor.Balance.from_rao(0) # default to 0 if no owner stake.
)
if delegate[0].hotkey_ss58 in registered_delegate_info:
delegate_name = registered_delegate_info[delegate[0].hotkey_ss58]['name']
delegate_url = registered_delegate_info[delegate[0].hotkey_ss58]['url']
delegate_description = registered_delegate_info[delegate[0].hotkey_ss58]['description']
delegate_name = registered_delegate_info[delegate[0].hotkey_ss58].name
delegate_url = registered_delegate_info[delegate[0].hotkey_ss58].url
delegate_description = registered_delegate_info[delegate[0].hotkey_ss58].description
else:
delegate_name = ''
delegate_url = ''
Expand Down
4 changes: 2 additions & 2 deletions bittensor/_cli/commands/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@ def run (cli):
rows.append((
str(subnet.netuid),
str(subnet.subnetwork_n),
str(bittensor.utils.registration.millify(subnet.max_n)),
str(bittensor.utils.registration.millify(subnet.difficulty)),
str(bittensor.utils.formatting.millify(subnet.max_n)),
str(bittensor.utils.formatting.millify(subnet.difficulty)),
str(subnet.tempo),
str([ f'{cr[0]}: {cr[1] * 100:.1f}%' for cr in subnet.connection_requirements.items()] if len(subnet.connection_requirements) > 0 else None ),
f'{subnet.emission_value / bittensor.utils.RAOPERTAO * 100:0.2f}%',
Expand Down
2 changes: 1 addition & 1 deletion bittensor/_cli/commands/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def run ( cli ):
check_for_cuda_reg_config(wallet.config)
print(wallet.config)

wallet.reregister( netuid = cli.config.netuid )
wallet.reregister( subtensor=subtensor, netuid = cli.config.netuid )

# Run miner.
if cli.config.model == 'core_server':
Expand Down
39 changes: 23 additions & 16 deletions bittensor/_endpoint/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
MAXPORT = 65535
MAXUID = 4294967295
ACCEPTABLE_IPTYPES = [4,6,0]
ACCEPTABLE_PROTOCOLS = [0] # TODO
ACCEPTABLE_PROTOCOLS = [0,4] # TODO
ENDPOINT_BUFFER_SIZE = 250

class endpoint:
Expand Down Expand Up @@ -107,7 +107,7 @@ def from_neuron( neuron: Union['bittensor.NeuronInfo', 'bittensor.NeuronInfoLite
def from_dict(endpoint_dict: dict) -> 'bittensor.Endpoint':
""" Return an endpoint with spec from dictionary
"""
endpoint.assert_format(
if not endpoint.assert_format(
version = endpoint_dict['version'],
uid = endpoint_dict['uid'],
hotkey = endpoint_dict['hotkey'],
Expand All @@ -116,7 +116,8 @@ def from_dict(endpoint_dict: dict) -> 'bittensor.Endpoint':
ip_type = endpoint_dict['ip_type'],
protocol = endpoint_dict['protocol'],
coldkey = endpoint_dict['coldkey']
)
):
raise ValueError('Invalid endpoint dict')
return endpoint_impl.Endpoint(
version = endpoint_dict['version'],
uid = endpoint_dict['uid'],
Expand Down Expand Up @@ -152,7 +153,10 @@ def from_tensor( tensor: torch.LongTensor) -> 'bittensor.Endpoint':
endpoint_bytes = bytearray( endpoint_list )
endpoint_string = endpoint_bytes.decode('utf-8')
endpoint_dict = json.loads( endpoint_string )
return endpoint.from_dict(endpoint_dict)
try:
return endpoint.from_dict(endpoint_dict)
except ValueError:
return endpoint.dummy()

@staticmethod
def dummy():
Expand All @@ -170,18 +174,21 @@ def assert_format(
coldkey:str
) -> bool:
""" Asserts that the endpoint has a valid format
Raises:
Multiple assertion errors.
"""
assert version >= 0, 'endpoint version must be positive. - got {}'.format(version)
assert version <= MAX_VERSION, 'endpoint version must be less than 999. - got {}'.format(version)
assert uid >= 0 and uid <= MAXUID, 'endpoint uid must positive and be less than u32 max: 4294967295. - got {}'.format(uid)
assert len(ip) < MAX_IP_LENGTH, 'endpoint ip string must have length less than 8*4. - got {}'.format(ip)
assert ip_type in ACCEPTABLE_IPTYPES, 'endpoint ip_type must be either 4 or 6.- got {}'.format(ip_type)
assert port >= 0 and port < MAXPORT , 'port must be positive and less than 65535 - got {}'.format(port)
assert len(coldkey) == SS58_LENGTH, 'coldkey string must be length 48 - got {}'.format(coldkey)
assert len(hotkey) == SS58_LENGTH, 'hotkey string must be length 48 - got {}'.format(hotkey)
# TODO
assert protocol in ACCEPTABLE_PROTOCOLS, 'protocol must be 0 (for now) - got {}'.format(protocol)
try:
assert version >= 0, 'endpoint version must be positive. - got {}'.format(version)
assert version <= MAX_VERSION, 'endpoint version must be less than 999. - got {}'.format(version)
assert uid >= 0 and uid <= MAXUID, 'endpoint uid must positive and be less than u32 max: 4294967295. - got {}'.format(uid)
assert len(ip) < MAX_IP_LENGTH, 'endpoint ip string must have length less than 8*4. - got {}'.format(ip)
assert ip_type in ACCEPTABLE_IPTYPES, 'endpoint ip_type must be either 4 or 6.- got {}'.format(ip_type)
assert port >= 0 and port < MAXPORT , 'port must be positive and less than 65535 - got {}'.format(port)
assert len(coldkey) == SS58_LENGTH, 'coldkey string must be length 48 - got {}'.format(coldkey)
assert len(hotkey) == SS58_LENGTH, 'hotkey string must be length 48 - got {}'.format(hotkey)
# TODO
assert protocol in ACCEPTABLE_PROTOCOLS, 'protocol must be 0 (for now) - got {}'.format(protocol)

return True
except AssertionError:
return False


27 changes: 15 additions & 12 deletions bittensor/_endpoint/endpoint_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,23 @@ def __init__( self, version: int, uid:int, hotkey:str, ip:str, ip_type:int, port
self.modality = modality


def assert_format( self ):
def assert_format( self ) -> bool:
""" Asserts that the endpoint has a valid format
Raises:
Multiple assertion errors.
"""
assert self.version > 0, 'endpoint version must be positive. - got {}'.format(self.version)
assert self.version < MAX_VERSION, 'endpoint version must be less than 999. - got {}'.format(self.version)
assert self.uid >= 0 and self.uid < MAXUID, 'endpoint uid must positive and be less than u32 max: 4294967295. - got {}'.format(self.uid)
assert len(self.ip) < MAX_IP_LENGTH, 'endpoint ip string must have length less than 8*4. - got {}'.format(self.ip)
assert self.ip_type in ACCEPTABLE_IPTYPES, 'endpoint ip_type must be either 4 or 6.- got {}'.format(self.ip_type)
assert self.port > 0 and self.port < MAXPORT , 'port must be positive and less than 65535 - got {}'.format(self.port)
assert len(self.coldkey) == SS58_LENGTH, 'coldkey string must be length 48 - got {}'.format(self.coldkey)
assert len(self.hotkey) == SS58_LENGTH, 'hotkey string must be length 48 - got {}'.format(self.hotkey)
assert self.protocol in ACCEPTABLE_PROTOCOLS, 'protocol must be 0 (for now) - got {}'.format(self.protocol)
try:
assert self.version > 0, 'endpoint version must be positive. - got {}'.format(self.version)
assert self.version < MAX_VERSION, 'endpoint version must be less than 999. - got {}'.format(self.version)
assert self.uid >= 0 and self.uid < MAXUID, 'endpoint uid must positive and be less than u32 max: 4294967295. - got {}'.format(self.uid)
assert len(self.ip) < MAX_IP_LENGTH, 'endpoint ip string must have length less than 8*4. - got {}'.format(self.ip)
assert self.ip_type in ACCEPTABLE_IPTYPES, 'endpoint ip_type must be either 4 or 6.- got {}'.format(self.ip_type)
assert self.port > 0 and self.port < MAXPORT , 'port must be positive and less than 65535 - got {}'.format(self.port)
assert len(self.coldkey) == SS58_LENGTH, 'coldkey string must be length 48 - got {}'.format(self.coldkey)
assert len(self.hotkey) == SS58_LENGTH, 'hotkey string must be length 48 - got {}'.format(self.hotkey)
assert self.protocol in ACCEPTABLE_PROTOCOLS, 'protocol must be 0 (for now) - got {}'.format(self.protocol)

return True
except AssertionError as e:
return False

@property
def is_serving(self) -> bool:
Expand Down
13 changes: 7 additions & 6 deletions bittensor/_subtensor/extrinsics/registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from rich.prompt import Confirm
from typing import List, Dict, Union, Optional
import bittensor.utils.networking as net
from bittensor.utils.registration import POWSolution, create_pow
from ..errors import *

def register_extrinsic (
Expand Down Expand Up @@ -105,9 +106,9 @@ def register_extrinsic (
if prompt:
bittensor.__console__.error('CUDA is not available.')
return False
pow_result = bittensor.utils.create_pow( subtensor, wallet, netuid, output_in_place, cuda, dev_id, TPB, num_processes=num_processes, update_interval=update_interval, log_verbose=log_verbose )
pow_result: Optional[POWSolution] = create_pow( subtensor, wallet, netuid, output_in_place, cuda, dev_id, TPB, num_processes=num_processes, update_interval=update_interval, log_verbose=log_verbose )
else:
pow_result = bittensor.utils.create_pow( subtensor, wallet, netuid, output_in_place, num_processes=num_processes, update_interval=update_interval, log_verbose=log_verbose )
pow_result: Optional[POWSolution] = create_pow( subtensor, wallet, netuid, output_in_place, num_processes=num_processes, update_interval=update_interval, log_verbose=log_verbose )

# pow failed
if not pow_result:
Expand All @@ -120,17 +121,17 @@ def register_extrinsic (
else:
with bittensor.__console__.status(":satellite: Submitting POW..."):
# check if pow result is still valid
while bittensor.utils.POWNotStale(subtensor, pow_result):
while not pow_result.is_stale(subtensor=subtensor):
with subtensor.substrate as substrate:
# create extrinsic call
call = substrate.compose_call(
call_module='SubtensorModule',
call_function='register',
call_params={
'netuid': netuid,
'block_number': pow_result['block_number'],
'nonce': pow_result['nonce'],
'work': bittensor.utils.hex_bytes_to_u8_list( pow_result['work'] ),
'block_number': pow_result.block_number,
'nonce': pow_result.nonce,
'work': [int(byte_) for byte_ in pow_result.seal],
'hotkey': wallet.hotkey.ss58_address,
'coldkey': wallet.coldkeypub.ss58_address,
}
Expand Down
79 changes: 68 additions & 11 deletions bittensor/_subtensor/subtensor_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,10 @@ def mock(cls):

if not cls.global_mock_process_is_running():
# Remove any old chain db
if os.path.exists(bittensor.__mock_chain_db__):
os.system(f'rm -rf {bittensor.__mock_chain_db__}')
_owned_mock_subtensor_process = cls.create_global_mock_process()
if os.path.exists(f'{bittensor.__mock_chain_db__}_{os.getpid()}'):
# Name mock chain db using pid to avoid conflicts while multiple processes are running.
os.system(f'rm -rf {bittensor.__mock_chain_db__}_{os.getpid()}')
_owned_mock_subtensor_process = cls.create_global_mock_process(os.getpid())
else:
_owned_mock_subtensor_process = None
print ('Mock subtensor already running.')
Expand All @@ -101,13 +102,15 @@ def mock(cls):
return subtensor

@classmethod
def global_mock_process_is_running(cle) -> bool:
r""" If subtensor is running a mock process this kills the mock.
def global_mock_process_is_running(cls) -> bool:
r""" Check if the global mocked subtensor process is running under a process with the same name as this one.
"""
this_process = psutil.Process(os.getpid())
for p in psutil.process_iter():
if p.name() == GLOBAL_SUBTENSOR_MOCK_PROCESS_NAME and p.parent().pid == os.getpid() and p.status() != psutil.STATUS_ZOMBIE and p.status() != psutil.STATUS_DEAD:
print(f"Found process with name {p.name()}, parent {p.parent().pid} status {p.status()} and pid {p.pid}")
return True
if p.name() == GLOBAL_SUBTENSOR_MOCK_PROCESS_NAME and p.status() != psutil.STATUS_ZOMBIE and p.status() != psutil.STATUS_DEAD:
if p.parent().name == this_process.name:
print(f"Found process with name {p.name()}, parent {p.parent().pid} status {p.status()} and pid {p.pid}")
return True
return False

@classmethod
Expand All @@ -121,7 +124,7 @@ def kill_global_mock_process(self):
time.sleep(2) # Buffer to ensure the processes actually die

@classmethod
def create_global_mock_process(self):
def create_global_mock_process(self, pid: int) -> 'subprocess.Popen[bytes]':
r""" Creates a global mocked subtensor process running in the backgroun with name GLOBAL_SUBTENSOR_MOCK_PROCESS_NAME.
"""
try:
Expand All @@ -133,7 +136,7 @@ def create_global_mock_process(self):
ws_port = int(bittensor.__mock_entrypoint__.split(':')[1])
print(f'MockSub ws_port: {ws_port}')

command_args = [ path ] + f'--chain {path_to_spec} --base-path {bittensor.__mock_chain_db__} --execution native --ws-max-connections 1000 --no-mdns --rpc-cors all'.split(' ') + \
command_args = [ path ] + f'--chain {path_to_spec} --base-path {bittensor.__mock_chain_db__}_{pid} --execution native --ws-max-connections 1000 --no-mdns --rpc-cors all'.split(' ') + \
f'--port {int(bittensor.get_random_unused_port())} --rpc-port {int(bittensor.get_random_unused_port())} --ws-port {ws_port}'.split(' ') + \
'--validator --alice'.split(' ')

Expand All @@ -146,7 +149,7 @@ def create_global_mock_process(self):
# Wait for the process to start. Check for errors.
try:
# Timeout is okay.
error_code = _mock_subtensor_process.wait(timeout=3)
error_code = _mock_subtensor_process.wait(timeout=12)
except subprocess.TimeoutExpired:
error_code = None

Expand Down Expand Up @@ -321,6 +324,60 @@ def sudo_set_difficulty(self, netuid: int, difficulty: int, wait_for_inclusion:
return True, None
else:
return False, response.error_message

def sudo_set_max_difficulty(self, netuid: int, max_difficulty: int, wait_for_inclusion: bool = True, wait_for_finalization: bool = True ) -> Tuple[bool, Optional[str]]:
r""" Sets the max difficulty of the mock chain using the sudo key.
"""
with self.substrate as substrate:
call = substrate.compose_call(
call_module='SubtensorModule',
call_function='sudo_set_max_difficulty',
call_params = {
'netuid': netuid,
'max_difficulty': max_difficulty
}
)

wrapped_call = self.wrap_sudo(call)

extrinsic = substrate.create_signed_extrinsic( call = wrapped_call, keypair = self.sudo_keypair )
response = substrate.submit_extrinsic( extrinsic, wait_for_inclusion = wait_for_inclusion, wait_for_finalization = wait_for_finalization )

if not wait_for_finalization:
return True, None

response.process_events()
if response.is_success:
return True, None
else:
return False, response.error_message

def sudo_set_min_difficulty(self, netuid: int, min_difficulty: int, wait_for_inclusion: bool = True, wait_for_finalization: bool = True ) -> Tuple[bool, Optional[str]]:
r""" Sets the min difficulty of the mock chain using the sudo key.
"""
with self.substrate as substrate:
call = substrate.compose_call(
call_module='SubtensorModule',
call_function='sudo_set_min_difficulty',
call_params = {
'netuid': netuid,
'min_difficulty': min_difficulty
}
)

wrapped_call = self.wrap_sudo(call)

extrinsic = substrate.create_signed_extrinsic( call = wrapped_call, keypair = self.sudo_keypair )
response = substrate.submit_extrinsic( extrinsic, wait_for_inclusion = wait_for_inclusion, wait_for_finalization = wait_for_finalization )

if not wait_for_finalization:
return True, None

response.process_events()
if response.is_success:
return True, None
else:
return False, response.error_message

def sudo_add_network(self, netuid: int, tempo: int = 0, modality: int = 0, wait_for_inclusion: bool = True, wait_for_finalization: bool = True ) -> Tuple[bool, Optional[str]]:
r""" Adds a network to the mock chain using the sudo key.
Expand Down
4 changes: 2 additions & 2 deletions bittensor/utils/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import numbers
from typing import Callable, Union
from typing import Callable, Union, List, Optional, Dict

import bittensor
import pandas
Expand All @@ -8,7 +8,7 @@
import scalecodec
from substrateinterface import Keypair
from substrateinterface.utils import ss58
from .registration import *
from .registration import create_pow

RAOPERTAO = 1e9
U16_MAX = 65535
Expand Down
Loading