github.com/FUSIONFoundation/efsn@v3.6.2-0.20200916075423-dbb5dd5d2cc7+incompatible/QuickNodeSetup/fsnNode.sh (about) 1 #!/bin/bash 2 # FUSION Foundation 3 4 # no need for a complex versioning scheme, just increment 5 SCRIPT_VERSION=10 6 7 # historically grown, changing this would break stuff 8 BASE_DIR="/home/$USER" 9 10 # global configuration file containing node settings 11 CONF_FILE="$BASE_DIR/fusion-node/node.json" 12 13 # set to 1 to enable debug mode, or use -d argument 14 DEBUG_MODE=0 15 16 txtred=$(tput setaf 1) # Red 17 txtgrn=$(tput setaf 2) # Green 18 txtylw=$(tput setaf 3) # Yellow 19 txtrst=$(tput sgr0) # Text reset 20 21 while getopts ":d" opt; do 22 case $opt in 23 d) DEBUG_MODE=1 ;; 24 \?) echo "${txtred}Invalid argument: -$OPTARG${txtrst}" ; exit 1 ;; 25 esac 26 done 27 28 [ $DEBUG_MODE -eq 1 ] && set -x 29 30 scriptUpdate() { 31 # get the first 150 bytes and extract the script version 32 remoteVersion="$(curl -fsSL -r 0-150 "https://raw.githubusercontent.com/FUSIONFoundation/efsn/master/QuickNodeSetup/fsnNode.sh" | grep -Po '(?<=SCRIPT_VERSION=)[0-9]+')" 33 # prevent an error if the version number can't be read 34 if [ -n "$remoteVersion" ]; then 35 if [ $SCRIPT_VERSION -lt $remoteVersion ]; then 36 echo "tbd" 37 fi 38 fi 39 } 40 41 distroChecks() { 42 if ! command -v lsb_release >/dev/null 2>&1; then 43 echo "${txtred}Missing command 'lsb_release', please install it${txtrst}" 44 exit 1 45 fi 46 # check for distribution and corresponding version (release) 47 distroID="$(lsb_release -si)" 48 distroMajorVerion="$(lsb_release -sr | sed -E 's/([0-9]+).*/\1/')" 49 if [ "$distroID" = "Ubuntu" ]; then 50 if [ $distroMajorVerion -lt 18 ]; then 51 echo "${txtred}Warning: Unsupported Ubuntu release${txtrst}" 52 echo "Currently supported: Ubuntu 18.04 or newer" 53 # exit 1 54 fi 55 elif [ "$distroID" = "CentOS" ]; then 56 if [ $distroMajorVerion -lt 7 ]; then 57 echo "${txtred}Warning: Unsupported CentOS release${txtrst}" 58 echo "Currently supported: CentOS 7 or newer" 59 # exit 1 60 fi 61 else 62 echo "${txtred}Warning: May be unsupported distribution${txtrst}" 63 echo "Ubuntu and CentOS is advised" 64 #exit 1 # don't forbid other OS systems but warning 65 fi 66 } 67 68 dependChecks() { 69 echo 70 echo "${txtylw}Checking dependencies${txtrst}" 71 72 if ! command -v docker >/dev/null 2>&1; then 73 echo "${txtred}Missing command 'docker', please install it${txtrst}" 74 exit 1 75 fi 76 77 neededCmds="curl jq locate" 78 neededPkgs="ca-certificates curl jq mlocate" 79 missingCmds="" 80 for cmd in $neededCmds; do 81 if ! command -v $cmd >/dev/null 2>&1; then 82 missingCmds="$missingCmds $cmd" 83 fi 84 done 85 86 if [ -n "$missingCmds" ]; then 87 if command -v apt >/dev/null 2>&1; then 88 sudo apt install -q -y $neededPkgs 89 elif command -v yum >/dev/null 2>&1; then 90 sudo yum install -q -y $neededPkgs 91 else 92 echo "${txtred}Please install missing commands: $missingCmds${txtrst}" 93 exit 1 94 fi 95 fi 96 97 echo "${txtred}✓${txtrst} Check dependencies passed" 98 } 99 100 sanityChecks() { 101 if [ -z "$BASH" ]; then 102 echo "${txtred}The setup script has to be run in the bash shell.${txtrst}" 103 echo "Please run it again in bash:" 104 echo "bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/FUSIONFoundation/efsn/master/QuickNodeSetup/fsnNode.sh)\"" 105 exit 1 106 fi 107 108 # checking the effective user id, where 0 is root 109 if [ $EUID -ne 0 ]; then 110 # make sure that the script isn't run as root and non-root user alternately 111 if sudo [ -f "/home/root/fusion-node/node.json" ]; then 112 echo "${txtred}Warning: The setup script was originally run with root privileges.${txtrst}" 113 echo "We suggest you to run it again as user root or by invoking sudo:" 114 echo "sudo bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/FUSIONFoundation/efsn/master/QuickNodeSetup/fsnNode.sh)\"" 115 echo 116 local question="${txtylw}Are you sure you want to continue as user $USER?${txtrst} [Y/n] " 117 askToContinue "$question" 118 if [ $? -eq 1 ]; then 119 exit 1 120 fi 121 fi 122 fi 123 124 # using locate without prior update is a perf vs reliability tradeoff 125 # we don't want to wait until the whole fs is indexed or even use find 126 if [ $(sudo locate -r .*/efsn/chaindata$ -c) -gt 1 ]; then 127 echo "${txtred}Warning: Found more than one chaindata directory.${txtrst}" 128 echo "Please check and clean up the system manually first." 129 sudo locate -r .*/efsn/chaindata$ 130 131 echo 132 local question="${txtylw}Do you believe this issue is already resolved?${txtrst} [Y/n] " 133 askToContinue "$question" 134 if [ $? -eq 1 ]; then 135 exit 1 136 fi 137 fi 138 } 139 140 getDockerImageName() { 141 local nodetype="$1" 142 local testnet="$2" 143 case $nodetype in 144 "minerandlocalgateway") 145 if [ "$testnet" = "true" ]; then 146 echo "fusionnetwork/testnet-minerandlocalgateway" 147 else 148 echo "fusionnetwork/minerandlocalgateway" 149 fi 150 ;; 151 "efsn") 152 if [ "$testnet" = "true" ]; then 153 echo "fusionnetwork/testnet-efsn" 154 else 155 echo "fusionnetwork/efsn" 156 fi 157 ;; 158 "gateway") 159 if [ "$testnet" = "true" ]; then 160 echo "fusionnetwork/testnet-gateway" 161 else 162 echo "fusionnetwork/gateway" 163 fi 164 ;; 165 *) echo "" 166 ;; 167 esac 168 } 169 170 checkUpdate() { 171 local nodetype="$(getCfgValue 'nodeType')" 172 local testnet="$(getCfgValue 'testnet')" 173 local imagename="$(getDockerImageName $nodetype $testnet)" 174 175 # get the container creation date as unix epoch for easy comparison 176 local dateCreated=$(date -d "$(sudo docker container inspect -f "{{.Created}}" fusion 2>/dev/null)" '+%s') 177 # query the Docker Hub registry for when the image was last updated 178 local dateUpdated="$(curl -fsL "https://registry.hub.docker.com/v2/repositories/$imagename" | jq -r '.last_updated')" 179 # make sure that no update is triggered if the registry returns no data 180 [ -z "$dateUpdated" ] && dateUpdated=0 || dateUpdated=$(date -d "$dateUpdated" '+%s') 181 # if the container is older than dateUpdated return 0, otherwise return 1 182 [ $dateCreated -lt $dateUpdated ] && return 0 || return 1 183 } 184 185 pauseScript() { 186 local fackEnterKey 187 read -s -p "${txtylw}Press [Enter] to continue...${txtrst}" fackEnterKey 188 } 189 190 askToContinue() { 191 local input 192 while true; do 193 read -n1 -r -s -p "$1" input 194 case $input in 195 [yY]) echo; return 0 ;; 196 [nN]) echo; return 1 ;; 197 *) echo -e "\n${txtred}Invalid input${txtrst}" ;; 198 esac 199 done 200 } 201 202 getCfgValue() { 203 # read configuration values from the respective JSON files 204 local cfg_arg="$1" 205 local cfg_val 206 207 if [ $# -ne 1 ]; then 208 echo "${txtred}Incorrect number of arguments ($#)${txtrst}" 209 return 1 210 fi 211 212 local keystore_file="$BASE_DIR/fusion-node/data/keystore/UTC.json" 213 local cfg_file="$CONF_FILE" 214 215 # extra spacing for readability 216 if [ "$cfg_arg" = "address" ]; then 217 cfg_val="0x$(jq -r '.address' $keystore_file)" 218 219 elif [ "$cfg_arg" = "nodeType" ]; then 220 cfg_val="$(jq -r '.nodeType' $cfg_file)" 221 222 elif [ "$cfg_arg" = "testnet" ]; then 223 cfg_val="$(jq -r '.testnet' $cfg_file)" 224 225 elif [ "$cfg_arg" = "autobt" ]; then 226 cfg_val="$(jq -r '.autobt' $cfg_file)" 227 228 elif [ "$cfg_arg" = "mining" ]; then 229 cfg_val="$(jq -r '.mining' $cfg_file)" 230 231 elif [ "$cfg_arg" = "nodeName" ]; then 232 cfg_val="$(jq -r '.nodeName' $cfg_file)" 233 234 else 235 echo "${txtred}Unknown argument ($cfg_arg)${txtrst}" 236 return 1 237 fi 238 239 echo "$cfg_val" 240 } 241 242 putCfgValue() { 243 # write configuration values to the respective JSON files 244 local cfg_arg="$1" 245 local cfg_val="$2" 246 247 if [ $# -ne 2 ]; then 248 echo "${txtred}Incorrect number of arguments ($#)${txtrst}" 249 return 1 250 fi 251 252 # create main node data directory 253 mkdir -p "$BASE_DIR/fusion-node/" 254 255 local cfg_file="$CONF_FILE" 256 257 # create minimal JSON skeleton for jq if the config file doesn't exist yet 258 if [ ! -f "$cfg_file" ]; then 259 echo '{}' > "$cfg_file" 260 fi 261 262 # extra spacing for readability 263 if [ "$cfg_arg" = "nodeType" ]; then 264 cat <<< "$(jq --arg nodeType "$cfg_val" '.nodeType = $nodeType' < $cfg_file)" > "$cfg_file" 265 266 elif [ "$cfg_arg" = "testnet" ]; then 267 cat <<< "$(jq --arg testnet "$cfg_val" '.testnet = $testnet' < $cfg_file)" > "$cfg_file" 268 269 elif [ "$cfg_arg" = "autobt" ]; then 270 cat <<< "$(jq --arg autobt "$cfg_val" '.autobt = $autobt' < $cfg_file)" > "$cfg_file" 271 272 elif [ "$cfg_arg" = "mining" ]; then 273 cat <<< "$(jq --arg mining "$cfg_val" '.mining = $mining' < $cfg_file)" > "$cfg_file" 274 275 elif [ "$cfg_arg" = "nodeName" ]; then 276 cat <<< "$(jq --arg nodeName "$cfg_val" '.nodeName = $nodeName' < $cfg_file)" > "$cfg_file" 277 278 else 279 echo "${txtred}Unknown argument ($cfg_arg)${txtrst}" 280 return 1 281 fi 282 } 283 284 updateKeystoreFile() { 285 echo 286 echo "${txtylw}Open your keystore file (its name usually starts with UTC--) in any" 287 echo "plaintext editor (like notepad) and copy and paste its full contents" 288 echo "here; it should contain a lot of cryptic text surrounded by \"{...}\".${txtrst}" 289 local keystorejson 290 while true; do 291 read -p "Paste keystore contents: " keystorejson 292 if [ -z "$keystorejson" ]; then 293 echo "${txtred}Keystore contents required${txtrst}" 294 elif [[ "$keystorejson" != *"address"* ]]; then 295 echo "${txtred}Invalid keystore format${txtrst}" 296 elif ! jq -e . >/dev/null 2>&1 <<< "$keystorejson"; then 297 echo "${txtred}Invalid keystore format${txtrst}" 298 else 299 # this breaks for me - avoid xargs if possible 300 #echo $keystorejson | xargs > "$BASE_DIR/fusion-node/data/keystore/UTC.json" 301 # this should be a pretty robust solution 302 mkdir -p "$BASE_DIR/fusion-node/data/keystore/" 303 printf '%s' "$keystorejson" > "$BASE_DIR/fusion-node/data/keystore/UTC.json" 304 305 echo 306 local address="$(getCfgValue 'address')" 307 local question="${txtylw}Is this the expected address of your staking wallet?${txtrst} $address [Y/n] " 308 askToContinue "$question" 309 if [ $? -eq 1 ]; then 310 echo "${txtred}Please use the right keystore file${txtrst}" 311 else 312 break 313 fi 314 fi 315 done 316 } 317 318 updateKeystorePass() { 319 echo 320 echo "${txtylw}Please enter or paste the password that unlocks the keystore file.${txtrst}" 321 local keystorepass 322 while true; do 323 read -p "Enter keystore password: " keystorepass 324 if [ -z "$keystorepass" ]; then 325 echo "${txtred}Keystore password required${txtrst}" 326 else 327 break 328 fi 329 done 330 printf '%s' "$keystorepass" > "$BASE_DIR/fusion-node/password.txt" 331 } 332 333 updateExplorerListing() { 334 echo 335 question="${txtylw}Do you want your node to be listed on the node explorer?${txtrst} [Y/n] " 336 local nodename 337 askToContinue "$question" 338 if [ $? -eq 0 ]; then 339 echo 340 echo "${txtylw}What name do you want the node to have? No spaces or special characters, three characters minimum.${txtrst}" 341 while true; do 342 read -p "Enter node name: " nodename 343 if [ -z "$nodename" ]; then 344 echo "${txtred}Node name required${txtrst}" 345 elif [[ ! "$nodename" =~ ^[-_a-zA-Z0-9]{3,}$ ]]; then 346 echo "${txtred}Invalid characters in node name or too short${txtrst}" 347 echo "Only a-z, 0-9, - and _ allowed, minimum 3 chars" 348 else 349 break 350 fi 351 done 352 echo "${txtgrn}✓${txtrst} The node will be listed on the node explorer as \"$nodename\"" 353 else 354 echo "${txtred}✓${txtrst} The node will not be listed on the node explorer" 355 fi 356 putCfgValue 'nodeName' "$nodename" 357 } 358 359 initConfig() { 360 local question 361 362 # purge existing node data; the user was warned about this, 363 # he can reconfigure the node if that's not what he wants 364 sudo rm -rf "$BASE_DIR/fusion-node/" 365 366 echo 367 echo "${txtylw}Please select the node type to install:${txtrst}" 368 echo "${txtylw}1. minerandlocalgateway${txtrst} - miner with local API access; if unsure, select this" 369 echo "${txtylw}2. efsn${txtrst} - pure miner without local API access; only select if you have a good reason" 370 echo "${txtylw}3. gateway${txtrst} - local API access without mining; doesn't require keystore and password" 371 local nodetype 372 local input 373 while true; do 374 read -n1 -r -s -p "Select option [1-3] " input 375 case $input in 376 1) nodetype="minerandlocalgateway"; break ;; 377 2) nodetype="efsn"; break ;; 378 3) nodetype="gateway"; break ;; 379 *) echo -e "\n${txtred}Invalid input${txtrst}" ;; 380 esac 381 done 382 echo 383 echo "${txtgrn}✓${txtrst} Selected node type $nodetype" 384 putCfgValue 'nodeType' "$nodetype" 385 386 echo 387 question="${txtylw}Do you want to install a mainnet node?${txtrst} [Y/n] " 388 local testnet="false" 389 askToContinue "$question" 390 if [ $? -eq 0 ]; then 391 echo "${txtgrn}✓${txtrst} Installing mainnet node" 392 else 393 echo 394 question="${txtylw}Are you sure you want to install a testnet node?${txtrst} [Y/n] " 395 askToContinue "$question" 396 if [ $? -eq 0 ]; then 397 testnet="true" 398 echo "${txtgrn}✓${txtrst} Installing testnet node" 399 else 400 echo "${txtgrn}✓${txtrst} Installing mainnet node" 401 fi 402 fi 403 putCfgValue 'testnet' "$testnet" 404 405 if [ "$nodetype" = "minerandlocalgateway" -o "$nodetype" = "efsn" ]; then 406 updateKeystoreFile 407 echo "${txtgrn}✓${txtrst} Saved keystore file" 408 409 updateKeystorePass 410 echo "${txtgrn}✓${txtrst} Saved keystore password" 411 412 echo 413 question="${txtylw}Do you want your node to auto-buy tickets required for staking?${txtrst} [Y/n] " 414 local autobuy="false" 415 askToContinue "$question" 416 if [ $? -eq 0 ]; then 417 autobuy="true" 418 echo "${txtgrn}✓${txtrst} Enabled ticket auto-buy" 419 else 420 echo "${txtred}✓${txtrst} Disabled ticket auto-buy" 421 fi 422 putCfgValue 'autobt' "$autobuy" 423 424 echo 425 question="${txtylw}Do you want your node to mine blocks (participate in staking)?${txtrst} [Y/n] " 426 local mining="false" 427 askToContinue "$question" 428 if [ $? -eq 0 ]; then 429 mining="true" 430 echo "${txtgrn}✓${txtrst} Enabled mining of blocks" 431 else 432 echo "${txtred}✓${txtrst} Disabled mining of blocks" 433 fi 434 putCfgValue 'mining' "$mining" 435 fi 436 437 echo 438 question="${txtylw}Do you want your node to auto-start after boot to prevent downtimes?${txtrst} [Y/n] " 439 askToContinue "$question" 440 if [ $? -eq 0 ]; then 441 if [ ! -f "/etc/systemd/system/fusion.service" ]; then 442 sudo curl -fsSL "https://raw.githubusercontent.com/FUSIONFoundation/efsn/master/QuickNodeSetup/fusion.service" \ 443 -o "/etc/systemd/system/fusion.service" 444 fi 445 sudo systemctl daemon-reload 446 sudo systemctl -q enable fusion 447 echo "${txtgrn}✓${txtrst} Enabled node auto-start" 448 else 449 # suppress warning about nonexisting service unit on fresh install 450 sudo systemctl -q disable fusion 2>/dev/null 451 echo "${txtred}✓${txtrst} Disabled node auto-start" 452 fi 453 454 updateExplorerListing 455 } 456 457 removeContainer() { 458 # only try to stop the container if it's running 459 [ "$(sudo docker container inspect -f "{{.State.Running}}" fusion 2>/dev/null)" = "true" ] && stopNode 460 # remove container and base images no matter what 461 echo 462 echo "${txtylw}Removing container and base images${txtrst}" 463 sudo docker rm fusion >/dev/null 2>&1 464 # mainnet images 465 sudo docker rmi fusionnetwork/minerandlocalgateway \ 466 fusionnetwork/efsn \ 467 fusionnetwork/gateway >/dev/null 2>&1 468 sudo docker rmi fusionnetwork/minerandlocalgateway2 \ 469 fusionnetwork/efsn2 \ 470 fusionnetwork/gateway2 >/dev/null 2>&1 471 # testnet images 472 sudo docker rmi fusionnetwork/testnet-minerandlocalgateway \ 473 fusionnetwork/testnet-efsn \ 474 fusionnetwork/testnet-gateway >/dev/null 2>&1 475 echo "${txtgrn}✓${txtrst} Removed container and base images" 476 } 477 478 createContainer() { 479 # read configuration files 480 echo 481 echo "${txtylw}Reading node configuration${txtrst}" 482 local nodetype="$(getCfgValue 'nodeType')" 483 local testnet="$(getCfgValue 'testnet')" 484 local nodename="$(getCfgValue 'nodeName')" 485 if [ "$nodetype" = "minerandlocalgateway" -o "$nodetype" = "efsn" ]; then 486 local autobuy="$(getCfgValue 'autobt')" 487 local mining="$(getCfgValue 'mining')" 488 local address="$(getCfgValue 'address')" 489 fi 490 echo "${txtgrn}✓${txtrst} Read node configuration" 491 local imagename="$(getDockerImageName $nodetype $testnet)" 492 493 if [ "$testnet" = "true" ]; then 494 # run testnet node 495 testnet="--testnet" 496 else 497 # run mainnet node 498 testnet="" 499 fi 500 501 if [ "$autobuy" = "true" ]; then 502 # turn autobuy on 503 autobuy="--autobt" 504 else 505 # turn autobuy off 506 autobuy="" 507 fi 508 509 # make sure mining remains enabled for old configs 510 if [ "$mining" != "false" ]; then 511 # turn mining on 512 mining="" 513 else 514 # turn mining off 515 mining="--disable-mining" 516 fi 517 518 echo 519 echo "${txtylw}Creating node container from image $imagename${txtrst}" 520 if [ "$nodetype" = "minerandlocalgateway" ]; then 521 # docker create automatically pulls the image if it's not there 522 # we do not need -i here as it's not really an interactive terminal 523 sudo docker create --name fusion -t --restart unless-stopped \ 524 -p 127.0.0.1:9000:9000 -p 127.0.0.1:9001:9001 -p 40408:40408 -p 40408:40408/udp \ 525 -v "$BASE_DIR/fusion-node":/fusion-node \ 526 $imagename \ 527 -u "$address" $testnet $autobuy $mining \ 528 -e "$nodename" 529 530 elif [ "$nodetype" = "efsn" ]; then 531 sudo docker create --name fusion -t --restart unless-stopped \ 532 -p 40408:40408 -p 40408:40408/udp \ 533 -v "$BASE_DIR/fusion-node":/fusion-node \ 534 $imagename \ 535 -u "$address" $testnet $autobuy $mining \ 536 -e "$nodename" 537 538 elif [ "$nodetype" = "gateway" ]; then 539 # one could optionally create a public gateway, but that should always utilize 540 # encryption which requires a properly configured reverse TLS proxy like nginx 541 sudo docker create --name fusion -t --restart unless-stopped \ 542 -p 127.0.0.1:9000:9000 -p 127.0.0.1:9001:9001 -p 40408:40408 -p 40408:40408/udp \ 543 -v "$BASE_DIR/fusion-node":/fusion-node \ 544 $imagename \ 545 $testnet \ 546 -e "$nodename" 547 548 # workaround for the breaking change introduced with https://github.com/FUSIONFoundation/efsn/commit/8fab78ee3872be05cda3c53db24a49ddea0dfe98 549 # originally the gateway did not use an entrypoint script which defined a data subdirectory; this prevents two things: 550 # 1) orphaned chaindata wasting disk space 551 # 2) a full resync because chaindata is gone 552 if [ -d "$BASE_DIR/fusion-node/efsn" ]; then 553 if [ -d "$BASE_DIR/fusion-node/data/efsn" ]; then 554 sudo rm -rf "$BASE_DIR/fusion-node/efsn/" 555 else 556 sudo mkdir -p "$BASE_DIR/fusion-node/data/" 557 sudo mv "$BASE_DIR/fusion-node/efsn/" "$BASE_DIR/fusion-node/data/efsn" 558 fi 559 sudo rm -rf "$BASE_DIR/fusion-node/efsn.ipc" "$BASE_DIR/fusion-node/keystore/" 560 fi 561 562 else 563 echo "${txtred}Invalid node type${txtrst}" 564 exit 1 565 fi 566 567 # check the container is really created. it may fail as network reasons. 568 createdTime="$(sudo docker container inspect -f "{{.Created}}" fusion 2>/dev/null)" 569 if [ -z "$createdTime" ]; then 570 echo "${txtred}Create container failed, please check your network${txtrst}" 571 exit 1 572 fi 573 574 # reset global update variable 575 hasUpdate=1 576 echo "${txtgrn}✓${txtrst} Created node container" 577 } 578 579 startNode() { 580 echo 581 echo "${txtylw}Starting the node${txtrst}" 582 sudo docker start fusion >/dev/null 583 if [ $? -eq 0 ]; then 584 echo "${txtgrn}✓${txtrst} Node started" 585 echo 586 echo "---------------------------------------------------------------" 587 echo "| Please use the \"Show node logs\" function from the main menu |" 588 echo "| to verify that the node is really running without errors! |" 589 echo "---------------------------------------------------------------" 590 else 591 echo "${txtred}Node failed to start${txtrst}" 592 fi 593 } 594 595 stopNode() { 596 echo 597 echo "${txtylw}Stopping the node${txtrst}" 598 echo "This might take a moment, please wait..." 599 sudo docker stop fusion >/dev/null 600 if [ $? -eq 0 ]; then 601 echo "${txtgrn}✓${txtrst} Node stopped" 602 else 603 echo "${txtred}Node failed to stop${txtrst}" 604 fi 605 } 606 607 installNode() { 608 [ $DEBUG_MODE -ne 1 ] && clear 609 echo 610 echo "---------------------" 611 echo "| Node Installation |" 612 echo "---------------------" 613 614 if [ -d "$BASE_DIR/fusion-node" ]; then 615 echo 616 echo "${txtylw}You already seem to have a node installed in $BASE_DIR/fusion-node.${txtrst}" 617 echo "It will be stopped and its configuration and chaindata will be purged." 618 echo "This means it has to sync from scratch again, which could take a while." 619 echo "Please look into the \"configure node\" menu if you want to change node" 620 echo "configuration settings which don't require a full reset." 621 echo 622 local question="${txtylw}Are you sure you want to continue?${txtrst} [Y/n] " 623 askToContinue "$question" 624 if [ $? -eq 1 ]; then 625 echo "${txtred}✓${txtrst} Installation cancelled" 626 return 1 627 fi 628 fi 629 630 mkdir -p "$BASE_DIR/" 631 local spacefree=$(df -B 1024k --output=avail $BASE_DIR | egrep -o '[0-9]+') 632 local spaceoccup=$(sudo du -B 1024k --summarize $BASE_DIR | awk '{print $1}') 633 local spaceavail=$(expr $spacefree + $spaceoccup) 634 if [ $spaceavail -lt 25000 ]; then 635 echo 636 echo "${txtylw}You seem to have less than 25GB of free storage available for chaindata in $BASE_DIR.${txtrst}" 637 echo "If the node runs out of disk space, it will stop syncing and your tickets might get retreated." 638 echo 639 local question="${txtylw}Are you sure you want to continue?${txtrst} [Y/n] " 640 askToContinue "$question" 641 if [ $? -eq 1 ]; then 642 echo "${txtred}✓${txtrst} Installation cancelled" 643 return 1 644 fi 645 fi 646 647 local memavail=$(awk '/^MemAvailable/ {print $2}' /proc/meminfo) 648 if [ $memavail -lt 2097152 ]; then 649 echo 650 echo "${txtylw}You seem to have less than 2GB of free memory available.${txtrst}" 651 echo "If the node runs out of memory, it will crash and your tickets might get retreated." 652 echo 653 local question="${txtylw}Are you sure you want to continue?${txtrst} [Y/n] " 654 askToContinue "$question" 655 if [ $? -eq 1 ]; then 656 echo "${txtred}✓${txtrst} Installation cancelled" 657 return 1 658 fi 659 fi 660 661 echo 662 echo "<<< Installing node >>>" 663 initConfig 664 removeContainer 665 createContainer 666 startNode 667 echo 668 echo "<<< ${txtgrn}✓${txtrst} Installed node >>>" 669 echo 670 pauseScript 671 } 672 673 deinstallNode() { 674 [ $DEBUG_MODE -ne 1 ] && clear 675 echo 676 echo "-----------------------" 677 echo "| Node Deinstallation |" 678 echo "-----------------------" 679 680 if [ -d "$BASE_DIR/fusion-node" ]; then 681 echo 682 echo "You already seem to have a node installed in $BASE_DIR/fusion-node." 683 echo "It will be stopped and its configuration and chaindata will be purged." 684 echo 685 local question="${txtylw}Are you sure you want to continue?${txtrst} [Y/n] " 686 askToContinue "$question" 687 if [ $? -eq 1 ]; then 688 echo "${txtred}✓${txtrst} Deinstallation cancelled" 689 return 1 690 fi 691 fi 692 693 echo 694 echo "<<< Deinstalling node >>>" 695 sudo rm -rf "$BASE_DIR/fusion-node/" 696 removeContainer 697 sudo systemctl -q stop fusion 698 sudo systemctl -q disable fusion 699 sudo systemctl daemon-reload 700 sudo rm -f "/etc/systemd/system/fusion.service" 701 echo 702 echo "<<< ${txtgrn}✓${txtrst} Deinstalled node >>>" 703 echo 704 pauseScript 705 } 706 707 updateNode() { 708 echo 709 echo "<<< Updating node >>>" 710 removeContainer 711 createContainer 712 startNode 713 echo 714 echo "<<< ${txtgrn}✓${txtrst} Updated node >>>" 715 } 716 717 updateNodeScreen() { 718 [ $DEBUG_MODE -ne 1 ] && clear 719 echo 720 echo "---------------" 721 echo "| Node Update |" 722 echo "---------------" 723 updateNode 724 echo 725 pauseScript 726 } 727 728 showNodeLogs() { 729 [ $DEBUG_MODE -ne 1 ] && clear 730 echo 731 echo "-------------------" 732 echo "| Node Log Viewer |" 733 echo "-------------------" 734 echo 735 echo "${txtylw}Press Ctrl + C to quit!${txtrst}" 736 echo 737 pauseScript 738 echo 739 echo 740 # entering a subshell here so killing the logger doesn't exit the main script 741 ( 742 # restoring SIGINT so Ctrl + C works 743 trap - SIGINT 744 # we do not have to attach because we don't need interactive access 745 # this also has the advantage that the node doesn't need to be running 746 sudo docker logs fusion --tail=25 -f 747 if [ $? -ne 0 ]; then 748 echo "${txtred}Failed to show node log${txtrst}" 749 fi 750 # ignoring SIGINT again 751 trap '' SIGINT 752 ) 753 echo 754 echo 755 pauseScript 756 } 757 758 change_autobuy() { 759 local nodetype="$(getCfgValue 'nodeType')" 760 if [ "$nodetype" = "minerandlocalgateway" -o "$nodetype" = "efsn" ]; then 761 local autobuy="$(getCfgValue 'autobt')" 762 local state 763 # just making the output a bit nicer 764 [ "$autobuy" = "true" ] && state="${txtgrn}enabled${txtrst}" || state="${txtred}disabled${txtrst}" 765 echo 766 echo "Ticket auto-buy is currently $state" 767 # we can't just use the API here as an unexpected node restart would cause problems 768 local question="${txtylw}Do you want to change this setting? Doing so will enforce a node update and restart!${txtrst} [Y/n] " 769 askToContinue "$question" 770 if [ $? -eq 0 ]; then 771 echo 772 echo "<<< Changing auto-buy setting >>>" 773 [ "$autobuy" = "true" ] && autobuy="false" || autobuy="true" 774 putCfgValue 'autobt' "$autobuy" 775 updateNode 776 echo 777 echo "<<< ${txtgrn}✓${txtrst} Changed auto-buy setting >>>" 778 echo 779 pauseScript 780 fi 781 else 782 echo 783 echo "This setting is only available for minerandlocalgateway and efsn node types" 784 echo 785 pauseScript 786 fi 787 } 788 789 change_mining() { 790 local nodetype="$(getCfgValue 'nodeType')" 791 if [ "$nodetype" = "minerandlocalgateway" -o "$nodetype" = "efsn" ]; then 792 local mining="$(getCfgValue 'mining')" 793 local state 794 # just making the output a bit nicer 795 [ "$mining" != "false" ] && state="${txtgrn}enabled${txtrst}" || state="${txtred}disabled${txtrst}" 796 echo 797 echo "Mining of new blocks is currently $state" 798 # we can't just use the API here as an unexpected node restart would cause problems 799 local question="${txtylw}Do you want to change this setting? Doing so will enforce a node update and restart!${txtrst} [Y/n] " 800 askToContinue "$question" 801 if [ $? -eq 0 ]; then 802 echo 803 echo "<<< Changing mining setting >>>" 804 # make sure mining remains enabled for old configs 805 [ "$mining" != "false" ] && mining="false" || mining="true" 806 putCfgValue 'mining' "$mining" 807 updateNode 808 echo 809 echo "<<< ${txtgrn}✓${txtrst} Changed mining setting >>>" 810 echo 811 pauseScript 812 fi 813 else 814 echo 815 echo "This setting is only available for minerandlocalgateway and efsn node types" 816 echo 817 pauseScript 818 fi 819 } 820 821 change_wallet() { 822 local nodetype="$(getCfgValue 'nodeType')" 823 if [ "$nodetype" = "minerandlocalgateway" -o "$nodetype" = "efsn" ]; then 824 local address="$(getCfgValue 'address')" 825 echo 826 echo "The current staking wallet address is ${txtgrn}$address${txtrst}" 827 # we can't just use the API here as an unexpected node restart would cause problems 828 local question="${txtylw}Do you want to change this setting? Doing so will enforce a node update and restart!${txtrst} [Y/n] " 829 askToContinue "$question" 830 if [ $? -eq 0 ]; then 831 echo 832 echo "<<< Changing staking wallet >>>" 833 updateKeystoreFile 834 echo "${txtgrn}✓${txtrst} Updated keystore file" 835 updateKeystorePass 836 echo "${txtgrn}✓${txtrst} Updated keystore password" 837 updateNode 838 echo 839 echo "<<< ${txtgrn}✓${txtrst} Changed staking wallet >>>" 840 echo 841 pauseScript 842 fi 843 else 844 echo 845 echo "This setting is only available for minerandlocalgateway and efsn node types" 846 echo 847 pauseScript 848 fi 849 } 850 851 change_autostart() { 852 local state="$(systemctl show fusion -p UnitFileState --value)" 853 # just making the output a bit nicer 854 local statemsg 855 [ "$state" = "enabled" ] && statemsg="${txtgrn}enabled${txtrst}" || statemsg="${txtred}disabled${txtrst}" 856 echo 857 echo "Node auto-start is currently $statemsg" 858 local question="${txtylw}Do you want to change this setting?${txtrst} [Y/n] " 859 askToContinue "$question" 860 if [ $? -eq 0 ]; then 861 echo 862 echo "<<< Changing auto-start setting >>>" 863 # if auto-start wasn't enabled during installation, state will be empty here 864 if [ "$state" != "enabled" ]; then 865 # download systemd service unit definition if it doesn't exist yet 866 if [ ! -f "/etc/systemd/system/fusion.service" ]; then 867 sudo curl -fsSL "https://raw.githubusercontent.com/FUSIONFoundation/efsn/master/QuickNodeSetup/fusion.service" \ 868 -o "/etc/systemd/system/fusion.service" 869 fi 870 # reload systemd service unit definitions 871 sudo systemctl daemon-reload 872 # enable the systemd service unit 873 sudo systemctl -q enable fusion 874 else 875 # disable the systemd service unit 876 sudo systemctl -q disable fusion 877 fi 878 echo 879 echo "${txtylw}Modified systemd service unit${txtrst}" 880 echo 881 echo "<<< ${txtgrn}✓${txtrst} Changed auto-start setting >>>" 882 echo 883 pauseScript 884 fi 885 } 886 887 change_explorer() { 888 local nodename="$(getCfgValue 'nodeName')" 889 if [ -n "$nodename" ]; then 890 echo 891 echo "The node is currently listed on the node explorer as ${txtgrn}$nodename${txtrst}" 892 else 893 echo 894 echo "The node is currently not listed on the node explorer" 895 fi 896 local question="${txtylw}Do you want to change this setting? Doing so will enforce a node update and restart!${txtrst} [Y/n] " 897 askToContinue "$question" 898 if [ $? -eq 0 ]; then 899 echo 900 echo "<<< Changing explorer listing >>>" 901 updateExplorerListing 902 updateNode 903 echo 904 echo "<<< ${txtgrn}✓${txtrst} Changed explorer listing >>>" 905 echo 906 pauseScript 907 fi 908 } 909 910 warnRetreat() { 911 local nodetype="$(getCfgValue 'nodeType')" 912 if [ "$nodetype" != "minerandlocalgateway" -a "$nodetype" != "efsn" ]; then 913 return 914 fi 915 local mining="$(getCfgValue 'mining')" 916 if [ "$mining" = "false" ]; then 917 return 918 fi 919 local address="$(getCfgValue 'address')" 920 if [ -z "$address" ]; then 921 return 922 fi 923 924 local tickets=$(sudo docker exec fusion efsn --exec "fsn.totalNumberOfTicketsByAddress(\"$address\")" attach /fusion-node/data/efsn.ipc 2>/dev/null) 925 926 if [ -n "$tickets" ] && [ $tickets -gt 0 ]; then 927 echo 928 echo "${txtylw}Your node is currently configured for mining and has $tickets active tickets.${txtrst}" 929 echo "If you stop the node for too long, your tickets might get retreated." 930 echo 931 local question="${txtylw}Are you sure you want to continue?${txtrst} [Y/n] " 932 askToContinue "$question" 933 [ $? -eq 0 ] || return 1 934 fi 935 } 936 937 configureNode() { 938 while true; do 939 [ $DEBUG_MODE -ne 1 ] && clear 940 echo 941 echo "----------------------" 942 echo "| Node Configuration |" 943 echo "----------------------" 944 echo 945 echo "${txtylw}1. Enable/disable ticket auto-buy" 946 echo "2. Enable/disable mining of new blocks" 947 echo "3. Change staking wallet to be unlocked" 948 echo "4. Enable/disable auto-start after boot" 949 echo "5. Hide/show or rename on node explorer" 950 echo "6. Return to main menu${txtrst}" 951 echo 952 local input 953 read -n1 -r -s -p "Select option [1-6] " input 954 case $input in 955 1) echo; change_autobuy ;; 956 2) echo; warnRetreat && change_mining ;; 957 3) echo; warnRetreat && change_wallet ;; 958 4) echo; change_autostart ;; 959 5) echo; change_explorer ;; 960 6) break ;; 961 *) echo -e "\n${txtred}Invalid input${txtrst}"; sleep 1 ;; 962 esac 963 done 964 } 965 966 show_menus_init() { 967 [ $DEBUG_MODE -ne 1 ] && clear 968 echo 969 echo "-----------------------" 970 echo "| FUSION Node Manager |" 971 echo "-----------------------" 972 echo 973 echo "${txtylw}1. Install node and dependencies" 974 echo "2. Exit to shell${txtrst}" 975 echo 976 } 977 978 read_options_init() { 979 local input 980 read -n1 -r -s -p "Select option [1-2] " input 981 case $input in 982 1) installNode ;; 983 2) echo -e "\n${txtylw}Bye...${txtrst}"; exit 0 ;; 984 *) echo -e "\n${txtred}Invalid input${txtrst}"; sleep 1 ;; 985 esac 986 } 987 988 show_menus() { 989 [ $DEBUG_MODE -ne 1 ] && clear 990 echo 991 echo "-----------------------" 992 echo "| FUSION Node Manager |" 993 echo "-----------------------" 994 995 if [ $hasUpdate -eq 0 ]; then 996 echo 997 echo "${txtgrn}An update is available, please update your node!${txtrst}" 998 fi 999 1000 echo 1001 echo "${txtylw}1. Install node and dependencies" 1002 echo "2. Update node to current version" 1003 echo "3. Start the node" 1004 echo "4. Stop the node" 1005 echo "5. Deinstall node" 1006 echo "6. Show node logs" 1007 echo "7. Configure node" 1008 echo "8. Exit to shell${txtrst}" 1009 echo 1010 } 1011 1012 read_options() { 1013 local input 1014 read -n1 -r -s -p "Select option [1-8] " input 1015 case $input in 1016 1) echo; warnRetreat && installNode ;; 1017 2) updateNodeScreen ;; 1018 3) echo; startNode; echo; pauseScript ;; 1019 4) echo; warnRetreat && stopNode && echo && pauseScript ;; 1020 5) echo; warnRetreat && deinstallNode ;; 1021 6) showNodeLogs ;; 1022 7) configureNode ;; 1023 8) echo -e "\n${txtylw}Bye...${txtrst}"; exit 0 ;; 1024 *) echo -e "\n${txtred}Invalid input${txtrst}"; sleep 1 ;; 1025 esac 1026 } 1027 1028 [ $DEBUG_MODE -ne 1 ] && clear 1029 echo 1030 echo "-----------------------" 1031 echo "| FUSION Node Manager |" 1032 echo "-----------------------" 1033 echo 1034 echo "${txtylw}Initializing script, please wait...${txtrst}" 1035 echo 1036 # make sure we're not running into avoidable problems during setup 1037 scriptUpdate 1038 distroChecks 1039 # check dependencies instead of install dependencies 1040 # because the install method may diff in differrent OS 1041 dependChecks 1042 sanityChecks 1043 # check for updates if node.json already exists, save state in global variable 1044 hasUpdate=1 1045 if [ -f "$CONF_FILE" ]; then 1046 checkUpdate 1047 hasUpdate=$? 1048 fi 1049 1050 # ignoring some signals to keep the script running 1051 trap '' SIGINT SIGQUIT SIGTSTP 1052 while true; do 1053 # showing only the install option on initial launch 1054 if [ ! -f "$CONF_FILE" ]; then 1055 show_menus_init 1056 read_options_init 1057 else 1058 show_menus 1059 read_options 1060 fi 1061 done 1062 1063 #/* vim: set ts=4 sts=4 sw=4 et : */