zebra/zebra-utils/zcash-rpc-block-template-to...

228 lines
7.5 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
# Gets a block template from a Zcash node instance,
# turns it into a block proposal using `block-template-to-proposal`,
# and sends it to one or more Zcash node instances (which can include the same node).
#
# If there are multiple proposal ports, displays a diff of the responses.
#
# Uses `zcash-cli` with the RPC ports supplied on the command-line.
function usage()
{
echo "Usage:"
echo "$0 block-template-rpc-port proposal-rpc-port [extra-proposal-rpc-port...] -- [extra-block-template-rpc-json-fields] [extra-proposal-rpc-fields]"
}
# Override the commands used by this script using these environmental variables:
ZCASH_CLI="${ZCASH_CLI:-zcash-cli}"
DIFF="${DIFF:-diff --unified --color=always}"
BLOCK_TEMPLATE_TO_PROPOSAL="${BLOCK_TEMPLATE_TO_PROPOSAL:-block-template-to-proposal}"
# time how long a command takes to run
TIME="time"
# display the current date and time
DATE="date --rfc-3339=seconds"
# Override the settings for this script using these environmental variables:
TIME_SOURCES="${TIME_SOURCES:-CurTime MinTime MaxTime ClampedNow}"
# Process arguments
if [ $# -lt 2 ]; then
usage
exit 1
fi
TEMPLATE_RPC_PORT=$1
shift
PROPOSAL_RPC_PORTS=""
while [ -n "${1:-}" ] && [ "${1-}" != "--" ]; do
PROPOSAL_RPC_PORTS="$PROPOSAL_RPC_PORTS $1"
shift
done
if [ "${1-}" == "--" ]; then
shift
fi
TEMPLATE_ARG=""
if [ $# -ge 1 ]; then
TEMPLATE_ARG="${1:-}"
shift
fi
TEMPLATE_ARG_FULL="{ \"mode\": \"template\" ${TEMPLATE_ARG:+, $TEMPLATE_ARG} }"
PROPOSAL_ARG=""
if [ $# -ge 1 ]; then
PROPOSAL_ARG="${1:-}"
shift
fi
PROPOSAL_ARG_NO_DATA="{ \"mode\": \"proposal\", \"data\": \"...\" ${PROPOSAL_ARG:+, $PROPOSAL_ARG} }"
if [ $# -ge 1 ]; then
usage
exit 1
fi
$DATE
# Use an easily identified temp directory name,
# but fall back to the default temp name if `mktemp` does not understand `--suffix`.
ZCASH_RPC_TMP_DIR=$(mktemp --suffix=.block-template-proposal -d 2>/dev/null || mktemp -d)
TEMPLATE_NODE_RELEASE_INFO="$ZCASH_RPC_TMP_DIR/template-check-getinfo.json"
PROPOSAL_NODES_RELEASE_INFO_BASE="$ZCASH_RPC_TMP_DIR/proposal-check-getinfo"
echo "Checking getblocktemplate node release info..."
$ZCASH_CLI -rpcport="$TEMPLATE_RPC_PORT" getinfo > "$TEMPLATE_NODE_RELEASE_INFO"
TEMPLATE_NODE=$(cat "$TEMPLATE_NODE_RELEASE_INFO" | grep '"subversion"' | \
cut -d: -f2 | cut -d/ -f2 | \
tr 'A-Z' 'a-z' | sed 's/magicbean/zcashd/ ; s/zebra$/zebrad/')
echo "Connected to $TEMPLATE_NODE (port $TEMPLATE_RPC_PORT) for getblocktemplate $TEMPLATE_ARG_FULL"
echo
echo "Checking proposal nodes release info..."
for PORT in $PROPOSAL_RPC_PORTS; do
PROPOSAL_NODE_RELEASE_INFO=$PROPOSAL_NODES_RELEASE_INFO_BASE.$PORT.json
$ZCASH_CLI -rpcport="$PORT" getinfo > "$PROPOSAL_NODE_RELEASE_INFO"
PROPOSAL_NODE=$(cat "$PROPOSAL_NODE_RELEASE_INFO" | grep '"subversion"' | \
cut -d: -f2 | cut -d/ -f2 | \
tr 'A-Z' 'a-z' | sed 's/magicbean/zcashd/ ; s/zebra$/zebrad/')
echo "Connected to $PROPOSAL_NODE (port $PORT) for getblocktemplate $PROPOSAL_ARG_NO_DATA"
done
echo
TEMPLATE_NODE_BLOCKCHAIN_INFO="$ZCASH_RPC_TMP_DIR/template-check-getblockchaininfo.json"
PROPOSAL_NODES_BLOCKCHAIN_INFO_BASE="$ZCASH_RPC_TMP_DIR/proposal-check-getblockchaininfo"
echo "Checking $TEMPLATE_NODE template network and tip height..."
$ZCASH_CLI -rpcport="$TEMPLATE_RPC_PORT" getblockchaininfo > "$TEMPLATE_NODE_BLOCKCHAIN_INFO"
TEMPLATE_NET=$(cat "$TEMPLATE_NODE_BLOCKCHAIN_INFO" | grep '"chain"' | cut -d: -f2 | tr -d ' ,"')
TEMPLATE_HEIGHT=$(cat "$TEMPLATE_NODE_BLOCKCHAIN_INFO" | grep '"blocks"' | cut -d: -f2 | tr -d ' ,"')
echo "Checking proposal nodes network and tip height..."
for PORT in $PROPOSAL_RPC_PORTS; do
PROPOSAL_NODE_BLOCKCHAIN_INFO=$PROPOSAL_NODES_BLOCKCHAIN_INFO_BASE.$PORT.json
$ZCASH_CLI -rpcport="$PORT" getblockchaininfo > "$PROPOSAL_NODE_BLOCKCHAIN_INFO"
PROPOSAL_NET=$(cat "$PROPOSAL_NODE_BLOCKCHAIN_INFO" | grep '"chain"' | cut -d: -f2 | tr -d ' ,"')
PROPOSAL_HEIGHT=$(cat "$PROPOSAL_NODE_BLOCKCHAIN_INFO" | grep '"blocks"' | cut -d: -f2 | tr -d ' ,"')
if [ "$PROPOSAL_NET" != "$TEMPLATE_NET" ]; then
echo "WARNING: sending block templates between different networks:"
echo "$TEMPLATE_NODE (RPC port $TEMPLATE_RPC_PORT) template is on: $TEMPLATE_NET"
echo "RPC port $PORT proposal is on: $PROPOSAL_NET"
echo
fi
if [ "$PROPOSAL_HEIGHT" -ne "$TEMPLATE_HEIGHT" ]; then
echo "WARNING: proposing block templates at different heights:"
echo "$TEMPLATE_NODE (RPC port $TEMPLATE_RPC_PORT) template is on: $TEMPLATE_HEIGHT"
echo "RPC port $PORT proposal is on: $PROPOSAL_HEIGHT"
echo
fi
done
echo
TEMPLATE_NODE_TEMPLATE_RESPONSE="$ZCASH_RPC_TMP_DIR/template-getblocktemplate-template.json"
echo "getblocktemplate template request ($TEMPLATE_NODE port $TEMPLATE_RPC_PORT):"
echo "getblocktemplate $TEMPLATE_ARG_FULL"
echo
echo "Querying $TEMPLATE_NODE $TEMPLATE_NET chain at height >=$TEMPLATE_HEIGHT..."
$DATE
$TIME $ZCASH_CLI -rpcport="$TEMPLATE_RPC_PORT" getblocktemplate "$TEMPLATE_ARG_FULL" > "$TEMPLATE_NODE_TEMPLATE_RESPONSE"
echo "Block template data is in $TEMPLATE_NODE_TEMPLATE_RESPONSE"
#cat "$TEMPLATE_NODE_TEMPLATE_RESPONSE"
echo
PROPOSAL_DATA_BASE="$ZCASH_RPC_TMP_DIR/proposal-data"
echo "Turning the template into block proposal data using $BLOCK_TEMPLATE_TO_PROPOSAL..."
for TIME_SOURCE in $TIME_SOURCES; do
PROPOSAL_DATA="$PROPOSAL_DATA_BASE.$TIME_SOURCE.json"
PROPOSAL_DEBUG="$PROPOSAL_DATA_BASE.$TIME_SOURCE.debug"
echo -n '{ "mode": "proposal", ' > "$PROPOSAL_DATA"
echo -n '"data": "' >> "$PROPOSAL_DATA"
cat "$TEMPLATE_NODE_TEMPLATE_RESPONSE" | \
$BLOCK_TEMPLATE_TO_PROPOSAL \
2> "$PROPOSAL_DEBUG" | \
(tr -d '\r\n' || true) \
>> "$PROPOSAL_DATA"
echo -n '"' >> "$PROPOSAL_DATA"
echo -n "${PROPOSAL_ARG:+, $PROPOSAL_ARG} }" >> "$PROPOSAL_DATA"
done
echo "Block proposal data is in $PROPOSAL_DATA_BASE*"
#cat "$PROPOSAL_DATA_BASE"*
echo
echo
echo "getblocktemplate proposal submissions:"
echo "getblocktemplate $PROPOSAL_ARG_NO_DATA"
$DATE
echo
PROPOSAL_NODES_PROPOSAL_RESPONSE_BASE="$ZCASH_RPC_TMP_DIR/proposal-check-getblocktemplate-proposal"
PROPOSAL_NODES_PROPOSAL_RESPONSE_LIST=""
for TIME_SOURCE in $TIME_SOURCES; do
PROPOSAL_DATA="$PROPOSAL_DATA_BASE.$TIME_SOURCE.json"
for PORT in $PROPOSAL_RPC_PORTS; do
PROPOSAL_NODE_PROPOSAL_RESPONSE=$PROPOSAL_NODES_PROPOSAL_RESPONSE_BASE.$TIME_SOURCE.$PORT.json
PROPOSAL_NODES_PROPOSAL_RESPONSE_LIST="${PROPOSAL_NODES_PROPOSAL_RESPONSE_LIST:+$PROPOSAL_NODES_PROPOSAL_RESPONSE_LIST }$PROPOSAL_NODE_PROPOSAL_RESPONSE"
# read the proposal data from a file, to avoid command-line length limits
cat "$PROPOSAL_DATA" | \
$TIME $ZCASH_CLI -rpcport="$PORT" -stdin getblocktemplate \
> "$PROPOSAL_NODE_PROPOSAL_RESPONSE" || \
echo "$ZCASH_CLI -rpcport=$PORT exited with an error"
done
done
echo
echo "Proposal response diffs between ports $PROPOSAL_RPC_PORTS and time sources $TIME_SOURCES:"
$DIFF --from-file=$PROPOSAL_NODES_PROPOSAL_RESPONSE_LIST && \
echo "getblocktemplate proposal responses were identical"
echo
EXIT_STATUS=0
for RESPONSE in $PROPOSAL_NODES_PROPOSAL_RESPONSE_LIST; do
if [ -s "$RESPONSE" ]; then
echo "Node said proposal was invalid, error response from $RESPONSE:"
cat "$RESPONSE"
EXIT_STATUS=1
else
echo "Node said proposal was valid, empty success response in $RESPONSE"
fi
done
$DATE
exit $EXIT_STATUS