Files
stacks-puppet-node/net-test/bin/txload.sh
2020-11-18 19:03:35 -08:00

329 lines
7.5 KiB
Bash
Executable File

#!/usr/bin/env bash
FEE_RATE=300
MAX_CHAINING=25
CONFIRMATIONS=1
exit_error() {
printf "$1"
exit 1
}
for CMD in cut grep egrep sed blockstack-cli curl; do
which "$CMD" >/dev/null 2>&1 || exit_error "Missing command $CMD"
done
if [ $(echo ${BASH_VERSION} | cut -d '.' -f 1) -lt 4 ]; then
exit_error "This script requires Bash 4.x or higher"
fi
# grab fd 3 for curl
exec 3>&1
usage() {
exit_error "$0 <private-key-hex> <stacks-url> <num-txs>\n"
}
MAIN_PRIVATE_KEY="$1"
STACKS_NODE_URL="$2"
NUM_TXS="$3"
if [ -z "$MAIN_PRIVATE_KEY" ] || [ -z "$STACKS_NODE_URL" ] || [ -z "$NUM_TXS" ]; then
usage
fi
set -uo pipefail
function log() {
printf "%s" "$1" >&2
}
function logln() {
printf "%s\n" "$1" >&2
}
make_token_transfer() {
local PRIVKEY="$1"
local NONCE="$2"
local DEST="$3"
local AMOUNT="$4"
local MEMO="load test $NONCE"
local TX="$(blockstack-cli --testnet token-transfer "$PRIVKEY" "$FEE_RATE" "$NONCE" "$DEST" "$AMOUNT" "$MEMO" 2>&1)"
local RC=$?
if [ $RC -ne 0 ]; then
logln "Failed to generate tx: blockstack-cli --testnet token-transfer $PRIVKEY $FEE_RATE $NONCE $DEST $AMOUNT \"$MEMO\""
return 1
fi
printf "$TX"
return 0
}
send_tx() {
local STACKS_NODE_URL="$1"
read TX
TXID="$(printf "$TX" | \
xxd -r -p | \
curl -s -X POST --data-binary @- -w "%{http_code}" -o >(cat >&3) -H "content-type: application/octet-stream" "$STACKS_NODE_URL"/v2/transactions 2>&1 | ( \
read HTTP_CODE
read BODY
if [ $HTTP_CODE -ne 200 ]; then
logln "Failed to send to node $STACKS_NODE_URL: server replied $HTTP_CODE. Tx was $TX"
logln "Error text: $BODY"
return 1
fi
echo "$BODY"
))"
local RC=$?
if [ $RC -ne 0 ]; then
return 1
fi
echo "$TXID"
return 0
}
get_chain_tip() {
local STACKS_NODE_URL="$1"
local TIP="$(curl -sf "$STACKS_NODE_URL"/v2/info | jq -r '.stacks_tip' 2>&1)"
local RC=$?
if [ $RC -ne 0 ]; then
logln "Failed to query chain tip on node $STACKS_NODE_URL: curl exited with code $RC"
return 1
fi
echo "$TIP"
return 0
}
get_account_nonce() {
local STACKS_NODE_URL="$1"
local ADDR="$2"
local NONCE="$(curl -sf "$STACKS_NODE_URL"/v2/accounts/"$ADDR""?proof=0" | jq -r '.nonce')"
local RC=$?
if [ $RC -ne 0 ]; then
logln "Failed to query account $ADDR on node $STACKS_NODE_URL: curl exited with code $RC"
return 1
fi
echo "$NONCE"
return 0
}
wait_for_new_stacks_block() {
local TIP="$1"
local STACKS_NODE_URL="$2"
while true; do
local CUR_TIP="$(get_chain_tip "$STACKS_NODE_URL")"
local RC=$?
if [ $RC -ne 0 ]; then
return 1
fi
if [[ "$CUR_TIP" != "$TIP" ]]; then
echo "$CUR_TIP"
return 0
fi
sleep 5
done
}
wait_for_confirmations() {
local CONFS=$1
local STACKS_NODE_URL="$2"
local TIP="$(get_chain_tip "$STACKS_NODE_URL")"
local CONF=0
for CONF in $(seq 0 $CONFS); do
TIP="$(wait_for_new_stacks_block "$TIP" "$STACKS_NODE_URL")"
RC=$?
if [ $RC -ne 0 ]; then
return 1
fi
done
echo "$TIP"
return 0
}
fund_keys() {
local MAIN_PRIVKEY="$1"
local AMOUNT="$2"
local STACKS_NODE_URL="$3"
local MAIN_ADDR="$(blockstack-cli --testnet addresses "$MAIN_PRIVKEY" | jq -r '.STX')"
local RC=$?
if [ $RC -ne 0 ]; then
logln "Failed to generate address for \"$MAIN_PRIVKEY\""
return 1
fi
local MAIN_NONCE="$(get_account_nonce "$STACKS_NODE_URL" "$MAIN_ADDR")"
RC=$?
if [ $RC -ne 0 ]; then
return 1
fi
local NEXT_PRIVKEY=""
local CHAIN_TIP="$(get_chain_tip "$STACKS_NODE_URL")"
local TX_COUNT=0
while read NEXT_PRIVKEY; do
local ADDR="$(blockstack-cli --testnet addresses "$NEXT_PRIVKEY" | jq -r '.STX')"
RC=$?
if [ $RC -ne 0 ]; then
logln "Failed to generate address for \"$NEXT_PRIVKEY\""
return 1
fi
log "Funding $NEXT_PRIVKEY ($ADDR) with $AMOUNT uSTX as tx #$MAIN_NONCE..."
TXID="$(make_token_transfer "$MAIN_PRIVKEY" "$MAIN_NONCE" "$ADDR" "$AMOUNT" | send_tx "$STACKS_NODE_URL")"
RC=$?
if [ $RC -ne 0 ]; then
logln "FAILED!"
logln "Failed to send fund-load token-transfer to $NEXT_PRIVKEY ($ADDR)"
return 1
fi
logln " ok"
echo "$NEXT_PRIVKEY"
MAIN_NONCE=$((MAIN_NONCE + 1))
TX_COUNT=$((TX_COUNT + 1))
if (( $TX_COUNT >= $MAX_CHAINING )); then
while true; do
log "Wait for at least $CONFIRMATIONS new Stacks blocks after $CHAIN_TIP..."
CHAIN_TIP="$(wait_for_confirmations $CONFIRMATIONS "$STACKS_NODE_URL")"
RC=$?
if [ $RC -ne 0 ]; then
logln "FAILED"
return 1
fi
logln "ok"
TX_COUNT=0
# wait for blockchain to catch up with us
local CUR_NONCE="$(get_account_nonce "$STACKS_NODE_URL" "$MAIN_ADDR")"
if [ $RC -ne 0 ]; then
return 1
fi
if (( $CUR_NONCE >= $MAIN_NONCE )); then
MAIN_NONCE=$CUR_NONCE
break
else
logln "Current nonce of fund key is $CUR_NONCE; need to wait until it is $MAIN_NONCE"
fi
done
fi
done
return 0
}
get_addrs_and_nonces() {
local NEXT_PRIVKEY=""
local STACKS_NODE_URL="$1"
while read NEXT_PRIVKEY; do
local ADDR="$(blockstack-cli --testnet addresses "$NEXT_PRIVKEY" | jq -r '.STX')"
RC=$?
if [ $RC -ne 0 ]; then
logln "Failed to generate address for \"$NEXT_PRIVKEY\""
return 1
fi
NONCE="$(get_account_nonce "$STACKS_NODE_URL" "$ADDR")"
if [ $RC -ne 0 ]; then
return 1
fi
echo "$NEXT_PRIVKEY $ADDR $NONCE"
done
return 0
}
tx_load() {
local DEST="$1"
local AMOUNT="$2"
local STACKS_NODE_URL="$3"
local NEXT_PRIVKEY=""
local RC=0
local NONCE=0
while read NEXT_PRIVKEY_ADDR_NONCE; do
set -- $NEXT_PRIVKEY_ADDR_NONCE
NEXT_PRIVKEY="$1"
ADDR="$2"
NONCE="$3"
log "Send $AMOUNT uSTX from $NEXT_PRIVKEY ($ADDR) to $DEST as tx #$NONCE..."
TXID="$(make_token_transfer "$NEXT_PRIVKEY" "$NONCE" "$DEST" "$AMOUNT" | send_tx "$STACKS_NODE_URL")"
RC=$?
if [ $RC -ne 0 ]; then
logln "FAILED!"
logln "Failed to send tx-load token-transfer from $NEXT_PRIVKEY ($ADDR) to $DEST"
return 1
fi
logln " ok"
done
return 0
}
generate_keys() {
local NUM_KEYS="$1"
local CNT=0
for CNT in $(seq 1 $NUM_KEYS); do
local PRIVKEY="$(blockstack-cli --testnet generate-sk | jq -r '.secretKey')"
RC=$?
if [ $RC -ne 0 ]; then
logln "Failed to generate private key"
return 1
fi
echo "$PRIVKEY"
done
return 0
}
DEST_ADDR="$(blockstack-cli --testnet generate-sk | jq -r '.secretKey,.stacksAddress' | ( \
read DEST_PRIVKEY
read DEST_ADDR
logln "Destination private key: $DEST_PRIVKEY ($DEST_ADDR)"
echo "$DEST_ADDR"
))"
AMOUNT=1
generate_keys "$NUM_TXS" | \
fund_keys "$MAIN_PRIVATE_KEY" "$((AMOUNT + FEE_RATE))" "$STACKS_NODE_URL" \
> /tmp/tx-load.keys
logln "Waiting for $CONFIRMATIONS confirmations before beginning"
TIP="$(wait_for_confirmations $CONFIRMATIONS "$STACKS_NODE_URL")"
RC=$?
if [ $RC -ne 0 ]; then
logln "FAILED"
exit 1
fi
cat /tmp/tx-load.keys | \
get_addrs_and_nonces "$STACKS_NODE_URL" | \
tx_load "$DEST_ADDR" "$AMOUNT" "$STACKS_NODE_URL"
exit $?