diff --git a/.gitignore b/.gitignore index ba0430d..0630458 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -__pycache__/ \ No newline at end of file +__pycache__/ +venv +.venv \ No newline at end of file diff --git a/README.md b/README.md index a0cc4d7..b32116f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ - # Bittensor Subnet Template This repository provides a minimal template for setting up a simple Bittensor subnet with a miner and a validator. The miner and validator communicate using a custom protocol defined in `protocol.py`. This template serves as a starting point for developers interested in building on the Bittensor network. @@ -53,17 +52,22 @@ Before you begin, ensure you have the following installed: - Python 3.10 or higher - [Git](https://git-scm.com/) -- [Bittensor SDK](https://github.com/opentensor/bittensor) +- [Bittensor SDK](https://github.com/opentensor/bittensor) (version 10 or higher) +- An active subnet on Bittensor testnet or local chain instance. For more information, see [create a new subnet](https://docs.learnbittensor.org/subnets/create-a-subnet#creating-a-subnet-on-testchain) + +> **Note**: To create a local blockchain instance, see [Run a Local Bittensor Blockchain Instance](https://docs.learnbittensor.org/local-build/deploy#prerequisites). ## Setup Instructions -### 1. Clone the Repository +### 1. Fork and clone the Repository -Clone this repository to your local machine: +Fork the [subnet template](https://github.com/opentensor/subnet-template) repository to create a copy of the repository under your GitHub account. + +Next, clone this repository to your local machine and change directory ask shown: ```bash -git clone https://github.com/yourusername/bittensor_subnet.git -cd bittensor_subnet +git clone https://github.com/YOUR_USERNAME/subnet_template.git +cd subnet_template ``` ### 2. Install Dependencies @@ -91,7 +95,6 @@ The `btcli` tool is used to manage wallets and keys. ``` 2. **Create Hotkeys**: - - **Miner Hotkey**: ```bash @@ -106,66 +109,71 @@ The `btcli` tool is used to manage wallets and keys. ### 4. Register Wallets -Register both the miner and validator on the Bittensor network. +Register both the miner and validator on the active Bittensor subnet. + +> **Note**: Ensure your miner and validator wallets are sufficiently funded before attempting subnet registration. +> +> - For local development, transfer funds from the Alice account. +> - For testnet development, you can request testnet TAO from the [Bittensor Discord](https://discord.com/channels/799672011265015819/1107738550373454028/threads/1331693251589312553). - **Register the Miner**: ```bash - btcli s register --wallet.name mywallet --wallet.hotkey miner_hotkey --subtensor.network finney + btcli s register --wallet.name mywallet --wallet.hotkey miner_hotkey --subtensor.network NETWORK --netuid NETUID ``` - **Register the Validator**: ```bash - btcli s register --wallet.name mywallet --wallet.hotkey validator_hotkey --subtensor.network finney + btcli s register --wallet.name mywallet --wallet.hotkey validator_hotkey --subtensor.network NETWORK --netuid NETUID ``` -> **Note**: Replace `finney` with the name of the network you are connecting to if different. +> **Note**: Replace `NETWORK` with the name of the network you are connecting to if different—`local` or `test`. --- ## Running the Miner and Validator -### Running the Miner +### Start the miner process -In one terminal window, navigate to the project directory and run: +To start the miner, run the following Python script in the `subnet-template` directory: -```bash -python miner.py --wallet.name mywallet --wallet.hotkey miner_hotkey --subtensor.network finney --axon.port 8901 +```sh +python miner.py --wallet.name WALLET_NAME --wallet.hotkey HOTKEY --netuid NETUID --axon.port 8901 --subtensor.network NETWORK ``` -**Arguments**: +> **Note**: Run the `miner.py` script in a Python environment with the Bittensor SDK installed. -- `--wallet.name`: The name of the wallet. -- `--wallet.hotkey`: The hotkey name for the miner. -- `--subtensor.network`: The Bittensor network to connect to. +The script launches an Axon server on port `8901`, which the miner uses to receive incoming requests from validators. -### Running the Validator +### Start the validator process -In another terminal window, navigate to the project directory and run: +To start the validator process, run the following Python script in the `subnet-template` directory: -```bash -python validator.py --wallet.name mywallet --wallet.hotkey validator_hotkey --subtensor.network finney +```sh +python validator.py --wallet.name WALLET_NAME --wallet.hotkey HOTKEY --netuid NETUID --subtensor.network NETWORK ``` +> **Note**: Run the `validator.py` script in a Python environment with the Bittensor SDK installed. + +This script begins the process of sending inputs to the miners and setting weights based on miner responses. + **Arguments**: - `--wallet.name`: The name of the wallet. - `--wallet.hotkey`: The hotkey name for the validator. +- `--netuid`: The uid of the subnet in the network. - `--subtensor.network`: The Bittensor network to connect to. --- ## Monitoring and Logging -Both the miner and validator will output logs to the console and save logs to files in the following directory structure: +Use the `--logging.info` flag to print miner and validator log messages directly to the console. This helps you monitor activity in real time. For example +```sh +python validator.py --wallet.name WALLET_NAME --wallet.hotkey HOTKEY --netuid NETUID --subtensor.network NETWORK --logging.info ``` -~/.bittensor/wallets///netuid// -``` - -- **Miner Logs**: Located in the `miner` directory. -- **Validator Logs**: Located in the `validator` directory. You can monitor these logs to observe the interactions and performance metrics. @@ -203,7 +211,7 @@ else: ### Changing Network Parameters -You can adjust network parameters like `netuid`, timeouts, and other settings via command-line arguments or by modifying the code. +You can adjust network parameters like `netuid`, timeouts, and other settings via command-line arguments or by modifying the code in the `miner.py` and `validator.py`. --- diff --git a/validator.py b/validator.py index 4ca524e..5c2182f 100644 --- a/validator.py +++ b/validator.py @@ -16,12 +16,12 @@ def __init__(self): self.setup_logging() self.setup_bittensor_objects() self.my_uid = self.metagraph.hotkeys.index(self.wallet.hotkey.ss58_address) - self.scores = [1.0] * len(self.metagraph.S) + self.scores = [0] * len(self.metagraph.S) self.last_update = self.subtensor.blocks_since_last_update( self.config.netuid, self.my_uid ) self.tempo = self.subtensor.tempo(self.config.netuid) - self.moving_avg_scores = [1.0] * len(self.metagraph.S) + self.moving_avg_scores = [0] * len(self.metagraph.S) self.alpha = 0.1 def get_config(self): @@ -101,8 +101,9 @@ def setup_bittensor_objects(self): # Set up initial scoring weights for validation. logging.info("Building validation weights.") - self.scores = [1.0] * len(self.metagraph.S) - logging.info(f"Weights: {self.scores}") + self.scores = [0] * len(self.metagraph.S) + weights_with_uids = [(int(self.metagraph.uids[i]), score) for i, score in enumerate(self.scores)] + logging.info(f"Weights (uid, weight): {weights_with_uids}") def run(self): # The Main Validation Loop. @@ -118,6 +119,27 @@ def run(self): axons=self.metagraph.axons, synapse=synapse, timeout=12 ) logging.info(f"sending input {synapse.dummy_input}") + + # Log the results with UIDs showing input and output + responses_with_uids = [] + for i, response in enumerate(responses): + uid = int(self.metagraph.uids[i]) + if response is not None and response.dummy_output is not None: + responses_with_uids.append({ + 'uid': uid, + 'input': response.dummy_input, + 'output': response.dummy_output + }) + else: + responses_with_uids.append({ + 'uid': uid, + 'input': synapse.dummy_input, + 'output': None + }) + logging.info(f"Received responses: {responses_with_uids}") + + # Store original responses for scoring before filtering + original_responses = responses if responses: responses = [ response.dummy_output @@ -128,28 +150,40 @@ def run(self): # Log the results. logging.info(f"Received dummy responses: {responses}") - # Adjust the length of moving_avg_scores to match the number of responses - if len(self.moving_avg_scores) < len(responses): + # Adjust the length of moving_avg_scores to match the number of miners + if len(self.moving_avg_scores) < len(self.metagraph.S): self.moving_avg_scores.extend( - [1] * (len(responses) - len(self.moving_avg_scores)) + [0] * (len(self.metagraph.S) - len(self.moving_avg_scores)) ) # Adjust the scores based on responses from miners and update moving average. - for i, resp_i in enumerate(responses): - current_score = 1 if resp_i == synapse.dummy_input * 2 else 0 + # Process by original miner index to maintain UID mapping + for i, response in enumerate(original_responses): + if response is not None and response.dummy_output is not None: + current_score = 1 if response.dummy_output == synapse.dummy_input * 2 else 0 + else: + current_score = 0 self.moving_avg_scores[i] = ( 1 - self.alpha ) * self.moving_avg_scores[i] + self.alpha * current_score - logging.info(f"Moving Average Scores: {self.moving_avg_scores}") + # Create list of (uid, score) tuples + scores_with_uids = [(int(self.metagraph.uids[i]), score) for i, score in enumerate(self.moving_avg_scores)] + logging.info(f"Moving Average Scores (uid, score): {scores_with_uids}") self.last_update = self.subtensor.blocks_since_last_update( self.config.netuid, self.my_uid ) # set weights once every tempo total = sum(self.moving_avg_scores) - weights = [score / total for score in self.moving_avg_scores] - logging.info(f"[blue]Setting weights: {weights}[/blue]") + if total > 0: + weights = [score / total for score in self.moving_avg_scores] + else: + # If no miners responded, set zero weights + weights = [0.0] * len(self.moving_avg_scores) + # Create list of (uid, weight) tuples + weights_with_uids = [(int(self.metagraph.uids[i]), weight) for i, weight in enumerate(weights)] + logging.info(f"[blue]Setting weights (uid, weight): {weights_with_uids}[/blue]") # Update the incentive mechanism on the Bittensor blockchain. response = self.subtensor.set_weights( wallet=self.wallet,