#!/usr/bin/env bash

set -Eeuo pipefail
trap 'echo "Error at line $LINENO"' ERR

if [ -z "${CARDANO_NODE_SOCKET_PATH:-}" ]; then
  echo "CARDANO_NODE_SOCKET_PATH is not set" >&2
  exit 1
fi

SCRIPT_DIR="$(readlink -m "${0%/*}")"
SOCKET_PATH="$(readlink -m "$CARDANO_NODE_SOCKET_PATH")"
STATE_CLUSTER="${SOCKET_PATH%/*}"
STATE_CLUSTER_NAME="${STATE_CLUSTER##*/}"
SUPERVISORD_SOCKET_PATH="${STATE_CLUSTER}/supervisord.sock"
START_CLUSTER_LOG="${STATE_CLUSTER}/start-cluster.log"
START_CLUSTER_STATUS="${STATE_CLUSTER}/status_started"

INSTANCE_NUM="%%INSTANCE_NUM%%"
if [[ "$SOCKET_PATH" != *"/state-cluster${INSTANCE_NUM}/"* ]]; then
  echo "CARDANO_NODE_SOCKET_PATH must be set to a path containing 'state-cluster${INSTANCE_NUM}', line $LINENO" >&2
  exit 1
fi

NUM_BFT_NODES=1
NUM_POOLS=%%NUM_POOLS%%
NUM_CC=5
NUM_DREPS=5
TX_SUBMISSION_DELAY=60
SUBMIT_DELAY=5
POOL_PLEDGE=1000000000000
DREP_DELEGATED=500000000000
BYRON_INIT_SUPPLY=10020000000
PROTOCOL_VERSION=10
if [ -n "${PV9:-""}" ]; then
  PROTOCOL_VERSION=9
fi

SECURITY_PARAM="$(jq '.securityParam' < "${SCRIPT_DIR}/genesis.spec.json")"
NETWORK_MAGIC="$(jq '.networkMagic' < "${SCRIPT_DIR}/genesis.spec.json")"
MAX_SUPPLY="$(jq '.maxLovelaceSupply' < "${SCRIPT_DIR}/genesis.spec.json")"
POOL_COST="$(jq '.protocolParams.minPoolCost' < "${SCRIPT_DIR}/genesis.spec.json")"
if [ "$POOL_COST" -eq 0 ]; then
  POOL_COST=600
fi

# There is some weird calculation going on, and the deleg supply needs to have a minimum value,
# that is somehow based on non-delegated supply.
DELEG_MAGIC_VALUE=3340000000000000
DELEG_SUPPLY="$((POOL_PLEDGE * NUM_POOLS + DELEG_MAGIC_VALUE))"
NONDELEG_SUPPLY="$(( (MAX_SUPPLY - DELEG_SUPPLY) * 8 / 10))"

if [ -e "$SUPERVISORD_SOCKET_PATH" ]; then
  echo "Cluster already running. Please run \`${STATE_CLUSTER}/stop-cluster\` first!" >&2
  exit 1
fi

if [ "$NUM_POOLS" -lt 3 ]; then
  echo "NUM_POOLS must be at least 3" >&2
  exit 1
fi

ENABLE_SUBMIT_API="$(command -v cardano-submit-api >/dev/null 2>&1 && echo 1 || echo 0)"

source "${SCRIPT_DIR}/common.sh"

if [ -e "${SCRIPT_DIR}/shell_env" ]; then
  # shellcheck disable=SC1091
  source "${SCRIPT_DIR}/shell_env"
fi

rm -rf "$STATE_CLUSTER"
mkdir -p "$STATE_CLUSTER"/{shelley,webserver,db-sync,create_staked,governance_data}
cd "${STATE_CLUSTER}/.."

cp "$SCRIPT_DIR"/cardano-node-* "$STATE_CLUSTER"
cp "${SCRIPT_DIR}/run-cardano-submit-api" "$STATE_CLUSTER"
cp "${SCRIPT_DIR}/byron-params.json" "$STATE_CLUSTER"
cp "${SCRIPT_DIR}/dbsync-config.yaml" "$STATE_CLUSTER"
cp "${SCRIPT_DIR}/submit-api-config.json" "$STATE_CLUSTER"
cp "${SCRIPT_DIR}/supervisor.conf" "$STATE_CLUSTER"
cp "$SCRIPT_DIR/testnet.json" "$STATE_CLUSTER"
cp "$SCRIPT_DIR"/*genesis*.spec.json "${STATE_CLUSTER}/create_staked/"

if [ -n "${PV9:-""}" ]; then
  cp -f \
    "${SCRIPT_DIR}/genesis.conway.spec.pv9.json" \
    "${STATE_CLUSTER}/create_staked/genesis.conway.spec.json"
fi

if [ -z "${ENABLE_LEGACY:-""}" ]; then
  # use P2P topology files
  for tconf in "$SCRIPT_DIR"/p2p-topology-*.json; do
    tfname="${tconf##*/p2p-}"
    cp "$tconf" "${STATE_CLUSTER}/${tfname}"
  done
else
  cp "$SCRIPT_DIR"/topology-*.json "$STATE_CLUSTER"
fi

LIVE_TABLES_BASE="${STATE_CLUSTER_NAME}/lmdb"
case "${UTXO_BACKEND:=""}" in
  "" | mem | disk)
    ;;
  *)
    echo "Unknown \`UTXO_BACKEND\`: '$UTXO_BACKEND', line $LINENO" >&2
    exit 1
    ;;
esac

cat >> "${STATE_CLUSTER}/supervisor.conf" <<EoF

[unix_http_server]
file = ${SUPERVISORD_SOCKET_PATH}

[supervisorctl]
serverurl = unix:///${SUPERVISORD_SOCKET_PATH}
EoF

# enable db-sync service
if [ -n "${DBSYNC_SCHEMA_DIR:-""}" ]; then
  command -v cardano-db-sync > /dev/null 2>&1 || \
    { echo "The \`cardano-db-sync\` binary not found, line $LINENO" >&2; exit 1; }  # assert

  # create clean database
  if [ -z "${DRY_RUN:-""}" ]; then
    "${SCRIPT_DIR}/postgres-setup.sh"
  fi

  cp "${SCRIPT_DIR}/run-cardano-dbsync" "$STATE_CLUSTER"

  cat >> "${STATE_CLUSTER}/supervisor.conf" <<EoF

[program:dbsync]
command=./${STATE_CLUSTER_NAME}/run-cardano-dbsync
stderr_logfile=./${STATE_CLUSTER_NAME}/dbsync.stderr
stdout_logfile=./${STATE_CLUSTER_NAME}/dbsync.stdout
autostart=false
autorestart=false
startsecs=5
EoF
fi

# enable smash service
if [ -n "${DBSYNC_SCHEMA_DIR:-""}" ] && [ -n "${SMASH:-""}" ]; then
  command -v cardano-smash-server > /dev/null 2>&1 || \
    { echo "The \`cardano-smash-server\` binary not found, line $LINENO" >&2; exit 1; }  # assert

  cp "${SCRIPT_DIR}/run-cardano-smash" "$STATE_CLUSTER"

  cat >> "${STATE_CLUSTER}/supervisor.conf" <<EoF

[program:smash]
command=./${STATE_CLUSTER_NAME}/run-cardano-smash
stderr_logfile=./${STATE_CLUSTER_NAME}/smash.stderr
stdout_logfile=./${STATE_CLUSTER_NAME}/smash.stdout
autostart=false
autorestart=false
startsecs=5
EoF
fi

# enable cardano-submit-api service
if [ "$ENABLE_SUBMIT_API" -eq 1 ]; then
  cp "${SCRIPT_DIR}/run-cardano-submit-api" "$STATE_CLUSTER"

  cat >> "${STATE_CLUSTER}/supervisor.conf" <<EoF

[program:submit_api]
command=./${STATE_CLUSTER_NAME}/run-cardano-submit-api
stderr_logfile=./${STATE_CLUSTER_NAME}/submit_api.stderr
stdout_logfile=./${STATE_CLUSTER_NAME}/submit_api.stdout
autostart=false
autorestart=false
startsecs=5
EoF
fi

START_TIME_SHELLEY="$(date --utc +"%Y-%m-%dT%H:%M:%SZ" --date="5 seconds")"
START_TIME="$(date +%s --date="$START_TIME_SHELLEY")"
echo "$START_TIME" > "${STATE_CLUSTER}/cluster_start_time"

cardano_cli_log byron genesis genesis \
  --protocol-magic "$NETWORK_MAGIC" \
  --k "$SECURITY_PARAM" \
  --n-poor-addresses 0 \
  --n-delegate-addresses "$NUM_POOLS" \
  --total-balance "$BYRON_INIT_SUPPLY" \
  --delegate-share 1 \
  --avvm-entry-count 0 \
  --avvm-entry-balance 0 \
  --protocol-parameters-file "${STATE_CLUSTER}/byron-params.json" \
  --genesis-output-dir "${STATE_CLUSTER}/byron" \
  --start-time "$START_TIME"

mv "${STATE_CLUSTER}/byron-params.json" "${STATE_CLUSTER}/byron/params.json"

cardano_cli_log latest genesis create-staked \
  --genesis-dir "${STATE_CLUSTER}/create_staked" \
  --testnet-magic "$NETWORK_MAGIC" \
  --gen-pools "$NUM_POOLS" \
  --gen-utxo-keys 1 \
  --supply "$NONDELEG_SUPPLY" \
  --gen-stake-delegs "$NUM_POOLS" \
  --supply-delegated "$DELEG_SUPPLY" \
  --start-time "$START_TIME_SHELLEY"

# Create committee keys
if [ -z "${NO_CC:-""}" ]; then
  for i in $(seq 1 "$NUM_CC"); do
    cardano_cli_log conway governance committee key-gen-cold \
      --cold-verification-key-file "${STATE_CLUSTER}/governance_data/cc_member${i}_committee_cold.vkey" \
      --cold-signing-key-file "${STATE_CLUSTER}/governance_data/cc_member${i}_committee_cold.skey"
    cardano_cli_log conway governance committee key-gen-hot \
      --verification-key-file "${STATE_CLUSTER}/governance_data/cc_member${i}_committee_hot.vkey" \
      --signing-key-file "${STATE_CLUSTER}/governance_data/cc_member${i}_committee_hot.skey"
    cardano_cli_log conway governance committee create-hot-key-authorization-certificate \
      --cold-verification-key-file "${STATE_CLUSTER}/governance_data/cc_member${i}_committee_cold.vkey" \
      --hot-verification-key-file "${STATE_CLUSTER}/governance_data/cc_member${i}_committee_hot.vkey" \
      --out-file "${STATE_CLUSTER}/governance_data/cc_member${i}_committee_hot_auth.cert"
    cardano_cli_log conway governance committee key-hash \
      --verification-key-file "${STATE_CLUSTER}/governance_data/cc_member${i}_committee_cold.vkey" \
      > "${STATE_CLUSTER}/governance_data/cc_member${i}_committee_cold.hash"
  done

  # Pre-register committee in genesis
  KEY_HASH_JSON="$(jq -nR '[inputs | {("keyHash-" + .): 10000}] | add' \
    "$STATE_CLUSTER"/governance_data/cc_member*_committee_cold.hash)"
  jq \
    --argjson keyHashJson "$KEY_HASH_JSON" \
    '.committee.members = $keyHashJson
    | .committee.threshold = 0.6
    | .committeeMinSize = 2' \
    "${STATE_CLUSTER}/create_staked/genesis.conway.json" > "${STATE_CLUSTER}/create_staked/genesis.conway.json_jq"
  cat "${STATE_CLUSTER}/create_staked/genesis.conway.json_jq" > "${STATE_CLUSTER}/create_staked/genesis.conway.json"
  rm -f "${STATE_CLUSTER}/create_staked/genesis.conway.json_jq"
fi

mv "${STATE_CLUSTER}/create_staked/delegate-keys" "${STATE_CLUSTER}/shelley/delegate-keys"
mv "${STATE_CLUSTER}/create_staked/genesis-keys" "${STATE_CLUSTER}/shelley/genesis-keys"
jq \
  --argjson max_supply "$MAX_SUPPLY" \
  --argjson prot_ver "$PROTOCOL_VERSION" \
  '.protocolParams.protocolVersion.major = $prot_ver
  | .maxLovelaceSupply = $max_supply' \
  "${STATE_CLUSTER}/create_staked/genesis.json" > "${STATE_CLUSTER}/shelley/genesis.json"
rm -f "${STATE_CLUSTER}/create_staked/genesis.json"
mv "$STATE_CLUSTER"/create_staked/genesis*.json "${STATE_CLUSTER}/shelley/"

mv "${STATE_CLUSTER}/create_staked/utxo-keys/utxo1.skey" "${STATE_CLUSTER}/shelley/genesis-utxo.skey"
mv "${STATE_CLUSTER}/create_staked/utxo-keys/utxo1.vkey" "${STATE_CLUSTER}/shelley/genesis-utxo.vkey"
cardano_cli_log conway address build --payment-verification-key-file \
  "${STATE_CLUSTER}/shelley/genesis-utxo.vkey" \
  --out-file "${STATE_CLUSTER}/shelley/genesis-utxo.addr" \
  --testnet-magic "$NETWORK_MAGIC"

mv "${STATE_CLUSTER}/create_staked/stake-delegator-keys" "${STATE_CLUSTER}/shelley/stake-delegator-keys"

KEY_DEPOSIT="$(jq '.protocolParams.keyDeposit' \
  < "${STATE_CLUSTER}/shelley/genesis.json")"
DREP_DEPOSIT="$(jq '.dRepDeposit' \
  < "${STATE_CLUSTER}/shelley/genesis.conway.json")"

BYRON_GENESIS_HASH="$(cardano_cli_log byron genesis print-genesis-hash --genesis-json \
  "${STATE_CLUSTER}/byron/genesis.json")"
SHELLEY_GENESIS_HASH="$(cardano_cli_log latest genesis hash --genesis \
  "${STATE_CLUSTER}/shelley/genesis.json")"
ALONZO_GENESIS_HASH="$(cardano_cli_log latest genesis hash --genesis \
  "${STATE_CLUSTER}/shelley/genesis.alonzo.json")"
CONWAY_GENESIS_HASH="$(cardano_cli_log latest genesis hash --genesis \
  "${STATE_CLUSTER}/shelley/genesis.conway.json")"

for conf in "$SCRIPT_DIR"/config-*.json; do
  fname="${conf##*/}"
  node_name="${fname##config-}"
  node_name="${node_name%.json}"

  jq \
    --arg byron_hash "$BYRON_GENESIS_HASH" \
    --arg shelley_hash "$SHELLEY_GENESIS_HASH" \
    --arg alonzo_hash "$ALONZO_GENESIS_HASH" \
    --arg conway_hash "$CONWAY_GENESIS_HASH" \
    --argjson prot_ver "$PROTOCOL_VERSION" \
    --arg backend "$UTXO_BACKEND" \
    --arg live_tables_path "${LIVE_TABLES_BASE}-${node_name}" \
    '.ByronGenesisHash = $byron_hash
    | .ShelleyGenesisHash = $shelley_hash
    | .AlonzoGenesisHash = $alonzo_hash
    | .ConwayGenesisHash = $conway_hash
    | ."LastKnownBlockVersion-Major" = $prot_ver
    | if $backend == "mem" then
        .LedgerDB.Backend = "V2InMemory"
      elif $backend == "disk" then
        (.LedgerDB.Backend = "V1LMDB"
         | .LedgerDB.LiveTablesPath = $live_tables_path)
      elif has("LedgerDB") then
        .LedgerDB |= del(.Backend)
      else
        .
      end
    | if (.LedgerDB? // {}) == {} then del(.LedgerDB) else . end
    ' "$conf" > "${STATE_CLUSTER}/${fname}"

  # enable P2P
  if [ -z "${ENABLE_LEGACY:-""}" ]; then

    # setup mix of P2P and legacy
    if [ -n "${MIXED_P2P:-""}" ]; then
      if [ "$fname" = "config-bft1.json" ]; then
        # use legacy topology file for bft1
        cp -f "$SCRIPT_DIR"/topology-bft1.json "$STATE_CLUSTER"
        continue
      fi

      # use legacy topology files for odd numbered pools
      pool_num="${fname##*-pool}"
      pool_num="${pool_num%.json}"
      if [ "$((pool_num % 2))" != 0 ]; then
        cp -f "${SCRIPT_DIR}/topology-pool${pool_num}.json" "$STATE_CLUSTER"
        continue
      fi
    fi

    jq \
      '.EnableP2P = true
      | .MaxConcurrencyBulkSync = 2
      | .MaxConcurrencyDeadline = 4
      | .TargetNumberOfRootPeers = 100
      | .TargetNumberOfKnownPeers = 100
      | .TargetNumberOfEstablishedPeers = 50
      | .TargetNumberOfActivePeers = 20
      | .TraceBlockFetchClient = true
      | .TraceChainSyncClient = true' \
      "${STATE_CLUSTER}/${fname}" > "${STATE_CLUSTER}/${fname}_jq"
    cat "${STATE_CLUSTER}/${fname}_jq" > "${STATE_CLUSTER}/${fname}"
    rm -f "${STATE_CLUSTER}/${fname}_jq"
  fi
done

for i in $(seq 1 "$NUM_BFT_NODES"); do
  mkdir -p "${STATE_CLUSTER}/nodes/node-bft$i"
  BFT_PORT="$(("%%NODE_PORT_BASE%%" + (i - 1) * "%%PORTS_PER_NODE%%" ))"
  echo "$BFT_PORT" > "${STATE_CLUSTER}/nodes/node-bft${i}/port"
done

for i in $(seq 1 "$NUM_POOLS"); do
  mkdir -p "${STATE_CLUSTER}/nodes/node-pool$i"
  mv "${STATE_CLUSTER}/create_staked/pools/cold${i}.skey" "${STATE_CLUSTER}/nodes/node-pool${i}/cold.skey"
  mv "${STATE_CLUSTER}/create_staked/pools/cold${i}.vkey" "${STATE_CLUSTER}/nodes/node-pool${i}/cold.vkey"

  mv "${STATE_CLUSTER}/create_staked/pools/kes${i}.skey" "${STATE_CLUSTER}/nodes/node-pool${i}/kes.skey"
  mv "${STATE_CLUSTER}/create_staked/pools/kes${i}.vkey" "${STATE_CLUSTER}/nodes/node-pool${i}/kes.vkey"

  mv "${STATE_CLUSTER}/create_staked/pools/opcert${i}.cert" "${STATE_CLUSTER}/nodes/node-pool${i}/op.cert"
  mv "${STATE_CLUSTER}/create_staked/pools/opcert${i}.counter" "${STATE_CLUSTER}/nodes/node-pool${i}/cold.counter"

  # stake reward keys
  mv "${STATE_CLUSTER}/create_staked/pools/staking-reward${i}.skey" "${STATE_CLUSTER}/nodes/node-pool${i}/reward.skey"
  mv "${STATE_CLUSTER}/create_staked/pools/staking-reward${i}.vkey" "${STATE_CLUSTER}/nodes/node-pool${i}/reward.vkey"

  mv "${STATE_CLUSTER}/create_staked/pools/vrf${i}.skey" "${STATE_CLUSTER}/nodes/node-pool${i}/vrf.skey"
  mv "${STATE_CLUSTER}/create_staked/pools/vrf${i}.vkey" "${STATE_CLUSTER}/nodes/node-pool${i}/vrf.vkey"

  echo "Generating Pool $i Secrets"

  # pool owner addresses and keys
  cardano_cli_log conway address key-gen \
    --signing-key-file "${STATE_CLUSTER}/nodes/node-pool${i}/owner-utxo.skey" \
    --verification-key-file "${STATE_CLUSTER}/nodes/node-pool${i}/owner-utxo.vkey"
  cardano_cli_log conway stake-address key-gen \
    --signing-key-file "${STATE_CLUSTER}/nodes/node-pool${i}/owner-stake.skey" \
    --verification-key-file "${STATE_CLUSTER}/nodes/node-pool${i}/owner-stake.vkey"

  #   payment address
  cardano_cli_log conway address build \
    --payment-verification-key-file "${STATE_CLUSTER}/nodes/node-pool${i}/owner-utxo.vkey" \
    --stake-verification-key-file "${STATE_CLUSTER}/nodes/node-pool${i}/owner-stake.vkey" \
    --testnet-magic "$NETWORK_MAGIC" \
    --out-file "${STATE_CLUSTER}/nodes/node-pool${i}/owner.addr"

  #   stake address
  cardano_cli_log conway stake-address build \
    --stake-verification-key-file "${STATE_CLUSTER}/nodes/node-pool${i}/owner-stake.vkey" \
    --testnet-magic "$NETWORK_MAGIC" \
    --out-file "${STATE_CLUSTER}/nodes/node-pool${i}/owner-stake.addr"

  #   stake address registration cert
  cardano_cli_log conway stake-address registration-certificate \
    --stake-verification-key-file "${STATE_CLUSTER}/nodes/node-pool${i}/owner-stake.vkey" \
    --key-reg-deposit-amt "$KEY_DEPOSIT" \
    --out-file "${STATE_CLUSTER}/nodes/node-pool${i}/stake.reg.cert"

  if [ -n "${PV9:-""}" ]; then
    # stake reward address registration cert
    cardano_cli_log conway stake-address registration-certificate \
      --stake-verification-key-file "${STATE_CLUSTER}/nodes/node-pool${i}/reward.vkey" \
      --key-reg-deposit-amt "$KEY_DEPOSIT" \
      --out-file "${STATE_CLUSTER}/nodes/node-pool${i}/stake-reward.reg.cert"

    # owner stake address stake delegation cert
    cardano_cli_log conway stake-address stake-delegation-certificate \
      --stake-verification-key-file "${STATE_CLUSTER}/nodes/node-pool${i}/owner-stake.vkey" \
      --cold-verification-key-file  "${STATE_CLUSTER}/nodes/node-pool${i}/cold.vkey" \
      --out-file "${STATE_CLUSTER}/nodes/node-pool${i}/owner-stake.deleg.cert"
  else
    # stake reward address registration and vote delegation cert
    cardano_cli_log conway stake-address registration-and-vote-delegation-certificate \
      --stake-verification-key-file "${STATE_CLUSTER}/nodes/node-pool${i}/reward.vkey" \
      --always-abstain \
      --key-reg-deposit-amt "$KEY_DEPOSIT" \
      --out-file "${STATE_CLUSTER}/nodes/node-pool${i}/stake-reward.reg.cert"

    # owner stake address stake and vote delegation cert
    cardano_cli_log conway stake-address stake-and-vote-delegation-certificate \
      --stake-verification-key-file "${STATE_CLUSTER}/nodes/node-pool${i}/owner-stake.vkey" \
      --cold-verification-key-file  "${STATE_CLUSTER}/nodes/node-pool${i}/cold.vkey" \
      --always-abstain \
      --out-file "${STATE_CLUSTER}/nodes/node-pool${i}/owner-stake.deleg.cert"
  fi

  POOL_NAME="TestPool${i}"
  POOL_DESC="Test Pool $i"
  POOL_TICKER="TP${i}"

  cat > "${STATE_CLUSTER}/webserver/pool${i}.html" <<EoF
<!DOCTYPE html>
<html>
<head>
<title>${POOL_NAME}</title>
</head>
<body>
name: <strong>${POOL_NAME}</strong><br>
description: <strong>${POOL_DESC}</strong><br>
ticker: <strong>${POOL_TICKER}</strong><br>
</body>
</html>
EoF

  echo "Generating Pool $i Metadata"
  jq -n \
    --arg name "$POOL_NAME" \
    --arg description "$POOL_DESC" \
    --arg ticker "$POOL_TICKER" \
    --arg homepage "http://localhost:%%WEBSERVER_PORT%%/pool${i}.html" \
    '{"name": $name, "description": $description, "ticker": $ticker, "homepage": $homepage}' \
    > "${STATE_CLUSTER}/webserver/pool${i}.json"

  METADATA_URL="http://localhost:%%WEBSERVER_PORT%%/pool${i}.json"
  METADATA_HASH="$(cardano_cli_log conway stake-pool metadata-hash --pool-metadata-file \
    "${STATE_CLUSTER}/webserver/pool${i}.json")"
  POOL_PORT="$(("%%NODE_PORT_BASE%%" + (NUM_BFT_NODES + i - 1) * "%%PORTS_PER_NODE%%"))"
  echo "$POOL_PORT" > "${STATE_CLUSTER}/nodes/node-pool${i}/port"
  echo "$POOL_PLEDGE" > "${STATE_CLUSTER}/nodes/node-pool${i}/pledge"

  cardano_cli_log conway stake-pool registration-certificate \
    --cold-verification-key-file "${STATE_CLUSTER}/nodes/node-pool${i}/cold.vkey" \
    --vrf-verification-key-file "${STATE_CLUSTER}/nodes/node-pool${i}/vrf.vkey" \
    --pool-pledge "$POOL_PLEDGE" \
    --pool-margin 0.35 \
    --pool-cost "$POOL_COST" \
    --pool-reward-account-verification-key-file "${STATE_CLUSTER}/nodes/node-pool${i}/reward.vkey" \
    --pool-owner-stake-verification-key-file "${STATE_CLUSTER}/nodes/node-pool${i}/owner-stake.vkey" \
    --metadata-url "$METADATA_URL" \
    --metadata-hash "$METADATA_HASH" \
    --pool-relay-port "$POOL_PORT" \
    --pool-relay-ipv4 "127.0.0.1" \
    --testnet-magic "$NETWORK_MAGIC" \
    --out-file "${STATE_CLUSTER}/nodes/node-pool${i}/register.cert"
done

rm -rf "${STATE_CLUSTER}/create_staked"

for i in $(seq 1 "$NUM_DREPS"); do
  # DRep keys
  cardano_cli_log conway governance drep key-gen \
    --signing-key-file "${STATE_CLUSTER}/governance_data/default_drep_${i}_drep.skey" \
    --verification-key-file "${STATE_CLUSTER}/governance_data/default_drep_${i}_drep.vkey"

  # DRep registration
  cardano_cli_log conway governance drep registration-certificate \
    --drep-verification-key-file "${STATE_CLUSTER}/governance_data/default_drep_${i}_drep.vkey" \
    --key-reg-deposit-amt "$DREP_DEPOSIT" \
    --out-file "${STATE_CLUSTER}/governance_data/default_drep_${i}_drep_reg.cert"

  # delegatee payment keys
  cardano_cli_log conway address key-gen \
    --signing-key-file "${STATE_CLUSTER}/governance_data/vote_stake_addr${i}.skey" \
    --verification-key-file "${STATE_CLUSTER}/governance_data/vote_stake_addr${i}.vkey"

  # delegatee stake keys
  cardano_cli_log conway stake-address key-gen \
    --signing-key-file "${STATE_CLUSTER}/governance_data/vote_stake_addr${i}_stake.skey" \
    --verification-key-file "${STATE_CLUSTER}/governance_data/vote_stake_addr${i}_stake.vkey"

  # delegatee payment address
  cardano_cli_log conway address build \
    --payment-verification-key-file "${STATE_CLUSTER}/governance_data/vote_stake_addr${i}.vkey" \
    --stake-verification-key-file "${STATE_CLUSTER}/governance_data/vote_stake_addr${i}_stake.vkey" \
    --testnet-magic "$NETWORK_MAGIC" \
    --out-file "${STATE_CLUSTER}/governance_data/vote_stake_addr${i}.addr"

  # delegatee stake address
  cardano_cli_log conway stake-address build \
    --stake-verification-key-file "${STATE_CLUSTER}/governance_data/vote_stake_addr${i}_stake.vkey" \
    --testnet-magic "$NETWORK_MAGIC" \
    --out-file "${STATE_CLUSTER}/governance_data/vote_stake_addr${i}_stake.addr"

  # delegatee stake address registration cert
  cardano_cli_log conway stake-address registration-certificate \
    --stake-verification-key-file "${STATE_CLUSTER}/governance_data/vote_stake_addr${i}_stake.vkey" \
    --key-reg-deposit-amt "$KEY_DEPOSIT" \
    --out-file "${STATE_CLUSTER}/governance_data/vote_stake_addr${i}_stake.reg.cert"

  # delegatee vote delegation cert
  cardano_cli_log conway stake-address vote-delegation-certificate \
    --stake-verification-key-file "${STATE_CLUSTER}/governance_data/vote_stake_addr${i}_stake.vkey" \
    --drep-verification-key-file "${STATE_CLUSTER}/governance_data/default_drep_${i}_drep.vkey" \
    --out-file "${STATE_CLUSTER}/governance_data/vote_stake_addr${i}_stake.vote_deleg.cert"
done

# create scripts for cluster starting / stopping
printf "#!/bin/sh\n\nsupervisorctl -s unix:///%s start all" "$SUPERVISORD_SOCKET_PATH" > "${STATE_CLUSTER}/supervisorctl_start"
printf "#!/bin/sh\n\nsupervisorctl -s unix:///%s restart nodes:" "$SUPERVISORD_SOCKET_PATH" > "${STATE_CLUSTER}/supervisorctl_restart_nodes"
printf "#!/bin/sh\n\nsupervisorctl -s unix:///%s \"\$@\"" "$SUPERVISORD_SOCKET_PATH" > "${STATE_CLUSTER}/supervisorctl"

cat > "${STATE_CLUSTER}/supervisord_start" <<EoF
#!/usr/bin/env bash

set -uo pipefail

SCRIPT_DIR="\$(readlink -m "\${0%/*}")"

cd "\${SCRIPT_DIR}/.."

supervisord --config "\${SCRIPT_DIR}/supervisor.conf"
EoF

cat > "${STATE_CLUSTER}/stop-cluster" <<EoF
#!/usr/bin/env bash

set -uo pipefail

SCRIPT_DIR="\$(readlink -m "\${0%/*}")"
PID_FILE="\${SCRIPT_DIR}/supervisord.pid"
SUPERVISORD_SOCKET_PATH="${SUPERVISORD_SOCKET_PATH}"

if [ -e "\$SUPERVISORD_SOCKET_PATH" ]; then
  supervisorctl -s unix:///\${SUPERVISORD_SOCKET_PATH} stop all || rm -f "\$SUPERVISORD_SOCKET_PATH"
fi

if [ ! -f "\$PID_FILE" ]; then
  echo "Cluster is not running!"
  exit 0
fi

PID="\$(<"\$PID_FILE")"
for _ in {1..5}; do
  if ! kill "\$PID"; then
    break
  fi
  sleep 1
  if [ ! -f "\$PID_FILE" ]; then
    break
  fi
done

rm -f "\$PID_FILE"
echo "Cluster terminated!"
EoF

chmod u+x "$STATE_CLUSTER"/{supervisorctl*,supervisord_*,stop-cluster}

if [ -n "${DRY_RUN:-""}" ]; then
  echo "Dry run, not starting cluster"
  exit 0
fi

supervisord --config "${STATE_CLUSTER}/supervisor.conf"

for _ in {1..5}; do
  if [ -S "$CARDANO_NODE_SOCKET_PATH" ]; then
    break
  fi
  echo "Waiting 5 seconds for the nodes to start"
  sleep 5
done
[ -S "$CARDANO_NODE_SOCKET_PATH" ] || { echo "Failed to start the nodes, line $LINENO" >&2; exit 1; }  # assert


#
# In Conway era
#


# start db-sync
if [ -n "${DBSYNC_SCHEMA_DIR:-""}" ]; then
  echo "Starting db-sync"
  supervisorctl -s "unix:///${SUPERVISORD_SOCKET_PATH}" start dbsync
fi

# start smash
if [ -n "${DBSYNC_SCHEMA_DIR:-""}" ] && [ -n "${SMASH:-""}" ]; then
  echo "Starting smash"
  supervisorctl -s "unix:///${SUPERVISORD_SOCKET_PATH}" start smash
fi

echo "Sleeping for initial Tx submission delay of $TX_SUBMISSION_DELAY seconds"
sleep "$TX_SUBMISSION_DELAY"

echo "Re-registering pools, creating CC members and DReps"

GENESIS_SIGNING=()
for skey in "$STATE_CLUSTER"/shelley/genesis-keys/genesis?.skey; do
  GENESIS_SIGNING+=("--signing-key-file" "$skey")
done

DELEGATE_SIGNING=()
for skey in "$STATE_CLUSTER"/shelley/delegate-keys/delegate?.skey; do
  DELEGATE_SIGNING+=("--signing-key-file" "$skey")
done

# Transfer funds, register stake addresses and pools, CC members, DReps, all in one big transaction:

DEPOSIT_FOR_POOLS="$((KEY_DEPOSIT * 2))"
NEEDED_AMOUNT_POOLS="$(( (POOL_PLEDGE + DEPOSIT_FOR_POOLS) * NUM_POOLS ))"
DEPOSIT_FOR_DREPS="$((KEY_DEPOSIT + DREP_DEPOSIT))"
NEEDED_AMOUNT_DREPS="$(( (DREP_DELEGATED + DEPOSIT_FOR_DREPS) * NUM_DREPS ))"
NEEDED_AMOUNT="$((NEEDED_AMOUNT_POOLS + NEEDED_AMOUNT_DREPS))"

FEE_BUFFER=100000000
TXIN_ADDR="$(<"$STATE_CLUSTER"/shelley/genesis-utxo.addr)"
STOP_TXIN_AMOUNT="$((NEEDED_AMOUNT + FEE_BUFFER))"

get_txins "$TXIN_ADDR" "$STOP_TXIN_AMOUNT"

POOL_ARGS=()
POOL_SIGNING=()
for i in $(seq 1 "$NUM_POOLS"); do
  POOL_ARGS+=( \
    "--tx-out" "$(<"${STATE_CLUSTER}/nodes/node-pool${i}/owner.addr")+${POOL_PLEDGE}" \
    "--certificate-file" "${STATE_CLUSTER}/nodes/node-pool${i}/stake.reg.cert" \
    "--certificate-file" "${STATE_CLUSTER}/nodes/node-pool${i}/stake-reward.reg.cert" \
    "--certificate-file" "${STATE_CLUSTER}/nodes/node-pool${i}/register.cert" \
    "--certificate-file" "${STATE_CLUSTER}/nodes/node-pool${i}/owner-stake.deleg.cert" \
  )
  POOL_SIGNING+=( \
    "--signing-key-file" "${STATE_CLUSTER}/nodes/node-pool${i}/owner-stake.skey" \
    "--signing-key-file" "${STATE_CLUSTER}/nodes/node-pool${i}/reward.skey" \
    "--signing-key-file" "${STATE_CLUSTER}/nodes/node-pool${i}/cold.skey" \
  )
done

CC_ARGS=()
for f in "$STATE_CLUSTER"/governance_data/cc_member*_committee_hot_auth.cert; do
  [ -e "$f" ] || continue
  CC_ARGS+=( "--certificate-file" "$f" )
done

CC_SIGNING=()
for f in "$STATE_CLUSTER"/governance_data/cc_member*_committee_cold.skey; do
  [ -e "$f" ] || continue
  CC_SIGNING+=( "--signing-key-file" "$f" )
done

DREPS_ARGS=()
DREPS_SIGNING=()
for i in $(seq 1 "$NUM_DREPS"); do
  DREPS_ARGS+=( \
    "--tx-out" "$(<"${STATE_CLUSTER}/governance_data/vote_stake_addr${i}.addr")+${DREP_DELEGATED}" \
    "--certificate-file" "${STATE_CLUSTER}/governance_data/default_drep_${i}_drep_reg.cert" \
    "--certificate-file" "${STATE_CLUSTER}/governance_data/vote_stake_addr${i}_stake.reg.cert" \
    "--certificate-file" "${STATE_CLUSTER}/governance_data/vote_stake_addr${i}_stake.vote_deleg.cert" \
  )
  DREPS_SIGNING+=( \
    "--signing-key-file" "${STATE_CLUSTER}/governance_data/default_drep_${i}_drep.skey" \
    "--signing-key-file" "${STATE_CLUSTER}/governance_data/vote_stake_addr${i}.skey" \
    "--signing-key-file" "${STATE_CLUSTER}/governance_data/vote_stake_addr${i}_stake.skey" \
  )
done

WITNESS_COUNT="$((${#POOL_SIGNING[@]} + ${#GENESIS_SIGNING[@]} + ${#DELEGATE_SIGNING[@]} + ${#CC_SIGNING[@]} + ${#DREPS_SIGNING[@]} + 1))"

cardano_cli_log conway transaction build \
  "${TXINS[@]}" \
  --change-address   "$TXIN_ADDR" \
  "${POOL_ARGS[@]}" \
  "${CC_ARGS[@]}" \
  "${DREPS_ARGS[@]}" \
  --witness-override "$WITNESS_COUNT" \
  --testnet-magic    "$NETWORK_MAGIC" \
  --out-file         "${STATE_CLUSTER}/shelley/transfer-register-delegate-tx.txbody"

cardano_cli_log conway transaction sign \
  "${POOL_SIGNING[@]}" \
  "${GENESIS_SIGNING[@]}" \
  "${DELEGATE_SIGNING[@]}" \
  "${CC_SIGNING[@]}" \
  "${DREPS_SIGNING[@]}" \
  --signing-key-file "${STATE_CLUSTER}/shelley/genesis-utxo.skey" \
  --testnet-magic    "$NETWORK_MAGIC" \
  --tx-body-file     "${STATE_CLUSTER}/shelley/transfer-register-delegate-tx.txbody" \
  --out-file         "${STATE_CLUSTER}/shelley/transfer-register-delegate-tx.tx"

cardano_cli_log conway transaction submit \
  --tx-file "${STATE_CLUSTER}/shelley/transfer-register-delegate-tx.tx" \
  --testnet-magic "$NETWORK_MAGIC"

# start cardano-submit-api
if [ "$ENABLE_SUBMIT_API" -eq 1 ]; then
  echo "Starting cardano-submit-api"
  supervisorctl -s "unix:///${SUPERVISORD_SOCKET_PATH}" start submit_api
fi

sleep "$SUBMIT_DELAY"
if ! check_spend_success "${TXINS[@]}"; then
  echo "Failed to spend Tx inputs, line $LINENO" >&2  # assert
  exit 1
fi

: > "$START_CLUSTER_STATUS"
echo "Cluster started 🚀"
