├── grafana ├── grafana.ini ├── dashboards.yml ├── datasource.yml ├── dashboards │ ├── logs_dashboard.json │ └── single_node_dashboard.json └── alerts │ └── alerts.yml ├── jwt └── jwt.hex ├── DVNode.png ├── nimbus ├── Dockerfile └── run.sh ├── .gitignore ├── .github ├── workflows │ ├── test.yml │ ├── label-issues.yml │ └── dispath-update.yml ├── renovate.json └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── tempo └── tempo.yaml ├── logging.yml ├── prometheus ├── run.sh └── prometheus.yml.example ├── promtail ├── run.sh └── config.yml.example ├── relay └── docker-compose.yml ├── loki └── loki.yml ├── commit-boost ├── config.toml.sample.holesky ├── config.toml.sample.hoodi └── config.toml.sample.mainnet ├── compose-debug.yml ├── lodestar └── run.sh ├── prysm └── run.sh ├── compose-mev.yml ├── docker-compose.override.yml.sample ├── compose-el.yml ├── compose-vc.yml ├── compose-cl.yml ├── docker-compose.yml ├── .env.sample.hoodi ├── .env.sample.holesky ├── .env.sample.mainnet └── README.md /grafana/grafana.ini: -------------------------------------------------------------------------------- 1 | [auth.anonymous] 2 | enabled = true 3 | org_role = Admin -------------------------------------------------------------------------------- /jwt/jwt.hex: -------------------------------------------------------------------------------- 1 | 7074a5bf6bd6dae368fa598249d57edfcbccc67a1205b2c8d5d2fe7b800663aa -------------------------------------------------------------------------------- /DVNode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ObolNetwork/charon-distributed-validator-node/HEAD/DVNode.png -------------------------------------------------------------------------------- /grafana/dashboards.yml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | providers: 4 | - name: dashboards 5 | type: file 6 | updateIntervalSeconds: 30 7 | options: 8 | path: /etc/dashboards 9 | -------------------------------------------------------------------------------- /nimbus/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG VERSION 2 | 3 | FROM statusim/nimbus-eth2:${VERSION} AS nimbusbn 4 | 5 | FROM statusim/nimbus-validator-client:${VERSION} 6 | 7 | COPY --from=nimbusbn /home/user/nimbus_beacon_node /home/user/nimbus_beacon_node 8 | 9 | ENTRYPOINT ["/home/user/data/run.sh"] 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | .env.charon.more 3 | docker-compose.override.yml 4 | charon-enr-private-key 5 | validator_keys/ 6 | keystore-* 7 | deposit-data.json 8 | cluster-definition.json 9 | cluster-lock.json 10 | .DS_Store 11 | data/ 12 | .idea 13 | .charon 14 | prometheus/prometheus.yml 15 | commit-boost/config.toml 16 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | on: 3 | pull_request: 4 | push: 5 | branches: 6 | - main 7 | jobs: 8 | create_containers: 9 | # Ensures default fresh checkout can create containers. 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v6 13 | - run: docker compose up --no-start 14 | - run: docker compose -f docker-compose.yml -f compose-debug.yml up --no-start 15 | -------------------------------------------------------------------------------- /tempo/tempo.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | http_listen_port: 3200 3 | grpc_listen_port: 9095 4 | 5 | distributor: 6 | receivers: 7 | otlp: 8 | protocols: 9 | grpc: 10 | endpoint: 0.0.0.0:4317 11 | 12 | ingester: 13 | trace_idle_period: 10s 14 | max_block_bytes: 1_048_576 15 | max_block_duration: 5m 16 | 17 | compactor: 18 | compaction: 19 | block_retention: 24h 20 | 21 | storage: 22 | trace: 23 | backend: local 24 | local: 25 | path: /opt/tempo/traces 26 | -------------------------------------------------------------------------------- /logging.yml: -------------------------------------------------------------------------------- 1 | services: 2 | 3 | promtail: 4 | image: grafana/promtail:${PROMTAIL_VERSION:-2.8.2} 5 | environment: 6 | CHARON_LOKI_ADDRESSES: ${CHARON_LOKI_ADDRESSES} 7 | CLUSTER_NAME: ${CLUSTER_NAME} 8 | CLUSTER_PEER: ${CLUSTER_PEER} 9 | command: -config.file=/etc/promtail/config.yml 10 | volumes: 11 | - ./promtail:/etc/promtail 12 | - /var/run/docker.sock:/var/run/docker.sock 13 | networks: [dvnode] 14 | entrypoint: /etc/promtail/run.sh 15 | restart: unless-stopped 16 | 17 | networks: 18 | dvnode: 19 | -------------------------------------------------------------------------------- /prometheus/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ -z "$SERVICE_OWNER" ] 4 | then 5 | echo "\$SERVICE_OWNER variable is empty" >&2 6 | exit 1 7 | fi 8 | 9 | if [ -z "$PROM_REMOTE_WRITE_TOKEN" ] 10 | then 11 | echo "\$PROM_REMOTE_WRITE_TOKEN variable is empty" >&2 12 | exit 1 13 | fi 14 | 15 | sed -e "s|\$PROM_REMOTE_WRITE_TOKEN|${PROM_REMOTE_WRITE_TOKEN}|g" \ 16 | -e "s|\$SERVICE_OWNER|${SERVICE_OWNER}|g" \ 17 | /etc/prometheus/prometheus.yml.example > /etc/prometheus/prometheus.yml 18 | 19 | /bin/prometheus \ 20 | --config.file=/etc/prometheus/prometheus.yml 21 | -------------------------------------------------------------------------------- /.github/workflows/label-issues.yml: -------------------------------------------------------------------------------- 1 | name: Label issues 2 | on: 3 | issues: 4 | types: 5 | - reopened 6 | - opened 7 | jobs: 8 | label_issues: 9 | runs-on: ubuntu-latest 10 | permissions: 11 | issues: write 12 | steps: 13 | - uses: actions/github-script@v8 14 | with: 15 | script: | 16 | github.rest.issues.addLabels({ 17 | issue_number: context.issue.number, 18 | owner: context.repo.owner, 19 | repo: context.repo.repo, 20 | labels: ["protocol"] 21 | }) 22 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:recommended" 5 | ], 6 | "enabledManagers": [ 7 | "github-actions" 8 | ], 9 | "packageRules": [ 10 | { 11 | "matchManagers": [ 12 | "github-actions" 13 | ], 14 | "matchDepTypes": [ 15 | "github-actions" 16 | ], 17 | "matchFileNames": [ 18 | ".github/workflows/**" 19 | ], 20 | "schedule": [ 21 | "every weekend" 22 | ], 23 | "labels": [ 24 | "renovate/github-actions" 25 | ], 26 | "groupName": "GitHub Actions updates" 27 | } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /promtail/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ -z "$CHARON_LOKI_ADDRESSES" ]; then 4 | echo "Error: \$CHARON_LOKI_ADDRESSES variable is empty" >&2 5 | exit 1 6 | fi 7 | 8 | if [ -z "$CLUSTER_NAME" ]; then 9 | echo "Error: \$CLUSTER_NAME variable is empty" >&2 10 | exit 1 11 | fi 12 | 13 | if [ -z "$CLUSTER_PEER" ]; then 14 | echo "Error: \$CLUSTER_PEER variable is empty" >&2 15 | exit 1 16 | fi 17 | 18 | # Process the template file once 19 | sed -e "s|\$CHARON_LOKI_ADDRESSES|${CHARON_LOKI_ADDRESSES}|g" \ 20 | -e "s|\$CLUSTER_NAME|${CLUSTER_NAME}|g" \ 21 | -e "s|\$CLUSTER_PEER|${CLUSTER_PEER}|g" \ 22 | /etc/promtail/config.yml.example > /etc/promtail/config.yml 23 | 24 | # Start Promtail with the generated config 25 | /usr/bin/promtail \ 26 | -config.file=/etc/promtail/config.yml 27 | -------------------------------------------------------------------------------- /relay/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | # _ _ _ 3 | # _ _ ___ | | __ _ | || | 4 | # | '_|/ -_)| |/ _` | \_. | 5 | # |_| \___||_|\__/_| |__/ 6 | # 7 | relay: 8 | # Pegged charon version (update this for each release). 9 | image: obolnetwork/charon:${CHARON_VERSION:-v1.8.0} 10 | environment: 11 | CHARON_P2P_TCP_ADDRESS: 0.0.0.0:3610 12 | CHARON_HTTP_ADDRESS: 0.0.0.0:3640 13 | CHARON_LOG_LEVEL: debug 14 | CHARON_P2P_EXTERNAL_HOSTNAME: replace.with.public.ip.or.hostname 15 | ports: 16 | - 3610:3610/tcp 17 | - 3640:3640/tcp 18 | command: relay 19 | volumes: 20 | - .charon:/opt/charon/.charon # Relay charon-enr-private-key generated and persisted across restarts in this folder 21 | restart: on-failure 22 | -------------------------------------------------------------------------------- /grafana/datasource.yml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | deleteDatasources: 4 | - name: Prometheus 5 | orgId: 1 6 | - name: Loki 7 | orgId: 1 8 | 9 | 10 | datasources: 11 | - name: Prometheus 12 | type: prometheus 13 | uid: prometheus 14 | orgId: 1 15 | url: http://prometheus:9090 16 | basicAuth: false 17 | isDefault: true 18 | jsonData: 19 | graphiteVersion: "1.1" 20 | tlsAuth: false 21 | tlsAuthWithCACert: false 22 | version: 1 23 | editable: true 24 | 25 | - name: Loki 26 | type: loki 27 | uid: loki 28 | orgId: 1 29 | url: http://loki:3100 30 | basicAuth: false 31 | isDefault: false 32 | version: 1 33 | editable: true 34 | 35 | - name: Tempo 36 | type: tempo 37 | uid: tempo 38 | orgId: 1 39 | url: http://tempo:3200 40 | basicAuth: false 41 | isDefault: false 42 | version: 1 43 | editable: true -------------------------------------------------------------------------------- /loki/loki.yml: -------------------------------------------------------------------------------- 1 | auth_enabled: false 2 | 3 | server: 4 | http_listen_port: 3100 5 | 6 | ingester: 7 | lifecycler: 8 | address: 127.0.0.1 9 | ring: 10 | kvstore: 11 | store: inmemory 12 | replication_factor: 1 13 | final_sleep: 0s 14 | wal: 15 | enabled: false 16 | chunk_idle_period: 5m 17 | chunk_retain_period: 30s 18 | max_transfer_retries: 0 19 | 20 | schema_config: 21 | configs: 22 | - from: 2022-01-01 23 | store: boltdb 24 | object_store: filesystem 25 | schema: v11 26 | index: 27 | prefix: index_ 28 | period: 168h 29 | 30 | storage_config: 31 | boltdb: 32 | directory: /opt/loki/index 33 | 34 | filesystem: 35 | directory: /opt/loki/chunks 36 | 37 | limits_config: 38 | enforce_metric_name: false 39 | reject_old_samples: true 40 | reject_old_samples_max_age: 168h 41 | 42 | chunk_store_config: 43 | max_look_back_period: 0s 44 | 45 | table_manager: 46 | retention_deletes_enabled: false 47 | retention_period: 0s 48 | -------------------------------------------------------------------------------- /commit-boost/config.toml.sample.holesky: -------------------------------------------------------------------------------- 1 | chain = "Holesky" 2 | 3 | [pbs] 4 | port = 18550 5 | host = "0.0.0.0" 6 | #timeout_get_header_ms 7 | #timeout_get_payload_ms 8 | #timeout_register_validator_ms 9 | 10 | [metrics] 11 | enabled = true 12 | host = "0.0.0.0" 13 | 14 | [[relays]] 15 | id = "boost-relay-holesky.flashbots.net" 16 | url = "https://0xafa4c6985aa049fb79dd37010438cfebeb0f2bd42b115b89dd678dab0670c1de38da0c4e9138c9290a398ecd9a0b3110@boost-relay-holesky.flashbots.net" 17 | 18 | [[relays]] 19 | id = "holesky.titanrelay.xyz" 20 | url = "https://0xaa58208899c6105603b74396734a6263cc7d947f444f396a90f7b7d3e65d102aec7e5e5291b27e08d02c50a050825c2f@holesky.titanrelay.xyz" 21 | 22 | [[relays]] 23 | id = "relay-stag.ultrasound.money" 24 | url = "https://0xb1559beef7b5ba3127485bbbb090362d9f497ba64e177ee2c8e7db74746306efad687f2cf8574e38d70067d40ef136dc@relay-stag.ultrasound.money" 25 | 26 | [[relays]] 27 | id = "holesky.aestus.live" 28 | url = "https://0xab78bf8c781c58078c3beb5710c57940874dd96aef2835e7742c866b4c7c0406754376c2c8285a36c630346aa5c5f833@holesky.aestus.live" -------------------------------------------------------------------------------- /prometheus/prometheus.yml.example: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 30s # Set the scrape interval to every 30 seconds. 3 | evaluation_interval: 30s # Evaluate rules every 30 seconds. 4 | external_labels: 5 | service_owner: $SERVICE_OWNER # replace this with your Operator name you want to be identified by, it helps us route alerts and metrics to your notification channels easily 6 | 7 | remote_write: 8 | - url: https://vm.monitoring.gcp.obol.tech/write 9 | authorization: 10 | credentials: $PROM_REMOTE_WRITE_TOKEN 11 | write_relabel_configs: 12 | - source_labels: [job] 13 | regex: "charon" 14 | action: keep # Keeps charon metrics and drop metrics from other containers. 15 | 16 | scrape_configs: 17 | - job_name: "nethermind" 18 | static_configs: 19 | - targets: ["nethermind:8008"] 20 | - job_name: "lighthouse" 21 | static_configs: 22 | - targets: ["lighthouse:5054"] 23 | - job_name: "charon" 24 | static_configs: 25 | - targets: ["charon:3620"] 26 | - job_name: "lodestar" 27 | static_configs: 28 | - targets: ["lodestar:5064"] 29 | # Debug 30 | - job_name: "node-exporter" 31 | static_configs: 32 | - targets: ["node-exporter:9100"] 33 | - job_name: "cadvisor" 34 | static_configs: 35 | - targets: ["cadvisor:8080"] 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F680 Feature or Improvement Ticket" 3 | about: Create a new feature or suggest an improvement 4 | labels: Enhancement 5 | --- 6 | 7 | # 🎯 Problem to be solved 8 | 9 | 10 | 11 | # 🧪 Tests 12 | 13 | 14 | 15 | - [ ] Works in local docker-compose 16 | - [ ] Has a attested on a testnet at least once 17 | 18 | # 👐 Additional acceptance criteria 19 | 20 | 21 | 22 | # ❌ Out of Scope 23 | 24 | 25 | 26 | 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F41E Bug report" 3 | about: Report a bug or problem with running this repo 4 | labels: Bug 5 | --- 6 | 14 | 15 | # 🐞 Bug Report 16 | 17 | ### Description 18 | 19 | A clear and concise description of the problem... 20 | 21 | ## 🔬 Minimal Reproduction 22 | 23 | 26 | 27 | ## 🔥 Error 28 | 29 |

30 | 
31 | 
32 | 
33 | 
34 | 35 | 36 | ## 🌍 Your Environment 37 | 38 | **Operating System:** 39 | 40 |
41 |   
42 | 
43 |   
44 | 
45 | 46 | **What version of Charon are you running? (Which release)** 47 | 48 |
49 |   
50 | 
51 |   
52 | 
53 | 54 | **Anything else relevant (validator index / public key)?** 55 | 56 | -------------------------------------------------------------------------------- /.github/workflows/dispath-update.yml: -------------------------------------------------------------------------------- 1 | name: Dispatch Update Version 2 | 3 | on: 4 | repository_dispatch: 5 | types: [update-version] 6 | 7 | jobs: 8 | update-version: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout this repository 12 | uses: actions/checkout@v6 13 | 14 | - name: Extract tag name 15 | run: echo "TAG_NAME=${{ github.event.client_payload.tag }}" >> $GITHUB_ENV 16 | 17 | - name: Update version in Ansible configuration 18 | run: | 19 | TAG_NAME="$(echo "${TAG_NAME}" | sed 's/^v//')" 20 | 21 | sed -i -E 's|(image: obolnetwork/charon:\$\{CHARON_VERSION:-)v\.?[0-9]+\.[0-9]+\.[0-9]+[a-zA-Z0-9\-]*}|\1v'"${TAG_NAME}"'}|' docker-compose.yml 22 | sed -i -E 's|(image: obolnetwork/charon:\$\{CHARON_VERSION:-)v\.?[0-9]+\.[0-9]+\.[0-9]+[a-zA-Z0-9\-]*}|\1v'"${TAG_NAME}"'}|' relay/docker-compose.yml 23 | 24 | - name: Create Pull Request 25 | uses: peter-evans/create-pull-request@v8 26 | with: 27 | token: ${{ secrets.GITHUB_TOKEN }} 28 | base: main 29 | branch: update-version-${{ env.TAG_NAME }} 30 | title: "Update version to ${{ env.TAG_NAME }}" 31 | body: "Automatically generated PR to update version to ${{ env.TAG_NAME }}" 32 | commit-message: "Update version to ${{ env.TAG_NAME }}" 33 | author-name: "obol-platform" 34 | author-email: "platform@obol.tech" 35 | -------------------------------------------------------------------------------- /commit-boost/config.toml.sample.hoodi: -------------------------------------------------------------------------------- 1 | chain = "Hoodi" 2 | 3 | [pbs] 4 | port = 18550 5 | host = "0.0.0.0" 6 | #timeout_get_header_ms 7 | #timeout_get_payload_ms 8 | #timeout_register_validator_ms 9 | 10 | [metrics] 11 | enabled = true 12 | host = "0.0.0.0" 13 | 14 | [[relays]] 15 | id = "hoodi.aestus.live" 16 | url = "https://0x98f0ef62f00780cf8eb06701a7d22725b9437d4768bb19b363e882ae87129945ec206ec2dc16933f31d983f8225772b6@hoodi.aestus.live" 17 | 18 | [[relays]] 19 | id = "hoodi.titanrelay.xyz" 20 | url = "https://0xaa58208899c6105603b74396734a6263cc7d947f444f396a90f7b7d3e65d102aec7e5e5291b27e08d02c50a050825c2f@hoodi.titanrelay.xyz" 21 | 22 | [[relays]] 23 | id = "relay-hoodi.ultrasound.money" 24 | url = "https://0xb1559beef7b5ba3127485bbbb090362d9f497ba64e177ee2c8e7db74746306efad687f2cf8574e38d70067d40ef136dc@relay-hoodi.ultrasound.money" 25 | 26 | [[relays]] 27 | id = "boost-relay-hoodi.flashbots.net" 28 | url = "https://0xafa4c6985aa049fb79dd37010438cfebeb0f2bd42b115b89dd678dab0670c1de38da0c4e9138c9290a398ecd9a0b3110@boost-relay-hoodi.flashbots.net" 29 | 30 | [[relays]] 31 | id = "hoodi-builder-proxy-alpha.interstate.so" 32 | url = "https://0x9110847c15a7f5c80a9fdd5db989a614cc01104e53bd8c252b6f46a4842c7fdef6b9593336035b5094878deff386804c@hoodi-builder-proxy-alpha.interstate.so" 33 | 34 | [[relays]] 35 | id = "hoodi-relay.ethgas.com" 36 | url = "https://0xb20c3fe59db9c3655088839ef3d972878d182eb745afd8abb1dd2abf6c14f93cd5934ed4446a5fe1ba039e2bc0cf1011@hoodi-relay.ethgas.com" -------------------------------------------------------------------------------- /nimbus/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Cleanup nimbus directories if they already exist. 4 | rm -rf /home/user/data 5 | 6 | # Refer: https://nimbus.guide/keys.html 7 | # Running a nimbus VC involves two steps which need to run in order: 8 | # 1. Importing the validator keys 9 | # 2. And then actually running the VC 10 | tmpkeys="/home/validator_keys/tmpkeys" 11 | mkdir -p ${tmpkeys} 12 | 13 | for f in /home/validator_keys/keystore-*.json; do 14 | echo "Importing key ${f}" 15 | 16 | # Read password from keystore-*.txt into $password variable. 17 | password=$(<"${f//json/txt}") 18 | 19 | # Copy keystore file to tmpkeys/ directory. 20 | cp "${f}" "${tmpkeys}" 21 | 22 | # Import keystore with the password. 23 | echo "$password" | 24 | /home/user/nimbus_beacon_node deposits import \ 25 | --data-dir=/home/user/data \ 26 | /home/validator_keys/tmpkeys 27 | 28 | # Delete tmpkeys/keystore-*.json file that was copied before. 29 | filename="$(basename ${f})" 30 | rm "${tmpkeys}/${filename}" 31 | done 32 | 33 | # Delete the tmpkeys/ directory since it's no longer needed. 34 | rm -r ${tmpkeys} 35 | 36 | echo "Imported all keys" 37 | 38 | # Now run nimbus VC 39 | exec /home/user/nimbus_validator_client \ 40 | --data-dir=/home/user/data \ 41 | --beacon-node="${BEACON_NODE_ADDRESS}" \ 42 | --doppelganger-detection=false \ 43 | --metrics \ 44 | --metrics-address=0.0.0.0 \ 45 | --payload-builder=${BUILDER_API_ENABLED} \ 46 | --distributed 47 | -------------------------------------------------------------------------------- /promtail/config.yml.example: -------------------------------------------------------------------------------- 1 | server: 2 | http_listen_port: 9080 3 | grpc_listen_port: 0 4 | 5 | positions: 6 | filename: /tmp/positions.yaml 7 | 8 | clients: 9 | - url: $CHARON_LOKI_ADDRESSES 10 | 11 | scrape_configs: 12 | - job_name: docker 13 | docker_sd_configs: 14 | - host: unix:///var/run/docker.sock 15 | relabel_configs: 16 | - source_labels: 17 | [__meta_docker_container_label_promtail_monitored] 18 | regex: "true" 19 | action: keep 20 | - source_labels: ['__meta_docker_container_name'] 21 | regex: '/(.*)' 22 | replacement: '$1' 23 | target_label: 'container' 24 | - source_labels: ['container'] 25 | regex: '.*charon.*' 26 | replacement: 'charon' 27 | target_label: 'job' 28 | - source_labels: ['container'] 29 | regex: '.*nethermind.*' 30 | replacement: 'nethermind' 31 | target_label: 'job' 32 | - source_labels: ['container'] 33 | regex: '.*lodestar.*' 34 | replacement: 'lodestar' 35 | target_label: 'job' 36 | - source_labels: ['container'] 37 | regex: '.*lighthouse.*' 38 | replacement: 'lighthouse' 39 | target_label: 'job' 40 | - source_labels: ['container'] 41 | regex: '.*mev-boost.*' 42 | replacement: 'mev-boost' 43 | target_label: 'job' 44 | - target_label: 'cluster_name' 45 | replacement: $CLUSTER_NAME 46 | - target_label: 'cluster_peer' 47 | replacement: $CLUSTER_PEER 48 | pipeline_stages: 49 | - docker: {} 50 | -------------------------------------------------------------------------------- /commit-boost/config.toml.sample.mainnet: -------------------------------------------------------------------------------- 1 | chain = "Mainnet" 2 | 3 | [pbs] 4 | port = 18550 5 | host = "0.0.0.0" 6 | #timeout_get_header_ms 7 | #timeout_get_payload_ms 8 | #timeout_register_validator_ms 9 | 10 | [metrics] 11 | enabled = true 12 | host = "0.0.0.0" 13 | 14 | [[relays]] 15 | id = "aestus.live" 16 | url = "https://0xa15b52576bcbf1072f4a011c0f99f9fb6c66f3e1ff321f11f461d15e31b1cb359caa092c71bbded0bae5b5ea401aab7e@aestus.live" 17 | 18 | [[relays]] 19 | id = "agnostic-relay.net" 20 | url = "https://0xa7ab7a996c8584251c8f925da3170bdfd6ebc75d50f5ddc4050a6fdc77f2a3b5fce2cc750d0865e05d7228af97d69561@agnostic-relay.net" 21 | 22 | [[relays]] 23 | id = "bloxroute.max-profit.blxrbdn.com" 24 | url = "https://0x8b5d2e73e2a3a55c6c87b8b6eb92e0149a125c852751db1422fa951e42a09b82c142c3ea98d0d9930b056a3bc9896b8f@bloxroute.max-profit.blxrbdn.com" 25 | 26 | [[relays]] 27 | id = "bloxroute.regulated.blxrbdn.com" 28 | url = "https://0xb0b07cd0abef743db4260b0ed50619cf6ad4d82064cb4fbec9d3ec530f7c5e6793d9f286c4e082c0244ffb9f2658fe88@bloxroute.regulated.blxrbdn.com" 29 | 30 | [[relays]] 31 | id = "boost-relay.flashbots.net" 32 | url = "https://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@boost-relay.flashbots.net" 33 | 34 | [[relays]] 35 | id = "relay.ultrasound.money" 36 | url = "https://0xa1559ace749633b997cb3fdacffb890aeebdb0f5a3b6aaa7eeeaf1a38af0a8fe88b9e4b1f61f236d2e64d95733327a62@relay.ultrasound.money" 37 | 38 | [[relays]] 39 | id = "global.titanrelay.xyz" 40 | url = "https://0x8c4ed5e24fe5c6ae21018437bde147693f68cda427cd1122cf20819c30eda7ed74f72dece09bb313f2a1855595ab677d@global.titanrelay.xyz" -------------------------------------------------------------------------------- /compose-debug.yml: -------------------------------------------------------------------------------- 1 | # Docker-compose file to aid developers in debugging. This is not required for "normal" users. See the "Docker power users" section of the README.md for more info. 2 | 3 | # Override any defaults specified by `${FOO:-bar}` in `.env` with `FOO=qux`. 4 | # See .env.sample "Debug Config" section 5 | 6 | services: 7 | cadvisor: 8 | image: gcr.io/cadvisor/cadvisor:${CADVISOR_VERSION:-v0.47.0} 9 | command: --raw_cgroup_prefix_whitelist=/docker/ --disable_metrics=hugetlb 10 | privileged: true 11 | volumes: 12 | - "/:/rootfs:ro" 13 | - "/var/run:/var/run:ro" 14 | - "/sys:/sys:ro" 15 | - "/var/lib/docker/:/var/lib/docker:ro" 16 | - "/dev/disk/:/dev/disk:ro" 17 | devices: 18 | - "/dev/kmsg:/dev/kmsg" 19 | restart: unless-stopped 20 | 21 | node-exporter: 22 | image: bitnamilegacy/node-exporter:${NODE_EXPORTER_VERSION:-1.6.0} 23 | 24 | tempo: 25 | image: grafana/tempo:${TEMPO_VERSION:-2.7.1} 26 | user: ":" 27 | command: -config.file=/etc/tempo/tempo.yaml 28 | volumes: 29 | - ./tempo:/etc/tempo 30 | - ./data/tempo:/opt/tempo 31 | restart: unless-stopped 32 | 33 | loki: 34 | image: grafana/loki:${LOKI_VERSION:-2.8.2} 35 | user: ":" 36 | command: -config.file=/etc/loki/loki.yml 37 | volumes: 38 | - ./loki/loki.yml:/etc/loki/loki.yml 39 | - ./data/loki:/opt/loki 40 | restart: unless-stopped 41 | 42 | charon: 43 | environment: 44 | - CHARON_OTLP_ADDRESS=tempo:4317 45 | - CHARON_OTLP_SERVICE_NAME=charon 46 | - CHARON_LOKI_ADDRESSES=${CHARON_LOKI_ADDRESSES:-http://loki:3100/loki/api/v1/push} 47 | - CHARON_LOKI_SERVICE=charon 48 | 49 | networks: 50 | default: 51 | name: ${CHARON_DOCKER_NETWORK:-charon-distributed-validator-node_dvnode} 52 | external: true 53 | -------------------------------------------------------------------------------- /lodestar/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Remove the existing keystores to avoid keystore locking issues. 4 | rm -rf /opt/data/cache /opt/data/secrets /opt/data/keystores 5 | 6 | DATA_DIR="/opt/data" 7 | KEYSTORES_DIR="${DATA_DIR}/keystores" 8 | SECRETS_DIR="${DATA_DIR}/secrets" 9 | 10 | mkdir -p "${KEYSTORES_DIR}" "${SECRETS_DIR}" 11 | 12 | IMPORTED_COUNT=0 13 | EXISTING_COUNT=0 14 | 15 | for f in /home/charon/validator_keys/keystore-*.json; do 16 | echo "Importing key ${f}" 17 | 18 | # Extract pubkey from keystore file 19 | PUBKEY="0x$(grep '"pubkey"' "$f" | awk -F'"' '{print $4}')" 20 | 21 | PUBKEY_DIR="${KEYSTORES_DIR}/${PUBKEY}" 22 | 23 | # Skip import if keystore already exists 24 | if [ -d "${PUBKEY_DIR}" ]; then 25 | EXISTING_COUNT=$((EXISTING_COUNT + 1)) 26 | continue 27 | fi 28 | 29 | mkdir -p "${PUBKEY_DIR}" 30 | 31 | # Copy the keystore file to persisted keys backend 32 | install -m 600 "$f" "${PUBKEY_DIR}/voting-keystore.json" 33 | 34 | # Copy the corresponding password file 35 | PASSWORD_FILE="${f%.json}.txt" 36 | install -m 600 "${PASSWORD_FILE}" "${SECRETS_DIR}/${PUBKEY}" 37 | 38 | IMPORTED_COUNT=$((IMPORTED_COUNT + 1)) 39 | done 40 | 41 | echo "Processed all keys imported=${IMPORTED_COUNT}, existing=${EXISTING_COUNT}, total=$(ls /home/charon/validator_keys/keystore-*.json | wc -l)" 42 | 43 | exec node /usr/app/packages/cli/bin/lodestar validator \ 44 | --dataDir="$DATA_DIR" \ 45 | --keystoresDir="$KEYSTORES_DIR" \ 46 | --secretsDir="$SECRETS_DIR" \ 47 | --network="$NETWORK" \ 48 | --metrics=true \ 49 | --metrics.address="0.0.0.0" \ 50 | --metrics.port=5064 \ 51 | --beaconNodes="$BEACON_NODE_ADDRESS" \ 52 | --builder="$BUILDER_API_ENABLED" \ 53 | --builder.selection="$BUILDER_SELECTION" \ 54 | --distributed 55 | -------------------------------------------------------------------------------- /prysm/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | WALLET_DIR="/prysm-wallet" 4 | 5 | # Cleanup wallet directories if already exists. 6 | rm -rf $WALLET_DIR 7 | mkdir $WALLET_DIR 8 | 9 | # Refer: https://prysm.offchainlabs.com/docs/install-prysm/install-with-script/#step-5-run-a-validator-using-prysm 10 | # Running a prysm VC involves two steps which need to run in order: 11 | # 1. Import validator keys in a prysm wallet account. 12 | # 2. Run the validator client. 13 | WALLET_PASSWORD="prysm-validator-secret" 14 | echo $WALLET_PASSWORD > /wallet-password.txt 15 | /app/cmd/validator/validator wallet create --accept-terms-of-use --wallet-password-file=wallet-password.txt --keymanager-kind=direct --wallet-dir="$WALLET_DIR" 16 | 17 | tmpkeys="/home/validator_keys/tmpkeys" 18 | mkdir -p ${tmpkeys} 19 | 20 | for f in /home/charon/validator_keys/keystore-*.json; do 21 | echo "Importing key ${f}" 22 | 23 | # Copy keystore file to tmpkeys/ directory. 24 | cp "${f}" "${tmpkeys}" 25 | 26 | # Import keystore with password. 27 | /app/cmd/validator/validator accounts import \ 28 | --accept-terms-of-use=true \ 29 | --wallet-dir="$WALLET_DIR" \ 30 | --keys-dir="${tmpkeys}" \ 31 | --account-password-file="${f//json/txt}" \ 32 | --wallet-password-file=wallet-password.txt 33 | 34 | # Delete tmpkeys/keystore-*.json file that was copied before. 35 | filename="$(basename ${f})" 36 | rm "${tmpkeys}/${filename}" 37 | done 38 | 39 | # Delete the tmpkeys/ directory since it's no longer needed. 40 | rm -r ${tmpkeys} 41 | 42 | echo "Imported all keys" 43 | 44 | # Now run prysm VC 45 | /app/cmd/validator/validator --wallet-dir="$WALLET_DIR" \ 46 | --accept-terms-of-use=true \ 47 | --datadir="/data/vc" \ 48 | --wallet-password-file="/wallet-password.txt" \ 49 | --enable-beacon-rest-api \ 50 | --beacon-rest-api-provider="${BEACON_NODE_ADDRESS}" \ 51 | --beacon-rpc-provider="${BEACON_NODE_ADDRESS}" \ 52 | --"${NETWORK}" \ 53 | --distributed 54 | -------------------------------------------------------------------------------- /compose-mev.yml: -------------------------------------------------------------------------------- 1 | # Override any defaults specified by `${FOO:-bar}` in `.env` with `FOO=qux`. 2 | # ${VARIABLE:-default} evaluates to default if VARIABLE is unset or empty in the environment. 3 | # ${VARIABLE-default} evaluates to default only if VARIABLE is unset in the environment. 4 | 5 | services: 6 | # _ _ _ _ 7 | # ___ ___ _ __ ___ _ __ ___ (_) |_ | |__ ___ ___ ___| |_ 8 | # / __/ _ \| '_ ` _ \| '_ ` _ \| | __|____| '_ \ / _ \ / _ \/ __| __| 9 | # | (_| (_) | | | | | | | | | | | | ||_____| |_) | (_) | (_) \__ \ |_ 10 | # \___\___/|_| |_| |_|_| |_| |_|_|\__| |_.__/ \___/ \___/|___/\__| 11 | 12 | mev-commitboost: 13 | profiles: [mev-commitboost] 14 | image: ghcr.io/commit-boost/pbs:${MEV_COMMITBOOST_VERSION:-v0.9.2} 15 | environment: 16 | - CB_CONFIG=/etc/commit-boost/config.toml 17 | volumes: 18 | - ./commit-boost/config.toml:/etc/commit-boost/config.toml:ro 19 | labels: 20 | - "promtail-monitored=${MEV_COMMIT_BOOST_PROMTAIL_MONITORED:-true}" 21 | networks: [dvnode] 22 | restart: unless-stopped 23 | 24 | # _ _ 25 | # _ __ ___ _____ __ | |__ ___ ___ ___| |_ 26 | # | '_ ` _ \ / _ \ \ / /____| '_ \ / _ \ / _ \/ __| __| 27 | # | | | | | | __/\ V /_____| |_) | (_) | (_) \__ \ |_ 28 | # |_| |_| |_|\___| \_/ |_.__/ \___/ \___/|___/\__| 29 | 30 | mev-mevboost: 31 | profiles: [mev-mevboost] 32 | image: flashbots/mev-boost:${MEV_MEVBOOST_VERSION:-1.10.1} 33 | command: | 34 | -${NETWORK} 35 | -loglevel=debug 36 | -addr=0.0.0.0:18550 37 | -relay-check 38 | -relays=${MEV_RELAYS} 39 | -request-timeout-getheader=${MEV_TIMEOUT_GETHEADER:-950} 40 | -request-timeout-getpayload=${MEV_TIMEOUT_GETPAYLOAD:-4000} 41 | -request-timeout-regval=${MEV_TIMEOUT_REGVAL:-3000} 42 | labels: 43 | - "promtail-monitored=${MEV_MEV_BOOST_PROMTAIL_MONITORED:-true}" 44 | networks: [dvnode] 45 | restart: unless-stopped 46 | -------------------------------------------------------------------------------- /docker-compose.override.yml.sample: -------------------------------------------------------------------------------- 1 | # The "Multiple Compose File" feature provides a very powerful way to override 2 | # any configuration in docker-compose.yml without needing to modify 3 | # git-checked-in files since that results in conflicts when upgrading this repo. 4 | # See https://docs.docker.com/compose/extends/#multiple-compose-files for more. 5 | 6 | # Just copy this file to `docker-compose.override.yml` and customise it to your liking. 7 | # `cp docker-compose.override.yml.sample docker-compose.override.yml` 8 | 9 | # Some example overrides are commented out below. Any uncommented section 10 | # below will automatically override the same section in 11 | # docker-compose.yml when ran with `docker-compose up`. 12 | # See https://docs.docker.com/compose/extends/#adding-and-overriding-configuration for details. 13 | 14 | # WARNING: This is for power users only and requires a deep understanding of Docker Compose 15 | # and how the local docker-compose.yml is configured. 16 | 17 | #services: 18 | #nethermind: 19 | # Disable nethermind 20 | #profiles: [disable] 21 | # Bind nethermind internal ports to host ports 22 | #ports: 23 | #- 8545:8545 # JSON-RPC 24 | #- 8551:8551 # AUTH-RPC 25 | #- 8008:8008 # Metrics 26 | 27 | #lighthouse: 28 | # Disable lighthouse 29 | #profiles: [disable] 30 | # Bind lighthouse internal ports to host ports 31 | #ports: 32 | #- 5052:5052 # HTTP 33 | #- 5054:5054 # Metrics 34 | 35 | #charon: 36 | # Configure any additional env var flags in .env.charon.more 37 | #env_file: [.env.charon.more] 38 | # Uncomment the extra_hosts section if you are trying to communicate with a CL running in a different docker network on the same machine 39 | #extra_hosts: 40 | #- "host.docker.internal:host-gateway" 41 | # Bind charon internal ports to host ports 42 | #ports: 43 | #- 3600:3600/tcp # Validator API 44 | #- 3620:3620/tcp # Monitoring 45 | 46 | #lodestar: 47 | # Disable lodestar 48 | #profiles: [disable] 49 | # Bind lodestar internal ports to host ports 50 | #ports: 51 | #- 5064:5064 # Metrics 52 | 53 | #prometheus: 54 | # Disable prometheus 55 | #profiles: [disable] 56 | # Bind prometheus internal ports to host ports 57 | #ports: 58 | #- 9090:9090 # Metrics 59 | 60 | #mev-boost: 61 | # Disable mev-boost 62 | #profiles: [disable] 63 | # Bind mev-boost internal ports to host ports 64 | #ports: 65 | #- 18550:18550 # Metrics 66 | -------------------------------------------------------------------------------- /compose-el.yml: -------------------------------------------------------------------------------- 1 | # Override any defaults specified by `${FOO:-bar}` in `.env` with `FOO=qux`. 2 | # ${VARIABLE:-default} evaluates to default if VARIABLE is unset or empty in the environment. 3 | # ${VARIABLE-default} evaluates to default only if VARIABLE is unset in the environment. 4 | 5 | services: 6 | # _ _ _ _ 7 | # _ __ ___| |_| |__ ___ _ __ _ __ ___ (_)_ __ __| | 8 | # | '_ \ / _ \ __| '_ \ / _ \ '__| '_ ` _ \| | '_ \ / _` | 9 | # | | | | __/ |_| | | | __/ | | | | | | | | | | | (_| | 10 | # |_| |_|\___|\__|_| |_|\___|_| |_| |_| |_|_|_| |_|\__,_| 11 | 12 | el-nethermind: 13 | profiles: [el-nethermind] 14 | image: nethermind/nethermind:${EL_NETHERMIND_VERSION:-1.35.2} 15 | restart: unless-stopped 16 | ports: 17 | - ${EL_PORT_P2P:-30303}:30303/tcp # P2P TCP 18 | - ${EL_PORT_P2P:-30303}:30303/udp # P2P UDP 19 | - ${EL_IP_HTTP:-127.0.0.1}:${EL_PORT_HTTP:-8545}:8545 # JSON-RPC 20 | - ${EL_IP_ENGINE:-127.0.0.1}:${EL_PORT_ENGINE:-8551}:8551 # ENGINE-API 21 | labels: 22 | - "promtail-monitored=${EL_NETHERMIND_PROMTAIL_MONITORED:-true}" 23 | command: | 24 | --config=${NETWORK} 25 | --data-dir=/nethermind/data 26 | --HealthChecks.Enabled=true 27 | --JsonRpc.Enabled=true 28 | --JsonRpc.JwtSecretFile="/root/jwt/jwt.hex" 29 | --JsonRpc.EngineHost=0.0.0.0 30 | --JsonRpc.EnginePort=8551 31 | --JsonRpc.Host=0.0.0.0 32 | --JsonRpc.Port=8545 33 | --Metrics.Enabled=true 34 | --Metrics.ExposePort=8008 35 | --Sync.SnapSync=true 36 | --History.Pruning=Rolling 37 | networks: [dvnode] 38 | volumes: 39 | - ./data/nethermind:/nethermind/data 40 | - ./jwt:/root/jwt 41 | 42 | # _ _ 43 | # _ __ ___| |_| |__ 44 | # | '__/ _ \ __| '_ \ 45 | # | | | __/ |_| | | | 46 | # |_| \___|\__|_| |_| 47 | 48 | el-reth: 49 | profiles: [el-reth] 50 | image: ghcr.io/paradigmxyz/reth:${EL_RETH_VERSION:-v1.9.3} 51 | restart: unless-stopped 52 | ports: 53 | - ${EL_PORT_P2P:-30303}:30303/tcp # P2P TCP 54 | - ${EL_PORT_P2P:-30303}:30303/udp # P2P UDP 55 | - ${EL_IP_HTTP:-127.0.0.1}:${EL_PORT_HTTP:-8545}:8545 # JSON-RPC 56 | - ${EL_IP_ENGINE:-127.0.0.1}:${EL_PORT_ENGINE:-8551}:8551 # ENGINE-API 57 | labels: 58 | - "promtail-monitored=${EL_RETH_PROMTAIL_MONITORED:-true}" 59 | command: | 60 | node 61 | --full 62 | --chain=${NETWORK} 63 | --datadir=/reth/data 64 | --authrpc.jwtsecret="/root/jwt/jwt.hex" 65 | --authrpc.addr=0.0.0.0 66 | --authrpc.port=8551 67 | --http 68 | --http.addr=0.0.0.0 69 | --http.port=8545 70 | --metrics=0.0.0.0:8008 71 | networks: [dvnode] 72 | volumes: 73 | - ./data/reth:/reth/data 74 | - ./jwt:/root/jwt 75 | -------------------------------------------------------------------------------- /compose-vc.yml: -------------------------------------------------------------------------------- 1 | # Override any defaults specified by `${FOO:-bar}` in `.env` with `FOO=qux`. 2 | # ${VARIABLE:-default} evaluates to default if VARIABLE is unset or empty in the environment. 3 | # ${VARIABLE-default} evaluates to default only if VARIABLE is unset in the environment. 4 | 5 | services: 6 | # _ _ _ 7 | # | | ___ __| | ___ ___| |_ __ _ _ __ 8 | # | |/ _ \ / _` |/ _ \/ __| __/ _` | '__| 9 | # | | (_) | (_| | __/\__ \ || (_| | | 10 | # |_|\___/ \__,_|\___||___/\__\__,_|_| 11 | 12 | vc-lodestar: 13 | profiles: [vc-lodestar] 14 | image: chainsafe/lodestar:${VC_LODESTAR_VERSION:-v1.38.0} 15 | depends_on: [charon] 16 | entrypoint: /opt/lodestar/run.sh 17 | networks: [dvnode] 18 | environment: 19 | BEACON_NODE_ADDRESS: http://charon:3600 20 | NETWORK: ${NETWORK} 21 | BUILDER_API_ENABLED: ${BUILDER_API_ENABLED:-true} 22 | BUILDER_SELECTION: ${VC_LODESTAR_BUILDER_SELECTION:-builderalways} 23 | labels: 24 | - "promtail-monitored=${VC_LODESTAR_PROMTAIL_MONITORED:-true}" 25 | volumes: 26 | - ./lodestar/run.sh:/opt/lodestar/run.sh 27 | - .charon/validator_keys:/home/charon/validator_keys 28 | - ./data/lodestar:/opt/data # Keep data in lodestar and not vc-lodestar for backwards compatibility 29 | restart: unless-stopped 30 | 31 | # _ _ 32 | # _ __ (_)_ __ ___ | |__ _ _ ___ 33 | # | '_ \| | '_ ` _ \| '_ \| | | / __| 34 | # | | | | | | | | | | |_) | |_| \__ \ 35 | # |_| |_|_|_| |_| |_|_.__/ \__,_|___/ 36 | 37 | vc-nimbus: 38 | profiles: [vc-nimbus] 39 | image: "lido-nimbus-validator-client:${VC_NIMBUS_VERSION:-multiarch-v25.11.1}" 40 | build: 41 | context: nimbus 42 | args: 43 | VERSION: ${VC_NIMBUS_VERSION:-multiarch-v25.11.1} 44 | depends_on: [charon] 45 | networks: [dvnode] 46 | environment: 47 | BEACON_NODE_ADDRESS: http://charon:3600 48 | BUILDER_API_ENABLED: ${BUILDER_API_ENABLED:-true} 49 | labels: 50 | - "promtail-monitored=${VC_NIMBUS_PROMTAIL_MONITORED:-true}" 51 | volumes: 52 | - ./nimbus/run.sh:/home/user/data/run.sh 53 | - .charon/validator_keys:/home/validator_keys 54 | - ./data/vc-nimbus:/home/user/data 55 | restart: unless-stopped 56 | 57 | # _ __ _ __ _ _ ___ _ __ ___ 58 | # | '_ \| '__| | | / __| '_ ` _ \ 59 | # | |_) | | | |_| \__ \ | | | | | 60 | # | .__/|_| \__, |___/_| |_| |_| 61 | # |_| |___/ 62 | 63 | vc-prysm: 64 | profiles: [vc-prysm] 65 | image: offchainlabs/prysm-validator:${VC_PRYSM_VERSION:-v7.1.0} 66 | platform: "linux/amd64" 67 | depends_on: [charon] 68 | networks: [dvnode] 69 | entrypoint: /home/prysm/run.sh 70 | environment: 71 | BEACON_NODE_ADDRESS: http://charon:3600 72 | NETWORK: ${NETWORK} 73 | labels: 74 | - "promtail-monitored=${VC_PRYSM_PROMTAIL_MONITORED:-true}" 75 | volumes: 76 | - ./prysm/run.sh:/home/prysm/run.sh 77 | - ./data/vc-prysm:/data/vc 78 | - .charon/validator_keys:/home/charon/validator_keys 79 | restart: unless-stopped 80 | 81 | # _ _ 82 | # | |_ ___| | ___ _ 83 | # | __/ _ \ |/ / | | | 84 | # | || __/ <| |_| | 85 | # \__\___|_|\_\\__,_| 86 | 87 | vc-teku: 88 | profiles: [vc-teku] 89 | image: consensys/teku:${VC_TEKU_VERSION:-25.12.0} 90 | command: | 91 | validator-client 92 | --beacon-node-api-endpoint "http://charon:3600" 93 | --network="${NETWORK}" 94 | --data-base-path=/home/data 95 | --validator-keys="/opt/charon/validator_keys:/opt/charon/validator_keys" 96 | --validators-keystore-locking-enabled false 97 | --validators-external-signer-slashing-protection-enabled true 98 | --validators-builder-registration-default-enabled ${BUILDER_API_ENABLED:-true} 99 | --validators-proposer-default-fee-recipient "0x0000000000000000000000000000000000000000" 100 | --Xobol-dvt-integration-enabled true 101 | depends_on: [charon] 102 | networks: [dvnode] 103 | labels: 104 | - "promtail-monitored=${VC_TEKU_PROMTAIL_MONITORED:-true}" 105 | volumes: 106 | - .charon/validator_keys:/opt/charon/validator_keys 107 | - ./data/vc-teku:/home/data 108 | restart: unless-stopped 109 | -------------------------------------------------------------------------------- /compose-cl.yml: -------------------------------------------------------------------------------- 1 | # Override any defaults specified by `${FOO:-bar}` in `.env` with `FOO=qux`. 2 | # ${VARIABLE:-default} evaluates to default if VARIABLE is unset or empty in the environment. 3 | # ${VARIABLE-default} evaluates to default only if VARIABLE is unset in the environment. 4 | 5 | services: 6 | # _ _ 7 | # __ _ _ __ __ _ _ __ __| (_)_ __ ___ 8 | # / _` | '__/ _` | '_ \ / _` | | '_ \ / _ \ 9 | # | (_| | | | (_| | | | | (_| | | | | | __/ 10 | # \__, |_| \__,_|_| |_|\__,_|_|_| |_|\___| 11 | # |___/ 12 | 13 | cl-grandine: 14 | profiles: [cl-grandine] 15 | image: sifrai/grandine:${GRANDINE_VERSION:-2.0.1} 16 | restart: unless-stopped 17 | labels: 18 | - "promtail-monitored=${CL_GRANDINE_PROMTAIL_MONITORED:-true}" 19 | command: 20 | - --data-dir=/root/.grandine 21 | - --eth1-rpc-urls=http://${EL}:8551 22 | - --jwt-secret=/jwt/jwt.hex 23 | - --http-address=0.0.0.0 24 | - --http-port=5052 25 | - --network=${NETWORK} 26 | - --metrics 27 | - --metrics-port=5054 28 | - --metrics-address=0.0.0.0 29 | - --checkpoint-sync-url=${LIGHTHOUSE_CHECKPOINT_SYNC_URL} 30 | - --builder-url=http://${MEV}:18550 31 | - --max-empty-slots=4096 32 | ports: 33 | - ${CL_PORT_P2P:-9000}:9000 # P2P TCP+UDP 34 | volumes: 35 | - ./data/cl-grandine:/root/.grandine 36 | - ./jwt:/jwt:ro 37 | networks: [dvnode] 38 | 39 | # _ _ _ _ _ 40 | # | (_) __ _| |__ | |_| |__ ___ _ _ ___ ___ 41 | # | | |/ _` | '_ \| __| '_ \ / _ \| | | / __|/ _ \ 42 | # | | | (_| | | | | |_| | | | (_) | |_| \__ \ __/ 43 | # |_|_|\__, |_| |_|\__|_| |_|\___/ \__,_|___/\___| 44 | # |___/ 45 | 46 | cl-lighthouse: 47 | profiles: [cl-lighthouse] 48 | image: sigp/lighthouse:${LIGHTHOUSE_VERSION:-v8.0.1} 49 | restart: unless-stopped 50 | labels: 51 | - "promtail-monitored=${CL_LIGHTHOUSE_PROMTAIL_MONITORED:-true}" 52 | command: | 53 | lighthouse bn 54 | --network=${NETWORK} 55 | --checkpoint-sync-url=${LIGHTHOUSE_CHECKPOINT_SYNC_URL} 56 | --checkpoint-sync-url-timeout=600 57 | --execution-endpoint=http://${EL}:8551 58 | --execution-jwt=/opt/jwt/jwt.hex 59 | --datadir=/opt/app/beacon/ 60 | --builder=http://${MEV}:18550 61 | --http 62 | --http-address=0.0.0.0 63 | --http-port=5052 64 | --metrics 65 | --metrics-address=0.0.0.0 66 | --metrics-port=5054 67 | --metrics-allow-origin="*" 68 | ports: 69 | - ${CL_PORT_P2P:-9000}:9000 # P2P TCP+UDP 70 | volumes: 71 | - ./data/lighthouse:/opt/app/beacon # Keep data in lighthouse and not cl-lighthouse for backwards compatibility 72 | - ./jwt:/opt/jwt 73 | networks: [dvnode] 74 | 75 | # _ _ 76 | # | |_ ___| | ___ _ 77 | # | __/ _ \ |/ / | | | 78 | # | || __/ <| |_| | 79 | # \__\___|_|\_\\__,_| 80 | 81 | cl-teku: 82 | profiles: [cl-teku] 83 | image: consensys/teku:${VC_VERSION:-25.12.0} 84 | restart: unless-stopped 85 | labels: 86 | - "promtail-monitored=${CL_TEKU_PROMTAIL_MONITORED:-true}" 87 | command: | 88 | --network=${NETWORK} 89 | --checkpoint-sync-url=${LIGHTHOUSE_CHECKPOINT_SYNC_URL} 90 | --ee-endpoint=http://${EL}:8551 91 | --ee-jwt-secret-file=/jwt/jwt.hex 92 | --data-base-path=/opt/teku/data 93 | --builder-endpoint=http://${MEV}:18550 94 | --rest-api-enabled=true 95 | --rest-api-interface=0.0.0.0 96 | --rest-api-port=5052 97 | --rest-api-host-allowlist="*" 98 | --metrics-enabled=true 99 | --metrics-interface=0.0.0.0 100 | --metrics-port=5054 101 | --metrics-host-allowlist="*" 102 | volumes: 103 | - ./data/cl-teku:/opt/teku/data 104 | - ./jwt:/jwt:ro 105 | networks: [dvnode] 106 | 107 | # _ _ _ 108 | # | | ___ __| | ___ ___| |_ __ _ _ __ 109 | # | |/ _ \ / _` |/ _ \/ __| __/ _` | '__| 110 | # | | (_) | (_| | __/\__ \ || (_| | | 111 | # |_|\___/ \__,_|\___||___/\__\__,_|_| 112 | 113 | cl-lodestar: 114 | profiles: [cl-lodestar] 115 | image: chainsafe/lodestar:${VC_VERSION:-v1.38.0} 116 | restart: unless-stopped 117 | labels: 118 | - "promtail-monitored=${CL_LODESTAR_PROMTAIL_MONITORED:-true}" 119 | command: | 120 | beacon 121 | --network=${NETWORK} 122 | --checkpointSyncUrl=${LIGHTHOUSE_CHECKPOINT_SYNC_URL} 123 | --execution.urls=http://${EL}:8551 124 | --jwt-secret=/jwt/jwt.hex 125 | --dataDir=/opt/lodestar/data 126 | --builder 127 | --builder.url=http://${MEV}:18550 128 | --rest 129 | --rest.address=0.0.0.0 130 | --rest.port=5052 131 | --metrics 132 | --metrics.address=0.0.0.0 133 | --metrics.port=5054 134 | volumes: 135 | - ./data/cl-lodestar:/opt/lodestar/data 136 | - ./jwt:/jwt:ro 137 | networks: [dvnode] 138 | -------------------------------------------------------------------------------- /grafana/dashboards/logs_dashboard.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 | "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": 3, 28 | "links": [ 29 | { 30 | "asDropdown": false, 31 | "icon": "external link", 32 | "includeVars": false, 33 | "keepTime": false, 34 | "tags": [], 35 | "targetBlank": false, 36 | "title": "Explore Charon Logs", 37 | "tooltip": "Explore Charon Logs", 38 | "type": "link", 39 | "url": "/explore?orgId=1&left=%7B%22datasource%22:%22loki%22,%22queries%22:%5B%7B%22refId%22:%22A%22,%22expr%22:%22%7Bcompose_service%3D%5C%22charon%5C%22%7D%20%7C%20logfmt%20%7C%20line_format%20%60%7B%7B.level%7D%7D%5Ct%7B%7B.msg%7D%7D%60%22,%22queryType%22:%22range%22,%22editorMode%22:%22builder%22%7D%5D,%22range%22:%7B%22from%22:%22now-1h%22,%22to%22:%22now%22%7D%7D" 40 | } 41 | ], 42 | "liveNow": false, 43 | "panels": [ 44 | { 45 | "datasource": { 46 | "type": "loki", 47 | "uid": "loki" 48 | }, 49 | "description": "Top 10 count of errors and warning per minute grouped by message. ", 50 | "fieldConfig": { 51 | "defaults": { 52 | "color": { 53 | "mode": "palette-classic" 54 | }, 55 | "custom": { 56 | "axisLabel": "", 57 | "axisPlacement": "auto", 58 | "barAlignment": 0, 59 | "drawStyle": "line", 60 | "fillOpacity": 0, 61 | "gradientMode": "none", 62 | "hideFrom": { 63 | "legend": false, 64 | "tooltip": false, 65 | "viz": false 66 | }, 67 | "lineInterpolation": "linear", 68 | "lineWidth": 1, 69 | "pointSize": 5, 70 | "scaleDistribution": { 71 | "type": "linear" 72 | }, 73 | "showPoints": "auto", 74 | "spanNulls": false, 75 | "stacking": { 76 | "group": "A", 77 | "mode": "none" 78 | }, 79 | "thresholdsStyle": { 80 | "mode": "off" 81 | } 82 | }, 83 | "mappings": [], 84 | "min": 0, 85 | "noValue": "No warnings", 86 | "thresholds": { 87 | "mode": "absolute", 88 | "steps": [ 89 | { 90 | "color": "green", 91 | "value": null 92 | }, 93 | { 94 | "color": "red", 95 | "value": 80 96 | } 97 | ] 98 | } 99 | }, 100 | "overrides": [ 101 | { 102 | "__systemRef": "hideSeriesFrom", 103 | "matcher": { 104 | "id": "byNames", 105 | "options": { 106 | "mode": "exclude", 107 | "names": [ 108 | "E [sched] Emit scheduled slot event: eth2wrap: failed to send proposal preparations: POST failed with status 404: 404 page not found\n" 109 | ], 110 | "prefix": "All except:", 111 | "readOnly": true 112 | } 113 | }, 114 | "properties": [ 115 | { 116 | "id": "custom.hideFrom", 117 | "value": { 118 | "legend": false, 119 | "tooltip": false, 120 | "viz": true 121 | } 122 | } 123 | ] 124 | } 125 | ] 126 | }, 127 | "gridPos": { 128 | "h": 6, 129 | "w": 12, 130 | "x": 0, 131 | "y": 0 132 | }, 133 | "id": 2, 134 | "options": { 135 | "legend": { 136 | "calcs": [], 137 | "displayMode": "list", 138 | "placement": "right", 139 | "showLegend": true 140 | }, 141 | "tooltip": { 142 | "mode": "single", 143 | "sort": "none" 144 | } 145 | }, 146 | "targets": [ 147 | { 148 | "datasource": { 149 | "type": "loki", 150 | "uid": "loki" 151 | }, 152 | "editorMode": "code", 153 | "expr": "topk(10,sum(count_over_time({service=\"charon\"} | logfmt | level=~`(warn|error)` | label_format level=\"{{trunc 1 .level | upper}}\"[1m])) by (level,msg,topic))", 154 | "legendFormat": "{{level}} [{{topic}}] {{msg}}", 155 | "queryType": "range", 156 | "refId": "A" 157 | } 158 | ], 159 | "title": "Top Warnings and Errors", 160 | "type": "timeseries" 161 | }, 162 | { 163 | "datasource": { 164 | "type": "loki", 165 | "uid": "loki" 166 | }, 167 | "description": "Reasons why duties failed prefixed by slot and duty type", 168 | "gridPos": { 169 | "h": 6, 170 | "w": 12, 171 | "x": 12, 172 | "y": 0 173 | }, 174 | "id": 4, 175 | "options": { 176 | "dedupStrategy": "none", 177 | "enableLogDetails": true, 178 | "prettifyLogMessage": false, 179 | "showCommonLabels": false, 180 | "showLabels": false, 181 | "showTime": false, 182 | "sortOrder": "Descending", 183 | "wrapLogMessage": false 184 | }, 185 | "targets": [ 186 | { 187 | "datasource": { 188 | "type": "loki", 189 | "uid": "loki" 190 | }, 191 | "expr": "{service=\"charon\"} | logfmt | msg=`Duty failed` | line_format `{{.duty}}\t{{.reason}}`", 192 | "queryType": "range", 193 | "refId": "A" 194 | } 195 | ], 196 | "title": "Duty Failed Reasons", 197 | "type": "logs" 198 | }, 199 | { 200 | "datasource": { 201 | "type": "loki", 202 | "uid": "loki" 203 | }, 204 | "gridPos": { 205 | "h": 14, 206 | "w": 24, 207 | "x": 0, 208 | "y": 6 209 | }, 210 | "id": 6, 211 | "options": { 212 | "dedupStrategy": "none", 213 | "enableLogDetails": true, 214 | "prettifyLogMessage": false, 215 | "showCommonLabels": false, 216 | "showLabels": false, 217 | "showTime": true, 218 | "sortOrder": "Descending", 219 | "wrapLogMessage": false 220 | }, 221 | "targets": [ 222 | { 223 | "datasource": { 224 | "type": "loki", 225 | "uid": "loki" 226 | }, 227 | "expr": "{service=\"charon\"} | logfmt | line_format \"{{upper .level | trunc 4 }} {{.topic}}\t{{.msg}}\t\t{{if .slot}}slot={{.slot}}{{end}}{{if .duty}}duty={{.duty}}{{end}}\"", 228 | "queryType": "range", 229 | "refId": "A" 230 | } 231 | ], 232 | "title": "All Logs", 233 | "type": "logs" 234 | } 235 | ], 236 | "schemaVersion": 37, 237 | "style": "dark", 238 | "tags": [], 239 | "templating": { 240 | "list": [] 241 | }, 242 | "time": { 243 | "from": "now-6h", 244 | "to": "now" 245 | }, 246 | "timepicker": {}, 247 | "timezone": "", 248 | "title": "Charon Log Dashboard", 249 | "uid": "charon_log_dashboard", 250 | "version": 3, 251 | "weekStart": "" 252 | } 253 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | # Override any defaults specified by `${FOO:-bar}` in `.env` with `FOO=qux`. 2 | # ${VARIABLE:-default} evaluates to default if VARIABLE is unset or empty in the environment. 3 | # ${VARIABLE-default} evaluates to default only if VARIABLE is unset in the environment. 4 | 5 | services: 6 | # _ _ _ _ 7 | # _ __ ___| |_| |__ ___ _ __ _ __ ___ (_)_ __ __| | 8 | # | '_ \ / _ \ __| '_ \ / _ \ '__| '_ ` _ \| | '_ \ / _` | 9 | # | | | | __/ |_| | | | __/ | | | | | | | | | | | (_| | 10 | # |_| |_|\___|\__|_| |_|\___|_| |_| |_| |_|_|_| |_|\__,_| 11 | 12 | nethermind: 13 | image: nethermind/nethermind:${NETHERMIND_VERSION:-1.35.2} 14 | profiles: [""] 15 | restart: unless-stopped 16 | ports: 17 | - ${NETHERMIND_PORT_P2P:-30303}:30303/tcp # P2P TCP 18 | - ${NETHERMIND_PORT_P2P:-30303}:30303/udp # P2P UDP 19 | - ${NETHERMIND_IP_HTTP:-127.0.0.1}:${NETHERMIND_PORT_HTTP:-8545}:8545 # JSON-RPC 20 | - ${NETHERMIND_IP_ENGINE:-127.0.0.1}:${NETHERMIND_PORT_ENGINE:-8551}:8551 # ENGINE-API 21 | labels: 22 | - "promtail-monitored=${NETHERMIND_PROMTAIL_MONITORED:-true}" 23 | command: | 24 | --config=${NETWORK} 25 | --datadir=data 26 | --HealthChecks.Enabled=true 27 | --JsonRpc.Enabled=true 28 | --JsonRpc.JwtSecretFile="/root/jwt/jwt.hex" 29 | --JsonRpc.EngineHost=0.0.0.0 30 | --JsonRpc.EnginePort=8551 31 | --JsonRpc.Host=0.0.0.0 32 | --JsonRpc.Port=8545 33 | --Metrics.Enabled=true 34 | --Metrics.ExposePort=8008 35 | --Sync.SnapSync=true 36 | --History.Pruning=Rolling 37 | networks: [dvnode] 38 | volumes: 39 | - ./data/nethermind:/nethermind/data 40 | - ./jwt:/root/jwt 41 | 42 | # _ _ _ _ _ 43 | # | (_) __ _| |__ | |_| |__ ___ _ _ ___ ___ 44 | # | | |/ _` | '_ \| __| '_ \ / _ \| | | / __|/ _ \ 45 | # | | | (_| | | | | |_| | | | (_) | |_| \__ \ __/ 46 | # |_|_|\__, |_| |_|\__|_| |_|\___/ \__,_|___/\___| 47 | # |___/ 48 | 49 | lighthouse: 50 | image: sigp/lighthouse:${LIGHTHOUSE_VERSION:-v8.0.1} 51 | profiles: [""] 52 | ports: 53 | - ${LIGHTHOUSE_PORT_P2P:-9000}:9000/tcp # P2P TCP 54 | - 5054:5054/tcp # P2P TCP 55 | - ${LIGHTHOUSE_PORT_P2P:-9000}:9000/udp # P2P UDP 56 | labels: 57 | - "promtail-monitored=${LIGHTHOUSE_PROMTAIL_MONITORED:-true}" 58 | command: | 59 | lighthouse bn 60 | --network=${NETWORK} 61 | --checkpoint-sync-url=${LIGHTHOUSE_CHECKPOINT_SYNC_URL} 62 | --checkpoint-sync-url-timeout=600 63 | --execution-endpoint=http://nethermind:8551 64 | --execution-jwt=/opt/jwt/jwt.hex 65 | --datadir=/opt/app/beacon/ 66 | --builder=http://mev-boost:18550 67 | --http 68 | --http-address=0.0.0.0 69 | --http-port=5052 70 | --metrics 71 | --metrics-address=0.0.0.0 72 | --metrics-port=5054 73 | --metrics-allow-origin="*" 74 | networks: [dvnode] 75 | volumes: 76 | - ./data/lighthouse:/opt/app/beacon 77 | - ./jwt:/opt/jwt 78 | restart: unless-stopped 79 | 80 | # _ 81 | # ___| |__ __ _ _ __ ___ _ __ 82 | # / __| '_ \ / _` | '__/ _ \| '_ \ 83 | # | (__| | | | (_| | | | (_) | | | | 84 | # \___|_| |_|\__,_|_| \___/|_| |_| 85 | 86 | charon: 87 | image: obolnetwork/charon:${CHARON_VERSION:-v1.8.0} 88 | environment: 89 | - CHARON_BEACON_NODE_ENDPOINTS=${CHARON_BEACON_NODE_ENDPOINTS:-http://${CL:-lighthouse}:5052} 90 | - CHARON_BEACON_NODE_TIMEOUT=${CHARON_BEACON_NODE_TIMEOUT:-3s} 91 | - CHARON_BEACON_NODE_SUBMIT_TIMEOUT=${CHARON_BEACON_NODE_SUBMIT_TIMEOUT:-4s} 92 | - CHARON_FALLBACK_BEACON_NODE_ENDPOINTS=${CHARON_FALLBACK_BEACON_NODE_ENDPOINTS:-} 93 | - CHARON_LOG_LEVEL=${CHARON_LOG_LEVEL:-info} 94 | - CHARON_LOG_FORMAT=${CHARON_LOG_FORMAT:-console} 95 | - CHARON_P2P_RELAYS=${CHARON_P2P_RELAYS:-https://0.relay.obol.tech,https://1.relay.obol.tech/} 96 | - CHARON_P2P_EXTERNAL_HOSTNAME=${CHARON_P2P_EXTERNAL_HOSTNAME:-} # Empty default required to avoid warnings. 97 | - CHARON_P2P_TCP_ADDRESS=0.0.0.0:${CHARON_PORT_P2P_TCP:-3610} 98 | - CHARON_VALIDATOR_API_ADDRESS=0.0.0.0:3600 99 | - CHARON_MONITORING_ADDRESS=0.0.0.0:3620 100 | - CHARON_BUILDER_API=${BUILDER_API_ENABLED:-true} 101 | - CHARON_FEATURE_SET_ENABLE=${CHARON_FEATURE_SET_ENABLE:-} 102 | - CHARON_LOKI_ADDRESSES=${CHARON_LOKI_ADDRESSES:-http://loki:3100/loki/api/v1/push} 103 | - CHARON_LOKI_SERVICE=charon 104 | - CHARON_NICKNAME=${CHARON_NICKNAME:-} 105 | - CHARON_EXECUTION_CLIENT_RPC_ENDPOINT=${CHARON_EXECUTION_CLIENT_RPC_ENDPOINT:-http://nethermind:8545} 106 | ports: 107 | - ${CHARON_PORT_P2P_TCP:-3610}:${CHARON_PORT_P2P_TCP:-3610}/tcp # P2P TCP libp2p 108 | labels: 109 | - "promtail-monitored=${CHARON_PROMTAIL_MONITORED:-true}" 110 | networks: [dvnode] 111 | volumes: 112 | - .charon:/opt/charon/.charon 113 | restart: unless-stopped 114 | healthcheck: 115 | test: wget -qO- http://localhost:3620/readyz 116 | 117 | # _ _ _ 118 | # | | ___ __| | ___ ___| |_ __ _ _ __ 119 | # | |/ _ \ / _` |/ _ \/ __| __/ _` | '__| 120 | # | | (_) | (_| | __/\__ \ || (_| | | 121 | # |_|\___/ \__,_|\___||___/\__\__,_|_| 122 | 123 | lodestar: 124 | image: chainsafe/lodestar:${LODESTAR_VERSION:-v1.37.0} 125 | profiles: [""] 126 | depends_on: [charon] 127 | entrypoint: /opt/lodestar/run.sh 128 | networks: [dvnode] 129 | environment: 130 | BEACON_NODE_ADDRESS: http://charon:3600 131 | NETWORK: ${NETWORK} 132 | BUILDER_API_ENABLED: ${BUILDER_API_ENABLED:-true} 133 | BUILDER_SELECTION: ${BUILDER_SELECTION:-builderalways} 134 | labels: 135 | - "promtail-monitored=${LODESTAR_PROMTAIL_MONITORED:-true}" 136 | volumes: 137 | - ./lodestar/run.sh:/opt/lodestar/run.sh 138 | - .charon/validator_keys:/home/charon/validator_keys 139 | - ./data/lodestar:/opt/data 140 | restart: unless-stopped 141 | 142 | # _ _ 143 | # _ __ ___ _____ __ | |__ ___ ___ ___| |_ 144 | # | '_ ` _ \ / _ \ \ / /____| '_ \ / _ \ / _ \/ __| __| 145 | # | | | | | | __/\ V /_____| |_) | (_) | (_) \__ \ |_ 146 | # |_| |_| |_|\___| \_/ |_.__/ \___/ \___/|___/\__| 147 | 148 | mev-boost: 149 | image: ${MEVBOOST_IMAGE:-flashbots/mev-boost}:${MEVBOOST_VERSION:-1.10.1} 150 | profiles: [""] 151 | command: | 152 | -${NETWORK} 153 | -loglevel=debug 154 | -addr=0.0.0.0:18550 155 | -relay-check 156 | -relays=${MEVBOOST_RELAYS} 157 | labels: 158 | - "promtail-monitored=${MEV_BOOST_PROMTAIL_MONITORED:-true}" 159 | networks: [dvnode] 160 | restart: unless-stopped 161 | 162 | # _ _ _ 163 | # _ __ ___ ___ _ __ (_) |_ ___ _ __(_)_ __ __ _ 164 | # | '_ ` _ \ / _ \| '_ \| | __/ _ \| '__| | '_ \ / _` | 165 | # | | | | | | (_) | | | | | || (_) | | | | | | | (_| | 166 | # |_| |_| |_|\___/|_| |_|_|\__\___/|_| |_|_| |_|\__, | 167 | # |___/ 168 | 169 | prometheus: 170 | image: prom/prometheus:${PROMETHEUS_VERSION:-v3.7.3} 171 | user: ":" 172 | networks: [dvnode] 173 | environment: 174 | PROM_REMOTE_WRITE_TOKEN: ${PROM_REMOTE_WRITE_TOKEN} 175 | SERVICE_OWNER: ${SERVICE_OWNER:-"obol-cdvn"} 176 | volumes: 177 | - ./prometheus:/etc/prometheus 178 | - ./data/prometheus:/prometheus 179 | entrypoint: /etc/prometheus/run.sh 180 | restart: unless-stopped 181 | 182 | grafana: 183 | image: grafana/grafana:${GRAFANA_VERSION:-12.2.1} 184 | user: ":" 185 | ports: 186 | - ${MONITORING_IP_GRAFANA:-0.0.0.0}:${MONITORING_PORT_GRAFANA:-3000}:3000 187 | networks: [dvnode] 188 | volumes: 189 | - ./grafana/datasource.yml:/etc/grafana/provisioning/datasources/datasource.yml 190 | - ./grafana/dashboards.yml:/etc/grafana/provisioning/dashboards/datasource.yml 191 | - ./grafana/grafana.ini:/etc/grafana/grafana.ini:ro 192 | - ./grafana/dashboards:/etc/dashboards 193 | - ./data/grafana:/var/lib/grafana 194 | restart: unless-stopped 195 | 196 | networks: 197 | dvnode: 198 | -------------------------------------------------------------------------------- /.env.sample.hoodi: -------------------------------------------------------------------------------- 1 | # This is a sample environment file that allows overriding default configuration defined 2 | # in docker-compose.yml. Rename this file to `.env` and then uncomment and set any variable below. 3 | 4 | # Overrides network for all the relevant services. 5 | NETWORK=hoodi 6 | 7 | # Execution layer client to be used in a DV setup. Uncomment only the desired client. 8 | EL=el-nethermind 9 | #EL=el-reth 10 | #EL=el-none 11 | 12 | # Consensus layer client to be used in a DV setup. Uncomment only the desired client. 13 | CL=cl-lighthouse 14 | #CL=cl-grandine 15 | #CL=cl-teku 16 | #CL=cl-lodestar 17 | #CL=cl-none 18 | 19 | # Validator client to be used in a DV setup. Uncomment only the desired client. 20 | VC=vc-lodestar 21 | #VC=vc-nimbus 22 | #VC=vc-prysm 23 | #VC=vc-teku 24 | 25 | # MEV client to be used in a DV setup. Uncomment only the desired client. 26 | MEV=mev-mevboost 27 | #MEV=mev-commitboost 28 | #MEV=mev-none 29 | 30 | # Do not edit. These profiles and files dictate Docker which client types and from where to start for execution, consensus, validator and MEV. 31 | # The actual adjustable values are specified above 32 | COMPOSE_PROFILES=${EL},${CL},${VC},${MEV} 33 | COMPOSE_FILE=compose-el.yml:compose-cl.yml:compose-vc.yml:compose-mev.yml:docker-compose.yml 34 | 35 | # Enables Builder API. 36 | BUILDER_API_ENABLED=true 37 | 38 | ######### Execution Layer Config ######### 39 | 40 | # EL host exposed IPs and ports. 41 | #EL_PORT_P2P= 42 | #EL_IP_HTTP= 43 | #EL_PORT_HTTP= 44 | #EL_IP_ENGINE= 45 | #EL_PORT_ENGINE= 46 | 47 | # Nethermind docker container image version. 48 | # See available tags https://hub.docker.com/r/nethermind/nethermind/tags 49 | #NETHERMIND_VERSION= 50 | 51 | # Reth docker container image version. 52 | # See available tags https://github.com/paradigmxyz/reth/pkgs/container/reth 53 | #RETH_VERSION= 54 | 55 | ######### Consensus Layer Config ######### 56 | 57 | # CL beacon node host exposed ports. 58 | #CL_PORT_P2P= 59 | 60 | # Lighthouse becon node checkpoint sync URL used by consensus layer to fast sync. 61 | LIGHTHOUSE_CHECKPOINT_SYNC_URL=https://checkpoint-sync.hoodi.ethpandaops.io/ 62 | 63 | # Lighthouse beacon node docker container image version. 64 | # See available tags https://hub.docker.com/r/sigp/lighthouse/tags. 65 | #CL_LIGHTHOUSE_VERSION= 66 | 67 | # Grandine beacon node docker container image version. 68 | # See available tags https://hub.docker.com/r/sifrai/grandine/tags. 69 | #CL_GRANDINE_VERSION= 70 | 71 | # Teku beacon node docker container image version. 72 | # See available tags https://hub.docker.com/r/consensys/teku/tags 73 | #CL_TEKU_VERSION= 74 | 75 | # Lodestar beacon node docker container image version. 76 | # See available tags https://hub.docker.com/r/chainsafe/lodestar/tags 77 | #CL_LODESTAR_VERSION= 78 | 79 | ######### Validator Client Config ######### 80 | 81 | # Override prometheus metrics port for validator client. 82 | #VC_PORT_METRICS= 83 | 84 | # Lodestar validator client docker container image version. 85 | # See available tags https://hub.docker.com/r/chainsafe/lodestar/tags 86 | #VC_LODESTAR_VERSION= 87 | 88 | #VC_LODESTAR_BUILDER_SELECTION= 89 | 90 | # Nimbus validator client docker container image version. 91 | # See available tags https://hub.docker.com/r/statusim/nimbus-validator-client/tags 92 | #VC_NIMBUS_VERSION= 93 | 94 | # Prysm validator client docker container image version. 95 | # See available tags https://hub.docker.com/r/offchainlabs/prysm-validator/tags 96 | #VC_PRYSM_VERSION= 97 | 98 | # Teku validator client docker container image version. 99 | # See available tags https://hub.docker.com/r/consensys/teku/tags 100 | #VC_TEKU_VERSION= 101 | 102 | ######### MEV Config ######### 103 | 104 | # MEV timeouts. 105 | # N.B.: Commit-boost uses TOML configuration instead of env variables. Configure those at commit-boost/. 106 | #MEV_TIMEOUT_GETHEADER= 107 | #MEV_TIMEOUT_GETPAYLOAD= 108 | #MEV_TIMEOUT_REGVAL= 109 | 110 | # Comma separated list of MEV relays. You can choose public relays from https://enchanted-direction-844.notion.site/6d369eb33f664487800b0dedfe32171e?v=d255247c822c409f99c498aeb6a4e51d. 111 | # N.B.: Commit-boost uses TOML configuration instead of env variables. Configure those at commit-boost/. 112 | MEV_RELAYS=https://0x98f0ef62f00780cf8eb06701a7d22725b9437d4768bb19b363e882ae87129945ec206ec2dc16933f31d983f8225772b6@hoodi.aestus.live 113 | 114 | # MEV-Boost docker container image version. 115 | #MEV_MEVBOOST_VERSION= 116 | 117 | # Commit-Boost docker container image version. 118 | #MEV_COMMITBOOST_VERSION= 119 | 120 | ######### Charon Config ######### 121 | 122 | # Charon docker container image version. 123 | # See available tags https://hub.docker.com/r/obolnetwork/charon/tags. 124 | #CHARON_VERSION= 125 | 126 | # Define custom relays. One or more ENRs or an http URL that return an ENR. Use a comma separated list excluding spaces. 127 | #CHARON_P2P_RELAYS= 128 | 129 | # Connect to one or more external beacon nodes. Use a comma separated list excluding spaces. 130 | #CHARON_BEACON_NODE_ENDPOINTS= 131 | 132 | # Supply optional HTTP headers during beacon node requests. These headers are sent to all primary and fallback endpoints, be sure to rely on trusted BNs only. 133 | #CHARON_BEACON_NODE_HEADERS= 134 | 135 | # Specify one or more fallback beacon node endpoints, which are called in the case that the primary beacon nodes are offline or unhealthy. 136 | # Use fallback beacon nodes sparingly, particularly if latency is high, which can impact DV cluster performance. 137 | #CHARON_FALLBACK_BEACON_NODE_ENDPOINTS= 138 | 139 | # Increase the duration charon will wait for requests to the beacon node. 140 | #CHARON_BEACON_NODE_TIMEOUT= 141 | 142 | # Increase the duration charon will wait while publishing data to the beacon node. 143 | #CHARON_BEACON_NODE_SUBMIT_TIMEOUT= 144 | 145 | # The address of the execution engine JSON-RPC API. 146 | #CHARON_EXECUTION_CLIENT_RPC_ENDPOINT= 147 | 148 | # Override the charon logging level; debug, info, warning, error. 149 | #CHARON_LOG_LEVEL= 150 | 151 | # Override the charon logging format; console, logfmt, json. Grafana panels require logfmt. 152 | #CHARON_LOG_FORMAT= 153 | 154 | # Advertise a custom external DNS hostname or IP address for libp2p peer discovery. 155 | #CHARON_P2P_EXTERNAL_HOSTNAME= 156 | 157 | # Loki log aggregation server addresses. Disable loki log aggregation by setting an empty address. 158 | #CHARON_LOKI_ADDRESSES= 159 | 160 | # Charon Cluster Name. Mandatory to send logs with Promtail. 161 | #CLUSTER_NAME= 162 | 163 | # Charon Cluster Peer. Mandatory to send logs with Promtail. 164 | #CLUSTER_PEER= 165 | 166 | # Nickname to identify this charon node on monitoring (max 32 characters). 167 | #CHARON_NICKNAME= 168 | 169 | # Docker network of running charon node. See `docker network ls`. 170 | #CHARON_DOCKER_NETWORK= 171 | 172 | # Charon host exposed ports. 173 | #CHARON_PORT_P2P_TCP= 174 | 175 | ######### Monitoring Config ######### 176 | 177 | # Grafana docker container image version. 178 | # See available tags https://github.com/grafana/grafana/releases. 179 | #GRAFANA_VERSION= 180 | 181 | # Grafana host exposed IP and port. 182 | #MONITORING_IP_GRAFANA= 183 | #MONITORING_PORT_GRAFANA= 184 | 185 | # Prometheus docker container image version. 186 | # See available tags https://github.com/prometheus/prometheus/releases. 187 | #PROMETHEUS_VERSION= 188 | 189 | # Prometheus remote write token used for accessing external prometheus. 190 | #PROM_REMOTE_WRITE_TOKEN= 191 | 192 | # Prometheus service owner used to uniquely identify user from which metrics are pushed. 193 | #SERVICE_OWNER=charon_user 194 | 195 | # Uncomment these if you have log exporting with Promtail 196 | # and want to disable log export on a particular container. 197 | #EL_NETHERMIND_PROMTAIL_MONITORED=false 198 | #EL_RETH_PROMTAIL_MONITORED=false 199 | #CL_LIGHTHOUSE_PROMTAIL_MONITORED=false 200 | #CL_GRANDINE_PROMTAIL_MONITORED=false 201 | #CL_TEKU_PROMTAIL_MONITORED=false 202 | #CL_LODESTAR_PROMTAIL_MONITORED=false 203 | #CHARON_PROMTAIL_MONITORED=false 204 | #VC_LODESTAR_PROMTAIL_MONITORED=false 205 | #VC_NIMBUS_PROMTAIL_MONITORED=false 206 | #VC_PRYSM_PROMTAIL_MONITORED=false 207 | #VC_TEKU_PROMTAIL_MONITORED=false 208 | #MEV_MEV_BOOST_PROMTAIL_MONITORED=false 209 | #MEV_COMMIT_BOOST_PROMTAIL_MONITORED=false 210 | #EJECTOR_PROMTAIL_MONITORED=false 211 | #DV_EXIT_PROMTAIL_MONITORED=false 212 | 213 | ######### Debug Config ######### 214 | 215 | # This applies to compose-debug.yml only. 216 | 217 | # Prometheus Node exporter docker container image version. 218 | # See available tags https://hub.docker.com/r/bitnamilegacy/node-exporter/tags. 219 | #NODE_EXPORTER_VERSION= 220 | 221 | # Grafana Tempo docker container image version. 222 | # Use Grafana Explore to access Tempo data. 223 | # See available tags https://hub.docker.com/r/grafana/tempo/tags. 224 | #TEMPO_VERSION= 225 | 226 | # Grafana Loki docker container image version. 227 | # See available tags https://hub.docker.com/r/grafana/loki/tags. 228 | #LOKI_VERSION= 229 | 230 | # Loki host exposed port. 231 | #MONITORING_PORT_LOKI= 232 | -------------------------------------------------------------------------------- /.env.sample.holesky: -------------------------------------------------------------------------------- 1 | # This is a sample environment file that allows overriding default configuration defined 2 | # in docker-compose.yml. Rename this file to `.env` and then uncomment and set any variable below. 3 | 4 | # Overrides network for all the relevant services. 5 | NETWORK=holesky 6 | 7 | # Execution layer client to be used in a DV setup. Uncomment only the desired client. 8 | EL=el-nethermind 9 | #EL=el-reth 10 | #EL=el-none 11 | 12 | # Consensus layer client to be used in a DV setup. Uncomment only the desired client. 13 | CL=cl-lighthouse 14 | #CL=cl-grandine 15 | #CL=cl-teku 16 | #CL=cl-lodestar 17 | #CL=cl-none 18 | 19 | # Validator client to be used in a DV setup. Uncomment only the desired client. 20 | VC=vc-lodestar 21 | #VC=vc-nimbus 22 | #VC=vc-prysm 23 | #VC=vc-teku 24 | 25 | # MEV client to be used in a DV setup. Uncomment only the desired client. 26 | MEV=mev-mevboost 27 | #MEV=mev-commitboost 28 | #MEV=mev-none 29 | 30 | # Do not edit. These profiles and files dictate Docker which client types and from where to start for execution, consensus, validator and MEV. 31 | # The actual adjustable values are specified above 32 | COMPOSE_PROFILES=${EL},${CL},${VC},${MEV} 33 | COMPOSE_FILE=compose-el.yml:compose-cl.yml:compose-vc.yml:compose-mev.yml:docker-compose.yml 34 | 35 | # Enables Builder API. 36 | BUILDER_API_ENABLED=true 37 | 38 | ######### Execution Layer Config ######### 39 | 40 | # EL host exposed IPs and ports. 41 | #EL_PORT_P2P= 42 | #EL_IP_HTTP= 43 | #EL_PORT_HTTP= 44 | #EL_IP_ENGINE= 45 | #EL_PORT_ENGINE= 46 | 47 | # Nethermind docker container image version. 48 | # See available tags https://hub.docker.com/r/nethermind/nethermind/tags 49 | #NETHERMIND_VERSION= 50 | 51 | # Reth docker container image version. 52 | # See available tags https://github.com/paradigmxyz/reth/pkgs/container/reth 53 | #RETH_VERSION= 54 | 55 | ######### Consensus Layer Config ######### 56 | 57 | # CL beacon node host exposed ports. 58 | #CL_PORT_P2P= 59 | 60 | # Lighthouse becon node checkpoint sync URL used by consensus layer to fast sync. 61 | LIGHTHOUSE_CHECKPOINT_SYNC_URL=https://checkpoint-sync.holesky.ethpandaops.io/ 62 | 63 | # Lighthouse beacon node docker container image version. 64 | # See available tags https://hub.docker.com/r/sigp/lighthouse/tags. 65 | #CL_LIGHTHOUSE_VERSION= 66 | 67 | # Grandine beacon node docker container image version. 68 | # See available tags https://hub.docker.com/r/sifrai/grandine/tags. 69 | #CL_GRANDINE_VERSION= 70 | 71 | # Teku beacon node docker container image version. 72 | # See available tags https://hub.docker.com/r/consensys/teku/tags 73 | #CL_TEKU_VERSION= 74 | 75 | # Lodestar beacon node docker container image version. 76 | # See available tags https://hub.docker.com/r/chainsafe/lodestar/tags 77 | #CL_LODESTAR_VERSION= 78 | 79 | ######### Validator Client Config ######### 80 | 81 | # Override prometheus metrics port for validator client. 82 | #VC_PORT_METRICS= 83 | 84 | # Lodestar validator client docker container image version. 85 | # See available tags https://hub.docker.com/r/chainsafe/lodestar/tags 86 | #VC_LODESTAR_VERSION= 87 | 88 | #VC_LODESTAR_BUILDER_SELECTION= 89 | 90 | # Nimbus validator client docker container image version. 91 | # See available tags https://hub.docker.com/r/statusim/nimbus-validator-client/tags 92 | #VC_NIMBUS_VERSION= 93 | 94 | # Prysm validator client docker container image version. 95 | # See available tags https://hub.docker.com/r/offchainlabs/prysm-validator/tags 96 | #VC_PRYSM_VERSION= 97 | 98 | # Teku validator client docker container image version. 99 | # See available tags https://hub.docker.com/r/consensys/teku/tags 100 | #VC_TEKU_VERSION= 101 | 102 | ######### MEV Config ######### 103 | 104 | # MEV timeouts. 105 | # N.B.: Commit-boost uses TOML configuration instead of env variables. Configure those at commit-boost/. 106 | #MEV_TIMEOUT_GETHEADER= 107 | #MEV_TIMEOUT_GETPAYLOAD= 108 | #MEV_TIMEOUT_REGVAL= 109 | 110 | # Comma separated list of MEV relays. You can choose public relays from https://enchanted-direction-844.notion.site/6d369eb33f664487800b0dedfe32171e?v=d255247c822c409f99c498aeb6a4e51d. 111 | # N.B.: Commit-boost uses TOML configuration instead of env variables. Configure those at commit-boost/. 112 | MEV_RELAYS=https://0xab78bf8c781c58078c3beb5710c57940874dd96aef2835e7742c866b4c7c0406754376c2c8285a36c630346aa5c5f833@holesky.aestus.live,https://0xb1559beef7b5ba3127485bbbb090362d9f497ba64e177ee2c8e7db74746306efad687f2cf8574e38d70067d40ef136dc@relay-stag.ultrasound.money,https://0xaa58208899c6105603b74396734a6263cc7d947f444f396a90f7b7d3e65d102aec7e5e5291b27e08d02c50a050825c2f@holesky.titanrelay.xyz 113 | 114 | # MEV-Boost docker container image version. 115 | #MEV_MEVBOOST_VERSION= 116 | 117 | # Commit-Boost docker container image version. 118 | #MEV_COMMITBOOST_VERSION= 119 | 120 | ######### Charon Config ######### 121 | 122 | # Charon docker container image version. 123 | # See available tags https://hub.docker.com/r/obolnetwork/charon/tags. 124 | #CHARON_VERSION= 125 | 126 | # Define custom relays. One or more ENRs or an http URL that return an ENR. Use a comma separated list excluding spaces. 127 | #CHARON_P2P_RELAYS= 128 | 129 | # Connect to one or more external beacon nodes. Use a comma separated list excluding spaces. 130 | #CHARON_BEACON_NODE_ENDPOINTS= 131 | 132 | # Supply optional HTTP headers during beacon node requests. These headers are sent to all primary and fallback endpoints, be sure to rely on trusted BNs only. 133 | #CHARON_BEACON_NODE_HEADERS= 134 | 135 | # Specify one or more fallback beacon node endpoints, which are called in the case that the primary beacon nodes are offline or unhealthy. 136 | # Use fallback beacon nodes sparingly, particularly if latency is high, which can impact DV cluster performance. 137 | #CHARON_FALLBACK_BEACON_NODE_ENDPOINTS= 138 | 139 | # Increase the duration charon will wait for requests to the beacon node. 140 | #CHARON_BEACON_NODE_TIMEOUT= 141 | 142 | # Increase the duration charon will wait while publishing data to the beacon node. 143 | #CHARON_BEACON_NODE_SUBMIT_TIMEOUT= 144 | 145 | # The address of the execution engine JSON-RPC API. 146 | #CHARON_EXECUTION_CLIENT_RPC_ENDPOINT= 147 | 148 | # Override the charon logging level; debug, info, warning, error. 149 | #CHARON_LOG_LEVEL= 150 | 151 | # Override the charon logging format; console, logfmt, json. Grafana panels require logfmt. 152 | #CHARON_LOG_FORMAT= 153 | 154 | # Advertise a custom external DNS hostname or IP address for libp2p peer discovery. 155 | #CHARON_P2P_EXTERNAL_HOSTNAME= 156 | 157 | # Loki log aggregation server addresses. Disable loki log aggregation by setting an empty address. 158 | #CHARON_LOKI_ADDRESSES= 159 | 160 | # Charon Cluster Name. Mandatory to send logs with Promtail. 161 | #CLUSTER_NAME= 162 | 163 | # Charon Cluster Peer. Mandatory to send logs with Promtail. 164 | #CLUSTER_PEER= 165 | 166 | # Nickname to identify this charon node on monitoring (max 32 characters). 167 | #CHARON_NICKNAME= 168 | 169 | # Docker network of running charon node. See `docker network ls`. 170 | #CHARON_DOCKER_NETWORK= 171 | 172 | # Charon host exposed ports. 173 | #CHARON_PORT_P2P_TCP= 174 | 175 | ######### Monitoring Config ######### 176 | 177 | # Grafana docker container image version. 178 | # See available tags https://github.com/grafana/grafana/releases. 179 | #GRAFANA_VERSION= 180 | 181 | # Grafana host exposed IP and port. 182 | #MONITORING_IP_GRAFANA= 183 | #MONITORING_PORT_GRAFANA= 184 | 185 | # Prometheus docker container image version. 186 | # See available tags https://github.com/prometheus/prometheus/releases. 187 | #PROMETHEUS_VERSION= 188 | 189 | # Prometheus remote write token used for accessing external prometheus. 190 | #PROM_REMOTE_WRITE_TOKEN= 191 | 192 | # Prometheus service owner used to uniquely identify user from which metrics are pushed. 193 | #SERVICE_OWNER=charon_user 194 | 195 | # Uncomment these if you have log exporting with Promtail 196 | # and want to disable log export on a particular container. 197 | #EL_NETHERMIND_PROMTAIL_MONITORED=false 198 | #EL_RETH_PROMTAIL_MONITORED=false 199 | #CL_LIGHTHOUSE_PROMTAIL_MONITORED=false 200 | #CL_GRANDINE_PROMTAIL_MONITORED=false 201 | #CL_TEKU_PROMTAIL_MONITORED=false 202 | #CL_LODESTAR_PROMTAIL_MONITORED=false 203 | #CHARON_PROMTAIL_MONITORED=false 204 | #VC_LODESTAR_PROMTAIL_MONITORED=false 205 | #VC_NIMBUS_PROMTAIL_MONITORED=false 206 | #VC_PRYSM_PROMTAIL_MONITORED=false 207 | #VC_TEKU_PROMTAIL_MONITORED=false 208 | #MEV_MEV_BOOST_PROMTAIL_MONITORED=false 209 | #MEV_COMMIT_BOOST_PROMTAIL_MONITORED=false 210 | #EJECTOR_PROMTAIL_MONITORED=false 211 | #DV_EXIT_PROMTAIL_MONITORED=false 212 | 213 | ######### Debug Config ######### 214 | 215 | # This applies to compose-debug.yml only. 216 | 217 | # Prometheus Node exporter docker container image version. 218 | # See available tags https://hub.docker.com/r/bitnamilegacy/node-exporter/tags. 219 | #NODE_EXPORTER_VERSION= 220 | 221 | # Grafana Tempo docker container image version. 222 | # Use Grafana Explore to access Tempo data. 223 | # See available tags https://hub.docker.com/r/grafana/tempo/tags. 224 | #TEMPO_VERSION= 225 | 226 | # Grafana Loki docker container image version. 227 | # See available tags https://hub.docker.com/r/grafana/loki/tags. 228 | #LOKI_VERSION= 229 | 230 | # Loki host exposed port. 231 | #MONITORING_PORT_LOKI= 232 | -------------------------------------------------------------------------------- /.env.sample.mainnet: -------------------------------------------------------------------------------- 1 | # This is a sample environment file that allows overriding default configuration defined 2 | # in docker-compose.yml. Rename this file to `.env` and then uncomment and set any variable below. 3 | 4 | # Overrides network for all the relevant services. 5 | NETWORK=mainnet 6 | 7 | # Execution layer client to be used in a DV setup. Uncomment only the desired client. 8 | EL=el-nethermind 9 | #EL=el-reth 10 | #EL=el-none 11 | 12 | # Consensus layer client to be used in a DV setup. Uncomment only the desired client. 13 | CL=cl-lighthouse 14 | #CL=cl-grandine 15 | #CL=cl-teku 16 | #CL=cl-lodestar 17 | #CL=cl-none 18 | 19 | # Validator client to be used in a DV setup. Uncomment only the desired client. 20 | VC=vc-lodestar 21 | #VC=vc-nimbus 22 | #VC=vc-prysm 23 | #VC=vc-teku 24 | 25 | # MEV client to be used in a DV setup. Uncomment only the desired client. 26 | MEV=mev-mevboost 27 | #MEV=mev-commitboost 28 | #MEV=mev-none 29 | 30 | # Do not edit. These profiles and files dictate Docker which client types and from where to start for execution, consensus, validator and MEV. 31 | # The actual adjustable values are specified above 32 | COMPOSE_PROFILES=${EL},${CL},${VC},${MEV} 33 | COMPOSE_FILE=compose-el.yml:compose-cl.yml:compose-vc.yml:compose-mev.yml:docker-compose.yml 34 | 35 | # Enables Builder API. 36 | BUILDER_API_ENABLED=true 37 | 38 | ######### Execution Layer Config ######### 39 | 40 | # EL host exposed IPs and ports. 41 | #EL_PORT_P2P= 42 | #EL_IP_HTTP= 43 | #EL_PORT_HTTP= 44 | #EL_IP_ENGINE= 45 | #EL_PORT_ENGINE= 46 | 47 | # Nethermind docker container image version. 48 | # See available tags https://hub.docker.com/r/nethermind/nethermind/tags 49 | #NETHERMIND_VERSION= 50 | 51 | # Reth docker container image version. 52 | # See available tags https://github.com/paradigmxyz/reth/pkgs/container/reth 53 | #RETH_VERSION= 54 | 55 | ######### Consensus Layer Config ######### 56 | 57 | # CL beacon node host exposed ports. 58 | #CL_PORT_P2P= 59 | 60 | # Lighthouse becon node checkpoint sync URL used by consensus layer to fast sync. 61 | LIGHTHOUSE_CHECKPOINT_SYNC_URL=https://mainnet.checkpoint.sigp.io/ 62 | 63 | # Lighthouse beacon node docker container image version. 64 | # See available tags https://hub.docker.com/r/sigp/lighthouse/tags. 65 | #CL_LIGHTHOUSE_VERSION= 66 | 67 | # Grandine beacon node docker container image version. 68 | # See available tags https://hub.docker.com/r/sifrai/grandine/tags. 69 | #CL_GRANDINE_VERSION= 70 | 71 | # Teku beacon node docker container image version. 72 | # See available tags https://hub.docker.com/r/consensys/teku/tags 73 | #CL_TEKU_VERSION= 74 | 75 | # Lodestar beacon node docker container image version. 76 | # See available tags https://hub.docker.com/r/chainsafe/lodestar/tags 77 | #CL_LODESTAR_VERSION= 78 | 79 | ######### Validator Client Config ######### 80 | 81 | # Override prometheus metrics port for validator client. 82 | #VC_PORT_METRICS= 83 | 84 | # Lodestar validator client docker container image version. 85 | # See available tags https://hub.docker.com/r/chainsafe/lodestar/tags 86 | #VC_LODESTAR_VERSION= 87 | 88 | #VC_LODESTAR_BUILDER_SELECTION= 89 | 90 | # Nimbus validator client docker container image version. 91 | # See available tags https://hub.docker.com/r/statusim/nimbus-validator-client/tags 92 | #VC_NIMBUS_VERSION= 93 | 94 | # Prysm validator client docker container image version. 95 | # See available tags https://hub.docker.com/r/offchainlabs/prysm-validator/tags 96 | #VC_PRYSM_VERSION= 97 | 98 | # Teku validator client docker container image version. 99 | # See available tags https://hub.docker.com/r/consensys/teku/tags 100 | #VC_TEKU_VERSION= 101 | 102 | ######### MEV Config ######### 103 | 104 | # MEV timeouts. 105 | # N.B.: Commit-boost uses TOML configuration instead of env variables. Configure those at commit-boost/. 106 | #MEV_TIMEOUT_GETHEADER= 107 | #MEV_TIMEOUT_GETPAYLOAD= 108 | #MEV_TIMEOUT_REGVAL= 109 | 110 | # Comma separated list of MEV relays. You can choose public relays from https://enchanted-direction-844.notion.site/6d369eb33f664487800b0dedfe32171e?v=d255247c822c409f99c498aeb6a4e51d. 111 | # N.B.: Commit-boost uses TOML configuration instead of env variables. Configure those at commit-boost/. 112 | MEV_RELAYS=https://0xa15b52576bcbf1072f4a011c0f99f9fb6c66f3e1ff321f11f461d15e31b1cb359caa092c71bbded0bae5b5ea401aab7e@aestus.live,https://0xa7ab7a996c8584251c8f925da3170bdfd6ebc75d50f5ddc4050a6fdc77f2a3b5fce2cc750d0865e05d7228af97d69561@agnostic-relay.net,https://0x8b5d2e73e2a3a55c6c87b8b6eb92e0149a125c852751db1422fa951e42a09b82c142c3ea98d0d9930b056a3bc9896b8f@bloxroute.max-profit.blxrbdn.com,https://0xb0b07cd0abef743db4260b0ed50619cf6ad4d82064cb4fbec9d3ec530f7c5e6793d9f286c4e082c0244ffb9f2658fe88@bloxroute.regulated.blxrbdn.com,https://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@boost-relay.flashbots.net,https://0xa1559ace749633b997cb3fdacffb890aeebdb0f5a3b6aaa7eeeaf1a38af0a8fe88b9e4b1f61f236d2e64d95733327a62@relay.ultrasound.money,https://0x8c4ed5e24fe5c6ae21018437bde147693f68cda427cd1122cf20819c30eda7ed74f72dece09bb313f2a1855595ab677d@global.titanrelay.xyz 113 | 114 | # MEV-Boost docker container image version. 115 | #MEV_MEVBOOST_VERSION= 116 | 117 | # Commit-Boost docker container image version. 118 | #MEV_COMMITBOOST_VERSION= 119 | 120 | ######### Charon Config ######### 121 | 122 | # Charon docker container image version. 123 | # See available tags https://hub.docker.com/r/obolnetwork/charon/tags. 124 | #CHARON_VERSION= 125 | 126 | # Define custom relays. One or more ENRs or an http URL that return an ENR. Use a comma separated list excluding spaces. 127 | #CHARON_P2P_RELAYS= 128 | 129 | # Connect to one or more external beacon nodes. Use a comma separated list excluding spaces. 130 | #CHARON_BEACON_NODE_ENDPOINTS= 131 | 132 | # Supply optional HTTP headers during beacon node requests. These headers are sent to all primary and fallback endpoints, be sure to rely on trusted BNs only. 133 | #CHARON_BEACON_NODE_HEADERS= 134 | 135 | # Specify one or more fallback beacon node endpoints, which are called in the case that the primary beacon nodes are offline or unhealthy. 136 | # Use fallback beacon nodes sparingly, particularly if latency is high, which can impact DV cluster performance. 137 | #CHARON_FALLBACK_BEACON_NODE_ENDPOINTS= 138 | 139 | # Increase the duration charon will wait for requests to the beacon node. 140 | #CHARON_BEACON_NODE_TIMEOUT= 141 | 142 | # Increase the duration charon will wait while publishing data to the beacon node. 143 | #CHARON_BEACON_NODE_SUBMIT_TIMEOUT= 144 | 145 | # The address of the execution engine JSON-RPC API. 146 | #CHARON_EXECUTION_CLIENT_RPC_ENDPOINT= 147 | 148 | # Override the charon logging level; debug, info, warning, error. 149 | #CHARON_LOG_LEVEL= 150 | 151 | # Override the charon logging format; console, logfmt, json. Grafana panels require logfmt. 152 | #CHARON_LOG_FORMAT= 153 | 154 | # Advertise a custom external DNS hostname or IP address for libp2p peer discovery. 155 | #CHARON_P2P_EXTERNAL_HOSTNAME= 156 | 157 | # Loki log aggregation server addresses. Disable loki log aggregation by setting an empty address. 158 | #CHARON_LOKI_ADDRESSES= 159 | 160 | # Charon Cluster Name. Mandatory to send logs with Promtail. 161 | #CLUSTER_NAME= 162 | 163 | # Charon Cluster Peer. Mandatory to send logs with Promtail. 164 | #CLUSTER_PEER= 165 | 166 | # Nickname to identify this charon node on monitoring (max 32 characters). 167 | #CHARON_NICKNAME= 168 | 169 | # Docker network of running charon node. See `docker network ls`. 170 | #CHARON_DOCKER_NETWORK= 171 | 172 | # Charon host exposed ports. 173 | #CHARON_PORT_P2P_TCP= 174 | 175 | ######### Monitoring Config ######### 176 | 177 | # Grafana docker container image version. 178 | # See available tags https://github.com/grafana/grafana/releases. 179 | #GRAFANA_VERSION= 180 | 181 | # Grafana host exposed IP and port. 182 | #MONITORING_IP_GRAFANA= 183 | #MONITORING_PORT_GRAFANA= 184 | 185 | # Prometheus docker container image version. 186 | # See available tags https://github.com/prometheus/prometheus/releases. 187 | #PROMETHEUS_VERSION= 188 | 189 | # Prometheus remote write token used for accessing external prometheus. 190 | #PROM_REMOTE_WRITE_TOKEN= 191 | 192 | # Prometheus service owner used to uniquely identify user from which metrics are pushed. 193 | #SERVICE_OWNER=charon_user 194 | 195 | # Uncomment these if you have log exporting with Promtail 196 | # and want to disable log export on a particular container. 197 | #EL_NETHERMIND_PROMTAIL_MONITORED=false 198 | #EL_RETH_PROMTAIL_MONITORED=false 199 | #CL_LIGHTHOUSE_PROMTAIL_MONITORED=false 200 | #CL_GRANDINE_PROMTAIL_MONITORED=false 201 | #CL_TEKU_PROMTAIL_MONITORED=false 202 | #CL_LODESTAR_PROMTAIL_MONITORED=false 203 | #CHARON_PROMTAIL_MONITORED=false 204 | #VC_LODESTAR_PROMTAIL_MONITORED=false 205 | #VC_NIMBUS_PROMTAIL_MONITORED=false 206 | #VC_PRYSM_PROMTAIL_MONITORED=false 207 | #VC_TEKU_PROMTAIL_MONITORED=false 208 | #MEV_MEV_BOOST_PROMTAIL_MONITORED=false 209 | #MEV_COMMIT_BOOST_PROMTAIL_MONITORED=false 210 | #EJECTOR_PROMTAIL_MONITORED=false 211 | #DV_EXIT_PROMTAIL_MONITORED=false 212 | 213 | ######### Debug Config ######### 214 | 215 | # This applies to compose-debug.yml only. 216 | 217 | # Prometheus Node exporter docker container image version. 218 | # See available tags https://hub.docker.com/r/bitnamilegacy/node-exporter/tags. 219 | #NODE_EXPORTER_VERSION= 220 | 221 | # Grafana Tempo docker container image version. 222 | # Use Grafana Explore to access Tempo data. 223 | # See available tags https://hub.docker.com/r/grafana/tempo/tags. 224 | #TEMPO_VERSION= 225 | 226 | # Grafana Loki docker container image version. 227 | # See available tags https://hub.docker.com/r/grafana/loki/tags. 228 | #LOKI_VERSION= 229 | 230 | # Loki host exposed port. 231 | #MONITORING_PORT_LOKI= 232 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Obol Logo](https://obol.org/obolnetwork.png) 2 | 3 |

Charon Distributed Validator Node

4 | 5 | This repo contains the [docker-compose](https://docs.docker.com/compose/) files needed to run one node in a [charon](https://github.com/ObolNetwork/charon) [Distributed Validator Cluster](https://docs.obol.org/docs/int/key-concepts#distributed-validator-cluster). 6 | 7 | A distributed validator node is a machine running: 8 | 9 | - An Ethereum Execution client 10 | - An Ethereum Consensus client 11 | - An Ethereum Distributed Validator client 12 | - An Ethereum Validator client 13 | 14 | ![Distributed Validator Node](DVNode.png) 15 | 16 | # Quickstart 17 | 18 | Check the Obol [docs](https://docs.obol.org/docs/start/quickstart_overview) for detailed instructions on how to get started using this repo. 19 | 20 | # Versioning 21 | 22 | It is recommended to use a stable version of the codebase. Major and minor versions follow those of Charon itself (i.e.: latest `v1.6.X` of CDVN will reflect latest `v1.6.Y` Charon), but patch versions in CDVN might be higher (i.e.: `v1.6.2` of CDVN has (latest) `v1.6.1` of Charon). 23 | This is done with mind, that small improvements on CDVN can be made without being tied to a Charon release. 24 | 25 | # Adding Validators 26 | 27 | Starting with charon v1.6, you can add validators to your cluster using the `charon alpha add-validators` command. Note that this is an experimental feature and should not be used in production (Mainnet). The example below is designed for the default configuration provided by this repository and assumes the stack uses the Lodestar validator client. 28 | 29 | 1. Review the `add-validators` command [CLI reference](https://docs.obol.org/next/learn/charon/charon-cli-reference). 30 | 2. Ensure this folder contains a valid `.charon` directory currently used by the running node. Keep the DV node running during the process. 31 | 3. Run the following command to collectively generate and add 10 new validators with other node operators (similar to DKG): 32 | 33 | ```sh 34 | # If you prefer running a pre-built charon binary 35 | charon alpha add-validators --num-validators 10 --withdrawal-addresses=0x --fee-recipient-addresses=0x --output-dir=output 36 | 37 | # Or, if you prefer running it using Docker 38 | # (replace 'latest' with the most recent version if needed: https://hub.docker.com/r/obolnetwork/charon/tags) 39 | docker run --rm -v "$(pwd):/opt/charon" obolnetwork/charon:latest alpha add-validators --num-validators 10 --withdrawal-addresses=0x --fee-recipient-addresses=0x --data-dir=/opt/charon/.charon --output-dir=/opt/charon/output 40 | ``` 41 | 42 | This command will create a new cluster configuration that includes both existing and new validators. It will also generate the necessary keys for the new validators and deposit-data files. A new configuration will be saved in the `output` directory. 43 | 44 | 4. To start using the new configuration (with the added validators), stop the current charon and validator client instances: 45 | 46 | ```sh 47 | docker compose stop charon lodestar 48 | ``` 49 | 50 | 5. Back up and remove the existing `.charon` directory, then move the `output` directory to `.charon`: 51 | 52 | ```sh 53 | mv .charon .charon-backup 54 | mv output .charon 55 | ``` 56 | 57 | 6. Restart the charon and validator client instances: 58 | 59 | ```sh 60 | docker compose up -d charon lodestar 61 | ``` 62 | 63 | Lodestar's boot script (`lodestar/run.sh`) will automatically import all keys, removing any existing keys and cache. Charon will load the new `cluster-lock.json` and recognize all validators in the cluster. 64 | 65 | Steps 4–6 must be performed independently by all node operators, likely at different times. During this process, some nodes will use the old configuration and others the new one. Once the number of upgraded nodes reaches the BFT threshold, the newly added validators will begin participating in the cluster. 66 | 67 | ## Current limitations: 68 | 69 | - The new cluster configuration will not be reflected on the Launchpad. 70 | - The new cluster configuration will have a new cluster hash, so the observability stack will display new cluster data under a different identifier. 71 | - The `add-validators` command supports the KeyManager API (similar to the `dkg` command). However, it may not have direct access to the original private keys if they're no longer in the `.charon` folder you are adding validators to. In this case, it cannot produce valid cluster lock signatures, so you must use the `--unverified` flag. This means charon does not hash and sign the new cluster lock file with all the private keys to prove their existence. As a result, you need to add the `--no-verify` flag or set the `CHARON_NO_VERIFY=true` environment variable to the `charon run` command/container. 72 | - If you use different validator clients, review the keys import script. The old keys in `.charon/validator_keys` remain unchanged, so verify that importing the same keys will not disrupt the validator client's state. 73 | 74 | # Multi-client CDVN 75 | 76 | Default CDVN is available with the following stack: 77 | 78 | - Execution layer: Nethermind 79 | - Consensus layer: Lighthouse 80 | - Distributed validator: Charon 81 | - Validator cllient: Lodestar 82 | - MEV: MEV-boost 83 | 84 | Our focus at Obol being decentralisation, CDVN can also run with multiple clients. We will slowly be rolling out support for different EL, CL, VC and MEV clients. 85 | 86 | ## Migrating as an existing CDVN user 87 | 88 | In order to migrate a currently running Nethermind-Lighthouse-Charon-Lodestar-MEVBoost setup to multi-client one, the `.env` should be updated. 89 | 90 | 1. Copy the new `.env.sample.` file to `.env`. Make sure custom environment variables are not lost in the process. 91 | 92 | > [!IMPORTANT] 93 | > Some environment variables were renamed in order to be client-agnostic. If you have set those environment variables to custom values, after migrating to the multi client setup, use the new ones. They serve the same purpose. 94 | > 95 | > | Old | New | 96 | > |-------------------------------|--------------------------------- | 97 | > | NETHERMIND_PORT_P2P | EL_PORT_P2P | 98 | > | NETHERMIND_IP_HTTP | EL_IP_HTTP | 99 | > | NETHERMIND_PORT_HTTP | EL_PORT_HTTP | 100 | > | NETHERMIND_IP_ENGINE | EL_IP_ENGINE | 101 | > | NETHERMIND_PORT_ENGINE | EL_PORT_ENGINE | 102 | > | LIGHTHOUSE_PORT_P2P | CL_PORT_P2P | 103 | > | LODESTAR_PORT_METRICS | VC_PORT_METRICS | 104 | > | MEVBOOST_TIMEOUT_GETHEADER | MEV_TIMEOUT_GETHEADER | 105 | > | MEVBOOST_TIMEOUT_GETPAYLOAD | MEV_TIMEOUT_GETPAYLOAD | 106 | > | MEVBOOST_TIMEOUT_REGVAL | MEV_TIMEOUT_REGVAL | 107 | > | MEVBOOST_RELAYS | MEV_RELAYS | 108 | > | NETHERMIND_PROMTAIL_MONITORED | EL_NETHERMIND_PROMTAIL_MONITORED | 109 | > | LIGHTHOUSE_PROMTAIL_MONITORED | CL_LIGHTHOUSE_PROMTAIL_MONITORED | 110 | > | LODESTAR_PROMTAIL_MONITORED | VC_LODESTAR_PROMTAIL_MONITORED | 111 | > | MEV_BOOST_PROMTAIL_MONITORED | MEV_MEV_BOOST_PROMTAIL_MONITORED | 112 | 113 | 2. Stop the existing cluster. 114 | 115 | ```sh 116 | docker compose --profile "" down 117 | ``` 118 | 119 | 3. Start the new cluster. 120 | 121 | ```sh 122 | docker compose up -d 123 | ``` 124 | 125 | ## Switch consensus layer client 126 | 127 | 1. Stop the existing consensus layer client container. 128 | > [!TIP] 129 | > If you do not want to experience downtime while the new beacon node is syncing, you can set a fallback beacon node for Charon (`CHARON_FALLBACK_BEACON_NODE_ENDPOINTS` env variable) that will be used while the new BN is syncing. 130 | 131 | ```sh 132 | docker compose down cl-lighthouse 133 | ``` 134 | 135 | 2. Update the `CL` environment variable to a different supported consensus layer client (i.e.: `cl-grandine`). In the `.env` are listed the currently supported clients. 136 | 137 | 3. Start the new consensus layer client container. 138 | 139 | ```sh 140 | docker compose up cl-grandine -d 141 | ``` 142 | 143 | 4. Restart Charon in order to update the BN it's querying. 144 | 145 | ```sh 146 | docker compose down charon 147 | docker compose up charon -d 148 | ``` 149 | 150 | 5. After the new beacon node is synced and you are assured the new setup is working, you can delete the previous BN's data in order to save resources 151 | 152 | ```sh 153 | rm -rf ./data/lighthouse 154 | ``` 155 | 156 | ## Switch validator client 157 | 158 | > [!NOTE] 159 | > There is currently an incompatibility between validator clients that may cause attestation aggregation duties to fail. Aggregation duties are not economically rewarded nor punished for their completion. 160 | > 161 | > To ensure aggregations succeed; have at least threshold of nodes in the cluster running one of Lodestar, Lighthouse, and Nimbus, or alternatively; have a threshold of nodes in the cluster running one of Teku and Prysm. This incompatibility will be remediated in upcoming client releases. 162 | > 163 | 164 | 1. Stop the existing validator client container. 165 | 166 | ```sh 167 | docker compose down vc-lodestar 168 | ``` 169 | 170 | 2. Update the `VC` environment variable to a different supported validator client (i.e.: `vc-nimbus`). In the `.env` are listed the currently supported clients. 171 | 172 | 3. Start the new validator client container. 173 | 174 | ```sh 175 | docker compose up vc-nimbus -d 176 | ``` 177 | 178 | 4. After the new validator client is started and you are assured the new setup is working, you can delete the previous VC's data in order to save resources 179 | 180 | ```sh 181 | rm -rf ./data/lodestar 182 | ``` 183 | 184 | ## Switch MEV client 185 | 186 | 0. If switching to commit-boost, you will need to copy a commit-boost TOML config `commit-boost/config.toml.sample.` to `commit-boost/config.toml` , as it does not support `.env` configurations yet. Make sure the configuration matches what you have had set for mev-boost, in terms of relays and timeouts. 187 | 188 | 1. Stop the existing MEV client container. 189 | 190 | ```sh 191 | docker compose down mev-mevboost 192 | ``` 193 | 194 | 2. Update the `MEV` environment variable to a different supported MEV client (i.e.: `mev-commitboost`). In the `.env` are listed the currently supported clients. 195 | 196 | 3. Start the new MEV client container. 197 | 198 | ```sh 199 | docker compose up mev-commitboost -d 200 | ``` 201 | 202 | 4. Restart the beacon node in order to update the MEV it's querying. 203 | 204 | ```sh 205 | docker compose down cl-grandine 206 | docker compose up cl-grandine -d 207 | ``` 208 | 209 | # FAQs 210 | 211 | Check the Obol docs for frequent [errors and resolutions](https://docs.obol.org/docs/faq/errors) 212 | -------------------------------------------------------------------------------- /grafana/alerts/alerts.yml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | groups: 3 | - orgId: 1 4 | name: Cluster 5 | folder: Charon 6 | interval: 1m 7 | rules: 8 | - uid: f0e3fcb2-7325-47c0-a63b-c9d5cb31178f 9 | title: ' Cluster BeaconNode Down ' 10 | condition: B 11 | data: 12 | - refId: A 13 | relativeTimeRange: 14 | from: 300 15 | to: 0 16 | datasourceUid: prometheus 17 | model: 18 | editorMode: code 19 | expr: 'max((app_monitoring_readyz)) by (cluster_name, cluster_hash, cluster_peer) == 2' 20 | hide: false 21 | intervalMs: 1000 22 | legendFormat: __auto 23 | maxDataPoints: 43200 24 | range: true 25 | refId: A 26 | - refId: B 27 | relativeTimeRange: 28 | from: 300 29 | to: 0 30 | datasourceUid: __expr__ 31 | model: 32 | conditions: 33 | - evaluator: 34 | params: 35 | - 3 36 | type: gt 37 | operator: 38 | type: and 39 | query: 40 | params: 41 | - A 42 | reducer: 43 | params: [] 44 | type: last 45 | type: query 46 | datasource: 47 | type: __expr__ 48 | uid: __expr__ 49 | expression: A 50 | hide: false 51 | intervalMs: 1000 52 | maxDataPoints: 43200 53 | reducer: max 54 | refId: B 55 | settings: 56 | mode: dropNN 57 | type: reduce 58 | dashboardUid: d6qujIJVk 59 | panelId: 141 60 | noDataState: OK 61 | execErrState: OK 62 | for: 10m 63 | annotations: 64 | __dashboardUid__: d6qujIJVk 65 | __panelId__: "141" 66 | summary: Beacon node is down for node {{ $labels.cluster_peer }} in {{ $labels.cluster_name }} 67 | labels: 68 | cluster_hash: '{{ $labels.cluster_hash }}' 69 | cluster_name: '{{ $labels.cluster_name }}' 70 | cluster_peer: '{{ $labels.cluster_peer }}' 71 | severity: notify 72 | isPaused: false 73 | - uid: fdd9f034-22e8-428b-9d7c-52e031bf8cee 74 | title: ' Cluster BeaconNode Syncing ' 75 | condition: B 76 | data: 77 | - refId: A 78 | relativeTimeRange: 79 | from: 300 80 | to: 0 81 | datasourceUid: prometheus 82 | model: 83 | editorMode: code 84 | expr: 'max((app_monitoring_readyz)) by (cluster_name, cluster_hash, cluster_peer) == 3' 85 | hide: false 86 | intervalMs: 1000 87 | legendFormat: __auto 88 | maxDataPoints: 43200 89 | range: true 90 | refId: A 91 | - refId: B 92 | relativeTimeRange: 93 | from: 300 94 | to: 0 95 | datasourceUid: __expr__ 96 | model: 97 | conditions: 98 | - evaluator: 99 | params: 100 | - 3 101 | type: gt 102 | operator: 103 | type: and 104 | query: 105 | params: 106 | - A 107 | reducer: 108 | params: [] 109 | type: last 110 | type: query 111 | datasource: 112 | type: __expr__ 113 | uid: __expr__ 114 | expression: A 115 | hide: false 116 | intervalMs: 1000 117 | maxDataPoints: 43200 118 | reducer: max 119 | refId: B 120 | settings: 121 | mode: dropNN 122 | type: reduce 123 | dashboardUid: d6qujIJVk 124 | panelId: 141 125 | noDataState: OK 126 | execErrState: OK 127 | for: 10m 128 | annotations: 129 | __dashboardUid__: d6qujIJVk 130 | __panelId__: "141" 131 | summary: Beacon node is syncing for node {{ $labels.cluster_peer }} in {{ $labels.cluster_name }} 132 | labels: 133 | cluster_hash: '{{ $labels.cluster_hash }}' 134 | cluster_name: '{{ $labels.cluster_name }}' 135 | cluster_peer: '{{ $labels.cluster_peer }}' 136 | severity: notify 137 | isPaused: false 138 | - uid: d1cf2f49-e3a9-4aaa-98d9-f478b1faa1d2 139 | title: Cluster Missed Attestations 140 | condition: B 141 | data: 142 | - refId: A 143 | relativeTimeRange: 144 | from: 600 145 | to: 0 146 | datasourceUid: prometheus 147 | model: 148 | editorMode: code 149 | expr: 'max(increase(core_tracker_failed_duties_total[$__rate_interval])) by (cluster_hash, cluster_name) > 0 ' 150 | hide: false 151 | intervalMs: 1000 152 | legendFormat: __auto 153 | maxDataPoints: 43200 154 | range: true 155 | refId: A 156 | - refId: B 157 | relativeTimeRange: 158 | from: 600 159 | to: 0 160 | datasourceUid: __expr__ 161 | model: 162 | conditions: 163 | - evaluator: 164 | params: 165 | - 1 166 | type: gt 167 | operator: 168 | type: and 169 | query: 170 | params: 171 | - A 172 | reducer: 173 | params: [] 174 | type: last 175 | type: query 176 | datasource: 177 | type: __expr__ 178 | uid: "-100" 179 | expression: A 180 | hide: false 181 | intervalMs: 1000 182 | maxDataPoints: 43200 183 | reducer: max 184 | refId: B 185 | settings: 186 | mode: dropNN 187 | type: reduce 188 | dashboardUid: d6qujIJVk 189 | panelId: 85 190 | noDataState: OK 191 | execErrState: OK 192 | for: 10m 193 | annotations: 194 | __dashboardUid__: d6qujIJVk 195 | __panelId__: "85" 196 | summary: Missed attestations in cluster {{ $labels.cluster_name }} 197 | labels: 198 | cluster_hash: '{{ $labels.cluster_hash }}' 199 | cluster_name: '{{ $labels.cluster_name }}' 200 | severity: notify 201 | isPaused: false 202 | - uid: e874c008-2ff0-46ef-a1a1-bf62a60337cf 203 | title: Cluster in Unknown Status 204 | condition: B 205 | data: 206 | - refId: A 207 | relativeTimeRange: 208 | from: 600 209 | to: 0 210 | datasourceUid: prometheus 211 | model: 212 | editorMode: code 213 | expr: 'max((app_monitoring_readyz)) by (cluster_name, cluster_hash, cluster_peer, cluster_network) == 0' 214 | hide: false 215 | intervalMs: 1000 216 | legendFormat: __auto 217 | maxDataPoints: 43200 218 | range: true 219 | refId: A 220 | - refId: B 221 | relativeTimeRange: 222 | from: 600 223 | to: 0 224 | datasourceUid: __expr__ 225 | model: 226 | conditions: 227 | - evaluator: 228 | params: 229 | - 3 230 | type: gt 231 | operator: 232 | type: and 233 | query: 234 | params: 235 | - A 236 | reducer: 237 | params: [] 238 | type: last 239 | type: query 240 | datasource: 241 | type: __expr__ 242 | uid: "-100" 243 | expression: A 244 | hide: false 245 | intervalMs: 1000 246 | maxDataPoints: 43200 247 | reducer: count 248 | refId: B 249 | settings: 250 | mode: "" 251 | type: reduce 252 | dashboardUid: d6qujIJVk 253 | panelId: 87 254 | noDataState: OK 255 | execErrState: OK 256 | for: 10m 257 | annotations: 258 | __dashboardUid__: d6qujIJVk 259 | __panelId__: "87" 260 | summary: Node {{ $labels.cluster_peer }} in cluster {{ $labels.cluster_name }} is in unknown state 261 | labels: 262 | cluster_hash: '{{ $labels.cluster_hash }}' 263 | cluster_name: '{{ $labels.cluster_name }}' 264 | isPaused: false 265 | - uid: c23c531e-4386-466a-b9e8-3a3809148cb5 266 | title: Cluster Insufficient Peers 267 | condition: B 268 | data: 269 | - refId: A 270 | relativeTimeRange: 271 | from: 60 272 | to: 0 273 | datasourceUid: prometheus 274 | model: 275 | editorMode: code 276 | expr: 'max((app_monitoring_readyz)) by (cluster_name,cluster_hash,cluster_peer) == 4' 277 | hide: false 278 | intervalMs: 1000 279 | legendFormat: '{{cluster_name}} {{cluster_peer}}' 280 | maxDataPoints: 43200 281 | range: true 282 | refId: A 283 | - refId: B 284 | relativeTimeRange: 285 | from: 60 286 | to: 0 287 | datasourceUid: __expr__ 288 | model: 289 | conditions: 290 | - evaluator: 291 | params: 292 | - 0 293 | - 0 294 | type: gt 295 | operator: 296 | type: and 297 | query: 298 | params: 299 | - A 300 | reducer: 301 | params: [] 302 | type: max 303 | type: query 304 | datasource: 305 | name: Expression 306 | type: __expr__ 307 | uid: __expr__ 308 | expression: A 309 | hide: false 310 | intervalMs: 1000 311 | maxDataPoints: 43200 312 | reducer: max 313 | refId: B 314 | settings: 315 | mode: dropNN 316 | type: reduce 317 | dashboardUid: d6qujIJVk 318 | panelId: 186 319 | noDataState: OK 320 | execErrState: OK 321 | for: 10m 322 | annotations: 323 | __dashboardUid__: d6qujIJVk 324 | __panelId__: "186" 325 | summary: Insufficient Peers for node {{ $labels.cluster_peer }} in cluster {{ $labels.cluster_name }} 326 | labels: 327 | cluster_hash: '{{$labels.cluster_hash}}' 328 | cluster_name: '{{$labels.cluster_name}}' 329 | cluster_peer: '{{$labels.cluster_peer}}' 330 | severity: warning 331 | isPaused: false 332 | - uid: a2cf313f-e5dc-4a3c-a3ff-d7e51b55183e 333 | title: Cluster Failure Rate 334 | condition: B 335 | data: 336 | - refId: A 337 | relativeTimeRange: 338 | from: 900 339 | to: 0 340 | datasourceUid: prometheus 341 | model: 342 | editorMode: code 343 | expr: "floor(\n 100 * \n (\n max(increase(core_tracker_success_duties_total[$__range])) by (cluster_hash, cluster_name) / \n max(increase(core_tracker_expect_duties_total[$__range])) by (cluster_hash, cluster_name)\n )\n) < 95" 344 | hide: false 345 | instant: false 346 | intervalMs: 1000 347 | legendFormat: __auto 348 | maxDataPoints: 43200 349 | range: true 350 | refId: A 351 | - refId: B 352 | relativeTimeRange: 353 | from: 900 354 | to: 0 355 | datasourceUid: __expr__ 356 | model: 357 | conditions: 358 | - evaluator: 359 | params: 360 | - 3 361 | type: gt 362 | operator: 363 | type: and 364 | query: 365 | params: 366 | - A 367 | reducer: 368 | params: [] 369 | type: last 370 | type: query 371 | datasource: 372 | type: __expr__ 373 | uid: "-100" 374 | expression: A 375 | hide: false 376 | intervalMs: 1000 377 | maxDataPoints: 43200 378 | reducer: max 379 | refId: B 380 | settings: 381 | mode: dropNN 382 | type: reduce 383 | dashboardUid: d6qujIJVk 384 | panelId: 91 385 | noDataState: OK 386 | execErrState: OK 387 | for: 6h 388 | annotations: 389 | __dashboardUid__: d6qujIJVk 390 | __panelId__: "91" 391 | summary: Cluster {{ $labels.cluster_name }} success rate is less than {{ $values.B }}% 392 | labels: 393 | cluster_hash: '{{ $labels.cluster_hash }}' 394 | cluster_name: '{{ $labels.cluster_name }}' 395 | severity: notify 396 | isPaused: false 397 | - uid: f5b9fb9d-66b8-49b6-813d-cdb2928425f2 398 | title: ' Cluster VC missing validators ' 399 | condition: B 400 | data: 401 | - refId: A 402 | relativeTimeRange: 403 | from: 300 404 | to: 0 405 | datasourceUid: prometheus 406 | model: 407 | editorMode: code 408 | expr: 'max((app_monitoring_readyz)) by (cluster_name, cluster_hash, cluster_peer) == 6' 409 | hide: false 410 | intervalMs: 1000 411 | legendFormat: __auto 412 | maxDataPoints: 43200 413 | range: true 414 | refId: A 415 | - refId: B 416 | relativeTimeRange: 417 | from: 300 418 | to: 0 419 | datasourceUid: __expr__ 420 | model: 421 | conditions: 422 | - evaluator: 423 | params: 424 | - 3 425 | type: gt 426 | operator: 427 | type: and 428 | query: 429 | params: 430 | - A 431 | reducer: 432 | params: [] 433 | type: last 434 | type: query 435 | datasource: 436 | type: __expr__ 437 | uid: __expr__ 438 | expression: A 439 | hide: false 440 | intervalMs: 1000 441 | maxDataPoints: 43200 442 | reducer: max 443 | refId: B 444 | settings: 445 | mode: dropNN 446 | type: reduce 447 | noDataState: OK 448 | execErrState: OK 449 | for: 10m 450 | annotations: 451 | summary: VC missing some validators for node {{ $labels.cluster_peer }} in cluster {{ $labels.cluster_name }} 452 | labels: 453 | cluster_hash: '{{ $labels.cluster_hash }}' 454 | cluster_name: '{{ $labels.cluster_name }}' 455 | cluster_peer: '{{ $labels.cluster_peer }}' 456 | severity: warning 457 | isPaused: false 458 | - uid: fdhg9rxn9mmf4a 459 | title: ' Cluster BeaconNode has zero peers ' 460 | condition: B 461 | data: 462 | - refId: A 463 | relativeTimeRange: 464 | from: 300 465 | to: 0 466 | datasourceUid: prometheus 467 | model: 468 | editorMode: code 469 | expr: 'max((app_monitoring_readyz)) by (cluster_name, cluster_hash, cluster_peer) == 7' 470 | hide: false 471 | intervalMs: 1000 472 | legendFormat: __auto 473 | maxDataPoints: 43200 474 | range: true 475 | refId: A 476 | - refId: B 477 | relativeTimeRange: 478 | from: 300 479 | to: 0 480 | datasourceUid: __expr__ 481 | model: 482 | conditions: 483 | - evaluator: 484 | params: 485 | - 3 486 | type: gt 487 | operator: 488 | type: and 489 | query: 490 | params: 491 | - A 492 | reducer: 493 | params: [] 494 | type: last 495 | type: query 496 | datasource: 497 | type: __expr__ 498 | uid: __expr__ 499 | expression: A 500 | hide: false 501 | intervalMs: 1000 502 | maxDataPoints: 43200 503 | reducer: max 504 | refId: B 505 | settings: 506 | mode: dropNN 507 | type: reduce 508 | noDataState: OK 509 | execErrState: OK 510 | for: 10m 511 | annotations: 512 | summary: BeaconNode has zero peers for node {{ $labels.cluster_peer }} in cluster {{ $labels.cluster_name }} 513 | labels: 514 | cluster_hash: '{{ $labels.cluster_hash }}' 515 | cluster_name: '{{ $labels.cluster_name }}' 516 | cluster_peer: '{{ $labels.cluster_peer }}' 517 | service: charon 518 | isPaused: false 519 | - uid: e7e9de6b-f7f4-4a69-85b4-0512f5ef0aec 520 | title: High percentage failed sync message duty 521 | condition: B 522 | data: 523 | - refId: A 524 | relativeTimeRange: 525 | from: 10800 526 | to: 0 527 | datasourceUid: prometheus 528 | model: 529 | editorMode: code 530 | expr: "(\n sum(increase(core_tracker_failed_duties_total[1h])) by (cluster_name,cluster_hash,cluster_peer)\n) \n/ \n(\n sum(increase(core_tracker_failed_duties_total[1h])) by (cluster_name,cluster_hash,cluster_peer) \n + \n sum(increase(core_bcast_broadcast_total[1h])) by (cluster_name,cluster_hash,cluster_peer) \n) > 0.1" 531 | hide: false 532 | instant: false 533 | intervalMs: 1000 534 | legendFormat: __auto 535 | maxDataPoints: 43200 536 | range: true 537 | refId: A 538 | - refId: B 539 | relativeTimeRange: 540 | from: 10800 541 | to: 0 542 | datasourceUid: __expr__ 543 | model: 544 | conditions: 545 | - evaluator: 546 | params: 547 | - 3 548 | type: gt 549 | operator: 550 | type: and 551 | query: 552 | params: 553 | - A 554 | reducer: 555 | params: [] 556 | type: last 557 | type: query 558 | datasource: 559 | type: __expr__ 560 | uid: "-100" 561 | expression: A 562 | hide: false 563 | intervalMs: 1000 564 | maxDataPoints: 43200 565 | reducer: max 566 | refId: B 567 | settings: 568 | mode: dropNN 569 | type: reduce 570 | noDataState: OK 571 | execErrState: OK 572 | for: 5m 573 | annotations: 574 | summary: High percentage failed sync message duty for node {{ $labels.cluster_peer }} in cluster {{ $labels.cluster_name }} 575 | labels: 576 | cluster_hash: '{{ $labels.cluster_hash }}' 577 | cluster_name: '{{ $labels.cluster_name }}' 578 | cluster_peer: '{{ $labels.cluster_peer }}' 579 | service: charon 580 | isPaused: false 581 | - uid: f20e8a2f-8533-4524-bd5f-587e167c05ab 582 | title: Cluster - Number of Connected Relays 583 | condition: B 584 | data: 585 | - refId: A 586 | relativeTimeRange: 587 | from: 3600 588 | to: 0 589 | datasourceUid: prometheus 590 | model: 591 | datasource: 592 | type: prometheus 593 | uid: prometheus 594 | editorMode: code 595 | expr: 'group (p2p_relay_connections) by (cluster_peer)' 596 | instant: false 597 | interval: 2m 598 | intervalMs: 15000 599 | legendFormat: __auto 600 | maxDataPoints: 43200 601 | range: true 602 | refId: A 603 | - refId: B 604 | relativeTimeRange: 605 | from: 3600 606 | to: 0 607 | datasourceUid: __expr__ 608 | model: 609 | conditions: 610 | - evaluator: 611 | params: 612 | - 1 613 | - 0 614 | type: gt 615 | operator: 616 | type: and 617 | query: 618 | params: 619 | - A 620 | reducer: 621 | params: [] 622 | type: min 623 | type: query 624 | datasource: 625 | name: Expression 626 | type: __expr__ 627 | uid: __expr__ 628 | expression: "" 629 | intervalMs: 1000 630 | maxDataPoints: 43200 631 | refId: B 632 | type: classic_conditions 633 | dashboardUid: d6qujIJVk 634 | panelId: 156 635 | noDataState: OK 636 | execErrState: Error 637 | for: 10m 638 | annotations: 639 | __dashboardUid__: d6qujIJVk 640 | __panelId__: "156" 641 | summary: Cluster has no Connected Relays 642 | isPaused: false 643 | - uid: ee8dd3f8-bf16-4d1e-b644-ba01bb8c273b 644 | title: Peer ping latency (400ms threshold) 645 | condition: C 646 | data: 647 | - refId: A 648 | relativeTimeRange: 649 | from: 3600 650 | to: 0 651 | datasourceUid: prometheus 652 | model: 653 | datasource: 654 | type: prometheus 655 | uid: prometheus 656 | editorMode: code 657 | exemplar: true 658 | expr: 'histogram_quantile(0.90, sum(rate(p2p_ping_latency_secs_bucket[2m])) by (le,peer)) ' 659 | interval: 2m 660 | intervalMs: 15000 661 | legendFormat: '{{peer}}' 662 | maxDataPoints: 43200 663 | range: true 664 | refId: A 665 | - refId: B 666 | datasourceUid: __expr__ 667 | model: 668 | conditions: 669 | - evaluator: 670 | params: [] 671 | type: gt 672 | operator: 673 | type: and 674 | query: 675 | params: 676 | - B 677 | reducer: 678 | params: [] 679 | type: last 680 | type: query 681 | datasource: 682 | type: __expr__ 683 | uid: __expr__ 684 | expression: A 685 | hide: false 686 | intervalMs: 1000 687 | maxDataPoints: 43200 688 | reducer: last 689 | refId: B 690 | type: reduce 691 | - refId: C 692 | datasourceUid: __expr__ 693 | model: 694 | conditions: 695 | - evaluator: 696 | params: 697 | - 0.4 698 | type: gt 699 | operator: 700 | type: and 701 | query: 702 | params: 703 | - C 704 | reducer: 705 | params: [] 706 | type: last 707 | type: query 708 | datasource: 709 | type: __expr__ 710 | uid: __expr__ 711 | expression: B 712 | hide: false 713 | intervalMs: 1000 714 | maxDataPoints: 43200 715 | refId: C 716 | type: threshold 717 | dashboardUid: d6qujIJVk 718 | panelId: 25 719 | noDataState: OK 720 | execErrState: Error 721 | for: 5m 722 | annotations: 723 | __dashboardUid__: d6qujIJVk 724 | __panelId__: "25" 725 | summary: Peer ping latency is greater than (400ms threshold) 726 | isPaused: false 727 | -------------------------------------------------------------------------------- /grafana/dashboards/single_node_dashboard.json: -------------------------------------------------------------------------------- 1 | { 2 | "annotations": { 3 | "list": [ 4 | { 5 | "$$hashKey": "object:139", 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 | "target": { 16 | "limit": 100, 17 | "matchAny": false, 18 | "tags": [], 19 | "type": "dashboard" 20 | }, 21 | "type": "dashboard" 22 | } 23 | ] 24 | }, 25 | "editable": true, 26 | "fiscalYearStartMonth": 0, 27 | "graphTooltip": 0, 28 | "links": [], 29 | "liveNow": false, 30 | "panels": [ 31 | { 32 | "datasource": { 33 | "type": "loki", 34 | "uid": "loki" 35 | }, 36 | "description": "", 37 | "gridPos": { 38 | "h": 3, 39 | "w": 24, 40 | "x": 0, 41 | "y": 0 42 | }, 43 | "id": 261, 44 | "options": { 45 | "code": { 46 | "language": "plaintext", 47 | "showLineNumbers": false, 48 | "showMiniMap": false 49 | }, 50 | "content": "### ⚠️⚠️⚠️ This panel has been deprecated ⚠️⚠️⚠️\n\nPlease use the Charon overview dashboard for the latest metrics and visualisations about your node and cluster.", 51 | "mode": "markdown" 52 | }, 53 | "pluginVersion": "10.4.0", 54 | "targets": [ 55 | { 56 | "datasource": { 57 | "type": "loki", 58 | "uid": "loki" 59 | }, 60 | "expr": "", 61 | "queryType": "range", 62 | "refId": "A" 63 | } 64 | ], 65 | "transparent": true, 66 | "type": "text" 67 | }, 68 | { 69 | "collapsed": false, 70 | "gridPos": { 71 | "h": 1, 72 | "w": 24, 73 | "x": 0, 74 | "y": 3 75 | }, 76 | "id": 74, 77 | "panels": [], 78 | "title": "Execution Client", 79 | "type": "row" 80 | }, 81 | { 82 | "datasource": { 83 | "type": "prometheus", 84 | "uid": "prometheus" 85 | }, 86 | "fieldConfig": { 87 | "defaults": { 88 | "color": { 89 | "mode": "thresholds" 90 | }, 91 | "mappings": [], 92 | "thresholds": { 93 | "mode": "absolute", 94 | "steps": [ 95 | { 96 | "color": "green", 97 | "value": null 98 | }, 99 | { 100 | "color": "red", 101 | "value": 80 102 | } 103 | ] 104 | } 105 | }, 106 | "overrides": [] 107 | }, 108 | "gridPos": { 109 | "h": 1, 110 | "w": 24, 111 | "x": 0, 112 | "y": 4 113 | }, 114 | "id": 76, 115 | "options": { 116 | "colorMode": "none", 117 | "graphMode": "none", 118 | "justifyMode": "auto", 119 | "orientation": "auto", 120 | "reduceOptions": { 121 | "calcs": [ 122 | "lastNotNull" 123 | ], 124 | "fields": "", 125 | "values": false 126 | }, 127 | "showPercentChange": false, 128 | "textMode": "none", 129 | "wideLayout": true 130 | }, 131 | "pluginVersion": "10.4.0", 132 | "targets": [ 133 | { 134 | "datasource": { 135 | "type": "prometheus", 136 | "uid": "prometheus" 137 | }, 138 | "expr": "1", 139 | "refId": "A" 140 | } 141 | ], 142 | "title": "GETH", 143 | "type": "stat" 144 | }, 145 | { 146 | "datasource": { 147 | "type": "prometheus", 148 | "uid": "prometheus" 149 | }, 150 | "fieldConfig": { 151 | "defaults": { 152 | "color": { 153 | "mode": "thresholds" 154 | }, 155 | "mappings": [ 156 | { 157 | "options": { 158 | "0": { 159 | "color": "red", 160 | "index": 1, 161 | "text": "Inactive" 162 | }, 163 | "1": { 164 | "color": "green", 165 | "index": 0, 166 | "text": "Active" 167 | } 168 | }, 169 | "type": "value" 170 | } 171 | ], 172 | "thresholds": { 173 | "mode": "absolute", 174 | "steps": [ 175 | { 176 | "color": "green", 177 | "value": null 178 | }, 179 | { 180 | "color": "red", 181 | "value": 80 182 | } 183 | ] 184 | } 185 | }, 186 | "overrides": [] 187 | }, 188 | "gridPos": { 189 | "h": 3, 190 | "w": 4, 191 | "x": 0, 192 | "y": 5 193 | }, 194 | "id": 84, 195 | "options": { 196 | "colorMode": "value", 197 | "graphMode": "none", 198 | "justifyMode": "auto", 199 | "orientation": "auto", 200 | "reduceOptions": { 201 | "calcs": [ 202 | "lastNotNull" 203 | ], 204 | "fields": "", 205 | "values": false 206 | }, 207 | "showPercentChange": false, 208 | "textMode": "auto", 209 | "wideLayout": true 210 | }, 211 | "pluginVersion": "10.4.0", 212 | "targets": [ 213 | { 214 | "datasource": { 215 | "type": "prometheus", 216 | "uid": "prometheus" 217 | }, 218 | "expr": "up{job=\"geth\"}", 219 | "refId": "A" 220 | } 221 | ], 222 | "title": "Status", 223 | "type": "stat" 224 | }, 225 | { 226 | "datasource": { 227 | "type": "prometheus", 228 | "uid": "prometheus" 229 | }, 230 | "description": "Peers connected with our execution client. Also number of peers we dialled and we are serving.", 231 | "fieldConfig": { 232 | "defaults": { 233 | "color": { 234 | "mode": "thresholds" 235 | }, 236 | "mappings": [], 237 | "min": 0, 238 | "thresholds": { 239 | "mode": "absolute", 240 | "steps": [ 241 | { 242 | "color": "green", 243 | "value": null 244 | }, 245 | { 246 | "color": "red", 247 | "value": 80 248 | } 249 | ] 250 | }, 251 | "unit": "none" 252 | }, 253 | "overrides": [] 254 | }, 255 | "gridPos": { 256 | "h": 6, 257 | "w": 4, 258 | "x": 4, 259 | "y": 5 260 | }, 261 | "id": 78, 262 | "options": { 263 | "colorMode": "value", 264 | "graphMode": "area", 265 | "justifyMode": "auto", 266 | "orientation": "auto", 267 | "reduceOptions": { 268 | "calcs": [ 269 | "lastNotNull" 270 | ], 271 | "fields": "", 272 | "values": false 273 | }, 274 | "showPercentChange": false, 275 | "textMode": "auto", 276 | "wideLayout": true 277 | }, 278 | "pluginVersion": "10.4.0", 279 | "targets": [ 280 | { 281 | "datasource": { 282 | "type": "prometheus", 283 | "uid": "prometheus" 284 | }, 285 | "editorMode": "code", 286 | "expr": "p2p_peers", 287 | "legendFormat": "peers", 288 | "range": true, 289 | "refId": "A" 290 | } 291 | ], 292 | "title": "Peers", 293 | "type": "stat" 294 | }, 295 | { 296 | "datasource": { 297 | "type": "prometheus", 298 | "uid": "prometheus" 299 | }, 300 | "description": "Memory used by execution client.", 301 | "fieldConfig": { 302 | "defaults": { 303 | "color": { 304 | "mode": "palette-classic" 305 | }, 306 | "custom": { 307 | "axisBorderShow": false, 308 | "axisCenteredZero": false, 309 | "axisColorMode": "text", 310 | "axisLabel": "", 311 | "axisPlacement": "auto", 312 | "barAlignment": 0, 313 | "drawStyle": "line", 314 | "fillOpacity": 10, 315 | "gradientMode": "none", 316 | "hideFrom": { 317 | "legend": false, 318 | "tooltip": false, 319 | "viz": false 320 | }, 321 | "insertNulls": false, 322 | "lineInterpolation": "linear", 323 | "lineWidth": 1, 324 | "pointSize": 5, 325 | "scaleDistribution": { 326 | "type": "linear" 327 | }, 328 | "showPoints": "never", 329 | "spanNulls": false, 330 | "stacking": { 331 | "group": "A", 332 | "mode": "none" 333 | }, 334 | "thresholdsStyle": { 335 | "mode": "off" 336 | } 337 | }, 338 | "mappings": [], 339 | "thresholds": { 340 | "mode": "absolute", 341 | "steps": [ 342 | { 343 | "color": "green", 344 | "value": null 345 | }, 346 | { 347 | "color": "red", 348 | "value": 80 349 | } 350 | ] 351 | }, 352 | "unit": "bytes" 353 | }, 354 | "overrides": [] 355 | }, 356 | "gridPos": { 357 | "h": 6, 358 | "w": 8, 359 | "x": 8, 360 | "y": 5 361 | }, 362 | "id": 80, 363 | "options": { 364 | "legend": { 365 | "calcs": [], 366 | "displayMode": "list", 367 | "placement": "bottom", 368 | "showLegend": true 369 | }, 370 | "tooltip": { 371 | "mode": "single", 372 | "sort": "none" 373 | } 374 | }, 375 | "targets": [ 376 | { 377 | "datasource": { 378 | "type": "prometheus", 379 | "uid": "prometheus" 380 | }, 381 | "editorMode": "code", 382 | "expr": "rate(system_memory_allocs[1m])", 383 | "legendFormat": "alloc", 384 | "range": true, 385 | "refId": "A" 386 | }, 387 | { 388 | "datasource": { 389 | "type": "prometheus", 390 | "uid": "prometheus" 391 | }, 392 | "editorMode": "code", 393 | "expr": "system_memory_used", 394 | "hide": false, 395 | "legendFormat": "used", 396 | "range": true, 397 | "refId": "B" 398 | }, 399 | { 400 | "datasource": { 401 | "type": "prometheus", 402 | "uid": "prometheus" 403 | }, 404 | "editorMode": "code", 405 | "expr": "system_memory_held", 406 | "hide": false, 407 | "legendFormat": "held", 408 | "range": true, 409 | "refId": "C" 410 | } 411 | ], 412 | "title": "Memory", 413 | "type": "timeseries" 414 | }, 415 | { 416 | "datasource": { 417 | "type": "prometheus", 418 | "uid": "prometheus" 419 | }, 420 | "fieldConfig": { 421 | "defaults": { 422 | "color": { 423 | "mode": "palette-classic" 424 | }, 425 | "custom": { 426 | "axisBorderShow": false, 427 | "axisCenteredZero": false, 428 | "axisColorMode": "text", 429 | "axisLabel": "", 430 | "axisPlacement": "auto", 431 | "barAlignment": 0, 432 | "drawStyle": "line", 433 | "fillOpacity": 10, 434 | "gradientMode": "none", 435 | "hideFrom": { 436 | "legend": false, 437 | "tooltip": false, 438 | "viz": false 439 | }, 440 | "insertNulls": false, 441 | "lineInterpolation": "linear", 442 | "lineWidth": 1, 443 | "pointSize": 5, 444 | "scaleDistribution": { 445 | "type": "linear" 446 | }, 447 | "showPoints": "never", 448 | "spanNulls": false, 449 | "stacking": { 450 | "group": "A", 451 | "mode": "none" 452 | }, 453 | "thresholdsStyle": { 454 | "mode": "off" 455 | } 456 | }, 457 | "mappings": [], 458 | "thresholds": { 459 | "mode": "absolute", 460 | "steps": [ 461 | { 462 | "color": "green", 463 | "value": null 464 | }, 465 | { 466 | "color": "red", 467 | "value": 80 468 | } 469 | ] 470 | }, 471 | "unit": "percent" 472 | }, 473 | "overrides": [] 474 | }, 475 | "gridPos": { 476 | "h": 6, 477 | "w": 8, 478 | "x": 16, 479 | "y": 5 480 | }, 481 | "id": 86, 482 | "options": { 483 | "legend": { 484 | "calcs": [], 485 | "displayMode": "list", 486 | "placement": "bottom", 487 | "showLegend": true 488 | }, 489 | "tooltip": { 490 | "mode": "multi", 491 | "sort": "none" 492 | } 493 | }, 494 | "pluginVersion": "9.0.7", 495 | "targets": [ 496 | { 497 | "datasource": { 498 | "type": "prometheus", 499 | "uid": "prometheus" 500 | }, 501 | "expr": "system_cpu_sysload", 502 | "format": "time_series", 503 | "intervalFactor": 1, 504 | "legendFormat": "system", 505 | "refId": "A" 506 | }, 507 | { 508 | "datasource": { 509 | "type": "prometheus", 510 | "uid": "prometheus" 511 | }, 512 | "expr": "system_cpu_syswait", 513 | "format": "time_series", 514 | "intervalFactor": 1, 515 | "legendFormat": "iowait", 516 | "refId": "B" 517 | }, 518 | { 519 | "datasource": { 520 | "type": "prometheus", 521 | "uid": "prometheus" 522 | }, 523 | "expr": "system_cpu_procload", 524 | "format": "time_series", 525 | "intervalFactor": 1, 526 | "legendFormat": "geth", 527 | "refId": "C" 528 | } 529 | ], 530 | "title": "CPU", 531 | "type": "timeseries" 532 | }, 533 | { 534 | "datasource": { 535 | "type": "prometheus", 536 | "uid": "prometheus" 537 | }, 538 | "fieldConfig": { 539 | "defaults": { 540 | "color": { 541 | "mode": "thresholds" 542 | }, 543 | "mappings": [], 544 | "thresholds": { 545 | "mode": "absolute", 546 | "steps": [ 547 | { 548 | "color": "green", 549 | "value": null 550 | }, 551 | { 552 | "color": "red", 553 | "value": 80 554 | } 555 | ] 556 | }, 557 | "unit": "locale" 558 | }, 559 | "overrides": [] 560 | }, 561 | "gridPos": { 562 | "h": 3, 563 | "w": 4, 564 | "x": 0, 565 | "y": 8 566 | }, 567 | "id": 82, 568 | "options": { 569 | "colorMode": "none", 570 | "graphMode": "none", 571 | "justifyMode": "auto", 572 | "orientation": "auto", 573 | "reduceOptions": { 574 | "calcs": [ 575 | "lastNotNull" 576 | ], 577 | "fields": "", 578 | "values": false 579 | }, 580 | "showPercentChange": false, 581 | "textMode": "auto", 582 | "wideLayout": true 583 | }, 584 | "pluginVersion": "10.4.0", 585 | "targets": [ 586 | { 587 | "datasource": { 588 | "type": "prometheus", 589 | "uid": "prometheus" 590 | }, 591 | "expr": "chain_head_header", 592 | "refId": "A" 593 | } 594 | ], 595 | "title": "Latest Chain Header", 596 | "type": "stat" 597 | }, 598 | { 599 | "datasource": { 600 | "type": "prometheus", 601 | "uid": "prometheus" 602 | }, 603 | "fieldConfig": { 604 | "defaults": { 605 | "color": { 606 | "mode": "thresholds" 607 | }, 608 | "mappings": [], 609 | "thresholds": { 610 | "mode": "absolute", 611 | "steps": [ 612 | { 613 | "color": "green", 614 | "value": null 615 | }, 616 | { 617 | "color": "red", 618 | "value": 80 619 | } 620 | ] 621 | } 622 | }, 623 | "overrides": [] 624 | }, 625 | "gridPos": { 626 | "h": 1, 627 | "w": 24, 628 | "x": 0, 629 | "y": 11 630 | }, 631 | "id": 53, 632 | "options": { 633 | "colorMode": "none", 634 | "graphMode": "none", 635 | "justifyMode": "auto", 636 | "orientation": "auto", 637 | "reduceOptions": { 638 | "calcs": [ 639 | "lastNotNull" 640 | ], 641 | "fields": "", 642 | "values": false 643 | }, 644 | "showPercentChange": false, 645 | "textMode": "none", 646 | "wideLayout": true 647 | }, 648 | "pluginVersion": "10.4.0", 649 | "targets": [ 650 | { 651 | "datasource": { 652 | "type": "prometheus", 653 | "uid": "prometheus" 654 | }, 655 | "expr": "1", 656 | "refId": "A" 657 | } 658 | ], 659 | "title": "LIGHTHOUSE", 660 | "type": "stat" 661 | }, 662 | { 663 | "collapsed": false, 664 | "gridPos": { 665 | "h": 1, 666 | "w": 24, 667 | "x": 0, 668 | "y": 12 669 | }, 670 | "id": 55, 671 | "panels": [], 672 | "title": "Beacon Client", 673 | "type": "row" 674 | }, 675 | { 676 | "datasource": { 677 | "type": "prometheus", 678 | "uid": "prometheus" 679 | }, 680 | "description": "", 681 | "fieldConfig": { 682 | "defaults": { 683 | "color": { 684 | "mode": "palette-classic" 685 | }, 686 | "custom": { 687 | "axisBorderShow": false, 688 | "axisCenteredZero": false, 689 | "axisColorMode": "text", 690 | "axisLabel": "", 691 | "axisPlacement": "auto", 692 | "axisSoftMin": 0, 693 | "barAlignment": 0, 694 | "drawStyle": "line", 695 | "fillOpacity": 10, 696 | "gradientMode": "none", 697 | "hideFrom": { 698 | "legend": false, 699 | "tooltip": false, 700 | "viz": false 701 | }, 702 | "insertNulls": false, 703 | "lineInterpolation": "linear", 704 | "lineWidth": 2, 705 | "pointSize": 5, 706 | "scaleDistribution": { 707 | "type": "linear" 708 | }, 709 | "showPoints": "never", 710 | "spanNulls": true, 711 | "stacking": { 712 | "group": "A", 713 | "mode": "none" 714 | }, 715 | "thresholdsStyle": { 716 | "mode": "off" 717 | } 718 | }, 719 | "decimals": 0, 720 | "mappings": [], 721 | "thresholds": { 722 | "mode": "absolute", 723 | "steps": [ 724 | { 725 | "color": "red", 726 | "value": null 727 | }, 728 | { 729 | "color": "green", 730 | "value": 80 731 | } 732 | ] 733 | }, 734 | "unit": "short" 735 | }, 736 | "overrides": [] 737 | }, 738 | "gridPos": { 739 | "h": 5, 740 | "w": 6, 741 | "x": 0, 742 | "y": 13 743 | }, 744 | "id": 64, 745 | "options": { 746 | "legend": { 747 | "calcs": [], 748 | "displayMode": "list", 749 | "placement": "bottom", 750 | "showLegend": true 751 | }, 752 | "tooltip": { 753 | "mode": "multi", 754 | "sort": "none" 755 | } 756 | }, 757 | "pluginVersion": "8.5.3", 758 | "targets": [ 759 | { 760 | "expr": "sync_range_chains", 761 | "interval": "", 762 | "legendFormat": "{{range_type}}", 763 | "refId": "A" 764 | } 765 | ], 766 | "title": "Syncing chain counts", 767 | "type": "timeseries" 768 | }, 769 | { 770 | "datasource": { 771 | "type": "prometheus", 772 | "uid": "prometheus" 773 | }, 774 | "description": "Lighthouse's reported current slot (unsafe not finalised)", 775 | "fieldConfig": { 776 | "defaults": { 777 | "color": { 778 | "mode": "thresholds" 779 | }, 780 | "mappings": [ 781 | { 782 | "options": { 783 | "match": "null", 784 | "result": { 785 | "color": "red", 786 | "index": 0, 787 | "text": "Unknown" 788 | } 789 | }, 790 | "type": "special" 791 | } 792 | ], 793 | "noValue": "Unknown", 794 | "thresholds": { 795 | "mode": "absolute", 796 | "steps": [ 797 | { 798 | "color": "red", 799 | "value": null 800 | }, 801 | { 802 | "color": "red", 803 | "value": 80 804 | } 805 | ] 806 | }, 807 | "unit": "locale" 808 | }, 809 | "overrides": [] 810 | }, 811 | "gridPos": { 812 | "h": 3, 813 | "w": 3, 814 | "x": 6, 815 | "y": 13 816 | }, 817 | "id": 58, 818 | "maxDataPoints": 100, 819 | "options": { 820 | "colorMode": "none", 821 | "graphMode": "none", 822 | "justifyMode": "auto", 823 | "orientation": "horizontal", 824 | "reduceOptions": { 825 | "calcs": [ 826 | "last" 827 | ], 828 | "fields": "", 829 | "values": false 830 | }, 831 | "showPercentChange": false, 832 | "textMode": "auto", 833 | "wideLayout": true 834 | }, 835 | "pluginVersion": "10.4.0", 836 | "targets": [ 837 | { 838 | "expr": "max(slotclock_present_slot)", 839 | "format": "time_series", 840 | "intervalFactor": 1, 841 | "refId": "A" 842 | } 843 | ], 844 | "title": "Current Slot", 845 | "transparent": true, 846 | "type": "stat" 847 | }, 848 | { 849 | "datasource": { 850 | "type": "prometheus", 851 | "uid": "prometheus" 852 | }, 853 | "description": "The sync status for lighthouse's peers", 854 | "fieldConfig": { 855 | "defaults": { 856 | "color": { 857 | "mode": "palette-classic" 858 | }, 859 | "custom": { 860 | "hideFrom": { 861 | "legend": false, 862 | "tooltip": false, 863 | "viz": false 864 | } 865 | }, 866 | "mappings": [ 867 | { 868 | "options": { 869 | "Ahead": { 870 | "color": "red", 871 | "index": 2 872 | }, 873 | "Behind": { 874 | "color": "orange", 875 | "index": 1 876 | }, 877 | "Synced": { 878 | "color": "green", 879 | "index": 0 880 | } 881 | }, 882 | "type": "value" 883 | } 884 | ] 885 | }, 886 | "overrides": [] 887 | }, 888 | "gridPos": { 889 | "h": 5, 890 | "w": 4, 891 | "x": 9, 892 | "y": 13 893 | }, 894 | "id": 60, 895 | "options": { 896 | "displayLabels": [ 897 | "value" 898 | ], 899 | "legend": { 900 | "displayMode": "table", 901 | "placement": "right", 902 | "showLegend": true, 903 | "values": [ 904 | "value" 905 | ] 906 | }, 907 | "pieType": "pie", 908 | "reduceOptions": { 909 | "calcs": [ 910 | "lastNotNull" 911 | ], 912 | "fields": "", 913 | "values": false 914 | }, 915 | "tooltip": { 916 | "mode": "single", 917 | "sort": "none" 918 | } 919 | }, 920 | "pluginVersion": "8.1.3", 921 | "targets": [ 922 | { 923 | "datasource": { 924 | "type": "prometheus", 925 | "uid": "prometheus" 926 | }, 927 | "exemplar": false, 928 | "expr": "sync_peers_per_status", 929 | "instant": true, 930 | "interval": "", 931 | "legendFormat": "{{sync_status}}", 932 | "refId": "A" 933 | } 934 | ], 935 | "title": "Peer Sync Status", 936 | "transparent": true, 937 | "type": "piechart" 938 | }, 939 | { 940 | "datasource": { 941 | "type": "prometheus", 942 | "uid": "prometheus" 943 | }, 944 | "description": "Peers that have dialed us. Indicates if our node is reachable", 945 | "fieldConfig": { 946 | "defaults": { 947 | "color": { 948 | "mode": "palette-classic" 949 | }, 950 | "custom": { 951 | "hideFrom": { 952 | "legend": false, 953 | "tooltip": false, 954 | "viz": false 955 | } 956 | }, 957 | "mappings": [] 958 | }, 959 | "overrides": [] 960 | }, 961 | "gridPos": { 962 | "h": 5, 963 | "w": 4, 964 | "x": 13, 965 | "y": 13 966 | }, 967 | "id": 62, 968 | "options": { 969 | "displayLabels": [ 970 | "value" 971 | ], 972 | "legend": { 973 | "displayMode": "table", 974 | "placement": "right", 975 | "showLegend": true, 976 | "values": [ 977 | "value" 978 | ] 979 | }, 980 | "pieType": "pie", 981 | "reduceOptions": { 982 | "calcs": [ 983 | "lastNotNull" 984 | ], 985 | "fields": "", 986 | "values": false 987 | }, 988 | "tooltip": { 989 | "mode": "single", 990 | "sort": "none" 991 | } 992 | }, 993 | "pluginVersion": "8.1.3", 994 | "targets": [ 995 | { 996 | "datasource": { 997 | "type": "prometheus", 998 | "uid": "prometheus" 999 | }, 1000 | "exemplar": false, 1001 | "expr": "network_inbound_peers", 1002 | "instant": true, 1003 | "interval": "", 1004 | "legendFormat": "Inbound", 1005 | "refId": "A" 1006 | }, 1007 | { 1008 | "datasource": { 1009 | "type": "prometheus", 1010 | "uid": "prometheus" 1011 | }, 1012 | "exemplar": false, 1013 | "expr": "network_outbound_peers", 1014 | "format": "time_series", 1015 | "hide": false, 1016 | "instant": true, 1017 | "interval": "", 1018 | "legendFormat": "Outbound", 1019 | "refId": "B" 1020 | } 1021 | ], 1022 | "title": "Peer Type", 1023 | "transparent": true, 1024 | "type": "piechart" 1025 | }, 1026 | { 1027 | "datasource": { 1028 | "type": "prometheus", 1029 | "uid": "prometheus" 1030 | }, 1031 | "description": "Identifies if there is an upstream execution client connected", 1032 | "fieldConfig": { 1033 | "defaults": { 1034 | "color": { 1035 | "mode": "thresholds" 1036 | }, 1037 | "decimals": 0, 1038 | "mappings": [ 1039 | { 1040 | "options": { 1041 | "0": { 1042 | "color": "red", 1043 | "index": 1, 1044 | "text": "Not Connected" 1045 | }, 1046 | "1": { 1047 | "color": "green", 1048 | "index": 0, 1049 | "text": "Connected" 1050 | } 1051 | }, 1052 | "type": "value" 1053 | }, 1054 | { 1055 | "options": { 1056 | "match": "null", 1057 | "result": { 1058 | "color": "orange", 1059 | "index": 2, 1060 | "text": "Unknown" 1061 | } 1062 | }, 1063 | "type": "special" 1064 | }, 1065 | { 1066 | "options": { 1067 | "match": "empty", 1068 | "result": { 1069 | "color": "red", 1070 | "index": 3, 1071 | "text": "Not Connected" 1072 | } 1073 | }, 1074 | "type": "special" 1075 | } 1076 | ], 1077 | "min": 0, 1078 | "noValue": "Not Connected", 1079 | "thresholds": { 1080 | "mode": "absolute", 1081 | "steps": [ 1082 | { 1083 | "color": "red", 1084 | "value": null 1085 | }, 1086 | { 1087 | "color": "red", 1088 | "value": 80 1089 | } 1090 | ] 1091 | }, 1092 | "unit": "short" 1093 | }, 1094 | "overrides": [] 1095 | }, 1096 | "gridPos": { 1097 | "h": 4, 1098 | "w": 4, 1099 | "x": 17, 1100 | "y": 13 1101 | }, 1102 | "id": 65, 1103 | "options": { 1104 | "colorMode": "value", 1105 | "graphMode": "area", 1106 | "justifyMode": "auto", 1107 | "orientation": "auto", 1108 | "reduceOptions": { 1109 | "calcs": [ 1110 | "last" 1111 | ], 1112 | "fields": "", 1113 | "values": false 1114 | }, 1115 | "showPercentChange": false, 1116 | "textMode": "auto", 1117 | "wideLayout": true 1118 | }, 1119 | "pluginVersion": "10.4.0", 1120 | "targets": [ 1121 | { 1122 | "datasource": { 1123 | "type": "prometheus", 1124 | "uid": "prometheus" 1125 | }, 1126 | "expr": "sync_eth1_connected", 1127 | "interval": "", 1128 | "legendFormat": "{{range_type}}", 1129 | "refId": "A" 1130 | } 1131 | ], 1132 | "title": "Eth1 Execution Client Connected", 1133 | "type": "stat" 1134 | }, 1135 | { 1136 | "datasource": { 1137 | "type": "prometheus", 1138 | "uid": "prometheus" 1139 | }, 1140 | "description": "Identifies if the consensus client is synced", 1141 | "fieldConfig": { 1142 | "defaults": { 1143 | "color": { 1144 | "mode": "thresholds" 1145 | }, 1146 | "decimals": 0, 1147 | "mappings": [ 1148 | { 1149 | "options": { 1150 | "0": { 1151 | "color": "red", 1152 | "index": 1, 1153 | "text": "Not Synced" 1154 | }, 1155 | "1": { 1156 | "color": "green", 1157 | "index": 0, 1158 | "text": "Synced" 1159 | } 1160 | }, 1161 | "type": "value" 1162 | } 1163 | ], 1164 | "min": 0, 1165 | "thresholds": { 1166 | "mode": "absolute", 1167 | "steps": [ 1168 | { 1169 | "color": "green", 1170 | "value": null 1171 | }, 1172 | { 1173 | "color": "red", 1174 | "value": 80 1175 | } 1176 | ] 1177 | }, 1178 | "unit": "short" 1179 | }, 1180 | "overrides": [] 1181 | }, 1182 | "gridPos": { 1183 | "h": 4, 1184 | "w": 3, 1185 | "x": 21, 1186 | "y": 13 1187 | }, 1188 | "id": 66, 1189 | "options": { 1190 | "colorMode": "value", 1191 | "graphMode": "area", 1192 | "justifyMode": "auto", 1193 | "orientation": "auto", 1194 | "reduceOptions": { 1195 | "calcs": [ 1196 | "last" 1197 | ], 1198 | "fields": "", 1199 | "values": false 1200 | }, 1201 | "showPercentChange": false, 1202 | "textMode": "auto", 1203 | "wideLayout": true 1204 | }, 1205 | "pluginVersion": "10.4.0", 1206 | "targets": [ 1207 | { 1208 | "datasource": { 1209 | "type": "prometheus", 1210 | "uid": "prometheus" 1211 | }, 1212 | "expr": "sync_eth2_synced", 1213 | "interval": "", 1214 | "legendFormat": "{{range_type}}", 1215 | "refId": "A" 1216 | } 1217 | ], 1218 | "title": "Eth2 Consensus Client Synced", 1219 | "type": "stat" 1220 | }, 1221 | { 1222 | "collapsed": false, 1223 | "gridPos": { 1224 | "h": 1, 1225 | "w": 24, 1226 | "x": 0, 1227 | "y": 18 1228 | }, 1229 | "id": 48, 1230 | "panels": [], 1231 | "title": "Charon", 1232 | "type": "row" 1233 | }, 1234 | { 1235 | "datasource": { 1236 | "type": "prometheus", 1237 | "uid": "prometheus" 1238 | }, 1239 | "fieldConfig": { 1240 | "defaults": { 1241 | "color": { 1242 | "mode": "thresholds" 1243 | }, 1244 | "mappings": [], 1245 | "thresholds": { 1246 | "mode": "absolute", 1247 | "steps": [ 1248 | { 1249 | "color": "green", 1250 | "value": null 1251 | }, 1252 | { 1253 | "color": "red", 1254 | "value": 80 1255 | } 1256 | ] 1257 | } 1258 | }, 1259 | "overrides": [] 1260 | }, 1261 | "gridPos": { 1262 | "h": 1, 1263 | "w": 24, 1264 | "x": 0, 1265 | "y": 19 1266 | }, 1267 | "id": 56, 1268 | "options": { 1269 | "colorMode": "none", 1270 | "graphMode": "none", 1271 | "justifyMode": "auto", 1272 | "orientation": "auto", 1273 | "reduceOptions": { 1274 | "calcs": [ 1275 | "lastNotNull" 1276 | ], 1277 | "fields": "", 1278 | "values": false 1279 | }, 1280 | "showPercentChange": false, 1281 | "textMode": "none", 1282 | "wideLayout": true 1283 | }, 1284 | "pluginVersion": "10.4.0", 1285 | "targets": [ 1286 | { 1287 | "datasource": { 1288 | "type": "prometheus", 1289 | "uid": "prometheus" 1290 | }, 1291 | "expr": "1", 1292 | "refId": "A" 1293 | } 1294 | ], 1295 | "title": "CHARON", 1296 | "type": "stat" 1297 | }, 1298 | { 1299 | "datasource": { 1300 | "type": "prometheus", 1301 | "uid": "prometheus" 1302 | }, 1303 | "description": "Status returned from the `/readyz` health status endpoint. Unhealthy reasons include beacon node problems, charon p2p problems, or validator client problems.", 1304 | "fieldConfig": { 1305 | "defaults": { 1306 | "color": { 1307 | "mode": "thresholds" 1308 | }, 1309 | "mappings": [ 1310 | { 1311 | "options": { 1312 | "0": { 1313 | "color": "text", 1314 | "index": 1, 1315 | "text": "Unknown" 1316 | }, 1317 | "1": { 1318 | "color": "green", 1319 | "index": 0, 1320 | "text": "OK" 1321 | }, 1322 | "2": { 1323 | "color": "red", 1324 | "index": 3, 1325 | "text": "BeaconNode Down" 1326 | }, 1327 | "3": { 1328 | "color": "orange", 1329 | "index": 4, 1330 | "text": "BeaconNode Syncing" 1331 | }, 1332 | "4": { 1333 | "color": "orange", 1334 | "index": 5, 1335 | "text": "Insufficient Peers" 1336 | }, 1337 | "5": { 1338 | "color": "orange", 1339 | "index": 6, 1340 | "text": "VC not connected" 1341 | }, 1342 | "6": { 1343 | "color": "orange", 1344 | "index": 7, 1345 | "text": "VC missing validators" 1346 | }, 1347 | "7": { 1348 | "color": "orange", 1349 | "index": 8, 1350 | "text": "BeaconNode has zero peers" 1351 | }, 1352 | "8": { 1353 | "color": "orange", 1354 | "index": 9, 1355 | "text": "BeaconNode far behind" 1356 | } 1357 | }, 1358 | "type": "value" 1359 | }, 1360 | { 1361 | "options": { 1362 | "match": "null", 1363 | "result": { 1364 | "color": "text", 1365 | "index": 2, 1366 | "text": "Dead" 1367 | } 1368 | }, 1369 | "type": "special" 1370 | } 1371 | ], 1372 | "thresholds": { 1373 | "mode": "absolute", 1374 | "steps": [ 1375 | { 1376 | "color": "green", 1377 | "value": null 1378 | }, 1379 | { 1380 | "color": "red", 1381 | "value": 80 1382 | } 1383 | ] 1384 | }, 1385 | "unit": "none" 1386 | }, 1387 | "overrides": [] 1388 | }, 1389 | "gridPos": { 1390 | "h": 3, 1391 | "w": 4, 1392 | "x": 0, 1393 | "y": 20 1394 | }, 1395 | "id": 95, 1396 | "options": { 1397 | "colorMode": "value", 1398 | "graphMode": "none", 1399 | "justifyMode": "auto", 1400 | "orientation": "auto", 1401 | "reduceOptions": { 1402 | "calcs": [ 1403 | "lastNotNull" 1404 | ], 1405 | "fields": "", 1406 | "values": false 1407 | }, 1408 | "showPercentChange": false, 1409 | "textMode": "auto", 1410 | "wideLayout": true 1411 | }, 1412 | "pluginVersion": "10.4.0", 1413 | "targets": [ 1414 | { 1415 | "datasource": { 1416 | "type": "prometheus", 1417 | "uid": "prometheus" 1418 | }, 1419 | "editorMode": "code", 1420 | "exemplar": false, 1421 | "expr": "app_monitoring_readyz{job=\"charon\"}", 1422 | "hide": false, 1423 | "instant": true, 1424 | "interval": "", 1425 | "legendFormat": "", 1426 | "range": false, 1427 | "refId": "A" 1428 | } 1429 | ], 1430 | "title": "Health Status", 1431 | "type": "stat" 1432 | }, 1433 | { 1434 | "datasource": { 1435 | "type": "prometheus", 1436 | "uid": "prometheus" 1437 | }, 1438 | "description": "Successful cluster duty percentage by type over the whole time range", 1439 | "fieldConfig": { 1440 | "defaults": { 1441 | "color": { 1442 | "mode": "thresholds" 1443 | }, 1444 | "mappings": [], 1445 | "max": 1, 1446 | "min": 0, 1447 | "thresholds": { 1448 | "mode": "absolute", 1449 | "steps": [ 1450 | { 1451 | "color": "red", 1452 | "value": null 1453 | }, 1454 | { 1455 | "color": "#EAB839", 1456 | "value": 0.9 1457 | }, 1458 | { 1459 | "color": "green", 1460 | "value": 0.99 1461 | } 1462 | ] 1463 | }, 1464 | "unit": "percentunit" 1465 | }, 1466 | "overrides": [] 1467 | }, 1468 | "gridPos": { 1469 | "h": 7, 1470 | "w": 14, 1471 | "x": 4, 1472 | "y": 20 1473 | }, 1474 | "id": 100, 1475 | "options": { 1476 | "minVizHeight": 75, 1477 | "minVizWidth": 75, 1478 | "orientation": "auto", 1479 | "reduceOptions": { 1480 | "calcs": [ 1481 | "lastNotNull" 1482 | ], 1483 | "fields": "", 1484 | "values": false 1485 | }, 1486 | "showThresholdLabels": false, 1487 | "showThresholdMarkers": true, 1488 | "sizing": "auto" 1489 | }, 1490 | "pluginVersion": "10.4.0", 1491 | "targets": [ 1492 | { 1493 | "datasource": { 1494 | "type": "prometheus", 1495 | "uid": "prometheus" 1496 | }, 1497 | "editorMode": "code", 1498 | "expr": "(\n sum(increase(core_tracker_success_duties_total{job=\"charon\"}[$__range])) by (duty)\n) \n/ \n( \n sum(increase(core_tracker_expect_duties_total{job=\"charon\"}[$__range])) by (duty) \n) > 0", 1499 | "legendFormat": "__auto", 1500 | "range": true, 1501 | "refId": "A" 1502 | } 1503 | ], 1504 | "title": "Cluster Duty Success(%) ", 1505 | "type": "gauge" 1506 | }, 1507 | { 1508 | "datasource": { 1509 | "type": "prometheus", 1510 | "uid": "prometheus" 1511 | }, 1512 | "description": "Average beacon node score for the whole time window. The score is a combination of:\n - **errors**: the ratio or errors returned by the beacon node \n - **latency**: how fast or slow the beacon node is responding\n\n\nThe performance of the Beacon node is critical to the performance of the validators and therefore rewards. ", 1513 | "fieldConfig": { 1514 | "defaults": { 1515 | "color": { 1516 | "mode": "thresholds" 1517 | }, 1518 | "mappings": [], 1519 | "max": 1, 1520 | "min": 0, 1521 | "thresholds": { 1522 | "mode": "absolute", 1523 | "steps": [ 1524 | { 1525 | "color": "red", 1526 | "value": null 1527 | }, 1528 | { 1529 | "color": "orange", 1530 | "value": 0.5 1531 | }, 1532 | { 1533 | "color": "green", 1534 | "value": 0.8 1535 | } 1536 | ] 1537 | }, 1538 | "unit": "percentunit" 1539 | }, 1540 | "overrides": [] 1541 | }, 1542 | "gridPos": { 1543 | "h": 7, 1544 | "w": 6, 1545 | "x": 18, 1546 | "y": 20 1547 | }, 1548 | "id": 101, 1549 | "options": { 1550 | "minVizHeight": 75, 1551 | "minVizWidth": 75, 1552 | "orientation": "auto", 1553 | "reduceOptions": { 1554 | "calcs": [ 1555 | "lastNotNull" 1556 | ], 1557 | "fields": "", 1558 | "values": false 1559 | }, 1560 | "showThresholdLabels": false, 1561 | "showThresholdMarkers": true, 1562 | "sizing": "auto" 1563 | }, 1564 | "pluginVersion": "10.4.0", 1565 | "targets": [ 1566 | { 1567 | "datasource": { 1568 | "type": "prometheus", 1569 | "uid": "prometheus" 1570 | }, 1571 | "editorMode": "code", 1572 | "exemplar": false, 1573 | "expr": "(clamp(app_monitoring_readyz{job=\"charon\"} == 1 OR app_monitoring_readyz{job=\"charon\"} == 4 OR app_monitoring_readyz{job=\"charon\"} == 5 OR app_monitoring_readyz{job=\"charon\"} == 6, 1, 1) OR on() vector(0))\n*\n(\n (\n0.5 * (1.0 - 10*(sum(increase(app_eth2_errors_total{job=\"charon\"}[$__range])) / (sum(increase(app_eth2_latency_seconds_count{job=\"charon\"}[$__range]))))) OR on() vector(0.5)\n )\n +\n (\n 0.5 * (1.0 - clamp_max(histogram_quantile(0.99, sum(rate(app_eth2_latency_seconds_bucket{job=\"charon\"}[$__range])) by (le)),1))\n )\n)", 1574 | "instant": true, 1575 | "legendFormat": "__auto", 1576 | "range": false, 1577 | "refId": "A" 1578 | } 1579 | ], 1580 | "title": "Beacon Node Score", 1581 | "type": "gauge" 1582 | }, 1583 | { 1584 | "datasource": { 1585 | "type": "prometheus", 1586 | "uid": "prometheus" 1587 | }, 1588 | "description": "Information about the charon cluster.\n\n- **Network**: The blockchain network \n- **Operators/Nodes**: The number of operators or nodes or peers in the charon DV cluster.\n- **Threshold**: The minimum number of participating nodes (also quorum).\n- **Validators**: The number of validators added to the cluster, each validator is staking 32 ETH. ", 1589 | "fieldConfig": { 1590 | "defaults": { 1591 | "color": { 1592 | "mode": "thresholds" 1593 | }, 1594 | "mappings": [], 1595 | "thresholds": { 1596 | "mode": "absolute", 1597 | "steps": [ 1598 | { 1599 | "color": "text", 1600 | "value": null 1601 | } 1602 | ] 1603 | }, 1604 | "unit": "none" 1605 | }, 1606 | "overrides": [ 1607 | { 1608 | "matcher": { 1609 | "id": "byName", 1610 | "options": "Network" 1611 | }, 1612 | "properties": [ 1613 | { 1614 | "id": "mappings", 1615 | "value": [ 1616 | { 1617 | "options": { 1618 | "1": { 1619 | "color": "blue", 1620 | "index": 0, 1621 | "text": "Mainnet" 1622 | }, 1623 | "2": { 1624 | "color": "purple", 1625 | "index": 1, 1626 | "text": "Goerli" 1627 | }, 1628 | "3": { 1629 | "color": "purple", 1630 | "index": 2, 1631 | "text": "Sepolia" 1632 | }, 1633 | "4": { 1634 | "color": "purple", 1635 | "index": 3, 1636 | "text": "Gnosis" 1637 | } 1638 | }, 1639 | "type": "value" 1640 | } 1641 | ] 1642 | } 1643 | ] 1644 | } 1645 | ] 1646 | }, 1647 | "gridPos": { 1648 | "h": 4, 1649 | "w": 4, 1650 | "x": 0, 1651 | "y": 23 1652 | }, 1653 | "id": 96, 1654 | "options": { 1655 | "colorMode": "value", 1656 | "graphMode": "area", 1657 | "justifyMode": "auto", 1658 | "orientation": "horizontal", 1659 | "reduceOptions": { 1660 | "calcs": [ 1661 | "lastNotNull" 1662 | ], 1663 | "fields": "", 1664 | "values": false 1665 | }, 1666 | "showPercentChange": false, 1667 | "text": { 1668 | "titleSize": 15, 1669 | "valueSize": 15 1670 | }, 1671 | "textMode": "auto", 1672 | "wideLayout": true 1673 | }, 1674 | "pluginVersion": "10.4.0", 1675 | "targets": [ 1676 | { 1677 | "datasource": { 1678 | "type": "prometheus", 1679 | "uid": "prometheus" 1680 | }, 1681 | "editorMode": "code", 1682 | "exemplar": false, 1683 | "expr": "( 1 * app_version{job=\"charon\", cluster_network=\"mainnet\"} )\nor \n( 2 * app_version{job=\"charon\", cluster_network=\"goerli\"} )\nor\n( 3 * app_version{job=\"charon\", cluster_network=\"sepolia\"} )\nor\n( 4 * app_version{job=\"charon\", cluster_network=\"gnosis\"} )", 1684 | "format": "time_series", 1685 | "hide": false, 1686 | "instant": true, 1687 | "legendFormat": "Network", 1688 | "range": false, 1689 | "refId": "D" 1690 | }, 1691 | { 1692 | "datasource": { 1693 | "type": "prometheus", 1694 | "uid": "prometheus" 1695 | }, 1696 | "editorMode": "code", 1697 | "exemplar": false, 1698 | "expr": "cluster_operators{job=\"charon\"}", 1699 | "instant": true, 1700 | "legendFormat": "Operators/Nodes", 1701 | "range": false, 1702 | "refId": "A" 1703 | }, 1704 | { 1705 | "datasource": { 1706 | "type": "prometheus", 1707 | "uid": "prometheus" 1708 | }, 1709 | "editorMode": "code", 1710 | "exemplar": false, 1711 | "expr": "cluster_threshold{job=\"charon\"}", 1712 | "hide": false, 1713 | "instant": true, 1714 | "legendFormat": "Threshold", 1715 | "range": false, 1716 | "refId": "B" 1717 | }, 1718 | { 1719 | "datasource": { 1720 | "type": "prometheus", 1721 | "uid": "prometheus" 1722 | }, 1723 | "editorMode": "code", 1724 | "exemplar": false, 1725 | "expr": "core_scheduler_validators_active{job=\"charon\"}", 1726 | "hide": false, 1727 | "instant": true, 1728 | "legendFormat": "Validators Active", 1729 | "range": false, 1730 | "refId": "E" 1731 | }, 1732 | { 1733 | "datasource": { 1734 | "type": "prometheus", 1735 | "uid": "prometheus" 1736 | }, 1737 | "editorMode": "code", 1738 | "exemplar": false, 1739 | "expr": "cluster_validators{job=\"charon\"}", 1740 | "hide": false, 1741 | "instant": true, 1742 | "legendFormat": "Validators Total", 1743 | "range": false, 1744 | "refId": "C" 1745 | } 1746 | ], 1747 | "title": "Cluster Info", 1748 | "type": "stat" 1749 | }, 1750 | { 1751 | "datasource": { 1752 | "type": "prometheus", 1753 | "uid": "prometheus" 1754 | }, 1755 | "description": "- **Peer**: The peer's name (inferred from their *charon-enr-private-key*)\n- **You**: ⭐️ is this local charon node\n- **Connected**: Whether you are currently connected to this peer.\n- **Direct**: Whether the connection is *direct* (👍) or *relay* (👎) \n- **Latency**: The time messages take to travel to/from the peer.\n- **Version**: The version of the peer's charon node\n- **Supported**: Whether the peers charon version is supported/compatible or not.\n- **Uptime**\" The duration since peer was restarted.\n- **🚧Attest**: Number of attestation duties missed in the time window.\n- **🚧Propose**: Number of block proposal duties missed in the time window.\n- **🚧Other**: Number of other duties missed in the time window.\n\n", 1756 | "fieldConfig": { 1757 | "defaults": { 1758 | "color": { 1759 | "mode": "thresholds" 1760 | }, 1761 | "custom": { 1762 | "align": "center", 1763 | "cellOptions": { 1764 | "type": "auto" 1765 | }, 1766 | "inspect": false, 1767 | "minWidth": 0, 1768 | "width": 90 1769 | }, 1770 | "decimals": 0, 1771 | "mappings": [], 1772 | "noValue": "--", 1773 | "thresholds": { 1774 | "mode": "absolute", 1775 | "steps": [ 1776 | { 1777 | "color": "transparent", 1778 | "value": null 1779 | } 1780 | ] 1781 | } 1782 | }, 1783 | "overrides": [ 1784 | { 1785 | "matcher": { 1786 | "id": "byName", 1787 | "options": "Latency (ms)" 1788 | }, 1789 | "properties": [ 1790 | { 1791 | "id": "unit", 1792 | "value": "none" 1793 | }, 1794 | { 1795 | "id": "mappings", 1796 | "value": [ 1797 | { 1798 | "options": { 1799 | "from": 0, 1800 | "result": { 1801 | "color": "green", 1802 | "index": 0 1803 | }, 1804 | "to": 150 1805 | }, 1806 | "type": "range" 1807 | }, 1808 | { 1809 | "options": { 1810 | "from": 150, 1811 | "result": { 1812 | "color": "yellow", 1813 | "index": 1 1814 | }, 1815 | "to": 300 1816 | }, 1817 | "type": "range" 1818 | }, 1819 | { 1820 | "options": { 1821 | "from": 300, 1822 | "result": { 1823 | "color": "orange", 1824 | "index": 2 1825 | }, 1826 | "to": 500 1827 | }, 1828 | "type": "range" 1829 | }, 1830 | { 1831 | "options": { 1832 | "from": 500, 1833 | "result": { 1834 | "color": "red", 1835 | "index": 3 1836 | }, 1837 | "to": 100000 1838 | }, 1839 | "type": "range" 1840 | } 1841 | ] 1842 | }, 1843 | { 1844 | "id": "custom.cellOptions", 1845 | "value": { 1846 | "mode": "lcd", 1847 | "type": "gauge", 1848 | "valueDisplayMode": "color" 1849 | } 1850 | }, 1851 | { 1852 | "id": "custom.width", 1853 | "value": 200 1854 | }, 1855 | { 1856 | "id": "max", 1857 | "value": 700 1858 | } 1859 | ] 1860 | }, 1861 | { 1862 | "matcher": { 1863 | "id": "byName", 1864 | "options": "You" 1865 | }, 1866 | "properties": [ 1867 | { 1868 | "id": "noValue", 1869 | "value": "⭐" 1870 | }, 1871 | { 1872 | "id": "custom.cellOptions", 1873 | "value": { 1874 | "type": "auto" 1875 | } 1876 | }, 1877 | { 1878 | "id": "mappings", 1879 | "value": [ 1880 | { 1881 | "options": { 1882 | "0": { 1883 | "index": 0, 1884 | "text": "--" 1885 | }, 1886 | "1": { 1887 | "index": 1, 1888 | "text": "--" 1889 | } 1890 | }, 1891 | "type": "value" 1892 | } 1893 | ] 1894 | }, 1895 | { 1896 | "id": "custom.width", 1897 | "value": 60 1898 | } 1899 | ] 1900 | }, 1901 | { 1902 | "matcher": { 1903 | "id": "byName", 1904 | "options": "Connected" 1905 | }, 1906 | "properties": [ 1907 | { 1908 | "id": "mappings", 1909 | "value": [ 1910 | { 1911 | "options": { 1912 | "0": { 1913 | "index": 0, 1914 | "text": "❌" 1915 | }, 1916 | "1": { 1917 | "index": 1, 1918 | "text": "✅" 1919 | } 1920 | }, 1921 | "type": "value" 1922 | } 1923 | ] 1924 | } 1925 | ] 1926 | }, 1927 | { 1928 | "matcher": { 1929 | "id": "byName", 1930 | "options": "ClockDiff" 1931 | }, 1932 | "properties": [ 1933 | { 1934 | "id": "unit", 1935 | "value": "ms" 1936 | }, 1937 | { 1938 | "id": "mappings", 1939 | "value": [ 1940 | { 1941 | "options": { 1942 | "0": { 1943 | "index": 0, 1944 | "text": "🆗" 1945 | } 1946 | }, 1947 | "type": "value" 1948 | } 1949 | ] 1950 | } 1951 | ] 1952 | }, 1953 | { 1954 | "matcher": { 1955 | "id": "byName", 1956 | "options": "Direct" 1957 | }, 1958 | "properties": [ 1959 | { 1960 | "id": "custom.width", 1961 | "value": 55 1962 | }, 1963 | { 1964 | "id": "mappings", 1965 | "value": [ 1966 | { 1967 | "options": { 1968 | "0": { 1969 | "index": 0, 1970 | "text": "--" 1971 | } 1972 | }, 1973 | "type": "value" 1974 | }, 1975 | { 1976 | "options": { 1977 | "from": 1, 1978 | "result": { 1979 | "index": 1, 1980 | "text": "👎" 1981 | }, 1982 | "to": 9 1983 | }, 1984 | "type": "range" 1985 | }, 1986 | { 1987 | "options": { 1988 | "from": 10, 1989 | "result": { 1990 | "index": 2, 1991 | "text": "👍" 1992 | }, 1993 | "to": 1000 1994 | }, 1995 | "type": "range" 1996 | } 1997 | ] 1998 | } 1999 | ] 2000 | }, 2001 | { 2002 | "matcher": { 2003 | "id": "byName", 2004 | "options": "Peer" 2005 | }, 2006 | "properties": [ 2007 | { 2008 | "id": "custom.width", 2009 | "value": 150 2010 | } 2011 | ] 2012 | }, 2013 | { 2014 | "matcher": { 2015 | "id": "byName", 2016 | "options": "Uptime" 2017 | }, 2018 | "properties": [ 2019 | { 2020 | "id": "unit", 2021 | "value": "s" 2022 | } 2023 | ] 2024 | }, 2025 | { 2026 | "matcher": { 2027 | "id": "byName", 2028 | "options": "Index" 2029 | }, 2030 | "properties": [ 2031 | { 2032 | "id": "custom.width", 2033 | "value": 30 2034 | } 2035 | ] 2036 | }, 2037 | { 2038 | "matcher": { 2039 | "id": "byRegexp", 2040 | "options": "🚧.*" 2041 | }, 2042 | "properties": [ 2043 | { 2044 | "id": "unit", 2045 | "value": "percentunit" 2046 | }, 2047 | { 2048 | "id": "color", 2049 | "value": { 2050 | "fixedColor": "red", 2051 | "mode": "thresholds" 2052 | } 2053 | }, 2054 | { 2055 | "id": "custom.cellOptions", 2056 | "value": { 2057 | "type": "color-text" 2058 | } 2059 | }, 2060 | { 2061 | "id": "decimals", 2062 | "value": 1 2063 | }, 2064 | { 2065 | "id": "thresholds", 2066 | "value": { 2067 | "mode": "absolute", 2068 | "steps": [ 2069 | { 2070 | "color": "#585858", 2071 | "value": null 2072 | }, 2073 | { 2074 | "color": "super-light-green", 2075 | "value": 0.00001 2076 | }, 2077 | { 2078 | "color": "yellow", 2079 | "value": 0.01 2080 | }, 2081 | { 2082 | "color": "red", 2083 | "value": 0.1 2084 | } 2085 | ] 2086 | } 2087 | }, 2088 | { 2089 | "id": "noValue", 2090 | "value": "0%" 2091 | } 2092 | ] 2093 | }, 2094 | { 2095 | "matcher": { 2096 | "id": "byName", 2097 | "options": "Supported" 2098 | }, 2099 | "properties": [ 2100 | { 2101 | "id": "mappings", 2102 | "value": [ 2103 | { 2104 | "options": { 2105 | "0": { 2106 | "index": 0, 2107 | "text": "❌" 2108 | }, 2109 | "1": { 2110 | "index": 1, 2111 | "text": "🆗" 2112 | } 2113 | }, 2114 | "type": "value" 2115 | } 2116 | ] 2117 | } 2118 | ] 2119 | } 2120 | ] 2121 | }, 2122 | "gridPos": { 2123 | "h": 7, 2124 | "w": 24, 2125 | "x": 0, 2126 | "y": 27 2127 | }, 2128 | "id": 99, 2129 | "options": { 2130 | "cellHeight": "sm", 2131 | "footer": { 2132 | "countRows": false, 2133 | "fields": "", 2134 | "reducer": [ 2135 | "sum" 2136 | ], 2137 | "show": false 2138 | }, 2139 | "frameIndex": 0, 2140 | "showHeader": true, 2141 | "sortBy": [ 2142 | { 2143 | "desc": false, 2144 | "displayName": "You" 2145 | } 2146 | ] 2147 | }, 2148 | "pluginVersion": "10.4.0", 2149 | "targets": [ 2150 | { 2151 | "datasource": { 2152 | "type": "prometheus", 2153 | "uid": "prometheus" 2154 | }, 2155 | "editorMode": "code", 2156 | "exemplar": false, 2157 | "expr": "sum(p2p_ping_success{job=\"charon\"}) by (peer)", 2158 | "format": "table", 2159 | "instant": true, 2160 | "range": false, 2161 | "refId": "A" 2162 | }, 2163 | { 2164 | "datasource": { 2165 | "type": "prometheus", 2166 | "uid": "prometheus" 2167 | }, 2168 | "editorMode": "code", 2169 | "exemplar": false, 2170 | "expr": "histogram_quantile(0.90, sum(rate(p2p_ping_latency_secs_bucket{job=\"charon\"}[$__rate_interval])) by (le,peer)) * 1000", 2171 | "format": "table", 2172 | "hide": false, 2173 | "instant": true, 2174 | "range": false, 2175 | "refId": "B" 2176 | }, 2177 | { 2178 | "datasource": { 2179 | "type": "prometheus", 2180 | "uid": "prometheus" 2181 | }, 2182 | "editorMode": "code", 2183 | "exemplar": false, 2184 | "expr": "sum(p2p_ping_success{job=\"charon\"}) by (peer)", 2185 | "format": "table", 2186 | "hide": false, 2187 | "instant": true, 2188 | "legendFormat": "", 2189 | "range": false, 2190 | "refId": "F" 2191 | }, 2192 | { 2193 | "datasource": { 2194 | "type": "prometheus", 2195 | "uid": "prometheus" 2196 | }, 2197 | "editorMode": "code", 2198 | "exemplar": false, 2199 | "expr": "(max(p2p_peer_connection_types{job=\"charon\",type=\"direct\"}) by (peer)*10 + \nmax(p2p_peer_connection_types{job=\"charon\",type=\"relay\"}) by (peer))", 2200 | "format": "table", 2201 | "hide": false, 2202 | "instant": true, 2203 | "legendFormat": "", 2204 | "range": false, 2205 | "refId": "K" 2206 | }, 2207 | { 2208 | "datasource": { 2209 | "type": "prometheus", 2210 | "uid": "prometheus" 2211 | }, 2212 | "editorMode": "code", 2213 | "exemplar": false, 2214 | "expr": "sum(app_peerinfo_version{job=\"charon\"}) by (peer,version) ", 2215 | "format": "table", 2216 | "hide": false, 2217 | "instant": true, 2218 | "legendFormat": "__auto", 2219 | "range": false, 2220 | "refId": "L" 2221 | }, 2222 | { 2223 | "datasource": { 2224 | "type": "prometheus", 2225 | "uid": "prometheus" 2226 | }, 2227 | "editorMode": "code", 2228 | "exemplar": false, 2229 | "expr": "time() - max(app_peerinfo_start_time_secs{job=\"charon\"} > 0) by (peer)", 2230 | "format": "table", 2231 | "hide": false, 2232 | "instant": true, 2233 | "range": false, 2234 | "refId": "Q" 2235 | }, 2236 | { 2237 | "datasource": { 2238 | "type": "prometheus", 2239 | "uid": "prometheus" 2240 | }, 2241 | "editorMode": "code", 2242 | "exemplar": false, 2243 | "expr": "max(app_peerinfo_index{job=\"charon\"}) by (peer)", 2244 | "format": "table", 2245 | "hide": false, 2246 | "instant": true, 2247 | "range": false, 2248 | "refId": "R" 2249 | }, 2250 | { 2251 | "datasource": { 2252 | "type": "prometheus", 2253 | "uid": "prometheus" 2254 | }, 2255 | "editorMode": "code", 2256 | "exemplar": false, 2257 | "expr": "(\n sum(increase(core_tracker_participation_missed_total{job=\"charon\", duty=\"attester\"}[$__range])) by (peer) \n/\n sum(increase(core_tracker_participation_expected_total{job=\"charon\", duty=\"attester\"}[$__range])) by (peer) \n) OR on() vector(0)", 2258 | "format": "table", 2259 | "hide": false, 2260 | "instant": true, 2261 | "legendFormat": "__auto", 2262 | "range": false, 2263 | "refId": "C" 2264 | }, 2265 | { 2266 | "datasource": { 2267 | "type": "prometheus", 2268 | "uid": "prometheus" 2269 | }, 2270 | "editorMode": "code", 2271 | "exemplar": false, 2272 | "expr": "(\n sum(increase(core_tracker_participation_missed_total{job=\"charon\", duty=~\".*proposer\"}[$__range])) by (peer) \n/\n sum(increase(core_tracker_participation_expected_total{job=\"charon\", duty=~\".*proposer\"}[$__range])) by (peer) \n) OR on() vector(0)", 2273 | "format": "table", 2274 | "hide": false, 2275 | "instant": true, 2276 | "legendFormat": "__auto", 2277 | "range": false, 2278 | "refId": "D" 2279 | }, 2280 | { 2281 | "datasource": { 2282 | "type": "prometheus", 2283 | "uid": "prometheus" 2284 | }, 2285 | "editorMode": "code", 2286 | "exemplar": false, 2287 | "expr": "(\n sum(increase(core_tracker_participation_missed_total{job=\"charon\", duty!~\"(proposer|attester)\"}[$__range])) by (peer) \n/\n sum(increase(core_tracker_participation_expected_total{job=\"charon\", duty!~\"(proposer|attester)\"}[$__range])) by (peer) \n) OR on() vector(0)", 2288 | "format": "table", 2289 | "hide": false, 2290 | "instant": true, 2291 | "legendFormat": "__auto", 2292 | "range": false, 2293 | "refId": "E" 2294 | }, 2295 | { 2296 | "datasource": { 2297 | "type": "prometheus", 2298 | "uid": "prometheus" 2299 | }, 2300 | "editorMode": "code", 2301 | "exemplar": false, 2302 | "expr": "max(app_peerinfo_version_support{job=\"charon\"}) by (peer) ", 2303 | "format": "table", 2304 | "hide": false, 2305 | "instant": true, 2306 | "legendFormat": "", 2307 | "range": false, 2308 | "refId": "G" 2309 | } 2310 | ], 2311 | "title": "Peer Connectivity and Missed Duties (🚧)", 2312 | "transformations": [ 2313 | { 2314 | "id": "seriesToColumns", 2315 | "options": { 2316 | "byField": "peer" 2317 | } 2318 | }, 2319 | { 2320 | "id": "organize", 2321 | "options": { 2322 | "excludeByName": { 2323 | "Time 1": true, 2324 | "Time 10": true, 2325 | "Time 11": true, 2326 | "Time 12": true, 2327 | "Time 13": true, 2328 | "Time 14": true, 2329 | "Time 15": true, 2330 | "Time 16": true, 2331 | "Time 17": true, 2332 | "Time 2": true, 2333 | "Time 3": true, 2334 | "Time 4": true, 2335 | "Time 5": true, 2336 | "Time 6": true, 2337 | "Time 7": true, 2338 | "Time 8": true, 2339 | "Time 9": true, 2340 | "Value #F": false, 2341 | "Value #L": true, 2342 | "Value #M": true 2343 | }, 2344 | "indexByName": { 2345 | "Time 1": 9, 2346 | "Time 10": 22, 2347 | "Time 11": 23, 2348 | "Time 2": 11, 2349 | "Time 3": 12, 2350 | "Time 4": 13, 2351 | "Time 5": 14, 2352 | "Time 6": 15, 2353 | "Time 7": 16, 2354 | "Time 8": 17, 2355 | "Time 9": 21, 2356 | "Value #A": 3, 2357 | "Value #B": 5, 2358 | "Value #C": 18, 2359 | "Value #D": 19, 2360 | "Value #E": 20, 2361 | "Value #F": 2, 2362 | "Value #G": 7, 2363 | "Value #K": 4, 2364 | "Value #L": 10, 2365 | "Value #Q": 8, 2366 | "Value #R": 1, 2367 | "peer": 0, 2368 | "version": 6 2369 | }, 2370 | "renameByName": { 2371 | "Value #A": "Connected", 2372 | "Value #B": "Latency (ms)", 2373 | "Value #C": "🚧Attest", 2374 | "Value #D": "🚧Propose", 2375 | "Value #E": "🚧Other", 2376 | "Value #F": "You", 2377 | "Value #G": "Supported", 2378 | "Value #H": "Aggregate", 2379 | "Value #I": "Exit", 2380 | "Value #J": "ClockDiff", 2381 | "Value #K": "Direct", 2382 | "Value #L": "", 2383 | "Value #N": "SyncMsg", 2384 | "Value #O": "SyncContrib", 2385 | "Value #P": "PrepareContrib", 2386 | "Value #Q": "Uptime", 2387 | "Value #R": "Index", 2388 | "git_hash": "GitCommit", 2389 | "peer": "Peer", 2390 | "version": "Version" 2391 | } 2392 | } 2393 | } 2394 | ], 2395 | "type": "table" 2396 | }, 2397 | { 2398 | "collapsed": false, 2399 | "gridPos": { 2400 | "h": 1, 2401 | "w": 24, 2402 | "x": 0, 2403 | "y": 34 2404 | }, 2405 | "id": 50, 2406 | "panels": [], 2407 | "title": "Validator", 2408 | "type": "row" 2409 | }, 2410 | { 2411 | "datasource": { 2412 | "type": "prometheus", 2413 | "uid": "prometheus" 2414 | }, 2415 | "description": "A lodestar validator client serving as part of this distributed validator cluster.", 2416 | "fieldConfig": { 2417 | "defaults": { 2418 | "color": { 2419 | "mode": "thresholds" 2420 | }, 2421 | "mappings": [], 2422 | "thresholds": { 2423 | "mode": "absolute", 2424 | "steps": [ 2425 | { 2426 | "color": "green", 2427 | "value": null 2428 | }, 2429 | { 2430 | "color": "red", 2431 | "value": 80 2432 | } 2433 | ] 2434 | } 2435 | }, 2436 | "overrides": [] 2437 | }, 2438 | "gridPos": { 2439 | "h": 1, 2440 | "w": 24, 2441 | "x": 0, 2442 | "y": 35 2443 | }, 2444 | "id": 36, 2445 | "options": { 2446 | "colorMode": "none", 2447 | "graphMode": "none", 2448 | "justifyMode": "auto", 2449 | "orientation": "auto", 2450 | "reduceOptions": { 2451 | "calcs": [ 2452 | "lastNotNull" 2453 | ], 2454 | "fields": "", 2455 | "values": false 2456 | }, 2457 | "showPercentChange": false, 2458 | "textMode": "none", 2459 | "wideLayout": true 2460 | }, 2461 | "pluginVersion": "10.4.0", 2462 | "targets": [ 2463 | { 2464 | "datasource": { 2465 | "type": "prometheus", 2466 | "uid": "prometheus" 2467 | }, 2468 | "editorMode": "code", 2469 | "expr": "1", 2470 | "legendFormat": "__auto", 2471 | "range": true, 2472 | "refId": "A" 2473 | } 2474 | ], 2475 | "title": "LODESTAR", 2476 | "type": "stat" 2477 | }, 2478 | { 2479 | "datasource": { 2480 | "type": "prometheus", 2481 | "uid": "prometheus" 2482 | }, 2483 | "fieldConfig": { 2484 | "defaults": { 2485 | "color": { 2486 | "mode": "thresholds" 2487 | }, 2488 | "mappings": [ 2489 | { 2490 | "options": { 2491 | "match": "null", 2492 | "result": { 2493 | "text": "N/A" 2494 | } 2495 | }, 2496 | "type": "special" 2497 | } 2498 | ], 2499 | "thresholds": { 2500 | "mode": "absolute", 2501 | "steps": [ 2502 | { 2503 | "color": "#F2495C", 2504 | "value": null 2505 | }, 2506 | { 2507 | "color": "rgba(237, 129, 40, 0.89)", 2508 | "value": 0 2509 | }, 2510 | { 2511 | "color": "#299c46", 2512 | "value": 1 2513 | } 2514 | ] 2515 | }, 2516 | "unit": "none" 2517 | }, 2518 | "overrides": [] 2519 | }, 2520 | "gridPos": { 2521 | "h": 4, 2522 | "w": 6, 2523 | "x": 0, 2524 | "y": 36 2525 | }, 2526 | "id": 25, 2527 | "maxDataPoints": 100, 2528 | "options": { 2529 | "colorMode": "none", 2530 | "graphMode": "none", 2531 | "justifyMode": "auto", 2532 | "orientation": "horizontal", 2533 | "reduceOptions": { 2534 | "calcs": [ 2535 | "lastNotNull" 2536 | ], 2537 | "fields": "", 2538 | "values": false 2539 | }, 2540 | "showPercentChange": false, 2541 | "textMode": "auto", 2542 | "wideLayout": true 2543 | }, 2544 | "pluginVersion": "10.4.0", 2545 | "targets": [ 2546 | { 2547 | "datasource": { 2548 | "type": "prometheus", 2549 | "uid": "prometheus" 2550 | }, 2551 | "editorMode": "code", 2552 | "expr": "vc_indices_count", 2553 | "interval": "", 2554 | "legendFormat": "", 2555 | "range": true, 2556 | "refId": "A" 2557 | } 2558 | ], 2559 | "title": "Number of validators", 2560 | "type": "stat" 2561 | }, 2562 | { 2563 | "datasource": { 2564 | "type": "prometheus", 2565 | "uid": "prometheus" 2566 | }, 2567 | "fieldConfig": { 2568 | "defaults": { 2569 | "color": { 2570 | "fixedColor": "yellow", 2571 | "mode": "thresholds" 2572 | }, 2573 | "mappings": [], 2574 | "thresholds": { 2575 | "mode": "absolute", 2576 | "steps": [ 2577 | { 2578 | "color": "semi-dark-blue", 2579 | "value": null 2580 | }, 2581 | { 2582 | "color": "semi-dark-green", 2583 | "value": 0 2584 | } 2585 | ] 2586 | } 2587 | }, 2588 | "overrides": [ 2589 | { 2590 | "matcher": { 2591 | "id": "byName", 2592 | "options": "ERROR" 2593 | }, 2594 | "properties": [ 2595 | { 2596 | "id": "thresholds", 2597 | "value": { 2598 | "mode": "absolute", 2599 | "steps": [ 2600 | { 2601 | "color": "green", 2602 | "value": null 2603 | }, 2604 | { 2605 | "color": "red", 2606 | "value": 1 2607 | } 2608 | ] 2609 | } 2610 | } 2611 | ] 2612 | } 2613 | ] 2614 | }, 2615 | "gridPos": { 2616 | "h": 4, 2617 | "w": 6, 2618 | "x": 6, 2619 | "y": 36 2620 | }, 2621 | "id": 29, 2622 | "options": { 2623 | "colorMode": "background", 2624 | "graphMode": "none", 2625 | "justifyMode": "auto", 2626 | "orientation": "auto", 2627 | "reduceOptions": { 2628 | "calcs": [ 2629 | "last" 2630 | ], 2631 | "fields": "", 2632 | "values": false 2633 | }, 2634 | "showPercentChange": false, 2635 | "textMode": "auto", 2636 | "wideLayout": true 2637 | }, 2638 | "pluginVersion": "10.4.0", 2639 | "targets": [ 2640 | { 2641 | "datasource": { 2642 | "type": "prometheus", 2643 | "uid": "prometheus" 2644 | }, 2645 | "editorMode": "code", 2646 | "expr": "vc_published_attestations_total", 2647 | "interval": "", 2648 | "legendFormat": "{{outcome}}", 2649 | "range": true, 2650 | "refId": "A" 2651 | } 2652 | ], 2653 | "title": "Attestations Published", 2654 | "type": "stat" 2655 | }, 2656 | { 2657 | "datasource": { 2658 | "type": "prometheus", 2659 | "uid": "prometheus" 2660 | }, 2661 | "fieldConfig": { 2662 | "defaults": { 2663 | "color": { 2664 | "fixedColor": "dark-yellow", 2665 | "mode": "thresholds" 2666 | }, 2667 | "mappings": [], 2668 | "thresholds": { 2669 | "mode": "absolute", 2670 | "steps": [ 2671 | { 2672 | "color": "red", 2673 | "value": null 2674 | }, 2675 | { 2676 | "color": "blue", 2677 | "value": 0 2678 | }, 2679 | { 2680 | "color": "blue", 2681 | "value": 1 2682 | } 2683 | ] 2684 | } 2685 | }, 2686 | "overrides": [] 2687 | }, 2688 | "gridPos": { 2689 | "h": 4, 2690 | "w": 6, 2691 | "x": 12, 2692 | "y": 36 2693 | }, 2694 | "id": 30, 2695 | "options": { 2696 | "colorMode": "background", 2697 | "graphMode": "none", 2698 | "justifyMode": "auto", 2699 | "orientation": "auto", 2700 | "reduceOptions": { 2701 | "calcs": [ 2702 | "last" 2703 | ], 2704 | "fields": "", 2705 | "values": false 2706 | }, 2707 | "showPercentChange": false, 2708 | "textMode": "auto", 2709 | "wideLayout": true 2710 | }, 2711 | "pluginVersion": "10.4.0", 2712 | "targets": [ 2713 | { 2714 | "datasource": { 2715 | "type": "prometheus", 2716 | "uid": "prometheus" 2717 | }, 2718 | "editorMode": "code", 2719 | "expr": "vc_block_published_total", 2720 | "interval": "", 2721 | "legendFormat": "", 2722 | "range": true, 2723 | "refId": "A" 2724 | } 2725 | ], 2726 | "title": "Blocks Published", 2727 | "type": "stat" 2728 | }, 2729 | { 2730 | "datasource": { 2731 | "type": "prometheus", 2732 | "uid": "prometheus" 2733 | }, 2734 | "fieldConfig": { 2735 | "defaults": { 2736 | "color": { 2737 | "fixedColor": "yellow", 2738 | "mode": "thresholds" 2739 | }, 2740 | "mappings": [], 2741 | "thresholds": { 2742 | "mode": "absolute", 2743 | "steps": [ 2744 | { 2745 | "color": "semi-dark-blue", 2746 | "value": null 2747 | }, 2748 | { 2749 | "color": "purple", 2750 | "value": 0 2751 | } 2752 | ] 2753 | } 2754 | }, 2755 | "overrides": [ 2756 | { 2757 | "matcher": { 2758 | "id": "byName", 2759 | "options": "ERROR" 2760 | }, 2761 | "properties": [ 2762 | { 2763 | "id": "thresholds", 2764 | "value": { 2765 | "mode": "absolute", 2766 | "steps": [ 2767 | { 2768 | "color": "green", 2769 | "value": null 2770 | }, 2771 | { 2772 | "color": "red", 2773 | "value": 1 2774 | } 2775 | ] 2776 | } 2777 | } 2778 | ] 2779 | } 2780 | ] 2781 | }, 2782 | "gridPos": { 2783 | "h": 4, 2784 | "w": 6, 2785 | "x": 18, 2786 | "y": 36 2787 | }, 2788 | "id": 94, 2789 | "options": { 2790 | "colorMode": "background", 2791 | "graphMode": "none", 2792 | "justifyMode": "auto", 2793 | "orientation": "auto", 2794 | "reduceOptions": { 2795 | "calcs": [ 2796 | "last" 2797 | ], 2798 | "fields": "", 2799 | "values": false 2800 | }, 2801 | "showPercentChange": false, 2802 | "textMode": "auto", 2803 | "wideLayout": true 2804 | }, 2805 | "pluginVersion": "10.4.0", 2806 | "targets": [ 2807 | { 2808 | "datasource": { 2809 | "type": "prometheus", 2810 | "uid": "prometheus" 2811 | }, 2812 | "editorMode": "code", 2813 | "expr": "vc_published_aggregates_total", 2814 | "interval": "", 2815 | "legendFormat": "{{outcome}}", 2816 | "range": true, 2817 | "refId": "A" 2818 | } 2819 | ], 2820 | "title": "Aggregate Attestations Published", 2821 | "type": "stat" 2822 | } 2823 | ], 2824 | "refresh": "10s", 2825 | "revision": 1, 2826 | "schemaVersion": 39, 2827 | "tags": [], 2828 | "templating": { 2829 | "list": [] 2830 | }, 2831 | "time": { 2832 | "from": "now-1h", 2833 | "to": "now" 2834 | }, 2835 | "timepicker": { 2836 | "refresh_intervals": [ 2837 | "5s", 2838 | "10s", 2839 | "30s", 2840 | "1m", 2841 | "5m", 2842 | "15m", 2843 | "30m", 2844 | "1h", 2845 | "2h", 2846 | "1d" 2847 | ] 2848 | }, 2849 | "timezone": "", 2850 | "title": "Single Charon Node Dashboard", 2851 | "uid": "singlenode", 2852 | "version": 2, 2853 | "weekStart": "" 2854 | } 2855 | --------------------------------------------------------------------------------