#!/bin/bash # declare the variables required for this script function declareVars() { # this group will be created for docker group_to_add=docker # this is the url for the blockchain archive blockchain_7zip_url="https://archive.metervalidatorbot.com/archive" # if this flag is true we will download the chain to bootstrap the node installation download_chain_flag='false' # regenerate the public regenerate_public_key='false' # if this flag is true we will force remove any related containers that the end user may have attempted to install # themselves force_removal_flag='false' # if this flag is true we will download and install the watchtower container watchtower_install_flag='false' # force Y response to all messages assume_yes='false' # yes and no options accepted at keyboard prompts yes_option="y" no_option="n" install_directory="$HOME/meter_main_data" # mega installer package - blank by default mega_installer_package='' # by default we will remove the mega application after the script has finished executing remove_mega_after_archive_download='true' } # outputAscii outputs the ascii text function outputAscii() { echo "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM 0000000000000000|0xffbeddcaa68dc953ee4f3d040ab83cb0ac65498b|000000000000000 MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMMMMMMMMWNXKOkxdoollllooddxO0XNWMMMMMMMMMMMMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMMMMWXOdl:,'.................,;cox0XWMMMMMMMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMWN0dc,.............................,cx0NMMMMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMN0d:'.......';:lodxxkkkkkxxdol:,'.......':d0NMMMMMMMMMMMMMMM MMMMMMMMMMMMWNkc'......':ok0XWWMMMMMMMMMMMMMWWX0xo:'......'ckXMMMMMMMMMMMMM MMMMMMMMMMMNk:......,lxKNWMMMMMMMMMMMMMMMMMMMMMMMWN0xc'......:kNMMMMMMMMMMM MMMMMMMMMW0c......:xKWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMN0o;.....'c0WMMMMMMMMM MMMMMMMMXd,.....:kXMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWXx;.....,xNMMMMMMMM MMMMMMMKl.....,dXMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWXd,....'oXMMMMMMM MMMMMMKc.....c0WMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWO:.....lXMMMMMM MMMMMXl.....lKMMMMMMMMMMMMMMMMNKXMMMMMMMMMMMMMMMWXKNMMMMMMMMWKc....;xNMMMMM MMMMNd'....lXMMMMMMMMMMMMMMWKx:c0MMMMMMMMMMMWN0xl,c0MMMMMMMMMWXxdxOKNWMMWWW MMMWO,....:0MMMMMMMMMMMMMNOo,..cKMMMMMMMMWXOo:'...lXMMMMMMMMMMMMMWWXKOO0KNW MMMXl....'xWMMMMMMMMMMWXxc'....oNMMMWWN0xc,.......oNMMMMMMMWNX0kdolodkKNWMM MMM0;....cKMMMMMMMMMN0o;......'kWNKkoc;'.........'xWMWNKOxol:,',cdOXWMWWMMM MMWk,....oNMMMMMMWXkc'........'ldc,........'.....'ldoc;'...';okKWMWX0do0MMM MMWx'....xWMMMMN0o;....................':dkl'...........;lx0NWMMW0l;'.'xWMM MMWx'..'lKMMWXkc'.....,:;..........;loxKNWKc........,:dOXWMMMMMMNo....'xWMM MMMk;;d0WMWKd;....,cdOXKc......':oOXWMMMMWx'....';okKNMMMMMMMMMMXl....'kMMM MMMX0XWWNOl,..,cdOXWMMM0;...,cx0NWMMMMMMMKc..,cx0NWMMMMMMMMMMMMMK:....;0MMM MMMMMWKx:,;cdOXWMMMMMMWx;;okXWMMMMMMMMMMWOodOXWMMMMMMMMMMMMMMMMWk'....oNMMM MMMNOdcldOXWMMMMMMMMMMWK0NWMMMMMMMMMMMMMWNWMMMMMMMMMMMMMMMMMMMM0:....,OWMMM WN0kkOXWMWNKNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMKc.....oNMMMM NXXWMMWKxl;,lXMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMKl.....cKMMMMM MMMMMMXo.....c0WMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMW0c.....cKMMMMMM MMMMMMWKl.....,dXWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMXx;.....lKMMMMMMM MMMMMMMMXd,.....:kNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNk:.....,dXMMMMMMMM MMMMMMMMMW0c......:xXWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWKx:......cOWMMMMMMMMM MMMMMMMMMMMNk:......,okXWMMMMMMMMMMMMMMMMMMMMMMMMMWXkl,......:kNMMMMMMMMMMM MMMMMMMMMMMMMNkc'......,cdkKNWMMMMMMMMMMMMMMMWNKOdc,......'ckXWMMMMMMMMMMMM MMMMMMMMMMMMMMMN0o;........';codxkkOOOOOOkxdoc;'........;o0NMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMWXOd:'.............................,cdOXWMMMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMMMMNKkdc;,..................',:ldOXWMMMMMMMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMMMMMMMMWNK0Oxdooolooolooodxk0XNWMMMMMMMMMMMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM 0000000000000000|0xffbeddcaa68dc953ee4f3d040ab83cb0ac65498b|000000000000000" } # this function will return true if the application passed into it exists on the system function isInstalled() { command -v "$1" >/dev/null 2>&1 } # this function outputs the help text / manual for the -h output function outputHelpText() { echo "Below are the possible options to use this tool." echo "-d will download the chain before your node boots. It speeds up the process considerably." echo "-f will force remove any existing docker images if you have attempted to install/run them before." echo "-w will download and install watchtower." echo "-h will show this prompt." echo -e "\nPlease note that the options can be chained ie -dfw will chain the above options." exit } # outputs the exit message function exitMessage() { outputAscii echo "~~~~~ Don't forget to open your ports!!" if [ "$watchtower_install_flag" == 'false' ]; then echo "~~~~~ You opted not to install Watchtower. Please note this means that you must install updates yourself. Watchtower is advised." fi echo "~~~~~ Please consider making a MTR/MTRG donation if this script helped you [ 0xffbeddcaa68dc953ee4f3d040ab83cb0ac65498b ]. It would really help with the hosting costs. Thanks!" } installMegaIfRequired() { if isInstalled mega-version; then # we dont want to remove mega if it already existed before executing this script remove_mega_after_archive_download='false' return 1 elif test -r "/etc/os-release"; then # source the os-release file . /etc/os-release # todo - allow the end user to pass in a defined debian package URL to use if [ "$VERSION_CODENAME" == "bionic" ]; then # 18.04 deb="https://mega.nz/linux/MEGAsync/xUbuntu_18.04/amd64/megacmd_1.5.1-1.1_amd64.deb" elif [ "$VERSION_CODENAME" == "focal" ]; then # 20.04 deb="https://mega.nz/linux/MEGAsync/xUbuntu_20.04/amd64/megacmd_1.5.1-1.1_amd64.deb" elif [ "$VERSION_CODENAME" == "bullseye" ]; then deb="https://mega.nz/linux/MEGAsync/Debian_11/amd64/megacmd_1.5.1-1.1_amd64.deb" elif [ "$VERSION_CODENAME" == "buster" ]; then deb="https://mega.nz/linux/MEGAsync/Debian_10.0/amd64/megacmd_1.5.1-1.1_amd64.deb" else return 0 fi else return 0 fi # download the package wget -O ~/mega_debian_package.deb $deb # attempt to install the package # DEBIAN_FRONTEND=noninteractive will accept the defaults for any menu prompts sudo DEBIAN_FRONTEND=noninteractive apt install ~/mega_debian_package.deb -y # remove the installer rm ~/mega_debian_package.deb # required for Mega to start correctly sudo ldconfig } # downloads the 7z archive that contains the blockchain data function bootstrapChain() { echo "~~~~~Give the container a minute to boot up... Please wait for 60 seconds" sleep 1m echo "Lets see if the folders have been created" paths=($(find . -name "instance-*")) printf "%s\n" "${paths[@]}" node_dir=$paths cd $node_dir echo "~~~~~Changed directory to $PWD" # get the container id docker_container_id="$(< /tmp/meter_node_cont_id.txt)" echo "~~~~~Now we will stop the container id:" docker kill $docker_container_id echo "~~~~~While the blockchain is downloading, you could spend the time opening ports following point 2(e) of this guide here: https://paolo-g.medium.com/step-by-step-guide-to-creating-a-node-in-meter-mainnet-4cdde1085fbb" echo "~~~~~Lets download the blockchain data to bootstrap the syncing process" # assume we won't use mega for the download use_mega_link_for_download='false' # install the Mega application - it will be removed if not already installed on the system after the archive is downloaded installMegaIfRequired # check if Mega is usable if isInstalled mega-version; then # get the url for the latest archive megaLink=$(wget -q -O - https://archive.metervalidatorbot.com/archive-mega-link) # make sure we got a response value if [ megaLink ]; then echo "Mega Link fetched successfully: [$megaLink]" echo "We will use Mega to download the mirror - which is much faster" use_mega_link_for_download='true' fi fi # check if the we can use Mega (if any of the vars below are empty) if [[ -z $use_mega_link_for_download || -z $megaLink ]]; then echo "Issue occurred trying to use Mega. Falling back to server mirror for download:" # fall back to the slower mirror downloadStatus=$(downloadArchiveViaWget) if [ "$downloadStatus" -ne 0 ]; then echo "Failed to download the archive. Please try again." exit fi else echo "Mega application may take a second to start before the download starts...." echo "Please wait..." # trigger the download sudo mega-get $megaLink instance.7z # remove the mega application if it was installed by the script # we do this here instead of above the isInstalled check because the installation may have been attempted, but failed. if $remove_mega_after_archive_download; then echo "Removing the Mega application now that the archive is downloaded..." sudo apt remove -f -y megacmd fi fi echo "~~~~~Please wait - now unpacking the data" sudo 7z x instance.7z -aoa echo "~~~~~Deleting the 7z archive now that is is unpacked" sudo rm instance.7z docker start meter_main rm /tmp/meter_node_cont_id.txt } # function to download the archive via wget and handle any timeouts function downloadArchiveViaWget() { local attempt=0 local max_attempts=100 local archive_download_complete=false while [[ $archive_download_complete == false && "$attempt" -le "$max_attempts" ]] do attempt=$(( $attempt + 1 )) sudo wget --continue --tries=0 -O instance.7z $blockchain_7zip_url -q --show-progress if [ $? -eq 0 ]; then archive_download_complete=true elif [ "$attempt" -lt "$max_attempts" ]; then echo -e "~~~~~Intermittent issue occurred whilst downloading archive... please wait..." >&2 sleep 30s fi done # return a value based on the above status if [ $archive_download_complete == true ]; then echo 0 else echo 1 fi } # the main function function main() { local flag # output the ASCII art outputAscii declareVars # this string contains the text that will output to the end user before they confirm their choices (if y is not set) message_for_output="" while getopts 'dfwhpyi:m:' flag; do case "${flag}" in h) outputHelpText ;; d) # lets make sure that the mirror is actually available before setting the flag if wget --spider $blockchain_7zip_url 2>/dev/null; then # it looks like the mirror is UP message_for_output="${message_for_output} ~opted to download the blockchain directly to speed up the syncing process\n" download_chain_flag='true' else # looks like like the mirror is DOWN message_for_output="${message_for_output} ~IMPORTANT:: You opted to download the blockchain directly, but sadly it appears the mirror is down. The script will still setup your node for you but it will have to sync as normal.\n" download_chain_flag='false' fi ;; f) message_for_output="${message_for_output} ~opted to force remove any container that has already been installed with the name meter_main\n" force_removal_flag='true' ;; p) message_for_output="${message_for_output} ~opted to regenerate the public key\n" regenerate_public_key='true' ;; y) message_for_output="${message_for_output} ~opted to accept all messages automatically\n" assume_yes='true' ;; w) message_for_output="${message_for_output} ~opted to install watchtower that will manage updates for you\n" watchtower_install_flag='true' ;; i) install_directory=${OPTARG} ;; m) message_for_output="${message_for_output} ~requested to use ${OPTARG} as the mega installer package\n" mega_installer_package=${OPTARG} ;; esac done echo "@This script is provided as is without any warranty." echo "@You are welcome to view the source of this script before executing." echo "@Feel free to contribute" echo "@If you have any interest in providing a mirror, please get in touch" echo "@Twitter - https://twitter.com/DaveDeWire " echo "@You may need to enter your sudo password during execution." echo "@Please reach out in the Meter Validators Telegram group if you have any issues" echo "https://t.me/Meter_IO" echo "@Please confirm; you have:" echo -e "${message_for_output}" if [ "$assume_yes" == 'false' ]; then mainmenuinput="" echo Enter Y to continue: while [[ ( $(echo ${mainmenuinput,,} | xargs) != ${yes_option} && $(echo ${mainmenuinput,,} | xargs) != ${no_option} ) ]]; do read -n 1 mainmenuinput done if [ ${mainmenuinput,,} = ${yes_option} ]; then echo -e "\n~BEGINNING" else echo -e "\nDid not confirm. Exiting" exit fi fi #groups if grep -q $group_to_add /etc/group then echo "~~~~~group exists already. Not creating" else echo "~~~~~Group does not exist. Creating Now." sudo groupadd $group_to_add echo "~~~~~Group $group_to_add created" fi if groups $USER | grep -q $group_to_add then echo "~~~~~{$USER} is in group already. No need to re-add" else echo "~~~~~{$USER} Not in group yet adding now" sudo usermod -aG $group_to_add $USER echo "~~~~~{$USER} added to group {$group_to_add}" echo "~When a user is added to a new group, the user must logout and log back in" echo "~Because this script is designed to be run directly from GitHub, the safest" echo "~way to do that is to restart the machine. When the machine reboots simply rerun the same command." echo "~Are you happy to restart now??" if [ "$assume_yes" == 'false' ]; then restartconfirmation="" echo Enter Y to continue: while [[ ( $(echo ${restartconfirmation,,} | xargs) != ${yes_option} && $(echo ${restartconfirmation,,} | xargs) != ${no_option} ) ]]; do read -n 1 restartconfirmation done else restartconfirmation="y" fi if [ ${restartconfirmation,,} = ${yes_option} ]; then echo -e "\n~~~~~Restarting now" sudo reboot now exit else echo -e "\n~~~~~Did not confirm. You will get unexpected results if you re-run without reloading your groups correctly! Exiting" exit fi fi echo "~~~~~Creating the install folder (if required)" mkdir -p "$install_directory" cd "$install_directory" echo "~~~~~Setting the METER_MAIN_DATA_PATH variable in ~/.bashrc" #unset in case it has been set previously unset METER_MAIN_DATA_PATH #set METER_MAIN_DATA_PATH variable source <(grep -m 1 "METER_MAIN_DATA_PATH" ~/.bashrc ) #check if variable exists if [ ! -d "$install_directory" ]; then echo -e "~~~~~ERROR~~~~~" echo -e "~~~~~The path provided $install_directory is not valid or could not be created" echo -e "~~~~~Please check permissions or choose a different directory" exit elif [ -z "$METER_MAIN_DATA_PATH" ]; then echo "$METER_MAIN_DATA_PATH Variable doesnt exist, setting in bashrc" echo export "METER_MAIN_DATA_PATH=$PWD" >> ~/.bashrc source <(grep -m 1 "METER_MAIN_DATA_PATH" ~/.bashrc ) elif [ "$METER_MAIN_DATA_PATH" != "$PWD" ]; then echo -e "~~~~~ERROR~~~~~" echo -e "$PWD" echo -e "~~~~~The METER_MAIN_DATA_PATH variable already exists in ~/.bashrc - but contains the wrong value" echo -e "~~~~~This variable is used to store the location of the data that is required to run a node so that it can be filtered through to docker." echo -e "~~~~~Please edit ~/.bashrc with a text editor and remove the line:" echo -e "export METER_MAIN_DATA_PATH=$METER_MAIN_DATA_PATH" unset METER_MAIN_DATA_PATH exit fi echo "~~~~~Path variable set to:" echo $METER_MAIN_DATA_PATH echo "~~~~~Lets install docker.io and 7zip" sudo apt update -y sudo apt install sudo docker.io p7zip-full -y # if -f is passed in, we will force remove if [ "$force_removal_flag" == 'true' ]; then # remove container id file if exists if [ -f "/tmp/meter_node_cont_id.txt" ]; then echo "~~~~~removing container id file"; rm /tmp/meter_node_cont_id.txt fi if [ "$watchtower_install_flag" == 'true' ]; then echo "~~~~~Attempting to remove any previous references to Watchtower" docker container rm watchtower -f fi # remove the container docker container rm meter_main -f fi if [ "$download_chain_flag" == 'true' ]; then docker run --cidfile /tmp/meter_node_cont_id.txt --network host --name meter_main --restart always -e NETWORK="main" -v $METER_MAIN_DATA_PATH:/pos -d meterio/mainnet:latest bootstrapChain else echo -e "~~~~~Starting meter_main docker container" docker run --network host --name meter_main --restart always -e NETWORK="main" -v $METER_MAIN_DATA_PATH:/pos -d meterio/mainnet:latest fi # delete the public key if requested - it will be regenerated on boot if [ "$regenerate_public_key" == 'true' ]; then rm -f "$install_directory"/public.key echo -e "~~~~~Restarting meter_main after deleting old public key..." docker container restart meter_main fi if [ "$watchtower_install_flag" == 'true' ]; then echo -e "~~~~~Installing Watchtower" docker run -d --name watchtower --restart always -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtower --include-stopped --revive-stopped --enable-lifecycle-hooks --interval 10 --cleanup meter_main fi #output the private key if we can see it if [ -f "$PWD/public.key" ]; then echo "~~~~~Here is your public key. You can copy it from here, but make sure when you are setting up the node in the wallet that you do not have any whitespaces between the strings - it should all be on one line." cat public.key fi exitMessage } # trigger the main function main "$@"