diff --git a/scripts/cnode-helper-scripts/cnode.sh b/scripts/cnode-helper-scripts/cnode.sh index 459e41ce0..77ce671a5 100755 --- a/scripts/cnode-helper-scripts/cnode.sh +++ b/scripts/cnode-helper-scripts/cnode.sh @@ -61,6 +61,15 @@ pre_startup_sanity() { [[ $(find "${LOG_DIR}"/node*.json 2>/dev/null | wc -l) -gt 0 ]] && mv "${LOG_DIR}"/node*.json "${LOG_DIR}"/archive/ } +mithril_snapshot_download() { + [[ -z "${MITHRIL_CLIENT}" ]] && MITHRIL_CLIENT="${CNODE_HOME}"/scripts/mithril-client.sh + if [[ ! -f "${MITHRIL_CLIENT}" ]] || [[ ! -e "${MITHRIL_CLIENT}" ]]; then + echo "ERROR: Could not locate mithril-client.sh script or script is not executable. Skipping mithril snapshot download!!" + else + "${MITHRIL_CLIENT}" -d + fi +} + stop_node() { CNODE_PID=$(pgrep -fn "$(basename ${CNODEBIN}).*.--port ${CNODE_PORT}" 2>/dev/null) # env was only called in offline mode kill -2 ${CNODE_PID} 2>/dev/null @@ -131,6 +140,11 @@ if [[ "${DEPLOY_SYSTEMD}" == "Y" ]]; then fi pre_startup_sanity +# Download the latest mithril snapshot before starting node +if [[ "${MITHRIL_DOWNLOAD}" == "Y" ]]; then + mithril_snapshot_download +fi + # Run Node if [[ -f "${POOL_DIR}/${POOL_OPCERT_FILENAME}" && -f "${POOL_DIR}/${POOL_VRF_SK_FILENAME}" && -f "${POOL_DIR}/${POOL_HOTKEY_SK_FILENAME}" ]]; then exec "${CNODEBIN}" "${CPU_RUNTIME[@]}" run \ diff --git a/scripts/cnode-helper-scripts/deploy-as-systemd.sh b/scripts/cnode-helper-scripts/deploy-as-systemd.sh index 5c15e94fb..bd23d74c4 100755 --- a/scripts/cnode-helper-scripts/deploy-as-systemd.sh +++ b/scripts/cnode-helper-scripts/deploy-as-systemd.sh @@ -32,6 +32,20 @@ if [[ ${yn} = [Yy]* ]]; then ./submitapi.sh -d fi +if command -v mithril-signer >/dev/null 2>&1 ; then + echo -e "\e[32m~~ Mithril Signer ~~\e[0m" + echo "Deploy Mithril Signer as a systemd service? [y|n]" + read -rsn1 yn + if [[ ${yn} = [Yy]* ]]; then + ./mithril-signer.sh -d + else + if [[ -f /etc/systemd/system/${vname}-mithril-signer.service ]]; then + sudo systemctl disable ${vname}-mithril-signer.service + sudo rm -f /etc/systemd/system/${vname}-mithril-signer.service + fi + fi +fi + if command -v ogmios >/dev/null 2>&1 ; then echo -e "\e32m~~ Cardano Ogmios Server ~~\e[0m" echo "launches the ogmios.sh script to deploy ogmios" @@ -407,6 +421,7 @@ sudo systemctl daemon-reload [[ -f /etc/systemd/system/${vname}-cncli-validate.service ]] && sudo systemctl enable ${vname}-cncli-validate.service [[ -f /etc/systemd/system/${vname}-cncli-ptsendtip.service ]] && sudo systemctl enable ${vname}-cncli-ptsendtip.service [[ -f /etc/systemd/system/${vname}-cncli-ptsendslots.service ]] && sudo systemctl enable ${vname}-cncli-ptsendslots.service +[[ -f /etc/systemd/system/${vname}-mithril-signer.service ]] && sudo systemctl enable ${vname}-mithril-signer.service echo diff --git a/scripts/cnode-helper-scripts/env b/scripts/cnode-helper-scripts/env index 3db129e4b..46d55f628 100644 --- a/scripts/cnode-helper-scripts/env +++ b/scripts/cnode-helper-scripts/env @@ -80,6 +80,8 @@ #ASSET_POLICY_ID_FILENAME="policy.id" #CIP0094_POLL_URL="https://raw.githubusercontent.com/cardano-foundation/CIP-0094-polls/main/networks/polls.json" # URL for polls to vote against +#MITHRIL_DOWNLOAD="N" # (Y|N) Download latest Mithril snapshot + ###################################### # Do NOT modify code below # ###################################### @@ -798,6 +800,7 @@ set_default_vars() { [[ -z ${ASSET_POLICY_SCRIPT_FILENAME} ]] && ASSET_POLICY_SCRIPT_FILENAME="policy.script" [[ -z ${ASSET_POLICY_ID_FILENAME} ]] && ASSET_POLICY_ID_FILENAME="policy.id" [[ -z ${CIP0094_POLL_URL} ]] && CIP0094_POLL_URL="https://raw.githubusercontent.com/cardano-foundation/CIP-0094-polls/main/networks/polls.json" + [[ -z ${MITHRIL_DOWNLOAD} ]] && MITHRIL_DOWNLOAD="N" FG_BLACK='\e[30m' FG_RED='\e[31m' FG_GREEN='\e[32m' diff --git a/scripts/cnode-helper-scripts/guild-deploy.sh b/scripts/cnode-helper-scripts/guild-deploy.sh index 66d86c61d..d2bd63f11 100755 --- a/scripts/cnode-helper-scripts/guild-deploy.sh +++ b/scripts/cnode-helper-scripts/guild-deploy.sh @@ -61,7 +61,7 @@ versionCheck() { printf '%s\n%s' "${1//v/}" "${2//v/}" | sort -C -V; } #$1=avail usage() { cat <<-EOF >&2 - Usage: $(basename "$0") [-n ] [-p path] [-t ] [-b ] [-u] [-s [p][b][l][f][d][c][o][w][x]] + Usage: $(basename "$0") [-n ] [-p path] [-t ] [-b ] [-u] [-s [p][b][l][m][f][d][c][o][w][x]] Set up dependencies for building/using common tools across cardano ecosystem. The script will always update dynamic content from existing scripts retaining existing user variables @@ -74,6 +74,7 @@ usage() { p Install common pre-requisite OS-level Dependencies for most tools on this repo (Default: skip) b Install OS level dependencies for tools required while building cardano-node/cardano-db-sync components (Default: skip) l Build and Install libsodium fork from IO repositories (Default: skip) + m Download latest (released) binaries for mithril-signer, mithril-client (Default: skip) f Force overwrite entire content of scripts and config files (backups of existing ones will be created) (Default: skip) d Download latest (released) binaries for bech32, cardano-address, cardano-node, cardano-cli, cardano-db-sync and cardano-submit-api (Default: skip) c Install/Upgrade CNCLI binary (Default: skip) @@ -92,6 +93,7 @@ set_defaults() { [[ -z ${WANT_BUILD_DEPS} ]] && WANT_BUILD_DEPS='N' [[ -z ${FORCE_OVERWRITE} ]] && FORCE_OVERWRITE='N' [[ -z ${LIBSODIUM_FORK} ]] && LIBSODIUM_FORK='N' + [[ -z ${INSTALL_MITHRIL} ]] && INSTALL_MITHRIL='N' [[ -z ${INSTALL_CNCLI} ]] && INSTALL_CNCLI='N' [[ -z ${INSTALL_CWHCLI} ]] && INSTALL_CWHCLI='N' [[ -z ${INSTALL_OGMIOS} ]] && INSTALL_OGMIOS='N' @@ -489,6 +491,25 @@ download_cardanosigner() { fi } +# Download pre-built mithril-signer binary +download_mithril() { + echo -e "\nDownloading Mithril..." + pushd "${HOME}"/tmp >/dev/null || err_exit + # dynamic latest release updated automatically, uncomment and comment out the hardcoded release below if needed + # mithril_release="$(curl -s https://api.github.com/repos/input-output-hk/mithril/releases/latest | jq -r '.tag_name')" + # hardcoded latest release requiring a bump + mithril_release="2337.0" + echo -e "\n Downloading Mithril Signer/Client ${mithril_release}..." + rm -f mithril-signer mithril-client + curl -m 200 -sfL https://github.com/input-output-hk/mithril/releases/download/${mithril_release}/mithril-${mithril_release}-linux-x64.tar.gz -o mithril.tar.gz || err_exit " Could not download mithril's latest release archive from IO github!" + tar zxf mithril.tar.gz mithril-signer mithril-client &>/dev/null + rm -f mithril.tar.gz + [[ -f mithril-signer ]] || err_exit " mithril archive downloaded but binary (mithril-signer) not found after extracting package!" + [[ -f mithril-client ]] || err_exit " mithril archive downloaded but binary (mithril-client) not found after extracting package!" + mv -t "${HOME}"/.local/bin mithril-signer mithril-client + chmod +x "${HOME}"/.local/bin/* +} + # Create folder structure and set up permissions/ownerships setup_folder() { echo -e "\nCreating Folder Structure .." @@ -500,8 +521,14 @@ setup_folder() { echo -e "\nexport ${CNODE_VNAME}_HOME=${CNODE_HOME}" >> "${HOME}"/.bashrc fi - $sudo mkdir -p "${CNODE_HOME}"/files "${CNODE_HOME}"/db "${CNODE_HOME}"/guild-db "${CNODE_HOME}"/logs "${CNODE_HOME}"/scripts "${CNODE_HOME}"/scripts/archive "${CNODE_HOME}"/sockets "${CNODE_HOME}"/priv + $sudo mkdir -p "${CNODE_HOME}"/files "${CNODE_HOME}"/db "${CNODE_HOME}"/guild-db "${CNODE_HOME}"/logs "${CNODE_HOME}"/scripts "${CNODE_HOME}"/scripts/archive "${CNODE_HOME}"/sockets "${CNODE_HOME}"/priv "${CNODE_HOME}"/mithril $sudo chown -R "$U_ID":"$G_ID" "${CNODE_HOME}" 2>/dev/null + + if [[ ${INSTALL_MITHRIL} == 'Y' ]]; then + + $sudo mkdir -p "${CNODE_HOME}"/mithril/data-stores + $sudo chown -R "$U_ID":"$G_ID" "${CNODE_HOME}"/mithril 2>/dev/null + fi } # Download and update scripts for cnode @@ -591,6 +618,7 @@ parse_args() { [[ "${S_ARGS}" =~ "p" ]] && INSTALL_OS_DEPS="Y" [[ "${S_ARGS}" =~ "b" ]] && INSTALL_OS_DEPS="Y" && WANT_BUILD_DEPS="Y" [[ "${S_ARGS}" =~ "l" ]] && INSTALL_OS_DEPS="Y" && WANT_BUILD_DEPS="Y" && INSTALL_LIBSODIUM_FORK="Y" + [[ "${S_ARGS}" =~ "m" ]] && INSTALL_MITHRIL="Y" && WANT_BUILD_DEPS="Y" [[ "${S_ARGS}" =~ "f" ]] && FORCE_OVERWRITE="Y" && POPULATE_CNODE="F" [[ "${S_ARGS}" =~ "d" ]] && INSTALL_CNODEBINS="Y" [[ "${S_ARGS}" =~ "c" ]] && INSTALL_CNCLI="Y" @@ -613,6 +641,7 @@ main_flow() { [[ "${INSTALL_OS_DEPS}" == "Y" ]] && os_dependencies [[ "${WANT_BUILD_DEPS}" == "Y" ]] && build_dependencies [[ "${INSTALL_LIBSODIUM_FORK}" == "Y" ]] && build_libsodium + [[ "${INSTALL_MITHRIL}" == "Y" ]] && download_mithril [[ "${FORCE_OVERWRITE}" == "Y" ]] && POPULATE_CNODE="F" && populate_cnode [[ "${POPULATE_CNODE}" == "Y" ]] && populate_cnode [[ "${INSTALL_CNODEBINS}" == "Y" ]] && download_cnodebins diff --git a/scripts/cnode-helper-scripts/mithril-client.sh b/scripts/cnode-helper-scripts/mithril-client.sh new file mode 100644 index 000000000..728261746 --- /dev/null +++ b/scripts/cnode-helper-scripts/mithril-client.sh @@ -0,0 +1,193 @@ +#!/usr/bin/env bash +# shellcheck disable=SC2086 +#shellcheck source=/dev/null + +. "$(dirname $0)"/env offline + +###################################### +# User Variables - Change as desired # +# Common variables set in env file # +###################################### + +#MITHRILBIN="${HOME}"/.local/bin/mithril-client # Path for mithril-client binary, if not in $PATH + +###################################### +# Do NOT modify code below # +###################################### + +##################### +# Functions # +##################### + +usage() { + cat <<-EOF + + Usage: $(basename "$0") [-d] [-u] + + Cardano Mithril client wrapper script !! + -d Download latest Mithril snapshot + -u Update mithril environment file + -h Show this help text + + EOF +} + + +generate_environment_file() { + if [[ -n "${POOL_NAME}" ]] && [[ "${POOL_NAME}" != "CHANGE_ME" ]]; then + export ERA_READER_ADDRESS=https://raw.githubusercontent.com/input-output-hk/mithril/main/mithril-infra/configuration/${RELEASE}-${NETWORK_NAME,,}/era.addr + export ERA_READER_VKEY=https://raw.githubusercontent.com/input-output-hk/mithril/main/mithril-infra/configuration/${RELEASE}-${NETWORK_NAME,,}/era.vkey + bash -c "cat <<-'EOF' > ${CNODE_HOME}/mithril/mithril.env + KES_SECRET_KEY_PATH=${POOL_DIR}/${POOL_HOTKEY_SK_FILENAME} + OPERATIONAL_CERTIFICATE_PATH=${POOL_DIR}/${POOL_OPCERT_FILENAME} + NETWORK=${NETWORK_NAME,,} + RELEASE=${RELEASE} + AGGREGATOR_ENDPOINT=https://aggregator.${RELEASE}-${NETWORK_NAME,,}.api.mithril.network/aggregator + RUN_INTERVAL=60000 + DB_DIRECTORY=${CNODE_HOME}/db + CARDANO_NODE_SOCKET_PATH=${CARDANO_NODE_SOCKET_PATH} + CARDANO_CLI_PATH=${HOME}/.local/bin/cardano-cli + DATA_STORES_DIRECTORY=${CNODE_HOME}/mithril/data-stores + STORE_RETENTION_LIMITS=5 + ERA_READER_ADAPTER_TYPE=cardano-chain + ERA_READER_ADAPTER_PARAMS=$(jq -nc --arg address "$(wget -q -O - "${ERA_READER_ADDRESS}")" --arg verification_key "$(wget -q -O - "${ERA_READER_VKEY}")" '{"address": $address, "verification_key": $verification_key}') + GENESIS_VERIFICATION_KEY=$(wget -q -O - https://raw.githubusercontent.com/input-output-hk/mithril/main/mithril-infra/configuration/${RELEASE}-${NETWORK_NAME,,}/genesis.vkey) + PARTY_ID=$(cat ${POOL_DIR}/${POOL_ID_FILENAME}) + SNAPSHOT_DIGEST=latest + EOF" + else + bash -c "cat <<-'EOF' > ${CNODE_HOME}/mithril/mithril.env + NETWORK=${NETWORK_NAME,,} + RELEASE=${RELEASE} + AGGREGATOR_ENDPOINT=https://aggregator.${RELEASE}-${NETWORK_NAME,,}.api.mithril.network/aggregator + DB_DIRECTORY=${CNODE_HOME}/db + GENESIS_VERIFICATION_KEY=$(wget -q -O - https://raw.githubusercontent.com/input-output-hk/mithril/main/mithril-infra/configuration/${RELEASE}-${NETWORK_NAME,,}/genesis.vkey) + SNAPSHOT_DIGEST=latest + EOF" + fi + chown $USER:$USER "${CNODE_HOME}"/mithril/mithril.env +} + + +pre_startup_sanity() { + REQUIRED_PARAMETERS="Y" + if [[ ! -f "${CNODE_HOME}"/mithril/mithril.env ]]; then + echo "INFO: Mithril environment file not found, creating environment file.." + generate_environment_file && echo "INFO: Mithril environment file created successfully!!" + elif [[ "${UPDATE_ENVIRONMENT}" == "Y" ]]; then + echo "INFO: Updating mithril environment file.." + generate_environment_file && echo "INFO: Mithril environment file updated successfully!!" + fi + . "${CNODE_HOME}"/mithril/mithril.env + [[ -z "${NETWORK}" ]] && echo "ERROR: The NETWORK must be set before calling mithril-client!!" && REQUIRED_PARAMETERS="N" + [[ -z "${RELEASE}" ]] && echo "ERROR: Failed to set RELEASE variable, please check NETWORK variable in env file!!" && REQUIRED_PARAMETERS="N" + [[ -z "${CNODE_HOME}" ]] && echo "ERROR: The CNODE_HOME must be set before calling mithril-client!!" && REQUIRED_PARAMETERS="N" + [[ ! -d "${CNODE_HOME}" ]] && echo "ERROR: The CNODE_HOME directory does not exist, please check CNODE_HOME variable in env file!!" && REQUIRED_PARAMETERS="N" + [[ -z "${AGGREGATOR_ENDPOINT}" ]] && echo "ERROR: The AGGREGATOR_ENDPOINT must be set before calling mithril-client!!" && REQUIRED_PARAMETERS="N" + [[ -z "${GENESIS_VERIFICATION_KEY}" ]] && echo "ERROR: The GENESIS_VERIFICATION_KEY must be set before calling mithril-client!!" && REQUIRED_PARAMETERS="N" + [[ ! -x "${MITHRILBIN}" ]] && echo "ERROR: The MITHRILBIN variable does not contain an executable file, please check MITHRILBIN variable in env file!!" && REQUIRED_PARAMETERS="N" + [[ "${REQUIRED_PARAMETERS}" != "Y" ]] && exit 1 + export GENESIS_VERIFICATION_KEY + DOWNLOAD_SNAPSHOT="N" + REMOVE_DB_DIR="N" +} + +set_defaults() { + [[ -z "${MITHRILBIN}" ]] && MITHRILBIN="${HOME}"/.local/bin/mithril-client + if [[ -z "${NETWORK_NAME}" ]]; then + echo "ERROR: The NETWORK_NAME must be set before mithril-client can download snapshots!!" + exit 1 + else + case "${NETWORK_NAME,,}" in + mainnet|preprod|guild) + RELEASE="release" + ;; + preview) + RELEASE="pre-release" + ;; + *) + echo "ERROR: The NETWORK_NAME must be set to Mainnet, PreProd, Preview, Guild before mithril-client can download snapshots!!" + exit 1 + esac + fi + pre_startup_sanity +} + +check_db_dir() { + # If the DB directory does not exist then set DOWNLOAD_SNAPSHOT to Y + if [[ ! -d "${DB_DIRECTORY}" ]]; then + echo "INFO: The db directory does not exist.." + DOWNLOAD_SNAPSHOT="Y" + # If the DB directory is empty then set DOWNLOAD_SNAPSHOT to Y and REMOVE_DB_DIR to Y + elif [[ -d "${DB_DIRECTORY}" ]] && [[ -z "$(ls -A "${DB_DIRECTORY}")" ]] && [[ $(du -cs "${DB_DIRECTORY}"/* 2>/dev/null | awk '/total$/ {print $1}') -eq 0 ]]; then + echo "INFO: The db directory is empty.." + REMOVE_DB_DIR="Y" + DOWNLOAD_SNAPSHOT="Y" + else + echo "INFO: The db directory is not empty.." + fi +} + +remove_db_dir() { + # Mithril client errors if the db folder already exists, so remove it if it is empty + if [[ "${REMOVE_DB_DIR}" == "Y" ]]; then + echo "INFO: Removing empty db directory to prepare for snapshot download.." + rmdir "${DB_DIRECTORY}" + fi +} + +download_snapshot() { + if [[ "${DOWNLOAD_SNAPSHOT}" == "Y" ]]; then + echo "INFO: Downloading latest mithril snapshot.." + "${MITHRILBIN}" -v --aggregator-endpoint ${AGGREGATOR_ENDPOINT} snapshot download --download-dir ${CNODE_HOME} ${SNAPSHOT_DIGEST} + else + echo "INFO: Skipping snapshot download.." + fi +} + + +##################### +# Execution # +##################### + +# Parse command line options +while getopts :duh opt; do + case ${opt} in + d ) MITHRIL_DOWNLOAD="Y" ;; + u ) UPDATE_ENVIRONMENT="Y" ;; + h) + usage + exit 0 + ;; + \?) + echo "Invalid option: -${OPTARG}" >&2 + usage + exit 1 + ;; + :) + echo "Option -${OPTARG} requires an argument." >&2 + usage + exit 1 + ;; + esac +done + +#Deploy systemd if -d argument was specified +if [[ "${UPDATE_ENVIRONMENT}" == "Y" ]] && [[ "${MITHRIL_DOWNLOAD}" != "Y" ]]; then + set_defaults +elif [[ "${MITHRIL_DOWNLOAD}" == "Y" ]]; then + set_defaults + check_db_dir + remove_db_dir + download_snapshot +elif [[ "${UPDATE_ENVIRONMENT}" == "Y" ]] && [[ "${MITHRIL_DOWNLOAD}" == "Y" ]]; then + set_defaults + check_db_dir + remove_db_dir + download_snapshot +else + usage + exit 1 +fi + +exit 0 diff --git a/scripts/cnode-helper-scripts/mithril-relay.sh b/scripts/cnode-helper-scripts/mithril-relay.sh new file mode 100644 index 000000000..c395c232d --- /dev/null +++ b/scripts/cnode-helper-scripts/mithril-relay.sh @@ -0,0 +1,218 @@ +#!/bin/bash + +###################################### +# User Variables - Change as desired # +# Common variables set in env file # +###################################### + +RELAY_LISTENING_PORT=3132 + +###################################### +# Do NOT modify code below # +###################################### + +##################### +# Constants # +##################### + +BLOCK_PRODUCER_IP=() +RELAY_LISTENING_IP=() + +##################### +# Functions # +##################### + +# Usage menu +usage() { + cat <<-EOF + + $(basename "$0") [-d] [-l] + + Cardano Mithril relay wrapper script!! + -d Install squid and configure as a relay + -l Install nginx and configure as a load balancer + -h Show this help text + + EOF +} + +generate_nginx_conf() { + sudo bash -c "cat > /etc/nginx/nginx.conf <<'EOF' +worker_processes 1; + +events { + worker_connections 1024; +} + +http { + upstream mithril_relays { + $(for ip in "${RELAY_LISTENING_IP[@]}"; do + echo -e " server ${ip}:${RELAY_LISTENING_PORT};" + done) + } + + server { + listen ${SIDECAR_LISTENING_IP}:${RELAY_LISTENING_PORT}; + location / { + proxy_pass http://mithril_relays; + proxy_set_header Host \$host; + proxy_set_header X-Real-IP \$remote_addr; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + } + } +} +EOF" +} + +generate_squid_conf() { + # Write the squid config file + sudo bash -c "cat <<-'EOF' > /etc/squid/squid.conf + # Listening port (port 3132 is recommended) + http_port ${RELAY_LISTENING_PORT} + + EOF" + + # Write the ACLs for each relay IP address + sudo bash -c 'echo "# ACLs for IP of the block producers" >> /etc/squid/squid.conf' + for ip in "${BLOCK_PRODUCER_IP[@]}"; do + sudo bash -c "echo \"acl block_producer_ip src ${ip}\" >> /etc/squid/squid.conf" + done + + # Write the rest of the squid config file + sudo bash -c "cat <<-'EOF' >> /etc/squid/squid.conf + # ACL for aggregator endpoint + acl aggregator_domain dstdomain .mithril.network + + # ACL for SSL port only + acl SSL_port port 443 + + # Allowed traffic + http_access allow block_producer_ip aggregator_domain SSL_port + + # Do not disclose relay internal IP + forwarded_for delete + + # Turn off via header + via off + + # Deny request for original source of a request + follow_x_forwarded_for deny all + + # Anonymize request headers + request_header_access Authorization allow all + request_header_access Proxy-Authorization allow all + request_header_access Cache-Control allow all + request_header_access Content-Length allow all + request_header_access Content-Type allow all + request_header_access Date allow all + request_header_access Host allow all + request_header_access If-Modified-Since allow all + request_header_access Pragma allow all + request_header_access Accept allow all + request_header_access Accept-Charset allow all + request_header_access Accept-Encoding allow all + request_header_access Accept-Language allow all + request_header_access Connection allow all + request_header_access All deny all + + # Disable cache + cache deny all + + # Deny everything else + http_access deny all + EOF" +} + +# Parse command line arguments +while getopts :dlh opt; do + case ${opt} in + d) + # Install squid and make a backup of the config file + echo -e "\nInstalling squid proxy" + sudo apt-get update + sudo apt-get install -y squid + sudo cp /etc/squid/squid.conf /etc/squid/squid.conf.bak + + # Read the listening IP addresses from user input + while true; do + read -r -p "Enter the IP address of your Block Producer: " ip + BLOCK_PRODUCER_IP+=("${ip}") + read -r -p "Are there more block producers? (y/n) " yn + case ${yn} in + [Nn]*) break ;; + *) continue ;; + esac + done + + # Read the listening port from user input + read -r -p "Enter the relay's listening port (press Enter to use default 3132): " RELAY_LISTENING_PORT + RELAY_LISTENING_PORT=${RELAY_LISTENING_PORT:-3132} + echo "Using port ${RELAY_LISTENING_PORT} for relay's listening port." + generate_squid_conf + + # Restart squid and check status + echo -e "\nStarting Mithril relay (squid proxy)" + sudo systemctl restart squid + sudo systemctl status squid + + # Inform the user to create the appropriate firewall rule + for ip in "${RELAY_LISTENING_IP[@]}"; do + echo "Create the appropriate firewall rule: sudo ufw allow from ${ip} to any port ${RELAY_LISTENING_PORT} proto tcp" + done + ;; + l) + # Install nginx and configure load balancing + echo -e "\nInstalling nginx load balancer" + sudo apt-get update + sudo apt-get install -y nginx + + # Read the listening IP addresses from user input + while true; do + read -r -p "Enter the IP address of a relay: " ip + RELAY_LISTENING_IP+=("${ip}") + read -r -p "Are there more relays? (y/n) " yn + case ${yn} in + [Nn]*) break ;; + *) continue ;; + esac + done + + # Read the listening IP for the load balancer + read -r -p "Enter the IP address of the load balancer (press Enter to use default 127.0.0.1): " SIDECAR_LISTENING_IP + SIDECAR_LISTENING_IP=${SIDECAR_LISTENING_IP:-127.0.0.1} + echo "Using IP address ${SIDECAR_LISTENING_IP} for the load balancer configuration." + + # Read the listening port from user input + read -r -p "Enter the relay's listening port (press Enter to use default 3132): " RELAY_LISTENING_PORT + RELAY_LISTENING_PORT=${RELAY_LISTENING_PORT:-3132} + echo "Using port ${RELAY_LISTENING_PORT} for relay's listening port." + + # Generate the nginx configuration file + generate_nginx_conf + # Restart nginx and check status + echo -e "\nStarting Mithril relay sidecar (nginx load balancer)" + sudo systemctl restart nginx + sudo systemctl status nginx + ;; + h) + usage + exit 0 + ;; + \?) + echo "Invalid option: -${OPTARG}" >&2 + usage + exit 1 + ;; + :) + echo "Option -${OPTARG} requires an argument." >&2 + usage + exit 1 + ;; + esac +done + +# Display usage menu if no flags are provided +if [[ ${OPTIND} -eq 1 ]]; then + usage + exit 1 +fi diff --git a/scripts/cnode-helper-scripts/mithril-signer.sh b/scripts/cnode-helper-scripts/mithril-signer.sh new file mode 100755 index 000000000..cd5090743 --- /dev/null +++ b/scripts/cnode-helper-scripts/mithril-signer.sh @@ -0,0 +1,200 @@ +#!/usr/bin/env bash +# shellcheck disable=SC2086 +#shellcheck source=/dev/null + +. "$(dirname $0)"/env offline + +###################################### +# User Variables - Change as desired # +# Common variables set in env file # +###################################### + +#MITHRILBIN="${HOME}"/.local/bin/mithril-signer # Path for mithril-signer binary, if not in $PATH +#HOSTADDR=127.0.0.1 # Default Listen IP/Hostname for Mithril Signer Server + +###################################### +# Do NOT modify code below # +###################################### + +##################### +# Functions # +##################### + +usage() { + cat <<-EOF + + Usage: $(basename "$0") [-d] [-u] + + Cardano Mithril signer wrapper script !! + -d Deploy mithril-signer as a systemd service + -u Update mithril environment file + -h Show this help text + + EOF +} + +set_defaults() { + [[ -z "${MITHRILBIN}" ]] && MITHRILBIN="${HOME}"/.local/bin/mithril-signer + if [[ -z "${POOL_NAME}" ]] || [[ "${POOL_NAME}" == "CHANGE_ME" ]]; then + echo "ERROR: The POOL_NAME must be set before deploying mithril-signer as a systemd service!!" + exit 1 + else + case "${NETWORK_NAME,,}" in + mainnet|preprod|guild) + RELEASE="release" + ;; + preview) + RELEASE="pre-release" + ;; + *) + echo "ERROR: The NETWORK_NAME must be set to Mainnet, PreProd, Preview, or Guild before mithril-signer can be deployed!!" + exit 1 + esac + fi +} + +pre_startup_sanity() { + [[ ! -f "${MITHRILBIN}" ]] && MITHRILBIN="$(command -v mithril-signer)" + if [[ ! -S "${CARDANO_NODE_SOCKET_PATH}" ]]; then + echo "ERROR: Could not locate socket file at ${CARDANO_NODE_SOCKET_PATH}, the node may not have completed startup !!" + exit 1 + fi + # Move logs to archive + [[ -f "${LOG_DIR}"/mithril-signer.log ]] && mv "${LOG_DIR}"/mithril-signer.log "${LOG_DIR}"/archive/ +} + +get_relay_endpoint() { + read -r -p "Enter the IP address of the relay endpoint: " RELAY_ENDPOINT_IP + read -r -p "Enter the port of the relay endpoint (press Enter to use default 3132): " RELAY_PORT + RELAY_PORT=${RELAY_PORT:-3132} + echo "Using RELAY_ENDPOINT=${RELAY_ENDPOINT_IP}:${RELAY_PORT} for the Mithril signer relay endpoint." +} + +generate_environment_file() { + # Inquire about the relay endpoint + read -r -p "Are you using a relay endpoint? (y/n, press Enter to use default y): " ENABLE_RELAY_ENDPOINT + ENABLE_RELAY_ENDPOINT=${ENABLE_RELAY_ENDPOINT:-y} + if [[ "${ENABLE_RELAY_ENDPOINT}" == "y" ]]; then + get_relay_endpoint + else + echo "Using a naive Mithril configuration without a mithril relay." + fi + + # Generate the full set of environment variables required by Mithril signer use case + export ERA_READER_ADDRESS=https://raw.githubusercontent.com/input-output-hk/mithril/main/mithril-infra/configuration/${RELEASE}-${NETWORK_NAME,,}/era.addr + export ERA_READER_VKEY=https://raw.githubusercontent.com/input-output-hk/mithril/main/mithril-infra/configuration/${RELEASE}-${NETWORK_NAME,,}/era.vkey + sudo bash -c "cat <<-'EOF' > ${CNODE_HOME}/mithril/mithril.env + KES_SECRET_KEY_PATH=${POOL_DIR}/${POOL_HOTKEY_SK_FILENAME} + OPERATIONAL_CERTIFICATE_PATH=${POOL_DIR}/${POOL_OPCERT_FILENAME} + NETWORK=${NETWORK_NAME,,} + RELEASE=${RELEASE} + AGGREGATOR_ENDPOINT=https://aggregator.${RELEASE}-${NETWORK_NAME,,}.api.mithril.network/aggregator + RUN_INTERVAL=60000 + DB_DIRECTORY=${CNODE_HOME}/db + CARDANO_NODE_SOCKET_PATH=${CARDANO_NODE_SOCKET_PATH} + CARDANO_CLI_PATH=${HOME}/.local/bin/cardano-cli + DATA_STORES_DIRECTORY=${CNODE_HOME}/mithril/data-stores + STORE_RETENTION_LIMITS=5 + ERA_READER_ADAPTER_TYPE=cardano-chain + ERA_READER_ADAPTER_PARAMS=$(jq -nc --arg address "$(wget -q -O - "${ERA_READER_ADDRESS}")" --arg verification_key "$(wget -q -O - "${ERA_READER_VKEY}")" '{"address": $address, "verification_key": $verification_key}') + GENESIS_VERIFICATION_KEY=$(wget -q -O - https://raw.githubusercontent.com/input-output-hk/mithril/main/mithril-infra/configuration/${RELEASE}-${NETWORK_NAME,,}/genesis.vkey) + PARTY_ID=$(cat ${POOL_DIR}/${POOL_ID_FILENAME}) + SNAPSHOT_DIGEST=latest + EOF" && sudo chown $USER:$USER "${CNODE_HOME}"/mithril/mithril.env + + if [[ "${ENABLE_RELAY_ENDPOINT}" == "y" ]]; then + sudo bash -c "echo RELAY_ENDPOINT=http://${RELAY_ENDPOINT_IP}:${RELAY_PORT} >> ${CNODE_HOME}/mithril/mithril.env" + fi +} + +deploy_systemd() { + echo "Creating ${CNODE_VNAME}-mithril-signer systemd service environment file.." + if [[ ! -f "${CNODE_HOME}"/mithril/mithril.env ]]; then + generate_environment_file && echo "Mithril environment file created successfully!!" + fi + + echo "Deploying ${CNODE_VNAME}-mithril-signer as systemd service.." + sudo bash -c "cat <<-'EOF' > /etc/systemd/system/${CNODE_VNAME}-mithril-signer.service + [Unit] + Description=Cardano Mithril signer service + StartLimitIntervalSec=0 + Wants=network-online.target + After=network-online.target + BindsTo=${CNODE_VNAME}.service + After=${CNODE_VNAME}.service + + [Service] + Type=simple + Restart=always + RestartSec=5 + User=${USER} + EnvironmentFile=${CNODE_HOME}/mithril/mithril.env + ExecStart=/bin/bash -l -c \"exec ${HOME}/.local/bin/mithril-signer -vv\" + KillSignal=SIGINT + SuccessExitStatus=143 + StandardOutput=syslog + StandardError=syslog + SyslogIdentifier=${CNODE_VNAME}-mithril-signer + TimeoutStopSec=5 + KillMode=mixed + + [Install] + WantedBy=multi-user.target + EOF" && echo "${CNODE_VNAME}-mithril-signer.service deployed successfully!!" && sudo systemctl daemon-reload && sudo systemctl enable ${CNODE_VNAME}-mithril-signer.service +} + +################### +# Execution # +################### + +# Parse command line options +while getopts :duh opt; do + case ${opt} in + d ) DEPLOY_SYSTEMD="Y" ;; + u ) UPDATE_ENVIRONMENT="Y" ;; + h) + usage + exit 0 + ;; + \?) + echo "Invalid option: -${OPTARG}" >&2 + usage + exit 1 + ;; + :) + echo "Option -${OPTARG} requires an argument." >&2 + usage + exit 1 + ;; + esac +done + +# Check if env file is missing in current folder (no update checks as will mostly run as daemon), source env if present +[[ ! -f "$(dirname $0)"/env ]] && echo -e "\nCommon env file missing, please ensure latest guild-deploy.sh was run and this script is being run from ${CNODE_HOME}/scripts folder! \n" && exit 1 +. "$(dirname $0)"/env +case $? in + 1) echo -e "ERROR: Failed to load common env file\nPlease verify set values in 'User Variables' section in env file or log an issue on GitHub" && exit 1;; + 2) clear ;; +esac + +# Set defaults and do basic sanity checks +set_defaults +#Deploy systemd if -d argument was specified +if [[ "${DEPLOY_SYSTEMD}" == "Y" ]]; then + deploy_systemd && exit 0 + exit 2 +elif [[ "${UPDATE_ENVIRONMENT}" == "Y" ]]; then + generate_environment_file && echo "Environment file updated successfully!!" && exit 0 + exit 2 +elif [[ "${UPDATE_ENVIRONMENT}" == "Y" ]] && [[ "${DEPLOY_SYSTEMD}" == "Y" ]]; then + generate_environment_file && deploy_systemd && exit 0 + exit 2 +fi + +pre_startup_sanity + +# Run Mithril Signer Server +echo "Sourcing the Mithril Signer environment file.." +. "${CNODE_HOME}"/mithril/mithril.env +echo "Starting Mithril Signer Server.." +"${MITHRILBIN}" -vvv >> "${LOG_DIR}"/mithril-signer.log 2>&1