Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
47 changes: 21 additions & 26 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 @@ -62,8 +61,8 @@ Before you begin, ensure you have the following installed:
Clone this repository to your local machine:

```bash
git clone https://github.com/yourusername/bittensor_subnet.git
cd bittensor_subnet
git clone https://github.com/opentensor/subnet-template.git
cd subnet-template

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is what we want to do for a template.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you let me know what the idea is?

asking cause the readme walks through running the miner/validator logic defined in the repo but using the previous clone/change directory commands doesnt work.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well this is a template. So it's designed to be forked and the information in it updated by the forker. Having this hard-coded will work, and that's the problem. Because it works, people will think that's correct to do rather than updating the info to the fork.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gotcha! i can edit the README so that it includes the forking of the repo and then change the command to reflect that.

does that work?

```

### 2. Install Dependencies
Expand Down Expand Up @@ -111,61 +110,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**:

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

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 +198,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
59 changes: 34 additions & 25 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,7 +99,7 @@ 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)
self.scores = [0] * len(self.metagraph.S)
bt.logging.info(f"Weights: {self.scores}")

def run(self):
Expand All @@ -116,28 +116,33 @@ 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"Received responses: {responses}")

# Filter successful responses for logging
successful_responses = [
response.dummy_output
for response in responses
if response is not None
]
bt.logging.info(f"Successful responses: {successful_responses}")
Copy link

@ibraheem-abe ibraheem-abe Aug 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice if we can also mention the index which corresponds to the uid of the responses.
For example, if the raw responses were: None, None, 3, None, 6
Instead of outputting simply 3, and 6, it will be nice to know the uids associated with them.

Helps easily identify which miner is responding

Copy link
Author

@chideraao chideraao Aug 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tried something. wdyt

Screenshot 2025-08-13 at 22 37 43


# 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
)

bt.logging.info(f"Moving Average Scores: {self.moving_avg_scores}")
self.last_update = self.subtensor.blocks_since_last_update(
Expand All @@ -146,7 +151,11 @@ def run(self):

# set weights once every tempo
total = sum(self.moving_avg_scores)
weights = [score / total for score in self.moving_avg_scores]
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)
bt.logging.info(f"[blue]Setting weights: {weights}[/blue]")
# Update the incentive mechanism on the Bittensor blockchain.
self.subtensor.set_weights(
Expand Down