Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
2fef783
use new preseal for reg
camfairchild Apr 17, 2023
1558a51
bump cubit req
camfairchild Apr 17, 2023
2bd9ef7
fix arg order issue
camfairchild Apr 17, 2023
50ef607
cubit req back
camfairchild Apr 17, 2023
f6e22d2
use alt impl
camfairchild Apr 17, 2023
ea671bf
fix typehint
camfairchild Apr 17, 2023
dc5d50b
use 512
camfairchild Apr 17, 2023
f9b1f62
modify tests for new format
camfairchild Apr 17, 2023
db3c819
refactor functions to use helpers and remove useless
camfairchild Apr 17, 2023
48d9b49
refactor functions
camfairchild Apr 17, 2023
9a1e667
add test for CPU solver
camfairchild Apr 17, 2023
3d1c4fa
modify tests for privitized module and methods
camfairchild Apr 17, 2023
d961d26
private register cuda
camfairchild Apr 17, 2023
37c3172
move formatting funcs
camfairchild Apr 17, 2023
bf9d6a3
use powsolution
camfairchild Apr 17, 2023
a152767
privitize most methods
camfairchild Apr 17, 2023
f55fd5c
fix test
camfairchild Apr 17, 2023
8d1faa9
fix perms
camfairchild Apr 17, 2023
775d34d
remove test script
camfairchild Apr 17, 2023
b5f091b
remove debug
camfairchild Apr 17, 2023
555719b
fix call
camfairchild Apr 17, 2023
985b513
fix seal
camfairchild Apr 18, 2023
e72fec4
fix combined hash
camfairchild Apr 18, 2023
ee8c144
move to method
camfairchild Apr 18, 2023
0f8df00
fix test using real example
camfairchild Apr 18, 2023
1e811f3
update mock bins
camfairchild Apr 18, 2023
4a3afad
Merge branch 'release/4.0.0' into use-alt-new-preseal
camfairchild Apr 19, 2023
5ea9358
use new builder
camfairchild Apr 19, 2023
19d3f70
fix block update tests
camfairchild Apr 19, 2023
bd9dd2e
fix some patching in tests
camfairchild Apr 19, 2023
b46263c
mock live display for some tests
camfairchild Apr 19, 2023
0632190
fix chain mock
camfairchild Apr 19, 2023
ffce43b
update linux bin
camfairchild Apr 19, 2023
e177814
add mock network flag
camfairchild Apr 19, 2023
bbe53cb
set max diff at 0 for mock netuid 1
camfairchild Apr 19, 2023
8bc5356
set min diff too
camfairchild Apr 19, 2023
c9fe1c9
add try catch for setup
camfairchild Apr 19, 2023
fb64efd
add some logging during tests
camfairchild Apr 19, 2023
796e6b2
don't submit on cli register
camfairchild Apr 19, 2023
f805049
update test durations
camfairchild Apr 19, 2023
5f2cfe7
fix test to use mock keypair
camfairchild Apr 19, 2023
98d6215
return mock wallet
camfairchild Apr 19, 2023
434462b
should use subtensor instance during rereg
camfairchild Apr 19, 2023
46570b2
update node subtensor bins
camfairchild Apr 20, 2023
2737141
use fixtures and multiple subtensor instances
camfairchild Apr 20, 2023
00fb101
Merge branch 'release/4.0.0' into use-alt-new-preseal
camfairchild Apr 20, 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
654 changes: 219 additions & 435 deletions .test_durations

Large diffs are not rendered by default.

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
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
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import io


def solve_cuda(nonce_start: np.int64, update_interval: np.int64, TPB: int, block_bytes: bytes, bn: int, difficulty: int, limit: int, dev_id: int = 0) -> Tuple[np.int64, bytes]:
def solve_cuda(nonce_start: np.int64, update_interval: np.int64, TPB: int, block_and_hotkey_hash_bytes: bytes, difficulty: int, limit: int, dev_id: int = 0) -> Tuple[np.int64, bytes]:
"""
Solves the PoW problem using CUDA.
Args:
Expand All @@ -20,8 +20,8 @@ def solve_cuda(nonce_start: np.int64, update_interval: np.int64, TPB: int, block
Number of nonces to solve before updating block information.
TPB: int
Threads per block.
block_bytes: bytes
Bytes of the block hash. 64 bytes.
block_and_hotkey_hash_bytes: bytes
Keccak(Bytes of the block hash + bytes of the hotkey) 64 bytes.
difficulty: int256
Difficulty of the PoW problem.
limit: int256
Expand All @@ -44,33 +44,35 @@ def solve_cuda(nonce_start: np.int64, update_interval: np.int64, TPB: int, block

upper_bytes = upper.to_bytes(32, byteorder='little', signed=False)

def seal_meets_difficulty( seal:bytes, difficulty:int ):
seal_number = int.from_bytes(seal, "big")
product = seal_number * difficulty
limit = int(math.pow(2,256))- 1

return product < limit

def hex_bytes_to_u8_list( hex_bytes: bytes ):
def _hex_bytes_to_u8_list( hex_bytes: bytes ):
hex_chunks = [int(hex_bytes[i:i+2], 16) for i in range(0, len(hex_bytes), 2)]
return hex_chunks

def create_seal_hash( block_bytes:bytes, nonce:int ) -> bytes:
def _create_seal_hash( block_and_hotkey_hash_hex: bytes, nonce:int ) -> bytes:
nonce_bytes = binascii.hexlify(nonce.to_bytes(8, 'little'))
pre_seal = nonce_bytes + block_bytes
seal_sh256 = hashlib.sha256( bytearray(hex_bytes_to_u8_list(pre_seal)) ).digest()
pre_seal = nonce_bytes + block_and_hotkey_hash_hex
seal_sh256 = hashlib.sha256( bytearray(_hex_bytes_to_u8_list(pre_seal)) ).digest()
kec = keccak.new(digest_bits=256)
seal = kec.update( seal_sh256 ).digest()
return seal

def _seal_meets_difficulty( seal:bytes, difficulty:int ):
seal_number = int.from_bytes(seal, "big")
product = seal_number * difficulty
limit = int(math.pow(2,256)) - 1

return product < limit

# Call cython function
# int blockSize, uint64 nonce_start, uint64 update_interval, const unsigned char[:] limit,
# const unsigned char[:] block_bytes, int dev_id
solution = cubit.solve_cuda(TPB, nonce_start, update_interval, upper_bytes, block_bytes, dev_id) # 0 is first GPU
block_and_hotkey_hash_hex = binascii.hexlify(block_and_hotkey_hash_bytes)[:64]

solution = cubit.solve_cuda(TPB, nonce_start, update_interval, upper_bytes, block_and_hotkey_hash_hex, dev_id) # 0 is first GPU
seal = None
if solution != -1:
seal = create_seal_hash(block_bytes, solution)
if seal_meets_difficulty(seal, difficulty):
seal = _create_seal_hash(block_and_hotkey_hash_hex, solution)
if _seal_meets_difficulty(seal, difficulty):
return solution, seal
else:
return -1, b'\x00' * 32
Expand Down
16 changes: 16 additions & 0 deletions bittensor/utils/formatting.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import math

def get_human_readable(num, suffix="H"):
for unit in ["", "K", "M", "G", "T", "P", "E", "Z"]:
if abs(num) < 1000.0:
return f"{num:3.1f}{unit}{suffix}"
num /= 1000.0
return f"{num:.1f}Y{suffix}"

def millify(n: int):
millnames = ['',' K',' M',' B',' T']
n = float(n)
millidx = max(0,min(len(millnames)-1,
int(math.floor(0 if n == 0 else math.log10(abs(n))/3))))

return '{:.2f}{}'.format(n / 10**(3 * millidx), millnames[millidx])
Loading