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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ dmypy.json
# Cython debug symbols
cython_debug/

*.key

# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.1.0
0.2.0
19 changes: 19 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
version: "3"

services:
redis:
build:
context: .
dockerfile: ./scripts/redis/docker/Dockerfile
args:
- REDIS_PASSWORD=${REDIS_PASSWORD}
container_name: redis
restart: always
ports:
- 6379:6379
volumes:
- cache:/data

volumes:
cache:
driver: local
127 changes: 55 additions & 72 deletions neurons/miner.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,37 +17,30 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.

import os
import sys
import typing
import time
import json
import torch
import asyncio
import bittensor as bt
import threading
import traceback
from urllib.parse import urlparse
from redis import asyncio as aioredis

from subnet.protocol import IsAlive, Key, Subtensor, Challenge
from subnet.protocol import IsAlive, Key, Subtensor, Challenge, Score

from subnet.shared.key import generate_ssh_key, clean_ssh_key
from subnet.shared.checks import check_environment
from subnet.shared.checks import check_environment, check_registration

from subnet.miner import run
from subnet.miner.config import (
config,
check_config,
add_args,
)
from subnet.shared.utils import (
get_redis_password,
)
from subnet.miner.utils import (
update_storage_stats,
load_request_log,
get_purge_ttl_script_path,
)
from subnet.miner.utils import load_request_log


class Miner:
@classmethod
Expand Down Expand Up @@ -121,14 +114,7 @@ def __init__(self):
bt.logging.debug("loading wallet")
self.wallet = bt.wallet(config=self.config)
self.wallet.create_if_non_existent()
if not self.config.wallet._mock:
if not self.subtensor.is_hotkey_registered_on_subnet(
hotkey_ss58=self.wallet.hotkey.ss58_address, netuid=self.config.netuid
):
raise Exception(
f"Wallet not currently registered on netuid {self.config.netuid}, please first register wallet before running"
)

check_registration(self.subtensor, self.wallet, self.config.netuid)
bt.logging.debug(f"wallet: {str(self.wallet)}")

# Init metagraph.
Expand All @@ -144,9 +130,8 @@ def __init__(self):
)
bt.logging.info(f"Running miner on uid: {self.my_subnet_uid}")


# The axon handles request processing, allowing validators to send this process requests.
self.axon = bt.axon(wallet=self.wallet, config=self.config)
self.axon = bt.axon(wallet=self.wallet, config=self.config, external_ip=bt.net.get_external_ip())
bt.logging.info(f"Axon {self.axon}")

# Attach determiners which functions are called when servicing a request.
Expand All @@ -155,16 +140,29 @@ def __init__(self):
forward_fn=self._is_alive,
blacklist_fn=self.blacklist_isalive,
).attach(
forward_fn=self._generate_key,
blacklist_fn=self.blacklist_generate_key,
).attach(
forward_fn=self._subtensor,
blacklist_fn=self.blacklist_subtensor,
).attach(
forward_fn=self._challenge,
blacklist_fn=self.blacklist_challenge,
forward_fn=self._score,
blacklist_fn=self.blacklist_score,
)


# .attach(
# forward_fn=self._key,
# blacklist_fn=self.blacklist_key,
# )
# .attach(
# forward_fn=self._subtensor,
# blacklist_fn=self.blacklist_subtensor,
# ).attach(
# forward_fn=self._key,
# blacklist_fn=self.blacklist_key,
# )
# .attach(
# forward_fn=self._subtensor,
# blacklist_fn=self.blacklist_subtensor,
# ).attach(
# forward_fn=self._challenge,
# blacklist_fn=self.blacklist_challenge,
# )

# Serve passes the axon information to the network + netuid we are hosting on.
# This will auto-update if the axon port of external ip have changed.
bt.logging.info(
Expand Down Expand Up @@ -194,39 +192,39 @@ def __init__(self):
self.requests_per_hour = []
self.average_requests_per_hour = 0

# Init the miner's storage usage tracker
update_storage_stats(self)

self.rate_limiters = {}
self.request_log = load_request_log(self.config.miner.request_log_path)


def _is_alive(self, synapse: IsAlive) -> IsAlive:
bt.logging.info("I'm alive!")
synapse.answer = "alive"
return synapse



def blacklist_isalive(self, synapse: IsAlive) -> typing.Tuple[bool, str]:
return False, synapse.dendrite.hotkey

def _score(self, synapse: Score) -> Score:
bt.logging.info(f"Availability score {synapse.availability}")
bt.logging.info(f"Latency score {synapse.latency}")
bt.logging.info(f"Reliability score {synapse.reliability}")
bt.logging.info(f"Distribution score {synapse.distribution}")
bt.logging.success(f"Score {synapse.score}")
return synapse

async def _generate_key(
self, synapse: Key
) -> Key:
synapse_type="Save" if synapse.generate else "Clean"
def blacklist_score(self, synapse: Score) -> typing.Tuple[bool, str]:
return False, synapse.dendrite.hotkey

async def _key(self, synapse: Key) -> Key:
synapse_type = "Save" if synapse.generate else "Clean"
bt.logging.info(f"[Key/{synapse_type}] Synapse received")
if synapse.generate:
generate_ssh_key(synapse.validator_public_key)
else:
clean_ssh_key(synapse.validator_public_key)
bt.logging.info(f"[Key/{synapse_type}] Synapse proceed")
bt.logging.success(f"[Key/{synapse_type}] Synapse proceed")
return synapse


async def blacklist_generate_key(
self, synapse: Key
) -> typing.Tuple[bool, str]:
async def blacklist_key(self, synapse: Key) -> typing.Tuple[bool, str]:
if synapse.dendrite.hotkey not in self.metagraph.hotkeys:
# Ignore requests from unrecognized entities.
bt.logging.trace(
Expand All @@ -239,21 +237,19 @@ async def blacklist_generate_key(
)
return False, "Hotkey recognized!"


async def _subtensor(
self, synapse: Subtensor
) -> Subtensor:
async def _subtensor(self, synapse: Subtensor) -> Subtensor:
bt.logging.info("[Subtensor] Synapse received")
parsed_url = urlparse(self.subtensor.chain_endpoint)
ip = self.axon.external_ip if parsed_url.hostname == '127.0.0.1' else parsed_url.hostname
ip = (
self.axon.external_ip
if parsed_url.hostname == "127.0.0.1"
else parsed_url.hostname
)
synapse.subtensor_ip = ip
bt.logging.info("[Subtensor] Synapse proceed")
bt.logging.success("[Subtensor] Synapse proceed")
return synapse


async def blacklist_subtensor(
self, synapse: Subtensor
) -> typing.Tuple[bool, str]:
async def blacklist_subtensor(self, synapse: Subtensor) -> typing.Tuple[bool, str]:
if synapse.dendrite.hotkey not in self.metagraph.hotkeys:
# Ignore requests from unrecognized entities.
bt.logging.trace(
Expand All @@ -266,20 +262,14 @@ async def blacklist_subtensor(
)
return False, "Hotkey recognized!"


async def _challenge(
self, synapse: Challenge
) -> Challenge:
async def _challenge(self, synapse: Challenge) -> Challenge:
bt.logging.info("[Challenge] Synapse received")
block=self.subtensor.get_current_block()
block = self.subtensor.get_current_block()
synapse.answer = f"{block}"
bt.logging.info("[Challenge] Synapse proceed")
return synapse


async def blacklist_challenge(
self, synapse: Challenge
) -> typing.Tuple[bool, str]:
async def blacklist_challenge(self, synapse: Challenge) -> typing.Tuple[bool, str]:
if synapse.dendrite.hotkey not in self.metagraph.hotkeys:
# Ignore requests from unrecognized entities.
bt.logging.trace(
Expand All @@ -292,7 +282,6 @@ async def blacklist_challenge(
)
return False, "Hotkey recognized!"


def start_request_count_timer(self):
"""
Initializes and starts a timer for tracking the number of requests received by the miner in an hour.
Expand All @@ -307,7 +296,6 @@ def start_request_count_timer(self):
self.request_count_timer = threading.Timer(3600, self.reset_request_count)
self.request_count_timer.start()


def reset_request_count(self):
"""
Logs the number of requests received in the last hour and resets the count.
Expand All @@ -331,11 +319,9 @@ def reset_request_count(self):
self.request_count = 0
self.start_request_count_timer()


def run(self):
run(self)


def run_in_background_thread(self):
"""
Starts the miner's operations in a separate background thread.
Expand All @@ -349,7 +335,6 @@ def run_in_background_thread(self):
self.is_running = True
bt.logging.debug("Started")


def stop_run_thread(self):
"""
Stops the miner's operations that are running in the background thread.
Expand All @@ -361,15 +346,13 @@ def stop_run_thread(self):
self.is_running = False
bt.logging.debug("Stopped")


def __enter__(self):
"""
Starts the miner's operations in a background thread upon entering the context.
This method facilitates the use of the miner in a 'with' statement.
"""
self.run_in_background_thread()


def __exit__(self, exc_type, exc_value, traceback):
"""
Stops the miner's background operations upon exiting the context.
Expand Down
34 changes: 15 additions & 19 deletions neurons/validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,15 @@
from pprint import pformat
from traceback import print_exception
from substrateinterface.base import SubstrateInterface
# from dotenv import load_dotenv

from subnet.shared.checks import check_environment
from subnet.shared.checks import check_environment, check_registration
from subnet.shared.utils import get_redis_password
from subnet.shared.subtensor import get_current_block
from subnet.shared.weights import should_set_weights

from subnet.validator.config import config, check_config, add_args
from subnet.validator.encryption import setup_encryption_wallet
from subnet.validator.localisation import get_country, get_localisation
from subnet.validator.forward import forward
from subnet.validator.state import (
checkpoint,
Expand Down Expand Up @@ -86,6 +87,9 @@ def __init__(self):
self.check_config(self.config)
bt.logging(config=self.config, logging_dir=self.config.neuron.full_path)

# Load env variables
# load_dotenv()

try:
asyncio.run(check_environment(self.config.database.redis_conf_path))
except AssertionError as e:
Expand All @@ -112,25 +116,11 @@ def __init__(self):
self.wallet = bt.wallet(config=self.config)
self.wallet.create_if_non_existent()

if not self.config.wallet._mock:
if not self.subtensor.is_hotkey_registered_on_subnet(
hotkey_ss58=self.wallet.hotkey.ss58_address, netuid=self.config.netuid
):
raise Exception(
f"Wallet not currently registered on netuid {self.config.netuid}, please first register wallet before running"
)
# Check registration
check_registration(self.subtensor, self.wallet, self.config.netuid)

bt.logging.debug(f"wallet: {str(self.wallet)}")

# Setup dummy wallet for encryption purposes. No password needed.
self.encryption_wallet = setup_encryption_wallet(
wallet_name=self.config.encryption.wallet_name,
wallet_hotkey=self.config.encryption.hotkey,
password=self.config.encryption.password,
)
self.encryption_wallet.coldkey # Unlock the coldkey.
bt.logging.info(f"loading encryption wallet {self.encryption_wallet}")

# Init metagraph.
bt.logging.debug("loading metagraph")
self.metagraph = bt.metagraph(
Expand Down Expand Up @@ -171,6 +161,12 @@ def __init__(self):
self.dendrite = bt.dendrite(wallet=self.wallet)
bt.logging.debug(str(self.dendrite))

# Get the validator country
self.country = get_country(self.dendrite.external_ip)
country_localisation = get_localisation(self.country)
country_name = country_localisation['country'] if country_localisation else 'None'
bt.logging.debug(F"Validator based in {country_name}")

# Init the event loop.
self.loop = asyncio.get_event_loop()

Expand All @@ -179,7 +175,7 @@ def __init__(self):

# Start with 0 monitor pings
# TODO: load this from disk instead of reset on restart
self.monitor_lookup = {uid: 0 for uid in self.metagraph.uids.tolist()}
# self.monitor_lookup = {uid: 0 for uid in self.metagraph.uids.tolist()}

# Instantiate runners
self.should_exit: bool = False
Expand Down
Loading