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
53 changes: 25 additions & 28 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 @@ -57,13 +56,15 @@ Before you begin, ensure you have the following installed:

## Setup Instructions

### 1. Clone the Repository
### 1. Fork and clone the Repository

Fork the [subnet template](https://github.com/opentensor/subnet-template) repository to create a copy of the repository under your GitHub account.

Clone this repository to your local machine:
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 @@ -111,61 +112,57 @@ Register both the miner and validator on the Bittensor network.
- **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
```

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

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

---

## 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**:
The script launches an Axon server on port `8901`, which the miner uses to receive incoming requests from validators.

- `--wallet.name`: The name of the wallet.
- `--wallet.hotkey`: The hotkey name for the miner.
- `--subtensor.network`: The Bittensor network to connect to.
### Start the validator process

### Running the Validator
To start the validator process, run the following Python script in the `subnet-template` directory:

In another terminal window, navigate to the project directory and run:

```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
```

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 +200,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
88 changes: 58 additions & 30 deletions validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,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 @@ -99,8 +99,9 @@ def setup_bittensor_objects(self):

# Set up initial scoring weights for validation.
bt.logging.info("Building validation weights.")
self.scores = [1.0] * len(self.metagraph.S)
bt.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)]
bt.logging.info(f"Weights (uid, weight): {weights_with_uids}")

def run(self):
# The Main Validation Loop.
Expand All @@ -116,38 +117,65 @@ def run(self):
axons=self.metagraph.axons, synapse=synapse, timeout=12
)
bt.logging.info(f"sending input {synapse.dummy_input}")
if responses:
responses = [
response.dummy_output
for response in responses
if response is not None
]

# Log the results.
bt.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):
self.moving_avg_scores.extend(
[1] * (len(responses) - 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
self.moving_avg_scores[i] = (
1 - self.alpha
) * self.moving_avg_scores[i] + self.alpha * current_score

bt.logging.info(f"Moving Average Scores: {self.moving_avg_scores}")

# 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
})
bt.logging.info(f"Received responses: {responses_with_uids}")

# Filter successful responses for logging with UIDs
successful_responses_with_uids = []
for i, response in enumerate(responses):
if response is not None:
successful_responses_with_uids.append((int(self.metagraph.uids[i]), response.dummy_output))
bt.logging.info(f"Successful responses (uid, response): {successful_responses_with_uids}")

# Score all miners based on their responses
for i, response in enumerate(responses):
if response is not None:
# Miner responded - score based on correctness
current_score = 1 if response.dummy_output == synapse.dummy_input * 2 else 0
self.moving_avg_scores[i] = (
(1 - self.alpha) * self.moving_avg_scores[i] +
self.alpha * current_score
)
else:
# Miner didn't respond - set score to 0
self.moving_avg_scores[i] = (
(1 - self.alpha) * self.moving_avg_scores[i] +
self.alpha * 0
)

# Create list of (uid, score) tuples
scores_with_uids = [(int(self.metagraph.uids[i]), score) for i, score in enumerate(self.moving_avg_scores)]
bt.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]
bt.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)]
bt.logging.info(f"[blue]Setting weights (uid, weight): {weights_with_uids}[/blue]")
# Update the incentive mechanism on the Bittensor blockchain.
self.subtensor.set_weights(
netuid=self.config.netuid,
Expand Down