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

228 lines
7.5 KiB
Plaintext
Raw Normal View History

test(rpc): Create a script that submits block proposals to zcashd (#5944) * Revert "Update code that we're going to delete in the next PR anyway" This reverts commit 1fed70da9ef6f891d6465bcfc0ec4bacd9e81948. * Initial zcash-test-block-template script without block proposal construction * Try creating block data using jq and printf * Move proposal_block_from_template() to zebra-rpc and remove eyre dependency * Implement FromStr for DateTime32 and Duration32 * Basic block-template-to-proposal command without time source handling * Move block proposal code into its own module * Use time source in block-template-to-proposal * Make block-template-to-proposal require the getblocktemplate-rpcs feature * Use block-template-to-proposal in the test script zcash-rpc-block-template-to-proposal * Apply new hex formatting to commitments and nonces in block proposal tests * Re-add missing imports from rebase * Re-add missing conversions from rebase * Update to new method name after rebase * Derive a Default impl * Restore a comment that was accidentally deleted during the rebase * Avoid a clippy::unwrap-in-result * Temporarily fix the code for a disabled test * Fix tool build with Docker caches * Make clippy happy with the temporary fix * Give a pass/fail status for each proposal response * Accept zcashd block templates in block-template-to-proposal * Fix pretty printing * Zebra expects a longpollid, so give it a dummy value * Add "required" fields which Zebra requires * Use curtime as the dummy maxtime in zcashd templates * Support large block proposals by reading proposal data from a file * Test all valid time modes for each proposal * Allow the user to set the time command * Put debug logs into their own files * Exit with an error status when any proposal is invalid * Log the date and time to make it easier to match errors to node logs
2023-01-17 18:11:15 -08:00
#!/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