#!/usr/bin/env bash # Run two node local net. # Unlike the docker-compose script in the /docker folder, this version builds # the nodes based on the current state of the code, instead of depending in a # published version. set -e # chainspec defaults to ghost-local if no arguments are passed to this script; # if arguments are passed in, the first is the chainspec chainspec="${1:-ghost-local}" # PROJECT_ROOT=$(git rev-parse --show-toplevel) source "$(dirname "$0")"/common.sh # cd "$PROJECT_ROOT" last_modified_rust_file=$( find . -path ./target -prune -o -type f -name '*.rs' -printf '%T@ %p\n' | sort -nr | head -1 | cut -d' ' -f2- ) ghost="target/release/ghost" # ensure the ghost binary exists and is up to date if [ ! -x "$ghost" ] || [ "$ghost" -ot "$last_modified_rust_file" ]; then # cargo build --release echo "[+] Build needed" fi # setup variables node_offset=0 declare -a node_pids declare -a node_pipes # create a sed expression which injects the node name and stream type into # each line function make_sed_expr() { name="$1" type="$2" printf "s/^/%8s %s: /" "$name" "$type" } # turn a string into a flag function flagify() { printf -- '--%s' "$(tr '[:upper:]' '[:lower:]' <<< "$1")" } # start a node and label its output # # this function takes a single argument, the node name. # the name must be one of those which can be passed to the ghost binary, in # un-flagged form, one of: # alice, bob, charlie, dave, eve, ferdie, one, two function run_node() { name="$1" # create a named pipe so we can get the node's PID while also sedding # its output local stdout local stderr stdout=$(mktemp --dry-run --tmpdir) stderr=$(mktemp --dry-run --tmpdir) mkfifo "$stdout" mkfifo "$stderr" node_pipes+=("$stdout") node_pipes+=("$stderr") # compute ports from offset local port=$((30333+node_offset)) local rpc_port=$((9933+node_offset)) local ws_port=$((9944+node_offset)) node_offset=$((node_offset+1)) echo "$(flagify "$name")" echo "--node-key 000000000000000000000000000000000000000000000000000000000000000${node_offset}" # start the node # "$ghost" \ # --chain "$chainspec" \ # --tmp \ # --port "$port" \ # --rpc-port "$rpc_port" \ # --rpc-cors all \ # --node-key 0000000000000000000000000000000000000000000000000000000000000001 \ # "$(flagify "$name")" \ # > "$stdout" \ # 2> "$stderr" \ # & # local pid=$! # node_pids+=("$pid") # # # send output from the stdout pipe to stdout, prepending the node name # sed -e "$(make_sed_expr "$name" "OUT")" "$stdout" >&1 & # # send output from the stderr pipe to stderr, prepending the none name # sed -e "$(make_sed_expr "$name" "ERR")" "$stderr" >&2 & } # clean up the nodes when the script exits function finish { for node_pid in "${node_pids[@]}"; do kill -9 "$node_pid" done for node_pipe in "${node_pipes[@]}"; do rm "$node_pipe" done } trap finish EXIT # start the nodes run_node Alice run_node Bob # now wait; this will exit on its own only if both subprocess exit # the practical implication, as both subprocesses are supposed to run # forever, is that this script will also run forever, until killed, ath which # point the exit trap should kill the subprocesses wait