#!/usr/bin/env bash # Exit when any command fail (global solution) set -e # IFS OIFS=$IFS # Quickstart script - Version QUICKSTART_VERSION="2.0.0" # OS (Linux / Unix based) DISTRIBUTION_NAME=$(awk -F '[="]*' '/^NAME/ { print $2 }' /dev/null $PERMISSION_PREFIX apt-get update $PERMISSION_PREFIX apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin -y echo -e "\nDocker and Docker Compose were installed for ${DISTRIBUTION_NAME}." elif [[ $DISTRIBUTION_NAME == *"CentOS"* || $DISTRIBUTION_NAME == "Red Hat Enterprise Linux" ]]; then $PERMISSION_PREFIX yum install -y yum-utils $PERMISSION_PREFIX yum-config-manager \ --add-repo \ https://download.docker.com/linux/${DISTRIBUTION_ID}/docker-ce.repo $PERMISSION_PREFIX yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin -y $PERMISSION_PREFIX systemctl start docker echo -e "\nDocker and Docker Compose were installed for ${DISTRIBUTION_NAME}." elif [[$DISTRIBUTION_NAME == "Fedora" ]]; then $PERMISSION_PREFIX dnf -y install dnf-plugins-core $PERMISSION_PREFIX dnf config-manager \ --add-repo \ https://download.docker.com/linux/${DISTRIBUTION_ID}/docker-ce.repo $PERMISSION_PREFIX dnf install docker-ce docker-ce-cli containerd.io docker-compose-plugin -y echo -e "\nDocker and Docker Compose were installed for ${DISTRIBUTION_NAME}." else display_error_and_exit "\nWe'd support next distributions: Ubuntu, Debian, CentOS, Red Hat Enterprise Linux, Fedora. Please check out your distribution and install Docker." fi } # Function to install and configure NTP for specific Linux distribution function install_ntp() { echo -e "\nInstall and configure NTP (chrony)...\n" if [[ $DISTRIBUTION_NAME == "Ubuntu" || $DISTRIBUTION_NAME == "Debian" ]]; then $PERMISSION_PREFIX apt-get install chrony -y elif [[ $DISTRIBUTION_NAME == *"CentOS"* || $DISTRIBUTION_NAME == "Red Hat Enterprise Linux" ]]; then $PERMISSION_PREFIX yum install chrony -y elif [[ $DISTRIBUTION_NAME == "Fedora" ]]; then $PERMISSION_PREFIX dnf install chrony -y else display_error_and_exit "\nWe'd support next distributions: Ubuntu, Debian, Red Hat Enterprise Linux, CentOS, Fedora. Please check out your distribution and install / configure NTP." fi $PERMISSION_PREFIX systemctl stop chrony $PERMISSION_PREFIX chronyd -q 'server 0.europe.pool.ntp.org iburst' $PERMISSION_PREFIX systemctl start chrony $PERMISSION_PREFIX systemctl enable chrony } # Function to check disk space function check_disk_space() { # Specify disk space treshold REQUIRED_DISK_SPACE_GB=100 # We're using mount volume where is quickstart.sh file mounted_volume=$(df --output=target quickstart.sh | tail -n1) total_volume_size_mb=$(df -k --output=size "$mounted_volume" | tail -n1) total_volume_size_gb=$((total_volume_size_mb / 1024 / 1024)) # Check with specified treshold if [ $total_volume_size_gb -lt $REQUIRED_DISK_SPACE_GB ]; then display_error_and_exit "\nCheck disk space.... ERROR - Not enoguh total drive space! you have $total_volume_size_gb GB you require at least $REQUIRED_DISK_SPACE_GB GB!" else echo -e "\nCheck disk space.... OK!" fi } # Function to check RAM memory space function check_ram_memory_space() { # Specify RAM memory treshold REQUIRED_RAM_GB=8 # Identify RAM memory amount total_ram_memory_size_mb=$(free -m | grep Mem: | awk '{print $2}') total_ram_memory_size_gb=$((total_ram_memory_size_mb / 1024)) # Check with specified treshold if [ $total_ram_memory_size_gb -lt $REQUIRED_RAM_GB ]; then display_error_and_exit "\nCheck RAM memory space... ERROR - Not enoguh total RAM memory space! you have $total_ram_memory_size_gb GB you require at least $REQUIRED_RAM_GB GB!" else echo -e "\nCheck RAM memory space... OK!" fi } # Function to check are needed tools installed or not function check_install_tools() { if [[ $(command -v jq) && $(command -v curl) ]]; then echo -e "\nCheck needed tools install... OK!" else echo -e "\nCheck needed tools install... ERROR - Needed tools aren't installed. Installing...\n" install_tools if [[ $(command -v jq) && $(command -v curl) ]]; then echo -e "\nCheck needed tools install... OK!" fi fi } # Function to check are Docker and Docker Compose installed or not function check_install_docker() { if [[ $(command -v docker) && $(command -v docker compose) ]]; then echo -e "\nCheck Docker and Docker Compose install... OK!" else echo -e "\nCheck Docker and Docker Compose install... ERROR - Docker / Docker Compose aren't installed. Installing...\n" install_docker if [[ $(command -v docker) && $(command -v docker compose) ]]; then echo -e "\nCheck Docker and Docker Compose install... OK!" fi fi } # Function to check needed node arguments function check_node_arguments() { if [[ ${VALID_ROLE_LIST[*]} =~ "$ROLE" ]]; then echo -e "\nCheck is valid role or not... OK!" else display_error_and_exit "\nCheck is valid role or not... ERROR - Invalid role - $ROLE! Please choose of the following: ${VALID_ROLE_LIST[*]}" fi if [[ ${VALID_NETWORK_LIST[*]} =~ "$NETWORK" ]]; then echo -e "\nCheck is valid network or not... OK!" else display_error_and_exit "\nCheck is valid network or not... ERROR - Invalid network - $NETWORK! Please choose of the following: ${VALID_NETWORK_LIST[*]}" fi if [ -z $NODE_KEY ]; then display_error_and_exit "\nCheck is valid node key or not... ERROR - Node key is empty. Please enter some string like 'fuse-[customer]-[role_name]'." elif [ ${#NODE_KEY} -lt 8 ]; then display_error_and_exit "\nCheck is valid node key or not... ERROR - Node key characters lower than 8 symbols. Please enter some string like 'fuse-[customer]-[role_name]'." else echo -e "\nCheck is valid node key or not... OK!" fi } # Sanity checks - call all `check_...` functions function sanity_checks() { echo -e "\nSanity checks..." # Check OS check_os # Check is all needed tools are installed check_install_tools # Check Docker and Docker Compose install check_install_docker # Check disk space check_disk_space # Check RAM memory space check_ram_memory_space # Check node arguments check_node_arguments echo -e "\nSanity checks finished successfully!" } # Setup - prepare node to run Fuse client function setup() { echo -e "\nSetup..." # Install and configure NTP install_ntp if [ "$OVERRIDE_VERSION_FILE" == false ] ; then echo -e "\nGrab docker Versions" wget -O versionFile $VERSION_FILE export $(grep -v '^#' versionFile | xargs) else echo -e "\n Using hardcoded version Info" fi # Specify image versions (generic) FUSE_CLIENT_DOCKER_REPOSITORY="fusenet/node" FUSE_CLIENT_DOCKER_IMAGE_VERSION="$DOCKER_IMAGE_NM_CLIENT" if [[ $NETWORK == "spark" ]]; then FUSE_CLIENT_DOCKER_IMAGE_VERSION="$SPARK_DOCKER_IMAGE_NM_CLIENT" fi # Specify images / versions (Spark) SPARK_VALIDATOR_DOCKER_REPOSITORY="fusenet/spark-validator-app" SPARK_VALIDATOR_DOCKER_IMAGE_VERSION="$DOCKER_IMAGE_FUSE_APP_VERSION" SPARK_NETSTATS_CLIENT_DOCKER_REPOSITORY="fusenet/netstat" SPARK_NETSTATS_CLIENT_DOCKER_IMAGE_VERSION="$DOCKER_IMAGE_NET_STATS_VERSION" # Specify images / versions (Fuse) FUSE_VALIDATOR_DOCKER_REPOSITORY="fusenet/validator-app" FUSE_VALIDATOR_DOCKER_IMAGE_VERSION="$DOCKER_IMAGE_FUSE_APP_VERSION" NETSTATS_CLIENT_DOCKER_REPOSITORY="fusenet/netstat" NETSTATS_CLIENT_DOCKER_IMAGE_VERSION="$DOCKER_IMAGE_NET_STATS_VERSION" # Specify entire image (generic) FUSE_CLIENT_DOCKER_IMAGE=$FUSE_CLIENT_DOCKER_REPOSITORY:$FUSE_CLIENT_DOCKER_IMAGE_VERSION # Specify entire image (Spark) SPARK_VALIDATOR_DOCKER_IMAGE=$SPARK_VALIDATOR_DOCKER_REPOSITORY:$SPARK_VALIDATOR_DOCKER_IMAGE_VERSION SPARK_NETSTATS_CLIENT_DOCKER_IMAGE=$SPARK_NETSTATS_CLIENT_DOCKER_REPOSITORY:$SPARK_NETSTATS_CLIENT_DOCKER_IMAGE_VERSION # Specify entire image (Fuse) FUSE_VALIDATOR_DOCKER_IMAGE=$FUSE_VALIDATOR_DOCKER_REPOSITORY:$FUSE_VALIDATOR_DOCKER_IMAGE_VERSION NETSTATS_CLIENT_DOCKER_IMAGE=$NETSTATS_CLIENT_DOCKER_REPOSITORY:$NETSTATS_CLIENT_DOCKER_IMAGE_VERSION echo -e "\nFuse - Client: $FUSE_CLIENT_DOCKER_IMAGE_VERSION" if [[ $NETWORK == "spark" ]]; then # Print versions echo -e "Fuse - Netstat: $SPARK_NETSTATS_CLIENT_DOCKER_IMAGE_VERSION" echo -e "\nPull Docker images...\n" if [[ $ROLE == "validator" ]]; then echo -e "Fuse - Validator: $SPARK_VALIDATOR_DOCKER_IMAGE_VERSION" $PERMISSION_PREFIX docker pull $SPARK_VALIDATOR_DOCKER_IMAGE fi # Pull needed Docker images $PERMISSION_PREFIX docker pull $FUSE_CLIENT_DOCKER_IMAGE $PERMISSION_PREFIX docker pull $SPARK_NETSTATS_CLIENT_DOCKER_IMAGE else # Print versions echo -e "\nFuse - Client: $FUSE_CLIENT_DOCKER_IMAGE_VERSION" echo -e "Fuse - Netstat: $NETSTATS_CLIENT_DOCKER_IMAGE_VERSION" echo -e "\nPull Docker images...\n" if [[ $ROLE == "validator" ]]; then echo -e "Fuse - Validator: $FUSE_VALIDATOR_DOCKER_IMAGE_VERSION" $PERMISSION_PREFIX docker pull $FUSE_VALIDATOR_DOCKER_IMAGE fi # Pull needed Docker images $PERMISSION_PREFIX docker pull $FUSE_CLIENT_DOCKER_IMAGE $PERMISSION_PREFIX docker pull $NETSTATS_CLIENT_DOCKER_IMAGE fi # Directories BASE_DIR="$(pwd)/fusenet" DATABASE_DIR=$BASE_DIR/database LOGS_DIR=$BASE_DIR/logs KEYSTORE_DIR=$BASE_DIR/keystore # Create needed directories mkdir -p $BASE_DIR mkdir -p $DATABASE_DIR mkdir -p $LOGS_DIR mkdir -p $KEYSTORE_DIR # Generate keystore file if [[ $ROLE == "validator" ]]; then if [ -n "$(find "$KEYSTORE_DIR" -type f -name 'UTC--*' -print -quit)" ]; then for keystore_file_path in "$KEYSTORE_DIR"/UTC--*; do PUBLIC_ADDRESS=$($PERMISSION_PREFIX cat "$keystore_file_path" | jq -r '.address') echo -e "\nPrivate key is present in directory. Your public address - 0x$PUBLIC_ADDRESS" echo -e "\nChecking if key file matches expected format..." # Extract just the file name keystore_file_name=$(basename "$keystore_file_path") keystore_file_name=$(echo "$keystore_file_name" | tr -d '[:space:]') echo "keystore_file_name: $keystore_file_name" # Check date format if [[ $keystore_file_name =~ UTC--[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}-[0-9]{2}-[0-9]{2}\.[0-9]+Z ]]; then echo -e "\nDate format is correct...." # Check if 42 characters at the end are missing if [[ $keystore_file_name =~ .{42}$ ]]; then echo -e "\npublic address not found at the end." # Check if the fractional seconds part is missing if [[ $keystore_file_name != *.*Z* ]]; then echo -e "\nFractional seconds are missing. Appending..." stripped_name=$(echo "$keystore_file_name" | sed 's/\(.*\)--.*/\1/') stripped_name=$(echo "$stripped_name" | awk '{gsub(/Z$/, ".123456000Z")}1') new_file_name="$stripped_name--$PUBLIC_ADDRESS" mv "$keystore_file_path" "$KEYSTORE_DIR/$new_file_name" else echo -e "\nFractional seconds are present." fi else echo -e "\nAppending public address...." stripped_name=$(echo "$keystore_file_name" | sed 's/\(.*\)--.*/\1/') stripped_name=$(echo "$stripped_name" | awk '{gsub(/Z$/, ".123456000Z")}1') new_file_name="$stripped_name--$PUBLIC_ADDRESS" mv "$keystore_file_path" "$KEYSTORE_DIR/$new_file_name" fi else echo -e "\nDate format is incorrect." stripped_name=$(echo "$keystore_file_name" | sed 's/\(.*\)--.*/\1/') stripped_name=$(echo "$stripped_name" | awk '{gsub(/Z$/, ".123456000Z")}1') new_file_name="$stripped_name--$PUBLIC_ADDRESS" mv "$keystore_file_path" "$KEYSTORE_DIR/$new_file_name" fi echo -e "\nSkipping creating a new private key..." done else generate_eth_private_key fi fi } # Run - run needed Docker containers function run() { echo -e "\nDelete old containers if it's exist..." # Delete old containers if they're exists $PERMISSION_PREFIX docker container rm -f fuse spark validator netstats >/dev/null 2>&1 echo -e "\nDone!" echo -e "\nGenerate processes.json file for 'netstats' Docker container..." cat < $BASE_DIR/processes.json [ { "name": "netstats-agent", "script": "app.js", "log_date_format": "YYYY-MM-DD HH:mm Z", "merge_logs": false, "watch": false, "max_restarts": 10, "exec_interpreter": "node", "exec_mode": "fork_mode" } ] EOF echo -e "\nDone!" echo -e "\nRun Docker container for ${NETWORK^} network. Role - ${ROLE^}" # Specify needed variables (Spark) # Netstats if [[ $NETWORK == "spark" ]]; then WS_SERVER="https://health.fusespark.io/ws" WS_SECRET="i5WsUJWaMUHOS2CwvTRy" fi # For node / bootnode if [[ $NETWORK == "spark" ]] && [[ $ROLE == "node" || $ROLE == "bootnode" ]]; then CONTAINER_NAME="spark" DB_PREFIX="spark" CONFIG="spark" NETSTATS_DOCKER_IMAGE=$SPARK_NETSTATS_CLIENT_DOCKER_IMAGE NETSTATS_VERSION=$SPARK_NETSTATS_CLIENT_DOCKER_IMAGE_VERSION fi # For explorer (archive) if [[ $NETWORK == "spark" && $ROLE == "explorer" ]]; then CONTAINER_NAME="spark" DB_PREFIX="spark_archive" CONFIG="spark_archive" NETSTATS_DOCKER_IMAGE=$SPARK_NETSTATS_CLIENT_DOCKER_IMAGE NETSTATS_VERSION=$SPARK_NETSTATS_CLIENT_DOCKER_IMAGE_VERSION fi # For validator if [[ $NETWORK == "spark" && $ROLE == "validator" ]]; then CONTAINER_NAME="spark" DB_PREFIX="spark" CONFIG="spark_validator" VALIDATOR_DOCKER_IMAGE=$SPARK_VALIDATOR_DOCKER_IMAGE NETSTATS_DOCKER_IMAGE=$SPARK_NETSTATS_CLIENT_DOCKER_IMAGE NETSTATS_VERSION=$SPARK_NETSTATS_CLIENT_DOCKER_IMAGE_VERSION fi # Specify needed variables (Fuse) # Netstats if [[ $NETWORK == "fuse" ]]; then WS_SERVER="https://health.fuse.io/ws" WS_SECRET="i5WsUJWaMUHOS2CwvTRy" fi # For node / bootnode if [[ $NETWORK == "fuse" ]] && [[ $ROLE == "node" || $ROLE == "bootnode" ]]; then CONTAINER_NAME="fuse" DB_PREFIX="fuse" CONFIG="fuse" NETSTATS_DOCKER_IMAGE=$NETSTATS_CLIENT_DOCKER_IMAGE NETSTATS_VERSION=$NETSTATS_CLIENT_DOCKER_IMAGE_VERSION fi # For explorer (archive) if [[ $NETWORK == "fuse" && $ROLE == "explorer" ]]; then CONTAINER_NAME="fuse" DB_PREFIX="fuse_archive" CONFIG="fuse_archive" NETSTATS_DOCKER_IMAGE=$NETSTATS_CLIENT_DOCKER_IMAGE NETSTATS_VERSION=$NETSTATS_CLIENT_DOCKER_IMAGE_VERSION fi # For validator if [[ $NETWORK == "fuse" && $ROLE == "validator" ]]; then CONTAINER_NAME="fuse" DB_PREFIX="fuse" CONFIG="fuse_validator" VALIDATOR_DOCKER_IMAGE=$FUSE_VALIDATOR_DOCKER_IMAGE NETSTATS_DOCKER_IMAGE=$NETSTATS_CLIENT_DOCKER_IMAGE NETSTATS_VERSION=$NETSTATS_CLIENT_DOCKER_IMAGE_VERSION fi # Run Docker container if [[ $ROLE == "node" || $ROLE == "bootnode" || $ROLE == "explorer" ]]; then $PERMISSION_PREFIX docker run \ --detach \ --name $CONTAINER_NAME \ --volume $DATABASE_DIR:/nethermind/nethermind_db/$DB_PREFIX \ --volume $KEYSTORE_DIR:/nethermind/keystore \ --volume $LOGS_DIR:/nethermind/logs \ --log-opt max-size=10m \ --log-opt max-file=25 \ --log-opt compress=true \ --hostname $CONTAINER_NAME \ -p 30303:30300/tcp \ -p 30303:30300/udp \ -p 8545:8545 \ -p 8546:8546 \ --restart always \ $FUSE_CLIENT_DOCKER_IMAGE \ --config $CONFIG \ --Init.WebSocketsEnabled true \ --HealthChecks.Enabled true \ --HealthChecks.Slug /api/health \ --Discovery.Bootnodes $BOOTNODES_LIST \ --Network.Bootnodes $BOOTNODES_LIST \ --JsonRpc.EnabledModules "Eth,Web3,RPC,Net,Parity,Health" # Run Netstat $PERMISSION_PREFIX docker run \ --detach \ --name "netstats" \ --net container:$CONTAINER_NAME \ --log-opt max-size=10m \ --log-opt max-file=25 \ --log-opt compress=true \ --restart always \ --memory "250m" \ --volume $BASE_DIR/processes.json:/app/processes.json \ --env NODE_ENV=production \ --env RPC_HOST=$CONTAINER_NAME \ --env RPC_PORT=8545 \ --env LISTENING_PORT=30303 \ --env INSTANCE_NAME=$NODE_KEY \ --env ROLE=${ROLE^} \ --env BRIDGE_VERSION="" \ --env FUSE_APP_VERSION="" \ --env NETSTATS_VERSION=$NETSTATS_VERSION \ --env PARITY_VERSION="" \ --env CONTACT_DETAILS="" \ --env WS_SERVER=$WS_SERVER \ --env WS_SECRET=$WS_SECRET \ --env VERBOSITY=2 \ --entrypoint pm2 \ $NETSTATS_DOCKER_IMAGE \ start \ processes.json \ --no-daemon fi if [[ $ROLE == "validator" ]]; then $PERMISSION_PREFIX docker run \ --detach \ --name $CONTAINER_NAME \ --volume $DATABASE_DIR:/nethermind/nethermind_db/$DB_PREFIX \ --volume $KEYSTORE_DIR:/nethermind/keystore \ --volume $LOGS_DIR:/nethermind/logs \ --log-opt max-size=10m \ --log-opt max-file=25 \ --log-opt compress=true \ --hostname $CONTAINER_NAME \ -p 8545:8545 \ -p 30303:30300/tcp \ -p 30303:30300/udp \ --restart always \ $FUSE_CLIENT_DOCKER_IMAGE \ --config $CONFIG \ --JsonRpc.Enabled true \ --Discovery.Bootnodes $BOOTNODES_LIST \ --Network.Bootnodes $BOOTNODES_LIST \ --JsonRpc.EnabledModules [Eth,Web3,Personal,Net,Parity] \ --JsonRpc.Host 0.0.0.0 \ --JsonRpc.Port 8545 \ --KeyStore.PasswordFiles "keystore/pass.pwd" \ --KeyStore.EnodeAccount "0x$PUBLIC_ADDRESS" \ --KeyStore.UnlockAccounts "0x$PUBLIC_ADDRESS" \ --KeyStore.BlockAuthorAccount "0x$PUBLIC_ADDRESS" \ --HealthChecks.Enabled true \ --HealthChecks.Slug /api/health # Run Validator app $PERMISSION_PREFIX docker run \ --detach \ --name "validator" \ --net container:$CONTAINER_NAME \ --volume $KEYSTORE_DIR:/config/keys/FuseNetwork \ --volume $KEYSTORE_DIR/pass.pwd:/config/pass.pwd \ --restart always \ $VALIDATOR_DOCKER_IMAGE # Run Netstat $PERMISSION_PREFIX docker run \ --detach \ --name "netstats" \ --net container:$CONTAINER_NAME \ --log-opt max-size=10m \ --log-opt max-file=25 \ --log-opt compress=true \ --restart always \ --memory "250m" \ --volume $BASE_DIR/processes.json:/app/processes.json \ --env NODE_ENV=production \ --env RPC_HOST=$CONTAINER_NAME \ --env RPC_PORT=8545 \ --env LISTENING_PORT=30303 \ --env INSTANCE_NAME="${NODE_KEY}_0x${PUBLIC_ADDRESS}" \ --env ROLE=${ROLE^} \ --env BRIDGE_VERSION="" \ --env FUSE_APP_VERSION="1.0.0" \ --env NETSTATS_VERSION=$NETSTATS_VERSION \ --env PARITY_VERSION="" \ --env CONTACT_DETAILS="" \ --env WS_SERVER=$WS_SERVER \ --env WS_SECRET=$WS_SECRET \ --env VERBOSITY=2 \ --entrypoint pm2 \ $NETSTATS_DOCKER_IMAGE \ start \ processes.json \ --no-daemon fi # Get ENODE public address get_enode } # Get ENODE public address function get_enode() { # Need to wait 30 seconds to fetch ENODE URL endpoint echo -e "\nYou must wait 15 seconds for the node to start and initialize..." sleep 15 echo -e "\nRetriving enode public address...\n" # Identify ENODE address ENODE=$(curl --silent -X POST --data '{"jsonrpc":"2.0","method":"parity_enode","params":[],"id":67}' localhost:8545 | jq '.result') # Identify public IP address PERSONAL_PUBLIC_IP=$(curl ifconfig.me) # Print result ENODE_PUBLIC_ADDRESS=$(echo "${ENODE/"0.0.0.0"/$PERSONAL_PUBLIC_IP}") echo -e "\n${ENODE_PUBLIC_ADDRESS} - your public listen address." } # Function to create your private key function generate_eth_private_key() { echo -e "\nGenerating your personal ETH priavate key...\n" while true; do read -s -r -p "Passphrase: " PASSPHRASE echo read -s -r -p "Passphrase (again): " PASSPHRASE_SECOND echo [ "$PASSPHRASE" = "$PASSPHRASE_SECOND" ] && break echo "Passphrases do not match, please try again" done echo "$PASSPHRASE" >$KEYSTORE_DIR/pass.pwd # Generate private key (Geth) $PERMISSION_PREFIX docker pull ethereum/client-go:stable $PERMISSION_PREFIX docker run --rm -v $KEYSTORE_DIR:/root/.ethereum/keystore ethereum/client-go:stable account new --password /root/.ethereum/keystore/pass.pwd >/dev/null 2>&1 # Get full keystore file path KEYSTORE_FILE_PATH=$($PERMISSION_PREFIX find $KEYSTORE_DIR -type f -name "UTC--*") PUBLIC_ADDRESS=$($PERMISSION_PREFIX cat $KEYSTORE_DIR/UTC--* | jq -r '.address') echo -e "ETH public address: 0x$PUBLIC_ADDRESS." >$(pwd)/validator_info.txt echo -e "\nKeystore file: $KEYSTORE_FILE_PATH" >>$(pwd)/validator_info.txt echo -e "\nKeystore passphrase file: ${KEYSTORE_DIR}/pass.pwd\n\nNote: PLEASE DO NOT SHARE THIS FILE!" >>$(pwd)/validator_info.txt echo -e "\nAdd data stored in $(pwd)/validator_info.txt" } function unlock_account() { KEYSTORE_DIR=$BASE_DIR/keystore if [ ! "$(ls $KEYSTORE_DIR/UTC--**)" ]; then display_error_and_exit "No key store file found" fi pass=$(<"$KEYSTORE_DIR/pass.pwd") PUBLIC_ADDRESS=$($PERMISSION_PREFIX cat $KEYSTORE_DIR/UTC--* | jq -r '.address') RESULT=$(curl localhost:8545 -H 'Content-Type: application/json;charset=UTF-8' -H 'Accept: application/json, text/plain, /' -H 'Cache-Control: no-cache' -X \ POST --data '{"jsonrpc":"2.0","method":"personal_unlockAccount","params":["'"$PUBLIC_ADDRESS"'", "'"$pass"'"],"id":67}' | jq '.result') if [[ "$RESULT" != "true" ]]; then display_error_and_exit "Failed to unlock account" fi } function lock_account() { if [ ! "$(ls $KEYSTORE_DIR/UTC--**)" ]; then display_error_and_exit "No key store file found" fi PUBLIC_ADDRESS=$($PERMISSION_PREFIX cat $KEYSTORE_DIR/UTC--* | jq -r '.address') RESULT=$(curl localhost:8545 -H 'Content-Type: application/json;charset=UTF-8' -H 'Accept: application/json, text/plain, /' -H 'Cache-Control: no-cache' -X POST --data '{"jsonrpc":"2.0","method":"personal_lockAccount","params":["'"$PUBLIC_ADDRESS"'"],"id":67}' | jq '.result') if [[ "$RESULT" != "true" ]]; then display_error_and_exit "Failed to lock account" fi } function send_tx_to_consensus() { local DATA=$1 if [[ $DATA == "" ]]; then display_error_and_exit "No data supplied cannot send message to consensus" fi if [ ! "$($PERMISSION_PREFIX docker ps -q -f name=fuse)" ]; then display_error_and_exit "Fuse container not running cannot send tx to consensus" fi unlock_account if [[ $NETWORK == "spark" ]]; then CONSENSUS_ADDR="0x8C682051D70301A0ca913Ce0A0e71539702E1122" else CONSENSUS_ADDR="0x3014ca10b91cb3D0AD85fEf7A3Cb95BCAc9c0f79" fi PUBLIC_ADDRESS=$($PERMISSION_PREFIX cat $KEYSTORE_DIR/UTC--* | jq -r '.address') echo "$PUBLIC_ADDRESS" NONCE=$(curl localhost:8545 -H 'Content-Type: application/json;charset=UTF-8' -H 'Accept: application/json, text/plain, /' -H 'Cache-Control: no-cache' -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionCount","params":["'"$PUBLIC_ADDRESS"'"],"id":67}' | jq '.result') NONCE=${NONCE:1:-1} PUBLIC_ADDRESS="0x$PUBLIC_ADDRESS" TXHASH=$(curl --data '{"jsonrpc":"2.0","method":"eth_sendTransaction","params":[{"from":"'"$PUBLIC_ADDRESS"'","to":"'"$CONSENSUS_ADDR"'","value":0,"Nonce":"'"$NONCE"'", "Gas":"1000000","GasPrice":"10000000000","ChainId":"122","Data":"'"$DATA"'"}],"id":67}' -H "Content-Type: application/json" -X POST localhost:8545) echo -e "\nRequest sent TX_ID = ${TXHASH}" lock_account } # Function to create version.`date`.txt file function generate_version_file() { date=$(date '+%Y-%m-%d') echo -e "\nCreate / override version.txt.${date} file..." echo -e "ROLE=${ROLE}" >version.txt.$date echo -e "\nENODE_PUBLIC_ADDRESS=${ENODE_PUBLIC_ADDRESS}" >>version.txt.$date echo -e "\nFUSE_CLIENT_VERSION=${FUSE_CLIENT_DOCKER_IMAGE_VERSION}" >>version.txt.$date echo -e "\nNETSTATS_CLIENT_VERSION=${NETSTATS_CLIENT_DOCKER_IMAGE_VERSION}" >>version.txt.$date } # Help Help() { echo "The Fuse client - Bootstrap your own node." echo echo "Description:" echo " Script allow to run locally your own Fuse node based on specific role." echo echo "Note:" echo " quickstart.sh supports next Linux / Unix based distributions: Ubuntu, Debian, Fedora, CentOS, RHEL." echo echo "Usage:" echo " ./quickstart.sh [-r|-n|-k||-v|-h]" echo echo "Options:" echo " -r Specify needed node role. Available next roles: 'node', 'bootnode', 'explorer', 'validator'" echo " -n Network (mainnet or testnet). Available next values: 'fuse' and 'spark'" echo " -k Node key name for https://health.fuse.io. Example: 'my-own-fuse-node'" echo " -v Script version" echo " -u Unjail a node" echo " -m Flag a node for maintenance" echo " -h Help page" } # Check if any options presents after script if [ $# -lt 1 ]; then Help exit 1 fi # Check is right argument specified check_args() { if [[ $OPTARG =~ ^-[r/n/k/v/h/u/m]$ ]]; then display_error_and_exit "Unknow argument $OPTARG for option $opt!" fi } # Parse arguments while getopts ":r:n:k:vhum" flag; do case "${flag}" in r) check_args ROLE=${OPTARG} ;; n) check_args NETWORK=${OPTARG} ;; k) check_args NODE_KEY=${OPTARG} ;; u) check_args send_tx_to_consensus "0x6eae5b11" exit 1 ;; m) check_args send_tx_to_consensus "0x6c376cc5" exit 1 ;; v) check_args echo $QUICKSTART_VERSION exit 1 ;; h) check_args Help exit 1 ;; *) echo "No reasonable options found!" exit 1 ;; esac done # Go go go! echo -e "Start / update your own Fuse (Spark) node!" # Check all pre - requirements (needed env variables, installed tools, etc.) sanity_checks # Prepare node - pull latest Docker images create needed directories setup # Run run # Specify version file with client / netstat version, role, etc. generate_version_file echo -e "\nContainers started and running in background!"