├── .env ├── .gitattributes ├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── alertmanager └── config.yml ├── build-postgres ├── 1_compile.sh ├── 2_configure.sh ├── 3_optimize.sh ├── postgres.service ├── start.sh └── stop.sh ├── cli ├── Dockerfile ├── history │ └── .bash_history └── scripts │ └── poi ├── compose-graphnode.yml ├── compose-indexer.yml ├── compose-monitoring.yml ├── compose-optional.yml ├── docs ├── advanced-config.md ├── allocations.md ├── costmodels.md ├── getting-started.md ├── pre-requisites.md ├── tips.md └── troubleshooting.md ├── extract_queries_since ├── grafana └── provisioning │ ├── alerting │ └── file │ ├── dashboards │ ├── dashboard.yml │ ├── default.yml │ ├── deployment-details.json │ ├── graphql.json │ ├── indexing-performance.json │ ├── indexing-status-overview.json │ ├── logs-explorer.json │ ├── postgres-activity.json │ ├── postgres-sizes.json │ ├── query-performance-metrics.json │ ├── subgraph-radio.json │ ├── system-and-docker-performance-metrics.json │ ├── tap.json │ └── traefik.json │ ├── datasources │ ├── graphql.yml │ ├── loki.yml │ ├── postgres.yml │ ├── prometheus.yml │ └── subgraph_radio_graphql.yml │ └── plugins │ └── file ├── graph-node-configs └── config.tmpl ├── logs ├── loki ├── loki.yaml └── loki_config_runtime.yaml ├── offchain-subgraphs.sh ├── prometheus ├── alert.rules └── prometheus.yml ├── promtail └── promtail.yaml ├── refresh-sizes.sh ├── runagora ├── runqlog ├── shell ├── start-all ├── start-essential ├── start-optional ├── stop-all ├── stop-essential ├── stop-optional ├── traefik └── config │ └── dynamic_config.yml └── truncate-actions-table.sh /.env: -------------------------------------------------------------------------------- 1 | EMAIL=email@sld.tld 2 | 3 | INDEX_HOST=index.sld.tld 4 | GRAFANA_HOST=dashboard.sld.tld 5 | 6 | ADMIN_USER=your_user 7 | ADMIN_PASSWORD=your_password 8 | 9 | GRAPH_NODE_DB_HOST=postgres 10 | GRAPH_NODE_DB_USER=your_db_user 11 | GRAPH_NODE_DB_PASS=your_db_password 12 | GRAPH_NODE_DB_NAME=your_graphnode_db_name 13 | 14 | AGENT_DB_HOST=postgres-agent 15 | AGENT_DB_USER=your_db_user 16 | AGENT_DB_PASS=your_db_password 17 | AGENT_DB_NAME=your_agent_db_name 18 | 19 | 20 | NETWORK_SUBGRAPH_ENDPOINT="https://gateway.thegraph.com/api/{api-key}/subgraphs/id/DZz4kDTdmzWLWsV373w2bSmoar3umKKH9y82SUKr5qmp" 21 | #NETWORK_SUBGRAPH_ENDPOINT="http://query-node-0:8000/subgraphs/id/Qm" 22 | #NETWORK_SUBGRAPH_DEPLOYMENT=Qm 23 | 24 | EPOCH_SUBGRAPH_ENDPOINT="https://gateway.thegraph.com/api/{api-key}/subgraphs/id/4KFYqUWRTZQ9gn7GPHC6YQ2q15chJfVrX43ezYcwkgxB" 25 | #EPOCH_SUBGRAPH_ENDPOINT="http://query-node-0:8000/subgraphs/id/Qm" 26 | 27 | NETWORK_ESCROW_ENDPOINT="https://gateway.thegraph.com/api/{api-key}/subgraphs/id/4sukbNVTzGELnhdnpyPqsf1QqtzNHEYKKmJkgaT8z6M1" 28 | #NETWORK_ESCROW_ENDPOINT="http://query-node-0:8000/subgraphs/id/Qm" 29 | #NETWORK_ESCROW_DEPLOYMENT=Qm 30 | 31 | REGISTRY_SUBGRAPH_ENDPOINT="https://gateway.thegraph.com/api/{api-key}/subgraphs/id/5tHgjCNF4XxAzp9ja8dU3j9JrqU7zctXj6DnxWpwAzc6" 32 | #REGISTRY_SUBGRAPH_ENDPOINT="http://query-node-0:8000/subgraphs/id/Qm" 33 | 34 | CHAIN_0_NAME="network-name" 35 | CHAIN_0_RPC="http://ip:port" 36 | TXN_RPC="http://ip:port" 37 | 38 | OPERATOR_SEED_PHRASE="12 or 15 word mnemonic" 39 | STAKING_WALLET_ADDRESS=0xAdDreSs 40 | GEO_COORDINATES='69.420 69.420' 41 | 42 | INDEXER_AGENT_OFFCHAIN_SUBGRAPHS="" 43 | 44 | # Get all the env vars from: https://raw.githubusercontent.com/graphprotocol/indexer/refs/heads/main/docs/testnet-setup.md 45 | # And all TAP envs from: https://raw.githubusercontent.com/graphprotocol/indexer-rs/refs/heads/main/config/maximal-config-example.toml 46 | 47 | # Optional env vars depending on which services you use: 48 | 49 | #GRAPH_NODE_VERSION=graphprotocol/graph-node:v0.33.0 50 | #INDEXER_SERVICE_VERSION=ghcr.io/graphprotocol/indexer-service:v0.20.22 51 | #INDEXER_AGENT_VERSION=ghcr.io/graphprotocol/indexer-agent:v0.20.22 52 | #INDEXER_CLI_VERSION=ghcr.io/graphprotocol/indexer-cli:v0.21.4 53 | #POSTGRES_VERSION=postgres:16.1 54 | #POSTGRES_AGENT_VERSION=postgres:16.1 55 | 56 | ### Indexer agent GUI: 57 | # AGENT_GUI_HOST=agent.sld.tld 58 | # NEXTAUTH_SECRET=$(openssl rand -base64 32) 59 | 60 | ### POIfier 61 | # POIFIER_TOKEN=token 62 | 63 | ### Graphcast Subgraph Radio 64 | # PRIVATE_KEY=0xPrivateKey 65 | # GRAPHCAST_NETWORK= 66 | # REGISTRY_SUBGRAPH_ENDPOINT= 67 | # NETWORK_SUBGRAPH_ENDPOINT= 68 | # GRAPH_NODE_STATUS_ENDPOINT= 69 | # RUST_LOG= 70 | # INDEXER_ADDRESS= 71 | # METRICS_HOST= 72 | 73 | # If you change METRICS_PORT, make sure to also change the subgraph-radio job's targets in 74 | # prometheus/prometheus.yml, from targets: ['subgraph-radio:3010'] to targets: ['subgraph-radio:YOUR_NEW_PORT'] 75 | # METRICS_PORT= 76 | 77 | # SERVER_PORT= 78 | # ID_VALIDATION= 79 | # COVERAGE= 80 | # PERSISTENCE_FILE_PATH= 81 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text eol=lf 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | *.jpg binary 44 | *.png binary 45 | *.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *DS_Store 2 | .vs/ 3 | .vscode/ 4 | .idea/ 5 | .env 6 | offchain-subgraphs 7 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "qlog"] 2 | path = qlog 3 | url = git@github.com:graphprotocol/qlog.git 4 | [submodule "agora"] 5 | path = agora 6 | url = git@github.com:graphprotocol/agora.git 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Stefan Prodan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Graph Protocol Mainnet Docker Compose 2 | ============ 3 | 4 | 5 | 6 | This repository is a one-stop solution to the decentralized world of The Graph. It spins up all the necessary containers on one single machine including monitoring solutions and a CLI container that allows you to interact with the graph-nodes or the indexer-agent. 7 | 8 | ⚠️ **WARNING:** It is very important to read the entire documentation if you want to thoroughly understand the ins and outs of the Indexer Software Stack. If you're trying to binge through this documentation, no help will be offered, and you'll be sent back to **RTFM**. Thanks for understanding. 💖 9 | 10 | 11 | The monitoring configuration runs with [Prometheus](https://prometheus.io/), [Grafana](http://grafana.org/), [cAdvisor](https://github.com/google/cadvisor), [NodeExporter](https://github.com/prometheus/node_exporter) and alerting with [AlertManager](https://github.com/prometheus/alertmanager), a K8S template provided by the Graph team in the [mission control repository](https://github.com/graphprotocol/mission-control-indexer) during the Mission Control Testnet back in July 2020, and later adapted for mainnet using [this configuration](https://github.com/graphprotocol/indexer/blob/main/docs/networks.md#mainnet-and-testnet-configuration). 12 | 13 | The advantage of using Docker, as opposed to systemd bare-metal setups, is that Docker is easy to manipulate and scale up if needed. We personally ran the whole testnet infrastructure on the same machine, including an Erigon Archive Node (not included in this docker build). The best part of using Docker is that the data is stored in named volumes on the docker host and can be exported / copied over to a bigger machine once more performance is needed. 14 | 15 | Note that you **need** access to an **Ethereum Archive Node that supports EIP-1898**. 16 | 17 | The setup for the archive node is **not included** in this docker setup. 18 | 19 | The minimum configuration should to be the CPX51 VPS at Hetzner. Feel free to sign up using our [referral link](https://hetzner.cloud/?ref=x2opTk2fg2fM) -- you can save 20€ and we get 10€ bonus for setting up some testnet nodes to support the network growth. :) 20 | 21 | 22 | 23 | ## Table of contents 24 | 25 | 26 | - [README.md](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/README.md) <- you are here 27 | - [Pre-requisites](docs/pre-requisites.md) 28 | - [Getting Started](docs/getting-started.md) 29 | - [Advanced Configuration](docs/advanced-config.md) 30 | - [Setting Up Allocations](docs/allocations.md) 31 | - [Setting Up Cost Models](docs/costmodels.md) 32 | - [Tips and Tricks](docs/tips.md) 33 | - [Troubleshooting](docs/troubleshooting.md) 34 | -------------------------------------------------------------------------------- /alertmanager/config.yml: -------------------------------------------------------------------------------- 1 | route: 2 | receiver: 'slack' 3 | group_by: ['...'] 4 | 5 | receivers: 6 | - name: 'slack' 7 | slack_configs: 8 | - send_resolved: true 9 | text: "{{ .CommonAnnotations.description }}" 10 | username: 'Prometheus' 11 | channel: '#' 12 | api_url: 'https://hooks.slack.com/services/' 13 | -------------------------------------------------------------------------------- /build-postgres/1_compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | apt install -y software-properties-common 4 | add-apt-repository ppa:ubuntu-toolchain-r/test 5 | apt-get install -y gcc-10 g++-10 build-essential libreadline-dev zlib1g-dev flex bison libxml2-dev libxslt-dev libssl-dev libxml2-utils xsltproc git 6 | update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 100 --slave /usr/bin/g++ g++ /usr/bin/g++-10 7 | git clone https://github.com/postgres/postgres.git 8 | cd postgres/ 9 | git checkout REL_13_1 10 | ./configure CXXFLAGS="-march=native -O3" CFLAGS="-march=native -O3" 11 | make 12 | make install 13 | cd contrib 14 | make 15 | make install 16 | -------------------------------------------------------------------------------- /build-postgres/2_configure.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | apt install -y ufw 4 | ufw allow ssh 5 | ufw allow from 172.0.0.0/8 6 | ufw allow from 192.168.0.0/16 7 | ufw allow from 127.0.0.0/8 8 | 9 | echo "important: enabled a firewall" 10 | ufw enable 11 | 12 | adduser postgres --disabled-password 13 | 14 | chown -R postgres:postgres /usr/local/pgsql 15 | 16 | su -c "/usr/local/pgsql/bin/initdb --pgdata=/usr/local/pgsql/data --encoding=UTF8 --no-locale" postgres 17 | 18 | echo -e "\e[1;31m ################################################################################ \e[0m" 19 | echo -e "\e[1;31m ################################################################################ \e[0m" 20 | echo -e "\e[1;31m ################################################################################ \e[0m" 21 | 22 | 23 | echo -e "\e[1;33m add the following line above replication priviledges in the file \e[0m" 24 | echo -e "\e[1;33m /usr/local/pgsql/data/pg_hba.conf \e[0m" 25 | echo -e "\e[1;33m host all all 172.0.0.0/8 trust \e[0m" 26 | echo -e "\e[1;33m host all all 192.168.0.0/16 trust \e[0m" 27 | 28 | 29 | echo -e "\e[1;31m ################################################################################ \e[0m" 30 | echo -e "\e[1;31m ################################################################################ \e[0m" 31 | echo -e "\e[1;31m ################################################################################ \e[0m" 32 | 33 | 34 | 35 | echo -e "\e[1;33m go to pgtune https://pgtune.leopard.in.ua/#/ and generate your database configuration \e[0m" 36 | echo -e "\e[1;33m Webapplication is a good enough profile I guess. \e[0m" 37 | echo -e "\e[1;33m add the following line \e[0m" 38 | echo -e "\e[1;33m listen_addresses = '*' \e[0m" 39 | echo -e "\e[1;33m and store the file as /usr/local/pgsql/data/postgresql.conf \e[0m" 40 | 41 | cp postgres.service /lib/systemd/system/postgres.service 42 | systemctl enable postgres 43 | -------------------------------------------------------------------------------- /build-postgres/3_optimize.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | apt install tuned 4 | 5 | SYSCTL=/sbin/sysctl 6 | 7 | echo -e "\e[1;31m ################################################################################ \e[0m" 8 | echo -e "\e[1;31m ################################################################################ \e[0m" 9 | echo -e "\e[1;31m ################################################################################ \e[0m" 10 | echo 11 | echo 12 | 13 | echo -e "# add the output of this script to \e[1;31m /etc/sysctl.conf, \e[0m" 14 | echo -e "# and then, as root, run the following command:" 15 | echo 16 | echo -e "\e[1;33m sysctl -p /etc/sysctl.conf \e[0m" 17 | echo 18 | echo -e "# to load change the kernel settings for these parameters." 19 | 20 | echo 21 | echo 22 | echo -e "\e[1;31m ################################################################################ \e[0m" 23 | echo -e "\e[1;31m ################################################################################ \e[0m" 24 | echo -e "\e[1;31m ################################################################################ \e[0m" 25 | echo 26 | echo 27 | 28 | PAGE_SIZE=`getconf PAGE_SIZE` 29 | 30 | echo -e "# page size is: \e[1;31m $PAGE_SIZE \e[0m" 31 | 32 | NUM_PHYS_PAGES=`getconf _PHYS_PAGES` 33 | 34 | echo -e "# number of physical pages on this box: \e[1;31m $NUM_PHYS_PAGES \e[0m" 35 | 36 | 37 | CURR_SHMALL=`$SYSCTL -n kernel.shmall` 38 | PREF_SHMALL=`expr $NUM_PHYS_PAGES / 2` 39 | 40 | echo 41 | echo -e "# kernel.shmall should be half of the number of pages. Current kernel.shmall, in pages, is: \e[1;31m $CURR_SHMALL \e[0m" 42 | echo "# kernel.shmall should be:" 43 | echo -e "\e[1;33m kernel.shmall = $PREF_SHMALL \e[0m" 44 | echo 45 | echo 46 | echo 47 | 48 | CURR_SHMMAX=`$SYSCTL -n kernel.shmmax` 49 | PREF_SHMMAX=`expr $PREF_SHMALL \* $PAGE_SIZE` 50 | 51 | echo -e "# kernel.shmmax should be half of available RAM, in kB. Current kernel.shmmax, in kB, is: \e[1;31m $CURR_SHMMAX \e[0m" 52 | echo "# kernel.shmmax should be:" 53 | echo -e "\e[1;33m kernel.shmmax = $PREF_SHMMAX \e[0m" 54 | echo 55 | echo 56 | echo 57 | 58 | 59 | echo "# add these too:" 60 | echo -e "\e[1;33m net.core.rmem_max = 4194304 \e[0m" 61 | echo -e "\e[1;33m net.core.wmem_max = 4194304 \e[0m" 62 | echo 63 | echo 64 | echo 65 | 66 | 67 | echo "# the following multiplied by the size of hugepages (on AMD EPYC = 2 MB) should be slightly bigger" 68 | echo "# than your shared_buffers setting in postgresql.conf (8 GB on systems with 32 GB memory in total)." 69 | echo -e "\e[1;33m vm.nr_hugepages = 5000 \e[0m" 70 | 71 | echo 72 | echo 73 | echo -e "\e[1;31m ################################################################################ \e[0m" 74 | echo -e "\e[1;31m ################################################################################ \e[0m" 75 | echo -e "\e[1;31m ################################################################################ \e[0m" 76 | echo 77 | echo 78 | 79 | echo -e "# add the following lines to \e[1;31m /etc/security/limits.conf \e[0m" 80 | 81 | echo -e "\e[1;33m postgres soft memlock \e[0m" 82 | echo -e "\e[1;33m postgres hard memlock \e[0m" 83 | 84 | echo 85 | echo 86 | 87 | # tune cpu parameters 88 | echo -e "# on bare metal machines set the cpu performance profile as follows:" 89 | echo -e "\e[1;33m tuned-adm profile throughput-performance \e[0m" 90 | 91 | # reduce swappiness 92 | echo 0 > /proc/sys/vm/swappiness 93 | -------------------------------------------------------------------------------- /build-postgres/postgres.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=PostgreSQL database server 3 | After=network.target 4 | 5 | [Service] 6 | Type=forking 7 | 8 | User=postgres 9 | Group=postgres 10 | 11 | # Where to send early-startup messages from the server (before the logging 12 | # options of postgresql.conf take effect) 13 | # This is normally controlled by the global default set by systemd 14 | # StandardOutput=syslog 15 | 16 | # Disable OOM kill on the postmaster 17 | OOMScoreAdjust=-1000 18 | # ... but allow it still to be effective for child processes 19 | # (note that these settings are ignored by Postgres releases before 9.5) 20 | Environment=PG_OOM_ADJUST_FILE=/proc/self/oom_score_adj 21 | Environment=PG_OOM_ADJUST_VALUE=0 22 | 23 | # Maximum number of seconds pg_ctl will wait for postgres to start. Note that 24 | # PGSTARTTIMEOUT should be less than TimeoutSec value. 25 | Environment=PGSTARTTIMEOUT=270 26 | Environment=PGDATA=/usr/local/pgsql/data 27 | 28 | ExecStart=/usr/local/pgsql/bin/pg_ctl start -D ${PGDATA} -s -w -t ${PGSTARTTIMEOUT} 29 | ExecStop=/usr/local/pgsql/bin/pg_ctl stop -D ${PGDATA} -s -m fast 30 | ExecReload=/usr/local/pgsql/bin/pg_ctl reload -D ${PGDATA} -s 31 | 32 | # Give a reasonable amount of time for the server to start up/shut down. 33 | # Ideally, the timeout for starting PostgreSQL server should be handled more 34 | # nicely by pg_ctl in ExecStart, so keep its timeout smaller than this value. 35 | TimeoutSec=300 36 | LimitMEMLOCK=10000000 37 | 38 | [Install] 39 | WantedBy=multi-user.target 40 | -------------------------------------------------------------------------------- /build-postgres/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | systemctl start postgres 4 | -------------------------------------------------------------------------------- /build-postgres/stop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | systemctl stop postgres 4 | -------------------------------------------------------------------------------- /cli/Dockerfile: -------------------------------------------------------------------------------- 1 | # Accept the full base image URL as a build argument 2 | ARG INDEXER_CLI_VERSION=ghcr.io/graphprotocol/indexer-cli:v0.21.6-2 3 | FROM ${INDEXER_CLI_VERSION} 4 | 5 | # Switch to root user to run apt-get commands 6 | USER root 7 | 8 | # Update and install necessary packages, specify netcat-openbsd explicitly 9 | RUN apt-get update && apt-get install -y \ 10 | build-essential \ 11 | bc \ 12 | git \ 13 | curl \ 14 | httpie \ 15 | jq \ 16 | nano \ 17 | wget \ 18 | bsdmainutils \ 19 | base58 \ 20 | netcat-openbsd \ 21 | net-tools \ 22 | libsecret-1-dev \ 23 | python3 24 | 25 | # Create /history directory for bash history persistence 26 | RUN mkdir -p /history && chmod 777 /history 27 | 28 | # Create necessary directory for graph-cli configuration 29 | RUN mkdir -p "/root/.config/graph-cli/" 30 | 31 | # Add the API configuration to the indexing.toml file 32 | RUN echo "api = \"http://indexer-agent:8000/\"" >> "/root/.config/graph-cli/indexing.toml" 33 | 34 | # Append history command to bashrc for history persistence 35 | RUN echo "export PROMPT_COMMAND='history -a' && export HISTFILE=/history/.bash_history" >> "/root/.bashrc" 36 | 37 | RUN mkdir -p /root/scripts 38 | WORKDIR /root/scripts 39 | 40 | # Override entrypoint to /bin/bash 41 | ENTRYPOINT ["/bin/bash"] 42 | 43 | # Default command to keep the container running 44 | CMD ["-c", "tail -f /dev/null"] -------------------------------------------------------------------------------- /cli/history/.bash_history: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /cli/scripts/poi: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | SUBGRAPH=$1 6 | MIN_EPOCH=$2 7 | EPOCH=$2 8 | MAX_EPOCH=$3 9 | SAFE_VERIFICATION_NUMBER=$4 10 | FULL_NODE=$5 11 | 12 | timestamp=$(date +%s) 13 | FILENAME="${SUBGRAPH}-${timestamp}" 14 | 15 | QUERY_NODE_STATUS_ENDPOINT=http://query-node-0:8030/graphql 16 | SUCCESSFUL_VERIFICATIONS=0 17 | FAILED_VERIFICATIONS=0 18 | 19 | if [[ -z "$QUERY_NODE_STATUS_ENDPOINT" ]] || [[ -z "$MAX_EPOCH" ]] || [[ -z "$MIN_EPOCH" ]] || [[ -z "$SAFE_VERIFICATION_NUMBER" ]] || [[ -z "$FILENAME" ]] ||[[ -z "$SUBGRAPH" ]]; then 20 | echo "Usage: $0 " 21 | echo 22 | echo "Example: $0 QmRhYzT8HEZ9LziQhP6JfNfd4co9A7muUYQhPMJsMUojSF 100 135 1 http://ip:port" 23 | exit 1 24 | fi 25 | 26 | echo "Epoch,Verified,Indexer ID,Allocation ID,Subgraph PoI,Verification PoI,Verification Try Number" >> ${FILENAME}-successful.csv 27 | echo "Epoch,Verified,Indexer ID,Allocation ID,Subgraph PoI,Verification PoI,Verification Try Number" >> ${FILENAME}-failed.csv 28 | echo "Epoch,Verified,Indexer ID,Allocation ID,Subgraph PoI,Verification PoI,Verification Try Number" >> ${FILENAME}.csv 29 | 30 | while [[ $EPOCH -le $MAX_EPOCH ]] 31 | do 32 | echo "Checking for epoch: $EPOCH" 33 | 34 | echo "Generating block numbers and hashes for the amount of verifications required ($SAFE_VERIFICATION_NUMBER)" 35 | HASHES=() 36 | NON_HEX_NUMBERS=() 37 | start_block_index=0 38 | while [[ $start_block_index -lt $SAFE_VERIFICATION_NUMBER ]] 39 | do 40 | START_BLOCK=$(http -b post https://gateway.thegraph.com/network query='query epoch($epoch: ID!) { epoch(id: $epoch) { startBlock } }' variables:="{ \"epoch\": \"$((($EPOCH-$start_block_index)))\" }" | jq .data.epoch.startBlock) 41 | START_BLOCK_HEX=$(printf '%x' $START_BLOCK) 42 | 43 | BLOCK_DATA=$(http -b post $FULL_NODE jsonrpc="2.0" id="1" method="eth_getBlockByNumber" params:="[\"0x$START_BLOCK_HEX\", false]" | jq -c '.result | { number, hash }') 44 | 45 | HASHES[$start_block_index]=$(echo $BLOCK_DATA | jq '.hash') 46 | NON_HEX_NUMBERS[$start_block_index]=$(echo "$BLOCK_DATA" | jq '.number' | xargs printf '%d') 47 | 48 | ((start_block_index=start_block_index+1)) 49 | done 50 | 51 | SUBGRAPH_VARIABLES="{\"ipfsHash\": \"$SUBGRAPH\"}" 52 | DEPLOYMENT=$(http -b post https://gateway.thegraph.com/network \ 53 | query='query deployment($ipfsHash: String!) {subgraphDeployments (where: {ipfsHash: $ipfsHash}) {id}}' \ 54 | variables:="$(echo $SUBGRAPH_VARIABLES)" | jq .data.subgraphDeployments[0].id) 55 | VARIABLES="{\"epoch\": $EPOCH, \"deployment\": $DEPLOYMENT}" 56 | 57 | POIS=$(http -b post https://gateway.thegraph.com/network \ 58 | query='query pois($epoch: Int!, $deployment: String!) {allocations (where: {closedAtEpoch: $epoch, subgraphDeployment_contains: $deployment, poi_not:"0x0000000000000000000000000000000000000000000000000000000000000000"}) {indexer {id} id poi closedAtEpoch}}' \ 59 | variables:="$(echo $VARIABLES)") 60 | echo $VARIABLES 61 | echo $POIS 62 | 63 | ### Loop 64 | length=$(echo $POIS | jq -r '.data.allocations' | jq length) 65 | index=0 66 | 67 | echo "Allocations found for epoch $EPOCH: $length" 68 | 69 | while [[ $index -lt $length ]] 70 | do 71 | echo "Processing allocation $((($index+1))) for epoch $EPOCH" 72 | echo "Generating verifications for allocation #$((($index+1)))" 73 | verifications=0 74 | verified=false 75 | while [[ $verifications -lt $start_block_index ]] 76 | do 77 | NON_HEX_NUMBER="${NON_HEX_NUMBERS[$verifications]}" 78 | HASH="${HASHES[$verifications]}" 79 | echo "Number: $NON_HEX_NUMBER" 80 | echo "Hash: $HASH" 81 | VARIABLES="{\"number\": $NON_HEX_NUMBER, \"hash\": $HASH, \"indexer\": \"$(echo $POIS | jq -r ".data.allocations[$index].indexer.id")\", \"subgraph\": \"$SUBGRAPH\"}" 82 | 83 | VERIFICATION=$(http -b post $QUERY_NODE_STATUS_ENDPOINT \ 84 | query='query poi($number: Int!, $hash: String!, $indexer: String!, $subgraph: String!) { proofOfIndexing(subgraph: $subgraph, blockNumber: $number, blockHash: $hash, indexer: $indexer) }' \ 85 | variables:="$(echo $VARIABLES)") 86 | 87 | if [ "$(echo $POIS | jq -r ".data.allocations[$index].poi")" = "$(echo $VERIFICATION | jq -r '.data.proofOfIndexing')" ]; then 88 | echo "POIs are equal. Amount of verifications done: $((($verifications+1)))" 89 | indexer_id=$(echo $POIS | jq -r ".data.allocations[$index].indexer.id") 90 | allocation_id=$(echo $POIS | jq -r ".data.allocations[$index].id") 91 | subgraph_poi=$(echo $POIS | jq -r ".data.allocations[$index].poi") 92 | verification_poi=$(echo $VERIFICATION | jq -r '.data.proofOfIndexing') 93 | echo "$EPOCH,true,$indexer_id,$allocation_id,$subgraph_poi,$verification_poi,$verifications" >> ${FILENAME}-successful.csv 94 | echo "$EPOCH,true,$indexer_id,$allocation_id,$subgraph_poi,$verification_poi,$verifications" >> ${FILENAME}.csv 95 | verified=true 96 | ((SUCCESSFUL_VERIFICATIONS=SUCCESSFUL_VERIFICATIONS+1)) 97 | break 98 | fi 99 | ((verifications=verifications+1)) 100 | done 101 | 102 | 103 | if [ "$verified" = false ]; then 104 | indexer_id=$(echo $POIS | jq -r ".data.allocations[$index].indexer.id") 105 | allocation_id=$(echo $POIS | jq -r ".data.allocations[$index].id") 106 | subgraph_poi=$(echo $POIS | jq -r ".data.allocations[$index].poi") 107 | verification_poi=$(echo $VERIFICATION | jq -r '.data.proofOfIndexing') 108 | echo "Indexer ID: $indexer_id" 109 | echo "Allocation ID: $allocation_id" 110 | echo "Subgraph PoI: $subgraph_poi" 111 | echo "Verification PoI: $verification_poi" 112 | echo "ALERT ALERT ALERT !!! POIs are not equal." 113 | echo "$EPOCH,false,$indexer_id,$allocation_id,$subgraph_poi,$verification_poi,$verifications" >> ${FILENAME}-failed.csv 114 | echo "$EPOCH,false,$indexer_id,$allocation_id,$subgraph_poi,$verification_poi,$verifications" >> ${FILENAME}.csv 115 | ((FAILED_VERIFICATIONS=FAILED_VERIFICATIONS+1)) 116 | fi 117 | 118 | echo "####" 119 | ((index=index+1)) 120 | done 121 | 122 | ((EPOCH=EPOCH+1)) 123 | done 124 | 125 | TOTAL=$((SUCCESSFUL_VERIFICATIONS+FAILED_VERIFICATIONS)) 126 | if command -v bc &> /dev/null; then 127 | SUCCESS_RATE=$(bc -l <<< "scale=2; ${SUCCESSFUL_VERIFICATIONS}*100/${TOTAL}") 128 | FAIL_RATE=$(bc -l <<< "scale=2; ${FAILED_VERIFICATIONS}*100/${TOTAL}") 129 | else 130 | echo "bc not installed, falling back to integer based division for success and fail rate" 131 | SUCCESS_RATE=$((SUCCESSFUL_VERIFICATIONS*100/TOTAL)) 132 | FAIL_RATE=$((FAILED_VERIFICATIONS*100/TOTAL)) 133 | fi 134 | 135 | echo "Successes: ${SUCCESSFUL_VERIFICATIONS}, Fails: ${FAILED_VERIFICATIONS}, Total: ${TOTAL}" 136 | echo "Success rate: ${SUCCESS_RATE}%, Fail rate: ${FAIL_RATE}%" 137 | -------------------------------------------------------------------------------- /compose-graphnode.yml: -------------------------------------------------------------------------------- 1 | networks: 2 | monitor-net: 3 | driver: bridge 4 | 5 | volumes: 6 | postgres_data: {} 7 | 8 | 9 | services: 10 | 11 | 12 | 13 | ###################################################################################### 14 | ##################### INDEX NODE CONTAINER 0 ####################### 15 | ###################################################################################### 16 | 17 | 18 | index-node-0: 19 | image: ${GRAPH_NODE_VERSION:-graphprotocol/graph-node:v0.35.1} 20 | container_name: index-node-0 21 | depends_on: 22 | - postgres 23 | volumes: 24 | - ./graph-node-configs:/root/graph-node-configs/ 25 | environment: 26 | GRAPH_NODE_CONFIG: /root/graph-node-configs/config.toml 27 | ipfs: '${IPFS_ENDPOINT:-https://ipfs.network.thegraph.com/ipfs/}' 28 | node_role: index-node 29 | node_id: index_node_0 30 | BLOCK_INGESTOR: index_node_0 31 | GRAPH_LOG: ${GRAPHNODE_LOGLEVEL:-DEBUG} 32 | GRAPH_ETH_CALL_GAS: 50000000 33 | GRAPH_GETH_ETH_CALL_ERRORS: "out of gas" 34 | GRAPH_MAX_GAS_PER_HANDLER: 1000000000000000 35 | GRAPH_KILL_IF_UNRESPONSIVE: "true" 36 | GRAPH_ALLOW_NON_DETERMINISTIC_FULLTEXT_SEARCH: ${FULLTEXT_SEARCH:-true} 37 | GRAPH_ALLOW_NON_DETERMINISTIC_IPFS: ${GRAPH_ALLOW_NON_DETERMINISTIC_IPFS:-true} 38 | EXPERIMENTAL_SUBGRAPH_VERSION_SWITCHING_MODE: synced 39 | ETHEREUM_POLLING_INTERVAL: ${RPC_POLLING_RATE:-500} 40 | GRAPH_ETH_CALL_NO_GAS: "421613,42161" 41 | restart: unless-stopped 42 | expose: 43 | - 8001 44 | - 8000 45 | - 8030 46 | - 8040 47 | networks: 48 | - monitor-net 49 | 50 | 51 | ###################################################################################### 52 | ##################### QUERY NODE CONTAINER 0 ####################### 53 | ###################################################################################### 54 | 55 | 56 | query-node-0: 57 | image: ${GRAPH_NODE_VERSION:-graphprotocol/graph-node:v0.35.1} 58 | container_name: query-node-0 59 | depends_on: 60 | - postgres 61 | volumes: 62 | - ./graph-node-configs:/root/graph-node-configs/ 63 | environment: 64 | GRAPH_NODE_CONFIG: /root/graph-node-configs/config.toml 65 | ipfs: '${IPFS_ENDPOINT:-https://ipfs.network.thegraph.com/ipfs/}' 66 | node_role: query-node 67 | node_id: query_node_0 68 | GRAPH_LOG: INFO 69 | GRAPH_ETH_CALL_GAS: 50000000 70 | GRAPH_GETH_ETH_CALL_ERRORS: "out of gas" 71 | GRAPH_MAX_GAS_PER_HANDLER: 1000000000000000 72 | EXPERIMENTAL_SUBGRAPH_VERSION_SWITCHING_MODE: synced 73 | GRAPH_KILL_IF_UNRESPONSIVE: "true" 74 | GRAPH_LOG_QUERY_TIMING: ${GRAPH_LOG_QUERY_TIMING:-gql} 75 | GRAPH_ALLOW_NON_DETERMINISTIC_FULLTEXT_SEARCH: ${FULLTEXT_SEARCH:-true} 76 | restart: unless-stopped 77 | logging: 78 | driver: "journald" 79 | expose: 80 | - 8001 81 | - 8000 82 | - 8020 83 | - 8030 84 | - 8040 85 | networks: 86 | - monitor-net 87 | 88 | 89 | ###################################################################################### 90 | ##################### POSTGRES CONTAINER ####################### 91 | ###################################################################################### 92 | 93 | 94 | 95 | postgres: 96 | image: ${POSTGRES_VERSION:-postgres:16.4} 97 | container_name: postgres 98 | command: ["postgres", "-c", "shared_preload_libraries=pg_stat_statements"] 99 | restart: unless-stopped 100 | environment: 101 | POSTGRES_USER: ${GRAPH_NODE_DB_USER:-your_db_user} 102 | POSTGRES_PASSWORD: ${GRAPH_NODE_DB_PASS:-your_db_password} 103 | POSTGRES_DB: ${GRAPH_NODE_DB_NAME:-your_graphnode_db_name} 104 | POSTGRES_INITDB_ARGS: "-E UTF8 --locale=C" 105 | volumes: 106 | - postgres_data:/var/lib/postgresql/data 107 | networks: 108 | - monitor-net 109 | expose: 110 | - 5432 111 | -------------------------------------------------------------------------------- /compose-indexer.yml: -------------------------------------------------------------------------------- 1 | networks: 2 | monitor-net: 3 | driver: bridge 4 | 5 | volumes: 6 | postgres-agent_data: {} 7 | subgraph-radio_data: {} 8 | 9 | x-indexer-environment: &indexer-environment 10 | INDEXER_INDEXER__INDEXER_ADDRESS: ${STAKING_WALLET_ADDRESS} 11 | INDEXER_INDEXER__OPERATOR_MNEMONIC: ${OPERATOR_SEED_PHRASE} 12 | INDEXER_METRICS__PORT: 7300 13 | INDEXER_DATABASE__POSTGRES_URL: "postgres://${AGENT_DB_USER}:${AGENT_DB_PASS}@${AGENT_DB_HOST}:5432/${AGENT_DB_NAME}" 14 | INDEXER_GRAPH_NODE__QUERY_URL: "http://query-node-0:8000" 15 | INDEXER_GRAPH_NODE__STATUS_URL: "http://index-node-0:8030/graphql" 16 | 17 | # Subgraphs - Network Configuration 18 | INDEXER_SUBGRAPHS__NETWORK__QUERY_URL: ${NETWORK_SUBGRAPH_ENDPOINT} 19 | # INDEXER_SUBGRAPHS__NETWORK__QUERY_AUTH_TOKEN: ${FREE_QUERY_AUTH_TOKEN} 20 | INDEXER_SUBGRAPHS__NETWORK__DEPLOYMENT_ID: ${NETWORK_SUBGRAPH_DEPLOYMENT} 21 | INDEXER_SUBGRAPHS__NETWORK__SYNCING_INTERVAL_SECS: ${NETWORK_SYNCING_INTERVAL_SECS:-60} 22 | INDEXER_SUBGRAPHS__NETWORK__RECENTLY_CLOSED_ALLOCATION_BUFFER_SECS: ${RECENTLY_CLOSED_ALLOCATION_BUFFER_SECS:-3600} 23 | 24 | # Subgraphs - Escrow Configuration 25 | INDEXER_SUBGRAPHS__ESCROW__QUERY_URL: ${NETWORK_ESCROW_ENDPOINT} 26 | # INDEXER_SUBGRAPHS__ESCROW__QUERY_AUTH_TOKEN: ${FREE_QUERY_AUTH_TOKEN} 27 | INDEXER_SUBGRAPHS__ESCROW__DEPLOYMENT_ID: ${NETWORK_ESCROW_DEPLOYMENT} 28 | INDEXER_SUBGRAPHS__ESCROW__SYNCING_INTERVAL_SECS: ${NETWORK_SYNCING_INTERVAL_SECS:-60} 29 | 30 | # Blockchain Configuration 31 | INDEXER_BLOCKCHAIN__CHAIN_ID: ${INDEXER_CHAIN_ID:-42161} 32 | INDEXER_BLOCKCHAIN__RECEIPTS_VERIFIER_ADDRESS: ${INDEXER_RECEIPTS_VERIFIER_ADDRESS:-0x33f9E93266ce0E108fc85DdE2f71dab555A0F05a} 33 | 34 | # Service Configuration 35 | INDEXER_SERVICE__HOST_AND_PORT: "0.0.0.0:7600" 36 | INDEXER_SERVICE__URL_PREFIX: "/" 37 | INDEXER_SERVICE__SERVE_NETWORK_SUBGRAPH: ${INDEXER_SERVE_NETWORK_SUBGRAPH:-false} 38 | INDEXER_SERVICE__SERVE_ESCROW_SUBGRAPH: ${INDEXER_SERVE_ESCROW_SUBGRAPH:-false} 39 | # INDEXER_SERVICE__SERVE_AUTH_TOKEN: ${FREE_QUERY_AUTH_TOKEN} 40 | # INDEXER_SERVICE__FREE_QUERY_AUTH_TOKEN: ${FREE_QUERY_AUTH_TOKEN} 41 | 42 | # TAP Configuration 43 | INDEXER_SERVICE__TAP__MAX_RECEIPT_VALUE_GRT: "0.001" 44 | INDEXER_TAP__MAX_AMOUNT_WILLING_TO_LOSE_GRT: "20" 45 | INDEXER_TAP__RAV_REQUEST__TRIGGER_VALUE_DIVISOR: "10" 46 | INDEXER_TAP__RAV_REQUEST__TIMESTAMP_BUFFER_SECS: "60" 47 | INDEXER_TAP__RAV_REQUEST__REQUEST_TIMEOUT_SECS: "5" 48 | INDEXER_TAP__RAV_REQUEST__MAX_RECEIPTS_PER_REQUEST: "10000" 49 | 50 | # TAP Sender Aggregator Endpoints 51 | INDEXER_TAP__SENDER_AGGREGATOR_ENDPOINTS__0xDDE4cfFd3D9052A9cb618fC05a1Cd02be1f2F467: "https://tap-aggregator.network.thegraph.com" 52 | 53 | services: 54 | 55 | ###################################################################################### 56 | ##################### CLI CONTAINER ####################### 57 | ###################################################################################### 58 | 59 | cli: 60 | build: 61 | context: ./cli 62 | dockerfile: Dockerfile 63 | args: 64 | INDEXER_CLI_VERSION: ${INDEXER_CLI_VERSION:-ghcr.io/graphprotocol/indexer-cli:v0.21.6-2} 65 | container_name: cli 66 | restart: unless-stopped 67 | environment: 68 | GEO_COORDINATES: ${GEO_COORDINATES:-69.42069 69.42069} 69 | tty: true 70 | networks: 71 | - monitor-net 72 | volumes: 73 | - ./cli/scripts:/root/scripts/ 74 | - ./cli/history:/history 75 | 76 | 77 | ###################################################################################### 78 | ##################### INDEXER AGENT CONTAINER ####################### 79 | ###################################################################################### 80 | 81 | indexer-agent: 82 | image: ${INDEXER_AGENT_VERSION:-ghcr.io/graphprotocol/indexer-agent:v0.21.6-2} 83 | container_name: indexer-agent 84 | depends_on: 85 | - postgres-agent 86 | expose: 87 | - 7300 88 | - 8000 89 | - 8001 90 | - 8002 91 | environment: 92 | INDEXER_AGENT_MNEMONIC: ${OPERATOR_SEED_PHRASE} 93 | INDEXER_AGENT_INDEXER_ADDRESS: ${STAKING_WALLET_ADDRESS} 94 | INDEXER_AGENT_INDEX_NODE_IDS: "index_node_0" 95 | #INDEXER_AGENT_INJECT_DAI: "true" 96 | INDEXER_AGENT_ALLOCATION_MANAGEMENT: ${INDEXER_AGENT_ALLOCATION_MANAGEMENT:-auto} 97 | INDEXER_AGENT_REBATE_CLAIM_THRESHOLD: ${REBATE_CLAIM_THRESHOLD:-0} 98 | INDEXER_AGENT_REBATE_CLAIM_BATCH_THRESHOLD: ${REBATE_CLAIM_BATCH_THRESHOLD:-0} 99 | INDEXER_AGENT_REBATE_CLAIM_MAX_BATCH_SIZE: ${REBATE_CLAIM_MAX_BATCH_SIZE:-100} 100 | INDEXER_AGENT_VOUCHER_REDEMPTION_THRESHOLD: ${VOUCHER_REDEMPTION_THRESHOLD:-0} 101 | INDEXER_AGENT_VOUCHER_REDEMPTION_BATCH_THRESHOLD: ${VOUCHER_REDEMPTION_BATCH_THRESHOLD:-0} 102 | INDEXER_AGENT_VOUCHER_REDEMPTION_MAX_BATCH_SIZE: ${VOUCHER_REDEMPTION_MAX_BATCH_SIZE:-100} 103 | INDEXER_AGENT_ETHEREUM_NETWORK: arbitrum 104 | INDEXER_AGENT_ETHEREUM: ${TXN_RPC} 105 | INDEXER_AGENT_GRAPH_NODE_QUERY_ENDPOINT: http://query-node-0:8000 106 | INDEXER_AGENT_GRAPH_NODE_STATUS_ENDPOINT: http://index-node-0:8030/graphql 107 | INDEXER_AGENT_GRAPH_NODE_ADMIN_ENDPOINT: http://index-node-0:8020 108 | INDEXER_AGENT_PUBLIC_INDEXER_URL: 'https://${INDEX_HOST}/' 109 | INDEXER_AGENT_INDEXER_GEO_COORDINATES: ${GEO_COORDINATES:-69.420 69.420} 110 | INDEXER_AGENT_NETWORK_SUBGRAPH_ENDPOINT: ${NETWORK_SUBGRAPH_ENDPOINT} 111 | INDEXER_AGENT_NETWORK_SUBGRAPH_DEPLOYMENT: ${NETWORK_SUBGRAPH_DEPLOYMENT} 112 | INDEXER_AGENT_EPOCH_SUBGRAPH_ENDPOINT: ${EPOCH_SUBGRAPH_ENDPOINT} 113 | INDEXER_AGENT_POSTGRES_HOST: ${AGENT_DB_HOST:-postgres-agent} 114 | INDEXER_AGENT_POSTGRES_USERNAME: ${AGENT_DB_USER:-your_db_user} 115 | INDEXER_AGENT_POSTGRES_PASSWORD: ${AGENT_DB_PASS:-your_db_password} 116 | INDEXER_AGENT_POSTGRES_DATABASE: ${AGENT_DB_NAME:-your_agent_db_name} 117 | INDEXER_AGENT_DAI_CONTRACT: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" 118 | INDEXER_AGENT_GATEWAY_ENDPOINT: https://gateway-arbitrum.network.thegraph.com/ 119 | INDEXER_AGENT_OFFCHAIN_SUBGRAPHS: ${INDEXER_AGENT_OFFCHAIN_SUBGRAPHS} 120 | INDEXER_AGENT_GAS_PRICE_MAX: ${INDEXER_AGENT_GAS_PRICE_MAX:-5000} 121 | INDEXER_AGENT_SUBGRAPH_MAX_BLOCK_DISTANCE: 1000 122 | INDEXER_AGENT_TAP_SUBGRAPH_ENDPOINT: ${NETWORK_ESCROW_ENDPOINT:-https://api.thegraph.com/subgraphs/name/graphprotocol/tap-escrow-subgraph} 123 | #INDEXER_AGENT_POI_DISPUTE_MONITORING: "true" 124 | #INDEXER_AGENT_POI_DISPUTABLE_EPOCHS: 100 125 | networks: 126 | - monitor-net 127 | restart: unless-stopped 128 | 129 | ###################################################################################### 130 | ##################### INDEXER SERVICE CONTAINER ####################### 131 | ###################################################################################### 132 | indexer-service: 133 | image: ${INDEXER_SERVICE_VERSION:-ghcr.io/graphprotocol/indexer-service-rs:1.3.2} 134 | container_name: indexer-service 135 | depends_on: 136 | - postgres-agent 137 | environment: 138 | RUST_LOG: ${INDEXER_SERVICE_LOG_LEVEL:-DEBUG} 139 | <<: *indexer-environment 140 | expose: 141 | - 7300 142 | - 7600 143 | networks: 144 | - monitor-net 145 | restart: unless-stopped 146 | labels: 147 | - "traefik.enable=true" 148 | - "traefik.http.services.indexer-service.loadbalancer.server.port=7600" 149 | - "traefik.http.routers.indexer-service.entrypoints=websecure" 150 | - "traefik.http.routers.indexer-service.tls.certresolver=myresolver" 151 | - "traefik.http.routers.indexer-service.rule=Host(`$INDEX_HOST`)" 152 | 153 | ###################################################################################### 154 | ###################### INDEXER TAP CONTAINER ########################## 155 | ###################################################################################### 156 | indexer-tap: 157 | image: ${INDEXER_TAP_VERSION:-ghcr.io/graphprotocol/indexer-tap-agent:1.7.2} 158 | container_name: indexer-tap 159 | depends_on: 160 | - postgres-agent 161 | environment: 162 | RUST_LOG: ${TAP_AGENT_LOG_LEVEL:-DEBUG} 163 | <<: *indexer-environment 164 | networks: 165 | - monitor-net 166 | restart: unless-stopped 167 | 168 | 169 | ###################################################################################### 170 | ##################### POSTGRES AGENT CONTAINER ####################### 171 | ###################################################################################### 172 | 173 | postgres-agent: 174 | image: ${POSTGRES_AGENT_VERSION:-postgres:16.4} 175 | container_name: postgres-agent 176 | command: ["postgres", "-c", "shared_preload_libraries=pg_stat_statements"] 177 | restart: unless-stopped 178 | environment: 179 | POSTGRES_USER: ${AGENT_DB_USER:-your_db_user} 180 | POSTGRES_PASSWORD: ${AGENT_DB_PASS:-your_db_password} 181 | POSTGRES_DB: ${AGENT_DB_NAME:-your_agent_db_name} 182 | volumes: 183 | - postgres-agent_data:/var/lib/postgresql/data 184 | networks: 185 | - monitor-net 186 | expose: 187 | - 5432 188 | 189 | ###################################################################################### 190 | ##################### SUBGRAPH RADIO CONTAINER ################## 191 | ###################################################################################### 192 | 193 | subgraph-radio: 194 | image: ghcr.io/graphops/subgraph-radio:1.0.6 195 | container_name: subgraph-radio 196 | expose: 197 | - 3010 198 | - 3012 199 | restart: unless-stopped 200 | environment: 201 | GRAPHCAST_NETWORK: ${GRAPHCAST_NETWORK:-mainnet} 202 | REGISTRY_SUBGRAPH: ${REGISTRY_SUBGRAPH_ENDPOINT} 203 | NETWORK_SUBGRAPH: ${NETWORK_SUBGRAPH_ENDPOINT} 204 | MNEMONIC: ${OPERATOR_SEED_PHRASE} 205 | GRAPH_NODE_STATUS_ENDPOINT: ${GRAPH_NODE_STATUS_ENDPOINT:-http://index-node-0:8030/graphql} 206 | RUST_LOG: ${RUST_LOG:-warn,hyper=warn,graphcast_sdk=info,subgraph_radio=info} 207 | INDEXER_ADDRESS: ${STAKING_WALLET_ADDRESS} 208 | METRICS_HOST: ${METRICS_HOST:-0.0.0.0} 209 | METRICS_PORT: ${METRICS_PORT:-3010} 210 | SERVER_PORT: ${SERVER_PORT:-3012} 211 | ID_VALIDATION: ${ID_VALIDATION:-indexer} 212 | GOSSIP_TOPIC_COVERAGE: ${COVERAGE:-comprehensive} 213 | SQLITE_FILE_PATH: ${SQLITE_FILE_PATH:-/data/state.sqlite} 214 | volumes: 215 | - subgraph-radio_data:/data 216 | networks: 217 | - monitor-net 218 | 219 | ###################################################################################### 220 | ##################### TRAEFIK PROXY CONTAINER ####################### 221 | ###################################################################################### 222 | 223 | traefik: 224 | image: traefik:latest 225 | container_name: traefik 226 | restart: always 227 | expose: 228 | - "8082" 229 | ports: 230 | - "443:443" 231 | - "80:80" 232 | command: 233 | - "--api=true" 234 | - "--api.insecure=true" 235 | - "--api.dashboard=true" 236 | - "--log.level=DEBUG" 237 | - "--providers.docker=true" 238 | - "--providers.docker.exposedbydefault=true" 239 | - "--providers.file.filename=/dynamic_config.yml" 240 | - "--entrypoints.websecure.address=:443" 241 | - "--entryPoints.metrics.address=:8082" 242 | - "--metrics.prometheus.entryPoint=metrics" 243 | - "--certificatesresolvers.myresolver.acme.tlschallenge=true" 244 | # TESTING 245 | - "--certificatesresolvers.myresolver.acme.email=$EMAIL" 246 | - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json" 247 | volumes: 248 | - "./traefik/letsencrypt:/letsencrypt" 249 | - "./traefik/config/dynamic_config.yml:/dynamic_config.yml" 250 | - "/var/run/docker.sock:/var/run/docker.sock:ro" 251 | networks: 252 | - monitor-net 253 | labels: 254 | - "traefik.enable=true" 255 | -------------------------------------------------------------------------------- /compose-monitoring.yml: -------------------------------------------------------------------------------- 1 | networks: 2 | monitor-net: 3 | driver: bridge 4 | 5 | volumes: 6 | prometheus_data: {} 7 | grafana_data: {} 8 | loki_data: {} 9 | 10 | services: 11 | 12 | 13 | ###################################################################################### 14 | ##################### LOKI CONTAINER ####################### 15 | ###################################################################################### 16 | 17 | init-loki: 18 | image: busybox:latest 19 | command: sh -c "chown -R 10001:10001 /data" 20 | volumes: 21 | - loki_data:/data 22 | entrypoint: "" 23 | deploy: 24 | restart_policy: 25 | condition: none 26 | 27 | loki: 28 | image: grafana/loki 29 | container_name: loki 30 | volumes: 31 | - loki_data:/data 32 | - ./loki/loki.yaml:/etc/loki/config.yaml 33 | command: -config.file=/etc/loki/config.yaml --print-config-stderr 34 | expose: 35 | - 3100 36 | restart: unless-stopped 37 | depends_on: 38 | - init-loki 39 | networks: 40 | - monitor-net 41 | 42 | ###################################################################################### 43 | ##################### PROMTAIL CONTAINER ####################### 44 | ###################################################################################### 45 | 46 | 47 | promtail: 48 | image: grafana/promtail:latest 49 | container_name: promtail 50 | volumes: 51 | - ./promtail/promtail.yaml:/etc/promtail/docker-config.yaml 52 | - /var/lib/docker/containers:/var/lib/docker/containers:ro 53 | - /var/run/docker.sock:/var/run/docker.sock 54 | - /var/log:/var/log:ro 55 | command: -config.file=/etc/promtail/docker-config.yaml 56 | restart: unless-stopped 57 | networks: 58 | - monitor-net 59 | 60 | 61 | ###################################################################################### 62 | ##################### PROMETHEUS CONTAINER ####################### 63 | ###################################################################################### 64 | 65 | 66 | 67 | prometheus: 68 | image: prom/prometheus 69 | container_name: prometheus 70 | volumes: 71 | - ./prometheus:/etc/prometheus 72 | - prometheus_data:/prometheus 73 | command: 74 | - '--config.file=/etc/prometheus/prometheus.yml' 75 | - '--storage.tsdb.path=/prometheus' 76 | - '--web.console.libraries=/etc/prometheus/console_libraries' 77 | - '--web.console.templates=/etc/prometheus/consoles' 78 | - '--storage.tsdb.retention.time=1y' 79 | - '--web.enable-lifecycle' 80 | restart: unless-stopped 81 | expose: 82 | - 9090 83 | networks: 84 | - monitor-net 85 | 86 | 87 | 88 | ###################################################################################### 89 | ##################### ALERT MANAGER CONTAINER ####################### 90 | ###################################################################################### 91 | 92 | 93 | 94 | alertmanager: 95 | image: prom/alertmanager 96 | container_name: alertmanager 97 | volumes: 98 | - ./alertmanager:/etc/alertmanager 99 | command: 100 | - '--config.file=/etc/alertmanager/config.yml' 101 | - '--storage.path=/alertmanager' 102 | restart: unless-stopped 103 | expose: 104 | - 9093 105 | networks: 106 | - monitor-net 107 | 108 | 109 | 110 | ###################################################################################### 111 | ##################### NODE EXPORTER CONTAINER ####################### 112 | ###################################################################################### 113 | 114 | 115 | 116 | nodeexporter: 117 | image: prom/node-exporter 118 | container_name: nodeexporter 119 | volumes: 120 | - /proc:/host/proc:ro 121 | - /sys:/host/sys:ro 122 | - /:/rootfs:ro 123 | command: 124 | - '--path.procfs=/host/proc' 125 | - '--path.rootfs=/rootfs' 126 | - '--path.sysfs=/host/sys' 127 | - '--collector.filesystem.ignored-mount-points=^/(sys|proc|dev|host|etc)($$|/)' 128 | restart: unless-stopped 129 | expose: 130 | - 9100 131 | networks: 132 | - monitor-net 133 | 134 | 135 | 136 | ###################################################################################### 137 | ##################### CADVISOR CONTAINER ####################### 138 | ###################################################################################### 139 | 140 | 141 | 142 | cadvisor: 143 | image: gcr.io/cadvisor/cadvisor:v0.47.2 144 | container_name: cadvisor 145 | command: --enable_metrics=cpu,memory,network --store_container_labels=false --docker_only=true 146 | volumes: 147 | - /:/rootfs:ro 148 | - /var/run:/var/run:rw 149 | - /sys:/sys:ro 150 | - /var/lib/docker:/var/lib/docker:ro 151 | - /cgroup:/cgroup:ro #doesn't work on MacOS only for Linux 152 | restart: unless-stopped 153 | expose: 154 | - 8080 155 | networks: 156 | - monitor-net 157 | labels: 158 | org.label-schema.group: "monitoring" 159 | 160 | 161 | 162 | ###################################################################################### 163 | ##################### GRAFANA CONTAINER ####################### 164 | ###################################################################################### 165 | 166 | 167 | 168 | grafana: 169 | image: grafana/grafana 170 | container_name: grafana 171 | volumes: 172 | - grafana_data:/var/lib/grafana 173 | - ./grafana/provisioning:/etc/grafana/provisioning 174 | environment: 175 | - GF_SECURITY_ADMIN_USER=${ADMIN_USER:-admin} 176 | - GF_SECURITY_ADMIN_PASSWORD=${ADMIN_PASSWORD:-admin} 177 | - GF_USERS_ALLOW_SIGN_UP=false 178 | - GF_SECURITY_DISABLE_BRUTE_FORCE_LOGIN_PROTECTION=true 179 | - GF_INSTALL_PLUGINS=yesoreyeram-infinity-datasource 180 | - postgres_host=${GRAPH_NODE_DB_HOST:-postgres} 181 | - postgres_user=${GRAPH_NODE_DB_USER:-your_db_user} 182 | - postgres_pass=${GRAPH_NODE_DB_PASS:-your_db_password} 183 | - postgres_db=${GRAPH_NODE_DB_NAME:-your_graphnode_db_name} 184 | restart: unless-stopped 185 | expose: 186 | - 3000 187 | networks: 188 | - monitor-net 189 | labels: 190 | - "org.label-schema.group=monitoring" 191 | - "traefik.enable=true" 192 | - "traefik.http.services.grafana.loadbalancer.server.port=3000" 193 | - "traefik.http.routers.grafana.entrypoints=websecure" 194 | - "traefik.http.routers.grafana.tls.certresolver=myresolver" 195 | - "traefik.http.routers.grafana.rule=Host(`$GRAFANA_HOST`)" 196 | 197 | 198 | 199 | ###################################################################################### 200 | ##################### PUSHGATEWAY CONTAINER ####################### 201 | ###################################################################################### 202 | 203 | 204 | 205 | pushgateway: 206 | image: prom/pushgateway 207 | container_name: pushgateway 208 | restart: unless-stopped 209 | expose: 210 | - 9091 211 | networks: 212 | - monitor-net -------------------------------------------------------------------------------- /compose-optional.yml: -------------------------------------------------------------------------------- 1 | networks: 2 | monitor-net: 3 | driver: bridge 4 | 5 | ###################################################################################### 6 | ##################### POIFIER CONTAINER ####################### 7 | ###################################################################################### 8 | 9 | poifier: 10 | image: grassets/poifier-client:v2.0.3 11 | container_name: poifier 12 | command: 13 | - "--poifier-server=https://poifier.io" 14 | - "--graph-node-status-endpoint=http://index-node-0:8030/graphql" 15 | - "--mnemonic=${OPERATOR_SEED_PHRASE}" 16 | - "--indexer-address=${STAKING_WALLET_ADDRESS}" 17 | - "--indexer-agent-epoch-subgraph-endpoint=${INDEXER_AGENT_EPOCH_SUBGRAPH_ENDPOINT:-https://api.thegraph.com/subgraphs/name/graphprotocol/mainnet-epoch-block-oracle}" 18 | tty: true 19 | networks: 20 | - monitor-net 21 | restart: unless-stopped 22 | 23 | ###################################################################################### 24 | ##################### INDEXER AGENT GUI ####################### 25 | ###################################################################################### 26 | 27 | indexer-agent-gui: 28 | image: ${INDEXER_AGENT_GUI:-ghcr.io/stakemachine/indexer-agent-ui:v0.2.1} 29 | container_name: indexer-agent-gui 30 | expose: 31 | - 3000 32 | environment: 33 | - UI_LOGIN=${ADMIN_USER:-test} 34 | - UI_PASS=${ADMIN_PASSWORD:-pass} 35 | - AGENT_ENDPOINT=${INDEXER_AGENT_ENDPOINT:-http://indexer-agent:8000} 36 | - SUBGRAPH_ENDPOINT=${INDEXER_AGENT_NETWORK_SUBGRAPH_ENDPOINT:-https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-mainnet} 37 | - NEXTAUTH_SECRET=${NEXTAUTH_SECRET} 38 | - NEXTAUTH_URL=https://${AGENT_GUI_HOST}/ 39 | restart: unless-stopped 40 | networks: 41 | - monitor-net 42 | logging: *default-logging 43 | labels: 44 | - "traefik.enable=true" 45 | - "traefik.http.services.indexer-agent-gui.loadbalancer.server.port=3000" 46 | - "traefik.http.routers.indexer-agent-gui.entrypoints=websecure" 47 | - "traefik.http.routers.indexer-agent-gui.tls.certresolver=myresolver" 48 | - "traefik.http.routers.indexer-agent-gui.rule=Host(`$AGENT_GUI_HOST`)" 49 | -------------------------------------------------------------------------------- /docs/allocations.md: -------------------------------------------------------------------------------- 1 | #### Table of contents 2 | 3 | - [README.md](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/README.md) 4 | - [Pre-requisites](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/pre-requisites.md) 5 | - [Getting Started](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/getting-started.md) 6 | - [Advanced Configuration](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/advanced-config.md) 7 | - [Setting Up Allocations](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/allocations.md) <- you are here 8 | - [Setting Up Cost Models](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/costmodels.md) 9 | - [Tips and Tricks](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/tips.md) 10 | - [Troubleshooting](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/troubleshooting.md) 11 | 12 | 13 | ## Working environment 14 | 15 | To open or close allocations, we will be using the `cli` container. 16 | 17 | Get into the `cli` container by running the following command inside the root of the repository 18 | 19 | ```bash 20 | ./shell cli 21 | 22 | ``` 23 | 24 | Now we have access to both `graph-cli` and the `indexer-cli` as an extension to the former. 25 | 26 | To get more information about the available `graph` commands use the following: 27 | 28 | ```bash 29 | graph --help 30 | graph indexer --help 31 | 32 | 33 | ``` 34 | 35 | 36 | 37 | ## Understanding Subgraph Allocations 38 | 39 | In order to get a better understanding around Subgraph Allocations as an indexer, I would highly recommend reading the following article, written by Jim from WaveFive, along with the Network Overview blogposts written by Brandon. 40 | 41 | - https://wavefive.notion.site/The-Graph-Protocol-Indexer-Subgraph-Selection-Guide-725f6e575f6e4024ad7e50f2f4e9bbad 42 | - https://thegraph.com/blog/the-graph-network-in-depth-part-1 43 | - https://thegraph.com/blog/the-graph-network-in-depth-part-2 44 | 45 | 46 | Without a thorough understanding of the Protocol economics, you won't be profitable. So before jumping to anything else, give those links a read. 47 | 48 | 49 | 50 | ## Opening Allocations 51 | 52 | Once you read those links above and you know exactly what your plan is, and what you're doing, then make it to the Graph Explorer (https://thegraph.com/explorer), find the subgraphs that you want to allocate towards, and copy their IPFS hash (Deployment ID). 53 | 54 | ![ipfs_hash](https://i.ibb.co/BjKd9s7/image.png) 55 | 56 | 57 | Now, to allocate towards your chosen subgraph, inside the cli container, run the following command: 58 | 59 | ```bash 60 | graph indexer rules set allocationAmount decisionBasis always 61 | 62 | 63 | ``` 64 | 65 | This will trigger the `indexer-agent` to send an allocation transaction on the network, and once that's confirmed, you've successfully allocated to the subgraph of your choice! 66 | 67 | 68 | ## Reviewing your allocations using the indexer-cli 69 | 70 | ### Review local database of allocations 71 | 72 | We can use the following command with the indexer-cli: 73 | 74 | 75 | ```bash 76 | graph indexer rules get all 77 | 78 | ``` 79 | 80 | This will give us a table with all the allocations that we've set up. It doesn't check for on-chain allocations, as it's only displaying the allocation rules found in your agent database. 81 | 82 | ### Check for onchain allocations via the indexer-cli 83 | 84 | We can use the following command with the indexer-cli: 85 | 86 | ```bash 87 | graph indexer status 88 | 89 | 90 | ``` 91 | 92 | This will give you information about the status of your endpoints, and also display current on-chain allocations and their status. 93 | 94 | ### Check for onchain allocations via the Graph Explorer and other 3rd party tools 95 | 96 | You can easily see if you've successfully allocated to a subgraph by going to your indexer profile on the Graph Explorer, or other 3rd party tools. 97 | 98 | - https://thegraph.com/explorer/participants/indexers 99 | - https://graphscan.io/#indexers 100 | - https://www.graphtronauts.com/#/indexers 101 | - https://maplenodes.com/graph/indexers/ 102 | - https://indexer-tools.vincenttaglia.com/ 103 | 104 | You simply have to search for your indexer address (staking wallet) to find out if your allocations are set on-chain. 105 | 106 | 107 | ### Check for onchain allocations via querying the Network Subgraph 108 | 109 | Another, more direct, way of checking for successful allocations onchain, would be to query the Network Subgraph for your indexer address, with the following query: 110 | 111 | - https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-mainnet/graphql 112 | 113 | ```bash 114 | query MyQuery { 115 | allocations( 116 | where: {activeForIndexer: ""} 117 | ) { 118 | id 119 | subgraphDeployment { 120 | ipfsHash 121 | originalName 122 | } 123 | } 124 | } 125 | 126 | 127 | ``` 128 | 129 | 130 | 131 | ## Closing allocations 132 | 133 | To close allocations, you have two options: 134 | 135 | First option would be to run the same command that you used to allocate, but chainging the `decisionBasis` to `never`: 136 | 137 | ```bash 138 | graph indexer rules set decisionBasis never 139 | 140 | 141 | ``` 142 | 143 | This will trigger the `indexer-agent` to send an allocation closure transaction on the network, and once that's confirmed, you've successfully unallocated off that subgraph! 144 | 145 | The second option would be to just delete the allocation from the rules database. This also makes things much more nice and tidy, especially if you use the `get rules all` command all the time. 146 | 147 | ```bash 148 | graph indexer rules delete 149 | 150 | 151 | ``` 152 | 153 | Or you can delete all the rules via 154 | 155 | ```bash 156 | graph indexer rules delete all 157 | 158 | 159 | ``` 160 | 161 | 162 | ## The life of an allocation 163 | 164 | After being created by an indexer a healthy allocation goes through four states. 165 | 166 | - **Active** - Once an allocation is created on-chain ([allocateFrom()](https://github.com/graphprotocol/contracts/blob/master/contracts/staking/Staking.sol#L873)) it is considered **active**. A portion of the indexer's own and/or delegated stake is allocated towards a subgraph deployment, which allows them to claim indexing rewards and serve queries for that subgraph deployment. The indexer agent manages creating allocations based on the indexer rules. 167 | 168 | - **Closed** - An indexer is free to close an allocation once 1 epoch has passed ([closeAllocation()](https://github.com/graphprotocol/contracts/blob/master/contracts/staking/Staking.sol#L873)) or their indexer agent will automatically close the allocation after the **maxAllocationEpochs** (currently 28 days). When an allocation is closed with a valid proof of indexing (POI) their indexing rewards are distributed to the indexer and its delegators (see "how are rewards distributed?" below to learn more). 169 | 170 | - **Finalized** - Once an allocation has been closed there is a dispute period after which the allocation is considered **finalized** and it's query fee rebates are available to be claimed (claim()). The indexer agent monitors the network to detect **finalized** allocations and claims them if they are above a configurable (and optional) threshold, **—-allocation-claim-threshold**. 171 | 172 | - **Claimed** - The final state of an allocation; it has run its course as an active allocation, all eligible rewards have been distributed and its query fee rebates have been claimed. 173 | 174 | 175 | 176 | #### Table of contents 177 | 178 | - [README.md](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/README.md) 179 | - [Pre-requisites](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/pre-requisites.md) 180 | - [Getting Started](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/getting-started.md) 181 | - [Advanced Configuration](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/advanced-config.md) 182 | - [Setting Up Allocations](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/allocations.md) <- you are here 183 | - [Setting Up Cost Models](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/costmodels.md) 184 | - [Tips and Tricks](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/tips.md) 185 | - [Troubleshooting](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/troubleshooting.md) 186 | -------------------------------------------------------------------------------- /docs/costmodels.md: -------------------------------------------------------------------------------- 1 | #### Table of contents 2 | 3 | - [README.md](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/README.md) 4 | - [Pre-requisites](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/pre-requisites.md) 5 | - [Getting Started](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/getting-started.md) 6 | - [Advanced Configuration](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/advanced-config.md) 7 | - [Setting Up Allocations](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/allocations.md) 8 | - [Setting Up Cost Models](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/costmodels.md) <- you are here 9 | - [Tips and Tricks](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/tips.md) 10 | - [Troubleshooting](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/troubleshooting.md) 11 | 12 | 13 | 14 | ## Managing cost models 15 | 16 | ### What are cost models? 17 | 18 | Cost models are indexer tools that they can use in order to set a price for the data that they serve. 19 | 20 | You cannot earn GRT for the queries that you serve without a cost model. 21 | 22 | The cost models are denominated in decimal GRT. 23 | 24 | **Cost models can have two parts:** 25 | 26 | - The model — should contain the queries that you want to price 27 | - The variables — should contain the variables that the queries use 28 | 29 | You can either have a static, simple cost model, or you can dive into complicated cost models based on your database access times for different queries that you serve across different subgraphs, etc. 30 | 31 | The decision here is totally up to you 🙂 32 | 33 | ### How does a model look like? 34 | 35 | **The easiest cost model you can set, can look something like this:** 36 | 37 | ```bash 38 | default => price; 39 | 40 | or 41 | 42 | query {...} => price; 43 | 44 | ``` 45 | 46 | **Example — you're serving every query at 0.01 GRT / query** 47 | 48 | ```bash 49 | default => 0.01; 50 | 51 | ``` 52 | 53 | ### How to set a default cost model? 54 | 55 | Connect to your CLI 56 | 57 | ``` 58 | ./shell cli 59 | ``` 60 | 61 | Create a default cost model by creating a default file using `nano default` and the adding the following to the new file. 62 | ``` 63 | default => 0.00005; 64 | ``` 65 | **Note: This will serve each query at 0.00005 GRT / query** 66 | 67 | Save and exit the file, then apply this setting to each of your indexed subgraphs 68 | ``` 69 | graph indexer cost set model default 70 | ``` 71 | 72 | Once you have applied the default cost model to each you can review them by typeing `graph indexer cost get all` 73 | 74 | 75 | ### How do the variables look like? 76 | 77 | ```json 78 | { 79 | "VALUE-1": "10.0006390502074853", 80 | "VALUE-2": "5", 81 | "VALUE-3": "3", 82 | "VALUE-4": "1" 83 | } 84 | 85 | ``` 86 | 87 | --------------------- 88 | 89 | 90 | #### Table of contents 91 | 92 | - [README.md](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/README.md) 93 | - [Pre-requisites](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/pre-requisites.md) 94 | - [Getting Started](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/getting-started.md) 95 | - [Advanced Configuration](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/advanced-config.md) 96 | - [Setting Up Allocations](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/allocations.md) 97 | - [Setting Up Cost Models](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/costmodels.md) <- you are here 98 | - [Tips and Tricks](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/tips.md) 99 | - [Troubleshooting](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/troubleshooting.md) 100 | -------------------------------------------------------------------------------- /docs/getting-started.md: -------------------------------------------------------------------------------- 1 | #### Table of contents 2 | 3 | - [README.md](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/README.md) 4 | - [Pre-requisites](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/pre-requisites.md) 5 | - [Getting Started](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/getting-started.md) <- you are here 6 | - [Advanced Configuration](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/advanced-config.md) 7 | - [Setting Up Allocations](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/allocations.md) 8 | - [Setting Up Cost Models](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/costmodels.md) 9 | - [Tips and Tricks](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/tips.md) 10 | - [Troubleshooting](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/troubleshooting.md) 11 | 12 | ## Install from scratch 13 | 14 | Run the following commands to clone the repository and set everything up: 15 | 16 | ```bash 17 | git clone git@github.com:StakeSquid/graphprotocol-mainnet-docker.git 18 | cd graphprotocol-mainnet-docker 19 | git submodule init 20 | git submodule update 21 | git config --global user.email "you@example.com" 22 | git config --global user.name "Example User" 23 | git branch --set-upstream-to=origin 24 | 25 | 26 | ``` 27 | 28 | ## Get a domain 29 | 30 | To enable SSL on your host you should get a domain. 31 | 32 | You can use any domain and any regsitrar that allowes you to edit DNS records to point subdomains to your IP address. 33 | 34 | For a free option go to [myFreenom](https://my.freenom.com/) and find a free domain name. Create a account and complete the registration. 35 | 36 | In the last step choose "use dns" and enter the IP address of your server. You can choose up to 12 months for free. 37 | 38 | Under "Service > My Domains > Manage Domain > Manage Freenom DNS" you can add more subdomains later. 39 | 40 | Create 2 subdomains, named as follows: 41 | 42 | ``` 43 | index.sld.tld 44 | grafana.sld.tld 45 | ``` 46 | 47 | ## Create a mnemonic 48 | 49 | You need a wallet with a seed phrase that is registered as your operator wallet. This wallet will be the one that makes transactions on behalf of your main wallet (which holds and stakes the GRT). 50 | 51 | The operator wallet has limited functionality, and it's recommended to be used for security reasons. 52 | 53 | **_You need a 12-word, or 15-word mnemonic phrase in order for it to work._** 54 | 55 | To make yourself a mnemonic eth wallet you can go to this [website](https://iancoleman.io/bip39/), select ETH from the dropdown and press generate. 56 | 57 | You get a seed phrase in the input field labeled BIP39 Mnemonic. 58 | 59 | You can find your address, public key and private key in the first row of the table if you scroll down the page in the section with the heading "Derived Addresses". 60 | 61 | **Make sure you save the mnemonic, private key and the wallet address somewhere safe.** 62 | 63 | If you need, you can import the wallet using the private key into Metamask 64 | 65 | ## Configure the environment variables 66 | 67 | Edit the file called `.env` and add your values to the following envs: 68 | 69 | ```bash 70 | EMAIL=email@sld.tld 71 | INDEX_HOST=index.sld.tld 72 | GRAFANA_HOST=grafana.sld.tld 73 | AGENT_GUI_HOST=agent.sld.tld 74 | ADMIN_USER=your_user 75 | ADMIN_PASSWORD=your_password 76 | DB_USER=your_db_user 77 | DB_PASS=your_db_password 78 | GRAPH_NODE_DB_NAME=your_graphnode_db_name 79 | AGENT_DB_NAME=your_agent_db_name 80 | CHAIN_0_NAME="network-name" 81 | CHAIN_0_RPC="http://ip:port" 82 | TXN_RPC="http://ip:port" 83 | OPERATOR_SEED_PHRASE="12 or 15 word mnemonic" 84 | STAKING_WALLET_ADDRESS=0xAdDreSs 85 | GEO_COORDINATES='69.420 69.420' 86 | INDEXER_AGENT_OFFCHAIN_SUBGRAPHS="" 87 | 88 | # Optional env vars depending on which services you use: 89 | 90 | ### Indexer agent GUI: 91 | # AGENT_GUI_HOST=agent.sld.tld 92 | # NEXTAUTH_SECRET=$(openssl rand -base64 32) 93 | 94 | ### POIfier 95 | # POIFIER_TOKEN=token 96 | 97 | ### Graphcast Subgraph Radio 98 | # PRIVATE_KEY= 99 | # GRAPHCAST_NETWORK= 100 | # REGISTRY_SUBGRAPH= 101 | # NETWORK_SUBGRAPH= 102 | # GRAPH_NODE_STATUS_ENDPOINT= 103 | # RUST_LOG= 104 | # INDEXER_ADDRESS= 105 | # METRICS_HOST= 106 | 107 | # If you change METRICS_PORT, make sure to also change the subgraph-radio job's targets in 108 | # prometheus/prometheus.yml, from targets: ['subgraph-radio:3010'] to targets: ['subgraph-radio:YOUR_NEW_PORT'] 109 | # METRICS_PORT= 110 | 111 | # SERVER_PORT= 112 | # ID_VALIDATION= 113 | # COVERAGE= 114 | # PERSISTENCE_FILE_PATH= 115 | ``` 116 | 117 | ### Required env vars 118 | 119 | - `EMAIL` - only used as contact to create SSL certificates. Usually it doesn't receive any emails but is required by the certificate issuer. 120 | - `INDEX_HOST` - your indexer public endpoint. The gateway will be sending queries to this endpoint. 121 | - `GRAFANA_HOST` - your Grafana dashboard for indexer stack monitoring. 122 | - `ADMIN_USER` and `ADMIN_PASSWORD` - will be used by Grafana, Prometheus and AlertManager. 123 | - `DB_USER` and `DB_PASS` - will be used for initializing the PostgreSQL Databases (both index/query DB and indexer agent/service DB). 124 | - `GRAPH_NODE_DB_NAME` - the name of the database used by the Index/Query nodes. 125 | - `AGENT_DB_NAME` - the name of the database used by the Indexer agent/service nodes. 126 | - `CHAIN_0_NAME` - the name of the network that you want to index 127 | - `CHAIN_0_RPC` - your RPCs (archive nodes) used by the index nodes. 128 | - `TXN_RPC` - your Goerli ETH RPC used by Indexer agent/service nodes. This can be a fast/full/archive node, up to you! Please note that using Erigon as the TXN_RPC has proven unreliable by some indexers. 129 | - `OPERATOR_SEED_PHRASE` - the 12/15 word mnemonic that you generated earlier. Will be used by the Agent/Service to send transactions (open/close allocations, etc) 130 | - `STAKING_WALLET_ADDRESS` - the address (0x...) that you staked your GRT with, ideally living on an entirely different mnemonic phrase than your Operator Wallet. 131 | - `GEO_COORDINATES` of your server - you can search for an ip location website and check your server exact coordinates. 132 | 133 | ### Optional env vars 134 | 135 | **Note:** If you want to use any of the optional env vars, you need to copy the line that you want to enable above the last line, and uncomment it. 136 | 137 | #### Agent GUI 138 | 139 | - `AGENT_GUI_HOST` - your Agent GUI endpoint for controlling the Agent and allocations remotely 140 | - `NEXTAUTH_SECRET` - used by the Agent GUI to salt your password 141 | 142 | #### POIfier 143 | 144 | - `POIFIER_TOKEN` - Auth token for POIfier-client 145 | 146 | #### Graphcast Subgraph Radio 147 | 148 | There are a number of optional env vars available to configure [Subgraph Radio](https://github.com/graphops/subgraph-radio), you can learn more about them [here](https://docs.graphops.xyz/graphcast/radios/subgraph-radio#basic-configuration). 149 | 150 | ## Supporting multiple chains 151 | 152 | To add support for multiple chains, you need to edit the [config.tmpl](https://github.com/StakeSquid/graphprotocol-testnet-docker/blob/master/graph-node-configs/config.tmpl) file yourself. 153 | 154 | For each chain you wish to support, you need to add the corresponding provider line. 155 | 156 | **Example:** 157 | 158 | By default, we only support one chain: 159 | 160 | ```toml 161 | [chains.${CHAIN_0_NAME}] 162 | shard = "primary" 163 | provider = [ { label = "${CHAIN_0_NAME}", url = "${CHAIN_0_RPC}", features = ["archive", "traces"] } ] 164 | ``` 165 | 166 | To add another one, simply duplicate this, and increment the chain number: 167 | 168 | ```toml 169 | [chains.${CHAIN_0_NAME}] 170 | shard = "primary" 171 | provider = [ { label = "${CHAIN_0_NAME}", url = "${CHAIN_0_RPC}", features = ["archive", "traces"] } ] 172 | 173 | [chains.${CHAIN_1_NAME}] 174 | shard = "primary" 175 | provider = [ { label = "${CHAIN_1_NAME}", url = "${CHAIN_1_RPC}", features = ["archive", "traces"] } ] 176 | ``` 177 | 178 | After this, all you have to do is to include in the [.env file](https://github.com/StakeSquid/graphprotocol-testnet-docker/blob/master/.env) your new environment variables. 179 | 180 | **Example:** 181 | 182 | ``` 183 | CHAIN_0_NAME="gnosis" 184 | CHAIN_0_RPC="http://ip:port" 185 | CHAIN_1_NAME="matic" 186 | CHAIN_1_RPC="http://ip:port" 187 | ``` 188 | 189 | **Additional configs and details:** 190 | 191 | - Agent/Service - [networks.md](https://github.com/graphprotocol/indexer/blob/main/docs/networks.md) 192 | - Graph-Node - [environment-variables.md](https://github.com/graphprotocol/graph-node/blob/master/docs/environment-variables.md) 193 | 194 | ## Containers in each configuration: 195 | 196 | **Graphnode Stack:** 197 | 198 | - Index Node 199 | - Query Node 200 | - Postgres Database for the Graphnode Stack 201 | 202 | **Indexer Stack:** 203 | 204 | - Indexer Agent 205 | - Indexer Service 206 | - Indexer CLI 207 | - Nginx Proxy 208 | - Nginx SSL 209 | - Posgres Database for the Indexer Stack 210 | - [Subgraph Radio](https://docs.graphops.xyz/graphcast/radios/subgraph-radio) 211 | 212 | **Autoagora Stack:** 213 | 214 | - Indexer Service 215 | - Rabbitmq 216 | - Autoagora Processor 217 | - Autoagora 218 | - Nginx Proxy 219 | - Nginx SSL 220 | - Posgres Database for the Indexer Stack 221 | - Posgres Database for the Autoagora Stack 222 | 223 | **Monitoring Stack:** 224 | 225 | - Prometheus 226 | - Grafana 227 | - Alertmanager 228 | - Node exporter 229 | - Cadvisor 230 | - Pushgateway 231 | - Nginx Proxy 232 | - Nginx SSL 233 | 234 | **Optional Stack:** 235 | 236 | - Poifier client 237 | - Indexer Agent GUI 238 | - Nginx Proxy 239 | - Nginx SSL 240 | 241 | ## Start 242 | 243 | Start by picking up the right stack that you want to spin up. 244 | 245 | There are several start files used to spin up different components. 246 | 247 | I would recommend to start with: 248 | 249 | ```bash 250 | bash start-essential 251 | 252 | ``` 253 | 254 | Be aware that initially it takes several minutes to download and run all the containers (especially the cli container, that one takes a while to build), so be patient. :) 255 | 256 | Subsequent restarts will be much faster. 257 | 258 | In case something goes wrong, find the problem, edit the variables, and add `--force-recreate` at the end of the command, plus the container you want to recreate: 259 | 260 | ```bash 261 | bash start-essential --force-recreate 262 | 263 | ``` 264 | 265 | Or to recreate the entire stack: 266 | 267 | ```bash 268 | bash start-essential --force-recreate 269 | 270 | ``` 271 | 272 | ### Start file variants: 273 | 274 | **start-essential** - starts up the graphnode, indexer and monitoring stack - all you need to get up and running on the network 275 | 276 | **start-optional** - starts up the optional stack (for components, read above) 277 | 278 | **start-autoagora** - starts up the autoagora stack (for components, read above) 279 | 280 | **start-all** - starts up the entire stack 281 | 282 | ## Verify that it runs properly 283 | 284 | To verify that everything is up and running, you need to: 285 | 286 | ```bash 287 | docker ps 288 | 289 | ``` 290 | 291 | And look for containers that are crash looping - you will notice `restarting` and a countdown - that means those containers are not working properly. 292 | 293 | To further debug, try looking for the container logs and see what they say. 294 | More information in the [troubleshooting](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/troubleshooting.md) section. 295 | 296 | ## Indexer Infrastructure Ports 297 | 298 | ### Ports Overview 299 | 300 | The following ports are being used by all components by default. Also listed are 301 | the CLI flags and environment variables that can be used to change the ports. 302 | 303 | #### Graphical Overview 304 | 305 | ![](https://raw.githubusercontent.com/graphprotocol/mission-control-indexer/master/files/ports.png) 306 | 307 | #### Graph Node 308 | 309 | | Port | Purpose | Routes | CLI argument | Environment variable | 310 | | ---- | ------------------------------------------ | -------------------------------------------------- | ------------------- | -------------------- | 311 | | 8000 | GraphQL HTTP server (for subgraph queries) | `/subgraphs/id/...`
`subgraphs/name/.../...` | `--http-port` | - | 312 | | 8001 | GraphQL WS (for subgraph subscriptions) | `/subgraphs/id/...`
`subgraphs/name/.../...` | `--ws-port` | - | 313 | | 8020 | JSON-RPC (for managing deployments) | `/` | `--admin-port` | - | 314 | | 8030 | Subgraph indexing status API | `/graphql` | `--index-node-port` | - | 315 | | 8040 | Prometheus metrics | `/metrics` | `--metrics-port` | - | 316 | 317 | #### Indexer Service 318 | 319 | | Port | Purpose | Routes | CLI argument | Environment variable | 320 | | ---- | ----------------------------------------------- | ----------------------------------- | ------------ | ---------------------- | 321 | | 7600 | GraphQL HTTP server (for paid subgraph queries) | `/subgraphs/id/...`
`/status` | `--port` | `INDEXER_SERVICE_PORT` | 322 | | 7300 | Prometheus metrics | `/metrics` | - | - | 323 | 324 | #### Indexer Agent 325 | 326 | | Port | Purpose | Routes | CLI argument | Environment variable | 327 | | ---- | -------------------------------------------- | ------ | --------------------------- | --------------------------------------- | 328 | | 8000 | Indexer management API (for `graph indexer`) | `/` | `--indexer-management-port` | `INDEXER_AGENT_INDEXER_MANAGEMENT_PORT` | 329 | 330 | ## Install or Update the Agora and Qlog modules 331 | 332 | To update those repos to the latest version just do the following command occasionally. 333 | 334 | ```bash 335 | git submodule update 336 | 337 | ``` 338 | 339 | To use qlog or agora execute the `runqlog` or `runagora` scripts in the root of the repository. 340 | 341 | ```bash 342 | ./runagora --help 343 | ./runqlog --help 344 | 345 | ``` 346 | 347 | This will use the compiled qlog tool and extract queries since yesterday or 5 hours ago and store them to the query-logs folder. 348 | 349 | ```bash 350 | ./extract_queries_since yesterday 351 | ./extract_queries_since "5 hours ago" 352 | 353 | ``` 354 | 355 | To make journald logs persistent across restarts you need to create a folder for the logs to store in like this: 356 | 357 | ``` 358 | mkdir -p /var/log/journal 359 | 360 | ``` 361 | 362 | ## Updates and Upgrades 363 | 364 | The general procedure is the following: 365 | 366 | ```bash 367 | cd 368 | git fetch 369 | git pull 370 | 371 | ``` 372 | 373 | This will update the scripts from the repository. 374 | 375 | To upgrade the containers: 376 | 377 | ```bash 378 | bash start --force-recreate 379 | 380 | ``` 381 | 382 | To update Agora or Qlog repos to the latest version just do the following command occasionally: 383 | 384 | ```bash 385 | git submodule update 386 | 387 | ``` 388 | 389 | To use qlog or agora execute the `runqlog` or `runagora` scripts in the root of the repository. 390 | 391 | ```bash 392 | ./runagora --help 393 | ./runqlog --help 394 | 395 | ``` 396 | 397 | #### Table of contents 398 | 399 | - [README.md](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/README.md) 400 | - [Pre-requisites](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/pre-requisites.md) 401 | - [Getting Started](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/getting-started.md) <- you are here 402 | - [Advanced Configuration](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/advanced-config.md) 403 | - [Setting Up Allocations](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/allocations.md) 404 | - [Setting Up Cost Models](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/costmodels.md) 405 | - [Tips and Tricks](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/tips.md) 406 | - [Troubleshooting](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/troubleshooting.md) 407 | -------------------------------------------------------------------------------- /docs/pre-requisites.md: -------------------------------------------------------------------------------- 1 | #### Table of contents 2 | 3 | - [README.md](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/README.md) 4 | - [Pre-requisites](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/pre-requisites.md) <- you are here 5 | - [Getting Started](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/getting-started.md) 6 | - [Advanced Configuration](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/advanced-config.md) 7 | - [Setting Up Allocations](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/allocations.md) 8 | - [Setting Up Cost Models](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/costmodels.md) 9 | - [Viewing Logs](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/logs.md) 10 | - [Tips and Tricks](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/tips.md) 11 | - [Troubleshooting](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/troubleshooting.md) 12 | 13 | 14 | 15 | ## Stake on the Network 16 | 17 | In order to become an indexer on the Graph Protocol Network, you'll have to stake a minimum of 100,000 GRT. 18 | 19 | This can easily be done via the Web UI, by going to the [Graph Explorer](https://thegraph.com/explorer). 20 | 21 | 1. Login with Metamask on the Wallet that holds your GRT 22 | 23 | 2. Go to your Profile, then switch to the "Indexing" Tab and hit "Stake" 24 | ![](https://i.ibb.co/4KxB08t/image.png) 25 | 26 | 3. Stake the amount of GRT that you desire, then you're all done! 27 | 28 | 29 | ## Set your Operator 30 | 31 | The Operator is a wallet address that is entirely separate from the address which you staked your GRT from. This Operator wallet will be filled with ETH, and will be used to send transactions (such as allocations) to the network, while keeping your Staked GRT safe in case of an attack on your infrastructure. It is highly recommended for you to use a new wallet, generated from a new mnemonic phrase. 32 | 33 | For this, follow the [instructions here](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/getting-started.md#create-a-mnemonic) first, then head back for the rest. 34 | 35 | Okay, assuming that you followed the instructions and you have your new Operator wallet at hand, lets go and link it up with the wallet that you used to stake your GRT. 36 | 37 | 1. Login with Metamask on the wallet that you used to stake your GRT 38 | 2. Click the Profile dropdown button, and go to "Settings", and then to the "Operators" tab 39 | ![](https://i.ibb.co/4PYjJj0/image.png) 40 | 3. Click the Plus (+) button and add your operator public address there 41 | 4. Submit the transaction, then you're done 42 | 43 | 44 | 45 | 46 | ## Ethereum Archive Node Specs 47 | 48 | Again, as mentioned in the [README.md](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/README.md), the setup for the archive node is **not included** in this docker setup. 49 | 50 | This section is purely informative. 51 | 52 | | | Minimum Specs | Recommended Specs | Maxed out Specs | 53 | | ------- | --------------- | ----------------- | ----------------- | 54 | | CPUs | 16 vcore | 32 vcore | 64 vcore | 55 | | RAM | 32 GB | 64 GB | 128 GB | 56 | | Storage | 3 TB SATA SSD | 5 TB NVME | 5 TB NVME RAID 10 | 57 | 58 | *Note: The 3 TB requirement for storage is the absolute minimum, it needs to be at least SATA SSD as spinning disks as too slow to also serve the RPC data to the Graph stack. Also, only Erigon has that little space required. OE (now deprecated) and GETH all take 10 TB+ at the very minimum, and expanding pretty fast.* 59 | 60 | 61 | ### Archive node options 62 | 63 | | Self-hosted | Trace API | Stable | EIP-1898 | Min Disk Size | Deprecated | 64 | | ------------------ | --------- | ------ | -------- | ------------- |------------| 65 | | OpenEthereum | yes ✔️ | yes ✔️ | yes ✔️ | 8 TB |yes ⚠️ | 66 | | GETH | no ⚠️ | yes ✔️ | yes ✔️ | 8 TB |no ✔️ | 67 | | Erigon | yes ✔️ | yes ✔️ | yes ✔️ | 3 TB |no ✔️ | 68 | 69 | 70 | | Service Providers (WIP) | 71 | | ----------------------- | 72 | | Infura | 73 | | Alchemy | 74 | | ChainStack | 75 | | Quiknode | 76 | | Ankr | 77 | 78 | 79 | 80 | ## Graph Protocol Infrastructure Specs 81 | 82 | | | Minimum Specs | Recommended Specs | Maxed out Specs | 83 | | ------- | --------------- | ----------------- | ------------------ | 84 | | CPU | 16 vcore | 64 vcore | 128+ vcore | 85 | | RAM | 32 GB | 128 GB | 256/512+ GB | 86 | | Storage | 300 GB SATA SSD | 2 TB NVME | 8+ TB NVME RAID 10 | 87 | 88 | *The specs/requirements listed here come from our own experience during the testnet.* 89 | *Your mileage may vary, so take this with a grain of salt and be ready to upgrade.* :) 90 | 91 | - The minimum specs will definitely get you running, but not for long, assuming you want to serve data for more than a few heavy-weight subgraphs in the future. 92 | 93 | - The recommended specs are a good setup for those that want to dip more than their feet in the indexing waters. Can serve a decent number of subgraphs, but it's limited by the CPU if too many requests flow through. 94 | 95 | - The maxed out specs rule of thumb is basically more is better. More CPUs, more RAM, faster disks. There is never enough. IT...NEEDS....MORE!!!!11 96 | 97 | Closing note, regarding the specs mentioned above: ideally, they need to scale up proportional with your stake in the protocol. 98 | 99 | 100 | 101 | 102 | ## Software Prerequisites 103 | 104 | * Docker Engine 105 | * Docker Compose 106 | * git 107 | * httpie 108 | * curl 109 | * wget 110 | * jq 111 | 112 | On a fresh Ubuntu server login via ssh and execute the following commands: 113 | 114 | ```bash 115 | apt update -y && apt upgrade -y && apt autoremove -y 116 | 117 | apt install docker.io docker-compose httpie curl wget git jq nano apparmor -y 118 | 119 | rm -rf $(which envsubst) && curl -L https://github.com/a8m/envsubst/releases/download/v1.2.0/envsubst-`uname -s`-`uname -m` -o envsubst && chmod +x envsubst && sudo mv envsubst /usr/bin/envsubst 120 | 121 | ``` 122 | 123 | ## Optional Software 124 | * NPM (through Node Version Manager) 125 | * Uncomplicated Firewall (ufw) 126 | * pino-pretty 127 | 128 | ```bash 129 | wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash 130 | 131 | export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")" 132 | [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm 133 | 134 | # restart or open a new shell/terminal 135 | 136 | nvm install node 137 | 138 | # restart or open a new shell/terminal 139 | 140 | npm install -g pino-pretty 141 | 142 | apt install ufw 143 | 144 | 145 | ``` 146 | 147 | **IMPORTANT:** Make sure you open your ssh port in ufw before starting it. The default installation will try to open port 22 (default), but if you changed it, make sure you open the right port, otherwise you'll be locked out. In case that happens, reboot into rescue-mode and disable ufw. 148 | 149 | #### Table of contents 150 | 151 | - [README.md](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/README.md) 152 | - [Pre-requisites](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/pre-requisites.md) <- you are here 153 | - [Getting Started](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/getting-started.md) 154 | - [Advanced Configuration](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/advanced-config.md) 155 | - [Setting Up Allocations](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/allocations.md) 156 | - [Setting Up Cost Models](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/costmodels.md) 157 | - [Viewing Logs](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/logs.md) 158 | - [Tips and Tricks](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/tips.md) 159 | - [Troubleshooting](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/troubleshooting.md) 160 | -------------------------------------------------------------------------------- /docs/tips.md: -------------------------------------------------------------------------------- 1 | #### Table of contents 2 | 3 | - [README.md](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/README.md) 4 | - [Pre-requisites](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/pre-requisites.md) 5 | - [Getting Started](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/getting-started.md) 6 | - [Advanced Configuration](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/advanced-config.md) 7 | - [Setting Up Allocations](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/allocations.md) 8 | - [Setting Up Cost Models](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/costmodels.md) 9 | - [Tips and Tricks](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/tips.md) <- you are here 10 | - [Troubleshooting](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/troubleshooting.md) 11 | 12 | 13 | # Getting subgraph sizes in the indexing overview dashboard 14 | 15 | ## Setup a cronjob to refresh materialized view: 16 | 17 | ```bash 18 | echo "0 0,12 * * * $HOME/graphprotocol-mainnet-docker/refresh-sizes.sh" | crontab - 19 | ``` 20 | -------------------------------------------------------------------------------- /docs/troubleshooting.md: -------------------------------------------------------------------------------- 1 | #### Table of contents 2 | 3 | - [README.md](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/README.md) 4 | - [Pre-requisites](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/pre-requisites.md) 5 | - [Getting Started](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/getting-started.md) 6 | - [Advanced Configuration](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/advanced-config.md) 7 | - [Setting Up Allocations](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/allocations.md) 8 | - [Setting Up Cost Models](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/costmodels.md) 9 | - [Tips and Tricks](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/tips.md) 10 | - [Troubleshooting](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/troubleshooting.md) <- you are here 11 | 12 | 13 | 14 | # Logs 15 | 16 | 17 | ## Installing pre-requisites 18 | 19 | 20 | First off, I strongly recommend having either `graph-pino` or `pino-pretty` installed for this. 21 | 22 | You will need NPM installed for them to work and be viewable in a more human-esque manner, so for that, we'll be using NVM (Node Version Manager) to make things easier. 23 | 24 | ```bash 25 | wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash 26 | 27 | export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")" 28 | [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm 29 | 30 | # restart or open a new shell/terminal 31 | 32 | nvm install node 33 | 34 | # restart or open a new shell/terminal 35 | 36 | ``` 37 | 38 | To install `graph-pino`, you can simply do: 39 | 40 | ```bash 41 | npm install -g --registry https://registry.npmjs.org/ @graphprotocol/graph-pino 42 | 43 | ``` 44 | 45 | To install `pino-pretty`, you can simply do: 46 | 47 | ```bash 48 | npm install -g pino-pretty 49 | 50 | ``` 51 | 52 | And you're done. These two will greatly help you read through the `indexer-agent` and `indexer-service` logs to easily find errors and warning messages that might occur. 53 | 54 | ## Usage: 55 | 56 | #### Graph-pino with Docker 57 | 58 | ```bash 59 | docker logs indexer-agent --tail 10 -f | graph-pino 60 | 61 | ``` 62 | 63 | #### Graph-pino with Journald 64 | 65 | ```bash 66 | journalctl -fu indexer-agent -n 10 -f | graph-pino 67 | 68 | ``` 69 | 70 | #### Pino-pretty with Docker 71 | 72 | ```bash 73 | docker logs indexer-agent --tail 10 -f | pino-pretty -c -t 74 | 75 | ``` 76 | 77 | #### Pino-pretty with Journald 78 | 79 | ```bash 80 | journalctl -fu indexer-agent -n 10 -f | pino-pretty -c -t 81 | 82 | ``` 83 | 84 | :exclamation: **Note:** pino-pretty and graph-pino only work for logs that output json strings (ie. indexer agent and service) 85 | 86 | ## Printing logs to file 87 | 88 | The following examples strip the colors out of pino-pretty, sends the stdout to /dev/null and print the logs into a file without showing you the logs on screen. 89 | 90 | #### Pino-pretty with Docker 91 | 92 | ```bash 93 | docker logs indexer-service 2>&1 | pino-pretty -c -t | sed -r "s/[[:cntrl:]]\[[0-9]{1,3}m//g" | tee service.log &> /dev/null & 94 | ``` 95 | 96 | 97 | 98 | #### Pino-pretty with Journald 99 | 100 | ```bash 101 | journalctl CONTAINER_NAME=indexer-service -o cat 2>&1 | pino-pretty -c -t | sed -r "s/[[:cntrl:]]\[[0-9]{1,3}m//g" | tee service.log &> /dev/null & 102 | ``` 103 | 104 | If you want to extract specific dates from your logs you can do as follows, where `-S` is the date/hour since, and `-U` is the date/hour until. 105 | 106 | ```bash 107 | journalctl CONTAINER_NAME=indexer-service -S "20:22:00" -U "20:55:00" -o cat 2>&1 | pino-pretty -c -t | sed -r "s/[[:cntrl:]]\[[0-9]{1,3}m//g" | tee service.log &> /dev/null & 108 | ``` 109 | 110 | 111 | 112 | 113 | 114 | #### Table of contents 115 | 116 | - [README.md](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/README.md) 117 | - [Pre-requisites](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/pre-requisites.md) 118 | - [Getting Started](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/getting-started.md) 119 | - [Advanced Configuration](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/advanced-config.md) 120 | - [Setting Up Allocations](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/allocations.md) 121 | - [Setting Up Cost Models](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/costmodels.md) 122 | - [Tips and Tricks](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/tips.md) 123 | - [Troubleshooting](https://github.com/StakeSquid/graphprotocol-mainnet-docker/blob/master/docs/troubleshooting.md) <- you are here -------------------------------------------------------------------------------- /extract_queries_since: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR=$PWD 4 | 5 | FILE=$DIR/query-logs 6 | if [ ! -f "$FILE" ]; then 7 | mkdir -p $DIR/query-logs 8 | fi 9 | 10 | FILENAME=$DIR/query-logs/$(date +"%Y_%m_%d_%I_%M_%p").jsonl 11 | 12 | journalctl CONTAINER_NAME=query-node-0 --since="$1" --no-pager | grep 'Query timing' | $DIR/runqlog process --text --output /dev/stdout | sed 's/\\\\\\/\\/g' | sed 's/time/effort/g' > $FILENAME 13 | 14 | echo "Saved the output as $FILENAME" 15 | -------------------------------------------------------------------------------- /grafana/provisioning/alerting/file: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StakeSquid/graphprotocol-mainnet-docker/dca14a6efe47ebbd2a56c64a2f4d9b2d2a67c684/grafana/provisioning/alerting/file -------------------------------------------------------------------------------- /grafana/provisioning/dashboards/dashboard.yml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | providers: 4 | - name: 'Prometheus' 5 | orgId: 1 6 | folder: '' 7 | type: file 8 | disableDeletion: false 9 | editable: true 10 | allowUiUpdates: true 11 | options: 12 | path: /etc/grafana/provisioning/dashboards -------------------------------------------------------------------------------- /grafana/provisioning/dashboards/default.yml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | providers: 3 | - name: 'default' 4 | orgId: 1 5 | folder: '' 6 | folderUid: '' 7 | type: file 8 | allowUiUpdates: true 9 | updateIntervalSeconds: 31536000 10 | options: 11 | path: /etc/grafana/provisioning/dashboards -------------------------------------------------------------------------------- /grafana/provisioning/dashboards/graphql.json: -------------------------------------------------------------------------------- 1 | { 2 | "annotations": { 3 | "list": [ 4 | { 5 | "builtIn": 1, 6 | "datasource": { 7 | "type": "datasource", 8 | "uid": "grafana" 9 | }, 10 | "enable": true, 11 | "hide": true, 12 | "iconColor": "rgba(0, 211, 255, 1)", 13 | "name": "Annotations & Alerts", 14 | "type": "dashboard" 15 | } 16 | ] 17 | }, 18 | "editable": true, 19 | "fiscalYearStartMonth": 0, 20 | "graphTooltip": 0, 21 | "id": 3, 22 | "links": [], 23 | "panels": [ 24 | { 25 | "datasource": { 26 | "type": "yesoreyeram-infinity-datasource", 27 | "uid": "PAED31C11881F20F3" 28 | }, 29 | "fieldConfig": { 30 | "defaults": { 31 | "color": { 32 | "mode": "fixed" 33 | }, 34 | "custom": { 35 | "align": "center", 36 | "cellOptions": { 37 | "type": "auto" 38 | }, 39 | "filterable": false, 40 | "inspect": false 41 | }, 42 | "mappings": [], 43 | "thresholds": { 44 | "mode": "percentage", 45 | "steps": [ 46 | { 47 | "color": "dark-purple", 48 | "value": null 49 | } 50 | ] 51 | }, 52 | "unit": "string" 53 | }, 54 | "overrides": [ 55 | { 56 | "matcher": { 57 | "id": "byName", 58 | "options": "Signalled Tokens" 59 | }, 60 | "properties": [ 61 | { 62 | "id": "unit", 63 | "value": "locale" 64 | }, 65 | { 66 | "id": "decimals", 67 | "value": 0 68 | }, 69 | { 70 | "id": "custom.width", 71 | "value": 223 72 | } 73 | ] 74 | }, 75 | { 76 | "matcher": { 77 | "id": "byName", 78 | "options": "Staked Tokens" 79 | }, 80 | "properties": [ 81 | { 82 | "id": "unit", 83 | "value": "locale" 84 | }, 85 | { 86 | "id": "decimals", 87 | "value": 0 88 | } 89 | ] 90 | }, 91 | { 92 | "matcher": { 93 | "id": "byName", 94 | "options": "Query Fees Rebates" 95 | }, 96 | "properties": [ 97 | { 98 | "id": "unit", 99 | "value": "locale" 100 | }, 101 | { 102 | "id": "decimals", 103 | "value": 0 104 | } 105 | ] 106 | }, 107 | { 108 | "matcher": { 109 | "id": "byName", 110 | "options": "Query Fees Amount" 111 | }, 112 | "properties": [ 113 | { 114 | "id": "unit", 115 | "value": "locale" 116 | }, 117 | { 118 | "id": "decimals", 119 | "value": 0 120 | } 121 | ] 122 | }, 123 | { 124 | "matcher": { 125 | "id": "byName", 126 | "options": "Indexing Rewards" 127 | }, 128 | "properties": [ 129 | { 130 | "id": "unit", 131 | "value": "locale" 132 | }, 133 | { 134 | "id": "decimals", 135 | "value": 0 136 | } 137 | ] 138 | }, 139 | { 140 | "matcher": { 141 | "id": "byName", 142 | "options": "IPFS Hash" 143 | }, 144 | "properties": [ 145 | { 146 | "id": "custom.width", 147 | "value": 443 148 | } 149 | ] 150 | }, 151 | { 152 | "matcher": { 153 | "id": "byName", 154 | "options": "Deployment Name" 155 | }, 156 | "properties": [ 157 | { 158 | "id": "custom.width", 159 | "value": 176 160 | } 161 | ] 162 | }, 163 | { 164 | "matcher": { 165 | "id": "byName", 166 | "options": "STSR" 167 | }, 168 | "properties": [ 169 | { 170 | "id": "custom.width", 171 | "value": 177 172 | } 173 | ] 174 | } 175 | ] 176 | }, 177 | "gridPos": { 178 | "h": 24, 179 | "w": 24, 180 | "x": 0, 181 | "y": 0 182 | }, 183 | "id": 2, 184 | "options": { 185 | "cellHeight": "sm", 186 | "footer": { 187 | "countRows": false, 188 | "fields": "", 189 | "reducer": [ 190 | "sum" 191 | ], 192 | "show": false 193 | }, 194 | "frameIndex": 1, 195 | "showHeader": true, 196 | "sortBy": [ 197 | { 198 | "desc": true, 199 | "displayName": "Signalled Tokens" 200 | } 201 | ] 202 | }, 203 | "pluginVersion": "11.3.0", 204 | "targets": [ 205 | { 206 | "aliasBy": "", 207 | "annotationTags": "", 208 | "annotationText": "", 209 | "annotationTitle": "", 210 | "columns": [], 211 | "constant": 6.5, 212 | "dataPath": "subgraphDeployments", 213 | "datasource": { 214 | "type": "yesoreyeram-infinity-datasource", 215 | "uid": "PAED31C11881F20F3" 216 | }, 217 | "endTimePath": "endTime", 218 | "filters": [], 219 | "format": "table", 220 | "global_query_id": "", 221 | "groupBy": "", 222 | "hide": false, 223 | "queryText": "query MyQuery {\n subgraphDeployments(orderBy: signalledTokens, orderDirection: desc) {\n ipfsHash\n signalledTokens\n stakedTokens\n originalName\n indexingRewardAmount\n queryFeesAmount\n queryFeeRebates\n }\n}", 224 | "refId": "B", 225 | "root_selector": "$.data.[*]", 226 | "source": "url", 227 | "timePath": "", 228 | "type": "json", 229 | "url": "http://query-node-0:8000/subgraphs/id/QmXnGVrg6DvscnvJd86aHAPLGyGrkM17weMrAsFAEMmQLL", 230 | "url_options": { 231 | "body_content_type": "text/plain", 232 | "body_graphql_query": "query {\r\n data:subgraphDeployments(orderBy: signalledTokens, orderDirection: desc) {\r\n ipfsHash\r\n signalledTokens\r\n stakedTokens\r\n originalName\r\n indexingRewardAmount\r\n queryFeesAmount\r\n queryFeeRebates\r\n }\r\n}\r\n", 233 | "body_type": "graphql", 234 | "data": "", 235 | "method": "POST" 236 | } 237 | } 238 | ], 239 | "title": "Avaliable subgraphs", 240 | "transformations": [ 241 | { 242 | "id": "calculateField", 243 | "options": { 244 | "alias": "Indexing Rewards", 245 | "binary": { 246 | "left": "indexingRewardAmount", 247 | "operator": "/", 248 | "reducer": "sum", 249 | "right": "1000000000000000000" 250 | }, 251 | "mode": "binary", 252 | "reduce": { 253 | "reducer": "sum" 254 | } 255 | } 256 | }, 257 | { 258 | "id": "calculateField", 259 | "options": { 260 | "alias": "Query Fees Amount", 261 | "binary": { 262 | "left": "queryFeesAmount", 263 | "operator": "/", 264 | "reducer": "sum", 265 | "right": "1000000000000000000" 266 | }, 267 | "mode": "binary", 268 | "reduce": { 269 | "reducer": "sum" 270 | } 271 | } 272 | }, 273 | { 274 | "id": "calculateField", 275 | "options": { 276 | "alias": "Query Fee Rebates", 277 | "binary": { 278 | "left": "queryFeeRebates", 279 | "operator": "/", 280 | "reducer": "sum", 281 | "right": "1000000000000000000" 282 | }, 283 | "mode": "binary", 284 | "reduce": { 285 | "reducer": "sum" 286 | }, 287 | "replaceFields": false 288 | } 289 | }, 290 | { 291 | "id": "calculateField", 292 | "options": { 293 | "alias": "Signalled Tokens", 294 | "binary": { 295 | "left": "signalledTokens", 296 | "operator": "/", 297 | "reducer": "sum", 298 | "right": "1000000000000000000" 299 | }, 300 | "mode": "binary", 301 | "reduce": { 302 | "reducer": "sum" 303 | } 304 | } 305 | }, 306 | { 307 | "id": "calculateField", 308 | "options": { 309 | "alias": "Staked Tokens", 310 | "binary": { 311 | "left": "stakedTokens", 312 | "operator": "/", 313 | "reducer": "sum", 314 | "right": "1000000000000000000" 315 | }, 316 | "mode": "binary", 317 | "reduce": { 318 | "reducer": "sum" 319 | } 320 | } 321 | }, 322 | { 323 | "id": "calculateField", 324 | "options": { 325 | "alias": "STSR", 326 | "binary": { 327 | "left": "signalledTokens", 328 | "operator": "/", 329 | "reducer": "sum", 330 | "right": "stakedTokens" 331 | }, 332 | "mode": "binary", 333 | "reduce": { 334 | "reducer": "sum" 335 | } 336 | } 337 | }, 338 | { 339 | "id": "organize", 340 | "options": { 341 | "excludeByName": { 342 | "STSR": false, 343 | "Signalled Tokens": false, 344 | "indexingRewardAmount": true, 345 | "queryFeeRebates": true, 346 | "queryFeesAmount": true, 347 | "signalledTokens": true, 348 | "stakedTokens": true 349 | }, 350 | "indexByName": { 351 | "Indexing Rewards": 12, 352 | "Query Fee Rebates": 10, 353 | "Query Fees Amount": 11, 354 | "STSR": 2, 355 | "Signalled Tokens": 8, 356 | "Staked Tokens": 9, 357 | "indexingRewardAmount": 3, 358 | "ipfsHash": 0, 359 | "originalName": 1, 360 | "queryFeeRebates": 4, 361 | "queryFeesAmount": 5, 362 | "signalledTokens": 6, 363 | "stakedTokens": 7 364 | }, 365 | "renameByName": { 366 | "Query Fee Rebates": "Query Fees Rebates", 367 | "Query Fees Amount": "Query Fees Amount", 368 | "STSR": "", 369 | "Signalled Tokens": "Signalled Tokens", 370 | "Staked Tokens": "Staked Tokens", 371 | "indexingRewardAmount": "", 372 | "ipfsHash": "IPFS Hash", 373 | "originalName": "Deployment Name", 374 | "queryFeeRebates": "", 375 | "queryFeesAmount": "", 376 | "signalledTokens": "", 377 | "stakedTokens": "" 378 | } 379 | } 380 | } 381 | ], 382 | "type": "table" 383 | } 384 | ], 385 | "preload": false, 386 | "refresh": "", 387 | "schemaVersion": 40, 388 | "tags": [], 389 | "templating": { 390 | "list": [] 391 | }, 392 | "time": { 393 | "from": "now-6h", 394 | "to": "now" 395 | }, 396 | "timepicker": {}, 397 | "timezone": "", 398 | "title": "GraphQL", 399 | "uid": "LAczYo6Mk", 400 | "version": 4, 401 | "weekStart": "" 402 | } -------------------------------------------------------------------------------- /grafana/provisioning/dashboards/indexing-performance.json: -------------------------------------------------------------------------------- 1 | { 2 | "annotations": { 3 | "list": [ 4 | { 5 | "builtIn": 1, 6 | "datasource": { 7 | "type": "datasource", 8 | "uid": "grafana" 9 | }, 10 | "enable": true, 11 | "hide": true, 12 | "iconColor": "rgba(0, 211, 255, 1)", 13 | "name": "Annotations & Alerts", 14 | "target": { 15 | "limit": 100, 16 | "matchAny": false, 17 | "tags": [], 18 | "type": "dashboard" 19 | }, 20 | "type": "dashboard" 21 | } 22 | ] 23 | }, 24 | "editable": true, 25 | "fiscalYearStartMonth": 0, 26 | "graphTooltip": 1, 27 | "id": 7, 28 | "links": [ 29 | { 30 | "asDropdown": false, 31 | "icon": "external link", 32 | "includeVars": false, 33 | "keepTime": true, 34 | "tags": [], 35 | "targetBlank": true, 36 | "title": "Deployment Details", 37 | "tooltip": "", 38 | "type": "link", 39 | "url": "/d/SjWDBHSGz/deployment-details-graph?from=now-6h&to=now&var-account=indexer-agent&var-deployment=${deployment}&var-shard=PA942B37CCFAF5A81&var-horizon=1y" 40 | }, 41 | { 42 | "asDropdown": false, 43 | "icon": "external link", 44 | "includeVars": false, 45 | "keepTime": true, 46 | "tags": [], 47 | "targetBlank": true, 48 | "title": "Logs", 49 | "tooltip": "", 50 | "type": "link", 51 | "url": "/d/a9T5kG7dF/logs-explorer?from=now-5m&to=now&var-source=%2Findex-node-0&var-filter=${deployment}" 52 | } 53 | ], 54 | "panels": [ 55 | { 56 | "datasource": { 57 | "default": false, 58 | "type": "prometheus", 59 | "uid": "P1809F7CD0C75ACF3" 60 | }, 61 | "fieldConfig": { 62 | "defaults": { 63 | "color": { 64 | "mode": "palette-classic" 65 | }, 66 | "custom": { 67 | "axisBorderShow": false, 68 | "axisCenteredZero": false, 69 | "axisColorMode": "text", 70 | "axisLabel": "", 71 | "axisPlacement": "auto", 72 | "barAlignment": 0, 73 | "barWidthFactor": 0.6, 74 | "drawStyle": "line", 75 | "fillOpacity": 0, 76 | "gradientMode": "opacity", 77 | "hideFrom": { 78 | "legend": false, 79 | "tooltip": false, 80 | "viz": false 81 | }, 82 | "insertNulls": false, 83 | "lineInterpolation": "smooth", 84 | "lineWidth": 1, 85 | "pointSize": 5, 86 | "scaleDistribution": { 87 | "type": "linear" 88 | }, 89 | "showPoints": "never", 90 | "spanNulls": true, 91 | "stacking": { 92 | "group": "A", 93 | "mode": "none" 94 | }, 95 | "thresholdsStyle": { 96 | "mode": "off" 97 | } 98 | }, 99 | "decimals": 0, 100 | "mappings": [], 101 | "thresholds": { 102 | "mode": "absolute", 103 | "steps": [ 104 | { 105 | "color": "green", 106 | "value": null 107 | }, 108 | { 109 | "color": "red", 110 | "value": 80 111 | } 112 | ] 113 | }, 114 | "unit": "locale" 115 | }, 116 | "overrides": [] 117 | }, 118 | "gridPos": { 119 | "h": 8, 120 | "w": 24, 121 | "x": 0, 122 | "y": 0 123 | }, 124 | "id": 45, 125 | "options": { 126 | "legend": { 127 | "calcs": [ 128 | "mean", 129 | "lastNotNull" 130 | ], 131 | "displayMode": "table", 132 | "placement": "right", 133 | "showLegend": true, 134 | "sortBy": "Last *", 135 | "sortDesc": true 136 | }, 137 | "tooltip": { 138 | "mode": "multi", 139 | "sort": "desc" 140 | } 141 | }, 142 | "pluginVersion": "11.3.0", 143 | "targets": [ 144 | { 145 | "datasource": { 146 | "type": "prometheus", 147 | "uid": "P1809F7CD0C75ACF3" 148 | }, 149 | "editorMode": "code", 150 | "exemplar": true, 151 | "expr": "deriv(deployment_head{deployment=~\"$deployment\", network=~\"$network\", shard=~\"$shard\"}[10m]) * 60", 152 | "instant": false, 153 | "interval": "", 154 | "intervalFactor": 1, 155 | "legendFormat": "{{deployment}}", 156 | "refId": "A" 157 | } 158 | ], 159 | "title": "Individual subgraph sync rate", 160 | "transparent": true, 161 | "type": "timeseries" 162 | }, 163 | { 164 | "datasource": { 165 | "default": false, 166 | "type": "prometheus", 167 | "uid": "P1809F7CD0C75ACF3" 168 | }, 169 | "fieldConfig": { 170 | "defaults": { 171 | "color": { 172 | "mode": "palette-classic" 173 | }, 174 | "custom": { 175 | "axisBorderShow": false, 176 | "axisCenteredZero": false, 177 | "axisColorMode": "text", 178 | "axisLabel": "", 179 | "axisPlacement": "auto", 180 | "barAlignment": 0, 181 | "barWidthFactor": 0.6, 182 | "drawStyle": "line", 183 | "fillOpacity": 0, 184 | "gradientMode": "opacity", 185 | "hideFrom": { 186 | "legend": false, 187 | "tooltip": false, 188 | "viz": false 189 | }, 190 | "insertNulls": false, 191 | "lineInterpolation": "smooth", 192 | "lineWidth": 1, 193 | "pointSize": 5, 194 | "scaleDistribution": { 195 | "type": "linear" 196 | }, 197 | "showPoints": "never", 198 | "spanNulls": true, 199 | "stacking": { 200 | "group": "A", 201 | "mode": "none" 202 | }, 203 | "thresholdsStyle": { 204 | "mode": "off" 205 | } 206 | }, 207 | "decimals": 0, 208 | "mappings": [], 209 | "thresholds": { 210 | "mode": "absolute", 211 | "steps": [ 212 | { 213 | "color": "green", 214 | "value": null 215 | }, 216 | { 217 | "color": "red", 218 | "value": 80 219 | } 220 | ] 221 | }, 222 | "unit": "locale" 223 | }, 224 | "overrides": [ 225 | { 226 | "matcher": { 227 | "id": "byName", 228 | "options": "Value" 229 | }, 230 | "properties": [ 231 | { 232 | "id": "color", 233 | "value": { 234 | "fixedColor": "#1250B0", 235 | "mode": "fixed" 236 | } 237 | } 238 | ] 239 | } 240 | ] 241 | }, 242 | "gridPos": { 243 | "h": 9, 244 | "w": 24, 245 | "x": 0, 246 | "y": 8 247 | }, 248 | "id": 47, 249 | "options": { 250 | "legend": { 251 | "calcs": [ 252 | "mean", 253 | "lastNotNull" 254 | ], 255 | "displayMode": "table", 256 | "placement": "bottom", 257 | "showLegend": true 258 | }, 259 | "tooltip": { 260 | "mode": "multi", 261 | "sort": "none" 262 | } 263 | }, 264 | "pluginVersion": "11.3.0", 265 | "targets": [ 266 | { 267 | "datasource": { 268 | "type": "prometheus", 269 | "uid": "P1809F7CD0C75ACF3" 270 | }, 271 | "editorMode": "code", 272 | "exemplar": true, 273 | "expr": "sum(deriv(deployment_head[10m]) * 60)", 274 | "hide": false, 275 | "interval": "", 276 | "legendFormat": "Total Sync Rate", 277 | "range": true, 278 | "refId": "A" 279 | } 280 | ], 281 | "title": "All subgraphs sync rate", 282 | "transparent": true, 283 | "type": "timeseries" 284 | }, 285 | { 286 | "datasource": { 287 | "default": false, 288 | "type": "prometheus", 289 | "uid": "P1809F7CD0C75ACF3" 290 | }, 291 | "fieldConfig": { 292 | "defaults": { 293 | "color": { 294 | "mode": "palette-classic" 295 | }, 296 | "custom": { 297 | "axisBorderShow": false, 298 | "axisCenteredZero": false, 299 | "axisColorMode": "text", 300 | "axisLabel": "", 301 | "axisPlacement": "auto", 302 | "barAlignment": 0, 303 | "barWidthFactor": 0.6, 304 | "drawStyle": "line", 305 | "fillOpacity": 0, 306 | "gradientMode": "none", 307 | "hideFrom": { 308 | "legend": false, 309 | "tooltip": false, 310 | "viz": false 311 | }, 312 | "insertNulls": false, 313 | "lineInterpolation": "smooth", 314 | "lineWidth": 1, 315 | "pointSize": 5, 316 | "scaleDistribution": { 317 | "type": "linear" 318 | }, 319 | "showPoints": "never", 320 | "spanNulls": true, 321 | "stacking": { 322 | "group": "A", 323 | "mode": "none" 324 | }, 325 | "thresholdsStyle": { 326 | "mode": "off" 327 | } 328 | }, 329 | "decimals": 0, 330 | "mappings": [], 331 | "thresholds": { 332 | "mode": "absolute", 333 | "steps": [ 334 | { 335 | "color": "green", 336 | "value": null 337 | }, 338 | { 339 | "color": "red", 340 | "value": 80 341 | } 342 | ] 343 | }, 344 | "unit": "locale" 345 | }, 346 | "overrides": [] 347 | }, 348 | "gridPos": { 349 | "h": 10, 350 | "w": 24, 351 | "x": 0, 352 | "y": 17 353 | }, 354 | "id": 35, 355 | "options": { 356 | "legend": { 357 | "calcs": [ 358 | "lastNotNull" 359 | ], 360 | "displayMode": "table", 361 | "placement": "right", 362 | "showLegend": true, 363 | "sortBy": "Last *", 364 | "sortDesc": true 365 | }, 366 | "tooltip": { 367 | "mode": "multi", 368 | "sort": "desc" 369 | } 370 | }, 371 | "pluginVersion": "11.3.0", 372 | "targets": [ 373 | { 374 | "datasource": { 375 | "type": "prometheus", 376 | "uid": "P1809F7CD0C75ACF3" 377 | }, 378 | "editorMode": "code", 379 | "exemplar": true, 380 | "expr": "abs(deployment_head{deployment=~\"$deployment\", network=~\"$network\", shard=~\"$shard\"} - on (network) group_left max by (network) (ethereum_chain_head_number))", 381 | "format": "time_series", 382 | "instant": false, 383 | "interval": "", 384 | "intervalFactor": 1, 385 | "legendFormat": "{{deployment}}", 386 | "refId": "A" 387 | } 388 | ], 389 | "title": "Blocks behind over time", 390 | "transparent": true, 391 | "type": "timeseries" 392 | }, 393 | { 394 | "datasource": { 395 | "default": false, 396 | "type": "prometheus", 397 | "uid": "P1809F7CD0C75ACF3" 398 | }, 399 | "fieldConfig": { 400 | "defaults": { 401 | "color": { 402 | "mode": "palette-classic" 403 | }, 404 | "custom": { 405 | "axisBorderShow": false, 406 | "axisCenteredZero": false, 407 | "axisColorMode": "text", 408 | "axisLabel": "", 409 | "axisPlacement": "auto", 410 | "barAlignment": 0, 411 | "barWidthFactor": 0.6, 412 | "drawStyle": "line", 413 | "fillOpacity": 0, 414 | "gradientMode": "none", 415 | "hideFrom": { 416 | "legend": false, 417 | "tooltip": false, 418 | "viz": false 419 | }, 420 | "insertNulls": false, 421 | "lineInterpolation": "smooth", 422 | "lineWidth": 1, 423 | "pointSize": 5, 424 | "scaleDistribution": { 425 | "type": "linear" 426 | }, 427 | "showPoints": "never", 428 | "spanNulls": true, 429 | "stacking": { 430 | "group": "A", 431 | "mode": "none" 432 | }, 433 | "thresholdsStyle": { 434 | "mode": "line+area" 435 | } 436 | }, 437 | "mappings": [], 438 | "thresholds": { 439 | "mode": "absolute", 440 | "steps": [ 441 | { 442 | "color": "transparent", 443 | "value": null 444 | }, 445 | { 446 | "color": "red", 447 | "value": 30 448 | } 449 | ] 450 | }, 451 | "unit": "s" 452 | }, 453 | "overrides": [] 454 | }, 455 | "gridPos": { 456 | "h": 10, 457 | "w": 24, 458 | "x": 0, 459 | "y": 27 460 | }, 461 | "id": 41, 462 | "options": { 463 | "legend": { 464 | "calcs": [ 465 | "mean" 466 | ], 467 | "displayMode": "table", 468 | "placement": "right", 469 | "showLegend": true 470 | }, 471 | "tooltip": { 472 | "mode": "multi", 473 | "sort": "desc" 474 | } 475 | }, 476 | "pluginVersion": "11.3.0", 477 | "targets": [ 478 | { 479 | "datasource": { 480 | "type": "prometheus", 481 | "uid": "P1809F7CD0C75ACF3" 482 | }, 483 | "editorMode": "code", 484 | "expr": "avg_over_time(deployment_eth_rpc_request_duration{deployment=~\"$deployment\", provider=~\"$provider\"}[15m])", 485 | "instant": false, 486 | "interval": "1m", 487 | "legendFormat": "{{ deployment }} | {{ provider }} | {{ method }}", 488 | "refId": "A" 489 | } 490 | ], 491 | "title": "Eth RPC Request Duration per Subgraph", 492 | "transparent": true, 493 | "type": "timeseries" 494 | }, 495 | { 496 | "datasource": { 497 | "default": false, 498 | "type": "prometheus", 499 | "uid": "P1809F7CD0C75ACF3" 500 | }, 501 | "fieldConfig": { 502 | "defaults": { 503 | "color": { 504 | "mode": "palette-classic" 505 | }, 506 | "custom": { 507 | "axisBorderShow": false, 508 | "axisCenteredZero": false, 509 | "axisColorMode": "text", 510 | "axisLabel": "", 511 | "axisPlacement": "auto", 512 | "barAlignment": 0, 513 | "barWidthFactor": 0.6, 514 | "drawStyle": "line", 515 | "fillOpacity": 0, 516 | "gradientMode": "none", 517 | "hideFrom": { 518 | "legend": false, 519 | "tooltip": false, 520 | "viz": false 521 | }, 522 | "insertNulls": false, 523 | "lineInterpolation": "linear", 524 | "lineWidth": 1, 525 | "pointSize": 5, 526 | "scaleDistribution": { 527 | "type": "linear" 528 | }, 529 | "showPoints": "never", 530 | "spanNulls": true, 531 | "stacking": { 532 | "group": "A", 533 | "mode": "none" 534 | }, 535 | "thresholdsStyle": { 536 | "mode": "line+area" 537 | } 538 | }, 539 | "mappings": [], 540 | "thresholds": { 541 | "mode": "absolute", 542 | "steps": [ 543 | { 544 | "color": "transparent", 545 | "value": null 546 | }, 547 | { 548 | "color": "red", 549 | "value": 20 550 | } 551 | ] 552 | }, 553 | "unit": "short" 554 | }, 555 | "overrides": [] 556 | }, 557 | "gridPos": { 558 | "h": 8, 559 | "w": 24, 560 | "x": 0, 561 | "y": 37 562 | }, 563 | "id": 43, 564 | "options": { 565 | "legend": { 566 | "calcs": [ 567 | "mean" 568 | ], 569 | "displayMode": "table", 570 | "placement": "right", 571 | "showLegend": true 572 | }, 573 | "tooltip": { 574 | "mode": "multi", 575 | "sort": "none" 576 | } 577 | }, 578 | "pluginVersion": "11.3.0", 579 | "targets": [ 580 | { 581 | "datasource": { 582 | "type": "prometheus", 583 | "uid": "P1809F7CD0C75ACF3" 584 | }, 585 | "editorMode": "code", 586 | "expr": "rate(eth_rpc_errors{provider=~\"$provider\", job=~\"$job\"}[1m])*60", 587 | "instant": false, 588 | "interval": "", 589 | "legendFormat": "{{entity}} | {{provider}} | {{method}}", 590 | "refId": "A" 591 | } 592 | ], 593 | "title": "Eth RPC Errors per minute (all subgraphs)", 594 | "transparent": true, 595 | "type": "timeseries" 596 | } 597 | ], 598 | "preload": false, 599 | "refresh": "", 600 | "schemaVersion": 40, 601 | "tags": [], 602 | "templating": { 603 | "list": [ 604 | { 605 | "current": { 606 | "text": [ 607 | "All" 608 | ], 609 | "value": [ 610 | "$__all" 611 | ] 612 | }, 613 | "datasource": { 614 | "type": "prometheus", 615 | "uid": "P1809F7CD0C75ACF3" 616 | }, 617 | "definition": "label_values(deployment_head,deployment)", 618 | "includeAll": true, 619 | "multi": true, 620 | "name": "deployment", 621 | "options": [], 622 | "query": { 623 | "qryType": 1, 624 | "query": "label_values(deployment_head,deployment)", 625 | "refId": "PrometheusVariableQueryEditor-VariableQuery" 626 | }, 627 | "refresh": 1, 628 | "regex": "", 629 | "sort": 5, 630 | "type": "query" 631 | }, 632 | { 633 | "current": { 634 | "text": [ 635 | "All" 636 | ], 637 | "value": [ 638 | "$__all" 639 | ] 640 | }, 641 | "datasource": { 642 | "type": "prometheus", 643 | "uid": "P1809F7CD0C75ACF3" 644 | }, 645 | "definition": "label_values(ethereum_chain_head_number,network)", 646 | "includeAll": true, 647 | "multi": true, 648 | "name": "network", 649 | "options": [], 650 | "query": { 651 | "qryType": 1, 652 | "query": "label_values(ethereum_chain_head_number,network)", 653 | "refId": "PrometheusVariableQueryEditor-VariableQuery" 654 | }, 655 | "refresh": 1, 656 | "regex": "", 657 | "sort": 5, 658 | "type": "query" 659 | }, 660 | { 661 | "current": { 662 | "text": [ 663 | "All" 664 | ], 665 | "value": [ 666 | "$__all" 667 | ] 668 | }, 669 | "datasource": { 670 | "type": "prometheus", 671 | "uid": "P1809F7CD0C75ACF3" 672 | }, 673 | "definition": "label_values(deployment_head,shard)", 674 | "includeAll": true, 675 | "multi": true, 676 | "name": "shard", 677 | "options": [], 678 | "query": { 679 | "qryType": 1, 680 | "query": "label_values(deployment_head,shard)", 681 | "refId": "PrometheusVariableQueryEditor-VariableQuery" 682 | }, 683 | "refresh": 1, 684 | "regex": "", 685 | "sort": 5, 686 | "type": "query" 687 | }, 688 | { 689 | "current": { 690 | "text": "All", 691 | "value": "$__all" 692 | }, 693 | "datasource": { 694 | "type": "prometheus", 695 | "uid": "P1809F7CD0C75ACF3" 696 | }, 697 | "definition": "label_values(deployment_eth_rpc_request_duration,provider)", 698 | "includeAll": true, 699 | "multi": true, 700 | "name": "provider", 701 | "options": [], 702 | "query": { 703 | "qryType": 1, 704 | "query": "label_values(deployment_eth_rpc_request_duration,provider)", 705 | "refId": "PrometheusVariableQueryEditor-VariableQuery" 706 | }, 707 | "refresh": 1, 708 | "regex": "", 709 | "sort": 5, 710 | "type": "query" 711 | } 712 | ] 713 | }, 714 | "time": { 715 | "from": "now-24h", 716 | "to": "now" 717 | }, 718 | "timepicker": { 719 | "refresh_intervals": [ 720 | "10s", 721 | "30s", 722 | "1m", 723 | "5m", 724 | "15m", 725 | "30m", 726 | "1h", 727 | "2h", 728 | "1d" 729 | ] 730 | }, 731 | "timezone": "", 732 | "title": "Indexing Performance", 733 | "uid": "indexing-performance", 734 | "version": 3, 735 | "weekStart": "" 736 | } -------------------------------------------------------------------------------- /grafana/provisioning/dashboards/logs-explorer.json: -------------------------------------------------------------------------------- 1 | { 2 | "annotations": { 3 | "list": [ 4 | { 5 | "$$hashKey": "object:75", 6 | "builtIn": 1, 7 | "datasource": { 8 | "type": "datasource", 9 | "uid": "grafana" 10 | }, 11 | "enable": true, 12 | "hide": true, 13 | "iconColor": "rgba(0, 211, 255, 1)", 14 | "name": "Annotations & Alerts", 15 | "type": "dashboard" 16 | } 17 | ] 18 | }, 19 | "description": "Log Viewer Dashboard for Loki", 20 | "editable": true, 21 | "fiscalYearStartMonth": 0, 22 | "graphTooltip": 0, 23 | "id": 12, 24 | "links": [ 25 | { 26 | "$$hashKey": "object:59", 27 | "icon": "bolt", 28 | "includeVars": true, 29 | "keepTime": true, 30 | "tags": [], 31 | "targetBlank": true, 32 | "title": "View In Explore", 33 | "type": "link", 34 | "url": "/explore?orgId=1&left=[\"now-1h\",\"now\",\"Loki\",{\"expr\":\"{service_name=\\\"${source}\\\"}\"},{\"ui\":[true,true,true,\"none\"]}]" 35 | }, 36 | { 37 | "$$hashKey": "object:61", 38 | "icon": "external link", 39 | "tags": [], 40 | "targetBlank": true, 41 | "title": "Learn LogQL", 42 | "type": "link", 43 | "url": "https://grafana.com/docs/loki/latest/logql/" 44 | }, 45 | { 46 | "asDropdown": false, 47 | "icon": "external link", 48 | "includeVars": false, 49 | "keepTime": true, 50 | "tags": [], 51 | "targetBlank": true, 52 | "title": "Indexing Performance Metrics", 53 | "tooltip": "", 54 | "type": "link", 55 | "url": "/d/indexing-performance/indexing-performance?from=now-24h&to=now&var-deployment=${filter}&var-network=$__all&var-shard=$__all&var-provider=$__all" 56 | }, 57 | { 58 | "asDropdown": false, 59 | "icon": "external link", 60 | "includeVars": false, 61 | "keepTime": true, 62 | "tags": [], 63 | "targetBlank": true, 64 | "title": "Deployment Details", 65 | "tooltip": "", 66 | "type": "link", 67 | "url": "/d/SjWDBHSGz/deployment-details-graph?from=now-6h&to=now&var-account=indexer-agent&var-deployment=${filter}&var-shard=PA942B37CCFAF5A81&var-horizon=1y" 68 | } 69 | ], 70 | "panels": [ 71 | { 72 | "datasource": { 73 | "type": "loki", 74 | "uid": "P8E80F9AEF21F6940" 75 | }, 76 | "fieldConfig": { 77 | "defaults": { 78 | "color": { 79 | "mode": "palette-classic" 80 | }, 81 | "custom": { 82 | "axisBorderShow": false, 83 | "axisCenteredZero": false, 84 | "axisColorMode": "text", 85 | "axisLabel": "", 86 | "axisPlacement": "hidden", 87 | "barAlignment": 0, 88 | "barWidthFactor": 0.6, 89 | "drawStyle": "bars", 90 | "fillOpacity": 100, 91 | "gradientMode": "none", 92 | "hideFrom": { 93 | "legend": false, 94 | "tooltip": false, 95 | "viz": false 96 | }, 97 | "insertNulls": false, 98 | "lineInterpolation": "linear", 99 | "lineWidth": 1, 100 | "pointSize": 5, 101 | "scaleDistribution": { 102 | "type": "linear" 103 | }, 104 | "showPoints": "never", 105 | "spanNulls": false, 106 | "stacking": { 107 | "group": "A", 108 | "mode": "none" 109 | }, 110 | "thresholdsStyle": { 111 | "mode": "off" 112 | } 113 | }, 114 | "links": [], 115 | "mappings": [], 116 | "thresholds": { 117 | "mode": "absolute", 118 | "steps": [ 119 | { 120 | "color": "green", 121 | "value": null 122 | }, 123 | { 124 | "color": "red", 125 | "value": 80 126 | } 127 | ] 128 | }, 129 | "unit": "short" 130 | }, 131 | "overrides": [] 132 | }, 133 | "gridPos": { 134 | "h": 3, 135 | "w": 24, 136 | "x": 0, 137 | "y": 0 138 | }, 139 | "id": 6, 140 | "options": { 141 | "legend": { 142 | "calcs": [], 143 | "displayMode": "list", 144 | "placement": "bottom", 145 | "showLegend": false 146 | }, 147 | "tooltip": { 148 | "mode": "multi", 149 | "sort": "none" 150 | } 151 | }, 152 | "pluginVersion": "11.3.0", 153 | "targets": [ 154 | { 155 | "datasource": { 156 | "type": "loki", 157 | "uid": "P8E80F9AEF21F6940" 158 | }, 159 | "editorMode": "code", 160 | "expr": "sum(count_over_time({service_name=\"$source\"} |= \"$filter\" [$__interval]))", 161 | "legendFormat": "", 162 | "queryType": "range", 163 | "refId": "A" 164 | } 165 | ], 166 | "title": "", 167 | "type": "timeseries" 168 | }, 169 | { 170 | "datasource": { 171 | "type": "loki", 172 | "uid": "P8E80F9AEF21F6940" 173 | }, 174 | "fieldConfig": { 175 | "defaults": {}, 176 | "overrides": [] 177 | }, 178 | "gridPos": { 179 | "h": 25, 180 | "w": 24, 181 | "x": 0, 182 | "y": 3 183 | }, 184 | "id": 2, 185 | "maxDataPoints": "", 186 | "options": { 187 | "dedupStrategy": "none", 188 | "enableLogDetails": false, 189 | "prettifyLogMessage": false, 190 | "showCommonLabels": false, 191 | "showLabels": false, 192 | "showTime": false, 193 | "sortOrder": "Descending", 194 | "wrapLogMessage": false 195 | }, 196 | "pluginVersion": "11.3.0", 197 | "targets": [ 198 | { 199 | "datasource": { 200 | "type": "loki", 201 | "uid": "P8E80F9AEF21F6940" 202 | }, 203 | "editorMode": "code", 204 | "expr": "{service_name=\"$source\"} |= \"$filter\" | logfmt", 205 | "hide": false, 206 | "legendFormat": "", 207 | "queryType": "range", 208 | "refId": "A" 209 | } 210 | ], 211 | "title": "", 212 | "transparent": true, 213 | "type": "logs" 214 | } 215 | ], 216 | "preload": false, 217 | "refresh": "", 218 | "schemaVersion": 40, 219 | "tags": [], 220 | "templating": { 221 | "list": [ 222 | { 223 | "current": { 224 | "text": "/index-node-0", 225 | "value": "/index-node-0" 226 | }, 227 | "datasource": "P8E80F9AEF21F6940", 228 | "definition": "", 229 | "includeAll": false, 230 | "label": "Source", 231 | "name": "source", 232 | "options": [], 233 | "query": { 234 | "label": "service_name", 235 | "refId": "LokiVariableQueryEditor-VariableQuery", 236 | "stream": "", 237 | "type": 1 238 | }, 239 | "refresh": 1, 240 | "regex": "", 241 | "type": "query" 242 | }, 243 | { 244 | "current": { 245 | "text": "Qmc6zPWLPCj42k2vujAYaHaMZBFHAnpfsa4KzUwtFXFLA2", 246 | "value": "Qmc6zPWLPCj42k2vujAYaHaMZBFHAnpfsa4KzUwtFXFLA2" 247 | }, 248 | "label": "LogQL Filter", 249 | "name": "filter", 250 | "options": [ 251 | { 252 | "selected": true, 253 | "text": "Qmc6zPWLPCj42k2vujAYaHaMZBFHAnpfsa4KzUwtFXFLA2", 254 | "value": "Qmc6zPWLPCj42k2vujAYaHaMZBFHAnpfsa4KzUwtFXFLA2" 255 | } 256 | ], 257 | "query": "Qmc6zPWLPCj42k2vujAYaHaMZBFHAnpfsa4KzUwtFXFLA2", 258 | "type": "textbox" 259 | } 260 | ] 261 | }, 262 | "time": { 263 | "from": "now-5m", 264 | "to": "now" 265 | }, 266 | "timepicker": { 267 | "refresh_intervals": [ 268 | "10s", 269 | "30s", 270 | "1m", 271 | "5m", 272 | "15m", 273 | "30m", 274 | "1h", 275 | "2h", 276 | "1d" 277 | ] 278 | }, 279 | "timezone": "", 280 | "title": "Logs explorer", 281 | "uid": "a9T5kG7dF", 282 | "version": 3, 283 | "weekStart": "" 284 | } -------------------------------------------------------------------------------- /grafana/provisioning/dashboards/postgres-sizes.json: -------------------------------------------------------------------------------- 1 | { 2 | "annotations": { 3 | "list": [ 4 | { 5 | "builtIn": 1, 6 | "datasource": { 7 | "type": "datasource", 8 | "uid": "grafana" 9 | }, 10 | "enable": true, 11 | "hide": true, 12 | "iconColor": "rgba(0, 211, 255, 1)", 13 | "name": "Annotations & Alerts", 14 | "target": { 15 | "limit": 100, 16 | "matchAny": false, 17 | "tags": [], 18 | "type": "dashboard" 19 | }, 20 | "type": "dashboard" 21 | } 22 | ] 23 | }, 24 | "editable": true, 25 | "fiscalYearStartMonth": 0, 26 | "graphTooltip": 0, 27 | "id": 7, 28 | "links": [], 29 | "panels": [ 30 | { 31 | "datasource": { 32 | "type": "postgres", 33 | "uid": "$shard" 34 | }, 35 | "description": "Data from a materialized view that is refreshed only occasionally", 36 | "fieldConfig": { 37 | "defaults": { 38 | "color": { 39 | "mode": "thresholds" 40 | }, 41 | "custom": { 42 | "align": "auto", 43 | "cellOptions": { 44 | "type": "auto", 45 | "wrapText": false 46 | }, 47 | "filterable": true, 48 | "inspect": false 49 | }, 50 | "mappings": [], 51 | "thresholds": { 52 | "mode": "absolute", 53 | "steps": [ 54 | { 55 | "color": "green", 56 | "value": null 57 | }, 58 | { 59 | "color": "red", 60 | "value": 80 61 | } 62 | ] 63 | } 64 | }, 65 | "overrides": [ 66 | { 67 | "matcher": { 68 | "id": "byRegexp", 69 | "options": "/(.*)_bytes/" 70 | }, 71 | "properties": [ 72 | { 73 | "id": "displayName" 74 | }, 75 | { 76 | "id": "unit", 77 | "value": "bytes" 78 | } 79 | ] 80 | }, 81 | { 82 | "matcher": { 83 | "id": "byName", 84 | "options": "name" 85 | }, 86 | "properties": [ 87 | { 88 | "id": "custom.filterable", 89 | "value": true 90 | }, 91 | { 92 | "id": "custom.width", 93 | "value": 140 94 | } 95 | ] 96 | }, 97 | { 98 | "matcher": { 99 | "id": "byName", 100 | "options": "subgraph" 101 | }, 102 | "properties": [ 103 | { 104 | "id": "custom.filterable", 105 | "value": true 106 | } 107 | ] 108 | }, 109 | { 110 | "matcher": { 111 | "id": "byName", 112 | "options": "table_name" 113 | }, 114 | "properties": [ 115 | { 116 | "id": "custom.width", 117 | "value": 103 118 | } 119 | ] 120 | }, 121 | { 122 | "matcher": { 123 | "id": "byName", 124 | "options": "table_schema" 125 | }, 126 | "properties": [ 127 | { 128 | "id": "custom.width", 129 | "value": 123 130 | } 131 | ] 132 | }, 133 | { 134 | "matcher": { 135 | "id": "byName", 136 | "options": "row_estimate" 137 | }, 138 | "properties": [ 139 | { 140 | "id": "unit", 141 | "value": "short" 142 | } 143 | ] 144 | } 145 | ] 146 | }, 147 | "gridPos": { 148 | "h": 8, 149 | "w": 24, 150 | "x": 0, 151 | "y": 0 152 | }, 153 | "id": 4, 154 | "options": { 155 | "cellHeight": "sm", 156 | "footer": { 157 | "countRows": false, 158 | "fields": "", 159 | "reducer": [ 160 | "sum" 161 | ], 162 | "show": false 163 | }, 164 | "showHeader": true, 165 | "sortBy": [ 166 | { 167 | "desc": true, 168 | "displayName": "total_bytes" 169 | } 170 | ] 171 | }, 172 | "pluginVersion": "11.3.0", 173 | "targets": [ 174 | { 175 | "datasource": { 176 | "type": "postgres", 177 | "uid": "PA942B37CCFAF5A81" 178 | }, 179 | "editorMode": "code", 180 | "format": "table", 181 | "group": [], 182 | "hide": false, 183 | "metricColumn": "none", 184 | "rawQuery": true, 185 | "rawSql": "-- grafana ignore\nselect c.name, table_schema, table_name, row_estimate, total_bytes, total_bytes - index_bytes - toast_bytes as table_bytes, index_bytes, toast_bytes\n from info.chain_sizes sz, chains c\n where sz.table_schema = c.namespace\norder by total_bytes desc", 186 | "refId": "A", 187 | "select": [ 188 | [ 189 | { 190 | "params": [ 191 | "value" 192 | ], 193 | "type": "column" 194 | } 195 | ] 196 | ], 197 | "sql": { 198 | "columns": [ 199 | { 200 | "parameters": [], 201 | "type": "function" 202 | } 203 | ], 204 | "groupBy": [ 205 | { 206 | "property": { 207 | "type": "string" 208 | }, 209 | "type": "groupBy" 210 | } 211 | ], 212 | "limit": 50 213 | }, 214 | "timeColumn": "time", 215 | "where": [ 216 | { 217 | "name": "$__timeFilter", 218 | "params": [], 219 | "type": "macro" 220 | } 221 | ] 222 | } 223 | ], 224 | "title": "Chain sizes", 225 | "transformations": [ 226 | { 227 | "id": "merge", 228 | "options": { 229 | "reducers": [] 230 | } 231 | } 232 | ], 233 | "transparent": true, 234 | "type": "table" 235 | }, 236 | { 237 | "datasource": { 238 | "type": "postgres", 239 | "uid": "$shard" 240 | }, 241 | "description": "Data from a materialized view that is refreshed only occasionally", 242 | "fieldConfig": { 243 | "defaults": { 244 | "color": { 245 | "mode": "thresholds" 246 | }, 247 | "custom": { 248 | "align": "auto", 249 | "cellOptions": { 250 | "type": "auto" 251 | }, 252 | "inspect": false 253 | }, 254 | "mappings": [], 255 | "thresholds": { 256 | "mode": "absolute", 257 | "steps": [ 258 | { 259 | "color": "green", 260 | "value": null 261 | }, 262 | { 263 | "color": "red", 264 | "value": 80 265 | } 266 | ] 267 | } 268 | }, 269 | "overrides": [ 270 | { 271 | "matcher": { 272 | "id": "byRegexp", 273 | "options": "/(.*)_bytes/" 274 | }, 275 | "properties": [ 276 | { 277 | "id": "displayName" 278 | }, 279 | { 280 | "id": "unit", 281 | "value": "bytes" 282 | } 283 | ] 284 | }, 285 | { 286 | "matcher": { 287 | "id": "byName", 288 | "options": "name" 289 | }, 290 | "properties": [ 291 | { 292 | "id": "custom.filterable", 293 | "value": true 294 | } 295 | ] 296 | }, 297 | { 298 | "matcher": { 299 | "id": "byName", 300 | "options": "subgraph" 301 | }, 302 | "properties": [ 303 | { 304 | "id": "custom.filterable", 305 | "value": true 306 | } 307 | ] 308 | }, 309 | { 310 | "matcher": { 311 | "id": "byName", 312 | "options": "row_estimate" 313 | }, 314 | "properties": [ 315 | { 316 | "id": "unit", 317 | "value": "short" 318 | } 319 | ] 320 | } 321 | ] 322 | }, 323 | "gridPos": { 324 | "h": 9, 325 | "w": 24, 326 | "x": 0, 327 | "y": 8 328 | }, 329 | "id": 3, 330 | "options": { 331 | "cellHeight": "sm", 332 | "footer": { 333 | "countRows": false, 334 | "fields": "", 335 | "reducer": [ 336 | "sum" 337 | ], 338 | "show": false 339 | }, 340 | "showHeader": true, 341 | "sortBy": [ 342 | { 343 | "desc": true, 344 | "displayName": "toast_bytes" 345 | } 346 | ] 347 | }, 348 | "pluginVersion": "11.3.0", 349 | "targets": [ 350 | { 351 | "datasource": { 352 | "type": "postgres", 353 | "uid": "PA942B37CCFAF5A81" 354 | }, 355 | "editorMode": "code", 356 | "format": "table", 357 | "group": [], 358 | "hide": false, 359 | "metricColumn": "none", 360 | "rawQuery": true, 361 | "rawSql": "-- grafana ignore\nselect name, subgraph, row_estimate, total_bytes, total_bytes - index_bytes - toast_bytes as table_bytes, index_bytes, toast_bytes\n from info.subgraph_sizes\norder by total_bytes desc", 362 | "refId": "A", 363 | "select": [ 364 | [ 365 | { 366 | "params": [ 367 | "value" 368 | ], 369 | "type": "column" 370 | } 371 | ] 372 | ], 373 | "sql": { 374 | "columns": [ 375 | { 376 | "parameters": [], 377 | "type": "function" 378 | } 379 | ], 380 | "groupBy": [ 381 | { 382 | "property": { 383 | "type": "string" 384 | }, 385 | "type": "groupBy" 386 | } 387 | ], 388 | "limit": 50 389 | }, 390 | "timeColumn": "time", 391 | "where": [ 392 | { 393 | "name": "$__timeFilter", 394 | "params": [], 395 | "type": "macro" 396 | } 397 | ] 398 | } 399 | ], 400 | "title": "Subgraph sizes", 401 | "transformations": [ 402 | { 403 | "id": "merge", 404 | "options": { 405 | "reducers": [] 406 | } 407 | } 408 | ], 409 | "transparent": true, 410 | "type": "table" 411 | }, 412 | { 413 | "datasource": { 414 | "uid": "$shard" 415 | }, 416 | "description": "Data from a materialized view that is refreshed only occasionally", 417 | "fieldConfig": { 418 | "defaults": { 419 | "custom": { 420 | "align": "auto", 421 | "cellOptions": { 422 | "type": "auto" 423 | }, 424 | "inspect": false 425 | }, 426 | "mappings": [], 427 | "thresholds": { 428 | "mode": "absolute", 429 | "steps": [ 430 | { 431 | "color": "green", 432 | "value": null 433 | }, 434 | { 435 | "color": "red", 436 | "value": 80 437 | } 438 | ] 439 | } 440 | }, 441 | "overrides": [ 442 | { 443 | "matcher": { 444 | "id": "byRegexp", 445 | "options": "/(.*)_bytes/" 446 | }, 447 | "properties": [ 448 | { 449 | "id": "displayName", 450 | "value": "$1" 451 | }, 452 | { 453 | "id": "unit", 454 | "value": "bytes" 455 | }, 456 | { 457 | "id": "custom.align" 458 | } 459 | ] 460 | }, 461 | { 462 | "matcher": { 463 | "id": "byName", 464 | "options": "rows" 465 | }, 466 | "properties": [ 467 | { 468 | "id": "displayName", 469 | "value": "Rows" 470 | }, 471 | { 472 | "id": "unit", 473 | "value": "locale" 474 | }, 475 | { 476 | "id": "custom.align" 477 | } 478 | ] 479 | }, 480 | { 481 | "matcher": { 482 | "id": "byName", 483 | "options": "table_schema" 484 | }, 485 | "properties": [ 486 | { 487 | "id": "displayName", 488 | "value": "Schema" 489 | }, 490 | { 491 | "id": "unit", 492 | "value": "short" 493 | }, 494 | { 495 | "id": "decimals", 496 | "value": 2 497 | }, 498 | { 499 | "id": "custom.align" 500 | } 501 | ] 502 | }, 503 | { 504 | "matcher": { 505 | "id": "byName", 506 | "options": "table_name" 507 | }, 508 | "properties": [ 509 | { 510 | "id": "displayName", 511 | "value": "Table / Subgraph" 512 | }, 513 | { 514 | "id": "unit", 515 | "value": "short" 516 | }, 517 | { 518 | "id": "decimals", 519 | "value": 2 520 | }, 521 | { 522 | "id": "custom.align" 523 | } 524 | ] 525 | }, 526 | { 527 | "matcher": { 528 | "id": "byName", 529 | "options": "version" 530 | }, 531 | "properties": [ 532 | { 533 | "id": "displayName", 534 | "value": "Version" 535 | }, 536 | { 537 | "id": "unit", 538 | "value": "short" 539 | }, 540 | { 541 | "id": "decimals", 542 | "value": 2 543 | }, 544 | { 545 | "id": "custom.align" 546 | } 547 | ] 548 | } 549 | ] 550 | }, 551 | "gridPos": { 552 | "h": 8, 553 | "w": 24, 554 | "x": 0, 555 | "y": 17 556 | }, 557 | "id": 2, 558 | "options": { 559 | "cellHeight": "sm", 560 | "footer": { 561 | "countRows": false, 562 | "fields": "", 563 | "reducer": [ 564 | "sum" 565 | ], 566 | "show": false 567 | }, 568 | "showHeader": true 569 | }, 570 | "pluginVersion": "11.3.0", 571 | "targets": [ 572 | { 573 | "datasource": { 574 | "uid": "$shard" 575 | }, 576 | "format": "table", 577 | "group": [], 578 | "hide": false, 579 | "metricColumn": "none", 580 | "rawQuery": true, 581 | "rawSql": "-- grafana ignore\nselect table_schema, table_name, version, row_estimate, total_bytes, index_bytes, toast_bytes\n from info.table_sizes", 582 | "refId": "A", 583 | "select": [ 584 | [ 585 | { 586 | "params": [ 587 | "value" 588 | ], 589 | "type": "column" 590 | } 591 | ] 592 | ], 593 | "timeColumn": "time", 594 | "where": [ 595 | { 596 | "name": "$__timeFilter", 597 | "params": [], 598 | "type": "macro" 599 | } 600 | ] 601 | } 602 | ], 603 | "title": "Table sizes", 604 | "transparent": true, 605 | "type": "table" 606 | } 607 | ], 608 | "preload": false, 609 | "refresh": "", 610 | "schemaVersion": 40, 611 | "tags": [], 612 | "templating": { 613 | "list": [ 614 | { 615 | "current": { 616 | "text": "postgres", 617 | "value": "PA942B37CCFAF5A81" 618 | }, 619 | "includeAll": false, 620 | "name": "shard", 621 | "options": [], 622 | "query": "postgres", 623 | "refresh": 1, 624 | "regex": "/.*/", 625 | "type": "datasource" 626 | } 627 | ] 628 | }, 629 | "time": { 630 | "from": "now-6h", 631 | "to": "now" 632 | }, 633 | "timepicker": {}, 634 | "timezone": "", 635 | "title": "Postgres sizes", 636 | "uid": "W6lN8XaZz", 637 | "version": 4, 638 | "weekStart": "" 639 | } -------------------------------------------------------------------------------- /grafana/provisioning/dashboards/subgraph-radio.json: -------------------------------------------------------------------------------- 1 | { 2 | "annotations": { 3 | "list": [ 4 | { 5 | "builtIn": 1, 6 | "datasource": { 7 | "type": "datasource", 8 | "uid": "grafana" 9 | }, 10 | "enable": true, 11 | "hide": true, 12 | "iconColor": "rgba(0, 211, 255, 1)", 13 | "name": "Annotations & Alerts", 14 | "target": { 15 | "limit": 100, 16 | "matchAny": false, 17 | "tags": [], 18 | "type": "dashboard" 19 | }, 20 | "type": "dashboard" 21 | } 22 | ] 23 | }, 24 | "editable": true, 25 | "fiscalYearStartMonth": 0, 26 | "graphTooltip": 0, 27 | "id": 19, 28 | "links": [], 29 | "panels": [ 30 | { 31 | "datasource": { 32 | "type": "yesoreyeram-infinity-datasource", 33 | "uid": "P5A6B38C2885E7F26" 34 | }, 35 | "fieldConfig": { 36 | "defaults": { 37 | "color": { 38 | "mode": "thresholds" 39 | }, 40 | "mappings": [], 41 | "thresholds": { 42 | "mode": "absolute", 43 | "steps": [ 44 | { 45 | "color": "green", 46 | "value": null 47 | } 48 | ] 49 | } 50 | }, 51 | "overrides": [] 52 | }, 53 | "gridPos": { 54 | "h": 8, 55 | "w": 12, 56 | "x": 0, 57 | "y": 0 58 | }, 59 | "id": 123142, 60 | "options": { 61 | "minVizHeight": 75, 62 | "minVizWidth": 75, 63 | "orientation": "auto", 64 | "reduceOptions": { 65 | "calcs": [ 66 | "lastNotNull" 67 | ], 68 | "fields": "", 69 | "values": true 70 | }, 71 | "showThresholdLabels": false, 72 | "showThresholdMarkers": true, 73 | "sizing": "auto" 74 | }, 75 | "pluginVersion": "11.3.0", 76 | "targets": [ 77 | { 78 | "columns": [], 79 | "datasource": { 80 | "type": "yesoreyeram-infinity-datasource", 81 | "uid": "P5A6B38C2885E7F26" 82 | }, 83 | "filters": [ 84 | { 85 | "field": "", 86 | "operator": "equals", 87 | "value": [ 88 | "" 89 | ] 90 | } 91 | ], 92 | "format": "table", 93 | "global_query_id": "", 94 | "refId": "A", 95 | "root_selector": "$.data.[*]", 96 | "source": "url", 97 | "type": "graphql", 98 | "url": "http://subgraph-radio:3012/api/v1/graphql", 99 | "url_options": { 100 | "body_content_type": "application/json", 101 | "body_graphql_query": "query {\n data:comparisonResults{\n deployment\n resultType\n }\n}", 102 | "body_type": "graphql", 103 | "data": "", 104 | "method": "POST" 105 | } 106 | } 107 | ], 108 | "title": "POI Comparison Overview", 109 | "transformations": [ 110 | { 111 | "disabled": true, 112 | "id": "renameByRegex", 113 | "options": { 114 | "regex": "(.*)", 115 | "renamePattern": "$1" 116 | } 117 | }, 118 | { 119 | "disabled": true, 120 | "id": "renameByRegex", 121 | "options": { 122 | "regex": "(.+)_deployment.*", 123 | "renamePattern": "$1" 124 | } 125 | }, 126 | { 127 | "id": "groupBy", 128 | "options": { 129 | "fields": { 130 | "deployment": { 131 | "aggregations": [ 132 | "count" 133 | ], 134 | "operation": "aggregate" 135 | }, 136 | "resultType": { 137 | "aggregations": [], 138 | "operation": "groupby" 139 | } 140 | } 141 | } 142 | } 143 | ], 144 | "type": "gauge" 145 | }, 146 | { 147 | "datasource": { 148 | "type": "prometheus", 149 | "uid": "P1809F7CD0C75ACF3" 150 | }, 151 | "fieldConfig": { 152 | "defaults": { 153 | "color": { 154 | "mode": "palette-classic" 155 | }, 156 | "custom": { 157 | "axisBorderShow": false, 158 | "axisCenteredZero": false, 159 | "axisColorMode": "text", 160 | "axisLabel": "", 161 | "axisPlacement": "auto", 162 | "barAlignment": 0, 163 | "barWidthFactor": 0.6, 164 | "drawStyle": "line", 165 | "fillOpacity": 0, 166 | "gradientMode": "none", 167 | "hideFrom": { 168 | "legend": false, 169 | "tooltip": false, 170 | "viz": false 171 | }, 172 | "insertNulls": false, 173 | "lineInterpolation": "linear", 174 | "lineWidth": 1, 175 | "pointSize": 5, 176 | "scaleDistribution": { 177 | "type": "linear" 178 | }, 179 | "showPoints": "auto", 180 | "spanNulls": false, 181 | "stacking": { 182 | "group": "A", 183 | "mode": "none" 184 | }, 185 | "thresholdsStyle": { 186 | "mode": "off" 187 | } 188 | }, 189 | "mappings": [], 190 | "thresholds": { 191 | "mode": "absolute", 192 | "steps": [ 193 | { 194 | "color": "green", 195 | "value": null 196 | }, 197 | { 198 | "color": "red", 199 | "value": 80 200 | } 201 | ] 202 | } 203 | }, 204 | "overrides": [] 205 | }, 206 | "gridPos": { 207 | "h": 8, 208 | "w": 12, 209 | "x": 12, 210 | "y": 0 211 | }, 212 | "id": 123125, 213 | "options": { 214 | "legend": { 215 | "calcs": [ 216 | "last", 217 | "min", 218 | "max" 219 | ], 220 | "displayMode": "table", 221 | "placement": "bottom", 222 | "showLegend": true, 223 | "sortBy": "Last", 224 | "sortDesc": true 225 | }, 226 | "tooltip": { 227 | "mode": "single", 228 | "sort": "none" 229 | } 230 | }, 231 | "pluginVersion": "11.3.0", 232 | "targets": [ 233 | { 234 | "datasource": { 235 | "type": "prometheus", 236 | "uid": "P1809F7CD0C75ACF3" 237 | }, 238 | "editorMode": "code", 239 | "exemplar": false, 240 | "expr": "graphcast_subgraph_radio_connected_peers", 241 | "interval": "", 242 | "legendFormat": "", 243 | "range": true, 244 | "refId": "A" 245 | }, 246 | { 247 | "datasource": { 248 | "type": "prometheus", 249 | "uid": "P1809F7CD0C75ACF3" 250 | }, 251 | "exemplar": true, 252 | "expr": "graphcast_subgraph_radio_gossip_peers", 253 | "hide": false, 254 | "interval": "", 255 | "legendFormat": "", 256 | "refId": "B" 257 | } 258 | ], 259 | "title": "Number of Gossiping Indexers per Subgraph", 260 | "type": "timeseries" 261 | }, 262 | { 263 | "datasource": { 264 | "type": "prometheus", 265 | "uid": "P1809F7CD0C75ACF3" 266 | }, 267 | "description": "Average metrics based on each scrape\n- counter for received valid messages\n- gauge of cached messages\n\n- cached messages \n", 268 | "fieldConfig": { 269 | "defaults": { 270 | "color": { 271 | "mode": "thresholds" 272 | }, 273 | "mappings": [], 274 | "thresholds": { 275 | "mode": "absolute", 276 | "steps": [ 277 | { 278 | "color": "green", 279 | "value": null 280 | } 281 | ] 282 | } 283 | }, 284 | "overrides": [] 285 | }, 286 | "gridPos": { 287 | "h": 8, 288 | "w": 12, 289 | "x": 0, 290 | "y": 8 291 | }, 292 | "id": 123139, 293 | "options": { 294 | "colorMode": "value", 295 | "graphMode": "area", 296 | "justifyMode": "auto", 297 | "orientation": "horizontal", 298 | "percentChangeColorMode": "standard", 299 | "reduceOptions": { 300 | "calcs": [ 301 | "lastNotNull" 302 | ], 303 | "fields": "", 304 | "values": false 305 | }, 306 | "showPercentChange": false, 307 | "textMode": "auto", 308 | "wideLayout": true 309 | }, 310 | "pluginVersion": "11.3.0", 311 | "targets": [ 312 | { 313 | "datasource": { 314 | "type": "prometheus", 315 | "uid": "P1809F7CD0C75ACF3" 316 | }, 317 | "editorMode": "builder", 318 | "exemplar": false, 319 | "expr": "sum(rate(graphcast_subgraph_radio_validated_messages{}[30m])) * 60", 320 | "hide": false, 321 | "instant": false, 322 | "interval": "", 323 | "legendFormat": "Messages Validated/Minute", 324 | "range": true, 325 | "refId": "Received Messages" 326 | }, 327 | { 328 | "datasource": { 329 | "type": "prometheus", 330 | "uid": "P1809F7CD0C75ACF3" 331 | }, 332 | "editorMode": "code", 333 | "exemplar": false, 334 | "expr": "sum(graphcast_subgraph_radio_cached_ppoi_messages{})", 335 | "hide": false, 336 | "instant": false, 337 | "interval": "", 338 | "legendFormat": "Messages In Store", 339 | "refId": "Cached Messages" 340 | }, 341 | { 342 | "datasource": { 343 | "type": "prometheus", 344 | "uid": "P1809F7CD0C75ACF3" 345 | }, 346 | "exemplar": false, 347 | "expr": "sum(graphcast_subgraph_radio_received_messages)", 348 | "hide": false, 349 | "interval": "", 350 | "legendFormat": "Received Messages", 351 | "refId": "A" 352 | } 353 | ], 354 | "title": "Message stats", 355 | "type": "stat" 356 | }, 357 | { 358 | "datasource": { 359 | "type": "prometheus", 360 | "uid": "P1809F7CD0C75ACF3" 361 | }, 362 | "fieldConfig": { 363 | "defaults": { 364 | "color": { 365 | "mode": "palette-classic" 366 | }, 367 | "custom": { 368 | "axisBorderShow": false, 369 | "axisCenteredZero": false, 370 | "axisColorMode": "text", 371 | "axisLabel": "", 372 | "axisPlacement": "auto", 373 | "barAlignment": 0, 374 | "barWidthFactor": 0.6, 375 | "drawStyle": "line", 376 | "fillOpacity": 0, 377 | "gradientMode": "none", 378 | "hideFrom": { 379 | "legend": false, 380 | "tooltip": false, 381 | "viz": false 382 | }, 383 | "insertNulls": false, 384 | "lineInterpolation": "linear", 385 | "lineWidth": 1, 386 | "pointSize": 5, 387 | "scaleDistribution": { 388 | "type": "linear" 389 | }, 390 | "showPoints": "auto", 391 | "spanNulls": false, 392 | "stacking": { 393 | "group": "A", 394 | "mode": "none" 395 | }, 396 | "thresholdsStyle": { 397 | "mode": "off" 398 | } 399 | }, 400 | "mappings": [], 401 | "thresholds": { 402 | "mode": "absolute", 403 | "steps": [ 404 | { 405 | "color": "green", 406 | "value": null 407 | }, 408 | { 409 | "color": "red", 410 | "value": 80 411 | } 412 | ] 413 | } 414 | }, 415 | "overrides": [] 416 | }, 417 | "gridPos": { 418 | "h": 8, 419 | "w": 12, 420 | "x": 12, 421 | "y": 8 422 | }, 423 | "id": 123129, 424 | "options": { 425 | "legend": { 426 | "calcs": [], 427 | "displayMode": "list", 428 | "placement": "bottom", 429 | "showLegend": true 430 | }, 431 | "tooltip": { 432 | "mode": "single", 433 | "sort": "none" 434 | } 435 | }, 436 | "pluginVersion": "11.3.0", 437 | "targets": [ 438 | { 439 | "datasource": { 440 | "type": "prometheus", 441 | "uid": "P1809F7CD0C75ACF3" 442 | }, 443 | "exemplar": true, 444 | "expr": "function_calls_concurrent", 445 | "interval": "", 446 | "legendFormat": "", 447 | "refId": "A" 448 | }, 449 | { 450 | "datasource": { 451 | "type": "prometheus", 452 | "uid": "P1809F7CD0C75ACF3" 453 | }, 454 | "exemplar": true, 455 | "expr": "histogram_quantile(0.95, sum(rate(function_calls_duration_bucket[5m])) by (le))", 456 | "hide": false, 457 | "interval": "", 458 | "legendFormat": "", 459 | "refId": "B" 460 | }, 461 | { 462 | "datasource": { 463 | "type": "prometheus", 464 | "uid": "P1809F7CD0C75ACF3" 465 | }, 466 | "exemplar": true, 467 | "expr": "rate(function_calls_count[5m])", 468 | "hide": false, 469 | "interval": "", 470 | "legendFormat": "", 471 | "refId": "C" 472 | } 473 | ], 474 | "title": "Function Call Stats", 475 | "type": "timeseries" 476 | }, 477 | { 478 | "datasource": { 479 | "type": "yesoreyeram-infinity-datasource", 480 | "uid": "P5A6B38C2885E7F26" 481 | }, 482 | "fieldConfig": { 483 | "defaults": { 484 | "color": { 485 | "mode": "thresholds" 486 | }, 487 | "custom": { 488 | "align": "auto", 489 | "cellOptions": { 490 | "type": "auto" 491 | }, 492 | "inspect": false 493 | }, 494 | "mappings": [], 495 | "thresholds": { 496 | "mode": "absolute", 497 | "steps": [ 498 | { 499 | "color": "green", 500 | "value": null 501 | }, 502 | { 503 | "color": "red", 504 | "value": 80 505 | } 506 | ] 507 | } 508 | }, 509 | "overrides": [ 510 | { 511 | "matcher": { 512 | "id": "byName", 513 | "options": "blockNumber" 514 | }, 515 | "properties": [ 516 | { 517 | "id": "custom.width", 518 | "value": 117 519 | } 520 | ] 521 | }, 522 | { 523 | "matcher": { 524 | "id": "byName", 525 | "options": "deployment" 526 | }, 527 | "properties": [ 528 | { 529 | "id": "custom.width", 530 | "value": 452 531 | } 532 | ] 533 | } 534 | ] 535 | }, 536 | "gridPos": { 537 | "h": 16, 538 | "w": 12, 539 | "x": 0, 540 | "y": 16 541 | }, 542 | "id": 123143, 543 | "options": { 544 | "cellHeight": "sm", 545 | "footer": { 546 | "countRows": false, 547 | "fields": "", 548 | "reducer": [ 549 | "sum" 550 | ], 551 | "show": false 552 | }, 553 | "showHeader": true, 554 | "sortBy": [] 555 | }, 556 | "pluginVersion": "11.3.0", 557 | "targets": [ 558 | { 559 | "columns": [], 560 | "datasource": { 561 | "type": "yesoreyeram-infinity-datasource", 562 | "uid": "P5A6B38C2885E7F26" 563 | }, 564 | "filters": [], 565 | "format": "table", 566 | "global_query_id": "", 567 | "refId": "A", 568 | "root_selector": "$.data.[*]", 569 | "source": "url", 570 | "type": "graphql", 571 | "url": "http://subgraph-radio:3012/api/v1/graphql", 572 | "url_options": { 573 | "body_content_type": "application/json", 574 | "body_graphql_query": "query {\n data:comparisonRatio{\n deployment\n blockNumber\n senderRatio\n stakeRatio\n }\n}", 575 | "body_type": "graphql", 576 | "data": "", 577 | "method": "POST", 578 | "params": [] 579 | } 580 | } 581 | ], 582 | "title": "POI Comparison Results", 583 | "transformations": [ 584 | { 585 | "id": "filterByValue", 586 | "options": { 587 | "filters": [ 588 | { 589 | "config": { 590 | "id": "regex", 591 | "options": { 592 | "value": "null" 593 | } 594 | }, 595 | "fieldName": "blockNumber" 596 | } 597 | ], 598 | "match": "any", 599 | "type": "exclude" 600 | } 601 | } 602 | ], 603 | "type": "table" 604 | }, 605 | { 606 | "datasource": { 607 | "type": "prometheus", 608 | "uid": "P1809F7CD0C75ACF3" 609 | }, 610 | "fieldConfig": { 611 | "defaults": { 612 | "color": { 613 | "mode": "palette-classic" 614 | }, 615 | "custom": { 616 | "axisBorderShow": false, 617 | "axisCenteredZero": false, 618 | "axisColorMode": "text", 619 | "axisLabel": "", 620 | "axisPlacement": "auto", 621 | "barAlignment": 0, 622 | "barWidthFactor": 0.6, 623 | "drawStyle": "line", 624 | "fillOpacity": 0, 625 | "gradientMode": "none", 626 | "hideFrom": { 627 | "legend": false, 628 | "tooltip": false, 629 | "viz": false 630 | }, 631 | "insertNulls": false, 632 | "lineInterpolation": "linear", 633 | "lineWidth": 1, 634 | "pointSize": 5, 635 | "scaleDistribution": { 636 | "type": "linear" 637 | }, 638 | "showPoints": "auto", 639 | "spanNulls": false, 640 | "stacking": { 641 | "group": "A", 642 | "mode": "none" 643 | }, 644 | "thresholdsStyle": { 645 | "mode": "off" 646 | } 647 | }, 648 | "mappings": [], 649 | "thresholds": { 650 | "mode": "absolute", 651 | "steps": [ 652 | { 653 | "color": "green", 654 | "value": null 655 | }, 656 | { 657 | "color": "red", 658 | "value": 80 659 | } 660 | ] 661 | } 662 | }, 663 | "overrides": [] 664 | }, 665 | "gridPos": { 666 | "h": 8, 667 | "w": 12, 668 | "x": 12, 669 | "y": 16 670 | }, 671 | "id": 123135, 672 | "options": { 673 | "legend": { 674 | "calcs": [ 675 | "last", 676 | "min", 677 | "max", 678 | "sum" 679 | ], 680 | "displayMode": "table", 681 | "placement": "bottom", 682 | "showLegend": true, 683 | "sortBy": "Last", 684 | "sortDesc": true 685 | }, 686 | "tooltip": { 687 | "mode": "single", 688 | "sort": "none" 689 | } 690 | }, 691 | "pluginVersion": "11.3.0", 692 | "targets": [ 693 | { 694 | "datasource": { 695 | "type": "prometheus", 696 | "uid": "P1809F7CD0C75ACF3" 697 | }, 698 | "editorMode": "code", 699 | "exemplar": true, 700 | "expr": "graphcast_subgraph_radio_local_ppois_to_compare", 701 | "interval": "", 702 | "legendFormat": "{{deployment}}", 703 | "range": true, 704 | "refId": "A" 705 | } 706 | ], 707 | "title": "Locally tracked Public POIs", 708 | "type": "timeseries" 709 | }, 710 | { 711 | "datasource": { 712 | "type": "prometheus", 713 | "uid": "P1809F7CD0C75ACF3" 714 | }, 715 | "fieldConfig": { 716 | "defaults": { 717 | "color": { 718 | "mode": "palette-classic" 719 | }, 720 | "custom": { 721 | "axisBorderShow": false, 722 | "axisCenteredZero": false, 723 | "axisColorMode": "text", 724 | "axisLabel": "", 725 | "axisPlacement": "auto", 726 | "barAlignment": 0, 727 | "barWidthFactor": 0.6, 728 | "drawStyle": "line", 729 | "fillOpacity": 0, 730 | "gradientMode": "none", 731 | "hideFrom": { 732 | "legend": false, 733 | "tooltip": false, 734 | "viz": false 735 | }, 736 | "insertNulls": false, 737 | "lineInterpolation": "linear", 738 | "lineWidth": 1, 739 | "pointSize": 5, 740 | "scaleDistribution": { 741 | "type": "linear" 742 | }, 743 | "showPoints": "auto", 744 | "spanNulls": false, 745 | "stacking": { 746 | "group": "A", 747 | "mode": "none" 748 | }, 749 | "thresholdsStyle": { 750 | "mode": "off" 751 | } 752 | }, 753 | "mappings": [], 754 | "thresholds": { 755 | "mode": "absolute", 756 | "steps": [ 757 | { 758 | "color": "green", 759 | "value": null 760 | }, 761 | { 762 | "color": "red", 763 | "value": 80 764 | } 765 | ] 766 | } 767 | }, 768 | "overrides": [] 769 | }, 770 | "gridPos": { 771 | "h": 8, 772 | "w": 12, 773 | "x": 12, 774 | "y": 24 775 | }, 776 | "id": 123133, 777 | "options": { 778 | "legend": { 779 | "calcs": [], 780 | "displayMode": "list", 781 | "placement": "bottom", 782 | "showLegend": true 783 | }, 784 | "tooltip": { 785 | "mode": "single", 786 | "sort": "none" 787 | } 788 | }, 789 | "pluginVersion": "11.3.0", 790 | "targets": [ 791 | { 792 | "datasource": { 793 | "type": "prometheus", 794 | "uid": "P1809F7CD0C75ACF3" 795 | }, 796 | "editorMode": "code", 797 | "exemplar": true, 798 | "expr": "graphcast_subgraph_radio_diverging_subgraphs", 799 | "interval": "", 800 | "legendFormat": "", 801 | "range": true, 802 | "refId": "A" 803 | } 804 | ], 805 | "title": "Number of diverged subgraphs", 806 | "type": "timeseries" 807 | } 808 | ], 809 | "preload": false, 810 | "refresh": "", 811 | "schemaVersion": 40, 812 | "tags": [], 813 | "templating": { 814 | "list": [] 815 | }, 816 | "time": { 817 | "from": "now-6h", 818 | "to": "now" 819 | }, 820 | "timepicker": {}, 821 | "timezone": "browser", 822 | "title": "Graphcast Subgraph Radio v2", 823 | "uid": "graphcast-subgraph-radio", 824 | "version": 2, 825 | "weekStart": "" 826 | } -------------------------------------------------------------------------------- /grafana/provisioning/dashboards/tap.json: -------------------------------------------------------------------------------- 1 | { 2 | "annotations": { 3 | "list": [ 4 | { 5 | "builtIn": 1, 6 | "datasource": { 7 | "type": "grafana", 8 | "uid": "-- Grafana --" 9 | }, 10 | "enable": true, 11 | "hide": true, 12 | "iconColor": "rgba(0, 211, 255, 1)", 13 | "name": "Annotations & Alerts", 14 | "type": "dashboard" 15 | } 16 | ] 17 | }, 18 | "editable": true, 19 | "fiscalYearStartMonth": 0, 20 | "graphTooltip": 0, 21 | "id": 9, 22 | "links": [], 23 | "panels": [ 24 | { 25 | "datasource": { 26 | "type": "prometheus", 27 | "uid": "P1809F7CD0C75ACF3" 28 | }, 29 | "fieldConfig": { 30 | "defaults": { 31 | "color": { 32 | "mode": "palette-classic" 33 | }, 34 | "custom": { 35 | "axisBorderShow": false, 36 | "axisCenteredZero": false, 37 | "axisColorMode": "text", 38 | "axisLabel": "", 39 | "axisPlacement": "auto", 40 | "barAlignment": 0, 41 | "barWidthFactor": 0.6, 42 | "drawStyle": "line", 43 | "fillOpacity": 0, 44 | "gradientMode": "none", 45 | "hideFrom": { 46 | "legend": false, 47 | "tooltip": false, 48 | "viz": false 49 | }, 50 | "insertNulls": false, 51 | "lineInterpolation": "linear", 52 | "lineWidth": 1, 53 | "pointSize": 5, 54 | "scaleDistribution": { 55 | "type": "linear" 56 | }, 57 | "showPoints": "auto", 58 | "spanNulls": false, 59 | "stacking": { 60 | "group": "A", 61 | "mode": "none" 62 | }, 63 | "thresholdsStyle": { 64 | "mode": "off" 65 | } 66 | }, 67 | "mappings": [], 68 | "thresholds": { 69 | "mode": "absolute", 70 | "steps": [ 71 | { 72 | "color": "green", 73 | "value": null 74 | }, 75 | { 76 | "color": "red", 77 | "value": 80 78 | } 79 | ] 80 | } 81 | }, 82 | "overrides": [] 83 | }, 84 | "gridPos": { 85 | "h": 8, 86 | "w": 12, 87 | "x": 0, 88 | "y": 0 89 | }, 90 | "id": 2, 91 | "options": { 92 | "legend": { 93 | "calcs": [], 94 | "displayMode": "list", 95 | "placement": "bottom", 96 | "showLegend": true 97 | }, 98 | "tooltip": { 99 | "mode": "single", 100 | "sort": "none" 101 | } 102 | }, 103 | "pluginVersion": "11.3.0", 104 | "targets": [ 105 | { 106 | "datasource": { 107 | "type": "prometheus", 108 | "uid": "P1809F7CD0C75ACF3" 109 | }, 110 | "editorMode": "code", 111 | "expr": "sum by (sender) (tap_pending_rav_grt_total) * 10^-18", 112 | "legendFormat": "Pending Fees {{sender}}", 113 | "range": true, 114 | "refId": "A" 115 | }, 116 | { 117 | "datasource": { 118 | "type": "prometheus", 119 | "uid": "P1809F7CD0C75ACF3" 120 | }, 121 | "editorMode": "code", 122 | "expr": "tap_sender_escrow_balance_grt_total * 10^-18", 123 | "hide": false, 124 | "legendFormat": "Escrow balance {{sender}}", 125 | "range": true, 126 | "refId": "B" 127 | } 128 | ], 129 | "title": "Total Pending Fees over Balance", 130 | "type": "timeseries" 131 | }, 132 | { 133 | "datasource": { 134 | "type": "prometheus", 135 | "uid": "P1809F7CD0C75ACF3" 136 | }, 137 | "fieldConfig": { 138 | "defaults": { 139 | "color": { 140 | "mode": "palette-classic" 141 | }, 142 | "custom": { 143 | "axisBorderShow": false, 144 | "axisCenteredZero": false, 145 | "axisColorMode": "text", 146 | "axisLabel": "", 147 | "axisPlacement": "auto", 148 | "barAlignment": 0, 149 | "barWidthFactor": 0.6, 150 | "drawStyle": "line", 151 | "fillOpacity": 0, 152 | "gradientMode": "none", 153 | "hideFrom": { 154 | "legend": false, 155 | "tooltip": false, 156 | "viz": false 157 | }, 158 | "insertNulls": false, 159 | "lineInterpolation": "linear", 160 | "lineWidth": 1, 161 | "pointSize": 5, 162 | "scaleDistribution": { 163 | "type": "linear" 164 | }, 165 | "showPoints": "auto", 166 | "spanNulls": false, 167 | "stacking": { 168 | "group": "A", 169 | "mode": "none" 170 | }, 171 | "thresholdsStyle": { 172 | "mode": "off" 173 | } 174 | }, 175 | "mappings": [], 176 | "thresholds": { 177 | "mode": "absolute", 178 | "steps": [ 179 | { 180 | "color": "green", 181 | "value": null 182 | }, 183 | { 184 | "color": "red", 185 | "value": 80 186 | } 187 | ] 188 | } 189 | }, 190 | "overrides": [] 191 | }, 192 | "gridPos": { 193 | "h": 8, 194 | "w": 12, 195 | "x": 12, 196 | "y": 0 197 | }, 198 | "id": 3, 199 | "options": { 200 | "legend": { 201 | "calcs": [], 202 | "displayMode": "list", 203 | "placement": "bottom", 204 | "showLegend": true 205 | }, 206 | "tooltip": { 207 | "mode": "single", 208 | "sort": "none" 209 | } 210 | }, 211 | "pluginVersion": "11.3.0", 212 | "targets": [ 213 | { 214 | "datasource": { 215 | "type": "prometheus", 216 | "uid": "P1809F7CD0C75ACF3" 217 | }, 218 | "editorMode": "code", 219 | "expr": "tap_unaggregated_fees_grt_total * 10^-18", 220 | "legendFormat": "{{sender}}-{{allocation}}", 221 | "range": true, 222 | "refId": "A" 223 | }, 224 | { 225 | "datasource": { 226 | "type": "prometheus", 227 | "uid": "P1809F7CD0C75ACF3" 228 | }, 229 | "editorMode": "code", 230 | "expr": "sum by (sender) (tap_unaggregated_fees_grt_total) * 10^-18", 231 | "hide": false, 232 | "legendFormat": "Total Unaggregated Fees {{sender}}", 233 | "range": true, 234 | "refId": "B" 235 | }, 236 | { 237 | "datasource": { 238 | "type": "prometheus", 239 | "uid": "P1809F7CD0C75ACF3" 240 | }, 241 | "editorMode": "code", 242 | "expr": "tap_max_fee_per_sender_grt_total * 10^-18/1000", 243 | "hide": false, 244 | "legendFormat": "Trigger Rav {{sender}}", 245 | "range": true, 246 | "refId": "C" 247 | } 248 | ], 249 | "title": "Unaggregated fees", 250 | "type": "timeseries" 251 | }, 252 | { 253 | "datasource": { 254 | "type": "prometheus", 255 | "uid": "P1809F7CD0C75ACF3" 256 | }, 257 | "fieldConfig": { 258 | "defaults": { 259 | "color": { 260 | "mode": "palette-classic" 261 | }, 262 | "custom": { 263 | "axisBorderShow": false, 264 | "axisCenteredZero": false, 265 | "axisColorMode": "text", 266 | "axisLabel": "", 267 | "axisPlacement": "auto", 268 | "barAlignment": 0, 269 | "barWidthFactor": 0.6, 270 | "drawStyle": "line", 271 | "fillOpacity": 0, 272 | "gradientMode": "none", 273 | "hideFrom": { 274 | "legend": false, 275 | "tooltip": false, 276 | "viz": false 277 | }, 278 | "insertNulls": false, 279 | "lineInterpolation": "linear", 280 | "lineWidth": 1, 281 | "pointSize": 5, 282 | "scaleDistribution": { 283 | "type": "linear" 284 | }, 285 | "showPoints": "auto", 286 | "spanNulls": false, 287 | "stacking": { 288 | "group": "A", 289 | "mode": "none" 290 | }, 291 | "thresholdsStyle": { 292 | "mode": "off" 293 | } 294 | }, 295 | "mappings": [], 296 | "thresholds": { 297 | "mode": "absolute", 298 | "steps": [ 299 | { 300 | "color": "green", 301 | "value": null 302 | }, 303 | { 304 | "color": "red", 305 | "value": 80 306 | } 307 | ] 308 | } 309 | }, 310 | "overrides": [] 311 | }, 312 | "gridPos": { 313 | "h": 8, 314 | "w": 12, 315 | "x": 0, 316 | "y": 8 317 | }, 318 | "id": 4, 319 | "options": { 320 | "legend": { 321 | "calcs": [], 322 | "displayMode": "list", 323 | "placement": "bottom", 324 | "showLegend": true 325 | }, 326 | "tooltip": { 327 | "mode": "single", 328 | "sort": "none" 329 | } 330 | }, 331 | "pluginVersion": "11.3.0", 332 | "targets": [ 333 | { 334 | "datasource": { 335 | "type": "prometheus", 336 | "uid": "P1809F7CD0C75ACF3" 337 | }, 338 | "editorMode": "code", 339 | "expr": "rate(tap_receipts_received_total[$__rate_interval])", 340 | "legendFormat": "{{sender}}-{{allocation}}", 341 | "range": true, 342 | "refId": "A" 343 | } 344 | ], 345 | "title": "Receipts Rate", 346 | "type": "timeseries" 347 | }, 348 | { 349 | "datasource": { 350 | "type": "prometheus", 351 | "uid": "P1809F7CD0C75ACF3" 352 | }, 353 | "fieldConfig": { 354 | "defaults": { 355 | "color": { 356 | "mode": "palette-classic" 357 | }, 358 | "custom": { 359 | "axisBorderShow": false, 360 | "axisCenteredZero": false, 361 | "axisColorMode": "text", 362 | "axisLabel": "", 363 | "axisPlacement": "auto", 364 | "barAlignment": 0, 365 | "barWidthFactor": 0.6, 366 | "drawStyle": "line", 367 | "fillOpacity": 0, 368 | "gradientMode": "none", 369 | "hideFrom": { 370 | "legend": false, 371 | "tooltip": false, 372 | "viz": false 373 | }, 374 | "insertNulls": false, 375 | "lineInterpolation": "linear", 376 | "lineWidth": 1, 377 | "pointSize": 5, 378 | "scaleDistribution": { 379 | "type": "linear" 380 | }, 381 | "showPoints": "auto", 382 | "spanNulls": false, 383 | "stacking": { 384 | "group": "A", 385 | "mode": "none" 386 | }, 387 | "thresholdsStyle": { 388 | "mode": "off" 389 | } 390 | }, 391 | "mappings": [], 392 | "thresholds": { 393 | "mode": "absolute", 394 | "steps": [ 395 | { 396 | "color": "green", 397 | "value": null 398 | }, 399 | { 400 | "color": "red", 401 | "value": 80 402 | } 403 | ] 404 | } 405 | }, 406 | "overrides": [ 407 | { 408 | "matcher": { 409 | "id": "byName", 410 | "options": "0xDDE4cfFd3D9052A9cb618fC05a1Cd02be1f2F467" 411 | }, 412 | "properties": [ 413 | { 414 | "id": "color", 415 | "value": { 416 | "fixedColor": "green", 417 | "mode": "fixed" 418 | } 419 | } 420 | ] 421 | }, 422 | { 423 | "matcher": { 424 | "id": "byName", 425 | "options": "Failed Rav requests 0xDDE4cfFd3D9052A9cb618fC05a1Cd02be1f2F467" 426 | }, 427 | "properties": [ 428 | { 429 | "id": "color", 430 | "value": { 431 | "fixedColor": "red", 432 | "mode": "fixed" 433 | } 434 | } 435 | ] 436 | } 437 | ] 438 | }, 439 | "gridPos": { 440 | "h": 8, 441 | "w": 12, 442 | "x": 12, 443 | "y": 8 444 | }, 445 | "id": 5, 446 | "options": { 447 | "legend": { 448 | "calcs": [], 449 | "displayMode": "list", 450 | "placement": "bottom", 451 | "showLegend": true 452 | }, 453 | "tooltip": { 454 | "mode": "single", 455 | "sort": "none" 456 | } 457 | }, 458 | "pluginVersion": "11.3.0", 459 | "targets": [ 460 | { 461 | "datasource": { 462 | "type": "prometheus", 463 | "uid": "P1809F7CD0C75ACF3" 464 | }, 465 | "editorMode": "code", 466 | "expr": "sum by (sender) (rate(tap_ravs_created_total[1h]))", 467 | "legendFormat": "Successful Rav Requests {{sender}}", 468 | "range": true, 469 | "refId": "A" 470 | }, 471 | { 472 | "datasource": { 473 | "type": "prometheus", 474 | "uid": "P1809F7CD0C75ACF3" 475 | }, 476 | "editorMode": "code", 477 | "expr": "sum by (sender) (rate(tap_ravs_failed_total[1h]))", 478 | "hide": false, 479 | "legendFormat": "Failed Rav requests {{sender}}", 480 | "range": true, 481 | "refId": "B" 482 | } 483 | ], 484 | "title": "Rav Requests Rate", 485 | "type": "timeseries" 486 | }, 487 | { 488 | "datasource": { 489 | "type": "prometheus", 490 | "uid": "P1809F7CD0C75ACF3" 491 | }, 492 | "fieldConfig": { 493 | "defaults": { 494 | "color": { 495 | "mode": "palette-classic" 496 | }, 497 | "custom": { 498 | "axisBorderShow": false, 499 | "axisCenteredZero": false, 500 | "axisColorMode": "text", 501 | "axisLabel": "", 502 | "axisPlacement": "auto", 503 | "axisSoftMax": 1, 504 | "axisSoftMin": 0, 505 | "barAlignment": 0, 506 | "barWidthFactor": 0.6, 507 | "drawStyle": "line", 508 | "fillOpacity": 0, 509 | "gradientMode": "none", 510 | "hideFrom": { 511 | "legend": false, 512 | "tooltip": false, 513 | "viz": false 514 | }, 515 | "insertNulls": false, 516 | "lineInterpolation": "linear", 517 | "lineWidth": 1, 518 | "pointSize": 5, 519 | "scaleDistribution": { 520 | "type": "linear" 521 | }, 522 | "showPoints": "auto", 523 | "spanNulls": false, 524 | "stacking": { 525 | "group": "A", 526 | "mode": "none" 527 | }, 528 | "thresholdsStyle": { 529 | "mode": "off" 530 | } 531 | }, 532 | "mappings": [], 533 | "max": 1, 534 | "min": 0, 535 | "thresholds": { 536 | "mode": "absolute", 537 | "steps": [ 538 | { 539 | "color": "green", 540 | "value": null 541 | }, 542 | { 543 | "color": "red", 544 | "value": 80 545 | } 546 | ] 547 | }, 548 | "unit": "bool" 549 | }, 550 | "overrides": [] 551 | }, 552 | "gridPos": { 553 | "h": 8, 554 | "w": 12, 555 | "x": 0, 556 | "y": 16 557 | }, 558 | "id": 1, 559 | "options": { 560 | "legend": { 561 | "calcs": [], 562 | "displayMode": "list", 563 | "placement": "bottom", 564 | "showLegend": true 565 | }, 566 | "tooltip": { 567 | "mode": "single", 568 | "sort": "none" 569 | } 570 | }, 571 | "pluginVersion": "11.3.0", 572 | "targets": [ 573 | { 574 | "datasource": { 575 | "type": "prometheus", 576 | "uid": "P1809F7CD0C75ACF3" 577 | }, 578 | "editorMode": "code", 579 | "expr": "tap_sender_denied", 580 | "legendFormat": "{{sender}}", 581 | "range": true, 582 | "refId": "A" 583 | } 584 | ], 585 | "title": "Sender Blocked", 586 | "type": "timeseries" 587 | }, 588 | { 589 | "datasource": { 590 | "type": "prometheus", 591 | "uid": "P1809F7CD0C75ACF3" 592 | }, 593 | "fieldConfig": { 594 | "defaults": { 595 | "color": { 596 | "mode": "palette-classic" 597 | }, 598 | "custom": { 599 | "axisBorderShow": false, 600 | "axisCenteredZero": false, 601 | "axisColorMode": "text", 602 | "axisLabel": "", 603 | "axisPlacement": "auto", 604 | "barAlignment": 0, 605 | "barWidthFactor": 0.6, 606 | "drawStyle": "line", 607 | "fillOpacity": 0, 608 | "gradientMode": "none", 609 | "hideFrom": { 610 | "legend": false, 611 | "tooltip": false, 612 | "viz": false 613 | }, 614 | "insertNulls": false, 615 | "lineInterpolation": "linear", 616 | "lineWidth": 1, 617 | "pointSize": 5, 618 | "scaleDistribution": { 619 | "type": "linear" 620 | }, 621 | "showPoints": "auto", 622 | "spanNulls": false, 623 | "stacking": { 624 | "group": "A", 625 | "mode": "none" 626 | }, 627 | "thresholdsStyle": { 628 | "mode": "off" 629 | } 630 | }, 631 | "mappings": [], 632 | "thresholds": { 633 | "mode": "absolute", 634 | "steps": [ 635 | { 636 | "color": "green", 637 | "value": null 638 | }, 639 | { 640 | "color": "red", 641 | "value": 80 642 | } 643 | ] 644 | } 645 | }, 646 | "overrides": [ 647 | { 648 | "matcher": { 649 | "id": "byName", 650 | "options": "0xDDE4cfFd3D9052A9cb618fC05a1Cd02be1f2F467" 651 | }, 652 | "properties": [ 653 | { 654 | "id": "color", 655 | "value": { 656 | "fixedColor": "yellow", 657 | "mode": "fixed" 658 | } 659 | } 660 | ] 661 | } 662 | ] 663 | }, 664 | "gridPos": { 665 | "h": 8, 666 | "w": 12, 667 | "x": 12, 668 | "y": 16 669 | }, 670 | "id": 6, 671 | "options": { 672 | "legend": { 673 | "calcs": [], 674 | "displayMode": "list", 675 | "placement": "bottom", 676 | "showLegend": true 677 | }, 678 | "tooltip": { 679 | "mode": "single", 680 | "sort": "none" 681 | } 682 | }, 683 | "pluginVersion": "11.3.0", 684 | "targets": [ 685 | { 686 | "datasource": { 687 | "type": "prometheus", 688 | "uid": "P1809F7CD0C75ACF3" 689 | }, 690 | "editorMode": "code", 691 | "expr": "tap_invalid_receipt_fees_grt_total * 10^-18", 692 | "legendFormat": "{{sender}}", 693 | "range": true, 694 | "refId": "A" 695 | } 696 | ], 697 | "title": "Total Invalid Receipt", 698 | "type": "timeseries" 699 | } 700 | ], 701 | "preload": false, 702 | "refresh": "", 703 | "schemaVersion": 40, 704 | "tags": [], 705 | "templating": { 706 | "list": [] 707 | }, 708 | "time": { 709 | "from": "now-6h", 710 | "to": "now" 711 | }, 712 | "timepicker": {}, 713 | "timezone": "", 714 | "title": "TAP Dashboard", 715 | "uid": "fe2ixo2i2bsowf", 716 | "version": 6, 717 | "weekStart": "" 718 | } -------------------------------------------------------------------------------- /grafana/provisioning/datasources/graphql.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: 1 3 | datasources: 4 | - access: proxy 5 | editable: true 6 | name: graphql 7 | orgId: 1 8 | type: yesoreyeram-infinity-datasource 9 | url: http://query-node-0:8000/subgraphs/id/QmXnGVrg6DvscnvJd86aHAPLGyGrkM17weMrAsFAEMmQLL 10 | version: 1 11 | -------------------------------------------------------------------------------- /grafana/provisioning/datasources/loki.yml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | datasources: 4 | - name: Loki 5 | type: loki 6 | access: proxy 7 | url: http://loki:3100 8 | version: 1 9 | editable: false 10 | isDefault: true -------------------------------------------------------------------------------- /grafana/provisioning/datasources/postgres.yml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | datasources: 3 | - access: proxy 4 | editable: true 5 | name: postgres 6 | orgId: 1 7 | type: postgres 8 | url: $postgres_host 9 | user: $postgres_user 10 | database: $postgres_db 11 | secureJsonData: 12 | password: $postgres_pass 13 | jsonData: 14 | sslmode: disable 15 | postgresVersion: 906 16 | -------------------------------------------------------------------------------- /grafana/provisioning/datasources/prometheus.yml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | datasources: 3 | - access: proxy 4 | editable: true 5 | name: prometheus 6 | orgId: 1 7 | type: prometheus 8 | url: http://prometheus:9090/ 9 | version: 1 -------------------------------------------------------------------------------- /grafana/provisioning/datasources/subgraph_radio_graphql.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: 1 3 | datasources: 4 | - access: proxy 5 | editable: true 6 | name: SubgraphRadioGraphQL 7 | orgId: 1 8 | type: yesoreyeram-infinity-datasource 9 | url: http://subgraph-radio:3012/api/v1/graphql 10 | version: 1 11 | -------------------------------------------------------------------------------- /grafana/provisioning/plugins/file: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StakeSquid/graphprotocol-mainnet-docker/dca14a6efe47ebbd2a56c64a2f4d9b2d2a67c684/grafana/provisioning/plugins/file -------------------------------------------------------------------------------- /graph-node-configs/config.tmpl: -------------------------------------------------------------------------------- 1 | [store] 2 | [store.primary] 3 | connection = "postgresql://${GRAPH_NODE_DB_USER}:${GRAPH_NODE_DB_PASS}@${GRAPH_NODE_DB_HOST}:5432/${GRAPH_NODE_DB_NAME}" 4 | pool_size = 10 5 | 6 | [chains] 7 | ingestor = "index_node_0" 8 | 9 | [chains.${CHAIN_0_NAME}] 10 | shard = "primary" 11 | provider = [ { label = "${CHAIN_0_NAME}", url = "${CHAIN_0_RPC}", features = ["archive", "traces"] } ] 12 | 13 | [deployment] 14 | [[deployment.rule]] 15 | indexers = [ "index_node_0" ] 16 | 17 | 18 | [general] 19 | query = "query_node_0" 20 | -------------------------------------------------------------------------------- /logs: -------------------------------------------------------------------------------- 1 | if [ ! -z $1 ] 2 | then 3 | docker compose -f compose-autoagora.yml -f compose-graphnode.yml -f compose-monitoring.yml -f compose-optional.yml logs "${1}" -f --tail 10 4 | else 5 | docker compose -f compose-autoagora.yml -f compose-graphnode.yml -f compose-monitoring.yml -f compose-optional.yml logs -f --tail 10 6 | fi 7 | -------------------------------------------------------------------------------- /loki/loki.yaml: -------------------------------------------------------------------------------- 1 | # Configuration: https://grafana.com/docs/loki/latest/configuration/ 2 | 3 | auth_enabled: false 4 | 5 | server: 6 | http_listen_port: 3100 7 | log_level: warn 8 | http_server_read_timeout: 60s 9 | http_server_write_timeout: 30s 10 | grpc_server_max_recv_msg_size: 52428800 11 | grpc_server_max_send_msg_size: 52428800 12 | grpc_server_max_concurrent_streams: 100 13 | 14 | common: 15 | path_prefix: /data/loki 16 | storage: 17 | filesystem: 18 | chunks_directory: /data/chunks 19 | rules_directory: /data/rules 20 | replication_factor: 1 21 | 22 | frontend: 23 | max_outstanding_per_tenant: 2048 24 | 25 | frontend_worker: 26 | grpc_client_config: 27 | max_recv_msg_size: 52428800 28 | max_send_msg_size: 52428800 29 | 30 | ingester: 31 | wal: 32 | enabled: true 33 | dir: /loki/wal 34 | lifecycler: 35 | ring: 36 | kvstore: 37 | store: inmemory 38 | heartbeat_timeout: 5m 39 | 40 | chunk_encoding: "snappy" 41 | 42 | ingester_client: 43 | grpc_client_config: 44 | max_recv_msg_size: 52428800 45 | max_send_msg_size: 52428800 46 | 47 | limits_config: 48 | ingestion_rate_mb: 30 49 | ingestion_burst_size_mb: 100 50 | split_queries_by_interval: 24h 51 | per_stream_rate_limit: 6000000 52 | per_stream_rate_limit_burst: 12000000 53 | allow_structured_metadata: true # Enabled for schema v13 and tsdb index type 54 | 55 | ruler: 56 | alertmanager_url: http://alertmanager:9093 57 | 58 | querier: 59 | max_concurrent: 2048 60 | 61 | query_range: 62 | align_queries_with_step: true 63 | max_retries: 5 64 | cache_results: true 65 | 66 | query_scheduler: 67 | grpc_client_config: 68 | max_recv_msg_size: 52428800 69 | max_send_msg_size: 52428800 70 | 71 | schema_config: 72 | configs: 73 | - from: 2020-10-24 74 | store: tsdb # Updated to 'tsdb' for structured metadata support 75 | object_store: filesystem 76 | schema: v13 # Updated to schema version 'v13' for OTLP ingestion support 77 | index: 78 | prefix: index_ 79 | period: 24h 80 | 81 | analytics: 82 | reporting_enabled: false 83 | -------------------------------------------------------------------------------- /offchain-subgraphs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rm offchain-subgraphs 4 | 5 | mainnet_networks=$(http -b post "https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-mainnet" query="{networks {id}}" | jq -r .data.networks[].id)# > mainnet_networks 6 | testnet_networks=$(http -b post "https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-goerli" query="{networks {id}}" | jq -r .data.networks[].id)# > testnet_networks 7 | 8 | repeat=1 9 | 10 | 11 | while [ $repeat -gt 0 ]; do 12 | echo -e "\e[1;32m Which graph indexer environment do you want to query? \e[0m" 13 | 14 | select environment in "mainnet" "goerli"; do 15 | echo 16 | echo -e "\e[1;32m Which network do you want to sync subgraphs from? \e[0m" 17 | case $environment in 18 | mainnet ) select network in ${mainnet_networks}; do break;done;break;; 19 | goerli ) select network in ${testnet_networks}; do break;done;break;; 20 | esac 21 | done 22 | echo 23 | echo -e "\e[1;32m How many subgraphs do you want to offchain sync from the available ${network} subgraphs on the ${environment} environment? \e[0m" 24 | 25 | read subsnumber 26 | 27 | http -b post https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-${environment} query="{subgraphDeployments(first:$subsnumber, orderBy:signalledTokens, orderDirection:desc, where:{signalledTokens_gt:0, deniedAt:0, network:\"$network\"}) {ipfsHash}}" | jq -r .data.subgraphDeployments[].ipfsHash >> offchain-subgraphs 28 | 29 | echo -e "\e[1;32m Done 👏 \e[0m" 30 | echo 31 | 32 | echo -e "\e[1;32m Do you wish to add more networks to the list? \e[0m" 33 | select yn in "Yes" "No"; do 34 | case $yn in 35 | Yes ) break;; 36 | No ) repeat=0;break;; 37 | esac 38 | done 39 | done 40 | 41 | echo -e "\e[1;32m Done 👏 \e[0m" 42 | echo 43 | echo -e "\e[1;32m Do you wish to add more subgraphs to the list? \e[0m" 44 | select yn in "Yes" "No"; do 45 | case $yn in 46 | Yes ) echo -e "\e[1;32m Enter your Subgraph ID or an array of Subgraph IDs (comma separated) \e[0m" 47 | read list 48 | awk -F',' '{ for( i=1; i<=NF; i++ ) print $i }' <<<"$list" >> offchain-subgraphs;break;; 49 | No ) break;; 50 | esac 51 | done 52 | echo -e "\e[1;32m Done 👏 \e[0m" 53 | 54 | echo 55 | echo -e "\e[1;32m Should I edit the start file with the changes for you? \e[0m" 56 | select yn in "Yes" "No"; do 57 | case $yn in 58 | Yes ) sed -i.backup "s/\(^INDEXER_AGENT_OFFCHAIN_SUBGRAPHS=.*\)/INDEXER_AGENT_OFFCHAIN_SUBGRAPHS=$(cat offchain-subgraphs | sed -z 's/\n/,/g;s/,$/\n/') \\\/" .env;break;; 59 | No ) exit;; 60 | esac 61 | done 62 | echo -e "\e[1;32m Done 👏 \e[0m" 63 | 64 | echo 65 | echo -e "\e[1;32m Should I restart the containers for you so that the changes apply? \e[0m" 66 | select yn in "Yes" "No"; do 67 | case $yn in 68 | Yes ) bash start --force-recreate indexer-agent;break;; 69 | No ) exit;; 70 | esac 71 | done 72 | echo -e "\e[1;32m Done 👏 \e[0m" 73 | -------------------------------------------------------------------------------- /prometheus/alert.rules: -------------------------------------------------------------------------------- 1 | groups: 2 | - name: targets 3 | rules: 4 | - alert: monitor_service_down 5 | expr: up == 0 6 | for: 30s 7 | labels: 8 | severity: critical 9 | annotations: 10 | summary: "Monitor service non-operational" 11 | description: "Service {{ $labels.instance }} is down." 12 | 13 | - name: host 14 | rules: 15 | - alert: high_cpu_load 16 | expr: node_load1 > 16 17 | for: 30s 18 | labels: 19 | severity: warning 20 | annotations: 21 | summary: "Server under high load" 22 | description: "Docker host is under high load, the avg load 1m is at {{ $value}}. Reported by instance {{ $labels.instance }} of job {{ $labels.job }}." 23 | 24 | - alert: high_memory_load 25 | expr: (sum(node_memory_MemTotal_bytes) - sum(node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes) ) / sum(node_memory_MemTotal_bytes) * 100 > 85 26 | for: 30s 27 | labels: 28 | severity: warning 29 | annotations: 30 | summary: "Server memory is almost full" 31 | description: "Docker host memory usage is {{ humanize $value}}%. Reported by instance {{ $labels.instance }} of job {{ $labels.job }}." 32 | 33 | - alert: high_storage_load 34 | expr: (node_filesystem_size_bytes{fstype="aufs"} - node_filesystem_free_bytes{fstype="aufs"}) / node_filesystem_size_bytes{fstype="aufs"} * 100 > 85 35 | for: 30s 36 | labels: 37 | severity: warning 38 | annotations: 39 | summary: "Server storage is almost full" 40 | description: "Docker host storage usage is {{ humanize $value}}%. Reported by instance {{ $labels.instance }} of job {{ $labels.job }}." 41 | 42 | - name: containers 43 | rules: 44 | - alert: querynode_down 45 | expr: absent((time() - container_last_seen{name=~"query-node.*"}) < 10) 46 | for: 30s 47 | labels: 48 | severity: critical 49 | annotations: 50 | summary: "{{ $labels.instance }} is down" 51 | description: "{{ $labels.instance }} container is down for more than 30 seconds." 52 | 53 | - alert: querynode_high_cpu 54 | expr: sum(rate(container_cpu_usage_seconds_total{name=~"query-node.*"}[1m])) / count(node_cpu_seconds_total{mode="system"}) * 100 > 10 55 | for: 30s 56 | labels: 57 | severity: warning 58 | annotations: 59 | summary: "{{ $labels.instance }} high CPU usage" 60 | description: "Query Node {{ $labels.instance }} CPU usage is {{ humanize $value}}%." 61 | 62 | - alert: querynode_high_memory 63 | expr: sum(container_memory_usage_bytes{name=~"query-node.*"}) > 1200000000 64 | for: 30s 65 | labels: 66 | severity: warning 67 | annotations: 68 | summary: "{{ $labels.instance }} high memory usage" 69 | description: "Query Node {{ $labels.instance }} memory consumption is at {{ humanize $value}}." 70 | 71 | - alert: indexnode_down 72 | expr: absent((time() - container_last_seen{name=~"index-node.*"}) < 10) 73 | for: 30s 74 | labels: 75 | severity: critical 76 | annotations: 77 | summary: "{{ $labels.instance }} is down" 78 | description: "{{ $labels.instance }} container is down for more than 30 seconds." 79 | 80 | - alert: indexnode_high_cpu 81 | expr: sum(rate(container_cpu_usage_seconds_total{name=~"index-node.*"}[1m])) / count(node_cpu_seconds_total{mode="system"}) * 100 > 10 82 | for: 30s 83 | labels: 84 | severity: warning 85 | annotations: 86 | summary: "{{ $labels.instance }} high CPU usage" 87 | description: "{{ $labels.instance }} node CPU usage is {{ humanize $value}}%." 88 | 89 | - alert: indexnode_high_memory 90 | expr: sum(container_memory_usage_bytes{name=~"query-node.*"}) > 1200000000 91 | for: 30s 92 | labels: 93 | severity: warning 94 | annotations: 95 | summary: "{{ $labels.instance }} high memory usage" 96 | description: "{{ $labels.instance }} memory consumption is at {{ humanize $value}}." 97 | 98 | - alert: postgres_down 99 | expr: absent((time() - container_last_seen{name=~"postgres.*"}) < 10) 100 | for: 10s 101 | labels: 102 | severity: critical 103 | annotations: 104 | summary: "{{ $labels.instance }} down" 105 | description: "{{ $labels.instance }} container is down for more than 30 seconds." 106 | 107 | - alert: postgres_high_cpu 108 | expr: sum(rate(container_cpu_usage_seconds_total{name=~"postgres.*"}[1m])) / count(node_cpu_seconds_total{mode="system"}) * 100 > 10 109 | for: 30s 110 | labels: 111 | severity: warning 112 | annotations: 113 | summary: "{{ $labels.instance }} high CPU usage" 114 | description: "{{ $labels.instance }} CPU usage is {{ humanize $value}}%." 115 | 116 | - alert: postgres_high_memory 117 | expr: sum(container_memory_usage_bytes{name=~"postgres.*"}) > 1200000000 118 | for: 30s 119 | labels: 120 | severity: warning 121 | annotations: 122 | summary: "{{ $labels.instance }} high memory usage" 123 | description: "{{ $labels.instance }} memory consumption is at {{ humanize $value}}." 124 | 125 | - alert: traefik_down 126 | expr: absent((time() - container_last_seen{name="traefik"}) < 10) 127 | for: 30s 128 | labels: 129 | severity: critical 130 | annotations: 131 | summary: "Traefik down" 132 | description: "Traefik container is down for more than 30 seconds." 133 | 134 | - alert: traefik_high_cpu 135 | expr: sum(rate(container_cpu_usage_seconds_total{name="traefik"}[1m])) / count(node_cpu_seconds_total{mode="system"}) * 100 > 10 136 | for: 30s 137 | labels: 138 | severity: warning 139 | annotations: 140 | summary: "Traefik high CPU usage" 141 | description: "Traefik CPU usage is {{ humanize $value}}%." 142 | 143 | - alert: traefik_high_memory 144 | expr: sum(container_memory_usage_bytes{name="traefik"}) > 1200000000 145 | for: 30s 146 | labels: 147 | severity: warning 148 | annotations: 149 | summary: "traefik high memory usage" 150 | description: "traefik memory consumption is at {{ humanize $value}}." 151 | -------------------------------------------------------------------------------- /prometheus/prometheus.yml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 115s 3 | evaluation_interval: 115s 4 | 5 | # Attach these labels to any time series or alerts when communicating with 6 | # external systems (federation, remote storage, Alertmanager). 7 | external_labels: 8 | monitor: "docker-host-alpha" 9 | 10 | # Load and evaluate rules in this file every 'evaluation_interval' seconds. 11 | rule_files: 12 | - "alert.rules" 13 | 14 | # A scrape configuration containing exactly one endpoint to scrape. 15 | scrape_configs: 16 | - job_name: 'nodeexporter' 17 | scrape_interval: 5s 18 | static_configs: 19 | - targets: ['nodeexporter:9100'] 20 | 21 | - job_name: 'cadvisor' 22 | scrape_interval: 5s 23 | static_configs: 24 | - targets: ['cadvisor:8080'] 25 | 26 | - job_name: 'prometheus' 27 | scrape_interval: 10s 28 | static_configs: 29 | - targets: ['localhost:9090'] 30 | 31 | - job_name: 'pushgateway' 32 | scrape_interval: 10s 33 | honor_labels: true 34 | static_configs: 35 | - targets: ['pushgateway:9091'] 36 | 37 | - job_name: 'index-node-0' 38 | scrape_interval: 5s 39 | static_configs: 40 | - targets: ['index-node-0:8040'] 41 | 42 | - job_name: 'query-node-0' 43 | scrape_interval: 5s 44 | static_configs: 45 | - targets: ['query-node-0:8040'] 46 | 47 | - job_name: 'indexer-service' 48 | scrape_interval: 5s 49 | static_configs: 50 | - targets: ['indexer-service:7300'] 51 | 52 | - job_name: 'indexer-tap' 53 | scrape_interval: 5s 54 | static_configs: 55 | - targets: ['indexer-tap:7300'] 56 | 57 | - job_name: 'indexer-agent' 58 | scrape_interval: 5s 59 | static_configs: 60 | - targets: ['indexer-agent:7300'] 61 | 62 | - job_name: 'autoagora' 63 | scrape_interval: 5s 64 | static_configs: 65 | - targets: ['ag:8000'] 66 | 67 | - job_name: 'grafana' 68 | scrape_interval: 5s 69 | static_configs: 70 | - targets: ['grafana:3000'] 71 | 72 | - job_name: 'subgraph-radio' 73 | scrape_interval: 5s 74 | static_configs: 75 | - targets: ['subgraph-radio:3010'] 76 | 77 | - job_name: "traefik" 78 | metrics_path: /metrics 79 | scheme: http 80 | scrape_interval: 15s 81 | static_configs: 82 | - targets: ["traefik:8082"] 83 | 84 | alerting: 85 | alertmanagers: 86 | - scheme: http 87 | static_configs: 88 | - targets: 89 | - "alertmanager:9093" 90 | # - job_name: 'nginx' 91 | # scrape_interval: 15s 92 | # static_configs: 93 | # - targets: ['nginxexporter:9113'] 94 | 95 | # - job_name: 'aspnetcore' 96 | # scrape_interval: 15s 97 | # static_configs: 98 | # - targets: ['eventlog-proxy:5000', 'eventlog:5000'] 99 | -------------------------------------------------------------------------------- /promtail/promtail.yaml: -------------------------------------------------------------------------------- 1 | # https://grafana.com/docs/loki/latest/clients/promtail/configuration/ 2 | # https://docs.docker.com/engine/api/v1.41/#operation/ContainerList 3 | 4 | # https://cylab.be/blog/241/use-loki-to-monitor-the-logs-of-your-docker-compose-application 5 | 6 | server: 7 | http_listen_port: 9080 8 | grpc_listen_port: 0 9 | 10 | positions: 11 | filename: /tmp/positions.yaml 12 | 13 | clients: 14 | - url: http://loki:3100/loki/api/v1/push 15 | batchsize: 1024000 # Max size of logs to batch in bytes. Default is 100KB. 16 | batchwait: 1s # Max time to wait before sending a batch. Default is 1s. 17 | 18 | scrape_configs: 19 | - job_name: 'docker-containers' 20 | docker_sd_configs: 21 | - host: unix:///var/run/docker.sock 22 | refresh_interval: 10s 23 | filters: 24 | - name: network 25 | values: ['graphprotocol-mainnet-docker_monitor-net'] 26 | relabel_configs: 27 | - source_labels: ['__meta_docker_container_name'] 28 | target_label: 'container_name' 29 | - source_labels: ['__meta_docker_container_image'] 30 | target_label: 'container_image' 31 | - source_labels: ['__meta_docker_container_id'] 32 | target_label: 'container_id' 33 | - source_labels: ['__meta_docker_network_name'] 34 | target_label: 'network' 35 | 36 | - job_name: system 37 | static_configs: 38 | - targets: ["localhost"] 39 | labels: 40 | job: varlogs 41 | nodename: system 42 | __path__: /var/log/*log 43 | 44 | - job_name: journal 45 | journal: 46 | json: false 47 | max_age: 12h 48 | path: /var/log/journal 49 | # matches: _TRANSPORT=kernel 50 | labels: 51 | job: systemd-journal 52 | relabel_configs: 53 | - source_labels: 54 | - __journal__systemd_unit 55 | target_label: systemd_unit 56 | - source_labels: 57 | - __journal__hostname 58 | target_label: nodename 59 | - source_labels: 60 | - __journal_syslog_identifier 61 | target_label: syslog_identifier -------------------------------------------------------------------------------- /refresh-sizes.sh: -------------------------------------------------------------------------------- 1 | set -o allexport; source .env; set +o allexport; docker exec -it postgres psql -U ${GRAPH_NODE_DB_USER} ${GRAPH_NODE_DB_NAME} -c "refresh materialized view info.subgraph_sizes;" 2 | -------------------------------------------------------------------------------- /runagora: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR=$PWD 4 | 5 | FILE=$DIR/agora/target/release/agora 6 | if [ ! -f "$FILE" ]; then 7 | docker run --rm --name agora -it -v $DIR/agora:/code rust:latest bash -c '(cd /code/agora; cargo build --release)' 8 | fi 9 | 10 | $DIR/agora/target/release/agora "$@" 11 | -------------------------------------------------------------------------------- /runqlog: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR=$PWD 4 | 5 | FILE=$DIR/qlog/target/release/qlog 6 | if [ ! -f "$FILE" ]; then 7 | docker run --rm --name qlog -v $DIR/qlog:/code rust:latest bash -c '(cd /code; cargo install --bins --path .)' 8 | fi 9 | 10 | $DIR/qlog/target/release/qlog "$@" 11 | -------------------------------------------------------------------------------- /shell: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eEuo pipefail 3 | 4 | cd "$(dirname "${0}")/.." 5 | # shellcheck source=/dev/null 6 | # source ./.env.local 7 | docker exec -it "${1}" "${2:-/bin/bash}" || true 8 | -------------------------------------------------------------------------------- /start-all: -------------------------------------------------------------------------------- 1 | set -o allexport; source .env; set +o allexport; envsubst < graph-node-configs/config.tmpl > graph-node-configs/config.toml 2 | 3 | docker compose -f compose-graphnode.yml -f compose-monitoring.yml -f compose-optional.yml up -d --build $@ -------------------------------------------------------------------------------- /start-essential: -------------------------------------------------------------------------------- 1 | set -o allexport; source .env; set +o allexport; envsubst < graph-node-configs/config.tmpl > graph-node-configs/config.toml 2 | 3 | docker compose -f compose-graphnode.yml -f compose-indexer.yml -f compose-monitoring.yml up -d --build $@ -------------------------------------------------------------------------------- /start-optional: -------------------------------------------------------------------------------- 1 | set -o allexport; source .env; set +o allexport; envsubst < graph-node-configs/config.tmpl > graph-node-configs/config.toml 2 | 3 | docker compose -f compose-optional.yml up -d --build $@ -------------------------------------------------------------------------------- /stop-all: -------------------------------------------------------------------------------- 1 | docker compose -f compose-graphnode.yml -f compose-monitoring.yml -f compose-optional.yml down $@ 2 | -------------------------------------------------------------------------------- /stop-essential: -------------------------------------------------------------------------------- 1 | docker compose -f compose-graphnode.yml -f compose-indexer.yml -f compose-monitoring.yml down $@ 2 | -------------------------------------------------------------------------------- /stop-optional: -------------------------------------------------------------------------------- 1 | docker compose -f compose-optional.yml down $@ 2 | -------------------------------------------------------------------------------- /traefik/config/dynamic_config.yml: -------------------------------------------------------------------------------- 1 | tls: 2 | options: 3 | default: 4 | minVersion: VersionTLS12 5 | cipherSuites: 6 | # Recommended ciphers for TLSv1.2 7 | - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 8 | - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 9 | - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 10 | # Recommended ciphers for TLSv1.3 11 | - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 12 | - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 13 | - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 -------------------------------------------------------------------------------- /truncate-actions-table.sh: -------------------------------------------------------------------------------- 1 | set -o allexport; source .env; set +o allexport; docker exec -it postgres-agent psql -U ${AGENT_DB_USER} ${AGENT_DB_NAME} -c 'truncate "Actions"' --------------------------------------------------------------------------------