Taken from github - casey/just
curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to DESTIn my case DEST=~/bin
Taken from github - casey/just
curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to DESTIn 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) |