bittensor.utils.registration.pow

Contents

bittensor.utils.registration.pow#

This module provides utilities for solving Proof-of-Work (PoW) challenges in Bittensor network.

Attributes#

Classes#

CUDASolver

A process that solves the registration PoW problem.

LazyLoadedTorch

A lazy-loading proxy for the torch module.

POWSolution

A solution to the registration PoW problem.

RegistrationStatistics

Statistics for a registration.

RegistrationStatisticsLogger

Logs statistics for a registration.

Solver

A process that solves the registration PoW problem.

UsingSpawnStartMethod

_SolverBase

A process that solves the registration PoW problem.

Functions#

_check_for_newest_block_and_update(subtensor, netuid, ...)

Checks for a new block and updates the current block information if a new block is found.

_create_seal_hash(block_and_hotkey_hash_bytes, nonce)

Create a cryptographic seal hash from the given block and hotkey hash bytes and nonce.

_get_block_with_retry(subtensor, netuid)

Gets the current block number, difficulty, and block hash from the substrate node.

_get_real_torch()

_hash_block_with_hotkey(block_bytes, hotkey_bytes)

Hashes the block with the hotkey using Keccak-256 to get 32 bytes

_hex_bytes_to_u8_list(hex_bytes)

_registration_diff_pack(diff, packed_diff)

Packs the difficulty into two 32-bit integers. Little endian.

_registration_diff_unpack(packed_diff)

Unpacks the packed two 32-bit integers into one 64-bit integer. Little endian.

_seal_meets_difficulty(seal, difficulty, limit)

Determines if a seal meets the specified difficulty.

_solve_for_difficulty_fast(subtensor, wallet, netuid)

Solves the POW for registration using multiprocessing.

_solve_for_difficulty_fast_cuda(subtensor, wallet, netuid)

Solves the registration fast using CUDA.

_solve_for_nonce_block(nonce_start, nonce_end, ...)

Tries to solve the POW for a block of nonces (nonce_start, nonce_end)

_solve_for_nonce_block_cuda(nonce_start, ...)

Tries to solve the POW on a CUDA device for a block of nonces (nonce_start, nonce_start + update_interval * tpb

create_pow(subtensor, wallet, netuid[, ...])

Creates a proof of work for the given subtensor and wallet.

get_cpu_count()

Returns the number of CPUs in the system.

legacy_torch_api_compat(func)

Convert function operating on numpy Input&Output to legacy torch Input&Output API if use_torch() is True.

log_no_torch_error()

terminate_workers_and_wait_for_exit(workers)

update_curr_block(curr_diff, curr_block, ...)

Update the current block data with the provided block information and difficulty.

use_torch()

Force the use of torch over numpy for certain operations.

Module Contents#

class bittensor.utils.registration.pow.CUDASolver(proc_num, num_proc, update_interval, finished_queue, solution_queue, stopEvent, curr_block, curr_block_num, curr_diff, check_block, limit, dev_id, tpb)#

Bases: _SolverBase

A process that solves the registration PoW problem.

Parameters:
  • proc_num (int) – The number of the process being created.

  • num_proc (int) – The total number of processes running.

  • update_interval (int) – The number of nonces to try to solve before checking for a new block.

  • finished_queue (multiprocessing.Queue) – The queue to put the process number when a process finishes each update_interval. Used for calculating the average time per update_interval across all processes.

  • solution_queue (multiprocessing.Queue) – The queue to put the solution the process has found during the pow solve.

  • stopEvent (multiprocessing.Event) – The event to set by the main process when all the solver processes should stop. The solver process will check for the event after each update_interval. The solver process will stop when the event is set. Used to stop the solver processes when a solution is found.

  • curr_block (multiprocessing.Array) – The array containing this process’s current block hash. The main process will set the array to the new block hash when a new block is finalized in the network. The solver process will get the new block hash from this array when newBlockEvent is set.

  • curr_block_num (multiprocessing.Value) – The value containing this process’s current block number. The main process will set the value to the new block number when a new block is finalized in the network. The solver process will get the new block number from this value when newBlockEvent is set.

  • curr_diff (multiprocessing.Array) – The array containing this process’s current difficulty. The main process will set the array to the new difficulty when a new block is finalized in the network. The solver process will get the new difficulty from this array when newBlockEvent is set.

  • check_block (multiprocessing.Lock) – The lock to prevent this process from getting the new block data while the main process is updating the data.

  • limit (int) – The limit of the pow solve for a valid solution.

  • dev_id (int)

  • tpb (int)

dev_id: int#
run()#

Method to be run in sub-process; can be overridden in sub-class

tpb: int#
class bittensor.utils.registration.pow.LazyLoadedTorch#

A lazy-loading proxy for the torch module.

__bool__()#
__getattr__(name)#
class bittensor.utils.registration.pow.POWSolution#

A solution to the registration PoW problem.

block_number: int#
difficulty: int#
is_stale(subtensor)#

Synchronous implementation. Returns True if the POW is stale.

This means the block the POW is solved for is within 3 blocks of the current block.

Parameters:

subtensor (bittensor.core.subtensor.Subtensor)

Return type:

bool

async is_stale_async(subtensor)#

Asynchronous implementation. Returns True if the POW is stale.

This means the block the POW is solved for is within 3 blocks of the current block.

Parameters:

subtensor (bittensor.core.async_subtensor.AsyncSubtensor)

Return type:

bool

nonce: int#
seal: bytes#
class bittensor.utils.registration.pow.RegistrationStatistics#

Statistics for a registration.

block_hash: str#
block_number: int#
difficulty: int#
hash_rate: float#
hash_rate_perpetual: float#
rounds_total: int#
time_average: float#
time_spent: float#
time_spent_total: float#
class bittensor.utils.registration.pow.RegistrationStatisticsLogger(console=None, output_in_place=True)#

Logs statistics for a registration.

Parameters:
  • console (Optional[rich.console.Console])

  • output_in_place (bool)

console#
classmethod get_status_message(stats, verbose=False)#

Generates the status message based on registration statistics.

Parameters:
Return type:

str

start()#
Return type:

None

status: rich.status.Status | None#
stop()#
Return type:

None

update(stats, verbose=False)#
Parameters:
Return type:

None

class bittensor.utils.registration.pow.Solver(proc_num, num_proc, update_interval, finished_queue, solution_queue, stopEvent, curr_block, curr_block_num, curr_diff, check_block, limit)#

Bases: _SolverBase

A process that solves the registration PoW problem.

Parameters:
  • proc_num (int) – The number of the process being created.

  • num_proc (int) – The total number of processes running.

  • update_interval (int) – The number of nonces to try to solve before checking for a new block.

  • finished_queue (multiprocessing.Queue) – The queue to put the process number when a process finishes each update_interval. Used for calculating the average time per update_interval across all processes.

  • solution_queue (multiprocessing.Queue) – The queue to put the solution the process has found during the pow solve.

  • stopEvent (multiprocessing.Event) – The event to set by the main process when all the solver processes should stop. The solver process will check for the event after each update_interval. The solver process will stop when the event is set. Used to stop the solver processes when a solution is found.

  • curr_block (multiprocessing.Array) – The array containing this process’s current block hash. The main process will set the array to the new block hash when a new block is finalized in the network. The solver process will get the new block hash from this array when newBlockEvent is set.

  • curr_block_num (multiprocessing.Value) – The value containing this process’s current block number. The main process will set the value to the new block number when a new block is finalized in the network. The solver process will get the new block number from this value when newBlockEvent is set.

  • curr_diff (multiprocessing.Array) – The array containing this process’s current difficulty. The main process will set the array to the new difficulty when a new block is finalized in the network. The solver process will get the new difficulty from this array when newBlockEvent is set.

  • check_block (multiprocessing.Lock) – The lock to prevent this process from getting the new block data while the main process is updating the data.

  • limit (int) – The limit of the pow solve for a valid solution.

run()#

Method to be run in sub-process; can be overridden in sub-class

class bittensor.utils.registration.pow.UsingSpawnStartMethod(force=False)#
Parameters:

force (bool)

__enter__()#
__exit__(*args)#
_force#
_old_start_method = None#
class bittensor.utils.registration.pow._SolverBase(proc_num, num_proc, update_interval, finished_queue, solution_queue, stopEvent, curr_block, curr_block_num, curr_diff, check_block, limit)#

Bases: multiprocessing.Process

A process that solves the registration PoW problem.

Parameters:
  • proc_num (int) – The number of the process being created.

  • num_proc (int) – The total number of processes running.

  • update_interval (int) – The number of nonces to try to solve before checking for a new block.

  • finished_queue (multiprocessing.Queue) – The queue to put the process number when a process finishes each update_interval. Used for calculating the average time per update_interval across all processes.

  • solution_queue (multiprocessing.Queue) – The queue to put the solution the process has found during the pow solve.

  • stopEvent (multiprocessing.Event) – The event to set by the main process when all the solver processes should stop. The solver process will check for the event after each update_interval. The solver process will stop when the event is set. Used to stop the solver processes when a solution is found.

  • curr_block (multiprocessing.Array) – The array containing this process’s current block hash. The main process will set the array to the new block hash when a new block is finalized in the network. The solver process will get the new block hash from this array when newBlockEvent is set.

  • curr_block_num (multiprocessing.Value) – The value containing this process’s current block number. The main process will set the value to the new block number when a new block is finalized in the network. The solver process will get the new block number from this value when newBlockEvent is set.

  • curr_diff (multiprocessing.Array) – The array containing this process’s current difficulty. The main process will set the array to the new difficulty when a new block is finalized in the network. The solver process will get the new difficulty from this array when newBlockEvent is set.

  • check_block (multiprocessing.Lock) – The lock to prevent this process from getting the new block data while the main process is updating the data.

  • limit (int) – The limit of the pow solve for a valid solution.

check_block: multiprocessing.Lock#
static create_shared_memory()#

Creates shared memory for the solver processes to use.

Return type:

tuple[multiprocessing.Array, multiprocessing.Value, multiprocessing.Array]

curr_block: multiprocessing.Array#
curr_block_num: multiprocessing.Value#
curr_diff: multiprocessing.Array#
finished_queue: multiprocessing.Queue#
hotkey_bytes: bytes#
limit: int#
newBlockEvent: multiprocessing.Event#
num_proc: int#
proc_num: int#
abstract run()#

Method to be run in sub-process; can be overridden in sub-class

solution_queue: multiprocessing.Queue#
stopEvent: multiprocessing.Event#
update_interval: int#
bittensor.utils.registration.pow._check_for_newest_block_and_update(subtensor, netuid, old_block_number, hotkey_bytes, curr_diff, curr_block, curr_block_num, update_curr_block_, check_block, solvers, curr_stats)#

Checks for a new block and updates the current block information if a new block is found.

Parameters:
  • subtensor (bittensor.core.subtensor.Subtensor) – The subtensor object to use for getting the current block.

  • netuid (int) – The netuid to use for retrieving the difficulty.

  • old_block_number (int) – The old block number to check against.

  • hotkey_bytes (bytes) – The bytes of the hotkey’s pubkey.

  • curr_diff (multiprocessing.Array) – The current difficulty as a multiprocessing array.

  • curr_block (multiprocessing.Array) – Where the current block is stored as a multiprocessing array.

  • curr_block_num (multiprocessing.Value) – Where the current block number is stored as a multiprocessing value.

  • update_curr_block (Callable) – A function that updates the current block.

  • check_block (multiprocessing.Lock) – A mp lock that is used to check for a new block.

  • solvers (list[bittensor.utils.registration.Solver]) – A list of solvers to update the current block for.

  • curr_stats (bittensor.utils.registration.RegistrationStatistics) – The current registration statistics to update.

  • update_curr_block_ (Callable)

Returns:

(int) The current block number.

Return type:

int

bittensor.utils.registration.pow._create_seal_hash(block_and_hotkey_hash_bytes, nonce)#

Create a cryptographic seal hash from the given block and hotkey hash bytes and nonce.

This function generates a seal hash by combining the given block and hotkey hash bytes with a nonce. It first converts the nonce to a byte representation, then concatenates it with the first 64 hex characters of the block and hotkey hash bytes. The result is then hashed using SHA-256 followed by the Keccak-256 algorithm to produce the final seal hash.

Parameters:
  • block_and_hotkey_hash_bytes (bytes) – The combined hash bytes of the block and hotkey.

  • nonce (int) – The nonce value used for hashing.

Returns:

The resulting seal hash.

Return type:

bytes

bittensor.utils.registration.pow._get_block_with_retry(subtensor, netuid)#

Gets the current block number, difficulty, and block hash from the substrate node.

Parameters:
  • subtensor (bittensor.core.subtensor.Subtensor) – The subtensor object to use to get the block number, difficulty, and block hash.

  • netuid (int) – The netuid of the network to get the block number, difficulty, and block hash from.

Returns:

tuple[int, int, bytes] block_number (int): The current block number. difficulty (int): The current difficulty of the subnet. block_hash (bytes): The current block hash.

Raises:
Return type:

tuple[int, int, str]

bittensor.utils.registration.pow._get_real_torch()#
bittensor.utils.registration.pow._hash_block_with_hotkey(block_bytes, hotkey_bytes)#

Hashes the block with the hotkey using Keccak-256 to get 32 bytes

Parameters:
Return type:

bytes

bittensor.utils.registration.pow._hex_bytes_to_u8_list(hex_bytes)#
Parameters:

hex_bytes (bytes)

Return type:

list[int]

bittensor.utils.registration.pow._registration_diff_pack(diff, packed_diff)#

Packs the difficulty into two 32-bit integers. Little endian.

Parameters:
  • diff (int)

  • packed_diff (multiprocessing.Array)

bittensor.utils.registration.pow._registration_diff_unpack(packed_diff)#

Unpacks the packed two 32-bit integers into one 64-bit integer. Little endian.

Parameters:

packed_diff (multiprocessing.Array)

Return type:

int

bittensor.utils.registration.pow._seal_meets_difficulty(seal, difficulty, limit)#

Determines if a seal meets the specified difficulty.

Parameters:
Return type:

bool

bittensor.utils.registration.pow._solve_for_difficulty_fast(subtensor, wallet, netuid, output_in_place=True, num_processes=None, update_interval=None, n_samples=10, alpha_=0.8, log_verbose=False)#

Solves the POW for registration using multiprocessing.

Parameters:
  • subtensor (bittensor.core.subtensor.Subtensor) – Subtensor instance to connect to for block information and to submit.

  • wallet (bittensor_wallet.Wallet) – wallet to use for registration.

  • netuid (int) – The netuid of the subnet to register to.

  • output_in_place (bool) – If true, prints the status in place. Otherwise, prints the status on a new line.

  • num_processes (int) – Number of processes to use.

  • update_interval (int) – Number of nonces to solve before updating block information.

  • n_samples (int) – The number of samples of the hash_rate to keep for the EWMA.

  • alpha (float) – The alpha for the EWMA for the hash_rate calculation.

  • log_verbose (bool) – If true, prints more verbose logging of the registration metrics.

  • alpha_ (float)

Return type:

Optional[POWSolution]

Note: The hash rate is calculated as an exponentially weighted moving average in order to make the measure more robust. Note: We can also modify the update interval to do smaller blocks of work, while still updating the block information after a different number of nonces, to increase the transparency of the process while still keeping the speed.

bittensor.utils.registration.pow._solve_for_difficulty_fast_cuda(subtensor, wallet, netuid, output_in_place=True, update_interval=50000, tpb=512, dev_id=0, n_samples=10, alpha_=0.8, log_verbose=False)#

Solves the registration fast using CUDA.

Parameters:
  • subtensor (bittensor.core.subtensor.Subtensor) – The subtensor node to grab blocks.

  • wallet (bittensor_wallet.Wallet) – The wallet to register.

  • netuid (int) – The netuid of the subnet to register to.

  • output_in_place (bool)

  • update_interval (int) – The number of nonces to try before checking for more blocks.

  • tpb (int) – The number of threads per block. CUDA param that should match the GPU capability

  • dev_id (Union[list[int], int]) – The CUDA device IDs to execute the registration on, either a single device or a list of devices.

  • n_samples (int) – The number of samples of the hash_rate to keep for the EWMA.

  • alpha (float) – The alpha for the EWMA for the hash_rate calculation.

  • log_verbose (bool) – If true, prints more verbose logging of the registration metrics.

  • alpha_ (float)

Return type:

Optional[POWSolution]

Note: The hash rate is calculated as an exponentially weighted moving average in order to make the measure more robust.

bittensor.utils.registration.pow._solve_for_nonce_block(nonce_start, nonce_end, block_and_hotkey_hash_bytes, difficulty, limit, block_number)#

Tries to solve the POW for a block of nonces (nonce_start, nonce_end)

Parameters:
  • nonce_start (int)

  • nonce_end (int)

  • block_and_hotkey_hash_bytes (bytes)

  • difficulty (int)

  • limit (int)

  • block_number (int)

Return type:

Optional[POWSolution]

bittensor.utils.registration.pow._solve_for_nonce_block_cuda(nonce_start, update_interval, block_and_hotkey_hash_bytes, difficulty, limit, block_number, dev_id, tpb)#

Tries to solve the POW on a CUDA device for a block of nonces (nonce_start, nonce_start + update_interval * tpb

Parameters:
  • nonce_start (int)

  • update_interval (int)

  • block_and_hotkey_hash_bytes (bytes)

  • difficulty (int)

  • limit (int)

  • block_number (int)

  • dev_id (int)

  • tpb (int)

Return type:

Optional[POWSolution]

bittensor.utils.registration.pow.create_pow(subtensor, wallet, netuid, output_in_place=True, cuda=False, dev_id=0, tpb=256, num_processes=None, update_interval=None, log_verbose=False)#

Creates a proof of work for the given subtensor and wallet.

Parameters:
  • subtensor (bittensor.core.subtensor.Subtensor) – The subtensor to create a proof of work for.

  • wallet (bittensor_wallet.Wallet) – The wallet to create a proof of work for.

  • netuid (int) – The netuid for the subnet to create a proof of work for.

  • output_in_place (bool) – If true, prints the progress of the proof of work to the console in-place. Meaning the progress is printed on the same lines. Default is True.

  • cuda (bool) – If true, uses CUDA to solve the proof of work. Default is False.

  • dev_id (Union[List[int], int]) – The CUDA device id(s) to use. If cuda is true and dev_id is a list, then multiple CUDA devices will be used to solve the proof of work. Default is 0.

  • tpb (int) – The number of threads per block to use when solving the proof of work. Should be a multiple of 32. Default is 256.

  • num_processes (Optional[int]) – The number of processes to use when solving the proof of work. If None, then the number of processes is equal to the number of CPU cores. Default is None.

  • update_interval (Optional[int]) – The number of nonces to run before checking for a new block. Default is None.

  • log_verbose (bool) – If true, prints the progress of the proof of work more verbosely. Default is False.

Returns:

The proof of work solution or None if the wallet is already registered or there is a different error.

Return type:

Optional[Dict[str, Any]]

Raises:

ValueError – If the subnet does not exist.

bittensor.utils.registration.pow.get_cpu_count()#

Returns the number of CPUs in the system.

Return type:

int

bittensor.utils.registration.pow.legacy_torch_api_compat(func)#

Convert function operating on numpy Input&Output to legacy torch Input&Output API if use_torch() is True.

Parameters:

func (function) – Function with numpy Input/Output to be decorated.

Returns:

Decorated function.

Return type:

decorated (function)

bittensor.utils.registration.pow.log_no_torch_error()#
bittensor.utils.registration.pow.terminate_workers_and_wait_for_exit(workers)#
Parameters:

workers (list[Union[multiprocessing.Process, multiprocessing.queues.Queue]])

Return type:

None

bittensor.utils.registration.pow.torch#
bittensor.utils.registration.pow.update_curr_block(curr_diff, curr_block, curr_block_num, block_number, block_bytes, diff, hotkey_bytes, lock)#

Update the current block data with the provided block information and difficulty.

This function updates the current block and its difficulty in a thread-safe manner. It sets the current block number, hashes the block with the hotkey, updates the current block bytes, and packs the difficulty.

Parameters:
  • curr_diff (multiprocessing.Array) – Shared array to store the current difficulty.

  • curr_block (multiprocessing.Array) – Shared array to store the current block data.

  • curr_block_num (multiprocessing.Value) – Shared value to store the current block number.

  • block_number (int) – The block number to set as the current block number.

  • block_bytes (bytes) – The block data bytes to be hashed with the hotkey.

  • diff (int) – The difficulty value to be packed into the current difficulty array.

  • hotkey_bytes (bytes) – The hotkey bytes used for hashing the block.

  • lock (multiprocessing.Lock) – A lock to ensure thread-safe updates.

bittensor.utils.registration.pow.use_torch()#

Force the use of torch over numpy for certain operations.

Return type:

bool