Skip to content

Instantly share code, notes, and snippets.

@wileyj
Last active November 6, 2023 21:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wileyj/9922af657ae8048cb67ba9621141e7e1 to your computer and use it in GitHub Desktop.
Save wileyj/9922af657ae8048cb67ba9621141e7e1 to your computer and use it in GitHub Desktop.
Script to setup and run a node as a Stacks bootstrap instance
#!/usr/bin/env bash
set -eo pipefail
set -Eo functrace
shopt -s expand_aliases
##
## Meant to be run manually or via cron
## ex cron:
## 00 * * * * /usr/local/bin/seed >> /tmp/seed-log
##
## set some defaults
## Optional: use verbose logging
VERBOSE=true
## Optional: use an auth user/key to bypass API rate limits in the format of "-u user:key"
AUTH=""
## Local file paths
LOCAL_VERSION="/stacks_version"
LOCAL_KEYFILE="/stacks_key"
LOCAL_PUBLIC_IPV4="/stacks_ipv4"
LOCAL_BINARY_DIR="/usr/local/bin"
LOCAL_BINARY_NAME="stacks-node"
LOCAL_BINARY="${LOCAL_BINARY_DIR}/${LOCAL_BINARY_NAME}"
LOCAL_KEY_SCRIPT="${LOCAL_BINARY_DIR}/key"
## stacks specific values
STACKS_SERVICE_USER="stacks"
STACKS_SERVICE_NAME="stacks"
STACKS_CONFIG_DIR="/etc/stacks-blockchain"
STACKS_CHAINSTATE_DIR="/stacks-blockchain"
STACKS_CONFIG_FILE="${STACKS_CONFIG_DIR}/Config.toml"
STACKS_UNIT_FILE="/etc/systemd/system/${STACKS_SERVICE_NAME}.service"
STACKS_RPC_PORT=20443
STACKS_P2P_PORT=20444
## Optional but recommended for keeping the keypair consistent (can be retrieved after 1st run from /stacks_key)
STACKS_PRIVATE_KEY=""
STACKS_PUBLIC_KEY=""
STACKS_RELEASE_URL="https://api.github.com/repos/stacks-network/stacks-blockchain/releases"
## configure logging format
alias log="logger"
alias log_error='logger "${ERROR}"'
alias log_warn='logger "${WARN}"'
alias log_info='logger "${INFO}"'
alias log_exit='exit_error "${EXIT_MSG}"'
if ${VERBOSE}; then
alias log='logger "$(date "+%D %H:%m:%S")" "Func:${FUNCNAME:-main}" "Line:${LINENO:-null}"'
alias log_info='logger "$(date "+%D %H:%m:%S")" "Func:${FUNCNAME:-main}" "Line:${LINENO:-null}" "${INFO}"'
alias log_warn='logger "$(date "+%D %H:%m:%S")" "Func:${FUNCNAME:-main}" "Line:${LINENO:-null}" "${WARN}"'
alias log_error='logger "$(date "+%D %H:%m:%S")" "Func:${FUNCNAME:-main}" "Line:${LINENO:-null}" "${ERROR}"'
alias log_exit='exit_error "$(date "+%D %H:%m:%S")" "Func:${FUNCNAME:-main}" "Line:${LINENO:-null}" "${EXIT_MSG}"'
fi
logger() {
if ${VERBOSE}; then
printf "%s %-30s %-10s %-10s %-25s %s\\n" "${1}" "${2}" "${3}" "${DEBUG}" "${4}" "${5}"
else
printf "%-25s %s\\n" "${1}" "${2}"
fi
}
exit_error() {
if ${VERBOSE}; then
printf "%s %-25s %-10s %-10s %-25s %s\\n\\n" "${1}" "${2}" "${DEBUG}" "${3}" "${4}" "${5}"
else
printf "%-25s %s\\n\\n" "${1}" "${2}"
fi
exit 1
}
if ! (sudo test -f "${LOCAL_VERSION}" && sudo test -f "${LOCAL_KEYFILE}" && sudo test -f "${LOCAL_PUBLIC_IPV4}" ); then
${VERBOSE} && log "Local state files are missing. Trying to install dependencies"
log "Installing system dependencies"
## install required packages
sudo apt-get install -y curl unzip nodejs npm jq sed > /dev/null 2>&1 || log_exit "Error installing required packages"
## install required npm packages
sudo npm install -g @stacks/encryption elliptic > /dev/null 2>&1 || log_exit "Error installing required npm modules"
fi
# Check for required binaries, exit if missing
for cmd in curl node file unzip sed; do
command -v "${cmd}" > /dev/null 2>&1 || log_exit "Missing command: ${cmd}"
done
## Only set these values after dependencies are installed and we've checked the binaries are in $PATH
NODE_PATH="$(npm root -g)"
## Retrieve the latest release version from github
REMOTE_VERSION=$(curl -sL ${AUTH} -H "Accept: application/vnd.github+json" ${STACKS_RELEASE_URL}/latest | jq -r .tag_name)
if [ "${REMOTE_VERSION}" == "" ];then
log "Error retrieving the remote version"
log_exit "Exiting"
fi
LOCAL_BINARY_ARCHIVE="/tmp/stacks-blockchain-${REMOTE_VERSION}.zip" ## this has to be defined after we have the remote_version
## if verbose is set, print out the variables we'll be using throughout the script
${VERBOSE} && log "NODE_PATH: ${NODE_PATH}"
${VERBOSE} && log "STACKS_RELEASE_URL: ${STACKS_RELEASE_URL}"
${VERBOSE} && log "REMOTE_VERSION: ${REMOTE_VERSION}"
${VERBOSE} && log "LOCAL_TAG: ${LOCAL_VERSION}"
${VERBOSE} && log "LOCAL_KEYFILE: ${LOCAL_KEYFILE}"
${VERBOSE} && log "LOCAL_BINARY_ARCHIVE: ${LOCAL_BINARY_ARCHIVE}"
${VERBOSE} && log "LOCAL_BINARY_DIR: ${LOCAL_BINARY_DIR}"
${VERBOSE} && log "LOCAL_BINARY_NAME: ${LOCAL_BINARY_NAME}"
${VERBOSE} && log "LOCAL_BINARY: ${LOCAL_BINARY}"
${VERBOSE} && log "SERVICE_USER: ${STACKS_SERVICE_USER}"
${VERBOSE} && log "SERVICE_NAME: ${STACKS_SERVICE_NAME}"
## Install a simple node script to create a stacks keypair
install_seed_script() {
## create/recreate the script every runtime
log "Creating file: ${LOCAL_KEY_SCRIPT}"
sudo bash -c 'cat <<-EOF> '"${LOCAL_KEY_SCRIPT}"'
#!/usr/bin/env node
const EC = require("elliptic").ec;
const secp256k1 = new EC("secp256k1");
const enc = require("@stacks/encryption");
const process = require("process");
const key = secp256k1.genKeyPair();
while (true) {
const key_hex = key.getPrivate().toString("hex");
if (key_hex.length != 64) {
continue;
}
break;
}
try {
const privateKey = key.getPrivate().toString("hex");
const publicKey = enc.getPublicKeyFromPrivate(privateKey);
process.stdout.write([publicKey, ":", privateKey].join(""));
} catch {
return process.exit(1);
}
return process.exit(0);
EOF'
## set the script as executable
${VERBOSE} && log "Setting file permissions on ${LOCAL_KEY_SCRIPT}"
sudo chmod 755 "${LOCAL_KEY_SCRIPT}" || log_exit "Error creating script: ${LOCAL_KEY_SCRIPT}"
return 0
}
## Install the systemd unit for stacks
install_unit_file() {
## create/recreate the unit file every runtime
log "Creating unit file: ${STACKS_UNIT_FILE}"
sudo bash -c 'cat <<-EOF> '"${STACKS_UNIT_FILE}"'
## Modeled after https://github.com/bitcoin/bitcoin/blob/master/contrib/init/bitcoind.service
[Unit]
Description=Stacks Blockchain
# https://www.freedesktop.org/wiki/Software/systemd/NetworkTarget/
After=network-online.target
Wants=network-online.target
ConditionFileIsExecutable=LOCAL_BINARY
ConditionPathExists=STACKS_CONFIG_FILE
ConditionPathIsDirectory=STACKS_CHAINSTATE_DIR
[Service]
ExecStart=LOCAL_BINARY start --config=STACKS_CONFIG_FILE
# Make sure the config directory is readable by the service user
PermissionsStartOnly=true
ExecStartPre=/bin/chgrp stacks STACKS_CONFIG_DIR
# Process management
####################
PIDFile=/run/stacks-blockchain/stacks-blockchain.pid
Restart=no
TimeoutStopSec=900
KillSignal=SIGINT
SendSIGKILL=no
# Directory creation and permissions
####################################
# Run as SERVICE_USER:SERVICE_USER
User=STACKS_SERVICE_USER
Group=STACKS_SERVICE_USER
# /run/stacks-blockchain
RuntimeDirectory=stacks-blockchain
RuntimeDirectoryMode=0710
# /etc/stacks-blockchain
ConfigurationDirectory=stacks-blockchain
ConfigurationDirectoryMode=0710
# Hardening measures
####################
# Provide a private /tmp and /var/tmp.
PrivateTmp=true
# Mount /usr, /boot/ and /etc read-only for the process.
ProtectSystem=full
# Deny access to /home, /root and /run/user
ProtectHome=true
# Disallow the process and all of its children to gain
# new privileges through execve().
NoNewPrivileges=true
# Use a new /dev namespace only populated with API pseudo devices
# such as /dev/null, /dev/zero and /dev/random.
PrivateDevices=true
# Deny the creation of writable and executable memory mappings.
MemoryDenyWriteExecute=true
SystemCallArchitectures=native
[Install]
WantedBy=multi-user.target
EOF'
if ! sudo test -f "${STACKS_UNIT_FILE}";then
log_exit "Error creating unit file: ${STACKS_UNIT_FILE}"
fi
## replace some hardcoded values in the above file with variables from this script
${VERBOSE} && log "Substitute unit file strings with variables"
sudo sed -i -e "s|STACKS_SERVICE_USER|${STACKS_SERVICE_USER}|g" "${STACKS_UNIT_FILE}" || log_exit "Error sed'ing 'SERVICE_USER' in ${STACKS_UNIT_FILE}"
sudo sed -i -e "s|STACKS_CONFIG_DIR|${STACKS_CONFIG_DIR}|g" "${STACKS_UNIT_FILE}" || log_exit "Error sed'ing 'STACKS_CONFIG_DIR' in ${STACKS_UNIT_FILE}"
sudo sed -i -e "s|STACKS_CHAINSTATE_DIR|${STACKS_CHAINSTATE_DIR}|g" "${STACKS_UNIT_FILE}" || log_exit "Error sed'ing 'STACKS_CHAINSTATE_DIR' in ${STACKS_UNIT_FILE}"
sudo sed -i -e "s|STACKS_CONFIG_FILE|${STACKS_CONFIG_FILE}|g" "${STACKS_UNIT_FILE}" || log_exit "Error sed'ing 'STACKS_CONFIG_FILE' in ${STACKS_UNIT_FILE}"
sudo sed -i -e "s|LOCAL_BINARY|${LOCAL_BINARY}|g" "${STACKS_UNIT_FILE}" || log_exit "Error sed'ing 'LOCAL_BINARY' in ${STACKS_UNIT_FILE}"
## set the unit's file permissions
${VERBOSE} && log "Setting file permissions on ${STACKS_UNIT_FILE}"
sudo chmod 644 "${STACKS_UNIT_FILE}" || log_exit "Error setting permissions on ${STACKS_UNIT_FILE}"
## reload systemd and enable the unit
${VERBOSE} && log "Reloading systemd"
sudo systemctl daemon-reload > /dev/null 2>&1 || log_exit "Error reloading systemd"
${VERBOSE} && log "Enabling ${STACKS_SERVICE_NAME} on boot"
sudo systemctl enable ${STACKS_SERVICE_NAME} > /dev/null 2>&1 || log_exit "Error enabling ${STACKS_SERVICE_NAME} on boot"
log "Installed and enabled systemd unit"
return 0
}
## Install the stacks Config.toml
install_stacks_config() {
private_key=""
public_key=""
local_public_ipv4=""
## check for an existing keyfile to use values from
if ! sudo test -f "${LOCAL_KEYFILE}"; then
if [ "${STACKS_PRIVATE_KEY}" != "" -a "${STACKS_PUBLIC_KEY}" != "" ];then
## use hard-coded values if they are defined and local keyfile is missing
log "Creating keyfile from hardcoded stacks keypair"
sudo sh -c "echo -n ${STACKS_PUBLIC_KEY}:${STACKS_PRIVATE_KEY} > ${LOCAL_KEYFILE}" || log_exit "Error storing version in: ${LOCAL_KEYFILE}"
else
## create a new keyfile with new keypair from script in install_seed_script
log "Creating new stacks keypair"
sudo sh -c "NODE_PATH=${NODE_PATH} node ${LOCAL_KEY_SCRIPT} > ${LOCAL_KEYFILE}" || log_exit "Error saving key to: ${LOCAL_KEYFILE}"
fi
fi
## ensure the keyfile has the correct permissions
sudo chmod 600 ${LOCAL_KEYFILE} || log_exit "Error setting permissions: ${LOCAL_KEYFILE}"
## retrieve the keys from the (now) existing file
public_key=$(sudo cat ${LOCAL_KEYFILE} | cut -f1 -d ":")
private_key=$(sudo cat ${LOCAL_KEYFILE} | cut -f2 -d ":")
if [ "${private_key}" == "" ]; then
log_exit "Error retrieving private key from: ${LOCAL_KEYFILE}"
fi
${VERBOSE} && log "using private_key: ${private_key}"
${VERBOSE} && log "using public_key: ${public_key}"
## retrieve the host's public IP
## public_ipv4=$(curl -sL https://ipinfo.io/ip) ## non-aws hosts
public_ipv4=$(curl -sL http://169.254.169.254/latest/meta-data/public-ipv4) ## aws hosts, http only
if [ -f "${LOCAL_PUBLIC_IPV4}" ]; then
local_public_ipv4=$(sudo cat ${LOCAL_PUBLIC_IPV4})
fi
if [ "${public_ipv4}" != "${local_public_ipv4}" ];then
${VERBOSE} && log "Public IPv4 do not match"
fi
## if the config file does not exist or the public ip has changed, (over)write the config
if [ "${public_ipv4}" != "${local_public_ipv4}" ] || ! (sudo test -f "${STACKS_CONFIG_FILE}" ); then
log "Creating config file: ${STACKS_CONFIG_FILE}"
sudo bash -c 'cat <<-EOF> '"${STACKS_CONFIG_FILE}"'
[node]
working_dir = "STACKS_CHAINSTATE_DIR"
rpc_bind = "0.0.0.0:STACKS_RPC_PORT"
p2p_bind = "0.0.0.0:STACKS_P2P_PORT"
data_url = "http://PUBLIC_IPV4:STACKS_RPC_PORT"
p2p_address = "PUBLIC_IPV4:STACKS_P2P_PORT"
local_peer_seed = "PRIVATE_KEY"
bootstrap_node = "02196f005965cebe6ddc3901b7b1cc1aa7a88f305bb8c5893456b8f9a605923893@seed.mainnet.hiro.so:20444,02539449ad94e6e6392d8c1deb2b4e61f80ae2a18964349bc14336d8b903c46a8c@cet.stacksnodes.org:20444,02ececc8ce79b8adf813f13a0255f8ae58d4357309ba0cedd523d9f1a306fcfb79@sgt.stacksnodes.org:20444,0303144ba518fe7a0fb56a8a7d488f950307a4330f146e1e1458fc63fb33defe96@est.stacksnodes.org:20444"
name = "Seed"
[burnchain]
chain = "bitcoin"
mode = "mainnet"
peer_host = "bitcoin.mainnet.stacks.org"
username = "stacks"
password = "foundation"
rpc_port = 8332
peer_port = 8333
[connection_options]
public_ip_address = "PUBLIC_IPV4:STACKS_P2P_PORT"
read_only_call_limit_write_length = 0
read_only_call_limit_read_length = 100000
read_only_call_limit_write_count = 0
read_only_call_limit_read_count = 30
read_only_call_limit_runtime = 1000000000
EOF'
## replace some hardcoded values in the above file with variables from this script
${VERBOSE} && log "Substitute config file strings with variables"
sudo sed -i -e "s|STACKS_RPC_PORT|${STACKS_RPC_PORT}|g" "${STACKS_CONFIG_FILE}" || log_exit "Error sed'ing 'RPC_PORT' in ${STACKS_CONFIG_FILE}"
sudo sed -i -e "s|STACKS_P2P_PORT|${STACKS_P2P_PORT}|g" "${STACKS_CONFIG_FILE}" || log_exit "Error sed'ing 'P2P_PORT' in ${STACKS_CONFIG_FILE}"
sudo sed -i -e "s|STACKS_CHAINSTATE_DIR|${STACKS_CHAINSTATE_DIR}|g" "${STACKS_CONFIG_FILE}" || log_exit "Error sed'ing 'STACKS_CHAINSTATE_DIR' in ${STACKS_CONFIG_FILE}"
sudo sed -i -e "s|PUBLIC_IPV4|${public_ipv4}|g" "${STACKS_CONFIG_FILE}" || log_exit "Error sed'ing 'PUBLIC_IPV4' in ${STACKS_CONFIG_FILE}"
sudo sed -i -e "s|PRIVATE_KEY|${private_key}|g" "${STACKS_CONFIG_FILE}" || log_exit "Error sed'ing 'PRIVATE_KEY' in ${STACKS_CONFIG_FILE}"
if ! sudo test -f "${STACKS_CONFIG_FILE}";then
log_exit "Error creating config file: ${STACKS_CONFIG_FILE}"
fi
sudo sh -c "echo ${public_ipv4} > ${LOCAL_PUBLIC_IPV4}" || log_exit "Error storing public ipv4 in: ${LOCAL_PUBLIC_IPV4}"
if is_stacks_running; then
${VERBOSE} && log "Stopping ${STACKS_SERVICE_NAME} after config change"
## The stacks binary is running, stop it. the last step in the script will restart the pid, no need to do it here
run_systemctl "stop"
fi
fi
## change the group to the service user (will need to have read access to this file when binary is started)
sudo chgrp "${STACKS_SERVICE_USER}" "${STACKS_CONFIG_FILE}" || log_exit "Error setting group on: ${STACKS_CONFIG_FILE}"
return 0
}
## Create the user to own the pid and files/dirs
create_user(){
## check if the user exists
if [ ! $(getent passwd ${STACKS_SERVICE_USER}) ]; then
## create the service user with a bash shell using the chainstate dir as $HOME
sudo useradd "${STACKS_SERVICE_USER}" -s /usr/bin/bash -m -d "${STACKS_CHAINSTATE_DIR}" || log_exit "Error creating user: ${STACKS_SERVICE_USER}"
log "Created user: ${STACKS_SERVICE_USER}"
else
${VERBOSE} && log "User already exists: ${STACKS_SERVICE_USER}"
fi
return 0
}
## create the expected dirs if they don't exist
create_dirs() {
dirs=(
${STACKS_CONFIG_DIR}
${STACKS_CHAINSTATE_DIR}
)
for dir in "${dirs[@]}"; do
## if the dir is missing, create it
if ! sudo test -d "${dir}";then
log "Creating missing dir: $dir"
sudo mkdir -p "${dir}" || log_exit "Error creating dir: ${dir}"
## set the ownership only if we're createing the dir
sudo chown -R "${STACKS_SERVICE_USER}" "${dir}" || log_exit "Error setting ownership on: ${dir}"
fi
## Set permissions on the dirs (regardless if they were just created)
log "Setting permissions on: ${dir}"
if [ "${dir}" == "${STACKS_CONFIG_DIR}" ];then
${VERBOSE} && log "Setting permissions on: ${dir}"
sudo chmod 710 "${dir}" || log_exit "Error setting permissions on: ${dir}"
fi
## set the group ownership of the dir (less relevant for the chainstate, but important for the config dir/file)
log "Setting ownership on: ${dir}"
sudo chgrp "${STACKS_SERVICE_USER}" "${dir}" || log_exit "Error setting group on: ${dir}"
done
return 0
}
## Compare the remote version to a recorded local version file
check_version() {
## Check that the local version file exists
if [ ! -f "${LOCAL_VERSION}" ]; then
log "Version file missing: ${LOCAL_VERSION}"
return 0
fi
## compare the contents of the local version file vs the remote version
if [ "$(cat ${LOCAL_VERSION})" != "${REMOTE_VERSION}" ];then
# tags do not match
log "Versions do not match"
${VERBOSE} && log " local version: $(cat ${LOCAL_VERSION})"
${VERBOSE} && log " remote version: ${REMOTE_VERSION}"
return 0
else
log "Local and remote versions match"
${VERBOSE} && log " local version: $(cat ${LOCAL_VERSION})"
${VERBOSE} && log " remote version: ${REMOTE_VERSION}"
fi
return 1
}
## Check if the binary is running via systemd
is_stacks_running() {
sudo systemctl status "${STACKS_SERVICE_NAME}" > /dev/null 2>&1
if [[ "${?}" -eq 0 ]]; then
## service is running
return 0
fi
${VERBOSE} && log "${STACKS_SERVICE_NAME} service is not running"
return 1
}
## Execute systemcl command
run_systemctl(){
cmd="${1}"
${VERBOSE} && log "Running: systemctl sudo systemctl ${cmd} ${STACKS_SERVICE_NAME}"
sudo systemctl "${cmd}" "${STACKS_SERVICE_NAME}" > /dev/null 2>&1 || log_exit "Error Running: sudo systemctl ${cmd} ${STACKS_SERVICE_NAME}"
return 0
}
## Confirm if a filetype matches what is expected (uses an arg for matching file types)
check_filetype() {
file="${1}"
type="${2}"
if [ -f "${file}" ]; then
## check the filetype using the provided args
file -zEb "${file}" | grep "${type}" > /dev/null 2>&1
if [ "${?}" == "0" ]; then
${VERBOSE} && log "File matches expected type: ${file} (${type})"
return 0
fi
## File did not match what was expected in $2
${VERBOSE} && log "File does not match expected type: ${file} (${type})"
return 1
fi
## filetype matched what was expected
${VERBOSE} && log "File not found: ${file}"
return 1
}
## Download the stacks binary if the local version doesn't match the remote version (or the local version file is missing)
download_binary() {
## check if the file exists and is a zip archive
if ! check_filetype "${LOCAL_BINARY_ARCHIVE}" "Zip archive data"; then
${VERBOSE} && log "Downloading binary archive"
archive_url=$(curl -sL ${AUTH} ${STACKS_RELEASE_URL}/latest | jq -r '.assets[] | { name, browser_download_url } | select((.name == "linux-glibc-x64.zip")) | {browser_download_url}| .[]')
## download the zip archive since it does not exist, or it is not a zip file
curl -L ${AUTH} -# "${archive_url}" -o "${LOCAL_BINARY_ARCHIVE}" || log_exit "Error downloading binary archive: ${LOCAL_BINARY_ARCHIVE}"
## check the downloaded file
if ! check_filetype "${LOCAL_BINARY_ARCHIVE}" "Zip archive data"; then
## archive either does not exist or is not a zip file
log_exit "Error downloading archive: ${LOCAL_BINARY_ARCHIVE}"
else
log "Archive downloaded: ${LOCAL_BINARY_ARCHIVE}"
fi
fi
# Archive already exists and is a zipfile. no need to re-download it
return 0
}
## Extract the binary from the zip archive to /usr/local/bin
extract_binary() {
## extract the binary from the zip archive to LOCAL_BINARY_DIR/LOCAL_BINARY_NAME
sudo unzip -Djqo "${LOCAL_BINARY_ARCHIVE}" "${LOCAL_BINARY_NAME}" -d "${LOCAL_BINARY_DIR}" || log_exit "Error extracting archive: ${LOCAL_BINARY_ARCHIVE}"
## confirm that the extracted file is the expected filetype
if ! check_filetype "${LOCAL_BINARY}" "ELF 64-bit LSB pie executable, x86-64"; then
log_exit "Exiting - File (${LOCAL_BINARY}) does not match expected type"
fi
${VERBOSE} && log "Binary extracted to: ${LOCAL_BINARY}"
## save the version to a local file for future comparison
sudo sh -c "echo ${REMOTE_VERSION} > ${LOCAL_VERSION}" || log_exit "Error storing version in: ${LOCAL_VERSION}"
return 0
}
## Run these functions every time (only `create_user` and `create_dirs` has to be run in order)
create_user ## create the user binary will run as
create_dirs ## create the required dirs
install_seed_script ## install the script to generate a public key
install_unit_file ## install the systemd unit
install_stacks_config ## create the stacks config
## check if the remote version matches the local version file
if check_version; then
## if there is no match, download the binary archive
if download_binary; then
## check if binary is running
if is_stacks_running; then
## The stacks binary is running, stop it
run_systemctl "stop"
fi
## Extract the stacks-node binary file
if extract_binary && ! is_stacks_running; then
## Start the binary
run_systemctl "start"
fi
fi
fi
if ! is_stacks_running; then
## Binary is not running, start it. This will work to start a dead pid if something unexpectedly killed it
run_systemctl "start"
fi
if is_stacks_running; then
## Confirm the binary is running before exiting
log "Successfully exiting"
exit 0
else
log "service not running"
fi
## Fail with an error if the binary is still not running
exit 1
@wileyj
Copy link
Author

wileyj commented Sep 7, 2023

Some notes:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment