Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,22 @@ Once you have your wallet ready for validation, you can start the foundation val
$ python3 validators/openvalidators/neuron.py --wallet.name <your-wallet-name> --wallet.hotkey <your-wallet-hot-key>
```

# Automatic Mode
You can run the validator with automatic execution and updates so that it will remain up to date with the latest changes without you needing to continuously update it manually.

The script `run.sh` in the root of this repository accomplishes this in conjuction with PM2.

To do this, first ensure you have installed the [`jq` package](https://jqlang.github.io/jq/) on your system.

On Ubuntu: `sudo apt update && sudo apt install jq`
On OS X: `brew update && brew install jq`

Once you have installed `jq`, you can start the validator in automatic mode by running the following command:

```bash
$ pm2 start autorun.sh -- script validators/openvalidators/neuron.py --wallet.name <your-wallet-name> --wallet.hotkey <your-wallet-hot-key>
```

# Real-time monitoring with wandb integration
By default, the validator sends data to wandb, allowing users to monitor running validators and access key metrics in real time, such as:
- Gating model loss
Expand Down
255 changes: 255 additions & 0 deletions run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
#!/bin/bash

# Initialize variables
script=""
autoRunLoc=$(readlink -f "$0")
proc_name="auto_run_validator"
args=()
version_location="./openvalidators/__init__.py"
version="__version__"

args=$@

# 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 ;;
--*) args+=("$1=$2"); shift ;;
*) echo "Unknown parameter passed: $1"; exit 1 ;;
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 "${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 ../

# 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 "${args[@]}"
pm2 start "$script" --name $proc_name --interpreter python3 -- "${args[@]}"

# 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