Skip to content
Open
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
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
__pycache__/
__pycache__/
venv
.venv
68 changes: 38 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -91,7 +95,6 @@ The `btcli` tool is used to manage wallets and keys.
```

2. **Create Hotkeys**:

- **Miner Hotkey**:

```bash
Expand All @@ -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/<wallet.name>/<wallet.hotkey>/netuid<netuid>/<miner or validator>/
```

- **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.

Expand Down Expand Up @@ -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`.

---

Expand Down
58 changes: 46 additions & 12 deletions validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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.
Expand All @@ -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
Expand All @@ -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,
Expand Down