#!/bin/bash echo " _____ _ _ _ _ " echo " / ____| | \ | | | | | | " echo " ___| (___ _ _ _ __ ___ | \| | ___| |___ _____ _ __| | __ " echo " / _ \\\___ \| | | | '_ \ / __| | . \` |/ _ \ __\ \ /\ / / _ \| '__| |/ " echo " | __/____) | |_| | | | | (__ | |\ | __/ |_ \ V V / (_) | | | < " echo " \___|_____/ \__, |_| |_|\___| |_| \_|\___|\__| \_/\_/ \___/|_| |_|\_\ " echo " __/ | " echo " |___/ " REPOURL="https://raw.githubusercontent.com/eCredits/docs/master/static/files/node-setup/" POSREPOURL="https://raw.githubusercontent.com/esync-network/docs/master/static/files/node-setup/" UPDATESCRIPTURL="https://dl.ecredits.com/scripts/update" VERSION="1.3" remapuser=$(awk -F "\"" '/userns-remap/ { print $4 }' /etc/docker/daemon.json) restart="false" testnet="false" if [[ $# -le 2 ]] then if [[ $# -gt 0 ]] then if [[ $1 == "restart" ]] then restart="true" if [[ $# -eq 2 ]] then if [[ $2 == "testnet" ]] then testnet="true" else echo "- Unknown command line argument." exit 1 fi fi elif [[ $1 == "testnet" ]] then testnet="true" else echo "- Unknown command line argument." exit 1 fi fi else echo "- Too many command line arguments." echo '- Please use none or "testnet"' exit 1 fi new_docker_version="false" existing_pos_setup="false" existing_poa_setup="false" new_setup="false" if [[ -d "/var/lib/eCredits/datadir" ]] then existing_poa_setup="true" echo "+ Existing PoA setup identified." elif [[ -f "/var/lib/eSync/testnet/validator.testnet.docker-compose.yaml" ]] && [[ $testnet == "true" ]] then existing_pos_setup="true" echo "+ Existing PoS testnet setup identified." elif [[ -f "/var/lib/eSync/mainnet/validator.mainnet.docker-compose.yaml" ]] && [[ $testnet == "false" ]] then existing_pos_setup="true" echo "+ Existing PoS mainnet setup identified." else new_setup="true" echo "+ No existing setup identified. Running new setup." fi set_paths(){ if [[ $existing_pos_setup == "true" ]] || [[ $new_setup == "true" ]] then if [[ $testnet == "true" ]] then datadir="/var/lib/eSync/testnet" passwordpath="/etc/config/testnetpassword.cfg" validator_docker_compose_name="validator.testnet.docker-compose.yaml" rpcport=5053 else datadir="/var/lib/eSync/mainnet" passwordpath="/etc/config/mainnetpassword.cfg" validator_docker_compose_name="validator.mainnet.docker-compose.yaml" rpcport=5051 fi else datadir="/var/lib/eCredits" validator_docker_compose_name="validator.docker-compose.yaml" fi } set_paths if [[ $remapuser == "default" ]] then remapuid=$(awk -F ":" '/dockremap/ { print $2 }' /etc/subgid) remapgid=$(awk -F ":" '/dockremap/ { print $2 }' /etc/subuid) else remapuid=$(awk -F ":" '/remap/ { print $2 }' /etc/subgid) remapgid=$(awk -F ":" '/remap/ { print $2 }' /etc/subuid) fi docker-compose --version 2> /dev/null if [[ "$?" -eq 127 ]] then docker compose version if [[ "$?" -eq 127 ]] then echo "err-2: No docker compose version found on the system. Exiting." exit 1 else new_docker_version="true" fi fi load_container_names(){ if [[ $existing_pos_setup == "true" ]] || [[ $new_setup == "true" ]] then if($testnet) then if [[ $new_docker_version == "true" ]] then POS_VALIDATOR_CONTAINERNAME=testnet-validator-1 POS_BEACON_CONTAINERNAME=testnet-beacon-1 POS_GETH_CONTAINERNAME=testnet-geth-1 else POS_VALIDATOR_CONTAINERNAME=testnet_validator_1 POS_BEACON_CONTAINERNAME=testnet_beacon_1 POS_GETH_CONTAINERNAME=testnet_geth_1 fi else if [[ $new_docker_version == "true" ]] then POS_VALIDATOR_CONTAINERNAME=mainnet-validator-1 POS_BEACON_CONTAINERNAME=mainnet-beacon-1 POS_GETH_CONTAINERNAME=mainnet-geth-1 else POS_VALIDATOR_CONTAINERNAME=mainnet_validator_1 POS_BEACON_CONTAINERNAME=mainnet_beacon_1 POS_GETH_CONTAINERNAME=mainnet_geth_1 fi fi else ecredits_containers=$(docker ps --format "{{.Names}}" | grep ecredits) if [[ -n $ecredits_containers ]] then POA_CONTAINERNAME=$(docker ps --format "{{.Names}}") else if [[ $new_docker_version == "true" ]] then POA_CONTAINERNAME=ecredits-ecs-validator-1 else POA_CONTAINERNAME=ecredits_ecs-validator_1 fi fi fi } initialize() { echo "+ Initialize node directory at $datadir" if [[ -d $mainnet_file_count ]] then sudo rm -r $datadir fi if [[ $existing_pos_setup == "true" ]] || [[ $new_setup == "true" ]] then sudo mkdir -p "$datadir" #Generate jwt.hex cd $datadir if [[ $testnet == "true" ]] then openssl rand -hex 32 | sudo tee -a jwt.testnet.hex > /dev/null else openssl rand -hex 32 | sudo tee -a jwt.mainnet.hex > /dev/null fi else sudo mkdir -p "$datadir/datadir/geth" fi sudo chown -R $remapuid:$remapgid $datadir } download_files() { cd $datadir sudo wget "$REPOURL/archive-node.docker-compose.yaml" -O "archive-node.doker-compose.yaml" sudo wget "$REPOURL/full-node.docker-compose.yaml" -O "full-node.docker-compose.yaml" sudo wget "$REPOURL/light-node.docker-compose.yaml" -O "light-node.docker-compose.yaml" sudo wget "$REPOURL/validator.docker-compose.yaml" -O "validator.docker-compose.yaml" sudo chown -R $remapuid:$remapgid $datadir echo "Files updated." } download_pos_files(){ cd $datadir if($testnet) then sudo wget "$POSREPOURL/validator.testnet.docker-compose.yaml" -O "validator.testnet.docker-compose.yaml" else sudo wget "$POSREPOURL/validator.mainnet.docker-compose.yaml" -O "validator.mainnet.docker-compose.yaml" fi sudo chown -R $remapuid:$remapgid $datadir echo "Files updated." } stop_container() { container_exists=$(docker ps --format "{{ .Names }}" --filter "name=$POA_CONTAINERNAME") if [[ -n $container_exists ]] then docker exec $POA_CONTAINERNAME killall -INT geth fi if [[ -f "$datadir/validator.docker-compose.yaml" ]] then if ($new_docker_version) then docker compose -f $datadir/validator.docker-compose.yaml down -t 20 else docker-compose -f $datadir/validator.docker-compose.yaml down -t 20 fi else echo "+ No compose file found. Containers won't be stopped." fi } start_container() { if [[ -f "$datadir/$validator_docker_compose_name" ]] then if ($new_docker_version) then docker compose -f $datadir/$validator_docker_compose_name up -d else docker-compose -f $datadir/$validator_docker_compose_name up -d fi until [ "`docker inspect -f {{.State.Running}} $POA_CONTAINERNAME`"=="true" ]; do sleep 0.1; done; else echo "+ No docker compose file found. Containers will not be started." fi } validateAccount() { echo "+ Check validity of account $1" if [[ $1 =~ ^0x[0-9a-fA-F]{40} ]] then return 0 else return 1 fi } create_account() { echo "Creating a new public account." docker exec -it $POA_CONTAINERNAME geth account new } # Checks if a public account configuration is existing. # - Returns 0 if an account is existing # - Returns 1 if config file exists, but no etherbase configuration # - Returns 2 if no configuration file exists check_publicaccountconfig_exists() { echo "+ Check for existing public account configuration." configuration_existing="false" if [[ -f $datadir/esync.conf ]] then echo "+ Configuration found at $datadir/esync.conf. Reading public account configuration." public_account_config=$(grep public_account $datadir/esync.conf) if [[ -n $public_account_config ]] then IFS=: read public_account publicAccountID <<< $public_account_config echo "+ Public account configuration with configuration $publicAccountID found." configuration_existing="true" return 0 fi echo "+ No public account configuration found." return 1 fi echo "+ No configuration file found." return 2 } prepare_mining() { force_new_account="false" public_account="" if check_publicaccountconfig_exists then IFS=: read public_account_key public_account <<< $public_account_config read -p "Found public account $public_account in the configuration. Do you want to use it? [Y/n] " forceNewAccount if [[ $forceNewAccount == "n" || $forceNewAccount == "N" ]] then force_new_account="true" fi fi echo "------------------------ Start mining on your validator ------------------------" if [[ $public_account == "" || $force_new_account == "true" ]] then read -p "+ Do you want to create a new public account? [Y/n] " newAccount if [[ $newAccount == "Y" || $newAccount == "y" || $newAccount == "" ]] then create_account fi validPublicAddress="false" while [[ $validPublicAddress == "false" ]] do read -p "+ To start the mining, please provide the public Account address (e.g. 0xTODO0000ENTER000YOUR000ADDRESS000HERE000): " public_account if validateAccount $public_account then validPublicAddress="true" if [[ $configuration_existing == "false" ]] then echo "public_account:$public_account" | sudo tee -a $datadir/esync.conf else sudo sed -i "s/public_account:.*/public_account:$public_account/g" $datadir/esync.conf fi else echo "+ Format of public address is not valid. Please try again or cancel the process by pressing Ctrl + c." fi done fi start_mining "$public_account" } start_mining() { if validateAccount $1 then echo -n "Please enter the password to unlock your account: " read -s accountPassword echo "Public account is $1" docker exec -it $POA_CONTAINERNAME geth --exec "personal.unlockAccount(\"$1\",\"$accountPassword\",0)" attach docker exec -it $POA_CONTAINERNAME geth --exec "miner.start()" attach else echo "er-2: Invalid public account address." fi } help() { echo "This script supports the setup and maintenance of your eSync Network node." echo echo "Syntax: ecredits.sh" echo echo "If there is no eSync Network folder present at $datadir, the script initializes the node and starts it." echo "If there is already an eSync Network folder present, it presents a menu with the following options:" echo "" echo "1. Set etherbase - Allows you to set the account where your mining fees are collected." echo "2. Start mining - Unlocks the wallte account of the node and starts the mining process." echo "3. Node status - Show the general state of the node with some usefull information." echo "4. Update - Updates the docker compose files in case there are changes." echo "5. List wallets - List all available wallets." echo "6. Show logs - Shows the geth logs." echo "7. Create additional account - Creates a wallet account, that is required to do mining on this node." echo "8. Stop node - Stops the node if it's running." echo "9. Start node - Starts the node itself with the last configured values." echo "10. Erase and Reinitialize - This option deletes the whole node and does a clean setup." echo " *This will also delete your keyfile and settings!*" echo "11. Reset database - Deletes the whole chain database and allows a resync." echo "12. Help - Shows this help message." echo "13. Exit" } pos_help() { echo "----------------------------------- Help ---------------------------------------" echo "This script supports the setup and maintenance of your eSync Network node." echo echo "Syntax: ecredits" echo echo "If there is no eSync Network folder present at $datadir, the script initializes the " echo "node and starts it." echo "If there is already an eSync Network folder present, it presents a menu with the " echo "following options:" echo "" echo "1. Node status - Show the general state of the node with some usefull " echo " information." echo "2. Update - Updates the docker compose files in case there are " echo " changes." echo "3. List accounts - Lists the importet accounts of the validators wallet." echo "4. Update fee recipient - Updates the account that receives the fees." echo "5. Update etherbase - Updates the etherbase account to receive the block rewards." echo "6. Start node - Starts the node with the last configured values." echo "7. Stop node " echo "8. Import keys - Import existing keys from the gened/validator_keys directory." echo "9. Exit keys - Exit one or all keys from the staking process." echo "10. Backup data - Stores a backup of the validator.db and the wallet to " echo " the /var/lib/eSync/backups folder." echo "11. Restore backup - Restores a previously backed up state to the respective " echo " file locations in /var/lib/eSync/." echo " This will only work with a backup that has been created " echo " by this script!" echo "12. Show geth logs - Shows the logs of the geth container." echo "13.Show beacon logs - Shows the logs of the beacon container." echo "14.Show validator logs - Shows the logs of the validator container." echo "15.Help" echo "16.Exit" } # Checks if an etherbase configuration is existing. # - Returns 0 if an account is existing # - Returns 1 if config file exists, but no etherbase configuration # - Returns 2 if no configuration file exists check_etherbaseconfig_exists() { echo "+ Check for existing etherbase account configuration." configuration_existing="false" if [[ -f $datadir/esync.conf ]] then echo "+ Configuration found at $datadir/esync.conf. Reading etherbase account configuration." etherbase_config=$(grep etherbase $datadir/esync.conf) if [[ -n $etherbase_config ]] then echo "+ Etherbase account configuration with account $etherbase_config found." configuration_existing="true" return 0 fi echo "+ No etherbase account configuration found." return 1 fi echo "+ No configuration file found." return 2 } check_fee_recipientconfig_exists() { echo "+ Check for fee recipient account configuration." configuration_existing="false" if [[ -f $datadir/esync.conf ]] then echo "+ Configuration found at $datadir/esync.conf. Reading fee recipient configuration." fee_recipient_configuration=$(grep fee_recipient $datadir/esync.conf) if [[ -n $fee_recipient_configuration ]] then echo "+ Fee recipient configuration with account $fee_recipient_configuration found." configuration_existing="true" return 0 fi echo "+ No fee recipient account configuration found." return 1 fi echo "+ No configuration file found." return 2 } check_ipconfig_exists() { echo "+ Check for existing external ip configuration." configuration_existing="false" if [[ -f $datadir/esync.conf ]] then echo "+ Configuration found at $datadir/esync.conf. Reading ip configuration." ip_config=$(grep self_ip $datadir/esync.conf) if [[ -n $ip_config ]] then echo "+ IP configuration with account $ip_config found." configuration_existing="true" return 0 fi echo "+ No ip configuration found." return 1 fi echo "+ No configuration file found." return 2 } update_etherbase() { #Function only used for POS echo "---------------------------- Set etherbase address -----------------------------" set_new="true" if check_etherbaseconfig_exists then set_new="false" etherbase_config=$(grep etherbase $datadir/esync.conf) IFS=: read etherbase_key etherbaseAccountID <<< $etherbase_config read -p "Current etherbase account is $etherbaseAccountID. Do you want to set a new address? [Y/n] " newID if [[ $newID != "Y" || $newID != "y" || $newID != "" ]] then set_new="true" fi fi if [[ $set_new == "true" ]] then validEtherbaseAddress="false" while [[ $validEtherbaseAddress == "false" ]] do read -p "+ Please provide etherbase account address (e.g. 0xTODO0000ENTER000YOUR000ADDRESS000HERE000): " etherbaseAccountID if validateAccount $etherbaseAccountID then if [[ $configuration_existing == "false" ]] then echo "etherbase:$etherbaseAccountID" | sudo tee -a $datadir/esync.conf else sudo sed -i "s/etherbase:.*/etherbase:$etherbaseAccountID/g" $datadir/esync.conf fi validEtherbaseAddress="true" else echo "+ Format of etherbase address is not valid. Please try again or cancel the process by pressing Ctrl + c." fi done fi set_etherbase_account "$etherbaseAccountID" } get_etherbase() { set_new="true" etherbase_configuration_existing="false" if check_etherbaseconfig_exists then set_new="false" etherbase_configuration_existing="true" etherbase_config=$(grep etherbase $datadir/esync.conf) IFS=: read etherbase_key etherbaseAccountID <<< $etherbase_config read -p "Current etherbase account is $etherbaseAccountID. Do you want to set a new address? [y/N] " newID if [[ $newID = "Y" || $newID = "y" ]] then set_new="true" fi fi if [[ $set_new == "true" ]] then echo "---------------------------- Set etherbase address -----------------------------" validEtherbaseAddress="false" while [[ $validEtherbaseAddress == "false" ]] do read -p "+ Please provide etherbase account address (e.g. 0xTODO0000ENTER000YOUR000ADDRESS000HERE000): " etherbaseAccountID if validateAccount $etherbaseAccountID then if [[ $etherbase_configuration_existing == "false" ]] then echo "etherbase:$etherbaseAccountID" | sudo tee -a $datadir/esync.conf > /dev/null else sudo sed -i "s/etherbase:.*/etherbase:$etherbaseAccountID/g" $datadir/esync.conf > /dev/null fi validEtherbaseAddress="true" else echo "+ Format of etherbase address is not valid. Please try again or cancel the process by pressing Ctrl + c." fi done fi } set_fee_recipient_account() { echo "---------------------------- Set fee recipient account -----------------------------" new_fee_recipient_account="true" existing_fee_recipientconfig="false" if check_fee_recipientconfig_exists then new_fee_recipient_account="false" existing_fee_recipientconfig="true" fee_recipient_account_config=$(grep fee_recipient $datadir/esync.conf) IFS=: read recipient_account recipientAccountID <<< $fee_recipient_account_config read -p "+ Current fee recipient account is $recipientAccountID. Do you want to set a new address? [y/N] " newID if [[ $newID = "Y" || $newID = "y" ]] then new_fee_recipient_account="true" fi fi if [[ $new_fee_recipient_account == "true" ]] then valid_fee_recipient_address="false" while [[ $valid_fee_recipient_address == "false" ]] do read -p "+ Please provide then new fee recipient address (e.g. 0xTODO0000ENTER000YOUR000ADDRESS000HERE000): " recipientAccountID if validateAccount $recipientAccountID then if [[ $existing_fee_recipientconfig == "true" ]] then sudo sed -i "s/fee_recipient:.*/fee_recipient:$recipientAccountID/g" $datadir/esync.conf > /dev/null else echo "fee_recipient:$recipientAccountID" | sudo tee -a $datadir/esync.conf > /dev/null fi valid_fee_recipient_address="true" else echo "+ Format of the address is not valid. Please try again or cancel the process by pressing Ctrl + c." fi done fi } read_fee_recipient_account(){ fee_recipient_account_config=$(grep fee_recipient $datadir/esync.conf) IFS=: read recipient_account recipientAccountID <<< $fee_recipient_account_config echo $recipientAccountID } get_external_ip(){ echo "----------------------------- Set external IP address ------------------------------" new_ip_config="true" check_ipconfig_exists ip_config_exists=$? if [ "$ip_config_exists" -eq 0 ] then new_ip_config="false" ip_config=$(grep self_ip $datadir/esync.conf) IFS=: read self_ip external_ip <<< $ip_config read -p "+ Current external ip is $external_ip. Do you want to set a new address? [y/N] " newID if [[ $newID = "Y" || $newID = "y" ]] then new_ip_config="true" fi fi if [[ $new_ip_config == "true" ]] then read -p "+ Please provide the external ipv4 address of your node: " external_ip if [ "$ip_config_exists" -eq 0 ] then sudo sed -i "s/self_ip:.*/self_ip:$external_ip/g" $datadir/esync.conf > /dev/null else echo "self_ip:$external_ip" | sudo tee -a $datadir/esync.conf > /dev/null fi fi } read_external_ip(){ ip_config=$(grep self_ip $datadir/esync.conf) IFS=: read self_ip external_ip <<< $ip_config echo $external_ip } read_etherbase(){ etherbase_config=$(grep etherbase $datadir/esync.conf) IFS=: read etherbase etherbase_address <<< $etherbase_config echo $etherbase_address } set_etherbase_account() { if validateAccount $1 then results=$(grep -c '#--miner.etherbase' $datadir/$validator_docker_compose_name) if [[ "$results" -gt 0 ]] then sudo sed -i 's/# - ETHERBASE/ - ETHERBASE/g' $datadir/$validator_docker_compose_name sudo sed -i "s/#--miner.etherbase.*/--miner.etherbase $1/g" $datadir/$validator_docker_compose_name else sudo sed -i "s/--miner.etherbase.*/--miner.etherbase $1/g" $datadir/$validator_docker_compose_name fi echo "Set etherbase account to $1" else echo "err-1: Invalid etherbase account address!" fi } reset_db() { echo "--------------------------- Resetting chain database! ---------------------------" container_version=$(awk -F ":" '/ecredits\/node/ { printf $3 }' $datadir/validator.docker-compose.yaml) trimmed_container_version=$(echo $container_version |tr -d '\r') container="ecredits/node:$trimmed_container_version" stop_container docker run -it -v $datadir/datadir:/root/.ethereum -e POD_NAME --entrypoint geth "$container" removedb start_container } reset_geth_db() { echo "--------------------------- Resetting eth1 chain database! ---------------------------" container_name=$(docker ps --format "{{ .Names }}" --filter "name=geth") stop_pos_container docker run -it -v $datadir/datadir-eth1:/root/.ethereum -e POD_NAME --entrypoint geth "$container_name" removedb start_pos_container } reset_beacon_db() { echo "-------------- Resetting eth2 chain database and slashing protection db! ------------" container_name=$(docker ps --format "{{ .Names }}" --filter "name=beacon") stop_pos_container sudo rm -r $datadir/datadir-eth2 sudo rm $datadir/datadir-eth2-validator/validators/slashing_protection.sqlite sudo rm $datadir/datadir-eth2-validator/validators/slashing_protection.sqlite-journal start_pos_container } show_logs() { docker logs -f --tail=10 $POA_CONTAINERNAME } start_node() { echo "" echo "-------------------------------- Starting node ---------------------------------" if check_etherbaseconfig_exists then etherbase_account_config=$(grep etherbase $datadir/esync.conf) IFS=: read etherbase_account_key etherbaseAccountID <<< $etherbase_account_config echo "+ Using existing etherbase address: $etherbaseAccountID" set_etherbase_account "$etherbaseAccountID" fi start_container if check_publicaccountconfig_exists then echo "+ Waiting for node startup." mining_status=$(docker exec -it $POA_CONTAINERNAME geth --exec eth.mining attach) while echo -n "*" sleep 5s mining_status=$(docker exec -it $POA_CONTAINERNAME geth --exec eth.mining attach) [[ $mining_status != *"false"* ]] do true; done echo "" echo "+ Node is started." echo "+ Using existing public account configuration!" public_account_config=$(grep public_account $datadir/esync.conf) IFS=: read public_account_key publicAccountID <<< $public_account_config start_mining "$publicAccountID" fi } start_pos_node() { echo "" echo "-------------------------------- Starting PoS node ---------------------------------" get_external_ip node_external_ip=$(read_external_ip) set_fee_recipient_account recipientAccountID=$(read_fee_recipient_account) get_etherbase etherbase=$(read_etherbase) if [[ -f "$datadir/.env" ]] then fee_recipient_configuration=$(grep FEE_RECIPIENT_ACCOUNT $datadir/.env) if [[ -n $fee_recipient_configuration ]] then sudo sed -i "s/FEE_RECIPIENT_ACCOUNT=.*/FEE_RECIPIENT_ACCOUNT=$recipientAccountID/g" $datadir/.env else echo "FEE_RECIPIENT_ACCOUNT=$recipientAccountID" | sudo tee -a $datadir/.env > /dev/null fi external_ip_configuration=$(grep SELF_IP $datadir/.env) if [[ -n $external_ip_configuration ]] then sudo sed -i "s/SELF_IP=.*/SELF_IP=$node_external_ip/g" $datadir/.env else echo "SELF_IP=$node_external_ip" | sudo tee -a $datadir/.env > /dev/null fi etherbase_configuration=$(grep ETHERBASE_ACCOUNT $datadir/.env) if [[ -n $etherbase_configuration ]] then sudo sed -i "s/ETHERBASE_ACCOUNT=.*/ETHERBASE_ACCOUNT=$etherbase/g" $datadir/.env else echo "ETHERBASE_ACCOUNT=$etherbase" | sudo tee -a $datadir/.env > /dev/null fi passwordfile_path_configuration=$(grep PASSWORDFILE_PATH $datadir/.env) if [[ -n $passwordfile_path_configuration ]] then sudo sed -i "s|PASSWORDFILE_PATH=.*|PASSWORDFILE_PATH=$passwordpath|g" $datadir/.env else echo "PASSWORDFILE_PATH=$passwordpath" | sudo tee -a $datadir/.env > /dev/null fi else echo "FEE_RECIPIENT_ACCOUNT=$recipientAccountID" | sudo tee -a $datadir/.env > /dev/null echo "SELF_IP=$node_external_ip" | sudo tee -a $datadir/.env > /dev/null echo "ETHERBASE_ACCOUNT=$etherbase" | sudo tee -a $datadir/.env > /dev/null echo "PASSWORDFILE_PATH=$passwordpath" | sudo tee -a $datadir/.env > /dev/null fi if [[ -d "$datadir/datadir-eth2-validator/validators" ]] then number_of_imported_keys=$(find $datadir/datadir-eth2-validator/validators -type d -name "0x*" | wc -l) else number_of_imported_keys=0 fi if [[ $number_of_imported_keys -eq 0 ]] then echo "+ No existing wallet discovered." read -p "+ Do you want to restore a backup? [y/N] " import_backup if [[ $import_backup == "y" ]] || [[ $import_backup == "Y" ]] then restore_backup else read -p "+ Do you want to generate and stake keys? [Y/n] " generate_and_import_keys_question if [[ $generate_and_import_keys_question = "Y" || $generate_and_import_keys_question = "y" || $generate_and_import_keys_question = "" ]] then generate_and_import_keys fi fi fi start_pos_container echo "+ PoS node started." } start_pos_container() { if [[ -f "$datadir/$validator_docker_compose_name" ]] then if ($new_docker_version) then docker compose -f $datadir/$validator_docker_compose_name up -d else docker-compose -f $datadir/$validator_docker_compose_name up -d fi else echo "+ No docker compose file found. Containers will not be started." fi } stop_pos_container() { pos_geth_container_exists=$(docker ps --format "{{ .Names }}" --filter "name=$POS_GETH_CONTAINERNAME") pos_beacon_container_exists=$(docker ps --format "{{ .Names }}" --filter "name=$POS_BEACON_CONTAINERNAME") if [[ -n $pos_geth_container_exists ]] then docker exec -it $POS_GETH_CONTAINERNAME pkill geth fi if [[ -n $pos_beacon_container_exists ]] then docker exec -it $POS_BEACON_CONTAINERNAME pkill beacon-chain fi if [[ -f "$datadir/$validator_docker_compose_name" ]] then if ($new_docker_version) then docker compose -f $datadir/$validator_docker_compose_name down -t 10 else docker-compose -f $datadir/$validator_docker_compose_name down -t 10 fi else echo "+ No docker compose file found. Containers will not be stopped." fi } print_public_accounts(){ number_of_public_accounts=$(docker exec -it $POA_CONTAINERNAME geth --exec personal.listAccounts.length attach | sed -n 2p) public_accounts=$(docker exec -it $POA_CONTAINERNAME geth --exec personal.listAccounts attach | sed -n 2p) echo " Number of accounts on the node: $number_of_public_accounts" echo " Public accounts: $public_accounts" } print_wallets(){ wallets=$(docker exec -it $POA_CONTAINERNAME geth --exec personal.listWallets attach) echo "Wallets: $wallets" } create_pos_folders(){ sudo mkdir -p "$datadir/datadir-eth2-validator/wallet" sudo mkdir -p "$datadir/gened" sudo chown -R $remapuid:$remapgid "$datadir" } backup_keystore_to_homedir(){ current_time=$(date "+%Y.%m.%d-%H.%M.%S") backupfolder="keystorebackup_$current_time" echo "+ Backing up keystore folder to ~/$backupfolder." cd ~ sudo mkdir $backupfolder sudo cp -R "$datadir/datadir/keystore" "$backupfolder/." } generate_and_import_keys(){ create_pos_folders if [[ $testnet == "true" ]] then docker run --rm -it -v "$datadir/gened":/gened ecredits/staking-deposit-cli:latest -c "node /setup/eth2_setup_node.js testnet" else docker run --rm -it -v "$datadir/gened":/gened ecredits/staking-deposit-cli:latest -c "node /setup/eth2_setup_node.js mainnet" fi unlock_wallet import_keys echo " > Starting nodes." } import_keys(){ echo "-------------------------- Importing keys to wallet ----------------------------" echo "+ Creating wallet" if [[ $testnet == "true" ]] then docker run --rm -it -v "$datadir/gened/validator_keys":/keys -v "$datadir/datadir-eth2-validator":/root/.lighthouse -v "$passwordpath":/password.cfg --name validatorimport ecredits/lighthouse:latest lighthouse --network ecs_pubtest account validator import --datadir /root/.lighthouse --directory /keys --reuse-password --password-file /password.cfg else docker run --rm -it -v "$datadir/gened/validator_keys":/keys -v "$datadir/datadir-eth2-validator":/root/.lighthouse -v "$passwordpath":/password.cfg --name validatorimport ecredits/lighthouse:latest lighthouse --network ecs account validator import --datadir /root/.lighthouse --directory /keys --reuse-password --password-file /password.cfg fi } manual_import_keys(){ echo "-------------------------- Manual key import -----------------------------------" echo "This option allows to import existing keys to your wallet." echo "The key's are expected to reside in $datadir/gened/validator_keys in the correct" echo "format." echo "The password file is expected to be in $passwordpath." read -s -p "Are the keys and password file at the correct paths? [Y/n] " manual_import_approval if [[ $manual_import_approval == "" ]] || [[ $manual_import_approval == "y" ]] || [[ $manual_import_approval == "Y" ]] then stop_pos_container import_keys start_pos_container fi } unlock_wallet(){ echo "------------------------------- Unlock wallet ----------------------------------" if [[ ! -f $passwordpath ]] then read -s -p "Please provide the password to unlock you validator keys: " key_password sudo mkdir /etc/config/ sudo chown -R $remapuid:$remapgid /etc/config/ echo $key_password | sudo tee $passwordpath > /dev/null fi } delete_poa_files(){ sudo rm -r "$datadir/datadir" sudo rm -r "$datadir/archive-node.doker-compose.yaml" sudo rm -r "$datadir/full-node.docker-compose.yaml" sudo rm -r "$datadir/light-node.docker-compose.yaml" sudo rm -r "$datadir/validator.docker-compose.yaml" } merge(){ echo "================================ Start merge ===================================" echo "+ Stopping old node" stop_container backup_keystore_to_homedir delete_poa_files change_mounts_to_esync new_setup="true" existing_poa_setup="false" set_paths load_container_names initialize download_pos_files start_pos_node } change_mounts_to_esync(){ existing_mountpoint=$(grep /var/lib/eCredits /etc/fstab) if [ -n "$existing_mountpoint" ] then echo "+ Detected mountpoint at /var/lib/eCredits that will be migrated to /var/lib/eSync." if [[ $existing_poa_setup == "true" ]] then stop_container elif [[ $existing_pos_setup == "true " ]] then stop_pos_container fi cd ~ sleep 1 sudo umount /var/lib/eCredits sudo rm -r /var/lib/eCredits sudo mkdir /var/lib/eSync sudo sed -i "s/eCredits*/eSync/g" /etc/fstab sudo mount -a if [[ $existing_poa_setup == "true" ]] then start_container elif [[ $existing_pos_setup == "true " ]] then start_pos_container fi else echo "+ Mount already on /var/lib/eSync." fi } print_node_state() { clear while true do clear tput cup 0 0 container_state=$(docker ps --format "{{.Status}}") container_runs=$(docker ps | grep $POA_CONTAINERNAME) echo "--------------------------------------------------------------------------------" echo "| NODE STATUS |" echo "| press q to exit |" echo "--------------------------------------------------------------------------------" if [[ $container_runs == "" ]] then echo " Node state: Not running" else echo " Node state: $(docker ps --format {{.Names}}) | $(docker ps --format "{{.Image}}" | awk '{print substr($0, 15)}') | $(docker ps --format {{.Status}})" if [[ $container_state =~ "Up".* ]] then print_public_accounts echo " Mining started: $(docker exec -it $POA_CONTAINERNAME geth --exec eth.mining attach | sed -n 2p)" echo " Current peers: $(docker exec -it $POA_CONTAINERNAME geth --exec admin.peers.length attach | sed -n 2p)" echo " Current block: $(docker exec -it $POA_CONTAINERNAME geth --exec eth.blockNumber attach | sed -n 2p)" fi fi echo "--------------------------------------------------------------------------------" read -t 5 -N 1 input if [[ $input = "q" ]] || [[ $input = "Q" ]] then # The following line is for the prompt to appear on a new line. clear break fi done } print_pos_node_state() { clear while true do clear tput cup 0 0 container_state=$(docker ps --format "{{.Names}},{{.Status}}" | grep geth) validator_container_runs=$(docker ps --format "{{.Names}},{{.Image}},{{.Status}}" | grep $POS_VALIDATOR_CONTAINERNAME) IFS=',' read -r -a validator_container_status <<<"$validator_container_runs" validator_beacon_runs=$(docker ps --format "{{.Names}},{{.Image}},{{.Status}}" | grep $POS_BEACON_CONTAINERNAME) echo IFS=',' read -r -a validator_beacon_status <<<"$validator_beacon_runs" validator_geth_runs=$(docker ps --format "{{.Names}},{{.Image}},{{.Status}}" | grep $POS_GETH_CONTAINERNAME) IFS=',' read -r -a validator_geth_status <<<"$validator_geth_runs" echo "--------------------------------------------------------------------------------" echo "| NODE STATUS |" echo "| press q to exit |" echo "--------------------------------------------------------------------------------" if [[ $validator_container_runs == "" ]] then echo " Validator: Not running" else echo " Validator: ${validator_container_status[0]} | $(echo ${validator_container_status[1]} | awk '{print substr($0, 21)}') | ${validator_container_status[2]}" fi if [[ $validator_beacon_runs == "" ]] then echo " Beacon: Not running" else echo " Beacon: ${validator_beacon_status[0]} | $(echo ${validator_beacon_status[1]} | awk '{print substr($0, 21)}') | ${validator_beacon_status[2]}" fi if [[ $validator_geth_runs == "" ]] then echo " Geth: Not running" else echo " Geth: ${validator_geth_status[0]} | $(echo ${validator_geth_status[1]} | awk '{print substr($0, 15)}') | ${validator_geth_status[2]}" fi echo "--------------------------------------------------------------------------------" if [[ $container_state =~ "Up".* ]] then echo " Current geth peers: $(docker exec -it $POS_GETH_CONTAINERNAME geth --exec admin.peers.length attach | sed -n 2p)" echo "" echo " Beacon node peer count: " curl -X 'GET' "http://localhost:$rpcport/eth/v1/node/peer_count" -H 'accept: application/json' echo "" echo " Beacon health:" health_status_code=$(curl -o /dev/null -s -w "%{http_code}\n" -X 'GET' "http://localhost:$rpcport/eth/v1/node/health") health_status_description="Not initialized / has issues" if [ $health_status_code -eq 200 ] then health_status_description="Healthy" elif [ $health_status_code -eq 206 ] then health_status_description="Syncing" elif [ $health_status_code -eq 400 ] then health_status_description="Invalid syncing" fi echo "$health_status_description" if [[ -d "$datadir/datadir-eth2-validator/validators" ]] then number_of_imported_keys_report=$(find $datadir/datadir-eth2-validator/validators -type d -name "0x*" | wc -l) else number_of_imported_keys_report=0 fi echo "Number of imported keys: $number_of_imported_keys_report" fi echo "--------------------------------------------------------------------------------" read -t 5 -N 1 input if [[ $input = "q" ]] || [[ $input = "Q" ]] then # The following line is for the prompt to appear on a new line. clear break fi done } list_accounts() { docker exec -it $POS_VALIDATOR_CONTAINERNAME bash -c 'find ~/.lighthouse/validators -mindepth 1 -maxdepth 1 -name "0x*" -type d | sed "s|/root/.lighthouse/validators/||"' } backup(){ echo "---------------------------- Creating backup -----------------------------------" echo "+ To create a proper backup, the node will be stopped and restarted after the " echo "+ process." stop_pos_container current_time=$(date "+%Y.%m.%d-%H.%M.%S") backupname="nodebackup_$current_time" backupfolder="$datadir/$backupname" mkdir -p /tmp/$backupname echo "+ Backing upd wallet and slashing protection" sudo cp -R "$datadir/datadir-eth2-validator/validators" /tmp/$backupname/. cd /tmp/$backupname sudo mkdir -p "$datadir/backups" sudo tar czf $backupfolder.tar.gz . echo "+ Backup can be found in $backupfolder.tar.gz" sudo rm -rf /tmp/$backupname cd $datadir start_pos_node echo "+ Backup created." } restore_backup(){ echo "---------------------------- Restoring backup -----------------------------------" echo "When restoring a backup, the current validator.db and wallet will be replaced! Please make sure to backup this data if you might later need it!" echo "Restore will work only from the zip file structure, that is created by this scripts backup option!" read -p "Please provide the absolute full path to the backup file: " backup_path stop_pos_container mkdir /tmp/validatorrestore cd /tmp/validatorrestore tar -xf $backup_path echo "+ Replacing wallet" sudo rm -r "$datadir/datadir-eth2-validator/validators" sudo mkdir -p "$datadir/datadir-eth2-validator/validators" sudo cp -R "/tmp/validatorrestore/validators" "$datadir/datadir-eth2-validator/validators" sudo chown -R $remapuid:$remapgid $datadir unlock_wallet start_pos_node echo "+ Backup restored" } exit_keys(){ echo "-------------------------------- Exit keys --------------------------------------" cd "$datadir/datadir-eth2-validator/validators" imported_keys=$(ls -d 0x* | sort) counter=0 exit_all_keys="false" single_key_to_exit="" for key in $imported_keys do echo "$counter: $key" ((counter++)) done number_of_keys=$counter echo "$counter: All" read -p "Select the key that should exit: " exit_selection counter=0 for key in $imported_keys do if [[ $counter -eq $exit_selection ]] then echo "$key will be exited." single_key_to_exit=$key break; fi ((counter++)) done if [[ $counter -eq $number_of_keys ]] then echo "All keys will be exited." exit_all_keys="true" fi if [[ $exit_all_keys == "false" ]] then exit_key $single_key_to_exit else for key in $imported_keys do exit_key $key done fi cd $datadir } exit_key(){ exit_key=$1 cd $datadir/datadir-eth2-validator/validators/$exit_key keystore_name=$(ls *.json | sort) keystore_path=$datadir/datadir-eth2-validator/validators/$exit_key/$keystore_name if [[ $testnet == "true" ]] then docker run --rm -it --network testnet_ecredits -v "$keystore_path":/keystore.json -v "$passwordpath":/password.cfg --name validatorexit ecredits/lighthouse:latest lighthouse --network ecs_pubtest account validator exit --keystore /keystore.json --password-file /password.cfg --beacon-node "http://beacon:$rpcport" else docker run --rm -it --network mainnet_ecredits -v "$keystore_path":/keystore.json -v "$passwordpath":/password.cfg --name validatorexit ecredits/lighthouse:latest lighthouse --network ecs account validator exit --keystore /keystore.json --password-file /password.cfg --beacon-node "http://beacon:$rpcport" fi } load_container_names if [[ $existing_poa_setup == "true" ]] || [[ $existing_pos_setup == "true" ]] then if [[ $restart = "true" ]] then echo "Restarting container after update." if [[ $existing_pos_setup == "true" ]] then echo "+ Starting PoS node." start_pos_node else echo "+ Starting PoA node." start_node fi fi if [[ $new_setup == "true" ]] || [[ $existing_pos_setup == "true" ]] then while true; do if($testnet) then echo "* !!! TESTNET !!! *" fi echo "" echo "********************************************************************************" echo "* eSync Network Node Control Panel $VERSION *" echo "********************************************************************************" validator_container_runs=$(docker ps --format "{{.Names}},{{.Image}},{{.Status}}" | grep $POS_VALIDATOR_CONTAINERNAME) IFS=',' read -r -a validator_container_status <<<"$validator_container_runs" validator_beacon_runs=$(docker ps --format "{{.Names}},{{.Image}},{{.Status}}" | grep $POS_BEACON_CONTAINERNAME) IFS=',' read -r -a validator_beacon_status <<<"$validator_beacon_runs" validator_geth_runs=$(docker ps --format "{{.Names}},{{.Image}},{{.Status}}" | grep $POS_GETH_CONTAINERNAME) IFS=',' read -r -a validator_geth_status <<<"$validator_geth_runs" if [[ $validator_container_runs == "" ]] then echo " Validator: Not running" else echo " Validator: ${validator_container_status[0]} | $(echo ${validator_container_status[1]} | awk '{print substr($0, 21)}') | ${validator_container_status[2]}" fi if [[ $validator_beacon_runs == "" ]] then echo " Beacon: Not running" else echo " Beacon: ${validator_beacon_status[0]} | $(echo ${validator_beacon_status[1]} | awk '{print substr($0, 21)}') | ${validator_beacon_status[2]}" fi if [[ $validator_geth_runs == "" ]] then echo " Geth: Not running" else echo " Geth: ${validator_geth_status[0]} | $(echo ${validator_geth_status[1]} | awk '{print substr($0, 15)}') | ${validator_geth_status[2]}" fi echo "--------------------------------------------------------------------------------" echo "" COLUMNS=20 PS3="Existing setup identified. Please choose an option: " select opt in "Node status" "Update" "List accounts" "Update fee recipient" "Update etherbase" "Start node" "Stop node" "Import keys" "Exit keys" "Backup data" "Restore backup" "Show geth logs" "Show beacon logs" "Show validator logs" Help Exit do case $opt in "Node status") print_pos_node_state break ;; "Update") stop_pos_container sudo rm /usr/local/bin/ecredits_update sudo wget "$UPDATESCRIPTURL" -O /usr/local/bin/ecredits_update sudo chmod ugo+x /usr/local/bin/ecredits_update if($testnet) then exec ecredits_update testnet else exec ecredits_update fi break ;; "List accounts") list_accounts break ;; "Update fee recipient") set_fee_recipient_account stop_pos_container start_pos_node break ;; "Update etherbase") get_etherbase stop_pos_container start_pos_node break ;; "Start node") start_pos_node break ;; "Stop node") stop_pos_container break ;; "Import keys") manual_import_keys break ;; "Exit keys") exit_keys break ;; "Backup data") backup break ;; "Restore backup") restore_backup break ;; "Show geth logs") docker logs -f --tail=10 $POS_GETH_CONTAINERNAME break ;; "Show beacon logs") docker logs -f --tail=10 $POS_BEACON_CONTAINERNAME break ;; "Show validator logs") docker logs -f --tail=10 $POS_VALIDATOR_CONTAINERNAME break ;; "Help") pos_help break ;; "Exit") break 2 ;; esac echo "" COLUMNS=20 REPLY= done done else container_runs=$(docker ps | grep $POA_CONTAINERNAME) echo "" echo "********************************************************************************" echo "* eSync Network Node Control Panel $VERSION *" echo "********************************************************************************" if [[ $container_runs == "" ]] then echo " Node state: Not running" else echo " Node state: $(docker ps --format {{.Names}}) | $(docker ps --format "{{.Image}}" | awk '{print substr($0, 15)}') | $(docker ps --format {{.Status}})" fi echo "--------------------------------------------------------------------------------" echo "" COLUMNS=20 PS3="Existing eSync Network setup identified. Please choose an option: " select opt in "Set etherbase" "Start mining" "Node status" Update "List wallets" "Show logs" "Create additional account" "Stop node" "Start node" "Erase and Reinitialize" "Reset database" "Merge" Help Exit do case $opt in "Node status") print_node_state ;; "Erase and Reinitialize") echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" echo "! Please backup your private key before reinitialization! Otherwhise all funds on your account will be lost! !" echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" read -p "Did you backup your accounts private key from $datadir/datadir/keystore? [y/N] " keyBackedUp if [[ $keyBackedUp == "Y" || $keyBackedUp == "y" ]] then stop_container initialize download_files update_etherbase start_container read -p "Do you want to start mining? [Y/n] " startMiningInit if [[ $startMiningInit == "Y" || $startMiningInit == "y" || $startMiningInit == "" ]] then prepare_mining fi else echo "Please back up you key from $datadir/datadir/keystore and restart the initialization." fi ;; "Update") stop_container sudo rm /usr/local/bin/ecredits_update sudo wget "$UPDATESCRIPTURL" -O /usr/local/bin/ecredits_update sudo chmod ugo+x /usr/local/bin/ecredits_update exec ecredits_update ;; "Create additional account") create_account echo "Please be aware that the current account is not yet stored in the config for technical reasons!" read -p "Do you want to start mining? [Y/n] " startMining if [[ $startMining == "Y" || $startMining == "y" || $startMining == "" ]] then prepare_mining fi ;; "List wallets") print_wallets ;; "Set etherbase") stop_container update_etherbase start_container read -p "Do you want to start mining? [Y/n] " startMiningEtherbase if [[ $startMiningEtherbase == "Y" || $startMiningEtherbase == "y" || $startMiningEtherbase == "" ]] then prepare_mining fi ;; "Start mining") prepare_mining ;; "Reset database") reset_db ;; "Merge") if($testnet) then echo "Merge is not supported for the testnet. Please do a new setup." else merge fi break ;; "Show logs") show_logs ;; "Stop node") stop_container ;; "Start node") start_node ;; "Help") help ;; "Exit") break ;; esac echo "" COLUMNS=20 REPLY= done fi else echo "----------- No existing eSync Network setup identified. Initializing ... ------------" if($testnet) then echo "+ Initializing testnet!" else echo "+ Initializing mainnet!" fi initialize echo "+ Updating scripts ..." sudo rm /usr/local/bin/ecredits_update sudo wget "$UPDATESCRIPTURL" -O /usr/local/bin/ecredits_update sudo chmod ugo+x /usr/local/bin/ecredits_update if($testnet) then exec /usr/local/bin/ecredits_update testnet else exec /usr/local/bin/ecredits_update fi fi