Skip to content

Commit 2789eb1

Browse files
authored
Merge pull request #2839 from opentensor/fix/roman/add-force_register_neuron
Add `force_register_neuron` into MockSubtensor
2 parents e027019 + 05b433a commit 2789eb1

File tree

3 files changed

+160
-5
lines changed

3 files changed

+160
-5
lines changed

bittensor/utils/mock/subtensor_mock.py

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from collections.abc import Mapping
22
from dataclasses import dataclass
33
from hashlib import sha256
4+
from random import randint
45
from types import SimpleNamespace
56
from typing import Any, Optional, Union, TypedDict
67
from unittest.mock import MagicMock, patch
@@ -358,6 +359,104 @@ def set_difficulty(self, netuid: int, difficulty: int) -> None:
358359

359360
subtensor_state["Difficulty"][netuid][self.block_number] = difficulty
360361

362+
def _register_neuron(self, netuid: int, hotkey: str, coldkey: str) -> int:
363+
subtensor_state = self.chain_state["SubtensorModule"]
364+
if netuid not in subtensor_state["NetworksAdded"]:
365+
raise Exception("Subnet does not exist")
366+
367+
subnetwork_n = self._get_most_recent_storage(
368+
subtensor_state["SubnetworkN"][netuid]
369+
)
370+
371+
if subnetwork_n > 0 and any(
372+
self._get_most_recent_storage(subtensor_state["Keys"][netuid][uid])
373+
== hotkey
374+
for uid in range(subnetwork_n)
375+
):
376+
# already_registered
377+
raise Exception("Hotkey already registered")
378+
else:
379+
# Not found
380+
if subnetwork_n >= self._get_most_recent_storage(
381+
subtensor_state["MaxAllowedUids"][netuid]
382+
):
383+
# Subnet full, replace neuron randomly
384+
uid = randint(0, subnetwork_n - 1)
385+
else:
386+
# Subnet not full, add new neuron
387+
# Append as next uid and increment subnetwork_n
388+
uid = subnetwork_n
389+
subtensor_state["SubnetworkN"][netuid][self.block_number] = (
390+
subnetwork_n + 1
391+
)
392+
393+
subtensor_state["Stake"][hotkey] = {}
394+
subtensor_state["Stake"][hotkey][coldkey] = {}
395+
subtensor_state["Stake"][hotkey][coldkey][self.block_number] = 0
396+
397+
subtensor_state["Uids"][netuid][hotkey] = {}
398+
subtensor_state["Uids"][netuid][hotkey][self.block_number] = uid
399+
400+
subtensor_state["Keys"][netuid][uid] = {}
401+
subtensor_state["Keys"][netuid][uid][self.block_number] = hotkey
402+
403+
subtensor_state["Owner"][hotkey] = {}
404+
subtensor_state["Owner"][hotkey][self.block_number] = coldkey
405+
406+
subtensor_state["Active"][netuid][uid] = {}
407+
subtensor_state["Active"][netuid][uid][self.block_number] = True
408+
409+
subtensor_state["LastUpdate"][netuid][uid] = {}
410+
subtensor_state["LastUpdate"][netuid][uid][self.block_number] = (
411+
self.block_number
412+
)
413+
414+
subtensor_state["Rank"][netuid][uid] = {}
415+
subtensor_state["Rank"][netuid][uid][self.block_number] = 0.0
416+
417+
subtensor_state["Emission"][netuid][uid] = {}
418+
subtensor_state["Emission"][netuid][uid][self.block_number] = 0.0
419+
420+
subtensor_state["Incentive"][netuid][uid] = {}
421+
subtensor_state["Incentive"][netuid][uid][self.block_number] = 0.0
422+
423+
subtensor_state["Consensus"][netuid][uid] = {}
424+
subtensor_state["Consensus"][netuid][uid][self.block_number] = 0.0
425+
426+
subtensor_state["Trust"][netuid][uid] = {}
427+
subtensor_state["Trust"][netuid][uid][self.block_number] = 0.0
428+
429+
subtensor_state["ValidatorTrust"][netuid][uid] = {}
430+
subtensor_state["ValidatorTrust"][netuid][uid][self.block_number] = 0.0
431+
432+
subtensor_state["Dividends"][netuid][uid] = {}
433+
subtensor_state["Dividends"][netuid][uid][self.block_number] = 0.0
434+
435+
subtensor_state["PruningScores"][netuid][uid] = {}
436+
subtensor_state["PruningScores"][netuid][uid][self.block_number] = 0.0
437+
438+
subtensor_state["ValidatorPermit"][netuid][uid] = {}
439+
subtensor_state["ValidatorPermit"][netuid][uid][self.block_number] = False
440+
441+
subtensor_state["Weights"][netuid][uid] = {}
442+
subtensor_state["Weights"][netuid][uid][self.block_number] = []
443+
444+
subtensor_state["Bonds"][netuid][uid] = {}
445+
subtensor_state["Bonds"][netuid][uid][self.block_number] = []
446+
447+
subtensor_state["Axons"][netuid][hotkey] = {}
448+
subtensor_state["Axons"][netuid][hotkey][self.block_number] = {}
449+
450+
subtensor_state["Prometheus"][netuid][hotkey] = {}
451+
subtensor_state["Prometheus"][netuid][hotkey][self.block_number] = {}
452+
453+
if hotkey not in subtensor_state["IsNetworkMember"]:
454+
subtensor_state["IsNetworkMember"][hotkey] = {}
455+
subtensor_state["IsNetworkMember"][hotkey][netuid] = {}
456+
subtensor_state["IsNetworkMember"][hotkey][netuid][self.block_number] = True
457+
458+
return uid
459+
361460
@staticmethod
362461
def _convert_to_balance(balance: Union["Balance", float, int]) -> "Balance":
363462
if isinstance(balance, float):
@@ -368,6 +467,37 @@ def _convert_to_balance(balance: Union["Balance", float, int]) -> "Balance":
368467

369468
return balance
370469

470+
def force_register_neuron(
471+
self,
472+
netuid: int,
473+
hotkey: str,
474+
coldkey: str,
475+
stake: Union["Balance", float, int] = Balance(0),
476+
balance: Union["Balance", float, int] = Balance(0),
477+
) -> int:
478+
"""
479+
Force register a neuron on the mock chain, returning the UID.
480+
"""
481+
stake = self._convert_to_balance(stake)
482+
balance = self._convert_to_balance(balance)
483+
484+
subtensor_state = self.chain_state["SubtensorModule"]
485+
if netuid not in subtensor_state["NetworksAdded"]:
486+
raise Exception("Subnet does not exist")
487+
488+
uid = self._register_neuron(netuid=netuid, hotkey=hotkey, coldkey=coldkey)
489+
490+
subtensor_state["TotalStake"][self.block_number] = (
491+
self._get_most_recent_storage(subtensor_state["TotalStake"]) + stake.rao
492+
)
493+
subtensor_state["Stake"][hotkey][coldkey][self.block_number] = stake.rao
494+
495+
if balance.rao > 0:
496+
self.force_set_balance(coldkey, balance)
497+
self.force_set_balance(coldkey, balance)
498+
499+
return uid
500+
371501
def force_set_balance(
372502
self, ss58_address: str, balance: Union["Balance", float, int] = Balance(0)
373503
) -> tuple[bool, Optional[str]]:

tests/integration_tests/test_metagraph_integration.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
import os
12
from unittest import mock
23

3-
import bittensor
44
import torch
5-
import os
6-
from bittensor.utils.mock import MockSubtensor
5+
6+
import bittensor
77
from bittensor.core.metagraph import METAGRAPH_STATE_DICT_NDARRAY_KEYS, get_save_dir
8+
from bittensor.utils.mock import MockSubtensor
89

910
_subtensor_mock: MockSubtensor = MockSubtensor()
1011

tests/integration_tests/test_subtensor_integration.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import pytest
22

3-
from bittensor import NeuronInfo
4-
from bittensor.core.chain_data.axon_info import AxonInfo
3+
from bittensor.core.chain_data import AxonInfo, NeuronInfo
54
from bittensor.core.subtensor import Subtensor
65
from bittensor.utils.balance import Balance
76
from tests.helpers.helpers import FakeWebsocket
7+
from bittensor.utils.mock.subtensor_mock import MockSubtensor
88

99

1010
@pytest.fixture
@@ -126,3 +126,27 @@ async def test_get_neuron_for_pubkey_and_subnet(mocker):
126126
assert isinstance(result.total_stake, Balance)
127127
assert isinstance(result.axon_info, AxonInfo)
128128
assert result.is_null is False
129+
130+
131+
def test_mock_subtensor_force_register_neuron():
132+
"""Tests the force_register_neuron method of the MockSubtensor class."""
133+
# Preps
134+
test_netuid = 1
135+
subtensor = MockSubtensor()
136+
subtensor.create_subnet(netuid=test_netuid)
137+
138+
uid1 = subtensor.force_register_neuron(test_netuid, "hk1", "cc1")
139+
uid2 = subtensor.force_register_neuron(test_netuid, "hk2", "cc2")
140+
141+
# Calls
142+
neurons = subtensor.neurons(test_netuid)
143+
neuron1 = subtensor.neuron_for_uid(uid1, test_netuid)
144+
neuron2 = subtensor.neuron_for_uid(uid2, test_netuid)
145+
146+
# Assertions
147+
assert len(neurons) == 2
148+
assert [neuron1, neuron2] == neurons
149+
assert neuron1.hotkey == "hk1"
150+
assert neuron1.coldkey == "cc1"
151+
assert neuron2.hotkey == "hk2"
152+
assert neuron2.coldkey == "cc2"

0 commit comments

Comments
 (0)