#!/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"
# shellcheck disable=SC2034
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
PROPOSAL_DELAY=5
SUBMIT_DELAY=5
POOL_PLEDGE=1000000000000
DREP_DELEGATED=500000000000

FEE=5000000

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")"
# shellcheck disable=SC2034
SLOT_LENGTH="$(jq '.slotLength' < "${SCRIPT_DIR}/genesis.spec.json")"
# shellcheck disable=SC2034
EPOCH_SEC="$(jq '.epochLength * .slotLength | ceil' < "${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

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)"

# shellcheck disable=SC1091
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,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}/shelley/"

if [ -n "${PV9:-""}" ]; then
  cp -f \
    "${SCRIPT_DIR}/genesis.conway.spec.pv9.json" \
    "${STATE_CLUSTER}/shelley/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

FUNDS_PER_GENESIS_ADDRESS="$((MAX_SUPPLY / NUM_BFT_NODES))"
FUNDS_PER_BYRON_ADDRESS="$((FUNDS_PER_GENESIS_ADDRESS * 8 / 10))"

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_BFT_NODES" \
  --total-balance "$MAX_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"

# We need to use the "legacy" command here. With the "latest" command, Alonzo genesis
# would have 185 entries for PlutusV2 cost model instead of the expected 175 entries.
cardano_cli_log legacy genesis create \
  --genesis-dir "${STATE_CLUSTER}/shelley" \
  --testnet-magic "$NETWORK_MAGIC" \
  --gen-genesis-keys "$NUM_BFT_NODES" \
  --start-time "$START_TIME_SHELLEY" \
  --gen-utxo-keys 1

jq -r '
  .initialFunds = {}' \
  < "${STATE_CLUSTER}/shelley/genesis.json" > "${STATE_CLUSTER}/shelley/genesis.json_jq"
cat "${STATE_CLUSTER}/shelley/genesis.json_jq" > "${STATE_CLUSTER}/shelley/genesis.json"
rm -f "${STATE_CLUSTER}/shelley/genesis.json_jq"

# 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}/shelley/genesis.conway.json" > "${STATE_CLUSTER}/shelley/genesis.conway.json_jq"
  cat "${STATE_CLUSTER}/shelley/genesis.conway.json_jq" > "${STATE_CLUSTER}/shelley/genesis.conway.json"
  rm -f "${STATE_CLUSTER}/shelley/genesis.conway.json_jq"
fi

KEY_DEPOSIT="$(jq '.protocolParams.keyDeposit' \
  < "${STATE_CLUSTER}/shelley/genesis.json")"
POOL_DEPOSIT="$(jq '.protocolParams.poolDeposit' \
  < "${STATE_CLUSTER}/shelley/genesis.json")"
DREP_DEPOSIT="$(jq '.dRepDeposit' \
  < "${STATE_CLUSTER}/shelley/genesis.conway.json")"
GOV_ACTION_DEPOSIT="$(jq '.govActionDeposit' \
  < "${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" \
    --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
    | 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
      | .ExperimentalProtocolsEnabled = true
      | .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"
  ln -s "../../shelley/delegate-keys/delegate${i}.vrf.skey" "${STATE_CLUSTER}/nodes/node-bft${i}/vrf.skey"
  ln -s "../../shelley/delegate-keys/delegate${i}.vrf.vkey" "${STATE_CLUSTER}/nodes/node-bft${i}/vrf.vkey"

  cardano_cli_log latest node key-gen-KES \
    --verification-key-file "${STATE_CLUSTER}/nodes/node-bft${i}/kes.vkey" \
    --signing-key-file "${STATE_CLUSTER}/nodes/node-bft${i}/kes.skey"

  cardano_cli_log latest node issue-op-cert \
    --kes-period 0 \
    --cold-signing-key-file "${STATE_CLUSTER}/shelley/delegate-keys/delegate${i}.skey" \
    --kes-verification-key-file "${STATE_CLUSTER}/nodes/node-bft${i}/kes.vkey" \
    --operational-certificate-issue-counter-file \
      "${STATE_CLUSTER}/shelley/delegate-keys/delegate${i}.counter" \
    --out-file "${STATE_CLUSTER}/nodes/node-bft${i}/op.cert"

  INDEX="$(printf "%03d" $((i - 1)))"

  cardano_cli_log byron key keygen \
    --secret "${STATE_CLUSTER}/byron/payment-keys.${INDEX}.key"

  cardano_cli_log byron key signing-key-address \
    --byron-formats \
    --testnet-magic "$NETWORK_MAGIC" \
    --secret "${STATE_CLUSTER}/byron/payment-keys.${INDEX}.key" > "${STATE_CLUSTER}/byron/address-${INDEX}"

  # write Genesis addresses to files
  cardano_cli_log byron key signing-key-address \
    --byron-formats  \
    --testnet-magic "$NETWORK_MAGIC" \
    --secret "${STATE_CLUSTER}/byron/genesis-keys.${INDEX}.key" \
      > "${STATE_CLUSTER}/byron/genesis-address-${INDEX}"

  ln -s "../../byron/delegate-keys.${INDEX}.key" "${STATE_CLUSTER}/nodes/node-bft${i}/byron-deleg.key"
  ln -s "../../byron/delegation-cert.${INDEX}.json" "${STATE_CLUSTER}/nodes/node-bft${i}/byron-deleg.json"

  # create Byron address that moves funds out of the genesis UTxO into a regular address
  cardano_cli_log byron transaction issue-genesis-utxo-expenditure \
    --genesis-json "${STATE_CLUSTER}/byron/genesis.json" \
    --testnet-magic "$NETWORK_MAGIC" \
    --byron-formats \
    --tx "${STATE_CLUSTER}/byron/tx${i}.tx" \
    --wallet-key "${STATE_CLUSTER}/nodes/node-bft${i}/byron-deleg.key" \
    --rich-addr-from "$(head -n 1 "${STATE_CLUSTER}/byron/genesis-address-${INDEX}")" \
    --txout "(\"$(head -n 1 "${STATE_CLUSTER}/byron/address-${INDEX}")\", ${FUNDS_PER_BYRON_ADDRESS})"

  # convert to Shelley addresses and keys
  cardano_cli_log latest key convert-byron-key \
    --byron-signing-key-file "${STATE_CLUSTER}/byron/payment-keys.${INDEX}.key" \
    --out-file "${STATE_CLUSTER}/byron/payment-keys.${INDEX}-converted.skey" \
    --byron-payment-key-type

  cardano_cli_log latest key verification-key \
    --signing-key-file "${STATE_CLUSTER}/byron/payment-keys.${INDEX}-converted.skey" \
    --verification-key-file "${STATE_CLUSTER}/byron/payment-keys.${INDEX}-converted.vkey"

  cardano_cli_log latest address build \
    --testnet-magic "$NETWORK_MAGIC" \
    --payment-verification-key-file "${STATE_CLUSTER}/byron/payment-keys.${INDEX}-converted.vkey" \
    > "${STATE_CLUSTER}/byron/address-${INDEX}-converted"

  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"
  echo "Generating Pool $i Secrets"

  # pool owner addresses and keys
  cardano_cli_log latest 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 latest 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 latest 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 latest 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 for Shelley era
  cardano_cli_log compatible shelley stake-address registration-certificate \
    --stake-verification-key-file "${STATE_CLUSTER}/nodes/node-pool${i}/owner-stake.vkey" \
    --out-file "${STATE_CLUSTER}/nodes/node-pool${i}/stake.reg.shelley.cert"
  # stake address registration cert for Conway era
  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"

  # stake reward keys
  cardano_cli_log latest stake-address key-gen \
    --signing-key-file "${STATE_CLUSTER}/nodes/node-pool${i}/reward.skey" \
    --verification-key-file "${STATE_CLUSTER}/nodes/node-pool${i}/reward.vkey"
  # stake reward address registration cert
  cardano_cli_log compatible shelley stake-address registration-certificate \
    --stake-verification-key-file "${STATE_CLUSTER}/nodes/node-pool${i}/reward.vkey" \
    --out-file "${STATE_CLUSTER}/nodes/node-pool${i}/stake-reward.reg.shelley.cert"
  # stake reward delegation to alwaysAbstain DRep cert
  cardano_cli_log conway stake-address vote-delegation-certificate \
    --stake-verification-key-file "${STATE_CLUSTER}/nodes/node-pool${i}/reward.vkey" \
    --always-abstain \
    --out-file "${STATE_CLUSTER}/nodes/node-pool${i}/stake-reward.vote_deleg.cert"
  if [ -n "${PV9:-""}" ]; then
    ln \
      "${STATE_CLUSTER}/nodes/node-pool${i}/stake-reward.reg.shelley.cert" \
      "${STATE_CLUSTER}/nodes/node-pool${i}/stake-reward.reg.cert"
  else
    # stake reward address registration and vote delegation cert, to be used later in tests
    # when re-registering the reward address in Conway
    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"
  fi

  # pool keys
  cardano_cli_log latest node key-gen \
    --cold-verification-key-file "${STATE_CLUSTER}/nodes/node-pool${i}/cold.vkey" \
    --cold-signing-key-file "${STATE_CLUSTER}/nodes/node-pool${i}/cold.skey" \
    --operational-certificate-issue-counter-file "${STATE_CLUSTER}/nodes/node-pool${i}/cold.counter"
  cardano_cli_log latest node key-gen-KES \
    --verification-key-file "${STATE_CLUSTER}/nodes/node-pool${i}/kes.vkey" \
    --signing-key-file "${STATE_CLUSTER}/nodes/node-pool${i}/kes.skey"
  cardano_cli_log latest node key-gen-VRF \
    --verification-key-file "${STATE_CLUSTER}/nodes/node-pool${i}/vrf.vkey" \
    --signing-key-file "${STATE_CLUSTER}/nodes/node-pool${i}/vrf.skey"

  # stake address delegation certs for Shelley era
  cardano_cli_log compatible shelley 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.shelley.cert"
  # stake address delegation certs for Conway era
  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"

  # pool opcert
  cardano_cli_log latest node issue-op-cert \
    --kes-period 0 \
    --cold-signing-key-file "${STATE_CLUSTER}/nodes/node-pool${i}/cold.skey" \
    --kes-verification-key-file "${STATE_CLUSTER}/nodes/node-pool${i}/kes.vkey" \
    --operational-certificate-issue-counter-file "${STATE_CLUSTER}/nodes/node-pool${i}/cold.counter" \
    --out-file "${STATE_CLUSTER}/nodes/node-pool${i}/op.cert"

  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 latest 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"

  # pool registration cert for Shelley era
  cardano_cli_log compatible shelley 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.shelley.cert"
  # pool registration cert for Conway era
  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

mv "${STATE_CLUSTER}/shelley/utxo-keys/utxo1.vkey" "${STATE_CLUSTER}/shelley/genesis-utxo.vkey"
mv "${STATE_CLUSTER}/shelley/utxo-keys/utxo1.skey" "${STATE_CLUSTER}/shelley/genesis-utxo.skey"
rmdir "${STATE_CLUSTER}/shelley/utxo-keys"

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 Byron era
#

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

echo "Moving funds out of Byron genesis"
for i in $(seq 1 "$NUM_BFT_NODES"); do
  cardano_cli_log byron transaction submit-tx \
    --testnet-magic "$NETWORK_MAGIC" \
    --tx "${STATE_CLUSTER}/byron/tx${i}.tx"
done

# We need to submit an update proposal close to the beginning of an epoch, therefore
# we'll wait for the next epoch.
echo "Waiting for next Byron epoch to start"
# length of Byron era is 200 sec
sleep "$((200 - TX_SUBMISSION_DELAY + 5))"

# Create an update proposal and votes for Byron PV1 era
BYRON_V1_HF_PROPOSAL_FILE="${STATE_CLUSTER}/byron/update-proposal-byron-v1.proposal"
cardano_cli_log byron governance create-update-proposal \
  --filepath "$BYRON_V1_HF_PROPOSAL_FILE" \
  --testnet-magic "$NETWORK_MAGIC" \
  --signing-key "${STATE_CLUSTER}/nodes/node-bft1/byron-deleg.key" \
  --protocol-version-major 1 \
  --protocol-version-minor 0 \
  --protocol-version-alt 0 \
  --application-name "cardano-sl" \
  --software-version-num 1 \
  --system-tag "linux" \
  --installer-hash 0

cardano_cli_log byron governance submit-update-proposal \
  --testnet-magic "$NETWORK_MAGIC" \
  --filepath "$BYRON_V1_HF_PROPOSAL_FILE"
sleep 5

for i in $(seq 1 "$NUM_BFT_NODES"); do
  cardano_cli_log byron governance create-proposal-vote \
    --proposal-filepath "$BYRON_V1_HF_PROPOSAL_FILE" \
    --testnet-magic "$NETWORK_MAGIC" \
    --signing-key "${STATE_CLUSTER}/nodes/node-bft${i}/byron-deleg.key" \
    --vote-yes \
    --output-filepath "${STATE_CLUSTER}/byron/update-proposal-byron-v1-${i}.vote"

  cardano_cli_log byron governance submit-proposal-vote  \
    --testnet-magic "$NETWORK_MAGIC" \
    --filepath "${STATE_CLUSTER}/byron/update-proposal-byron-v1-${i}.vote"
done
sleep 5

echo "Waiting for Byron era with PV1 to start"
sleep 200

#
# In Byron era with PV1
#

# Create an update proposal and votes for Shelley era
SHELLEY_HF_PROPOSAL_FILE="${STATE_CLUSTER}/byron/update-proposal-shelley.proposal"
cardano_cli_log byron governance create-update-proposal \
  --filepath "$SHELLEY_HF_PROPOSAL_FILE" \
  --testnet-magic "$NETWORK_MAGIC" \
  --signing-key "${STATE_CLUSTER}/nodes/node-bft1/byron-deleg.key" \
  --protocol-version-major 2 \
  --protocol-version-minor 0 \
  --protocol-version-alt 0 \
  --application-name "cardano-sl" \
  --software-version-num 1 \
  --system-tag "linux" \
  --installer-hash 0

cardano_cli_log byron governance submit-update-proposal \
  --testnet-magic "$NETWORK_MAGIC" \
  --filepath "$SHELLEY_HF_PROPOSAL_FILE"
sleep 5

for i in $(seq 1 "$NUM_BFT_NODES"); do
  cardano_cli_log byron governance create-proposal-vote \
    --proposal-filepath "$SHELLEY_HF_PROPOSAL_FILE" \
    --testnet-magic "$NETWORK_MAGIC" \
    --signing-key "${STATE_CLUSTER}/nodes/node-bft${i}/byron-deleg.key" \
    --vote-yes \
    --output-filepath "${STATE_CLUSTER}/byron/update-proposal-shelley-${i}.vote"

  cardano_cli_log byron governance submit-proposal-vote  \
    --testnet-magic "$NETWORK_MAGIC" \
    --filepath "${STATE_CLUSTER}/byron/update-proposal-shelley-${i}.vote"
done
sleep 5

for conf in "$STATE_CLUSTER"/config-*.json; do
  fname="${conf##*/}"
  jq '
    ."LastKnownBlockVersion-Major" = 2' \
    "$conf" > "${STATE_CLUSTER}/${fname}_jq"
  cat "${STATE_CLUSTER}/${fname}_jq" > "${STATE_CLUSTER}/${fname}"
  rm -f "${STATE_CLUSTER}/${fname}_jq"
done

supervisorctl -s unix:///"$SUPERVISORD_SOCKET_PATH" restart nodes:

echo "Waiting for Shelley era to start"
sleep 190


#
# In Shelley era
#

# variables used in Shelley-based eras
GENESIS_VERIFICATION=()
for vkey in "$STATE_CLUSTER"/shelley/genesis-keys/genesis?.vkey; do
  GENESIS_VERIFICATION+=("--genesis-verification-key-file" "$vkey")
done

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

FAUCET_ADDR="$(<"$STATE_CLUSTER"/byron/address-000-converted)"
FAUCET_SKEY="${STATE_CLUSTER}/byron/payment-keys.000-converted.skey"


wait_for_era "Shelley"
SHELLEY_EPOCH="$(get_epoch)"

# 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

sleep "$PROPOSAL_DELAY"
echo "Submitting update proposal to transfer to Allegra, transferring funds to pool owners, registering pools and delegations"

ALLEGRA_HF_PROPOSAL_FILE="${STATE_CLUSTER}/shelley/update-proposal-allegra.proposal"
ALLEGRA_TX_BASE="${STATE_CLUSTER}/shelley/transfer-register-delegate"

cardano_cli_log compatible shelley governance action create-protocol-parameters-update \
  --out-file "$ALLEGRA_HF_PROPOSAL_FILE" \
  --epoch "$(get_epoch)" \
  "${GENESIS_VERIFICATION[@]}" \
  --protocol-major-version 3 \
  --protocol-minor-version 0

# Transfer funds, register pools and delegations, submit update proposal, all in one big transaction:

DEPOSITS="$((POOL_DEPOSIT + (2 * KEY_DEPOSIT) ))"
NEEDED_AMOUNT="$(( (POOL_PLEDGE + DEPOSITS) * NUM_POOLS ))"
STOP_TXIN_AMOUNT="$((NEEDED_AMOUNT + FEE))"

get_txins "$FAUCET_ADDR" "$STOP_TXIN_AMOUNT"

TXOUT_AMOUNT="$((TXIN_AMOUNT - 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.shelley.cert" \
    "--certificate-file" "${STATE_CLUSTER}/nodes/node-pool${i}/stake-reward.reg.shelley.cert" \
    "--certificate-file" "${STATE_CLUSTER}/nodes/node-pool${i}/register.shelley.cert" \
    "--certificate-file" "${STATE_CLUSTER}/nodes/node-pool${i}/owner-stake.deleg.shelley.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

cardano_cli_log compatible shelley transaction signed-transaction \
  --fee    "$FEE" \
  "${TXINS[@]}" \
  --tx-out "${FAUCET_ADDR}+${TXOUT_AMOUNT}" \
  "${POOL_ARGS[@]}" \
  --update-proposal-file "$ALLEGRA_HF_PROPOSAL_FILE" \
  "${POOL_SIGNING[@]}" \
  "${GENESIS_SIGNING[@]}" \
  "${DELEGATE_SIGNING[@]}" \
  --signing-key-file "$FAUCET_SKEY" \
  --testnet-magic    "$NETWORK_MAGIC" \
  --out-file         "${ALLEGRA_TX_BASE}-tx.tx"

cardano_cli_log latest transaction submit \
  --tx-file "${ALLEGRA_TX_BASE}-tx.tx" \
  --testnet-magic "$NETWORK_MAGIC"

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

echo "Waiting for Allegra era to start"
wait_for_epoch "$((SHELLEY_EPOCH + 1))"


#
# In Allegra era
#


wait_for_era "Allegra"
ALLEGRA_EPOCH="$(get_epoch)"

sleep "$PROPOSAL_DELAY"
echo "Submitting update proposal to transfer to Mary, set d = 0"

MARY_HF_PROPOSAL="${STATE_CLUSTER}/shelley/update-proposal-mary"

cardano_cli_log compatible allegra governance action create-protocol-parameters-update \
  --out-file "${MARY_HF_PROPOSAL}.proposal" \
  --epoch "$(get_epoch)" \
  "${GENESIS_VERIFICATION[@]}" \
  --decentralization-parameter 0 \
  --protocol-major-version 4 \
  --protocol-minor-version 0

get_txins "$FAUCET_ADDR" "$FEE"

TXOUT_AMOUNT="$((TXIN_AMOUNT - FEE))"

cardano_cli_log compatible allegra transaction signed-transaction \
  --fee    "$FEE" \
  "${TXINS[@]}" \
  --tx-out "${FAUCET_ADDR}+${TXOUT_AMOUNT}" \
  --update-proposal-file "${MARY_HF_PROPOSAL}.proposal" \
  --signing-key-file "$FAUCET_SKEY" \
  "${DELEGATE_SIGNING[@]}" \
  --testnet-magic    "$NETWORK_MAGIC" \
  --out-file         "${MARY_HF_PROPOSAL}-tx.tx"

cardano_cli_log latest transaction submit \
  --tx-file "${MARY_HF_PROPOSAL}-tx.tx" \
  --testnet-magic "$NETWORK_MAGIC"

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

echo "Waiting for Mary era to start"
wait_for_epoch "$((ALLEGRA_EPOCH + 1))"


#
# In Mary era
#


wait_for_era "Mary"
MARY_EPOCH="$(get_epoch)"

sleep "$PROPOSAL_DELAY"
echo "Submitting update proposal to transfer to Alonzo"

ALONZO_UPDATE_PROPOSAL="${STATE_CLUSTER}/shelley/update-proposal-alonzo"

cardano_cli_log compatible mary governance action create-protocol-parameters-update \
  --out-file "${ALONZO_UPDATE_PROPOSAL}.proposal" \
  --epoch "$(get_epoch)" \
  "${GENESIS_VERIFICATION[@]}" \
  --protocol-major-version 5 \
  --protocol-minor-version 0

get_txins "$FAUCET_ADDR" "$FEE"

TXOUT_AMOUNT="$((TXIN_AMOUNT - FEE))"

cardano_cli_log compatible mary transaction signed-transaction \
  --fee    "$FEE" \
  "${TXINS[@]}" \
  --tx-out "${FAUCET_ADDR}+${TXOUT_AMOUNT}" \
  --update-proposal-file "${ALONZO_UPDATE_PROPOSAL}.proposal" \
  --signing-key-file "$FAUCET_SKEY" \
  "${DELEGATE_SIGNING[@]}" \
  --testnet-magic    "$NETWORK_MAGIC" \
  --out-file         "${ALONZO_UPDATE_PROPOSAL}-tx.tx"

cardano_cli_log latest transaction submit \
  --tx-file "${ALONZO_UPDATE_PROPOSAL}-tx.tx" \
  --testnet-magic "$NETWORK_MAGIC"

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

echo "Waiting for Alonzo era to start"
wait_for_epoch "$((MARY_EPOCH + 1))"


#
# In Alonzo era
#


wait_for_era "Alonzo"
ALONZO_EPOCH="$(get_epoch)"

sleep "$PROPOSAL_DELAY"
echo "Submitting update proposal to update to PV6"

ALONZO_UPDATE_PROPOSAL_PV6="${STATE_CLUSTER}/shelley/update-proposal-alonzo-pv6"

# protocol version + dapps parameters update
cardano_cli_log compatible alonzo governance action create-protocol-parameters-update \
  --out-file "${ALONZO_UPDATE_PROPOSAL_PV6}.proposal" \
  --epoch "$(get_epoch)" \
  "${GENESIS_VERIFICATION[@]}" \
  --protocol-major-version 6 \
  --protocol-minor-version 0

get_txins "$FAUCET_ADDR" "$FEE"

TXOUT_AMOUNT="$((TXIN_AMOUNT - FEE))"

cardano_cli_log compatible alonzo transaction signed-transaction \
  --fee    "$FEE" \
  "${TXINS[@]}" \
  --tx-out "${FAUCET_ADDR}+${TXOUT_AMOUNT}" \
  --update-proposal-file "${ALONZO_UPDATE_PROPOSAL_PV6}.proposal" \
  --signing-key-file "$FAUCET_SKEY" \
  "${DELEGATE_SIGNING[@]}" \
  --testnet-magic    "$NETWORK_MAGIC" \
  --out-file         "${ALONZO_UPDATE_PROPOSAL_PV6}-tx.tx"

cardano_cli_log latest transaction submit \
  --tx-file "${ALONZO_UPDATE_PROPOSAL_PV6}-tx.tx" \
  --testnet-magic "$NETWORK_MAGIC"

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


echo "Waiting for Alonzo era with PV6 to start"
wait_for_epoch "$((ALONZO_EPOCH + 1))"


#
# In Alonzo era with PV6
#

ALONZO_PV6_EPOCH="$(get_epoch)"

# 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

# Workaround for https://github.com/IntersectMBO/cardano-cli/issues/1262
if cardano_cli_log latest query protocol-parameters \
  --testnet-magic "$NETWORK_MAGIC" \
  --out-file "${STATE_CLUSTER}/pparams.json"; then

  PROTOCOL_VERSION="$(jq ".protocolVersion.major" < "${STATE_CLUSTER}/pparams.json")"

  [ "$PROTOCOL_VERSION" = 6 ] || { echo "Unexpected protocol version '$PROTOCOL_VERSION' on line $LINENO" >&2; exit 1; }  # assert
fi

sleep "$PROPOSAL_DELAY"
echo "Submitting update proposal to update to Babbage"

BABBAGE_UPDATE_PROPOSAL="${STATE_CLUSTER}/shelley/update-proposal-babbage"

# protocol version + dapps parameters update
cardano_cli_log compatible alonzo governance action create-protocol-parameters-update \
  --out-file "${BABBAGE_UPDATE_PROPOSAL}.proposal" \
  --epoch "$(get_epoch)" \
  "${GENESIS_VERIFICATION[@]}" \
  --protocol-major-version 7 \
  --protocol-minor-version 0

get_txins "$FAUCET_ADDR" "$FEE"

TXOUT_AMOUNT="$((TXIN_AMOUNT - FEE))"

cardano_cli_log compatible alonzo transaction signed-transaction \
  --fee    "$FEE" \
  "${TXINS[@]}" \
  --tx-out "${FAUCET_ADDR}+${TXOUT_AMOUNT}" \
  --update-proposal-file "${BABBAGE_UPDATE_PROPOSAL}.proposal" \
  --signing-key-file "$FAUCET_SKEY" \
  "${DELEGATE_SIGNING[@]}" \
  --testnet-magic    "$NETWORK_MAGIC" \
  --out-file         "${BABBAGE_UPDATE_PROPOSAL}-tx.tx"

cardano_cli_log latest transaction submit \
  --tx-file "${BABBAGE_UPDATE_PROPOSAL}-tx.tx" \
  --testnet-magic "$NETWORK_MAGIC"

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

echo "Waiting for Babbage era to start"
wait_for_epoch "$((ALONZO_PV6_EPOCH + 1))"


#
# In Babbage era
#

wait_for_era "Babbage"
BABBAGE_EPOCH="$(get_epoch)"

# update to PV8
sleep "$PROPOSAL_DELAY"
echo "Submitting update proposal to update to PV8"

BABBAGE_UPDATE_PROPOSAL_PV8="${STATE_CLUSTER}/shelley/update-proposal-babbage-pv8"

# protocol version 8
cardano_cli_log compatible babbage governance action create-protocol-parameters-update \
  --out-file "${BABBAGE_UPDATE_PROPOSAL_PV8}.proposal" \
  --epoch "$(get_epoch)" \
  "${GENESIS_VERIFICATION[@]}" \
  --protocol-major-version 8 \
  --protocol-minor-version 0

get_txins "$FAUCET_ADDR" "$FEE"

TXOUT_AMOUNT="$((TXIN_AMOUNT - FEE))"

cardano_cli_log compatible babbage transaction signed-transaction \
  --fee    "$FEE" \
  "${TXINS[@]}" \
  --tx-out "${FAUCET_ADDR}+${TXOUT_AMOUNT}" \
  --update-proposal-file "${BABBAGE_UPDATE_PROPOSAL_PV8}.proposal" \
  --signing-key-file "$FAUCET_SKEY" \
  "${DELEGATE_SIGNING[@]}" \
  --testnet-magic    "$NETWORK_MAGIC" \
  --out-file         "${BABBAGE_UPDATE_PROPOSAL_PV8}-tx.tx"

cardano_cli_log latest transaction submit \
  --tx-file "${BABBAGE_UPDATE_PROPOSAL_PV8}-tx.tx" \
  --testnet-magic "$NETWORK_MAGIC"

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

echo "Waiting for Babbage era with PV8 to start"
wait_for_epoch "$((BABBAGE_EPOCH + 1))"


#
# In Babbage era with PV8
#

BABBAGE_PV8_EPOCH="$(get_epoch)"

# Workaround for https://github.com/IntersectMBO/cardano-cli/issues/1262
if cardano_cli_log latest query protocol-parameters \
  --testnet-magic "$NETWORK_MAGIC" \
  --out-file "${STATE_CLUSTER}/pparams.json"; then

  PROTOCOL_VERSION="$(jq ".protocolVersion.major" < "${STATE_CLUSTER}/pparams.json")"

  [ "$PROTOCOL_VERSION" = 8 ] || { echo "Unexpected protocol version '$PROTOCOL_VERSION' on line $LINENO" >&2; exit 1; }  # assert
fi

# update to Conway
sleep "$PROPOSAL_DELAY"
echo "Submitting update proposal to update to Conway"

CONWAY_UPDATE_PROPOSAL="${STATE_CLUSTER}/shelley/update-proposal-conway"

# protocol version 9
cardano_cli_log compatible babbage governance action create-protocol-parameters-update \
  --out-file "${CONWAY_UPDATE_PROPOSAL}.proposal" \
  --epoch "$(get_epoch)" \
  "${GENESIS_VERIFICATION[@]}" \
  --protocol-major-version 9 \
  --protocol-minor-version 0

get_txins "$FAUCET_ADDR" "$FEE"

TXOUT_AMOUNT="$((TXIN_AMOUNT - FEE))"

cardano_cli_log compatible babbage transaction signed-transaction \
  --fee    "$FEE" \
  "${TXINS[@]}" \
  --tx-out "${FAUCET_ADDR}+${TXOUT_AMOUNT}" \
  --update-proposal-file "${CONWAY_UPDATE_PROPOSAL}.proposal" \
  --signing-key-file "$FAUCET_SKEY" \
  "${DELEGATE_SIGNING[@]}" \
  --testnet-magic    "$NETWORK_MAGIC" \
  --out-file         "${CONWAY_UPDATE_PROPOSAL}-tx.tx"

cardano_cli_log latest transaction submit \
  --tx-file "${CONWAY_UPDATE_PROPOSAL}-tx.tx" \
  --testnet-magic "$NETWORK_MAGIC"

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

echo "Waiting for Conway to start"
wait_for_epoch "$((BABBAGE_PV8_EPOCH + 1))"


#
# In Conway era
#

wait_for_era "Conway"

CONWAY_PV9_EPOCH="$(get_epoch)"

cardano_cli_log latest query protocol-parameters \
  --testnet-magic "$NETWORK_MAGIC" \
  --out-file "${STATE_CLUSTER}/pparams.json"

PROTOCOL_VERSION="$(jq ".protocolVersion.major" < "${STATE_CLUSTER}/pparams.json")"

[ "$PROTOCOL_VERSION" = 9 ] || { echo "Unexpected protocol version '$PROTOCOL_VERSION' on line $LINENO" >&2; exit 1; }  # assert

# Register CC members, DReps, all in one big transaction:

DEPOSITS="$((KEY_DEPOSIT + DREP_DEPOSIT))"
NEEDED_AMOUNT="$(( (DREP_DELEGATED + DEPOSITS) * NUM_DREPS ))"
STOP_TXIN_AMOUNT="$((FEE + NEEDED_AMOUNT))"

get_txins "$FAUCET_ADDR" "$STOP_TXIN_AMOUNT"

TXOUT_AMOUNT="$((TXIN_AMOUNT - STOP_TXIN_AMOUNT))"

V9_TX="${STATE_CLUSTER}/governance_data/setup_governance"

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

POOL_ARGS=()
POOL_SIGNING=()
for i in $(seq 1 "$NUM_POOLS"); do
  POOL_ARGS+=( \
    "--certificate-file" "${STATE_CLUSTER}/nodes/node-pool${i}/stake-reward.vote_deleg.cert" \
  )
  POOL_SIGNING+=( \
    "--signing-key-file" "${STATE_CLUSTER}/nodes/node-pool${i}/reward.skey" \
  )
done

cardano_cli_log conway transaction build-raw \
  --fee    "$FEE" \
  "${TXINS[@]}" \
  "${CC_ARGS[@]}" \
  "${DREPS_ARGS[@]}" \
  "${POOL_ARGS[@]}" \
  --tx-out "${FAUCET_ADDR}+${TXOUT_AMOUNT}" \
  --out-file "${V9_TX}-tx.txbody"

cardano_cli_log conway transaction sign \
  --signing-key-file "$FAUCET_SKEY" \
  "${CC_SIGNING[@]}" \
  "${DREPS_SIGNING[@]}" \
  "${POOL_SIGNING[@]}" \
  --testnet-magic    "$NETWORK_MAGIC" \
  --tx-body-file     "${V9_TX}-tx.txbody" \
  --out-file         "${V9_TX}-tx.tx"

cardano_cli_log conway transaction submit \
  --tx-file "${V9_TX}-tx.tx" \
  --testnet-magic "$NETWORK_MAGIC"

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

if [ -z "${NO_CC:-""}" ]; then
  cc_size="$(cardano-cli conway query committee-state --active --testnet-magic "$NETWORK_MAGIC" |
    grep -c '"status": "Active"')"
  [ "$cc_size" -ge "$NUM_CC" ] || \
    { echo "The CC members were not registered, line $LINENO" >&2; exit 1; }  # assert
fi

# Hard fork to Conway protocol version 10

if [ -z "${PV9:-""}" ]; then
  PV10_ACTION="${STATE_CLUSTER}/governance_data/hardfork_pv10_action"

  echo "Submitting hard fork proposal to update to Conway PV10"

  cardano_cli_log conway governance action create-hardfork \
    --testnet \
    --governance-action-deposit "$GOV_ACTION_DEPOSIT" \
    --deposit-return-stake-verification-key-file "${STATE_CLUSTER}/nodes/node-pool1/reward.vkey" \
    --anchor-url "http://www.hardfork-pv10.com" \
    --anchor-data-hash 5d372dca1a4cc90d7d16d966c48270e33e3aa0abcb0e78f0d5ca7ff330d2245d \
    --protocol-major-version 10 \
    --protocol-minor-version 0 \
    --out-file "${PV10_ACTION}.action"

  STOP_TXIN_AMOUNT="$((FEE + GOV_ACTION_DEPOSIT))"

  get_txins "$FAUCET_ADDR" "$STOP_TXIN_AMOUNT"

  TXOUT_AMOUNT="$((TXIN_AMOUNT - STOP_TXIN_AMOUNT))"

  cardano_cli_log conway transaction build-raw \
    --fee    "$FEE" \
    "${TXINS[@]}" \
    --proposal-file "${PV10_ACTION}.action" \
    --tx-out "${FAUCET_ADDR}+${TXOUT_AMOUNT}" \
    --out-file "${PV10_ACTION}-tx.txbody"

  cardano_cli_log conway transaction sign \
    --signing-key-file "$FAUCET_SKEY" \
    --testnet-magic    "$NETWORK_MAGIC" \
    --tx-body-file     "${PV10_ACTION}-tx.txbody" \
    --out-file         "${PV10_ACTION}-tx.tx"

  cardano_cli_log conway transaction submit \
    --tx-file "${PV10_ACTION}-tx.tx" \
    --testnet-magic "$NETWORK_MAGIC"

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

  ACTION_TXID="$(cardano_cli_log conway transaction txid --output-text --tx-body-file "${PV10_ACTION}-tx.txbody")"

  echo "Voting on hard fork proposal"

  INDEX=0
  for f in "$STATE_CLUSTER"/governance_data/cc_member*_committee_hot.vkey; do
    [ -e "$f" ] || continue
    INDEX="$((INDEX + 1))"
    cardano_cli_log conway governance vote create \
      --yes \
      --governance-action-tx-id "$ACTION_TXID" \
      --governance-action-index 0 \
      --cc-hot-verification-key-file "$f" \
      --out-file "${PV10_ACTION}_cc${INDEX}.vote"
  done

  INDEX=0
  for f in "$STATE_CLUSTER"/nodes/node-pool*/cold.vkey; do
    INDEX="$((INDEX + 1))"
    cardano_cli_log conway governance vote create \
      --yes \
      --governance-action-tx-id "$ACTION_TXID" \
      --governance-action-index 0 \
      --cold-verification-key-file "$f" \
      --out-file "${PV10_ACTION}_spo${INDEX}.vote"
  done

  # Submit the votes

  PV10_VOTES="${STATE_CLUSTER}/governance_data/hardfork_pv10_votes"

  VOTE_FILES=()
  for f in "$PV10_ACTION"_*.vote; do
    VOTE_FILES+=( "--vote-file" "$f" )
  done

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

  POOL_SIGNING=()
  for f in "$STATE_CLUSTER"/nodes/node-pool*/cold.skey; do
    POOL_SIGNING+=( \
      "--signing-key-file" "$f" \
    )
  done

  get_txins "$FAUCET_ADDR" "$FEE"

  TXOUT_AMOUNT="$((TXIN_AMOUNT - FEE))"

  cardano_cli_log conway transaction build-raw \
    --fee    "$FEE" \
    "${TXINS[@]}" \
    "${VOTE_FILES[@]}" \
    --tx-out "${FAUCET_ADDR}+${TXOUT_AMOUNT}" \
    --out-file "${PV10_VOTES}-tx.txbody"

  cardano_cli_log conway transaction sign \
    --signing-key-file "$FAUCET_SKEY" \
    "${CC_SIGNING[@]}" \
    "${POOL_SIGNING[@]}" \
    --testnet-magic    "$NETWORK_MAGIC" \
    --tx-body-file     "${PV10_VOTES}-tx.txbody" \
    --out-file         "${PV10_VOTES}-tx.tx"

  cardano_cli_log conway transaction submit \
    --tx-file "${PV10_VOTES}-tx.tx" \
    --testnet-magic "$NETWORK_MAGIC"

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

  echo "Waiting for Conway PV10 to start"
  wait_for_epoch "$((CONWAY_PV9_EPOCH + 2))"

  cardano_cli_log conway query protocol-parameters \
    --testnet-magic "$NETWORK_MAGIC" \
    --out-file "${STATE_CLUSTER}/pparams.json"

  PROTOCOL_VERSION="$(jq ".protocolVersion.major" < "${STATE_CLUSTER}/pparams.json")"

  [ "$PROTOCOL_VERSION" = 10 ] || { echo "Unexpected protocol version '$PROTOCOL_VERSION' on line $LINENO" >&2; exit 1; }  # assert
fi

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