Skip to content

Commit

Permalink
Support for Mithril Signer deployment. (#1693)
Browse files Browse the repository at this point in the history
Adds support to download, install, and set up a mithril-signer for the appropriate network. Includes changes to `deploy-as-systemd.sh` to provide an option to run it as a Systemd service. 

## New scripts

### `mithril-client.sh` 
* Opt `-d` downloads the latest mithril snapshot
  * If the environment file does not exist it will create it.
* Opt `-u` creates or updates the environment file.
  * If the POOL_NAME is undefined or **CHANGE_ME** will create a minimal environment suitable for mithril client
  * If the POOL_NAME is defined will create a complete environment suitable for mithril signer
    * Presumes a naive deployment without mithril relay for automated environment setup on first start
    * Use either `deploy-as-systemd.sh`, or `mithril-signer.sh -u` directly, to define a complex mithril environment with a mithril relay (or the sidecar)

### `mithril-signer.sh` 
* follows the `ogmios.sh` format such that it can be used to start the mithril signer.
* Opt `-d` sets up the Systemd service unit.
  * If the environment file does not exist it will create it.
* Opt `-u` creates or updates the environment file.
  * uses read to determine if naive deployment or use a mithril relay (or the sidecar) IP and port to set RELAY_ENDPOINT

### `mithril-relay.sh`
* Opt `-d`
  * installs squid
  * uses read to gather variables for block producer IP and relay port.
  * Creates a squid.conf for a reverse proxy.
    * applies an ACL in the config for each block producer.
  * Starts the squid systemd service.
* Opt `-l`
  * installs nginx
  * uses read to gather variables for relay IP address(es), relay port, and IP to bind sidecar  (Relay port shared between all relays and sidecar)
  * Creates an nginx.conf load balancing over relays.
  * starts nginx systems service.
## Additional Details
* Increases storage requirements for binaries by ~42MB.
* Currently uses a static `mithril_release` set to **2337.0**.
  * Includes a commented-out option to obtain the latest release via tag_name, similar to cardano-signer.
  * Open to the preferred method suggested.

The mithril relay and squid configuration comes from Mithril docs. The HA setup via an nginx sidecar is a Proof of Concept at the moment. I have tested with a single relay, but not yet with the sidecar and multiple relays.
  • Loading branch information
TrevorBenson authored Oct 31, 2023
1 parent 2ce4881 commit 934f059
Show file tree
Hide file tree
Showing 7 changed files with 674 additions and 2 deletions.
14 changes: 14 additions & 0 deletions scripts/cnode-helper-scripts/cnode.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 \
Expand Down
15 changes: 15 additions & 0 deletions scripts/cnode-helper-scripts/deploy-as-systemd.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions scripts/cnode-helper-scripts/env
Original file line number Diff line number Diff line change
Expand Up @@ -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 #
######################################
Expand Down Expand Up @@ -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'
Expand Down
33 changes: 31 additions & 2 deletions scripts/cnode-helper-scripts/guild-deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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 <mainnet|preprod|guild|preview>] [-p path] [-t <name>] [-b <branch>] [-u] [-s [p][b][l][f][d][c][o][w][x]]
Usage: $(basename "$0") [-n <mainnet|preprod|guild|preview>] [-p path] [-t <name>] [-b <branch>] [-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
Expand All @@ -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)
Expand All @@ -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'
Expand Down Expand Up @@ -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 .."
Expand All @@ -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
Expand Down Expand Up @@ -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"
Expand All @@ -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
Expand Down
193 changes: 193 additions & 0 deletions scripts/cnode-helper-scripts/mithril-client.sh
Original file line number Diff line number Diff line change
@@ -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
Loading

0 comments on commit 934f059

Please sign in to comment.