From cf2187612200e790e91cf6f2fa618ebb06a4c2f7 Mon Sep 17 00:00:00 2001 From: p-ferreira <38992619+p-ferreira@users.noreply.github.com> Date: Mon, 12 Jun 2023 15:00:59 -0400 Subject: [PATCH 1/3] Quick fixes to run.sh to make updating pm2 faster Removed erroneous code --- README.md | 20 +++ openvalidators/utils.py | 9 +- run.sh | 263 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 286 insertions(+), 6 deletions(-) create mode 100755 run.sh diff --git a/README.md b/README.md index dfa5397..4356137 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,26 @@ the creation of valuable datasets for the community's miners. To learn more about the Bittensor validation process, check out this [documentation](https://tensor-wiki.vercel.app/validating/validating). +# Running + +These validators are designed to run and update themselves automatically. To run a validator, follow these steps: + +1. Install this repository, you can do so by following the steps outlined in [the installation section](#install). +2. Install [Weights and Biases](https://docs.wandb.ai/quickstart) and run `wandb.init()` within this repository. This will initialize Weights and Biases, enabling you to view KPIs and Metrics on your validator. +3. Install [PM2](https://pm2.io/docs/runtime/guide/installation/) and the [`jq` package](https://jqlang.github.io/jq/) on your system. + **On Linux**: + ```bash + sudo apt update && sudo apt install jq + ``` + **On Mac OS** + ```bash + brew update && brew install jq + ``` +4. Run the `run.sh` script which will handle running your validator and pulling the latest updates as they are issued. + ```bash + $ pm2 start autorun.sh -- script validators/openvalidators/neuron.py --wallet.name --wallet.hotkey + ``` + # Usage There are currently four main avenues for engaging with this repository: diff --git a/openvalidators/utils.py b/openvalidators/utils.py index cc71649..4899916 100644 --- a/openvalidators/utils.py +++ b/openvalidators/utils.py @@ -91,13 +91,10 @@ def resync_metagraph(self): # Sync the metagraph. self.metagraph.sync() - # Creates a dictionary of uids and hotkeys from the previous metagraph state. - uids_hotkeys_state_dict = dict(zip(previous_metagraph.uids.tolist(), previous_metagraph.hotkeys)) - - # Creates a dictionary of latest uids and hotkeys of the metagraph. - latest_uids_hotkeys_state_dict = dict(zip(self.metagraph.uids.tolist(), self.metagraph.hotkeys)) + # Check if the metagraph axon info has changed. + metagraph_axon_info_updated = previous_metagraph.axons != self.metagraph.axons - if uids_hotkeys_state_dict != latest_uids_hotkeys_state_dict: + if metagraph_axon_info_updated: bt.logging.info("Metagraph updated, re-syncing hotkeys, dendrite pool and moving averages") # Reconstruct the dendrite pool with the new endpoints. self.dendrite_pool.resync(self.metagraph) diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..48fdbbe --- /dev/null +++ b/run.sh @@ -0,0 +1,263 @@ +#!/bin/bash + +# Initialize variables +script="" +autoRunLoc=$(readlink -f "$0") +proc_name="auto_run_validator" +args=() +version_location="./openvalidators/__init__.py" +version="__version__" + +# Check if pm2 is installed +if ! command -v pm2 &> /dev/null +then + echo "pm2 could not be found. To install see: https://pm2.keymetrics.io/docs/usage/quick-start/" + exit 1 +fi + +# Checks if $1 is smaller than $2 +# If $1 is smaller than or equal to $2, then true. +# else false. +version_less_than_or_equal() { + [ "$1" = "`echo -e "$1\n$2" | sort -V | head -n1`" ] +} + +# Checks if $1 is smaller than $2 +# If $1 is smaller than $2, then true. +# else false. +version_less_than() { + [ "$1" = "$2" ] && return 1 || version_less_than_or_equal $1 $2 +} + +# Returns the difference between +# two versions as a numerical value. +get_version_difference() { + local tag1="$1" + local tag2="$2" + + # Extract the version numbers from the tags + local version1=$(echo "$tag1" | sed 's/v//') + local version2=$(echo "$tag2" | sed 's/v//') + + # Split the version numbers into an array + IFS='.' read -ra version1_arr <<< "$version1" + IFS='.' read -ra version2_arr <<< "$version2" + + # Calculate the numerical difference + local diff=0 + for i in "${!version1_arr[@]}"; do + local num1=${version1_arr[$i]} + local num2=${version2_arr[$i]} + + # Compare the numbers and update the difference + if (( num1 > num2 )); then + diff=$((diff + num1 - num2)) + elif (( num1 < num2 )); then + diff=$((diff + num2 - num1)) + fi + done + + strip_quotes $diff +} + +read_version_value() { + # Read each line in the file + while IFS= read -r line; do + # Check if the line contains the variable name + if [[ "$line" == *"$version"* ]]; then + # Extract the value of the variable + local value=$(echo "$line" | awk -F '=' '{print $2}' | tr -d ' ') + strip_quotes $value + return 0 + fi + done < "$version_location" + + echo "" +} + +check_package_installed() { + local package_name="$1" + os_name=$(uname -s) + + if [[ "$os_name" == "Linux" ]]; then + # Use dpkg-query to check if the package is installed + if dpkg-query -W -f='${Status}' "$package_name" 2>/dev/null | grep -q "installed"; then + return 1 + else + return 0 + fi + elif [[ "$os_name" == "Darwin" ]]; then + if brew list --formula | grep -q "^$package_name$"; then + return 1 + else + return 0 + fi + else + echo "Unknown operating system" + return 0 + fi +} + +check_variable_value_on_github() { + local repo="$1" + local file_path="$2" + local variable_name="$3" + + local url="https://api.github.com/repos/$repo/contents/$file_path" + local response=$(curl -s "$url") + + # Check if the response contains an error message + if [[ $response =~ "message" ]]; then + echo "Error: Failed to retrieve file contents from GitHub." + return 1 + fi + + # Extract the content from the response + local content=$(echo "$response" | tr -d '\n' | jq -r '.content') + + if [[ "$content" == "null" ]]; then + echo "File '$file_path' not found in the repository." + return 1 + fi + + # Decode the Base64-encoded content + local decoded_content=$(echo "$content" | base64 --decode) + + # Extract the variable value from the content + local variable_value=$(echo "$decoded_content" | grep "$variable_name" | awk -F '=' '{print $2}' | tr -d ' ') + + if [[ -z "$variable_value" ]]; then + echo "Variable '$variable_name' not found in the file '$file_path'." + return 1 + fi + + strip_quotes $variable_value +} + +strip_quotes() { + local input="$1" + + # Remove leading and trailing quotes using parameter expansion + local stripped="${input#\"}" + stripped="${stripped%\"}" + + echo "$stripped" +} + +# Parse command line arguments +while [[ "$#" -gt 0 ]]; do + case $1 in + --script) + script="$2"; + shift ;; + --name) + name="$2" + shift ;; + --*) + flag="$1"; + echo "flag is: $flag" + value="$2"; + if [[ $value == *"--"* ]]; then + value="True"; + args+=("$flag=$value"); + else + args+=("$flag=$value"); + shift; + fi + ;; + *) + echo "Unknown parameter passed" + shift ;; + esac + shift +done + +# Check if script argument was provided +if [[ -z "$script" ]]; then + echo "The --script argument is required." + exit 1 +fi + +branch=$(git branch --show-current) # get current branch. +echo watching branch: $branch +echo pm2 process name: $proc_name + +# Get the current version locally. +current_version=$(read_version_value) + +# Check if script is already running with pm2 +if pm2 status | grep -q $proc_name; then + echo "The script is already running with pm2. Stopping and restarting..." + pm2 delete $proc_name +fi + +# Run the Python script with the arguments using pm2 +echo "Running $script with the following arguments with pm2:" +echo "pm2 start $script --name $proc_name --interpreter python3 -- ${args[@]}" +pm2 start "$script" --name $proc_name --interpreter python3 -- "${args[@]}" + +# Check if packages are installed. +check_package_installed "jq" +if [ "$?" -eq 1 ]; then + while true; do + + # First ensure that this is a git installation + if [ -d "./.git" ]; then + + # check value on github remotely + latest_version=$(check_variable_value_on_github "opentensor/validators" "openvalidators/__init__.py" "__version__ ") + + # If the file has been updated + if version_less_than $current_version $latest_version; then + echo "latest version $latest_version" + echo "current version $current_version" + diff=$(get_version_difference $latest_version $current_version) + if [ "$diff" -eq 1 ]; then + echo "current validator version:" "$current_version" + echo "latest validator version:" "$latest_version" + + # Pull latest changes + # Failed git pull will return a non-zero output + if git pull origin $branch; then + # latest_version is newer than current_version, should download and reinstall. + echo "New version published. Updating the local copy." + + # Install latest changes just in case. + pip install -e ../ + + # # Run the Python script with the arguments using pm2 + echo "Restarting PM2 process" + pm2 restart $proc_name + + # Update current version: + current_version=$(read_version_value) + echo "" + + # Restart autorun script + echo "Restarting script..." + ./$(basename $0) $args && exit + else + echo "**Will not update**" + echo "It appears you have made changes on your local copy. Please stash your changes using git stash." + fi + else + # current version is newer than the latest on git. This is likely a local copy, so do nothing. + echo "**Will not update**" + echo "The local version is $diff versions behind. Please manually update to the latest version and re-run this script." + fi + else + echo "**Skipping update **" + echo "$current_version is the same as or more than $latest_version. You are likely running locally." + fi + else + echo "The installation does not appear to be done through Git. Please install from source at https://github.com/opentensor/validators and rerun this script." + fi + + # Wait about 30 minutes + # This should be plenty of time for validators to catch up + # and should prevent any rate limitations by GitHub. + sleep 1800 + done +else + echo "Missing package 'jq'. Please install it for your system first." +fi \ No newline at end of file From 74010940c57922915e0cf9e9497ad7eaca4081b6 Mon Sep 17 00:00:00 2001 From: Ala Shaabana Date: Tue, 13 Jun 2023 16:43:22 -0400 Subject: [PATCH 2/3] Resolved merge conflict part 2 --- run.sh | 5 ----- 1 file changed, 5 deletions(-) diff --git a/run.sh b/run.sh index 963de73..8df8112 100755 --- a/run.sh +++ b/run.sh @@ -8,11 +8,6 @@ args=() version_location="./openvalidators/__init__.py" version="__version__" -<<<<<<< HEAD -======= -args=$@ - ->>>>>>> d3962f425eea50cd648a963febe981a6fc5a4e7a # Check if pm2 is installed if ! command -v pm2 &> /dev/null then From 4de8542d0c729764d02edf24c2b8ed85f20cbc72 Mon Sep 17 00:00:00 2001 From: Ala Shaabana Date: Tue, 13 Jun 2023 16:43:47 -0400 Subject: [PATCH 3/3] Resolved merge conflict part 3 --- run.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/run.sh b/run.sh index 8df8112..48fdbbe 100755 --- a/run.sh +++ b/run.sh @@ -193,10 +193,7 @@ fi # Run the Python script with the arguments using pm2 echo "Running $script with the following arguments with pm2:" -<<<<<<< HEAD echo "pm2 start $script --name $proc_name --interpreter python3 -- ${args[@]}" -======= ->>>>>>> d3962f425eea50cd648a963febe981a6fc5a4e7a pm2 start "$script" --name $proc_name --interpreter python3 -- "${args[@]}" # Check if packages are installed.