diff --git a/bittensor/_cli/cli_impl.py b/bittensor/_cli/cli_impl.py index bdce4358dc..bdc4744e1a 100644 --- a/bittensor/_cli/cli_impl.py +++ b/bittensor/_cli/cli_impl.py @@ -309,7 +309,7 @@ def unstake( self ): if not self.config.no_prompt: if not Confirm.ask("Do you want to unstake from the following keys:\n" + \ "".join([ - f" [bold white]- {wallet.hotkey_str}: {amount.tao}𝜏[/bold white]\n" for wallet, amount in zip(final_wallets, final_amounts) + f" [bold white]- {wallet.hotkey_str}: {amount}𝜏[/bold white]\n" for wallet, amount in zip(final_wallets, final_amounts) ]) ): return None diff --git a/bittensor/_subtensor/subtensor_impl.py b/bittensor/_subtensor/subtensor_impl.py index 48d67d07e7..c05f3a68da 100644 --- a/bittensor/_subtensor/subtensor_impl.py +++ b/bittensor/_subtensor/subtensor_impl.py @@ -501,73 +501,74 @@ def register ( else: pow_result = bittensor.utils.create_pow( self, wallet, num_processes=num_processes, update_interval=update_interval) - # pow failed - if not pow_result: - # might be registered already - if (wallet.is_registered( self )): - bittensor.__console__.print(":white_heavy_check_mark: [green]Registered[/green]") - return True - - # pow successful, proceed to submit pow to chain for registration - else: - with bittensor.__console__.status(":satellite: Submitting POW..."): - # check if pow result is still valid - while bittensor.utils.POWNotStale(self, pow_result): - with self.substrate as substrate: - # create extrinsic call - call = substrate.compose_call( - call_module='SubtensorModule', - call_function='register', - call_params={ - 'block_number': pow_result['block_number'], - 'nonce': pow_result['nonce'], - 'work': bittensor.utils.hex_bytes_to_u8_list( pow_result['work'] ), - 'hotkey': wallet.hotkey.ss58_address, - 'coldkey': wallet.coldkeypub.ss58_address - } - ) - extrinsic = substrate.create_signed_extrinsic( call = call, keypair = wallet.hotkey ) - response = substrate.submit_extrinsic( extrinsic, wait_for_inclusion=wait_for_inclusion, wait_for_finalization=wait_for_finalization ) - - # We only wait here if we expect finalization. - if not wait_for_finalization and not wait_for_inclusion: - bittensor.__console__.print(":white_heavy_check_mark: [green]Sent[/green]") + # pow failed + if not pow_result: + # might be registered already + if (wallet.is_registered( self )): + bittensor.__console__.print(":white_heavy_check_mark: [green]Registered[/green]") + return True + + # pow successful, proceed to submit pow to chain for registration + else: + with bittensor.__console__.status(":satellite: Submitting POW..."): + # check if pow result is still valid + while bittensor.utils.POWNotStale(self, pow_result): + with self.substrate as substrate: + # create extrinsic call + call = substrate.compose_call( + call_module='SubtensorModule', + call_function='register', + call_params={ + 'block_number': pow_result['block_number'], + 'nonce': pow_result['nonce'], + 'work': bittensor.utils.hex_bytes_to_u8_list( pow_result['work'] ), + 'hotkey': wallet.hotkey.ss58_address, + 'coldkey': wallet.coldkeypub.ss58_address + } + ) + extrinsic = substrate.create_signed_extrinsic( call = call, keypair = wallet.hotkey ) + response = substrate.submit_extrinsic( extrinsic, wait_for_inclusion=wait_for_inclusion, wait_for_finalization=wait_for_finalization ) + + # We only wait here if we expect finalization. + if not wait_for_finalization and not wait_for_inclusion: + bittensor.__console__.print(":white_heavy_check_mark: [green]Sent[/green]") + return True + + # process if registration successful, try again if pow is still valid + response.process_events() + if not response.is_success: + if 'key is already registered' in response.error_message: + # Error meant that the key is already registered. + bittensor.__console__.print(":white_heavy_check_mark: [green]Already Registered[/green]") + return True + + bittensor.__console__.print(":cross_mark: [red]Failed[/red]: error:{}".format(response.error_message)) + time.sleep(0.5) + + # Successful registration, final check for neuron and pubkey + else: + bittensor.__console__.print(":satellite: Checking Balance...") + neuron = self.neuron_for_pubkey( wallet.hotkey.ss58_address ) + if not neuron.is_null: + bittensor.__console__.print(":white_heavy_check_mark: [green]Registered[/green]") return True - - # process if registration successful, try again if pow is still valid - response.process_events() - if not response.is_success: - if 'key is already registered' in response.error_message: - # Error meant that the key is already registered. - bittensor.__console__.print(":white_heavy_check_mark: [green]Already Registered[/green]") - return True - - bittensor.__console__.print(":cross_mark: [red]Failed[/red]: error:{}".format(response.error_message)) - time.sleep(0.5) - - # Successful registration, final check for neuron and pubkey else: - bittensor.__console__.print(":satellite: Checking Balance...") - neuron = self.neuron_for_pubkey( wallet.hotkey.ss58_address ) - if not neuron.is_null: - bittensor.__console__.print(":white_heavy_check_mark: [green]Registered[/green]") - return True - else: - # neuron not found, try again - bittensor.__console__.print(":cross_mark: [red]Unknown error. Neuron not found.[/red]") - continue - else: - # Exited loop because pow is no longer valid. - bittensor.__console__.print( "[red]POW is stale.[/red]" ) - return False - if attempts < max_allowed_attempts: - #Failed registration, retry pow - attempts += 1 - bittensor.__console__.print( ":satellite: Failed registration, retrying pow ...({}/{})".format(attempts, max_allowed_attempts)) - else: - # Failed to register after max attempts. - bittensor.__console__.print( "[red]No more attempts.[/red]" ) - return False + # neuron not found, try again + bittensor.__console__.print(":cross_mark: [red]Unknown error. Neuron not found.[/red]") + continue + else: + # Exited loop because pow is no longer valid. + bittensor.__console__.print( "[red]POW is stale.[/red]" ) + return False + + if attempts < max_allowed_attempts: + #Failed registration, retry pow + attempts += 1 + bittensor.__console__.print( ":satellite: Failed registration, retrying pow ...({}/{})".format(attempts, max_allowed_attempts)) + else: + # Failed to register after max attempts. + bittensor.__console__.print( "[red]No more attempts.[/red]" ) + return False def serve ( self, diff --git a/tests/unit_tests/bittensor_tests/utils/test_utils.py b/tests/unit_tests/bittensor_tests/utils/test_utils.py index 5d0643bc08..d3bad0f6f6 100644 --- a/tests/unit_tests/bittensor_tests/utils/test_utils.py +++ b/tests/unit_tests/bittensor_tests/utils/test_utils.py @@ -10,6 +10,7 @@ import random import torch import multiprocessing +from types import SimpleNamespace from sys import platform from substrateinterface.base import Keypair @@ -346,6 +347,57 @@ def test_pow_not_stale_diff_block_number_too_old(self): assert not bittensor.utils.POWNotStale(mock_subtensor, mock_solution) +def test_pow_called_for_cuda(): + class MockException(Exception): + pass + mock_compose_call = MagicMock(side_effect=MockException) + + mock_subtensor = bittensor.subtensor(_mock=True) + mock_subtensor.neuron_for_pubkey=MagicMock(is_null=True) + mock_subtensor.substrate = MagicMock( + __enter__= MagicMock(return_value=MagicMock( + compose_call=mock_compose_call + )), + __exit__ = MagicMock(return_value=None), + ) + + mock_wallet = SimpleNamespace( + hotkey=SimpleNamespace( + ss58_address='' + ), + coldkeypub=SimpleNamespace( + ss58_address='' + ) + ) + + mock_result = { + "block_number": 1, + 'nonce': random.randint(0, pow(2, 32)), + 'work': b'\x00' * 64, + } + + with patch('bittensor.utils.POWNotStale', return_value=True) as mock_pow_not_stale: + with patch('torch.cuda.is_available', return_value=True) as mock_cuda_available: + with patch('bittensor.utils.create_pow', return_value=mock_result) as mock_create_pow: + with patch('bittensor.utils.hex_bytes_to_u8_list', return_value=b''): + + # Should exit early + with pytest.raises(MockException): + mock_subtensor.register(mock_wallet, cuda=True, prompt=False) + + mock_pow_not_stale.assert_called_once() + mock_create_pow.assert_called_once() + mock_cuda_available.assert_called_once() + + call0 = mock_pow_not_stale.call_args + assert call0[0][0] == mock_subtensor + assert call0[0][1] == mock_result + + mock_compose_call.assert_called_once() + call1 = mock_compose_call.call_args + assert call1[1]['call_function'] == 'register' + call_params = call1[1]['call_params'] + assert call_params['nonce'] == mock_result['nonce'] if __name__ == "__main__": test_solve_for_difficulty_fast_registered_already() \ No newline at end of file