From 0b717e5c2b0b55475a0042401fe0f7b4d942609d Mon Sep 17 00:00:00 2001 From: Peter Carlson Date: Mon, 13 Jan 2025 10:43:55 -0500 Subject: [PATCH 01/14] update docs --- README.md | 48 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f379af8..51fd93b 100644 --- a/README.md +++ b/README.md @@ -70,8 +70,6 @@ poetry install --- ## Configuration -### Makefile - ### .env Files Copy the example `.env` files and edit all desired values: @@ -79,7 +77,26 @@ Copy the example `.env` files and edit all desired values: ``` cp .env.validator.example .env.validator ``` -Edit `.env.validator` with your desired values. +Edit `.env.validator` with your desired values. + +``` +# Network Configuration +# Options: localnet, testnet, finney +NETWORK=testnet + +# Wallet Configuration +COLDKEY=your_validator_coldkey +VALIDATOR_HOTKEY=your_validator_hotkey + +# Node Configuration +VALIDATOR_NAME=validator +VALIDATOR_PORT=8091 + +# Logging +# Options: info, debug, trace +LOGGING_LEVEL=debug + +``` #### .env.miner ``` @@ -87,6 +104,31 @@ cp .env.miner.example .env.miner ``` Edit `.env.miner` with your desired values. +```# Network Configuration +# Options: localnet, testnet, finney +NETWORK=testnet + +# Wallet Configuration +COLDKEY=your_miner_coldkey +MINER_HOTKEY=your_miner_hotkey + +# Node Configuration +MINER_NAME=miner +# This port must be open to accept incoming TCP connections. +MINER_PORT=8092 + +# Miner Settings +TIMEOUT=16 +VPERMIT_TAO_LIMIT=2 + +#Adjust this function if you would like to specify a custom forward function +FORWARD_FUNCTION=base_miner + +# Logging +# Options: info, debug, trace +LOGGING_LEVEL=debug +``` + ### Wandb Wandb integration is planned for mainnet launch and does not currently work. From c521c82dc33f185ef37bee8a8d106edf64bac743 Mon Sep 17 00:00:00 2001 From: Peter Carlson Date: Mon, 13 Jan 2025 11:07:56 -0500 Subject: [PATCH 02/14] update readme to include a prereqs section --- README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/README.md b/README.md index 51fd93b..8eece23 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,29 @@ The incentive mechanism was specifically designed to reward precise statements o | 2 vCPUs | 2 vCPUs | --- + +## Prerequisites + +Before beginning, ensure you have: + +1. **Python Installation** + - Python version 3.9, 3.10, or 3.11 installed + - We recommend using `pyenv` for Python version management + +2. **Bittensor Knowledge** + - Understanding of the Bittensor ecosystem and wallet management + - Familiarity with creating and managing Bittensor wallets + - Review the [Bittensor Wallet Documentation](https://docs.bittensor.com/getting-started/wallets) + - For general understanding, see the [Bittensor Documentation](https://docs.bittensor.com/) + +3. **Poetry** + - Basic understanding of Poetry for dependency management + - See the [Poetry Documentation](https://python-poetry.org/docs/) for installation and usage + +4. **System Requirements** + - NodeJS and NPM (for PM2 installation) + - Basic understanding of command-line interfaces + ## Installation First, install PM2: From b21e4572d937dad9daa0880e10b49a62c1f1a270 Mon Sep 17 00:00:00 2001 From: Peter Carlson Date: Mon, 13 Jan 2025 11:24:58 -0500 Subject: [PATCH 03/14] more readme updates. Include registration instructions --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8eece23..b515305 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ Before beginning, ensure you have: 4. **System Requirements** - NodeJS and NPM (for PM2 installation) - Basic understanding of command-line interfaces - + ## Installation First, install PM2: @@ -94,7 +94,7 @@ poetry install ## Configuration ### .env Files -Copy the example `.env` files and edit all desired values: +Copy the example `.env` files and edit all desired values. If you are running a validator, you will only need to copy the .env.validator file. If you are running a miner, you will only need to copy the .env.miner file: #### .env.validator ``` @@ -118,7 +118,6 @@ VALIDATOR_PORT=8091 # Logging # Options: info, debug, trace LOGGING_LEVEL=debug - ``` #### .env.miner @@ -158,6 +157,9 @@ Wandb integration is planned for mainnet launch and does not currently work. --- ## Deployment +### Registering a Hotkey +Once you have configured your .env files as per the instructions above, you can register a miner with `make register ENV_FILE=.env.miner` or register a validator with `make register ENV_FILE=.env.validator`. + ### Running a Miner Base miner: 1. Run the command: From c10a8a2f82ee1efccf3b6ca7db20bf3f715af1c8 Mon Sep 17 00:00:00 2001 From: Peter Carlson Date: Mon, 13 Jan 2025 14:40:20 -0500 Subject: [PATCH 04/14] revert axon initialization --- precog/utils/bittensor.py | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/precog/utils/bittensor.py b/precog/utils/bittensor.py index ce48803..11d9caf 100644 --- a/precog/utils/bittensor.py +++ b/precog/utils/bittensor.py @@ -31,32 +31,8 @@ def setup_bittensor_objects(self): self.metagraph = self.subtensor.metagraph(self.config.netuid) self.wallet = bt.wallet(config=self.config) self.dendrite = bt.dendrite(wallet=self.wallet) - - # Initialize axon config - axon_config = bt.axon.config() - axon_config.max_workers = self.config.axon.max_workers - axon_config.port = self.config.axon.port - axon_config.ip = self.config.axon.ip - axon_config.external_ip = self.config.axon.external_ip - axon_config.external_port = self.config.axon.external_port - self.config.axon = axon_config - - # Debug prints - bt.logging.debug(f"Axon config - port: {self.config.axon.port}") - bt.logging.debug(f"Axon config - ip: {self.config.axon.ip}") - bt.logging.debug(f"Axon config - external_ip: {self.config.axon.external_ip}") - bt.logging.debug(f"Axon config - external_port: {self.config.axon.external_port}") - bt.logging.debug(f"Axon config - max_workers: {self.config.axon.max_workers}") - - self.axon = bt.axon( - wallet=self.wallet, - config=self.config, - port=self.config.axon.port, - ip=self.config.axon.ip, - external_ip=self.config.axon.external_ip, - external_port=self.config.axon.external_port, - max_workers=self.config.axon.max_workers, - ) + self.axon = bt.axon(wallet=self.wallet, config=self.config, port=self.config.axon.port) + # Connect the validator to the network. if self.wallet.hotkey.ss58_address not in self.metagraph.hotkeys: bt.logging.error( From ce6e937dec3eb0a5d2dd2bf2b79ac23c98ceab41 Mon Sep 17 00:00:00 2001 From: Peter Carlson Date: Mon, 13 Jan 2025 14:56:10 -0500 Subject: [PATCH 05/14] fix reward error --- precog/validators/weight_setter.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/precog/validators/weight_setter.py b/precog/validators/weight_setter.py index bbea858..0eff51e 100755 --- a/precog/validators/weight_setter.py +++ b/precog/validators/weight_setter.py @@ -176,16 +176,16 @@ async def scheduled_prediction_request(self): responses, self.timestamp = self.query_miners() try: rewards = calc_rewards(self, responses=responses) + # Adjust the scores based on responses from miners and update moving average. + for i, value in zip(self.available_uids, rewards): + self.moving_average_scores[i] = ( + 1 - self.config.neuron.moving_average_alpha + ) * self.moving_average_scores[i] + self.config.neuron.moving_average_alpha * value + self.scores = list(self.moving_average_scores.values()) + if not self.config.wandb.off: + log_wandb(responses, rewards, self.available_uids) except Exception as e: bt.logging.error(f"Failed to calculate rewards with error: {e}") - # Adjust the scores based on responses from miners and update moving average. - for i, value in zip(self.available_uids, rewards): - self.moving_average_scores[i] = ( - 1 - self.config.neuron.moving_average_alpha - ) * self.moving_average_scores[i] + self.config.neuron.moving_average_alpha * value - self.scores = list(self.moving_average_scores.values()) - if not self.config.wandb.off: - log_wandb(responses, rewards, self.available_uids) else: print_info(self) From 57e0f751f629bb48a67520c8cf9d4fc6a0623b5f Mon Sep 17 00:00:00 2001 From: Peter Carlson Date: Mon, 13 Jan 2025 15:09:25 -0500 Subject: [PATCH 06/14] more logging --- precog/validators/weight_setter.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/precog/validators/weight_setter.py b/precog/validators/weight_setter.py index 0eff51e..61a61d4 100755 --- a/precog/validators/weight_setter.py +++ b/precog/validators/weight_setter.py @@ -175,7 +175,13 @@ async def scheduled_prediction_request(self): if is_query_time(self.prediction_interval, self.timestamp) or query_lag >= 60 * self.prediction_interval: responses, self.timestamp = self.query_miners() try: + bt.logging.debug(f"Processing responses for UIDs: {self.available_uids}") + bt.logging.debug(f"Number of responses: {len(responses)}") + for uid, response in zip(self.available_uids, responses): + bt.logging.debug(f"Response from UID {uid}: {response}") + rewards = calc_rewards(self, responses=responses) + # Adjust the scores based on responses from miners and update moving average. for i, value in zip(self.available_uids, rewards): self.moving_average_scores[i] = ( @@ -185,7 +191,16 @@ async def scheduled_prediction_request(self): if not self.config.wandb.off: log_wandb(responses, rewards, self.available_uids) except Exception as e: - bt.logging.error(f"Failed to calculate rewards with error: {e}") + import traceback + bt.logging.error(f"Failed to calculate rewards with error: {str(e)}") + bt.logging.error(f"Error type: {type(e)}") + bt.logging.error("Full traceback:") + bt.logging.error(traceback.format_exc()) + bt.logging.error(f"Available UIDs: {self.available_uids}") + bt.logging.error(f"Response count: {len(responses)}") + for uid, response in zip(self.available_uids, responses): + bt.logging.error(f"UID {uid} response status: {getattr(response, 'status_code', 'unknown')}") + bt.logging.error(f"UID {uid} response type: {type(response)}") else: print_info(self) From 19028f06256aa5fd731bd51bf0519c48d6658a61 Mon Sep 17 00:00:00 2001 From: Peter Carlson Date: Mon, 13 Jan 2025 15:21:08 -0500 Subject: [PATCH 07/14] more logging --- precog/validators/weight_setter.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/precog/validators/weight_setter.py b/precog/validators/weight_setter.py index 61a61d4..4de6247 100755 --- a/precog/validators/weight_setter.py +++ b/precog/validators/weight_setter.py @@ -198,6 +198,8 @@ async def scheduled_prediction_request(self): bt.logging.error(traceback.format_exc()) bt.logging.error(f"Available UIDs: {self.available_uids}") bt.logging.error(f"Response count: {len(responses)}") + bt.logging.error(f"MinerHistory keys: {list(self.MinerHistory.keys())}") + bt.logging.error(f"Full MinerHistory: {self.MinerHistory}") for uid, response in zip(self.available_uids, responses): bt.logging.error(f"UID {uid} response status: {getattr(response, 'status_code', 'unknown')}") bt.logging.error(f"UID {uid} response type: {type(response)}") From 20fec69bf5cb7ef7bd3e717e0a97957509fc1e84 Mon Sep 17 00:00:00 2001 From: Peter Carlson Date: Mon, 13 Jan 2025 16:07:07 -0500 Subject: [PATCH 08/14] update resync_metagraph --- precog/validators/weight_setter.py | 53 +++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/precog/validators/weight_setter.py b/precog/validators/weight_setter.py index 4de6247..733006d 100755 --- a/precog/validators/weight_setter.py +++ b/precog/validators/weight_setter.py @@ -89,26 +89,69 @@ async def get_available_uids(self): return miner_uids async def resync_metagraph(self): - """Resyncs the metagraph and updates the hotkeys and moving averages based on the new metagraph.""" + """Resyncs the metagraph and updates the hotkeys, available UIDs, and MinerHistory. + Ensures all data structures remain in sync.""" + # Resync subtensor and metagraph self.subtensor = bt.subtensor(config=self.config, network=self.config.subtensor.chain_endpoint) bt.logging.info("Syncing Metagraph...") self.metagraph.sync(subtensor=self.subtensor) bt.logging.info("Metagraph updated, re-syncing hotkeys, dendrite pool and moving averages") - # Zero out all hotkeys that have been replaced. + + # Get current state for logging + old_uids = set(self.available_uids) + old_history = set(self.MinerHistory.keys()) + bt.logging.debug(f"Before sync - Available UIDs: {old_uids}") + bt.logging.debug(f"Before sync - MinerHistory keys: {old_history}") + + # Update available UIDs self.available_uids = asyncio.run(self.get_available_uids()) + new_uids = set(self.available_uids) + + # Process hotkey changes for uid, hotkey in enumerate(self.metagraph.hotkeys): new_miner = uid not in self.hotkeys - # replaced_miner will throw a key error if the uid is not in the hotkeys dict if not new_miner: replaced_miner = self.hotkeys[uid] != hotkey else: replaced_miner = False + if new_miner or replaced_miner: bt.logging.info(f"Replacing hotkey on {uid} with {self.metagraph.hotkeys[uid]}") - self.hotkeys = {uid: value for uid, value in enumerate(self.metagraph.hotkeys)} + self.moving_average_scores[uid] = 0 + if uid in new_uids: # Only create history for available UIDs + self.MinerHistory[uid] = MinerHistory(uid, timezone=self.timezone) + + # Update hotkeys dictionary + self.hotkeys = {uid: value for uid, value in enumerate(self.metagraph.hotkeys)} + + # Ensure all available UIDs have MinerHistory entries + for uid in self.available_uids: + if uid not in self.MinerHistory: + bt.logging.info(f"Creating new MinerHistory for available UID {uid}") self.MinerHistory[uid] = MinerHistory(uid, timezone=self.timezone) self.moving_average_scores[uid] = 0 - self.scores = list(self.moving_average_scores.values()) + + # Clean up old MinerHistory entries + for uid in list(self.MinerHistory.keys()): + if uid not in new_uids: + bt.logging.info(f"Removing MinerHistory for inactive UID {uid}") + del self.MinerHistory[uid] + + # Update scores list + self.scores = list(self.moving_average_scores.values()) + + # Log changes + added_uids = new_uids - old_uids + removed_uids = old_uids - new_uids + if added_uids: + bt.logging.info(f"Added UIDs: {added_uids}") + if removed_uids: + bt.logging.info(f"Removed UIDs: {removed_uids}") + + bt.logging.debug(f"After sync - Available UIDs: {new_uids}") + bt.logging.debug(f"After sync - MinerHistory keys: {set(self.MinerHistory.keys())}") + + # Save updated state self.save_state() def query_miners(self): From 132048595c6d9cea746a90fadc873edf10105ce7 Mon Sep 17 00:00:00 2001 From: Peter Carlson Date: Tue, 14 Jan 2025 09:26:05 -0500 Subject: [PATCH 09/14] update mainnet uid --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f36e0e3..802eb95 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ ifeq ($(NETWORK),localnet) else ifeq ($(NETWORK),testnet) netuid = 256 else ifeq ($(NETWORK),finney) - #netuid = 64 + netuid = 55 $(error Finney network not supported yet) endif From b04501129769299b7edc3d723c6d21dada6ec8cf Mon Sep 17 00:00:00 2001 From: Peter Carlson Date: Tue, 14 Jan 2025 11:39:18 -0500 Subject: [PATCH 10/14] update testnet and mainnet UID --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index b515305..4205a63 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,15 @@ # **CoinMetrics Precog Subnet** +
+ +| **Testnet UID:** 256
**Mainnet UID:** 55 | +| - | + +
+ +
+ | | | | :-: | :-: | | **Status** |

| From c83b295143106c472d56aba1e5f651e232b6d41e Mon Sep 17 00:00:00 2001 From: Peter Carlson Date: Tue, 14 Jan 2025 11:41:08 -0500 Subject: [PATCH 11/14] remove mention of wandb in readme --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index 4205a63..e9e2e80 100644 --- a/README.md +++ b/README.md @@ -160,9 +160,6 @@ FORWARD_FUNCTION=base_miner LOGGING_LEVEL=debug ``` -### Wandb -Wandb integration is planned for mainnet launch and does not currently work. - --- ## Deployment From 58833ce70e540c795cc075b018e3044226fdc181 Mon Sep 17 00:00:00 2001 From: Peter Carlson Date: Tue, 14 Jan 2025 11:46:31 -0500 Subject: [PATCH 12/14] update version --- docs/Release Notes.md | 5 +++++ pyproject.toml | 2 +- tests/test_package.py | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/Release Notes.md b/docs/Release Notes.md index ee8f021..43408dd 100644 --- a/docs/Release Notes.md +++ b/docs/Release Notes.md @@ -1,6 +1,11 @@ Release Notes ============= +1.0.0 +----- +Released on January 14th 2025 +- Release to mainnet + 0.3.0 ----- Released on January 7th 2025 diff --git a/pyproject.toml b/pyproject.toml index 4d70659..79819cd 100755 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "precog" -version = "0.3.0" +version = "1.0.0" description = "Bitcoin Price Prediction Subnet" authors = ["Coin Metrics", "Yuma Group"] readme = "README.md" diff --git a/tests/test_package.py b/tests/test_package.py index d94327e..89b0eb0 100644 --- a/tests/test_package.py +++ b/tests/test_package.py @@ -16,4 +16,4 @@ def setUp(self): def test_package_version(self): # Check that version is as expected # Must update to increment package version successfully - self.assertEqual(__version__, "0.3.0") + self.assertEqual(__version__, "1.0.0") From 67d066a28bc3ce4ac0755d7ce602fdac3ec1a7d5 Mon Sep 17 00:00:00 2001 From: Peter Carlson Date: Tue, 14 Jan 2025 12:07:44 -0500 Subject: [PATCH 13/14] precommit hooks pass --- README.md | 4 ++-- precog/utils/bittensor.py | 2 +- precog/validators/weight_setter.py | 17 +++++------------ 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index e9e2e80..c2c384c 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,7 @@ Copy the example `.env` files and edit all desired values. If you are running a ``` cp .env.validator.example .env.validator ``` -Edit `.env.validator` with your desired values. +Edit `.env.validator` with your desired values. ``` # Network Configuration @@ -146,7 +146,7 @@ MINER_HOTKEY=your_miner_hotkey # Node Configuration MINER_NAME=miner # This port must be open to accept incoming TCP connections. -MINER_PORT=8092 +MINER_PORT=8092 # Miner Settings TIMEOUT=16 diff --git a/precog/utils/bittensor.py b/precog/utils/bittensor.py index 11d9caf..b283c0f 100644 --- a/precog/utils/bittensor.py +++ b/precog/utils/bittensor.py @@ -32,7 +32,7 @@ def setup_bittensor_objects(self): self.wallet = bt.wallet(config=self.config) self.dendrite = bt.dendrite(wallet=self.wallet) self.axon = bt.axon(wallet=self.wallet, config=self.config, port=self.config.axon.port) - + # Connect the validator to the network. if self.wallet.hotkey.ss58_address not in self.metagraph.hotkeys: bt.logging.error( diff --git a/precog/validators/weight_setter.py b/precog/validators/weight_setter.py index 4eee0e4..38f10d2 100755 --- a/precog/validators/weight_setter.py +++ b/precog/validators/weight_setter.py @@ -114,7 +114,7 @@ async def resync_metagraph(self): replaced_miner = self.hotkeys[uid] != hotkey else: replaced_miner = False - + if new_miner or replaced_miner: bt.logging.info(f"Replacing hotkey on {uid} with {self.metagraph.hotkeys[uid]}") self.moving_average_scores[uid] = 0 @@ -123,7 +123,7 @@ async def resync_metagraph(self): # Update hotkeys dictionary self.hotkeys = {uid: value for uid, value in enumerate(self.metagraph.hotkeys)} - + # Ensure all available UIDs have MinerHistory entries for uid in self.available_uids: if uid not in self.MinerHistory: @@ -140,17 +140,9 @@ async def resync_metagraph(self): # Update scores list self.scores = list(self.moving_average_scores.values()) - # Log changes - added_uids = new_uids - old_uids - removed_uids = old_uids - new_uids - if added_uids: - bt.logging.info(f"Added UIDs: {added_uids}") - if removed_uids: - bt.logging.info(f"Removed UIDs: {removed_uids}") - bt.logging.debug(f"After sync - Available UIDs: {new_uids}") bt.logging.debug(f"After sync - MinerHistory keys: {set(self.MinerHistory.keys())}") - + # Save updated state self.save_state() @@ -229,7 +221,7 @@ async def scheduled_prediction_request(self): bt.logging.debug(f"Number of responses: {len(responses)}") for uid, response in zip(self.available_uids, responses): bt.logging.debug(f"Response from UID {uid}: {response}") - + rewards = calc_rewards(self, responses=responses) # Adjust the scores based on responses from miners and update moving average. @@ -242,6 +234,7 @@ async def scheduled_prediction_request(self): log_wandb(responses, rewards, self.available_uids) except Exception as e: import traceback + bt.logging.error(f"Failed to calculate rewards with error: {str(e)}") bt.logging.error(f"Error type: {type(e)}") bt.logging.error("Full traceback:") From 95355fe2e38f164030608687a97ded2f6e371eac Mon Sep 17 00:00:00 2001 From: Peter Carlson Date: Tue, 14 Jan 2025 12:57:51 -0500 Subject: [PATCH 14/14] update new_miner check in weight_setter.py --- precog/validators/weight_setter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/precog/validators/weight_setter.py b/precog/validators/weight_setter.py index 38f10d2..c8cc71c 100755 --- a/precog/validators/weight_setter.py +++ b/precog/validators/weight_setter.py @@ -109,7 +109,7 @@ async def resync_metagraph(self): # Process hotkey changes for uid, hotkey in enumerate(self.metagraph.hotkeys): - new_miner = uid not in self.hotkeys + new_miner = uid in new_uids and uid not in old_uids if not new_miner: replaced_miner = self.hotkeys[uid] != hotkey else: