Taken from github - casey/just
curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to DEST
In my case DEST=~/bin
Taken from github - casey/just
curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to DEST
In my case DEST=~/bin
❯ just nuke
deleting /Users/zeph/networks/niftynetwork
❯ export DATA_NODE=Follower
❯ just pub-create conduit testnet
Ready for public network with node datadir: /Users/zeph/networks/niftynetwork/Follower
mkdir -p $ALGORAND_DATA
algocfg profile set conduit -d $ALGORAND_DATA
cp ${GO_ALGORAND}/installer/genesis/testnet/genesis.json $ALGORAND_DATA
❯ just tree
/Users/zeph/networks/niftynetwork
└── Follower
├── config.json
└── genesis.json
1 directory, 2 files
❯ just start
Algorand node successfully started!
❯ just status
Last committed block: 64
Time since last block: 2.4s
Sync Time: 0.0s
Last consensus protocol: https://github.com/algorand/spec/tree/a26ed78ed8f834e2b9ccb6eb7d3ee9f629a6e622
Next consensus protocol: https://github.com/algorand/spec/tree/a26ed78ed8f834e2b9ccb6eb7d3ee9f629a6e622
Round for next consensus protocol: 65
Next consensus protocol supported: true
Last Catchpoint:
Consensus upgrade state: Voting
Yes votes: 64
No votes: 0
Votes remaining: 9936
Yes votes required: 9000
Vote window close round: 10001
Genesis ID: testnet-v1.0
Genesis hash: SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=
RUNNING
❯ just algod | jq '.["last-round"]'
...
64
❯ just algod /v2/ledger/sync
...
{"round":1}
❯ just algod /v2/deltas/1
... looks good ...
❯ just stop
❯ just start
❯ just stop
❯ just start
❯ just algod /v2/ledger/sync
...
{"round":1}
❯ just algod /v2/deltas/1
... looks good ...
❯ just algod /v2/ledger/sync/1337 POST
...
❯ just algod /v2/ledger/sync
...
{"round":1337}
❯ just algod | jq '.["last-round"]'
...
1400
❯ just algod /v2/deltas/1
...
{"message":"failed retrieving State Delta"}
❯ just algod /v2/deltas/1337
... looks good ...
❯ python make_just.py --just-out-file Justfile3 --name blue-whale
❯ grep blue-whale Justfile3
NAME := "blue-whale"
#!/usr/bin/env bash | |
# --- Courtesy of Will Winder --- # | |
unset ALGORAND_DATA | |
export ALGORAND_DATA=~/algorand/conduit/foo/algod_data | |
unset CONDUIT_DATA | |
export CONDUIT_DATA=~/algorand/conduit/foo/conduit_data | |
# Prep | |
if [[ -d $ALGORAND_DATA ]]; then | |
goal node stop -d "$ALGORAND_DATA" | |
rm -rf $ALGORAND_DATA | |
fi | |
if [[ -d $CONDUIT_DATA ]]; then | |
rm -rf $CONDUIT_DATA | |
fi | |
docker stop some-postgres || true | |
docker rm some-postgres || true | |
######### | |
# algod # | |
######### | |
mkdir -p $ALGORAND_DATA | |
algocfg profile set conduit -d "$ALGORAND_DATA" | |
cp ~/algorand/go-algorand/installer/genesis/mainnet/genesis.json "$ALGORAND_DATA"/genesis.json | |
goal node start -d "$ALGORAND_DATA" | |
###################### | |
# Postgres container # | |
###################### | |
pg_port=5555 | |
pg_pass=pgpass | |
pg_user=algorand | |
pg_db=conduitdb | |
docker run -d --name some-postgres -p $pg_port:5432 -e POSTGRES_PASSWORD=$pg_pass -e POSTGRES_USER=$pg_user -e POSTGRES_DB=$pg_db postgres | |
########### | |
# conduit # | |
########### | |
# Initialize and start conduit | |
mkdir -p $CONDUIT_DATA | |
conduit init -i algod -e postgresql > "$CONDUIT_DATA"/conduit.yml | |
# update config with yq | |
algod_addr=$(cat "$ALGORAND_DATA"/algod.net) | |
yq -i ".importer.config.netaddr = \"http://$algod_addr\"" conduit_data/conduit.yml | |
algod_token=$(cat "$ALGORAND_DATA"/algod.token) | |
yq -i ".importer.config.token = \"$algod_token\"" conduit_data/conduit.yml | |
algod_admin=$(cat "$ALGORAND_DATA"/algod.admin.token) | |
yq -i ".importer.config.catchup-config.admin-token = \"$algod_admin\"" conduit_data/conduit.yml | |
# postgres connection string | |
yq -i ".exporter.config.connection-string = \"host=localhost port=$pg_port user=$pg_user password=$pg_pass dbname=$pg_db\"" conduit_data/conduit.yml | |
echo "Run 'conduit -d conduit_data'" |
set export | |
set shell := ["zsh", "-cu"] | |
NETWORKS := `echo $HOME` + "/networks" | |
NAME := "conduitnetwork" | |
CURR_NETWORK := NETWORKS + "/" + NAME | |
GO_ALGORAND := "/Users/zeph/github/tzaffi/go-algorand" | |
NODE_TEMPLATE := GO_ALGORAND + "/test/testdata/nettemplates/TwoNodesFollower100Second.json" | |
PRIVATE_DATA_NODE := "Primary" | |
DATA_NODE := env_var_or_default("DATA_NODE", PRIVATE_DATA_NODE) | |
IS_PUBLIC_TRUTHY := env_var_or_default("DATA_NODE", "") | |
ALGORAND_DATA := CURR_NETWORK + "/" + DATA_NODE | |
ALGORAND_TOKEN_PATH := ALGORAND_DATA + "/algod.token" | |
ALGORAND_ADTOKEN_PATH := ALGORAND_DATA + "/algod.admin.token" | |
ALGORAND_ALGOD_PATH := ALGORAND_DATA + "/algod.net" | |
ALGORAND_PID_PATH := ALGORAND_DATA + "/algod.pid" | |
ENDPOINT_PORT := "56765" | |
CONDUIT := "./conduit" | |
CONDUIT_DATA := CURR_NETWORK + "/conduit" | |
CONDUIT_CONFIG := CONDUIT_DATA + "/conduit.yml" | |
CONDUIT_LOG := CONDUIT_DATA + "/conduit.log" | |
CONDUIT_DOCKER := "conduit-postgres" | |
LOG_LEVEL := "INFO" # "TRACE" | |
# These fake pre-set tokens make it easier to test against a local network | |
PRESET_ALGOD_TOKEN := "16b29a0a2bbcc535f1e9e40f0c0888013f3789bf2bd34e7907c8fb1ae9d16024" | |
PRESET_ALGOD_ADMIN := "20064faacad1e590e757ac9492506c2d948633d7c458651b16a3991d26997695" | |
# Older: | |
BOXES_TEAL := "boxes.teal" | |
# --- SUMMARY --- # | |
# list all available commands | |
default: | |
just --list | |
# echo all variables | |
@echo: | |
echo NETWORKS: $NETWORKS | |
echo NAME: $NAME | |
echo CURR_NETWORK: $CURR_NETWORK | |
echo GO_ALGORAND: $GO_ALGORAND | |
echo NODE_TEMPLATE: $NODE_TEMPLATE | |
echo PRIVATE_DATA_NODE: $PRIVATE_DATA_NODE | |
echo DATA_NODE: $DATA_NODE | |
echo IS_PUBLIC_TRUTHY: $IS_PUBLIC_TRUTHY | |
echo ALGORAND_DATA: $ALGORAND_DATA | |
echo ALGORAND_TOKEN_PATH: $ALGORAND_TOKEN_PATH | |
echo ALGORAND_ALGOD_PATH: $ALGORAND_ALGOD_PATH | |
echo ALGORAND_PID_PATH: $ALGORAND_PID_PATH | |
echo ENDPOINT_PORT: $ENDPOINT_PORT | |
echo CONDUIT: $CONDUIT | |
echo CONDUIT_DATA: $CONDUIT_DATA | |
echo CONDUIT_CONFIG: $CONDUIT_CONFIG | |
echo CONDUIT_LOG: $CONDUIT_LOG | |
echo CONDUIT_DOCKER: $CONDUIT_DOCKER | |
echo BOXES_TEAL: $BOXES_TEAL | |
# --- algod curl --- # | |
algod ENDPOINT="/v2/status" VERB="GET": | |
#! /usr/bin/env bash | |
# set -euxo pipefail | |
set -euo pipefail | |
ALGORAND_TOKEN=$(cat ${ALGORAND_TOKEN_PATH}) | |
ALGORAND_ALGOD=$(cat ${ALGORAND_ALGOD_PATH}) | |
ALGORAND_PID=$(cat ${ALGORAND_PID_PATH}) | |
curl -X ${VERB} "http://${ALGORAND_ALGOD}${ENDPOINT}" -H "Authorization: Bearer ${ALGORAND_TOKEN}" | |
# pass thru goal command but with the $ALGORAND_DATA set | |
goal *ARGS: | |
goal {{ARGS}} | |
# --- GENERATOR SCRIPT COMMANDS --- # | |
# generate an arbitrary number of app and box scenarios, each with up to BOXES_PER_APP boxes | |
gen-mult-app-boxes NUM_APPS="10" BOXES_PER_APP="2048": | |
#!/usr/bin/env python3 | |
import subprocess | |
from subprocess import CalledProcessError | |
num_apps = int({{NUM_APPS}}) | |
print(f"{num_apps=}") | |
for i in range(num_apps): | |
print("\n", "\n", "\n", f"gen-app-and-box-scenarios #{i+1}" ) | |
subprocess.run(["just", "gen-app-and-box-scenarios", "{{BOXES_PER_APP}}"]).check_returncode() | |
# create an app and add up to BOXES_PER_APP random boxes to it in a multi-threaded fashion | |
gen-app-and-box-scenarios BOXES_PER_APP="10": | |
#!/usr/bin/env python3 | |
from concurrent.futures import ThreadPoolExecutor | |
import json | |
import logging | |
import random | |
import string | |
import subprocess | |
from subprocess import CalledProcessError | |
import time | |
CHARS = string.digits + string.ascii_letters | |
VAL_SIZE = 24 | |
BOXES_PER_APP = int({{BOXES_PER_APP}}) | |
NLS = "\n" * 3 | |
subprocess.run(["just", "app-create_fund"]).check_returncode() | |
def worker(thread_number): | |
logging.info(f"HELLO from {thread_number}!") | |
create_cpe = set_cpe = test_cpe = del_cpe = None | |
rand_key_size = random.randint(4, 64) | |
rand_key = "".join(random.choice(CHARS) for _ in range(rand_key_size)) | |
print(f"{NLS}{thread_number}: {rand_key=}") | |
try: | |
subprocess.run(["just", "box-create", rand_key]).check_returncode() | |
except CalledProcessError as cpe: | |
create_cpe = str(cpe) | |
rand_val = "".join(random.choice(CHARS) for _ in range(VAL_SIZE)) | |
print(f"{NLS}{thread_number}: {rand_val=}") | |
try: | |
subprocess.run(["just", "box-set", rand_key, rand_val]).check_returncode() | |
except CalledProcessError as cpe: | |
set_cpe = str(cpe) | |
print(f"{NLS}{thread_number}: checking {rand_val=}") | |
try: | |
subprocess.run(["just", "box-test", rand_key, rand_val]).check_returncode() | |
except CalledProcessError as cpe: | |
test_cpe = str(cpe) | |
delete = random.choice([True, False]) | |
if delete: | |
print(f"{NLS}{thread_number}: deleting") | |
try: | |
subprocess.run(["just", "box-delete", rand_key]).check_returncode() | |
except CalledProcessError as cpe: | |
del_cpe = str(cpe) | |
return { | |
"thread_number": thread_number, | |
"key_size": rand_key_size, | |
"key": rand_key, | |
"val": rand_val, | |
"deleted": delete, | |
"called_process_errors": { | |
"create_cpe": create_cpe, | |
"set_cpe": set_cpe, | |
"test_cpe": test_cpe, | |
"del_cpe": del_cpe, | |
}, | |
} | |
format = "%(asctime)s: %(message)s" | |
logging.basicConfig(format=format, level=logging.INFO, | |
datefmt="%H:%M:%S") | |
results = [] | |
with ThreadPoolExecutor() as executor: | |
for r in executor.map(worker, range(BOXES_PER_APP)): | |
results.append(r) | |
print(json.dumps(results, indent=2)) | |
for result in results: | |
for err in result["called_process_errors"].values(): | |
if err: | |
raise err | |
# --- HIGHER LEVEL --- # | |
# create and then start (error if already created) | |
@create_and_start: create start status | |
sleep 5 | |
just status | |
# create an app and then fund it | |
@app-create_fund: app-create last-app-fund | |
# --- BOX PUT: HIGHER LEVEL --- # | |
# create box[BOX] for last app with provided key variable BOX | |
@box-create $BOX: | |
just app-call-last '\"create\", \"{{BOX}}\"' | |
# set box[BOX]=VAL for last app with key BOX and val VAL | |
@box-set $BOX $VAL: | |
just app-call-last '\"set\", \"{{BOX}}\", \"{{VAL}}\"' | |
# set box[BOX]=VAL for last app with key BOX and val VAL | |
@box-test $BOX $VAL: | |
just app-call-last '\"check\", \"{{BOX}}\", \"{{VAL}}\"' | |
# delete box[BOX] for last app | |
@box-delete $BOX: | |
just app-call-last '\"delete\", \"{{BOX}}\"' | |
# stop and tear down the node network. WARNING: YOU WILL LOSE ALL YOUR NODE DATA FROM THE FILE SYSTEM. | |
@stop_and_nuke: stop nuke | |
# --- PRE-REQUISITES --- # | |
# calculate an app's address using the python SDK | |
app-address *ARGS: | |
#!/usr/bin/env python3 | |
from algosdk import logic | |
print(logic.get_application_address({{ ARGS }})) | |
# --- NETWORKS / NODES --- # | |
# Private vs. Public Networks. Typical workflow: | |
# 1. Create a directory for your network (CURR_NETWORK = NETWORKS/NAME) | |
# 2. Populate the node information under CURR_NETWORK. Branch on Public vs. Private. | |
# In either case the the data directory is ALGORAND_DATA == CURR_NETWORK/DATA_NODE == NETWORKS/NAME/DATA_NODE. | |
# a. Public: Use algocfg to configure a single node: see `just pub-create` | |
# b. Private: Use `goal` to configure a network nodes under CURR_NETWORK. See `just create` | |
# 3. Start the network: `just start` | |
# | |
# NOTE: To run a public network commands, you need to supply the env var `DATA_NODE`. EG: | |
# DATA_NODE=Follower just pub-validate-datadir | |
# Or, export and run: | |
# export DATA_NODE=Follower | |
# just pub-validate-datadir | |
# create a private network with one node (error if already created) | |
create: | |
mkdir -p $NETWORKS | |
goal network create -n $NAME -r $CURR_NETWORK -t $NODE_TEMPLATE | |
# print out the current network's data directory tree | |
@tree: | |
tree $CURR_NETWORK | |
# start a the network (error if already running or not created) | |
@start: | |
goal node start | |
# PUBLIC NETWORKS BEGIN | |
# check that is ready to connect to public network | |
pub-validate-datadir: | |
#! /usr/bin/env bash | |
set -euxo pipefail | |
[ -z "$IS_PUBLIC_TRUTHY" ] && { echo "Error: DATA_NODE env var required for public network" ; exit 1; } | |
echo "Ready for public network with node datadir: $ALGORAND_DATA" | |
# list available profiles for configuring a network | |
@pub-cfg-list: | |
algocfg profile list | |
# show the current network configuration | |
@pub-cfg-show: | |
echo "cat ${ALGORAND_DATA}/config.json" | |
cat ${ALGORAND_DATA}/config.json | |
# prepare for connecting to public network | |
pub-prepare: pub-validate-datadir | |
mkdir -p $ALGORAND_DATA | |
# configure a Conduit's network using `algocfg` | |
pub-create NODE_PROFILE="conduit" NETWORK="testnet" ENDPOINT="127.0.0.1:${ENDPOINT_PORT}" PT="1" PAT="1": pub-prepare | |
algocfg profile set {{NODE_PROFILE}} -d $ALGORAND_DATA | |
[ -n {{ENDPOINT}} ] && echo "setting ENDPOINT={{ENDPOINT}}" && algocfg set -p EndpointAddress -v {{ENDPOINT}} | |
[ {{PT}} = "1" ] && echo "setting ALGOD TOKEN=${PRESET_ALGOD_TOKEN}" && echo ${PRESET_ALGOD_TOKEN} > ${ALGORAND_TOKEN_PATH} | |
[ {{PAT}} = "1" ] && echo "setting ALGOD ADMIN TOKEN=${PRESET_ALGOD_ADMIN}" && echo ${PRESET_ALGOD_ADMIN} > ${ALGORAND_ADTOKEN_PATH} | |
cp ${GO_ALGORAND}/installer/genesis/{{NETWORK}}/genesis.json $ALGORAND_DATA | |
# status of network node | |
@status: | |
goal node status && echo "RUNNING" || echo "NOT RUNNING" | |
# stop the running node (error if not running) | |
@stop: | |
goal node stop | |
# remove the node's data from the file system | |
@nuke: | |
echo "deleting $CURR_NETWORK" | |
rm -rf $CURR_NETWORK | |
echo "killing endpoint on port ${ENDPOINT_PORT}" | |
pid=$(lsof -ti :${ENDPOINT_PORT}) && [ ! -z "$pid" ] && kill -9 $pid || true | |
# --- ACCOUNTS --- # | |
# list all associated accounts | |
@list: | |
goal account list | |
# create a new account without renaming it to a human friendly local alias | |
@raw-new-account: | |
goal account new | awk '{print $NF}' | |
# echo an account's alias | |
@account-alias $ACCOUNT: | |
just list | grep {{ACCOUNT}} | awk '{print $2}' | |
# create a new locally aliased account | |
@new-account $ALIAS $ACCOUNT=`just raw-new-account`: | |
goal account rename `just account-alias {{ACCOUNT}}` {{ALIAS}} | |
# create a new multisig account with threshold 1 using provided accounts (cannot handle aliases) | |
@raw-msig-account *ACCOUNTS: | |
goal account multisig new -T 1 {{ACCOUNTS}} | awk '{print $NF}' | |
# create a new multisig account with given ALIAS and threshold 1 using provided accounts (cannot handle aliases) | |
@new-msig-account $ALIAS *ACCOUNTS: | |
goal account rename `just account-alias $(just raw-msig-account {{ACCOUNTS}})` {{ALIAS}} | |
# funding account's address | |
@funder: | |
just list | awk '{print $2}' | |
# provide information about a given account | |
@info $ACCOUNT=`just funder`: | |
goal account info --address {{ACCOUNT}} | |
# provide an account's balance | |
@balance $ACCOUNT=`just funder`: | |
goal account balance --address {{ACCOUNT}} | |
# funder's most recently created app-id | |
@last-app-id: | |
just info | grep ID | tail -n 1 | cut -d "," -f1 | awk '{print $2}' | |
# the account address of the funders most recently created app-id | |
@last-app-address: | |
just app-address `just last-app-id` | |
# --- ASSETS --- # | |
# create a dummy asset for the provided FUNDER. Copy pasta from: https://dappradar.com/blog/algorand-dapp-development-2-standard-asset-management | |
@asset-create $FUNDER=`just funder`: | |
goal asset create --creator {{FUNDER}} --total 1000000 --unitname bUSD --name "Balgorand USD" --asseturl "https://b-usd.com" --decimals 9 | |
# --- APPLICATIONS --- # | |
# information about an application of given id | |
@app-info $APP_ID=`just last-app-id`: | |
goal app info --app-id {{APP_ID}} | |
# print out the boxes teal program | |
@boxes_teal: | |
cat $BOXES_TEAL | |
# shortcut for the approval and clear program `goal app create` params | |
@programs: | |
echo "--approval-prog $BOXES_TEAL --clear-prog clear.teal" | |
# shortcut for the storage params of `goal app create` | |
@app-vars $GBS="0" $GI="0" $LBS="0" $LI="0": | |
echo "--global-byteslices $GBS --global-ints $GI --local-byteslices $LBS --local-ints $LI" | |
# shortcut for creating the arguments of an app call | |
box-app-args *ARGS: | |
#!/usr/bin/env python3 | |
args = [] | |
box_arg = "" | |
i = 0 | |
for arg in {{ARGS}}: | |
try: | |
int(arg) | |
arg = f"int:{arg}" | |
except Exception: | |
arg = f"str:{arg}" | |
args.extend(["--app-arg", arg]) | |
if i == 1: | |
box_arg = f"--box {arg}" | |
i += 1 | |
if box_arg: | |
args = [box_arg] + args | |
print(*args) | |
# create an app funded by funder account | |
@app-create $GBS="0" $GI="0" $LBS="0" $LI="0": | |
echo "goal app create --creator `just funder` `just programs` `just app-vars $GBS $GI $LBS $LI`" | |
goal app create --creator `just funder` `just programs` `just app-vars $GBS $GI $LBS $LI` | |
# call the last app from the funder address using ARGS | |
@app-call-last *ARGS='\"create\", \"mybox\"': | |
(set -x; goal app call --app-id `just last-app-id` --from `just funder` `just box-app-args {{ARGS}}`) | |
# --- BOX INFO --- # | |
# get all the boxes associated a given app-id | |
app-box-list $APP_ID=`just last-app-id`: | |
goal app box list --app-id {{APP_ID}} --max 0 | |
# get box information for a given app-id and box name | |
app-box-info $APP_ID=`just last-app-id` $BOX="str:mybox": | |
goal app box info --app-id {{APP_ID}} --name {{BOX}} | |
# --- CLERK --- # | |
# send from one account to another a given amount | |
@send $FROM $TO $AMOUNT: | |
goal clerk send --from {{FROM}} --to {{TO}} --amount {{AMOUNT}} | |
# fund the most recently created app | |
@last-app-fund $AMOUNT=`echo 133713371337`: | |
just send `just funder` `just last-app-address` {{AMOUNT}} | |
# --- CONDUIT --- # | |
# start a postgres docker container for Conduit | |
conduit-pg-up $pg_port="5555" $pg_db="conduitdb" $pg_user="algorand" $pg_pass="pgpass": | |
# docker run -d --name ${CONDUIT_DOCKER} -e POSTGRES_USER=$pg_user -e POSTGRES_PASSWORD=$pg_pass -p $pg_port:5432 -e POSTGRES_DB=$pg_db postgres | |
# docker run -d --name {args.pg_container} -e POSTGRES_USER=algorand -e POSTGRES_PASSWORD=algorand -p {args.pg_port}:5432 postgres | |
docker run -d --name ${CONDUIT_DOCKER} -e POSTGRES_USER=$pg_user -e POSTGRES_PASSWORD=$pg_pass -p $pg_port:5432 postgres | |
echo "snoozing 3 secs..." | |
sleep 3 | |
docker exec -t ${CONDUIT_DOCKER} psql -U${pg_user} -c "create database ${pg_db};" | |
# stop and remove the postgres docker container for Conduit | |
conduit-pg-clean: | |
docker stop ${CONDUIT_DOCKER} || true | |
docker rm ${CONDUIT_DOCKER} || true | |
# enter the postgres docker container for Conduit | |
conduit-pg-enter $pg_user="algorand" $pg_db="conduitdb": | |
docker exec -it ${CONDUIT_DOCKER} psql -U ${pg_user} -d ${pg_db} | |
# query the Conduit database | |
conduit-pg-query $sql="select COUNT(*) from block_header;" $pg_user="algorand" $pg_db="conduitdb": | |
docker exec -t ${CONDUIT_DOCKER} psql -U{{pg_user}} -d {{pg_db}} -c "{{sql}}" | |
# connect to the postgress database for Conduit without entering the container | |
@conduit-pg-connect $pg_port="5555" $pg_user="algorand" $pg_pass="pgpass": # $pg_db="conduitdb" | |
echo "connecting to: postgresql://${pg_user}@localhost:${pg_port}" # /${pg_db} | |
psql postgresql://${pg_user}:${pg_pass}@localhost:${pg_port} # /${pg_db} | |
# stand up a Conduit postgres container and initialize the Conduit config | |
conduit-init $pg_port="5555" $pg_user="algorand" $pg_pass="pgpass" $pg_db="conduitdb": conduit-pg-clean conduit-pg-up | |
#! /usr/bin/env bash | |
set -euo pipefail | |
TOKEN=$(cat ${ALGORAND_TOKEN_PATH}) | |
ADTOKEN=$(cat ${ALGORAND_ADTOKEN_PATH}) | |
ALGOD=$(cat ${ALGORAND_ALGOD_PATH}) | |
echo "pg_port: ${pg_port}" | |
echo "pg_db: ${pg_db}" | |
echo "pg_user: ${pg_user}" | |
echo "pg_pass: ${pg_pass}" | |
echo "algod.token: ${TOKEN}" | |
echo "algod.admin.token: ${ADTOKEN}" | |
echo "algod.net: ${ALGOD}" | |
echo "CONDUIT: ${CONDUIT}" | |
echo "CONDUIT_CONFIG: ${CONDUIT_CONFIG}" | |
rm -rf ${CONDUIT_DATA} | |
mkdir -p ${CONDUIT_DATA} | |
${CONDUIT} init -i algod -e postgresql > ${CONDUIT_CONFIG} | |
yq -i ".log-level = \"${LOG_LEVEL}\"" ${CONDUIT_CONFIG} | |
yq -i ".log-file = \"${CONDUIT_LOG}\"" ${CONDUIT_CONFIG} | |
yq -i ".importer.config.netaddr = \"http://${ALGOD}\"" ${CONDUIT_CONFIG} | |
yq -i ".importer.config.token = \"${TOKEN}\"" ${CONDUIT_CONFIG} | |
yq -i ".importer.config.catchup-config.admin-token = \"${ADTOKEN}\"" ${CONDUIT_CONFIG} | |
yq -i ".exporter.config.connection-string = \"host=localhost port=$pg_port user=$pg_user password=$pg_pass dbname=$pg_db\"" ${CONDUIT_CONFIG} | |
# start the network, run Conduit for a prescribed duration, and report the number of rounds that were processed | |
conduit-bootstrap-and-go $duration="60" $pg_user="algorand" $pg_db="conduitdb": nuke pub-create start conduit-init | |
echo "launching Conduit for ${duration} seconds..." | |
timeout ${duration} ${CONDUIT} -d ${CONDUIT_DATA} || true | |
tail ${CONDUIT_LOG} | |
tail -n 100 ${CONDUIT_LOG} | grep -i "Pipeline round:" | |
just conduit-pg-query "select MAX(round) from block_header;" {{pg_user}} {{pg_db}} | |
wc -l ${CONDUIT_LOG} | |
# --- CONSENSUS PARAMS --- # | |
# list all consensus param declarations | |
@consensus-params-list: | |
cat ${GO_ALGORAND}/config/consensus.go | egrep " (bool|byte|int$|uint|map\[|Duration|PaysetCommitType)" | egrep -v "type|=|func|,|//" | |
# print out the value history of a consensus param | |
@consensus-param $CP="MaximumMinimumBalance": | |
cat ${GO_ALGORAND}/config/consensus.go | grep {{CP}} || echo "{{CP}} not found in consensus.go" | |
# consensus params for program size | |
consensus-prog-size: | |
just consensus-param LogicSigMaxSize | |
just consensus-param MaxAppProgramLen | |
# consensus param for LogicSigMaxCost | |
consensus-prog-cost: | |
just consensus-param MaxCost | |
just consensus-param MaxAppProgramCost | |
# consensus params for program pages | |
@consensus-prog-pages: | |
just consensus-param MaxExtraAppProgramPages | |
# consensus params for foreign refs: | |
consensus-foreign-refs: | |
just consensus-param MaxAppTxnAccounts | |
just consensus-param MaxAppTxnForeignApps | |
just consensus-param MaxAppTxnForeignAssets | |
just consensus-param MaxAppTotalTxnReferences | |
just consensus-param MaxAppBoxReferences | |
# consensus params for local/global storage: | |
consensus-storage: | |
just consensus-param MaxAppKeyLen | |
just consensus-param MaxAppBytesValueLen | |
just consensus-param MaxAppSumKeyValueLens | |
just consensus-param MaxLocalSchemaEntries | |
just consensus-param MaxGlobalSchemaEntries | |
# consensus params for min-balance calc: | |
consensus-minbal: | |
just consensus-param SchemaMinBalancePerEntry | |
just consensus-param SchemaUintMinBalance | |
just consensus-param SchemaBytesMinBalance | |
just consensus-param BoxFlatMinBalance | |
just consensus-param BoxByteMinBalance | |
# consensus params for boxes: | |
consensus-boxes: | |
just consensus-param MaxAppKeyLen | |
just consensus-param MaxBoxSize | |
just consensus-param BoxFlatMinBalance | |
just consensus-param BoxByteMinBalance | |
just consensus-param MaxAppBoxReferences | |
just consensus-param BytesPerBoxReference | |
# --- MISCELLANEOUS --- # | |
# print out the network's algod & kmd token and network/process info | |
client-info: | |
#! /usr/bin/env bash | |
set -euo pipefail | |
ALGORAND_TOKEN=$(cat ${ALGORAND_TOKEN_PATH}) | |
ALGORAND_ADTOKEN=$(cat ${ALGORAND_ADTOKEN_PATH}) | |
ALGORAND_ALGOD=$(cat ${ALGORAND_ALGOD_PATH}) | |
ALGORAND_PID=$(cat ${ALGORAND_PID_PATH}) | |
echo "algod.token: ${ALGORAND_TOKEN}" | |
echo "algod.admin.token: ${ALGORAND_ADTOKEN}" | |
echo "algod.net: ${ALGORAND_ALGOD}" | |
echo "algod.pid: ${ALGORAND_PID}" | |
if [[ -f "${ALGORAND_DATA}/kmd-v0.5/kmd.token" ]]; then | |
KMD=$(cat "${ALGORAND_DATA}/kmd-v0.5/kmd.token") | |
else | |
KMD="" | |
fi | |
echo "kmd.token: ${KMD}" | |
if [[ -n $KMD ]]; then | |
echo "kmd.net---->" | |
cat ${ALGORAND_DATA}/kmd-v0.5/kmd.log | grep 127.0.0.1 | head -n 1 | cut -d '"' -f4 | |
fi | |
# print out broadcastQueueBulk's channel size ... the default is 100 which is too small for the example | |
@broadcast-queue-size: | |
echo "default is 100. What is it actually in network/wsNetwork.go ?" | |
cat {{GO_ALGORAND}}/network/wsNetwork.go | grep "wn.broadcastQueueBulk = make(chan broadcastRequest" | cut -d "," -f2 | cut -d ")" -f1 | awk '{print $1}' |
set export | |
set shell := ["zsh", "-cu"] | |
NETWORKS := `echo $HOME` + "/networks" | |
NAME := "conduitnetwork" | |
CURR_NETWORK := NETWORKS + "/" + NAME | |
GO_ALGORAND := "/Users/zeph/github/tzaffi/go-algorand" | |
NODE_TEMPLATE := GO_ALGORAND + "/test/testdata/nettemplates/TwoNodesFollower100Second.json" | |
PRIVATE_DATA_NODE := "Primary" | |
DATA_NODE := env_var_or_default("DATA_NODE", PRIVATE_DATA_NODE) | |
IS_PUBLIC_TRUTHY := env_var_or_default("DATA_NODE", "") | |
ALGORAND_DATA := CURR_NETWORK + "/" + DATA_NODE | |
ALGORAND_TOKEN_PATH := ALGORAND_DATA + "/algod.token" | |
ALGORAND_ADTOKEN_PATH := ALGORAND_DATA + "/algod.admin.token" | |
ALGORAND_ALGOD_PATH := ALGORAND_DATA + "/algod.net" | |
ALGORAND_PID_PATH := ALGORAND_DATA + "/algod.pid" | |
ENDPOINT_PORT := "56765" | |
CONDUIT := "./conduit" | |
CONDUIT_DATA := CURR_NETWORK + "/conduit" | |
CONDUIT_CONFIG := CONDUIT_DATA + "/conduit.yml" | |
CONDUIT_LOG := CONDUIT_DATA + "/conduit.log" | |
CONDUIT_DOCKER := "conduit-postgres" | |
LOG_LEVEL := "INFO" # "INFO" # "TRACE" | |
# These fake pre-set tokens make it easier to test against a local network | |
PRESET_ALGOD_TOKEN := "16b29a0a2bbcc535f1e9e40f0c0888013f3789bf2bd34e7907c8fb1ae9d16024" | |
PRESET_ALGOD_ADMIN := "20064faacad1e590e757ac9492506c2d948633d7c458651b16a3991d26997695" | |
# Older: | |
BOXES_TEAL := "boxes.teal" | |
# --- SUMMARY --- # | |
# list all available commands | |
default: | |
just --list | |
# echo all variables | |
@echo: | |
echo NETWORKS: $NETWORKS | |
echo NAME: $NAME | |
echo CURR_NETWORK: $CURR_NETWORK | |
echo GO_ALGORAND: $GO_ALGORAND | |
echo NODE_TEMPLATE: $NODE_TEMPLATE | |
echo PRIVATE_DATA_NODE: $PRIVATE_DATA_NODE | |
echo DATA_NODE: $DATA_NODE | |
echo IS_PUBLIC_TRUTHY: $IS_PUBLIC_TRUTHY | |
echo ALGORAND_DATA: $ALGORAND_DATA | |
echo ALGORAND_TOKEN_PATH: $ALGORAND_TOKEN_PATH | |
echo ALGORAND_ALGOD_PATH: $ALGORAND_ALGOD_PATH | |
echo ALGORAND_PID_PATH: $ALGORAND_PID_PATH | |
echo ENDPOINT_PORT: $ENDPOINT_PORT | |
echo CONDUIT: $CONDUIT | |
echo CONDUIT_DATA: $CONDUIT_DATA | |
echo CONDUIT_CONFIG: $CONDUIT_CONFIG | |
echo CONDUIT_LOG: $CONDUIT_LOG | |
echo CONDUIT_DOCKER: $CONDUIT_DOCKER | |
echo BOXES_TEAL: $BOXES_TEAL | |
# --- algod curl --- # | |
algod ENDPOINT="/v2/status" VERB="GET": | |
#! /usr/bin/env bash | |
# set -euxo pipefail | |
set -euo pipefail | |
ALGORAND_TOKEN=$(cat ${ALGORAND_TOKEN_PATH}) | |
ALGORAND_ALGOD=$(cat ${ALGORAND_ALGOD_PATH}) | |
ALGORAND_PID=$(cat ${ALGORAND_PID_PATH}) | |
curl -X ${VERB} "http://${ALGORAND_ALGOD}${ENDPOINT}" -H "Authorization: Bearer ${ALGORAND_TOKEN}" | |
# pass thru goal command but with the $ALGORAND_DATA set | |
goal *ARGS: | |
goal {{ARGS}} | |
# --- GENERATOR SCRIPT COMMANDS --- # | |
# generate an arbitrary number of app and box scenarios, each with up to BOXES_PER_APP boxes | |
gen-mult-app-boxes NUM_APPS="10" BOXES_PER_APP="2048": | |
#!/usr/bin/env python3 | |
import subprocess | |
from subprocess import CalledProcessError | |
num_apps = int({{NUM_APPS}}) | |
print(f"{num_apps=}") | |
for i in range(num_apps): | |
print("\n", "\n", "\n", f"gen-app-and-box-scenarios #{i+1}" ) | |
subprocess.run(["just", "gen-app-and-box-scenarios", "{{BOXES_PER_APP}}"]).check_returncode() | |
# create an app and add up to BOXES_PER_APP random boxes to it in a multi-threaded fashion | |
gen-app-and-box-scenarios BOXES_PER_APP="10": | |
#!/usr/bin/env python3 | |
from concurrent.futures import ThreadPoolExecutor | |
import json | |
import logging | |
import random | |
import string | |
import subprocess | |
from subprocess import CalledProcessError | |
import time | |
CHARS = string.digits + string.ascii_letters | |
VAL_SIZE = 24 | |
BOXES_PER_APP = int({{BOXES_PER_APP}}) | |
NLS = "\n" * 3 | |
subprocess.run(["just", "app-create_fund"]).check_returncode() | |
def worker(thread_number): | |
logging.info(f"HELLO from {thread_number}!") | |
create_cpe = set_cpe = test_cpe = del_cpe = None | |
rand_key_size = random.randint(4, 64) | |
rand_key = "".join(random.choice(CHARS) for _ in range(rand_key_size)) | |
print(f"{NLS}{thread_number}: {rand_key=}") | |
try: | |
subprocess.run(["just", "box-create", rand_key]).check_returncode() | |
except CalledProcessError as cpe: | |
create_cpe = str(cpe) | |
rand_val = "".join(random.choice(CHARS) for _ in range(VAL_SIZE)) | |
print(f"{NLS}{thread_number}: {rand_val=}") | |
try: | |
subprocess.run(["just", "box-set", rand_key, rand_val]).check_returncode() | |
except CalledProcessError as cpe: | |
set_cpe = str(cpe) | |
print(f"{NLS}{thread_number}: checking {rand_val=}") | |
try: | |
subprocess.run(["just", "box-test", rand_key, rand_val]).check_returncode() | |
except CalledProcessError as cpe: | |
test_cpe = str(cpe) | |
delete = random.choice([True, False]) | |
if delete: | |
print(f"{NLS}{thread_number}: deleting") | |
try: | |
subprocess.run(["just", "box-delete", rand_key]).check_returncode() | |
except CalledProcessError as cpe: | |
del_cpe = str(cpe) | |
return { | |
"thread_number": thread_number, | |
"key_size": rand_key_size, | |
"key": rand_key, | |
"val": rand_val, | |
"deleted": delete, | |
"called_process_errors": { | |
"create_cpe": create_cpe, | |
"set_cpe": set_cpe, | |
"test_cpe": test_cpe, | |
"del_cpe": del_cpe, | |
}, | |
} | |
format = "%(asctime)s: %(message)s" | |
logging.basicConfig(format=format, level=logging.INFO, | |
datefmt="%H:%M:%S") | |
results = [] | |
with ThreadPoolExecutor() as executor: | |
for r in executor.map(worker, range(BOXES_PER_APP)): | |
results.append(r) | |
print(json.dumps(results, indent=2)) | |
for result in results: | |
for err in result["called_process_errors"].values(): | |
if err: | |
raise err | |
# --- HIGHER LEVEL --- # | |
# create and then start (error if already created) | |
@create_and_start: create start status | |
sleep 5 | |
just status | |
# create an app and then fund it | |
@app-create_fund: app-create last-app-fund | |
# --- BOX PUT: HIGHER LEVEL --- # | |
# create box[BOX] for last app with provided key variable BOX | |
@box-create $BOX: | |
just app-call-last '\"create\", \"{{BOX}}\"' | |
# set box[BOX]=VAL for last app with key BOX and val VAL | |
@box-set $BOX $VAL: | |
just app-call-last '\"set\", \"{{BOX}}\", \"{{VAL}}\"' | |
# set box[BOX]=VAL for last app with key BOX and val VAL | |
@box-test $BOX $VAL: | |
just app-call-last '\"check\", \"{{BOX}}\", \"{{VAL}}\"' | |
# delete box[BOX] for last app | |
@box-delete $BOX: | |
just app-call-last '\"delete\", \"{{BOX}}\"' | |
# stop and tear down the node network. WARNING: YOU WILL LOSE ALL YOUR NODE DATA FROM THE FILE SYSTEM. | |
@stop_and_nuke: stop nuke | |
# --- PRE-REQUISITES --- # | |
# calculate an app's address using the python SDK | |
app-address *ARGS: | |
#!/usr/bin/env python3 | |
from algosdk import logic | |
print(logic.get_application_address({{ ARGS }})) | |
# --- NETWORKS / NODES --- # | |
# Private vs. Public Networks. Typical workflow: | |
# 1. Create a directory for your network (CURR_NETWORK = NETWORKS/NAME) | |
# 2. Populate the node information under CURR_NETWORK. Branch on Public vs. Private. | |
# In either case the the data directory is ALGORAND_DATA == CURR_NETWORK/DATA_NODE == NETWORKS/NAME/DATA_NODE. | |
# a. Public: Use algocfg to configure a single node: see `just pub-create` | |
# b. Private: Use `goal` to configure a network nodes under CURR_NETWORK. See `just create` | |
# 3. Start the network: `just start` | |
# | |
# NOTE: To run a public network commands, you need to supply the env var `DATA_NODE`. EG: | |
# DATA_NODE=Follower just pub-validate-datadir | |
# Or, export and run: | |
# export DATA_NODE=Follower | |
# just pub-validate-datadir | |
# create a private network with one node (error if already created) | |
create: | |
mkdir -p $NETWORKS | |
goal network create -n $NAME -r $CURR_NETWORK -t $NODE_TEMPLATE | |
# print out the current network's data directory tree | |
@tree: | |
tree $CURR_NETWORK | |
# start a the network (error if already running or not created) | |
@start: | |
goal node start | |
# PUBLIC NETWORKS BEGIN | |
# check that is ready to connect to public network | |
pub-validate-datadir: | |
#! /usr/bin/env bash | |
set -euxo pipefail | |
[ -z "$IS_PUBLIC_TRUTHY" ] && { echo "Error: DATA_NODE env var required for public network" ; exit 1; } | |
echo "Ready for public network with node datadir: $ALGORAND_DATA" | |
# list available profiles for configuring a network | |
@pub-cfg-list: | |
algocfg profile list | |
# show the current network configuration | |
@pub-cfg-show: | |
echo "cat ${ALGORAND_DATA}/config.json" | |
cat ${ALGORAND_DATA}/config.json | |
# prepare for connecting to public network | |
pub-prepare: pub-validate-datadir | |
mkdir -p $ALGORAND_DATA | |
# configure a Conduit's network using `algocfg` | |
pub-create NODE_PROFILE="conduit" NETWORK="testnet" ENDPOINT="127.0.0.1:${ENDPOINT_PORT}" PT="1" PAT="1": pub-prepare | |
algocfg profile set {{NODE_PROFILE}} -d $ALGORAND_DATA | |
[ -n {{ENDPOINT}} ] && echo "setting ENDPOINT={{ENDPOINT}}" && algocfg set -p EndpointAddress -v {{ENDPOINT}} | |
[ {{PT}} = "1" ] && echo "setting ALGOD TOKEN=${PRESET_ALGOD_TOKEN}" && echo ${PRESET_ALGOD_TOKEN} > ${ALGORAND_TOKEN_PATH} | |
[ {{PAT}} = "1" ] && echo "setting ALGOD ADMIN TOKEN=${PRESET_ALGOD_ADMIN}" && echo ${PRESET_ALGOD_ADMIN} > ${ALGORAND_ADTOKEN_PATH} | |
cp ${GO_ALGORAND}/installer/genesis/{{NETWORK}}/genesis.json $ALGORAND_DATA | |
# status of network node | |
@status: | |
goal node status && echo "RUNNING" || echo "NOT RUNNING" | |
# stop the running node (error if not running) | |
@stop: | |
goal node stop | |
# remove the node's data from the file system | |
@nuke: | |
echo "deleting $CURR_NETWORK" | |
rm -rf $CURR_NETWORK | |
echo "killing endpoint on port ${ENDPOINT_PORT}" | |
pid=$(lsof -ti :${ENDPOINT_PORT}) && [ ! -z "$pid" ] && kill -9 $pid || true | |
# --- ACCOUNTS --- # | |
# list all associated accounts | |
@list: | |
goal account list | |
# create a new account without renaming it to a human friendly local alias | |
@raw-new-account: | |
goal account new | awk '{print $NF}' | |
# echo an account's alias | |
@account-alias $ACCOUNT: | |
just list | grep {{ACCOUNT}} | awk '{print $2}' | |
# create a new locally aliased account | |
@new-account $ALIAS $ACCOUNT=`just raw-new-account`: | |
goal account rename `just account-alias {{ACCOUNT}}` {{ALIAS}} | |
# create a new multisig account with threshold 1 using provided accounts (cannot handle aliases) | |
@raw-msig-account *ACCOUNTS: | |
goal account multisig new -T 1 {{ACCOUNTS}} | awk '{print $NF}' | |
# create a new multisig account with given ALIAS and threshold 1 using provided accounts (cannot handle aliases) | |
@new-msig-account $ALIAS *ACCOUNTS: | |
goal account rename `just account-alias $(just raw-msig-account {{ACCOUNTS}})` {{ALIAS}} | |
# funding account's address | |
@funder: | |
just list | awk '{print $2}' | |
# provide information about a given account | |
@info $ACCOUNT=`just funder`: | |
goal account info --address {{ACCOUNT}} | |
# provide an account's balance | |
@balance $ACCOUNT=`just funder`: | |
goal account balance --address {{ACCOUNT}} | |
# funder's most recently created app-id | |
@last-app-id: | |
just info | grep ID | tail -n 1 | cut -d "," -f1 | awk '{print $2}' | |
# the account address of the funders most recently created app-id | |
@last-app-address: | |
just app-address `just last-app-id` | |
# --- ASSETS --- # | |
# create a dummy asset for the provided FUNDER. Copy pasta from: https://dappradar.com/blog/algorand-dapp-development-2-standard-asset-management | |
@asset-create $FUNDER=`just funder`: | |
goal asset create --creator {{FUNDER}} --total 1000000 --unitname bUSD --name "Balgorand USD" --asseturl "https://b-usd.com" --decimals 9 | |
# --- APPLICATIONS --- # | |
# information about an application of given id | |
@app-info $APP_ID=`just last-app-id`: | |
goal app info --app-id {{APP_ID}} | |
# print out the boxes teal program | |
@boxes_teal: | |
cat $BOXES_TEAL | |
# shortcut for the approval and clear program `goal app create` params | |
@programs: | |
echo "--approval-prog $BOXES_TEAL --clear-prog clear.teal" | |
# shortcut for the storage params of `goal app create` | |
@app-vars $GBS="0" $GI="0" $LBS="0" $LI="0": | |
echo "--global-byteslices $GBS --global-ints $GI --local-byteslices $LBS --local-ints $LI" | |
# shortcut for creating the arguments of an app call | |
box-app-args *ARGS: | |
#!/usr/bin/env python3 | |
args = [] | |
box_arg = "" | |
i = 0 | |
for arg in {{ARGS}}: | |
try: | |
int(arg) | |
arg = f"int:{arg}" | |
except Exception: | |
arg = f"str:{arg}" | |
args.extend(["--app-arg", arg]) | |
if i == 1: | |
box_arg = f"--box {arg}" | |
i += 1 | |
if box_arg: | |
args = [box_arg] + args | |
print(*args) | |
# create an app funded by funder account | |
@app-create $GBS="0" $GI="0" $LBS="0" $LI="0": | |
echo "goal app create --creator `just funder` `just programs` `just app-vars $GBS $GI $LBS $LI`" | |
goal app create --creator `just funder` `just programs` `just app-vars $GBS $GI $LBS $LI` | |
# call the last app from the funder address using ARGS | |
@app-call-last *ARGS='\"create\", \"mybox\"': | |
(set -x; goal app call --app-id `just last-app-id` --from `just funder` `just box-app-args {{ARGS}}`) | |
# --- BOX INFO --- # | |
# get all the boxes associated a given app-id | |
app-box-list $APP_ID=`just last-app-id`: | |
goal app box list --app-id {{APP_ID}} --max 0 | |
# get box information for a given app-id and box name | |
app-box-info $APP_ID=`just last-app-id` $BOX="str:mybox": | |
goal app box info --app-id {{APP_ID}} --name {{BOX}} | |
# --- CLERK --- # | |
# send from one account to another a given amount | |
@send $FROM $TO $AMOUNT: | |
goal clerk send --from {{FROM}} --to {{TO}} --amount {{AMOUNT}} | |
# fund the most recently created app | |
@last-app-fund $AMOUNT=`echo 133713371337`: | |
just send `just funder` `just last-app-address` {{AMOUNT}} | |
# --- CONDUIT --- # | |
# start a postgres docker container for Conduit | |
conduit-pg-up $pg_port="5555" $pg_db="conduitdb" $pg_user="algorand" $pg_pass="pgpass": | |
# docker run -d --name ${CONDUIT_DOCKER} -e POSTGRES_USER=$pg_user -e POSTGRES_PASSWORD=$pg_pass -p $pg_port:5432 -e POSTGRES_DB=$pg_db postgres | |
# docker run -d --name {args.pg_container} -e POSTGRES_USER=algorand -e POSTGRES_PASSWORD=algorand -p {args.pg_port}:5432 postgres | |
docker run -d --name ${CONDUIT_DOCKER} -e POSTGRES_USER=$pg_user -e POSTGRES_PASSWORD=$pg_pass -p $pg_port:5432 postgres | |
echo "snoozing 3 secs..." | |
sleep 3 | |
docker exec -t ${CONDUIT_DOCKER} psql -U${pg_user} -c "create database ${pg_db};" | |
# stop and remove the postgres docker container for Conduit | |
conduit-pg-clean: | |
docker stop ${CONDUIT_DOCKER} || true | |
docker rm ${CONDUIT_DOCKER} || true | |
# enter the postgres docker container for Conduit | |
conduit-pg-enter $pg_user="algorand" $pg_db="conduitdb": | |
docker exec -it ${CONDUIT_DOCKER} psql -U ${pg_user} -d ${pg_db} | |
# query the Conduit database | |
conduit-pg-query $sql="select COUNT(*) from block_header;" $pg_user="algorand" $pg_db="conduitdb": | |
docker exec -t ${CONDUIT_DOCKER} psql -U{{pg_user}} -d {{pg_db}} -c "{{sql}}" | |
# connect to the postgress database for Conduit without entering the container | |
@conduit-pg-connect $pg_port="5555" $pg_user="algorand" $pg_pass="pgpass": # $pg_db="conduitdb" | |
echo "connecting to: postgresql://${pg_user}@localhost:${pg_port}" # /${pg_db} | |
psql postgresql://${pg_user}:${pg_pass}@localhost:${pg_port} # /${pg_db} | |
# stand up a Conduit postgres container and initialize the Conduit config | |
conduit-init $pg_port="5555" $pg_user="algorand" $pg_pass="pgpass" $pg_db="conduitdb": conduit-pg-clean conduit-pg-up | |
#! /usr/bin/env bash | |
set -euo pipefail | |
TOKEN=$(cat ${ALGORAND_TOKEN_PATH}) | |
ADTOKEN=$(cat ${ALGORAND_ADTOKEN_PATH}) | |
ALGOD=$(cat ${ALGORAND_ALGOD_PATH}) | |
echo "pg_port: ${pg_port}" | |
echo "pg_db: ${pg_db}" | |
echo "pg_user: ${pg_user}" | |
echo "pg_pass: ${pg_pass}" | |
echo "algod.token: ${TOKEN}" | |
echo "algod.admin.token: ${ADTOKEN}" | |
echo "algod.net: ${ALGOD}" | |
echo "CONDUIT: ${CONDUIT}" | |
echo "CONDUIT_CONFIG: ${CONDUIT_CONFIG}" | |
rm -rf ${CONDUIT_DATA} | |
mkdir -p ${CONDUIT_DATA} | |
${CONDUIT} init -i algod -e postgresql > ${CONDUIT_CONFIG} | |
yq -i ".log-level = \"${LOG_LEVEL}\"" ${CONDUIT_CONFIG} | |
yq -i ".log-file = \"${CONDUIT_LOG}\"" ${CONDUIT_CONFIG} | |
yq -i ".importer.config.netaddr = \"http://${ALGOD}\"" ${CONDUIT_CONFIG} | |
yq -i ".importer.config.token = \"${TOKEN}\"" ${CONDUIT_CONFIG} | |
yq -i ".importer.config.catchup-config.admin-token = \"${ADTOKEN}\"" ${CONDUIT_CONFIG} | |
yq -i ".exporter.config.connection-string = \"host=localhost port=$pg_port user=$pg_user password=$pg_pass dbname=$pg_db\"" ${CONDUIT_CONFIG} | |
# start the network, run Conduit for a prescribed duration, and report the number of rounds that were processed | |
conduit-experiment $duration="60" $pg_user="algorand" $pg_db="conduitdb": nuke pub-create start conduit-init | |
echo "launching Conduit for ${duration} seconds..." | |
timeout ${duration} ${CONDUIT} -d ${CONDUIT_DATA} || true | |
tail ${CONDUIT_LOG} | |
tail -n 100 ${CONDUIT_LOG} | grep -i "FINISHED Pipeline round" | |
just conduit-pg-query "select MAX(round) from block_header;" {{pg_user}} {{pg_db}} | |
wc -l ${CONDUIT_LOG} | |
# --- CONSENSUS PARAMS --- # | |
# list all consensus param declarations | |
@consensus-params-list: | |
cat ${GO_ALGORAND}/config/consensus.go | egrep " (bool|byte|int$|uint|map\[|Duration|PaysetCommitType)" | egrep -v "type|=|func|,|//" | |
# print out the value history of a consensus param | |
@consensus-param $CP="MaximumMinimumBalance": | |
cat ${GO_ALGORAND}/config/consensus.go | grep {{CP}} || echo "{{CP}} not found in consensus.go" | |
# consensus params for program size | |
consensus-prog-size: | |
just consensus-param LogicSigMaxSize | |
just consensus-param MaxAppProgramLen | |
# consensus param for LogicSigMaxCost | |
consensus-prog-cost: | |
just consensus-param MaxCost | |
just consensus-param MaxAppProgramCost | |
# consensus params for program pages | |
@consensus-prog-pages: | |
just consensus-param MaxExtraAppProgramPages | |
# consensus params for foreign refs: | |
consensus-foreign-refs: | |
just consensus-param MaxAppTxnAccounts | |
just consensus-param MaxAppTxnForeignApps | |
just consensus-param MaxAppTxnForeignAssets | |
just consensus-param MaxAppTotalTxnReferences | |
just consensus-param MaxAppBoxReferences | |
# consensus params for local/global storage: | |
consensus-storage: | |
just consensus-param MaxAppKeyLen | |
just consensus-param MaxAppBytesValueLen | |
just consensus-param MaxAppSumKeyValueLens | |
just consensus-param MaxLocalSchemaEntries | |
just consensus-param MaxGlobalSchemaEntries | |
# consensus params for min-balance calc: | |
consensus-minbal: | |
just consensus-param SchemaMinBalancePerEntry | |
just consensus-param SchemaUintMinBalance | |
just consensus-param SchemaBytesMinBalance | |
just consensus-param BoxFlatMinBalance | |
just consensus-param BoxByteMinBalance | |
# consensus params for boxes: | |
consensus-boxes: | |
just consensus-param MaxAppKeyLen | |
just consensus-param MaxBoxSize | |
just consensus-param BoxFlatMinBalance | |
just consensus-param BoxByteMinBalance | |
just consensus-param MaxAppBoxReferences | |
just consensus-param BytesPerBoxReference | |
# --- MISCELLANEOUS --- # | |
# print out the network's algod & kmd token and network/process info | |
client-info: | |
#! /usr/bin/env bash | |
set -euo pipefail | |
ALGORAND_TOKEN=$(cat ${ALGORAND_TOKEN_PATH}) | |
ALGORAND_ADTOKEN=$(cat ${ALGORAND_ADTOKEN_PATH}) | |
ALGORAND_ALGOD=$(cat ${ALGORAND_ALGOD_PATH}) | |
ALGORAND_PID=$(cat ${ALGORAND_PID_PATH}) | |
echo "algod.token: ${ALGORAND_TOKEN}" | |
echo "algod.admin.token: ${ALGORAND_ADTOKEN}" | |
echo "algod.net: ${ALGORAND_ALGOD}" | |
echo "algod.pid: ${ALGORAND_PID}" | |
if [[ -f "${ALGORAND_DATA}/kmd-v0.5/kmd.token" ]]; then | |
KMD=$(cat "${ALGORAND_DATA}/kmd-v0.5/kmd.token") | |
else | |
KMD="" | |
fi | |
echo "kmd.token: ${KMD}" | |
if [[ -n $KMD ]]; then | |
echo "kmd.net---->" | |
cat ${ALGORAND_DATA}/kmd-v0.5/kmd.log | grep 127.0.0.1 | head -n 1 | cut -d '"' -f4 | |
fi | |
# print out broadcastQueueBulk's channel size ... the default is 100 which is too small for the example | |
@broadcast-queue-size: | |
echo "default is 100. What is it actually in network/wsNetwork.go ?" | |
cat {{GO_ALGORAND}}/network/wsNetwork.go | grep "wn.broadcastQueueBulk = make(chan broadcastRequest" | cut -d "," -f2 | cut -d ")" -f1 | awk '{print $1}' |
import argparse | |
from string import Template | |
# EG: | |
# | |
# ❯ python make_just.py --name blue-whale | |
class DblDollars(Template): | |
delimiter = '$$' # Use $$ as the delimiter | |
# Define the substitutions | |
substitutions = { | |
"NAME": "niftynetwork", | |
"NETWORKS": '`echo $HOME` + "/networks"', | |
"GO_ALGORAND": "/Users/zeph/github/algorand/go-algorand", | |
"NODE_TEMPLATE": "OneNodeFuture.json", | |
"PRIVATE_DATA_NODE": "Primary", | |
} | |
# Parse command-line arguments | |
parser = argparse.ArgumentParser() | |
parser.add_argument("--just-out-file", default="Justfile.tmp") | |
parser.add_argument("--name") | |
parser.add_argument("--networks") | |
parser.add_argument("--go-algorand") | |
parser.add_argument("--node-template") | |
parser.add_argument("--private-data-node") | |
args = parser.parse_args() | |
templ_args = vars(args) | |
file_out = templ_args.pop("just_out_file") | |
# Update the substitutions with the arguments | |
substitutions.update({ | |
key: templ_args[k] for key in substitutions if templ_args[(k := key.lower())] is not None | |
}) | |
# Open the template and substitute the placeholders with actual values | |
with open('Justfile.tmpl', 'r') as f: | |
template = DblDollars(f.read()) | |
result = template.substitute(substitutions) | |
# Write the result to the output file | |
with open(file_out, 'w') as f: | |
f.write(result) |