diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index c1edfc9e..903efcb1 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -6,10 +6,10 @@ // Built from https://github.com/inference-labs-inc/tensor-tools/blob/main/bittensor-devcontainer/Dockerfile "image": "ghcr.io/inference-labs-inc/bittensor-devcontainer:latest", // "build": { - // // Path is relative to the devcontainer.json file. - // "context": "..", - // "dockerfile": "Dockerfile" - // }, + // // Path is relative to the devcontainer.json file. + // "context": "..", + // "dockerfile": "Dockerfile" + // }, // "runArgs": ["--platform=linux/amd64"], // Features to add to the dev container. More info: https://containers.dev/features. @@ -24,17 +24,25 @@ // "forwardPorts": [], // Use 'postCreateCommand' to run commands after the container is created. - // "postCreateCommand": "uname -a", + // "postCreateCommand": [ + // "uv sync --locked", + // "source .venv/bin/activate.fish" + // ], // Configure tool-specific properties. "customizations": { "vscode": { "settings": { - "python.defaultInterpreterPath": "/home/vscode/.venv/bin/python" - } + "terminal.integrated.defaultProfile.linux": "fish" + // "python.defaultInterpreterPath": "/home/vscode/.venv/bin/python" + }, + "extensions": [ + "ms-python.black-formatter", + "ms-python.python" + ] } - }, + } // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. - "remoteUser": "root" + // "remoteUser": "root" } diff --git a/.isort.cfg b/.isort.cfg index ddd7e429..f61d09b1 100644 --- a/.isort.cfg +++ b/.isort.cfg @@ -10,4 +10,4 @@ ensure_newline_before_comments=True line_length=88 split_on_trailing_comma=True known_third_party=fastapi,bittensor -known_first_party=_validator,_miner,constants,utils,execution_layer,deployment_layer,miner,validator,protocol,models,constants +known_first_party=_validator,_miner,constants,utils,execution_layer,deployment_layer,miner,validator,protocol,models,constants,cli_parser diff --git a/contributing.md b/contributing.md index a8f1e37c..f5c183bf 100644 --- a/contributing.md +++ b/contributing.md @@ -49,7 +49,7 @@ Running miner locally for development: ```sh python miner.py \ --netuid 1 \ - --subtensor.chain_endpoint ws://127.0.0.1:9946 \ + --subtensor.chain_endpoint ws://127.0.0.1:9944 \ --wallet.name miner \ --wallet.hotkey default \ --subtensor.network local \ @@ -67,7 +67,7 @@ Running validator locally for development: ```sh python validator.py \ --netuid 1 \ - --subtensor.chain_endpoint ws://127.0.0.1:9946 \ + --subtensor.chain_endpoint ws://127.0.0.1:9944 \ --wallet.name validator \ --wallet.hotkey default \ --subtensor.network local \ diff --git a/cspell.json b/cspell.json index 045214d9..91240ee0 100644 --- a/cspell.json +++ b/cspell.json @@ -8,10 +8,12 @@ "bittensor", "blocktime", "btcli", + "btlogging", "CIRCOM", "circuitized", "coldkey", "dtype", + "ezkl", "fastapi", "Gbps", "hexsha", @@ -19,6 +21,7 @@ "Keypair", "libudev", "localnet", + "logrows", "Mbps", "metagraph", "netuid", diff --git a/docs/running_on_staging.md b/docs/running_on_staging.md index 2990351c..a679f871 100644 --- a/docs/running_on_staging.md +++ b/docs/running_on_staging.md @@ -106,10 +106,10 @@ Run the following command to mint yourself tokens on your chain. ```bash # Mint tokens for the owner -btcli wallet faucet --wallet.name owner --subtensor.chain_endpoint ws://127.0.0.1:9946 +btcli wallet faucet --wallet.name owner --subtensor.chain_endpoint ws://127.0.0.1:9944 >> Balance: τ0.000000000 ➡ τ100.000000000 # Mint tokens to your validator. -btcli wallet faucet --wallet.name validator --subtensor.chain_endpoint ws://127.0.0.1:9946 +btcli wallet faucet --wallet.name validator --subtensor.chain_endpoint ws://127.0.0.1:9944 >> Balance: τ0.000000000 ➡ τ100.000000000 ``` @@ -118,7 +118,7 @@ btcli wallet faucet --wallet.name validator --subtensor.chain_endpoint ws://127. The commands below establish a new subnetwork on the local chain. The cost will be exactly τ100.000000000 for the first network you create. ```bash -btcli subnet create --wallet.name owner --subtensor.chain_endpoint ws://127.0.0.1:9946 +btcli subnet create --wallet.name owner --subtensor.chain_endpoint ws://127.0.0.1:9944 >> Your balance is: τ200.000000000 >> Do you want to register a subnet for τ100.000000000? [y/n]: >> Enter password to unlock key: [YOUR_PASSWORD] @@ -133,7 +133,7 @@ Enroll your validator and miner on the network. This gives your two keys unique ```bash # Register the miner -btcli subnet register --wallet.name miner --wallet.hotkey default --subtensor.chain_endpoint ws://127.0.0.1:9946 +btcli subnet register --wallet.name miner --wallet.hotkey default --subtensor.chain_endpoint ws://127.0.0.1:9944 >> Enter netuid [1] (1): 1 >> Continue Registration? [y/n]: y >> ⠦ 📡 Submitting POW... @@ -141,7 +141,7 @@ btcli subnet register --wallet.name miner --wallet.hotkey default --subtensor.ch # Register the validator -btcli subnet register --wallet.name validator --wallet.hotkey default --subtensor.chain_endpoint ws://127.0.0.1:9946 +btcli subnet register --wallet.name validator --wallet.hotkey default --subtensor.chain_endpoint ws://127.0.0.1:9944 >> Enter netuid [1] (1): 1 >> Continue Registration? [y/n]: y >> ⠦ 📡 Submitting POW... @@ -153,7 +153,7 @@ btcli subnet register --wallet.name validator --wallet.hotkey default --subtenso This bootstraps the incentives on your new subnet by adding stake into its incentive mechanism. ```bash -btcli stake add --wallet.name validator --wallet.hotkey default --subtensor.chain_endpoint ws://127.0.0.1:9946 +btcli stake add --wallet.name validator --wallet.hotkey default --subtensor.chain_endpoint ws://127.0.0.1:9944 >> Stake all Tao from account: 'validator'? [y/n]: y >> Stake: τ0.000000000 ➡ τ100.000000000 @@ -164,20 +164,20 @@ btcli stake add --wallet.name validator --wallet.hotkey default --subtensor.chai Ensure both the miner and validator keys are successfully registered. ```bash -btcli subnet list --subtensor.chain_endpoint ws://127.0.0.1:9946 +btcli subnet list --subtensor.chain_endpoint ws://127.0.0.1:9944 Subnets - finney NETUID NEURONS MAX_N DIFFICULTY TEMPO CON_REQ EMISSION BURN(τ) 1 2 256.00 10.00 M 1000 None 0.00% τ1.00000 2 128 -btcli wallet overview --wallet.name validator --subtensor.chain_endpoint ws://127.0.0.1:9946 +btcli wallet overview --wallet.name validator --subtensor.chain_endpoint ws://127.0.0.1:9944 Subnet: 1 COLDKEY HOTKEY UID ACTIVE STAKE(τ) RANK TRUST CONSENSUS INCENTIVE DIVIDENDS EMISSION(ρ) VTRUST VPERMIT UPDATED AXON HOTKEY_SS58 miner default 0 True 100.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0 0.00000 14 none 5GTFrsEQfvTsh3WjiEVFeKzFTc2xcf… 1 1 2 τ100.00000 0.00000 0.00000 0.00000 0.00000 0.00000 ρ0 0.00000 Wallet balance: τ0.0 -btcli wallet overview --wallet.name miner --subtensor.chain_endpoint ws://127.0.0.1:9946 +btcli wallet overview --wallet.name miner --subtensor.chain_endpoint ws://127.0.0.1:9944 Subnet: 1 COLDKEY HOTKEY UID ACTIVE STAKE(τ) RANK TRUST CONSENSUS INCENTIVE DIVIDENDS EMISSION(ρ) VTRUST VPERMIT UPDATED AXON HOTKEY_SS58 miner default 1 True 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0 0.00000 14 none 5GTFrsEQfvTsh3WjiEVFeKzFTc2xcf… @@ -191,8 +191,8 @@ miner default 1 True 0.00000 0.00000 0.00000 0.00000 0.00000 Use the following commands to run the miner and validator against the local chain. ```bash -pm2 start neurons/miner.py --interpreter python3 --name miner -- --netuid 1 --subtensor.chain_endpoint ws://127.0.0.1:9946 --wallet.name miner --wallet.hotkey default -pm2 start neurons/validator.py --interpreter python3 --name validator -- --netuid 1 --subtensor.chain_endpoint ws://127.0.0.1:9946 --wallet.name validator --wallet.hotkey default +pm2 start neurons/miner.py --interpreter python3 --name miner -- --netuid 1 --subtensor.chain_endpoint ws://127.0.0.1:9944 --wallet.name miner --wallet.hotkey default +pm2 start neurons/validator.py --interpreter python3 --name validator -- --netuid 1 --subtensor.chain_endpoint ws://127.0.0.1:9944 --wallet.name validator --wallet.hotkey default ``` [View all acceptable CLI arguments →] diff --git a/neurons/_miner/miner_session.py b/neurons/_miner/miner_session.py index cacb7d7b..179f58ff 100644 --- a/neurons/_miner/miner_session.py +++ b/neurons/_miner/miner_session.py @@ -1,38 +1,37 @@ # from __future__ import annotations +import json import time import traceback -import json from typing import Tuple, Union import bittensor as bt +import websocket + +import cli_parser +from _validator.models.request_type import RequestType from constants import ( SINGLE_PROOF_OF_WEIGHTS_MODEL_ID, STEAK, VALIDATOR_REQUEST_TIMEOUT_SECONDS, VALIDATOR_STAKE_THRESHOLD, ) - -from protocol import QueryForProofAggregation, QueryZkProof, ProofOfWeightsSynapse -from utils import wandb_logger -import websocket -from execution_layer.verified_model_session import VerifiedModelSession from deployment_layer.circuit_store import circuit_store -from utils import AutoUpdate, clean_temp_files from execution_layer.generic_input import GenericInput -from _validator.models.request_type import RequestType +from execution_layer.verified_model_session import VerifiedModelSession +from protocol import ProofOfWeightsSynapse, QueryForProofAggregation, QueryZkProof +from utils import AutoUpdate, clean_temp_files, wandb_logger class MinerSession: axon: Union[bt.axon, None] = None - def __init__(self, config): - self.config = config + def __init__(self): self.configure() self.check_register(should_exit=True) self.auto_update = AutoUpdate() self.log_batch = [] - if self.config.disable_blacklist: + if cli_parser.config.disable_blacklist: bt.logging.warning( "Blacklist disabled, allowing all requests. Consider enabling to filter requests." ) @@ -42,10 +41,10 @@ def start_axon(self): bt.logging.info( "Starting axon. Custom arguments include the following.\n" "Note that any null values will fallback to defaults, " - f"which are usually sufficient. {self.config.axon}" + f"which are usually sufficient. {cli_parser.config.axon}" ) - axon = bt.axon(wallet=self.wallet, config=self.config) + axon = bt.axon(wallet=self.wallet, config=cli_parser.config) bt.logging.info(f"Axon created: {axon.info()}") # Attach determines which functions are called when a request is received. @@ -60,11 +59,11 @@ def start_axon(self): # Serve passes the axon information to the network + netuid we are hosting on. # This will auto-update if the axon port of external ip has changed. bt.logging.info( - f"Serving axon on network: {self.subtensor.chain_endpoint} with netuid: {self.config.netuid}" + f"Serving axon on network: {self.subtensor.chain_endpoint} with netuid: {cli_parser.config.netuid}" ) - axon.serve(netuid=self.config.netuid, subtensor=self.subtensor) + axon.serve(netuid=cli_parser.config.netuid, subtensor=self.subtensor) bt.logging.info( - f"Served axon on network: {self.subtensor.chain_endpoint} with netuid: {self.config.netuid}" + f"Served axon on network: {self.subtensor.chain_endpoint} with netuid: {cli_parser.config.netuid}" ) # Start the miner's axon, making it active on the network. @@ -88,7 +87,7 @@ def run(self): step += 1 try: if step % 10 == 0: - if not self.config.no_auto_update: + if not cli_parser.config.no_auto_update: self.auto_update.try_update() else: bt.logging.info( @@ -111,7 +110,9 @@ def run(self): if step % 24 == 0 and self.subnet_uid is not None: try: - self.metagraph = self.subtensor.metagraph(self.config.netuid) + self.metagraph = self.subtensor.metagraph( + cli_parser.config.netuid + ) bt.logging.info( f"Step:{step} | " f"Block:{self.metagraph.block.item()} | " @@ -156,10 +157,10 @@ def check_register(self, should_exit=False): def configure(self): # === Configure Bittensor objects ==== - self.wallet = bt.wallet(config=self.config) - self.subtensor = bt.subtensor(config=self.config) - self.metagraph = self.subtensor.metagraph(self.config.netuid) - wandb_logger.safe_init("Miner", self.wallet, self.metagraph, self.config) + self.wallet = bt.wallet(config=cli_parser.config) + self.subtensor = bt.subtensor(config=cli_parser.config) + self.metagraph = self.subtensor.metagraph(cli_parser.config.netuid) + wandb_logger.safe_init("Miner", self.wallet, self.metagraph, cli_parser.config) def proof_blacklist(self, synapse: QueryZkProof) -> Tuple[bool, str]: """ @@ -197,7 +198,7 @@ def _blacklist( returns: (is_blacklisted, reason) """ try: - if self.config.disable_blacklist: + if cli_parser.config.disable_blacklist: bt.logging.trace("Blacklist disabled, allowing request.") return False, "Allowed" diff --git a/neurons/_validator/core/validator_loop.py b/neurons/_validator/core/validator_loop.py index fdff6568..92f2929c 100644 --- a/neurons/_validator/core/validator_loop.py +++ b/neurons/_validator/core/validator_loop.py @@ -53,7 +53,7 @@ def __init__(self, config: ValidatorConfig): self.config.check_register() self.auto_update = AutoUpdate() self.score_manager = ScoreManager( - self.config.metagraph, self.config.user_uid, self.config.full_path + self.config.metagraph, self.config.user_uid, self.config.full_path_score ) self.response_processor = ResponseProcessor( self.config.metagraph, diff --git a/neurons/_validator/validator_session.py b/neurons/_validator/validator_session.py index 0d87a696..65aab65a 100644 --- a/neurons/_validator/validator_session.py +++ b/neurons/_validator/validator_session.py @@ -1,15 +1,18 @@ from __future__ import annotations +import sys + import bittensor as bt + +import cli_parser from _validator.config import ValidatorConfig from _validator.core.validator_loop import ValidatorLoop from utils import clean_temp_files -import sys class ValidatorSession: - def __init__(self, config: bt.config): - self.config = ValidatorConfig(config) + def __init__(self): + self.config = ValidatorConfig(cli_parser.config) self.validator_loop = ValidatorLoop(self.config) def run(self): diff --git a/neurons/cli_parser.py b/neurons/cli_parser.py new file mode 100644 index 00000000..2dd74b3b --- /dev/null +++ b/neurons/cli_parser.py @@ -0,0 +1,260 @@ +import argparse +import os +from typing import Optional + +import bittensor as bt + +from constants import ONCHAIN_PROOF_OF_WEIGHTS_ENABLED, PROOF_OF_WEIGHTS_INTERVAL, Roles + +parser: Optional[argparse.ArgumentParser] +config: Optional[bt.config] + + +def init_config(role: Optional[str]): + """ + Initialize the configuration for the node. + Config is based on CLI arguments, some of which are common to both miner and validator, + and some of which are specific to each. + The configuration itself is stored in the global variable `config`. Kinda singleton pattern. + """ + from utils import wandb_logger + + global parser + global config + + parser = argparse.ArgumentParser() + + # init common CLI arguments for both miner and validator: + parser.add_argument("--netuid", type=int, default=1, help="The UID of the subnet.") + parser.add_argument( + "--no-auto-update", + default=bool(os.getenv("OMRON_NO_AUTO_UPDATE", False)), + help="Whether this miner should NOT automatically update upon new release.", + action="store_true", + ) + parser.add_argument( + "--wandb-key", type=str, default="", help="A https://wandb.ai API key" + ) + parser.add_argument( + "--disable-wandb", + default=False, + help="Whether to disable WandB logging.", + action="store_true", + ) + parser.add_argument( + "--dev", + default=False, + help="Whether to run in development mode for internal testing.", + action="store_true", + ) + parser.add_argument( + "--localnet", + action="store_true", + default=False, + help="Whether to run the miner in localnet mode.", + ) + parser.add_argument( + "--external-model-dir", + default=None, + help="Custom location for storing models data (optional)", + ) + + if role == Roles.VALIDATOR: + # CLI arguments specific to the validator + _validator_config() + elif role == Roles.MINER: + # CLI arguments specific to the miner + _miner_config() + else: + bt.subtensor.add_args(parser) + bt.logging.add_args(parser) + bt.wallet.add_args(parser) + config = bt.config(parser) + + if config.localnet: + # quick localnet configuration set up for testing (common params for both miner and validator) + if ( + config.subtensor.chain_endpoint + == "wss://entrypoint-finney.opentensor.ai:443" + ): + # in case of default value, change to localnet + config.subtensor.chain_endpoint = "ws://127.0.0.1:9944" + if config.subtensor.network == "finney": + config.subtensor.network = "local" + config.eth_wallet = ( + config.eth_wallet if config.eth_wallet is not None else "0x002" + ) + config.timeout = config.timeout if config.timeout is None else 120 + config.disable_wandb = True + config.verbose = config.verbose if config.verbose is None else True + config.max_workers = config.max_workers or 1 + + config.full_path = os.path.expanduser("~/.bittensor/omron") # type: ignore + config.full_path_score = os.path.join(config.full_path, "scores") + if not config.certificate_path: + config.certificate_path = os.path.join(config.full_path, "cert") + + if config.external_model_dir: + # user might have specified a custom location for storing models data + # if not, we use the default location + config.full_path_models = config.external_model_dir + else: + config.full_path_models = os.path.join(config.full_path, "models") + + os.makedirs(config.full_path, exist_ok=True) + os.makedirs(config.full_path_score, exist_ok=True) + os.makedirs(config.full_path_models, exist_ok=True) + os.makedirs(config.certificate_path, exist_ok=True) + + bt.logging(config=config, logging_dir=config.logging.logging_dir) + bt.logging.enable_info() + + if config.wandb_key: + wandb_logger.safe_login(api_key=config.wandb_key) + bt.logging.success("Logged into WandB") + +def _miner_config(): + """ + Add CLI arguments specific to the miner. + """ + global parser + global config + + parser.add_argument( + "--disable-blacklist", + default=False, + action="store_true", + help="Disables request filtering and allows all incoming requests.", + ) + + bt.subtensor.add_args(parser) + bt.logging.add_args(parser) + bt.wallet.add_args(parser) + bt.axon.add_args(parser) + + config = bt.config(parser) + + if config.localnet: + # quick localnet configuration set up for testing (specific params for miner) + if config.wallet.name == "default": + config.wallet.name = "miner" + if not config.axon: + config.axon = bt.config() + config.axon.ip = "127.0.0.1" + config.axon.external_ip = "127.0.0.1" + config.disable_blacklist = ( + config.disable_blacklist if config.disable_blacklist is not None else True + ) + + +def _validator_config(): + """ + Add CLI arguments specific to the validator. + """ + global parser + global config + + parser.add_argument( + "--blocks_per_epoch", + type=int, + default=100, + help="Number of blocks to wait before setting weights", + ) + + parser.add_argument( + "--disable-statistic-logging", + default=False, + help="Whether to disable statistic logging.", + action="store_true", + ) + + parser.add_argument( + "--enable-pow", + default=ONCHAIN_PROOF_OF_WEIGHTS_ENABLED, + action="store_true", + help="Whether proof of weights is enabled", + ) + + parser.add_argument( + "--pow-target-interval", + type=int, + default=PROOF_OF_WEIGHTS_INTERVAL, + help="The target interval for committing proof of weights to the chain", + ) + + parser.add_argument( + "--ignore-external-requests", + type=lambda x: x.lower() == "true", + default=True, + help="Whether to ignore external requests.", + ) + + parser.add_argument( + "--external-api-host", + type=str, + default="0.0.0.0", + help="The host for the external API.", + ) + + parser.add_argument( + "--external-api-port", + type=int, + default=8000, + help="The port for the external API.", + ) + + parser.add_argument( + "--external-api-workers", + type=int, + default=1, + help="The number of workers for the external API.", + ) + + parser.add_argument( + "--do-not-verify-external-signatures", + default=False, + action="store_true", + help=( + "External PoW requests are signed by validator's (sender's) wallet. " + "By default we verify is the wallet legitimate. " + "You can disable this check with the flag." + ), + ) + + parser.add_argument( + "--certificate-path", + type=str, + default=None, + help="A custom path to a directory containing a public and private SSL certificate. " + "(cert.pem and key.pem) " + "Please note that this should not be used unless you have issued your own certificate. " + "Omron will issue a certificate for you by default.", + ) + + parser.add_argument( + "--prometheus-monitoring", + action="store_true", + default=False, + help="Whether to enable prometheus monitoring.", + ) + + parser.add_argument( + "--prometheus-port", + type=int, + default=9090, + help="The port for the prometheus monitoring.", + ) + + bt.subtensor.add_args(parser) + bt.logging.add_args(parser) + bt.wallet.add_args(parser) + + config = bt.config(parser) + + if config.localnet: + # quick localnet configuration set up for testing (specific params for validator) + if config.wallet.name == "default": + config.wallet.name = "validator" + config.external_api_workers = config.external_api_workers or 1 + config.external_api_port = config.external_api_port or 8000 + config.do_not_verify_external_signatures = True diff --git a/neurons/constants.py b/neurons/constants.py index 31440322..c879ee9b 100644 --- a/neurons/constants.py +++ b/neurons/constants.py @@ -1,3 +1,12 @@ +from dataclasses import dataclass + + +@dataclass +class Roles: + VALIDATOR = "validator" + MINER = "miner" + + # The model ID for a batched proof of weights model BATCHED_PROOF_OF_WEIGHTS_MODEL_ID = ( "e84b2e5f223621fa20078eb9f920d8d4d3a4ff95fa6e2357646fdbb43a2557c9" diff --git a/neurons/deployment_layer/circuit_store.py b/neurons/deployment_layer/circuit_store.py index d1a13143..34e9f64d 100644 --- a/neurons/deployment_layer/circuit_store.py +++ b/neurons/deployment_layer/circuit_store.py @@ -1,11 +1,16 @@ from __future__ import annotations + import os import traceback +from typing import Optional + import bittensor as bt -from execution_layer.circuit import Circuit -from constants import IGNORED_MODEL_HASHES from packaging import version +import cli_parser +from constants import IGNORED_MODEL_HASHES +from execution_layer.circuit import Circuit + class CircuitStore: """ @@ -31,12 +36,8 @@ def __init__(self): Creates an empty dictionary to store Circuit objects and loads circuits. """ self.circuits: dict[str, Circuit] = {} - # load circuits from the deployment layer path - # these circuits come precompiled with the docker image - deployment_layer_path = os.path.dirname(__file__) - self.load_circuits(deployment_layer_path) - def load_circuits(self, deployment_layer_path): + def load_circuits(self, deployment_layer_path: Optional[str] = None): """ Load circuits from the file system. @@ -44,6 +45,9 @@ def load_circuits(self, deployment_layer_path): attempts to create Circuit objects from these directories, and stores them in the circuits dictionary. """ + deployment_layer_path = ( + deployment_layer_path or cli_parser.config.full_path_models + ) bt.logging.info(f"Loading circuits from {deployment_layer_path}") for folder_name in os.listdir(deployment_layer_path): diff --git a/neurons/dry_run.py b/neurons/dry_run.py new file mode 100644 index 00000000..0453f338 --- /dev/null +++ b/neurons/dry_run.py @@ -0,0 +1,23 @@ +""" +Entry point for running just preflight checks: + - Check CLI args (in fact completely unnecessary here) + - Model files are synced up + - Node.js >= 20 is installed + - SnarkJS is installed + - Rust and Cargo are installed + - Rust nightly toolchain is installed + - Jolt is installed + +This script is created to be called during the Docker image build process +to ensure that all dependencies are installed. +""" + +import bittensor as bt + +from utils import run_shared_preflight_checks + +if __name__ == "__main__": + # Run preflight checks, and that's it + run_shared_preflight_checks() + + bt.logging.info("Preflight checks completed. Exiting...") diff --git a/neurons/execution_layer/circuit.py b/neurons/execution_layer/circuit.py index 7d3f829c..70b1d2e8 100644 --- a/neurons/execution_layer/circuit.py +++ b/neurons/execution_layer/circuit.py @@ -3,6 +3,7 @@ from enum import Enum import os import json +import cli_parser from execution_layer.input_registry import InputRegistry # trunk-ignore(pylint/E0611) @@ -73,7 +74,7 @@ def __post_init__(self): f"model_{self.model_id}", ) self.external_base_path = os.path.join( - os.getenv("OMRON_EXTERNAL_MODEL_DIR", os.path.dirname(self.base_path)), + cli_parser.config.full_path_models, f"model_{self.model_id}", ) self.input = os.path.join(self.base_path, "input.json") diff --git a/neurons/miner.py b/neurons/miner.py index 2220ec7f..c3552c63 100644 --- a/neurons/miner.py +++ b/neurons/miner.py @@ -1,139 +1,22 @@ -import argparse -import os -import sys import traceback import bittensor as bt -import utils.wandb_logger as wandb_logger + from _miner.miner_session import MinerSession +from constants import Roles from utils import run_shared_preflight_checks - -def get_config_from_args(): - """ - Creates the configuration from CLI args. - """ - parser = argparse.ArgumentParser() - - parser.add_argument( - "--netuid", type=int, default=1, help="The UID for the Omron subnet." - ) - parser.add_argument( - "--no-auto-update", - default=bool(os.getenv("OMRON_NO_AUTO_UPDATE", False)), - help="Whether this miner should NOT automatically update upon new release.", - action="store_true", - ) - parser.add_argument( - "--disable-blacklist", - default=False, - action="store_true", - help="Disables request filtering and allows all incoming requests.", - ) - parser.add_argument( - "--wandb-key", type=str, default="", help="A https://wandb.ai API key" - ) - parser.add_argument( - "--disable-wandb", - default=False, - help="Whether to disable WandB logging.", - action="store_true", - ) - parser.add_argument( - "--dev", - default=False, - help="Whether to run the miner in development mode for internal testing.", - action="store_true", - ) - parser.add_argument( - "--localnet", - action="store_true", - default=False, - help="Whether to run the miner in localnet mode.", - ) - - bt.subtensor.add_args(parser) - bt.logging.add_args(parser) - bt.wallet.add_args(parser) - bt.axon.add_args(parser) - - config = bt.config(parser) - - if config.localnet: - # quick localnet configuration set up for testing - if ( - config.subtensor.chain_endpoint - == "wss://entrypoint-finney.opentensor.ai:443" - ): - # in case of default value, change to localnet - config.subtensor.chain_endpoint = "ws://127.0.0.1:9946" - if config.wallet.name == "default": - config.wallet.name = "miner" - if config.subtensor.network == "finney": - config.subtensor.network = "local" - config.eth_wallet = ( - config.eth_wallet if config.eth_wallet is not None else "0x002" - ) - if not config.axon: - config.axon = bt.config() - config.axon.ip = "127.0.0.1" - config.axon.external_ip = "127.0.0.1" - config.timeout = config.timeout if config.timeout is None else 120 - config.disable_wandb = True - config.verbose = config.verbose if config.verbose is None else True - config.disable_blacklist = ( - config.disable_blacklist if config.disable_blacklist is None else True - ) - config.max_workers = config.max_workers or 1 - - config.full_path = os.path.expanduser( - "{}/{}/{}/netuid{}/{}".format( - config.logging.logging_dir, # type: ignore - config.wallet.name, # type: ignore - config.wallet.hotkey, # type: ignore - config.netuid, - "miner", - ) - ) - - bt.logging(config=config, logging_dir=config.full_path) - bt.logging.enable_info() - - if not os.path.exists(config.full_path): - os.makedirs(config.full_path, exist_ok=True) - - if config.wandb_key: - wandb_logger.safe_login(api_key=config.wandb_key) - bt.logging.success("Logged into WandB") - return config - - if __name__ == "__main__": - bt.logging.info("Getting miner configuration...") - config = get_config_from_args() - - config.external_model_dir = os.path.join( - os.path.dirname(config.full_path), "deployment_layer" - ) - os.environ["OMRON_EXTERNAL_MODEL_DIR"] = config.external_model_dir - os.environ["EZKL_REPO_PATH"] = os.path.join( - os.path.dirname(config.full_path), "ezkl" - ) - - run_shared_preflight_checks(config.external_model_dir) - - if os.getenv("OMRON_DOCKER_BUILD", False): - bt.logging.info("Docker build steps complete. Exiting.") - sys.exit(0) + run_shared_preflight_checks(Roles.MINER) try: # Initialize the circuit store and load external models from deployment_layer.circuit_store import circuit_store - circuit_store.load_circuits(config.external_model_dir) + circuit_store.load_circuits() bt.logging.info("Creating miner session...") - miner_session = MinerSession(config) + miner_session = MinerSession() bt.logging.info("Running main loop...") miner_session.run() except Exception: diff --git a/neurons/utils/auto_update.py b/neurons/utils/auto_update.py index f8ad8901..15e79783 100644 --- a/neurons/utils/auto_update.py +++ b/neurons/utils/auto_update.py @@ -9,6 +9,7 @@ from bittensor import logging from .system import restart_app +import cli_parser TARGET_BRANCH = "main" @@ -20,8 +21,9 @@ class AutoUpdate: def __init__(self): try: - self.repo = git.Repo(search_parent_directories=True) - self.current_requirements_hash = self.get_requirements_hash() + if not cli_parser.config.no_auto_update: + self.repo = git.Repo(search_parent_directories=True) + self.current_requirements_hash = self.get_requirements_hash() except Exception as e: logging.exception("Failed to initialize the repository", e) diff --git a/neurons/utils/pre_flight.py b/neurons/utils/pre_flight.py index e8db2d39..8ac42dbd 100644 --- a/neurons/utils/pre_flight.py +++ b/neurons/utils/pre_flight.py @@ -1,19 +1,22 @@ -import traceback +import asyncio +import json import os +import shutil import subprocess import time -import json -import requests -import ezkl -import asyncio +import traceback +from functools import partial +from typing import Optional # trunk-ignore(pylint/E0611) -from bittensor import logging +import bittensor as bt +import ezkl +import requests +import cli_parser from constants import IGNORED_MODEL_HASHES from execution_layer.circuit import ProofSystem - LOCAL_SNARKJS_INSTALL_DIR = os.path.join(os.path.expanduser("~"), ".snarkjs") LOCAL_SNARKJS_PATH = os.path.join( LOCAL_SNARKJS_INSTALL_DIR, "node_modules", ".bin", "snarkjs" @@ -27,7 +30,7 @@ async def download_srs(logrows): await ezkl.get_srs(logrows=logrows, commitment=ezkl.PyCommitments.KZG) -def run_shared_preflight_checks(external_model_dir: str): +def run_shared_preflight_checks(role: Optional[str] = None): """ This function executes a series of checks to ensure the environment is properly set up for both validator and miner operations. @@ -42,35 +45,35 @@ def run_shared_preflight_checks(external_model_dir: str): Raises: Exception: If any of the pre-flight checks fail. """ - global EXTERNAL_MODEL_DIR - EXTERNAL_MODEL_DIR = external_model_dir preflight_checks = [ + ("Init configs", partial(cli_parser.init_config, role=role)), + ("Resolve legacy folders", partial(resolve_legacy_folders, role=role)), ("Syncing model files", sync_model_files), ("Ensuring Node.js version", ensure_nodejs_version), ("Checking SnarkJS installation", ensure_snarkjs_installed), ("Checking EZKL installation", ensure_ezkl_installed), ] - logging.info(" PreFlight | Running pre-flight checks") + bt.logging.info(" PreFlight | Running pre-flight checks") # Skip sync_model_files during docker build if os.getenv("OMRON_DOCKER_BUILD", False): - logging.info(" PreFlight | Skipping model file sync") + bt.logging.info(" PreFlight | Skipping model file sync") preflight_checks.remove(("Syncing model files", sync_model_files)) for check_name, check_function in preflight_checks: - logging.info(f" PreFlight | {check_name}") + bt.logging.info(f" PreFlight | {check_name}") try: check_function() - logging.success(f" PreFlight | {check_name} completed successfully") + bt.logging.success(f" PreFlight | {check_name} completed successfully") except Exception as e: - logging.error(f"Failed {check_name.lower()}.", e) - logging.debug(f" PreFlight | {check_name} error details: {str(e)}") + bt.logging.error(f"Failed {check_name.lower()}.", e) + bt.logging.debug(f" PreFlight | {check_name} error details: {str(e)}") traceback.print_exc() raise e - logging.info(" PreFlight | Pre-flight checks completed.") + bt.logging.info(" PreFlight | Pre-flight checks completed.") def ensure_ezkl_installed(): @@ -89,12 +92,12 @@ def ensure_ezkl_installed(): check=True, ) if python_ezkl_version in result.stdout: - logging.info( + bt.logging.info( f"EZKL is already installed with correct version: {python_ezkl_version}" ) return else: - logging.warning("EZKL version mismatch, reinstalling...") + bt.logging.warning("EZKL version mismatch, reinstalling...") # trunk-ignore(bandit/B605) subprocess.run( @@ -102,10 +105,10 @@ def ensure_ezkl_installed(): shell=True, check=True, ) - logging.info("EZKL installed successfully") + bt.logging.info("EZKL installed successfully") except subprocess.CalledProcessError as e: - logging.error(f"Failed to install/verify EZKL: {e}") + bt.logging.error(f"Failed to install/verify EZKL: {e}") raise RuntimeError( "EZKL installation failed. Please install it manually." ) from e @@ -124,11 +127,11 @@ def ensure_snarkjs_installed(): capture_output=True, text=True, ) - logging.info( + bt.logging.info( "snarkjs is already installed and available in the local directory." ) except (subprocess.CalledProcessError, FileNotFoundError): - logging.warning( + bt.logging.warning( "snarkjs not found in local directory. Attempting to install..." ) try: @@ -148,11 +151,11 @@ def ensure_snarkjs_installed(): ], check=True, ) - logging.info( + bt.logging.info( "snarkjs has been successfully installed in the local directory." ) except subprocess.CalledProcessError as e: - logging.error(f"Failed to install snarkjs: {e}") + bt.logging.error(f"Failed to install snarkjs: {e}") raise RuntimeError( "snarkjs installation failed. Please install it manually." ) from e @@ -170,7 +173,7 @@ def sync_model_files(): continue if model_hash.split("_")[1] in IGNORED_MODEL_HASHES: - logging.info( + bt.logging.info( SYNC_LOG_PREFIX + f"Ignoring model {model_hash} as it is in the ignored list." ) @@ -178,7 +181,7 @@ def sync_model_files(): metadata_file = os.path.join(MODEL_DIR, model_hash, "metadata.json") if not os.path.isfile(metadata_file): - logging.error( + bt.logging.error( SYNC_LOG_PREFIX + f"Metadata file not found at {metadata_file} for {model_hash}. Skipping sync for this model." ) @@ -188,7 +191,7 @@ def sync_model_files(): with open(metadata_file, "r", encoding="utf-8") as f: metadata = json.load(f) except json.JSONDecodeError: - logging.error( + bt.logging.error( SYNC_LOG_PREFIX + f"Failed to parse JSON from {metadata_file}" ) continue @@ -196,7 +199,7 @@ def sync_model_files(): if metadata.get("proof_system") == ProofSystem.EZKL: ezkl_settings_file = os.path.join(MODEL_DIR, model_hash, "settings.json") if not os.path.isfile(ezkl_settings_file): - logging.error( + bt.logging.error( f"{SYNC_LOG_PREFIX}Settings file not found at {ezkl_settings_file} for {model_hash}. Skipping sync." ) continue @@ -207,34 +210,37 @@ def sync_model_files(): if logrows: loop = asyncio.get_event_loop() loop.run_until_complete(download_srs(logrows)) - logging.info( + bt.logging.info( f"{SYNC_LOG_PREFIX}Successfully downloaded SRS for logrows={logrows}" ) except (json.JSONDecodeError, subprocess.CalledProcessError) as e: - logging.error( + bt.logging.error( f"{SYNC_LOG_PREFIX}Failed to process settings or download SRS: {e}" ) continue external_files = metadata.get("external_files", {}) for key, url in external_files.items(): - file_path = os.path.join(EXTERNAL_MODEL_DIR, model_hash, key) + file_path = os.path.join( + cli_parser.config.full_path_models, model_hash, key + ) os.makedirs(os.path.dirname(file_path), exist_ok=True) if os.path.isfile(file_path): - logging.info( + bt.logging.info( SYNC_LOG_PREFIX + f"File {key} for {model_hash} already downloaded, skipping..." ) continue - logging.info(SYNC_LOG_PREFIX + f"Downloading {url} to {file_path}...") + bt.logging.info(SYNC_LOG_PREFIX + f"Downloading {url} to {file_path}...") try: - response = requests.get(url, timeout=600) - response.raise_for_status() - with open(file_path, "wb") as f: - f.write(response.content) + with requests.get(url, timeout=600, stream=True) as response: + response.raise_for_status() + with open(file_path, "wb") as f: + for chunk in response.iter_content(chunk_size=8192): + f.write(chunk) except requests.RequestException as e: - logging.error( + bt.logging.error( SYNC_LOG_PREFIX + f"Failed to download {url} to {file_path}: {e}" ) continue @@ -252,7 +258,7 @@ def ensure_nodejs_version(): npm_version = subprocess.check_output(["npm", "--version"]).decode().strip() if node_version.startswith("v20."): - logging.info( + bt.logging.info( NODE_LOG_PREFIX + f"Node.js version {node_version} and npm version {npm_version} are installed." ) @@ -260,10 +266,10 @@ def ensure_nodejs_version(): except (subprocess.CalledProcessError, FileNotFoundError): pass - logging.error( + bt.logging.error( NODE_LOG_PREFIX + "Node.js is not installed or is not the correct version." ) - logging.error( + bt.logging.error( NODE_LOG_PREFIX + "\033[91mPlease install Node.js >= 20 using the following command\n./setup.sh --no-install\033[0m" ) @@ -298,9 +304,9 @@ def ensure_rust_cargo_installed(): check=True, capture_output=True, ) - logging.info(f"{RUST_LOG_PREFIX}Rust and Cargo are already installed.") + bt.logging.info(f"{RUST_LOG_PREFIX}Rust and Cargo are already installed.") except (subprocess.CalledProcessError, FileNotFoundError): - logging.info(f"{RUST_LOG_PREFIX}Rust and/or Cargo not found. Installing...") + bt.logging.info(f"{RUST_LOG_PREFIX}Rust and/or Cargo not found. Installing...") try: rustup_script = requests.get("https://sh.rustup.rs").text subprocess.run( @@ -311,7 +317,7 @@ def ensure_rust_cargo_installed(): ) cargo_path = os.path.join(os.path.expanduser("~"), ".cargo", "bin", "cargo") if not os.path.exists(cargo_path): - logging.info( + bt.logging.info( f"{RUST_LOG_PREFIX}Cargo not found. Adding cargo component..." ) try: @@ -327,30 +333,30 @@ def ensure_rust_cargo_installed(): check=True, capture_output=True, ) - logging.info( + bt.logging.info( f"{RUST_LOG_PREFIX}Cargo component added successfully." ) except subprocess.CalledProcessError as e: - logging.error( + bt.logging.error( f"{RUST_LOG_PREFIX}Failed to add cargo component: {e}" ) raise RuntimeError("Failed to add cargo component.") from e - logging.info( + bt.logging.info( f"{RUST_LOG_PREFIX}Rust and Cargo have been successfully installed." ) - logging.info(f"{RUST_LOG_PREFIX}Installation complete.") - logging.info( + bt.logging.info(f"{RUST_LOG_PREFIX}Installation complete.") + bt.logging.info( f"{RUST_LOG_PREFIX}\033[93mIMPORTANT: Ensure you have pkg-config, libssl-dev and openssl installed" "with sudo apt install pkg-config libssl-dev openssl.\033[0m" ) - logging.info( + bt.logging.info( f"{RUST_LOG_PREFIX}\033[93mPausing. To complete install, restart your machine using sudo reboot.\033[0m" ) time.sleep(1e9) except subprocess.CalledProcessError as e: - logging.error(f"{RUST_LOG_PREFIX}Failed to install Rust and Cargo: {e}") + bt.logging.error(f"{RUST_LOG_PREFIX}Failed to install Rust and Cargo: {e}") raise RuntimeError( "Rust and Cargo installation failed. Please install them manually." ) from e @@ -387,7 +393,7 @@ def ensure_rust_nightly_installed(): except subprocess.CalledProcessError: pass - logging.info(f"{RUST_LOG_PREFIX}Installing Rust {TOOLCHAIN}...") + bt.logging.info(f"{RUST_LOG_PREFIX}Installing Rust {TOOLCHAIN}...") try: subprocess.run( [ @@ -398,11 +404,11 @@ def ensure_rust_nightly_installed(): ], check=True, ) - logging.info( + bt.logging.info( f"{RUST_LOG_PREFIX}Rust {TOOLCHAIN} has been successfully installed." ) except subprocess.CalledProcessError as e: - logging.error(f"{RUST_LOG_PREFIX}Failed to install Rust toolchain: {e}") + bt.logging.error(f"{RUST_LOG_PREFIX}Failed to install Rust toolchain: {e}") raise RuntimeError( f"Rust {TOOLCHAIN} installation failed. Please install it manually." ) from e @@ -424,9 +430,9 @@ def ensure_jolt_installed(): check=True, capture_output=True, ) - logging.info(f"{JOLT_LOG_PREFIX}Jolt is already installed.") + bt.logging.info(f"{JOLT_LOG_PREFIX}Jolt is already installed.") except (subprocess.CalledProcessError, FileNotFoundError): - logging.info(f"{JOLT_LOG_PREFIX}Jolt not found. Installing...") + bt.logging.info(f"{JOLT_LOG_PREFIX}Jolt not found. Installing...") try: subprocess.run( [ @@ -443,14 +449,14 @@ def ensure_jolt_installed(): ], check=True, ) - logging.info(f"{JOLT_LOG_PREFIX}Jolt has been successfully installed.") + bt.logging.info(f"{JOLT_LOG_PREFIX}Jolt has been successfully installed.") except subprocess.CalledProcessError as e: - logging.error(f"{JOLT_LOG_PREFIX}Failed to install Jolt: {e}") + bt.logging.error(f"{JOLT_LOG_PREFIX}Failed to install Jolt: {e}") raise RuntimeError( "Jolt installation failed. Please install it manually." ) from e - logging.info(f"{JOLT_LOG_PREFIX}Running jolt install-toolchain...") + bt.logging.info(f"{JOLT_LOG_PREFIX}Running jolt install-toolchain...") try: subprocess.run( [ @@ -459,9 +465,11 @@ def ensure_jolt_installed(): ], check=True, ) - logging.info(f"{JOLT_LOG_PREFIX}jolt install-toolchain completed successfully.") + bt.logging.info( + f"{JOLT_LOG_PREFIX}jolt install-toolchain completed successfully." + ) except subprocess.CalledProcessError as e: - logging.error(f"{JOLT_LOG_PREFIX}Failed to run jolt install-toolchain: {e}") + bt.logging.error(f"{JOLT_LOG_PREFIX}Failed to run jolt install-toolchain: {e}") raise RuntimeError( "jolt install-toolchain failed. Please run it manually." ) from e @@ -479,7 +487,7 @@ def compile_jolt_circuits(): continue if model_hash.split("_")[1] in IGNORED_MODEL_HASHES: - logging.info( + bt.logging.info( JOLT_LOG_PREFIX + f"Ignoring model {model_hash} as it is in the ignored list." ) @@ -487,7 +495,7 @@ def compile_jolt_circuits(): metadata_file = os.path.join(MODEL_DIR, model_hash, "metadata.json") if not os.path.isfile(metadata_file): - logging.warning( + bt.logging.warning( f"{JOLT_LOG_PREFIX}Metadata file not found for {model_hash}. Skipping." ) continue @@ -496,36 +504,40 @@ def compile_jolt_circuits(): with open(metadata_file, "r", encoding="utf-8") as f: metadata = json.load(f) except json.JSONDecodeError: - logging.error(f"{JOLT_LOG_PREFIX}Failed to parse JSON from {metadata_file}") + bt.logging.error( + f"{JOLT_LOG_PREFIX}Failed to parse JSON from {metadata_file}" + ) continue if metadata.get("proof_system") != "JOLT": - logging.info(f"{JOLT_LOG_PREFIX}Skipping non-Jolt circuit: {model_hash}") + bt.logging.info(f"{JOLT_LOG_PREFIX}Skipping non-Jolt circuit: {model_hash}") continue circuit_path = os.path.join( MODEL_DIR, model_hash, "target", "release", "circuit" ) if os.path.exists(circuit_path): - logging.info(f"{JOLT_LOG_PREFIX}Circuit already compiled for {model_hash}") + bt.logging.info( + f"{JOLT_LOG_PREFIX}Circuit already compiled for {model_hash}" + ) continue - logging.info(f"{JOLT_LOG_PREFIX}Compiling circuit for {model_hash}") + bt.logging.info(f"{JOLT_LOG_PREFIX}Compiling circuit for {model_hash}") try: subprocess.run( ["cargo", "build", "--release"], cwd=os.path.join(MODEL_DIR, model_hash), check=True, ) - logging.info( + bt.logging.info( f"{JOLT_LOG_PREFIX}Successfully compiled circuit for {model_hash}" ) except subprocess.CalledProcessError as e: - logging.error( + bt.logging.error( f"{JOLT_LOG_PREFIX}Failed to compile circuit for {model_hash}: {e}" ) - logging.info(f"{JOLT_LOG_PREFIX}Jolt circuit compilation process completed.") + bt.logging.info(f"{JOLT_LOG_PREFIX}Jolt circuit compilation process completed.") def is_safe_path(base_path, path): @@ -538,3 +550,57 @@ def safe_extract(tar, path): if not is_safe_path(path, member_path): continue tar.extract(member, path) + + +def resolve_legacy_folders(role: str): + """ + Move files from legacy folders to the new locations. + This step gonna be removed in the future. + """ + + if not role: + # dry run - no actions needed + return + + if cli_parser.config.external_model_dir: + # user have specified a custom location for storing models data + # that means we don't need to move files from the legacy folders + return + + legacy_full_path = os.path.expanduser( + "{}/{}/{}/netuid{}".format( + cli_parser.config.logging.logging_dir, # type: ignore + cli_parser.config.wallet.name, # type: ignore + cli_parser.config.wallet.hotkey, # type: ignore + cli_parser.config.netuid, + ) + ) + + _move_files( + os.path.join(legacy_full_path, role), + cli_parser.config.full_path_score, + ) + _move_files( + os.path.join(legacy_full_path, "deployment_layer"), + cli_parser.config.full_path_models, + ) + + +def _move_files(src: str, dst: str): + """ + Move files recurcively from source to destination. + """ + if not os.path.exists(src) or not any(os.scandir(src)) or any(os.scandir(dst)): + # if source does not exist or is empty, or destination is not empty -> skip + return + + try: + for item in os.listdir(src): + s = os.path.join(src, item) + d = os.path.join(dst, item) + shutil.move(s, d) + + os.rmdir(src) + bt.logging.info(f"Moved files from {src} to {dst}") + except Exception as e: + bt.logging.error(f"Oops. Failed to move files from {src} to {dst}: {e}") diff --git a/neurons/validator.py b/neurons/validator.py index bd9aad59..32e5741d 100644 --- a/neurons/validator.py +++ b/neurons/validator.py @@ -1,237 +1,22 @@ -import argparse -import os -import sys import traceback import bittensor as bt -from constants import ( - ONCHAIN_PROOF_OF_WEIGHTS_ENABLED, - PROOF_OF_WEIGHTS_INTERVAL, - WHITELISTED_PUBLIC_KEYS, -) -from utils import wandb_logger from _validator.validator_session import ValidatorSession +from constants import Roles from utils import run_shared_preflight_checks - -def get_config_from_args(): - """ - Parses CLI arguments into bt configuration - """ - parser = argparse.ArgumentParser() - - parser.add_argument("--netuid", type=int, default=1, help="The uid of the subnet.") - - parser.add_argument( - "--no-auto-update", - default=bool(os.getenv("OMRON_NO_AUTO_UPDATE", False)), - action="store_true", - help="Disable auto update.", - ) - parser.add_argument( - "--blocks_per_epoch", - type=int, - default=100, - help="Number of blocks to wait before setting weights", - ) - parser.add_argument( - "--wandb-key", type=str, default="", help="A https://wandb.ai API key" - ) - - parser.add_argument( - "--disable-wandb", - default=False, - help="Whether to disable WandB logging.", - action="store_true", - ) - - parser.add_argument( - "--disable-statistic-logging", - default=False, - help="Whether to disable statistic logging.", - action="store_true", - ) - - parser.add_argument( - "--dev", - default=False, - help="Whether to run the miner in development mode for internal testing.", - action="store_true", - ) - - parser.add_argument( - "--enable-pow", - default=ONCHAIN_PROOF_OF_WEIGHTS_ENABLED, - action="store_true", - help="Whether proof of weights is enabled", - ) - - parser.add_argument( - "--pow-target-interval", - type=int, - default=PROOF_OF_WEIGHTS_INTERVAL, - help="The target interval for committing proof of weights to the chain", - ) - - parser.add_argument( - "--ignore-external-requests", - type=lambda x: x.lower() == "true", - default=True, - help="Whether to ignore external requests.", - ) - - parser.add_argument( - "--whitelisted-public-keys", - type=str, - nargs="*", - dest="alist", - default=WHITELISTED_PUBLIC_KEYS, - help="Comma separated list of public keys to whitelist for external requests.", - ) - - parser.add_argument( - "--external-api-host", - type=str, - default="0.0.0.0", - help="The host for the external API.", - ) - - parser.add_argument( - "--external-api-port", - type=int, - default=8443, - help="The port for the external API.", - ) - - parser.add_argument( - "--external-api-workers", - type=int, - default=1, - help="The number of workers for the external API.", - ) - - parser.add_argument( - "--do-not-verify-external-signatures", - default=False, - action="store_true", - help=( - "External PoW requests are signed by validator's (sender's) wallet. " - "By default we verify is the wallet legitimate. " - "You can disable this check with the flag." - ), - ) - - parser.add_argument( - "--localnet", - action="store_true", - default=False, - help="Whether to run the validator in localnet mode.", - ) - - parser.add_argument( - "--certificate-path", - type=str, - default=None, - help="A custom path to a directory containing a public and private SSL certificate. " - "(cert.pem and key.pem) " - "Please note that this should not be used unless you have issued your own certificate. " - "Omron will issue a certificate for you by default.", - ) - parser.add_argument( - "--prometheus-monitoring", - action="store_true", - default=False, - help="Whether to enable prometheus monitoring.", - ) - parser.add_argument( - "--prometheus-port", - type=int, - default=9090, - help="The port for the prometheus monitoring.", - ) - - bt.subtensor.add_args(parser) - bt.logging.add_args(parser) - bt.wallet.add_args(parser) - config = bt.config(parser) - - if config.localnet: - # quick localnet configuration set up for testing - if ( - config.subtensor.chain_endpoint - == "wss://entrypoint-finney.opentensor.ai:443" - ): - # in case of default value, change to localnet - config.subtensor.chain_endpoint = "ws://127.0.0.1:9946" - if config.wallet.name == "default": - config.wallet.name = "validator" - if config.subtensor.network == "finney": - config.subtensor.network = "local" - config.eth_wallet = ( - config.eth_wallet if config.eth_wallet is not None else "0x001" - ) - config.timeout = config.timeout if config.timeout is None else 120 - config.disable_wandb = True - config.verbose = config.verbose if config.verbose is None else True - config.disable_blacklist = ( - config.disable_blacklist if config.disable_blacklist is None else True - ) - config.external_api_workers = config.external_api_workers or 1 - config.external_api_port = config.external_api_port or 8443 - - config.full_path = os.path.expanduser( - "{}/{}/{}/netuid{}/{}".format( - config.logging.logging_dir, # type: ignore - config.wallet.name, # type: ignore - config.wallet.hotkey, # type: ignore - config.netuid, - "validator", - ) - ) - - if not config.certificate_path: - config.certificate_path = os.path.join(config.full_path, "cert") - - if not os.path.exists(config.full_path): - os.makedirs(config.full_path, exist_ok=True) - - bt.logging(config=config, logging_dir=config.full_path) - bt.logging.enable_info() - - if config.wandb_key: - wandb_logger.safe_login(api_key=config.wandb_key) - bt.logging.success("Logged into WandB") - - return config - - if __name__ == "__main__": - bt.logging.info("Getting validator configuration...") - config = get_config_from_args() - - config.external_model_dir = os.path.join( - os.path.dirname(config.full_path), "deployment_layer" - ) - os.environ["OMRON_EXTERNAL_MODEL_DIR"] = config.external_model_dir - os.environ["EZKL_REPO_PATH"] = os.path.join( - os.path.dirname(config.full_path), "ezkl" - ) - - run_shared_preflight_checks(config.external_model_dir) - - if os.getenv("OMRON_DOCKER_BUILD", False): - bt.logging.info("Docker build steps complete. Exiting.") - sys.exit(0) + run_shared_preflight_checks(Roles.VALIDATOR) try: # Initialize the circuit store and load external models from deployment_layer.circuit_store import circuit_store - circuit_store.load_circuits(config.external_model_dir) + circuit_store.load_circuits() bt.logging.info("Creating validator session...") - validator_session = ValidatorSession(config) + validator_session = ValidatorSession() bt.logging.info("Running main loop...") validator_session.run() except Exception as e: diff --git a/pyproject.toml b/pyproject.toml index b50c6ff1..56d96298 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,16 +13,18 @@ dependencies = [ "bittensor==8.5.1", "ezkl==16.2.0", "fastapi==0.110.1", + "jsonrpcserver>=5.0.9", "numpy==2.0.1", "packaging==24.1", "prometheus_client==0.21.1", "psutil==6.0.0", "pydantic==2.10.3", + "pyopenssl>=25.0.0", "requests==2.32.3", "rich==13.8.1", "torch==2.4.1", "uvicorn==0.22.0", - "wandb==0.18.1" + "wandb==0.18.1", ] [tool.setuptools] diff --git a/requirements.txt b/requirements.txt index 6c434767..bd2d3708 100644 --- a/requirements.txt +++ b/requirements.txt @@ -48,18 +48,18 @@ bittensor==8.5.1 \ bittensor-cli==8.4.2 \ --hash=sha256:43efc081ed2ecf4357bf5c5322ccd6f7d1a5110eb842cf138c75adb3f21686fd \ --hash=sha256:e7fc5ff510f039fa0cb9c0c701a56c4eb2b644befb019b1cd0fac29546bfb764 -bittensor-commit-reveal==0.1.0 \ - --hash=sha256:1c8bb8d77f6279988902c5c28361cc460167829c63ffa8d788209f8810933211 \ - --hash=sha256:25af2d9c82cacc4278095460493430d36070cb2843c0aa54b1c563788d0742eb \ - --hash=sha256:8509250549b6f5c475a9150e941b28fc66e82f30b27fe078fd80fa840943bb7b \ - --hash=sha256:bed04f82f162121747cfd7f51bb5d625dda0bf763a0699054565f255d219a9c2 \ - --hash=sha256:f8f530793274698aaf4ac7cc8f24e915749d8156df8302c9e1e16446177b429d -bittensor-wallet==2.1.3 \ - --hash=sha256:1e2f0d03a21a0c54b1f8cd59f34941d7a60df490e9aab7d7776b03f290de6074 \ - --hash=sha256:24c446b0af4c9ffc3ac122f97a1de25b283c877aa49892748ad06a8a61a74e13 \ - --hash=sha256:41927d7e5d68fff1494cef5abd861ede0afc684dff366824b0806cfa3ce13af0 \ - --hash=sha256:9eafd9c82720644b3eeac2f68deaa9cec4cf175836b16c89206d98ce22590e8e \ - --hash=sha256:f5122b05d8eede2bfc2eb242214b75ecab08f0da5d4f7547ed01ad253349e019 +bittensor-commit-reveal==0.2.0 \ + --hash=sha256:44773448eef88d28c0cc2953d06a4a7137f83b90ff4a246abd41c9d275601b4a \ + --hash=sha256:76218ffdba8b08248ea02b6f349d22171b12300126cb9a24d48241d746ad444f \ + --hash=sha256:81979fd35f95456a60da90e872d1c2d2e68babc8a745778ab5d4025659fef2d7 \ + --hash=sha256:9e6546b9b22fd392dfc569b58e6b3e86899427fc1c07ae52cb60e90c0a520796 \ + --hash=sha256:d67bc49cb93b94136ae10af25a98ec29fe9a88b4ebefadd4f8504eebf63643c0 +bittensor-wallet==3.0.0 \ + --hash=sha256:045561e1be2546965a4adecb1515f61c7953b262328809c71d1acdb3aeddc20f \ + --hash=sha256:48b5e32c40f1dfa9f6dc30c9525aedb02975fb25ea70692efd31890d02789225 \ + --hash=sha256:7f1744f87d2a859700409d6419448f12475147f8c213b4d1bcc073e11fb8e12d \ + --hash=sha256:a5beae01cffc7557dc6a68c3ceaf0568f105b25b8b53a4f02db8b39aa364fed4 \ + --hash=sha256:a69271528f81386dd644ca6c03ea902f60b19c5fd9520d86340137cb67241368 bt-decode==0.4.0 \ --hash=sha256:0b4107e8b75966c5be0822a5f0525b568c94dbc1faa8d928090fa48daa329b45 \ --hash=sha256:2e85f5f12e6bb00253e194372d90e60f129d613f0ddedae659d3b9a3049a69cf \ @@ -159,15 +159,15 @@ docker-pycreds==0.4.0 \ ecdsa==0.19.0 \ --hash=sha256:2cea9b88407fdac7bbeca0833b189e4c9c53f2ef1e1eaa29f6224dbc809b707a \ --hash=sha256:60eaad1199659900dd0af521ed462b793bbdf867432b3948e87416ae4caf6bf8 -eth-hash==0.7.0 \ - --hash=sha256:b8d5a230a2b251f4a291e3164a23a14057c4a6de4b0aa4a16fa4dc9161b57e2f \ - --hash=sha256:bacdc705bfd85dadd055ecd35fd1b4f846b671add101427e089a4ca2e8db310a -eth-keys==0.6.0 \ - --hash=sha256:b396fdfe048a5bba3ef3990739aec64901eb99901c03921caa774be668b1db6e \ - --hash=sha256:ba33230f851d02c894e83989185b21d76152c49b37e35b61b1d8a6d9f1d20430 -eth-typing==5.0.1 \ - --hash=sha256:83debf88c9df286db43bb7374974681ebcc9f048fac81be2548dbc549a3203c0 \ - --hash=sha256:f30d1af16aac598f216748a952eeb64fbcb6e73efa691d2de31148138afe96de +eth-hash==0.7.1 \ + --hash=sha256:0fb1add2adf99ef28883fd6228eb447ef519ea72933535ad1a0b28c6f65f868a \ + --hash=sha256:d2411a403a0b0a62e8247b4117932d900ffb4c8c64b15f92620547ca5ce46be5 +eth-keys==0.6.1 \ + --hash=sha256:7deae4cd56e862e099ec58b78176232b931c4ea5ecded2f50c7b1ccbc10c24cf \ + --hash=sha256:a43e263cbcabfd62fa769168efc6c27b1f5603040e4de22bb84d12567e4fd962 +eth-typing==5.1.0 \ + --hash=sha256:8581f212ee6252aaa285377a77620f6e5f6e16ac3f144c61f098fafd47967b1a \ + --hash=sha256:c0d6b93f5385aa84efc4b47ae2bd478da069bc0ffda8b67e0ccb573f43defd29 eth-utils==2.2.2 \ --hash=sha256:2580a8065273f62ca1ec4c175228c52e626a5f1007e965d2117e5eca1a93cae8 \ --hash=sha256:5ca6265177ce544d9d43cdf2272ae2227e5d6d9529c270bbb707d17339087101 @@ -227,6 +227,14 @@ iniconfig==2.0.0 \ jinja2==3.1.5 \ --hash=sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb \ --hash=sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb +jsonrpcserver==5.0.9 \ + --hash=sha256:a71fb2cfa18541c80935f60987f92755d94d74141248c7438847b96eee5c4482 +jsonschema==4.23.0 \ + --hash=sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4 \ + --hash=sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566 +jsonschema-specifications==2024.10.1 \ + --hash=sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272 \ + --hash=sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf levenshtein==0.26.1 \ --hash=sha256:04b7cabb82edf566b1579b3ed60aac0eec116655af75a3c551fee8754ffce2ea \ --hash=sha256:0d19ba22330d50609b2349021ec3cf7d905c6fe21195a2d0d876a146e7ed2575 \ @@ -262,9 +270,9 @@ markupsafe==3.0.2 \ mdurl==0.1.2 \ --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \ --hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba -more-itertools==10.5.0 \ - --hash=sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef \ - --hash=sha256:5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6 +more-itertools==10.6.0 \ + --hash=sha256:2cd7fad1009c31cc9fb6a035108509e6547547a7a738374f10bd49a09eb3ee3b \ + --hash=sha256:6eb054cb4b6db1473f6e15fcc676a08e4732548acd47c708f0e179c2c7c01e89 mpmath==1.3.0 \ --hash=sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f \ --hash=sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c @@ -326,6 +334,9 @@ numpy==2.0.1 \ --hash=sha256:bb2124fdc6e62baae159ebcfa368708867eb56806804d005860b6007388df171 \ --hash=sha256:cbab9fc9c391700e3e1287666dfd82d8666d10e69a6c4a09ab97574c0b7ee0a7 \ --hash=sha256:ea2326a4dca88e4a274ba3a4405eb6c6467d3ffbd8c7d38632502eaae3820587 +oslash==0.6.3 \ + --hash=sha256:868aeb58a656f2ed3b73d9dd6abe387b20b74fc9413d3e8653b615b15bf728f3 \ + --hash=sha256:89b978443b7db3ac2666106bdc3680add3c886a6d8fcdd02fd062af86d29494f packaging==24.1 \ --hash=sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002 \ --hash=sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124 @@ -360,14 +371,14 @@ propcache==0.2.1 \ --hash=sha256:d71264a80f3fcf512eb4f18f59423fe82d6e346ee97b90625f283df56aee103f \ --hash=sha256:e73091191e4280403bde6c9a52a6999d69cdfde498f1fdf629105247599b57ec \ --hash=sha256:f508b0491767bb1f2b87fdfacaba5f7eddc2f867740ec69ece6d1946d29029a6 -protobuf==5.29.2 \ - --hash=sha256:494229ecd8c9009dd71eda5fd57528395d1eacdf307dbece6c12ad0dd09e912e \ - --hash=sha256:842de6d9241134a973aab719ab42b008a18a90f9f07f06ba480df268f86432f9 \ - --hash=sha256:a0c53d78383c851bfa97eb42e3703aefdc96d2036a41482ffd55dc5f529466eb \ - --hash=sha256:b2cc8e8bb7c9326996f0e160137b0861f1a82162502658df2951209d0cb0309e \ - --hash=sha256:b6b0d416bbbb9d4fbf9d0561dbfc4e324fd522f61f7af0fe0f282ab67b22477e \ - --hash=sha256:c12ba8249f5624300cf51c3d0bfe5be71a60c63e4dcf51ffe9a68771d958c851 \ - --hash=sha256:fde4554c0e578a5a0bcc9a276339594848d1e89f9ea47b4427c80e5d72f90181 +protobuf==5.29.3 \ + --hash=sha256:0a18ed4a24198528f2333802eb075e59dea9d679ab7a6c5efb017a59004d849f \ + --hash=sha256:3ea51771449e1035f26069c4c7fd51fba990d07bc55ba80701c78f886bf9c888 \ + --hash=sha256:5da0f41edaf117bde316404bad1a486cb4ededf8e4a54891296f648e8e076620 \ + --hash=sha256:a4fa6f80816a9a0678429e84973f2f98cbc218cca434abe8db2ad0bffc98503a \ + --hash=sha256:a8434404bbf139aa9e1300dbf989667a83d42ddda9153d8ab76e0d5dcaca484e \ + --hash=sha256:c027e08a08be10b67c06bf2370b99c811c466398c357e615ca88c91c07f0910f \ + --hash=sha256:daaf63f70f25e8689c072cfad4334ca0ac1d1e05a92fc15c54eb9cf23c3efd84 psutil==6.0.0 \ --hash=sha256:33ea5e1c975250a720b3a6609c490db40dae5d83a4eb315170c4fe0d8b1f34b3 \ --hash=sha256:5fd9a97c8e94059b0ef54a7d4baf13b405011176c3b6ff257c247cae0d560ecd \ @@ -429,9 +440,7 @@ pycryptodome==3.21.0 \ --hash=sha256:18caa8cfbc676eaaf28613637a89980ad2fd96e00c564135bf90bc3f0b34dd93 \ --hash=sha256:2480ec2c72438430da9f601ebc12c518c093c13111a5c1644c82cdfc2e50b1e4 \ --hash=sha256:280b67d20e33bb63171d55b1067f61fbd932e0b1ad976b3a184303a3dad22764 \ - --hash=sha256:2cb635b67011bc147c257e61ce864879ffe6d03342dc74b6045059dfbdedafca \ --hash=sha256:2de4b7263a33947ff440412339cb72b28a5a4c769b5c1ca19e33dd6cd1dcec6e \ - --hash=sha256:4c26a2f0dc15f81ea3afa3b0c87b87e501f235d332b7f27e2225ecb80c0b1cdd \ --hash=sha256:7d85c1b613121ed3dbaa5a97369b3b757909531a959d229406a75b912dd51dd1 \ --hash=sha256:8898a66425a57bcf15e25fc19c12490b87bd939800f39a03ea2de2aea5e3611a \ --hash=sha256:932c905b71a56474bff8a9c014030bc3c882cee696b448af920399f730a650c2 \ @@ -471,6 +480,9 @@ pynacl==1.5.0 \ --hash=sha256:a36d4a9dda1f19ce6e03c9a784a2921a4b726b02e1c736600ca9c22029474394 \ --hash=sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b \ --hash=sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543 +pyopenssl==25.0.0 \ + --hash=sha256:424c247065e46e76a37411b9ab1782541c23bb658bf003772c3405fbaa128e90 \ + --hash=sha256:cd2cef799efa3936bb08e8ccb9433a575722b9dd986023f1cabc4ae64e9dac16 pytest==8.3.4 \ --hash=sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6 \ --hash=sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761 @@ -508,6 +520,9 @@ rapidfuzz==3.11.0 \ --hash=sha256:ed78c8e94f57b44292c1a0350f580e18d3a3c5c0800e253f1583580c1b417ad2 \ --hash=sha256:ef8937dae823b889c0273dfa0f0f6c46a3658ac0d851349c464d1b00e7ff4252 \ --hash=sha256:f382fec4a7891d66fb7163c90754454030bb9200a13f82ee7860b6359f3f2fa8 +referencing==0.35.1 \ + --hash=sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c \ + --hash=sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de requests==2.32.3 \ --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 @@ -517,12 +532,27 @@ retry==0.9.2 \ rich==13.8.1 \ --hash=sha256:1760a3c0848469b97b558fc61c85233e3dafb69c7a071b4d60c38099d3cd4c06 \ --hash=sha256:8260cda28e3db6bf04d2d1ef4dbc03ba80a824c88b0e7668a0f23126a424844a +rpds-py==0.22.3 \ + --hash=sha256:02fbb9c288ae08bcb34fb41d516d5eeb0455ac35b5512d03181d755d80810059 \ + --hash=sha256:0a0461200769ab3b9ab7e513f6013b7a97fdeee41c29b9db343f3c5a8e2b9e61 \ + --hash=sha256:1978d0021e943aae58b9b0b196fb4895a25cc53d3956b8e35e0b7682eefb6d56 \ + --hash=sha256:22bebe05a9ffc70ebfa127efbc429bc26ec9e9b4ee4d15a740033efda515cf3d \ + --hash=sha256:27e98004595899949bd7a7b34e91fa7c44d7a97c40fcaf1d874168bb652ec67e \ + --hash=sha256:3af6e48651c4e0d2d166dc1b033b7042ea3f871504b6805ba5f4fe31581d8d38 \ + --hash=sha256:593eba61ba0c3baae5bc9be2f5232430453fb4432048de28399ca7376de9c627 \ + --hash=sha256:655ca44a831ecb238d124e0402d98f6212ac527a0ba6c55ca26f616604e60a45 \ + --hash=sha256:8633e471c6207a039eff6aa116e35f69f3156b3989ea3e2d755f7bc41754a4a7 \ + --hash=sha256:d115bffdd417c6d806ea9069237a4ae02f513b778e3789a359bc5856e0404cc4 \ + --hash=sha256:e32fee8ab45d3c2db6da19a5323bc3362237c8b653c70194414b892fd06a080d \ + --hash=sha256:e67ba3c290821343c192f7eae1d8fd5999ca2dc99994114643e2f2d3e6138b15 \ + --hash=sha256:f56a6b404f74ab372da986d240e2e002769a7d7102cc73eb238a4f72eec5284e \ + --hash=sha256:feea821ee2a9273771bae61194004ee2fc33f8ec7db08117ef9147d4bbcbca8e scalecodec==1.2.11 \ --hash=sha256:99a2cdbfccdcaf22bd86b86da55a730a2855514ad2309faef4a4a93ac6cbeb8d \ --hash=sha256:d15c94965f617caa25096f83a45f5f73031d05e6ee08d6039969f0a64fc35de1 -sentry-sdk==2.19.2 \ - --hash=sha256:467df6e126ba242d39952375dd816fbee0f217d119bf454a8ce74cf1e7909e8d \ - --hash=sha256:ebdc08228b4d131128e568d696c210d846e5b9d70aa0327dec6b1272d9d40b84 +sentry-sdk==2.20.0 \ + --hash=sha256:afa82713a92facf847df3c6f63cec71eb488d826a50965def3d7722aa6f0fdab \ + --hash=sha256:c359a1edf950eb5e80cffd7d9111f3dbeef57994cb4415df37d39fda2cf22364 setproctitle==1.3.4 \ --hash=sha256:04d6ba8b816dbb0bfd62000b0c3e583160893e6e8c4233e1dca1a9ae4d95d924 \ --hash=sha256:0855006261635e8669646c7c304b494b6df0a194d2626683520103153ad63cc9 \ diff --git a/uv.lock b/uv.lock index 6162bc43..e0b4dc03 100644 --- a/uv.lock +++ b/uv.lock @@ -2,8 +2,8 @@ version = 1 requires-python = "==3.12.*" resolution-markers = [ "platform_machine != 'aarch64' and sys_platform == 'linux'", - "platform_machine == 'aarch64' and sys_platform == 'linux'", "sys_platform != 'darwin' and sys_platform != 'linux'", + "platform_machine == 'aarch64' and sys_platform == 'linux'", "sys_platform == 'darwin'", ] @@ -190,19 +190,19 @@ wheels = [ [[package]] name = "bittensor-commit-reveal" -version = "0.1.0" +version = "0.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/93/f6361d6d617f1620f1b642308384d7f22c7917c169b821ddb3a90856a0c9/bittensor_commit_reveal-0.1.0.tar.gz", hash = "sha256:1c8bb8d77f6279988902c5c28361cc460167829c63ffa8d788209f8810933211", size = 23249 } +sdist = { url = "https://files.pythonhosted.org/packages/a7/97/2bb9e34f807b06d6faaaf765285eddedb5bd969ad97bd5f5f99d53f81934/bittensor_commit_reveal-0.2.0.tar.gz", hash = "sha256:d67bc49cb93b94136ae10af25a98ec29fe9a88b4ebefadd4f8504eebf63643c0", size = 23303 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a8/3a/7705ea18c3d61c8affc4696b8ab483bdb7e3d0bfdfb61ca1583a787ef1e0/bittensor_commit_reveal-0.1.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:8509250549b6f5c475a9150e941b28fc66e82f30b27fe078fd80fa840943bb7b", size = 491259 }, - { url = "https://files.pythonhosted.org/packages/80/21/02b400750c7d1d5ed081dc22c740e21e22fd72fbb18b72517d5687eca8bd/bittensor_commit_reveal-0.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bed04f82f162121747cfd7f51bb5d625dda0bf763a0699054565f255d219a9c2", size = 492612 }, - { url = "https://files.pythonhosted.org/packages/9a/82/bf02fda4c7bfbe6830709476cf1893ad4e7b591c4e1f62eab2abbfcd0106/bittensor_commit_reveal-0.1.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25af2d9c82cacc4278095460493430d36070cb2843c0aa54b1c563788d0742eb", size = 712159 }, - { url = "https://files.pythonhosted.org/packages/31/d1/7e41e52251c277bf0bebe0fcb3f700e6faf6a488c9cefa8b8fb2bae42cee/bittensor_commit_reveal-0.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8f530793274698aaf4ac7cc8f24e915749d8156df8302c9e1e16446177b429d", size = 551180 }, + { url = "https://files.pythonhosted.org/packages/76/10/12fc321dc44eb0f6c305993d1644698baf2b4a8fe0e70490128fcd26fa14/bittensor_commit_reveal-0.2.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e6546b9b22fd392dfc569b58e6b3e86899427fc1c07ae52cb60e90c0a520796", size = 491647 }, + { url = "https://files.pythonhosted.org/packages/46/27/0025957757c40da992263d8de8d93cc3dc7ecf512071a8b3cbd42419acff/bittensor_commit_reveal-0.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76218ffdba8b08248ea02b6f349d22171b12300126cb9a24d48241d746ad444f", size = 492798 }, + { url = "https://files.pythonhosted.org/packages/9a/b3/789aa75457705cbb244ef28cb34e4361e692c01eb035ee66943a75ee0b54/bittensor_commit_reveal-0.2.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44773448eef88d28c0cc2953d06a4a7137f83b90ff4a246abd41c9d275601b4a", size = 723463 }, + { url = "https://files.pythonhosted.org/packages/8a/57/e7a808ccb4e3a4728e8ab0960e84219707bd1774a5152a6b07fe863ffca2/bittensor_commit_reveal-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81979fd35f95456a60da90e872d1c2d2e68babc8a745778ab5d4025659fef2d7", size = 566260 }, ] [[package]] name = "bittensor-wallet" -version = "2.1.3" +version = "3.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cryptography" }, @@ -211,15 +211,14 @@ dependencies = [ { name = "password-strength" }, { name = "py-bip39-bindings" }, { name = "rich" }, - { name = "substrate-interface" }, { name = "termcolor" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a4/17/38a9ec85be2167dd2c1aa2e75f0ac7c25ccf7c31859fe9b0d325b474fbbb/bittensor_wallet-2.1.3.tar.gz", hash = "sha256:41927d7e5d68fff1494cef5abd861ede0afc684dff366824b0806cfa3ce13af0", size = 70285 } +sdist = { url = "https://files.pythonhosted.org/packages/51/79/324672b28f7b3ac58baadc92f9a1b9fa74b32c978a7adf3430233103b06f/bittensor_wallet-3.0.0.tar.gz", hash = "sha256:045561e1be2546965a4adecb1515f61c7953b262328809c71d1acdb3aeddc20f", size = 72409 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/b0/a803fb7abe4b004464d67f6812f5067ee0346e7ba0bfb1e3012f569261cd/bittensor_wallet-2.1.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:1e2f0d03a21a0c54b1f8cd59f34941d7a60df490e9aab7d7776b03f290de6074", size = 797657 }, - { url = "https://files.pythonhosted.org/packages/24/35/506d88aed623872fe4ecbcc2d6484ac864dc2c639ef8810141628fd28763/bittensor_wallet-2.1.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:24c446b0af4c9ffc3ac122f97a1de25b283c877aa49892748ad06a8a61a74e13", size = 752425 }, - { url = "https://files.pythonhosted.org/packages/eb/37/c6feb7d6ac75c24bfe170ffabbd42f2d91bc34cc75b99575f2417ec486b1/bittensor_wallet-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eafd9c82720644b3eeac2f68deaa9cec4cf175836b16c89206d98ce22590e8e", size = 3146851 }, - { url = "https://files.pythonhosted.org/packages/8e/63/0dfe52c8c4c7d943d3ca2f52530039e1ee0dbdbffb3d16a90d770725b9bd/bittensor_wallet-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f5122b05d8eede2bfc2eb242214b75ecab08f0da5d4f7547ed01ad253349e019", size = 2954118 }, + { url = "https://files.pythonhosted.org/packages/87/35/c3bf16166c596dcc3b1498e336163cb7622dcdbfa6734c9c6b59c69642c0/bittensor_wallet-3.0.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:7f1744f87d2a859700409d6419448f12475147f8c213b4d1bcc073e11fb8e12d", size = 805856 }, + { url = "https://files.pythonhosted.org/packages/f2/7a/4efc2f566fbecc3a2b2c6b96794620d4f5ce322f6bafe58f82b0ae05ab37/bittensor_wallet-3.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:48b5e32c40f1dfa9f6dc30c9525aedb02975fb25ea70692efd31890d02789225", size = 771198 }, + { url = "https://files.pythonhosted.org/packages/56/e5/8235041c2fa655f42d4a3a45720863c5e810aa310a401f081db68c816a85/bittensor_wallet-3.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5beae01cffc7557dc6a68c3ceaf0568f105b25b8b53a4f02db8b39aa364fed4", size = 3165442 }, + { url = "https://files.pythonhosted.org/packages/f7/a3/14a9beec68caffda7660d92835c19fb1bf4d3bf07bc2c805b9682f8caab4/bittensor_wallet-3.0.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a69271528f81386dd644ca6c03ea902f60b19c5fd9520d86340137cb67241368", size = 2968740 }, ] [[package]] @@ -410,36 +409,36 @@ wheels = [ [[package]] name = "eth-hash" -version = "0.7.0" +version = "0.7.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c6/b6/57c89b91cf2dbb02b3019337f97bf346167d06cd23d3bde43c9fe52cae7e/eth-hash-0.7.0.tar.gz", hash = "sha256:bacdc705bfd85dadd055ecd35fd1b4f846b671add101427e089a4ca2e8db310a", size = 12463 } +sdist = { url = "https://files.pythonhosted.org/packages/ee/38/577b7bc9380ef9dff0f1dffefe0c9a1ded2385e7a06c306fd95afb6f9451/eth_hash-0.7.1.tar.gz", hash = "sha256:d2411a403a0b0a62e8247b4117932d900ffb4c8c64b15f92620547ca5ce46be5", size = 12227 } wheels = [ - { url = "https://files.pythonhosted.org/packages/73/f0/a35e791bd73fa425838d8d0157754150ded141a94cf30d567dfeb9d57316/eth_hash-0.7.0-py3-none-any.whl", hash = "sha256:b8d5a230a2b251f4a291e3164a23a14057c4a6de4b0aa4a16fa4dc9161b57e2f", size = 8650 }, + { url = "https://files.pythonhosted.org/packages/eb/db/f8775490669d28aca24871c67dd56b3e72105cb3bcae9a4ec65dd70859b3/eth_hash-0.7.1-py3-none-any.whl", hash = "sha256:0fb1add2adf99ef28883fd6228eb447ef519ea72933535ad1a0b28c6f65f868a", size = 8028 }, ] [[package]] name = "eth-keys" -version = "0.6.0" +version = "0.6.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "eth-typing" }, { name = "eth-utils" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/58/4a/aabe0bff4e299858845fba5598c435f2bee0646366b9635750133904e2d8/eth_keys-0.6.0.tar.gz", hash = "sha256:ba33230f851d02c894e83989185b21d76152c49b37e35b61b1d8a6d9f1d20430", size = 28944 } +sdist = { url = "https://files.pythonhosted.org/packages/ac/72/96db2e3d27c64d3e4a6bf1397447d029e4268fd70b0f1ee4192d6e8d75cd/eth_keys-0.6.1.tar.gz", hash = "sha256:a43e263cbcabfd62fa769168efc6c27b1f5603040e4de22bb84d12567e4fd962", size = 30090 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f0/ee/583612eed5d49f10bd1749d7dda9e93691ab02724b7af84830046e31c64c/eth_keys-0.6.0-py3-none-any.whl", hash = "sha256:b396fdfe048a5bba3ef3990739aec64901eb99901c03921caa774be668b1db6e", size = 21210 }, + { url = "https://files.pythonhosted.org/packages/5f/67/c241c85e9cb9c4d8c14440dd82f7fbe39536592bf59c6b643004ac63eab2/eth_keys-0.6.1-py3-none-any.whl", hash = "sha256:7deae4cd56e862e099ec58b78176232b931c4ea5ecded2f50c7b1ccbc10c24cf", size = 21292 }, ] [[package]] name = "eth-typing" -version = "5.0.1" +version = "5.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/33/32/d5a1bdf872f92a7c3361396b684aeba7abaabb341bd22a80029abcd1f68e/eth_typing-5.0.1.tar.gz", hash = "sha256:83debf88c9df286db43bb7374974681ebcc9f048fac81be2548dbc549a3203c0", size = 22716 } +sdist = { url = "https://files.pythonhosted.org/packages/0f/6f/ecd98de0b67eefc68e17f6979433534a63e11aac88adaae7dede0b694567/eth_typing-5.1.0.tar.gz", hash = "sha256:8581f212ee6252aaa285377a77620f6e5f6e16ac3f144c61f098fafd47967b1a", size = 21727 } wheels = [ - { url = "https://files.pythonhosted.org/packages/1a/ef/a66ff9b83df51b83c1af468fc7b5e4a3855d9e3c01e2365ecfe1c5e84077/eth_typing-5.0.1-py3-none-any.whl", hash = "sha256:f30d1af16aac598f216748a952eeb64fbcb6e73efa691d2de31148138afe96de", size = 20085 }, + { url = "https://files.pythonhosted.org/packages/c8/2e/40e7577866f4378fb9737e0cb08e3e96e5a25b53821b0139dbfbd77dd66e/eth_typing-5.1.0-py3-none-any.whl", hash = "sha256:c0d6b93f5385aa84efc4b47ae2bd478da069bc0ffda8b67e0ccb573f43defd29", size = 19116 }, ] [[package]] @@ -599,6 +598,43 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/bd/0f/2ba5fbcd631e3e88689309dbe978c5769e883e4b84ebfe7da30b43275c5a/jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb", size = 134596 }, ] +[[package]] +name = "jsonrpcserver" +version = "5.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jsonschema" }, + { name = "oslash" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e3/3b/8d4d4fe8c59a1a4d1e6edd6126ec118b989510fadf262950a5c4f4bca664/jsonrpcserver-5.0.9.tar.gz", hash = "sha256:a71fb2cfa18541c80935f60987f92755d94d74141248c7438847b96eee5c4482", size = 14506 } + +[[package]] +name = "jsonschema" +version = "4.23.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "jsonschema-specifications" }, + { name = "referencing" }, + { name = "rpds-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/38/2e/03362ee4034a4c917f697890ccd4aec0800ccf9ded7f511971c75451deec/jsonschema-4.23.0.tar.gz", hash = "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4", size = 325778 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/4a/4f9dbeb84e8850557c02365a0eee0649abe5eb1d84af92a25731c6c0f922/jsonschema-4.23.0-py3-none-any.whl", hash = "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566", size = 88462 }, +] + +[[package]] +name = "jsonschema-specifications" +version = "2024.10.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "referencing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/10/db/58f950c996c793472e336ff3655b13fbcf1e3b359dcf52dcf3ed3b52c352/jsonschema_specifications-2024.10.1.tar.gz", hash = "sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272", size = 15561 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/0f/8910b19ac0670a0f80ce1008e5e751c4a57e14d2c4c13a482aa6079fa9d6/jsonschema_specifications-2024.10.1-py3-none-any.whl", hash = "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf", size = 18459 }, +] + [[package]] name = "levenshtein" version = "0.26.1" @@ -666,11 +702,11 @@ wheels = [ [[package]] name = "more-itertools" -version = "10.5.0" +version = "10.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/51/78/65922308c4248e0eb08ebcbe67c95d48615cc6f27854b6f2e57143e9178f/more-itertools-10.5.0.tar.gz", hash = "sha256:5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6", size = 121020 } +sdist = { url = "https://files.pythonhosted.org/packages/88/3b/7fa1fe835e2e93fd6d7b52b2f95ae810cf5ba133e1845f726f5a992d62c2/more-itertools-10.6.0.tar.gz", hash = "sha256:2cd7fad1009c31cc9fb6a035108509e6547547a7a738374f10bd49a09eb3ee3b", size = 125009 } wheels = [ - { url = "https://files.pythonhosted.org/packages/48/7e/3a64597054a70f7c86eb0a7d4fc315b8c1ab932f64883a297bdffeb5f967/more_itertools-10.5.0-py3-none-any.whl", hash = "sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef", size = 60952 }, + { url = "https://files.pythonhosted.org/packages/23/62/0fe302c6d1be1c777cab0616e6302478251dfbf9055ad426f5d0def75c89/more_itertools-10.6.0-py3-none-any.whl", hash = "sha256:6eb054cb4b6db1473f6e15fcc676a08e4732548acd47c708f0e179c2c7c01e89", size = 63038 }, ] [[package]] @@ -797,18 +833,19 @@ wheels = [ [[package]] name = "omron" -version = "5.1.4" source = { editable = "." } dependencies = [ { name = "attrs" }, { name = "bittensor" }, { name = "ezkl" }, { name = "fastapi" }, + { name = "jsonrpcserver" }, { name = "numpy" }, { name = "packaging" }, { name = "prometheus-client" }, { name = "psutil" }, { name = "pydantic" }, + { name = "pyopenssl" }, { name = "requests" }, { name = "rich" }, { name = "torch", version = "2.4.1", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or sys_platform == 'darwin'" }, @@ -823,11 +860,13 @@ requires-dist = [ { name = "bittensor", specifier = "==8.5.1" }, { name = "ezkl", specifier = "==16.2.0" }, { name = "fastapi", specifier = "==0.110.1" }, + { name = "jsonrpcserver", specifier = ">=5.0.9" }, { name = "numpy", specifier = "==2.0.1" }, { name = "packaging", specifier = "==24.1" }, { name = "prometheus-client", specifier = "==0.21.1" }, { name = "psutil", specifier = "==6.0.0" }, { name = "pydantic", specifier = "==2.10.3" }, + { name = "pyopenssl", specifier = ">=25.0.0" }, { name = "requests", specifier = "==2.32.3" }, { name = "rich", specifier = "==13.8.1" }, { name = "torch", specifier = "==2.4.1", index = "https://download.pytorch.org/whl/cpu" }, @@ -835,6 +874,18 @@ requires-dist = [ { name = "wandb", specifier = "==0.18.1" }, ] +[[package]] +name = "oslash" +version = "0.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/60/b2/54ea4a7c6f768469a4c6a2f27f5c7cf572d63e9fd7f7618fca89c30966b3/OSlash-0.6.3.tar.gz", hash = "sha256:868aeb58a656f2ed3b73d9dd6abe387b20b74fc9413d3e8653b615b15bf728f3", size = 35228 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2d/c3/77d40a6e20fdfbf92b086d2c47e3cc82731e179e3f44bdc8e60b7306bcc3/OSlash-0.6.3-py3-none-any.whl", hash = "sha256:89b978443b7db3ac2666106bdc3680add3c886a6d8fcdd02fd062af86d29494f", size = 26943 }, +] + [[package]] name = "packaging" version = "24.1" @@ -910,16 +961,16 @@ wheels = [ [[package]] name = "protobuf" -version = "5.29.2" +version = "5.29.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a5/73/4e6295c1420a9d20c9c351db3a36109b4c9aa601916cb7c6871e3196a1ca/protobuf-5.29.2.tar.gz", hash = "sha256:b2cc8e8bb7c9326996f0e160137b0861f1a82162502658df2951209d0cb0309e", size = 424901 } +sdist = { url = "https://files.pythonhosted.org/packages/f7/d1/e0a911544ca9993e0f17ce6d3cc0932752356c1b0a834397f28e63479344/protobuf-5.29.3.tar.gz", hash = "sha256:5da0f41edaf117bde316404bad1a486cb4ededf8e4a54891296f648e8e076620", size = 424945 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f3/42/6db5387124708d619ffb990a846fb123bee546f52868039f8fa964c5bc54/protobuf-5.29.2-cp310-abi3-win32.whl", hash = "sha256:c12ba8249f5624300cf51c3d0bfe5be71a60c63e4dcf51ffe9a68771d958c851", size = 422697 }, - { url = "https://files.pythonhosted.org/packages/6c/38/2fcc968b377b531882d6ab2ac99b10ca6d00108394f6ff57c2395fb7baff/protobuf-5.29.2-cp310-abi3-win_amd64.whl", hash = "sha256:842de6d9241134a973aab719ab42b008a18a90f9f07f06ba480df268f86432f9", size = 434495 }, - { url = "https://files.pythonhosted.org/packages/cb/26/41debe0f6615fcb7e97672057524687ed86fcd85e3da3f031c30af8f0c51/protobuf-5.29.2-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:a0c53d78383c851bfa97eb42e3703aefdc96d2036a41482ffd55dc5f529466eb", size = 417812 }, - { url = "https://files.pythonhosted.org/packages/e4/20/38fc33b60dcfb380507b99494aebe8c34b68b8ac7d32808c4cebda3f6f6b/protobuf-5.29.2-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:494229ecd8c9009dd71eda5fd57528395d1eacdf307dbece6c12ad0dd09e912e", size = 319562 }, - { url = "https://files.pythonhosted.org/packages/90/4d/c3d61e698e0e41d926dbff6aa4e57428ab1a6fc3b5e1deaa6c9ec0fd45cf/protobuf-5.29.2-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:b6b0d416bbbb9d4fbf9d0561dbfc4e324fd522f61f7af0fe0f282ab67b22477e", size = 319662 }, - { url = "https://files.pythonhosted.org/packages/f3/fd/c7924b4c2a1c61b8f4b64edd7a31ffacf63432135a2606f03a2f0d75a750/protobuf-5.29.2-py3-none-any.whl", hash = "sha256:fde4554c0e578a5a0bcc9a276339594848d1e89f9ea47b4427c80e5d72f90181", size = 172539 }, + { url = "https://files.pythonhosted.org/packages/dc/7a/1e38f3cafa022f477ca0f57a1f49962f21ad25850c3ca0acd3b9d0091518/protobuf-5.29.3-cp310-abi3-win32.whl", hash = "sha256:3ea51771449e1035f26069c4c7fd51fba990d07bc55ba80701c78f886bf9c888", size = 422708 }, + { url = "https://files.pythonhosted.org/packages/61/fa/aae8e10512b83de633f2646506a6d835b151edf4b30d18d73afd01447253/protobuf-5.29.3-cp310-abi3-win_amd64.whl", hash = "sha256:a4fa6f80816a9a0678429e84973f2f98cbc218cca434abe8db2ad0bffc98503a", size = 434508 }, + { url = "https://files.pythonhosted.org/packages/dd/04/3eaedc2ba17a088961d0e3bd396eac764450f431621b58a04ce898acd126/protobuf-5.29.3-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:a8434404bbf139aa9e1300dbf989667a83d42ddda9153d8ab76e0d5dcaca484e", size = 417825 }, + { url = "https://files.pythonhosted.org/packages/4f/06/7c467744d23c3979ce250397e26d8ad8eeb2bea7b18ca12ad58313c1b8d5/protobuf-5.29.3-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:daaf63f70f25e8689c072cfad4334ca0ac1d1e05a92fc15c54eb9cf23c3efd84", size = 319573 }, + { url = "https://files.pythonhosted.org/packages/a8/45/2ebbde52ad2be18d3675b6bee50e68cd73c9e0654de77d595540b5129df8/protobuf-5.29.3-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:c027e08a08be10b67c06bf2370b99c811c466398c357e615ca88c91c07f0910f", size = 319672 }, + { url = "https://files.pythonhosted.org/packages/fd/b2/ab07b09e0f6d143dfb839693aa05765257bceaa13d03bf1a696b78323e7a/protobuf-5.29.3-py3-none-any.whl", hash = "sha256:0a18ed4a24198528f2333802eb075e59dea9d679ab7a6c5efb017a59004d849f", size = 172550 }, ] [[package]] @@ -1030,8 +1081,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/39/1b/d0b013bf7d1af7cf0a6a4fce13f5fe5813ab225313755367b36e714a63f8/pycryptodome-3.21.0-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:18caa8cfbc676eaaf28613637a89980ad2fd96e00c564135bf90bc3f0b34dd93", size = 2254397 }, { url = "https://files.pythonhosted.org/packages/14/71/4cbd3870d3e926c34706f705d6793159ac49d9a213e3ababcdade5864663/pycryptodome-3.21.0-cp36-abi3-win32.whl", hash = "sha256:280b67d20e33bb63171d55b1067f61fbd932e0b1ad976b3a184303a3dad22764", size = 1775641 }, { url = "https://files.pythonhosted.org/packages/43/1d/81d59d228381576b92ecede5cd7239762c14001a828bdba30d64896e9778/pycryptodome-3.21.0-cp36-abi3-win_amd64.whl", hash = "sha256:b7aa25fc0baa5b1d95b7633af4f5f1838467f1815442b22487426f94e0d66c53", size = 1812863 }, - { url = "https://files.pythonhosted.org/packages/25/b3/09ff7072e6d96c9939c24cf51d3c389d7c345bf675420355c22402f71b68/pycryptodome-3.21.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:2cb635b67011bc147c257e61ce864879ffe6d03342dc74b6045059dfbdedafca", size = 1691593 }, - { url = "https://files.pythonhosted.org/packages/a8/91/38e43628148f68ba9b68dedbc323cf409e537fd11264031961fd7c744034/pycryptodome-3.21.0-pp27-pypy_73-win32.whl", hash = "sha256:4c26a2f0dc15f81ea3afa3b0c87b87e501f235d332b7f27e2225ecb80c0b1cdd", size = 1765997 }, ] [[package]] @@ -1102,6 +1151,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5e/22/d3db169895faaf3e2eda892f005f433a62db2decbcfbc2f61e6517adfa87/PyNaCl-1.5.0-cp36-abi3-win_amd64.whl", hash = "sha256:20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93", size = 212141 }, ] +[[package]] +name = "pyopenssl" +version = "25.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cryptography" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9f/26/e25b4a374b4639e0c235527bbe31c0524f26eda701d79456a7e1877f4cc5/pyopenssl-25.0.0.tar.gz", hash = "sha256:cd2cef799efa3936bb08e8ccb9433a575722b9dd986023f1cabc4ae64e9dac16", size = 179573 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ca/d7/eb76863d2060dcbe7c7e6cccfd95ac02ea0b9acc37745a0d99ff6457aefb/pyOpenSSL-25.0.0-py3-none-any.whl", hash = "sha256:424c247065e46e76a37411b9ab1782541c23bb658bf003772c3405fbaa128e90", size = 56453 }, +] + [[package]] name = "pytest" version = "8.3.4" @@ -1178,6 +1240,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/92/d0/1406d6e110aff87303e98f47adc5e76ef2e69d51cdd08b2d463520158cab/rapidfuzz-3.11.0-cp312-cp312-win_arm64.whl", hash = "sha256:ed78c8e94f57b44292c1a0350f580e18d3a3c5c0800e253f1583580c1b417ad2", size = 858655 }, ] +[[package]] +name = "referencing" +version = "0.35.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "rpds-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/99/5b/73ca1f8e72fff6fa52119dbd185f73a907b1989428917b24cff660129b6d/referencing-0.35.1.tar.gz", hash = "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c", size = 62991 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/59/2056f61236782a2c86b33906c025d4f4a0b17be0161b63b70fd9e8775d36/referencing-0.35.1-py3-none-any.whl", hash = "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de", size = 26684 }, +] + [[package]] name = "requests" version = "2.32.3" @@ -1219,6 +1294,27 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b0/11/dadb85e2bd6b1f1ae56669c3e1f0410797f9605d752d68fb47b77f525b31/rich-13.8.1-py3-none-any.whl", hash = "sha256:1760a3c0848469b97b558fc61c85233e3dafb69c7a071b4d60c38099d3cd4c06", size = 241608 }, ] +[[package]] +name = "rpds-py" +version = "0.22.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/80/cce854d0921ff2f0a9fa831ba3ad3c65cee3a46711addf39a2af52df2cfd/rpds_py-0.22.3.tar.gz", hash = "sha256:e32fee8ab45d3c2db6da19a5323bc3362237c8b653c70194414b892fd06a080d", size = 26771 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/75/47/3383ee3bd787a2a5e65a9b9edc37ccf8505c0a00170e3a5e6ea5fbcd97f7/rpds_py-0.22.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:27e98004595899949bd7a7b34e91fa7c44d7a97c40fcaf1d874168bb652ec67e", size = 352334 }, + { url = "https://files.pythonhosted.org/packages/40/14/aa6400fa8158b90a5a250a77f2077c0d0cd8a76fce31d9f2b289f04c6dec/rpds_py-0.22.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1978d0021e943aae58b9b0b196fb4895a25cc53d3956b8e35e0b7682eefb6d56", size = 342111 }, + { url = "https://files.pythonhosted.org/packages/7d/06/395a13bfaa8a28b302fb433fb285a67ce0ea2004959a027aea8f9c52bad4/rpds_py-0.22.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:655ca44a831ecb238d124e0402d98f6212ac527a0ba6c55ca26f616604e60a45", size = 384286 }, + { url = "https://files.pythonhosted.org/packages/43/52/d8eeaffab047e6b7b7ef7f00d5ead074a07973968ffa2d5820fa131d7852/rpds_py-0.22.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:feea821ee2a9273771bae61194004ee2fc33f8ec7db08117ef9147d4bbcbca8e", size = 391739 }, + { url = "https://files.pythonhosted.org/packages/83/31/52dc4bde85c60b63719610ed6f6d61877effdb5113a72007679b786377b8/rpds_py-0.22.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:22bebe05a9ffc70ebfa127efbc429bc26ec9e9b4ee4d15a740033efda515cf3d", size = 427306 }, + { url = "https://files.pythonhosted.org/packages/70/d5/1bab8e389c2261dba1764e9e793ed6830a63f830fdbec581a242c7c46bda/rpds_py-0.22.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3af6e48651c4e0d2d166dc1b033b7042ea3f871504b6805ba5f4fe31581d8d38", size = 442717 }, + { url = "https://files.pythonhosted.org/packages/82/a1/a45f3e30835b553379b3a56ea6c4eb622cf11e72008229af840e4596a8ea/rpds_py-0.22.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67ba3c290821343c192f7eae1d8fd5999ca2dc99994114643e2f2d3e6138b15", size = 385721 }, + { url = "https://files.pythonhosted.org/packages/a6/27/780c942de3120bdd4d0e69583f9c96e179dfff082f6ecbb46b8d6488841f/rpds_py-0.22.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:02fbb9c288ae08bcb34fb41d516d5eeb0455ac35b5512d03181d755d80810059", size = 415824 }, + { url = "https://files.pythonhosted.org/packages/94/0b/aa0542ca88ad20ea719b06520f925bae348ea5c1fdf201b7e7202d20871d/rpds_py-0.22.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f56a6b404f74ab372da986d240e2e002769a7d7102cc73eb238a4f72eec5284e", size = 561227 }, + { url = "https://files.pythonhosted.org/packages/0d/92/3ed77d215f82c8f844d7f98929d56cc321bb0bcfaf8f166559b8ec56e5f1/rpds_py-0.22.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0a0461200769ab3b9ab7e513f6013b7a97fdeee41c29b9db343f3c5a8e2b9e61", size = 587424 }, + { url = "https://files.pythonhosted.org/packages/09/42/cacaeb047a22cab6241f107644f230e2935d4efecf6488859a7dd82fc47d/rpds_py-0.22.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8633e471c6207a039eff6aa116e35f69f3156b3989ea3e2d755f7bc41754a4a7", size = 555953 }, + { url = "https://files.pythonhosted.org/packages/e6/52/c921dc6d5f5d45b212a456c1f5b17df1a471127e8037eb0972379e39dff4/rpds_py-0.22.3-cp312-cp312-win32.whl", hash = "sha256:593eba61ba0c3baae5bc9be2f5232430453fb4432048de28399ca7376de9c627", size = 221339 }, + { url = "https://files.pythonhosted.org/packages/f2/c7/f82b5be1e8456600395366f86104d1bd8d0faed3802ad511ef6d60c30d98/rpds_py-0.22.3-cp312-cp312-win_amd64.whl", hash = "sha256:d115bffdd417c6d806ea9069237a4ae02f513b778e3789a359bc5856e0404cc4", size = 235786 }, +] + [[package]] name = "scalecodec" version = "1.2.11" @@ -1235,15 +1331,15 @@ wheels = [ [[package]] name = "sentry-sdk" -version = "2.19.2" +version = "2.20.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/36/4a/eccdcb8c2649d53440ae1902447b86e2e2ad1bc84207c80af9696fa07614/sentry_sdk-2.19.2.tar.gz", hash = "sha256:467df6e126ba242d39952375dd816fbee0f217d119bf454a8ce74cf1e7909e8d", size = 299047 } +sdist = { url = "https://files.pythonhosted.org/packages/68/e8/6a366c0cd5e129dda6ecb20ff097f70b18182c248d4c27e813c21f98992a/sentry_sdk-2.20.0.tar.gz", hash = "sha256:afa82713a92facf847df3c6f63cec71eb488d826a50965def3d7722aa6f0fdab", size = 300125 } wheels = [ - { url = "https://files.pythonhosted.org/packages/31/4d/74597bb6bcc23abc774b8901277652c61331a9d4d0a8d1bdb20679b9bbcb/sentry_sdk-2.19.2-py2.py3-none-any.whl", hash = "sha256:ebdc08228b4d131128e568d696c210d846e5b9d70aa0327dec6b1272d9d40b84", size = 322942 }, + { url = "https://files.pythonhosted.org/packages/e6/0f/6f7e6cd0f4a141752caef3f79300148422fdf2b8b68b531f30b2b0c0cbda/sentry_sdk-2.20.0-py2.py3-none-any.whl", hash = "sha256:c359a1edf950eb5e80cffd7d9111f3dbeef57994cb4415df37d39fda2cf22364", size = 322576 }, ] [[package]]