Add a Zagros Asset Hub history indexer for the explorer host (#32)

The explorer at explorer.pezkuwichain.io needs transfer history for Zagros
Asset Hub. It runs on the explorer host next to its own archive node, so the
manifest points at 127.0.0.1:9955 and the compose file binds everything
locally with memory limits and no published ports.

deploy-vps now ignores these files: a change to the Zagros indexer must not
rebuild or restart the mainnet stack and its bots on the indexer host.
This commit is contained in:
SatoshiQaziMuhammed authored and GitHub committed 2026-10-24 15:32:32 +04:00
1 parent dfa2527451
commit af7a0b4d6f
5 files changed
+225

No files matched your search

+5
View File
@@ -2,6 +2,11 @@ name: Deploy to VPS
on:
push:
branches: [main]
# The Zagros history indexer runs on the explorer host, not here.
paths-ignore:
- zagros-assethub.yaml
- docker-compose.zagros.yml
- ops/zagros/**
concurrency:
group: deploy-vps
+1
View File
@@ -32,3 +32,4 @@ secrets/
# SubQuery
.data/
project.yaml
.env.zagros
+82
View File
@@ -0,0 +1,82 @@
# Zagros Asset Hub history for explorer.pezkuwichain.io.
#
# Runs on the explorer host next to its own archive node (systemd unit
# zagros-ah-archive, RPC on 127.0.0.1:9955), never on the mainnet indexer host:
# deploy-vps ignores this file and zagros-assethub.yaml.
#
# Everything uses the host network. Postgres binds 127.0.0.1; subql-node (3101)
# and subql-query (3100) cannot be told to, so the host firewall (default deny,
# only 22/80/443 open) keeps them local. Docker would bypass that firewall for
# published ports, so nothing is published.
# nginx exposes only POST /history/assethub (same origin as the explorer).
#
# printf 'ZAGROS_DB_PASS=%s\n' "$(openssl rand -hex 24)" > .env.zagros && chmod 600 .env.zagros
# docker compose -f docker-compose.zagros.yml --env-file .env.zagros up -d
#
# The mapping in dist/ must be built first (see ops/zagros/README.md).
name: zagros-history
services:
postgres:
image: postgres:16-alpine
network_mode: host
command: ["postgres", "-c", "listen_addresses=127.0.0.1", "-c", "port=5433"]
volumes:
- zagros-pgdata:/var/lib/postgresql/data
- ./docker/init:/docker-entrypoint-initdb.d
environment:
POSTGRES_PASSWORD: ${ZAGROS_DB_PASS:?set ZAGROS_DB_PASS in .env.zagros}
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -h 127.0.0.1 -p 5433"]
interval: 5s
timeout: 5s
retries: 10
mem_limit: 1g
restart: unless-stopped
subquery-node-assethub:
build:
context: .
dockerfile: docker/Dockerfile.node
network_mode: host
depends_on:
postgres: { condition: service_healthy }
environment:
TZ: UTC
DB_USER: postgres
DB_PASS: ${ZAGROS_DB_PASS:?set ZAGROS_DB_PASS in .env.zagros}
DB_DATABASE: postgres
DB_HOST: 127.0.0.1
DB_PORT: 5433
volumes:
- ./:/app/project:ro
command:
- -f=/app/project/zagros-assethub.yaml
- --db-schema=subquery-zagros-assethub
- --disable-historical=true
- --batch-size=30
- --port=3101
mem_limit: 1g
restart: unless-stopped
graphql-engine-assethub:
image: onfinality/subql-query:v1.5.0
network_mode: host
depends_on:
- subquery-node-assethub
environment:
DB_USER: postgres
DB_PASS: ${ZAGROS_DB_PASS:?set ZAGROS_DB_PASS in .env.zagros}
DB_DATABASE: postgres
DB_HOST: 127.0.0.1
DB_PORT: 5433
command:
- --name=subquery-zagros-assethub
- --indexer=http://127.0.0.1:3101
- --port=3100
- --query-limit=100
mem_limit: 512m
restart: unless-stopped
volumes:
zagros-pgdata:
+38
View File
@@ -0,0 +1,38 @@
# Zagros Asset Hub history (explorer host)
Serves `HistoryElement` for Zagros Asset Hub to explorer.pezkuwichain.io. It
runs on the explorer host next to its own archive node, never on the mainnet
indexer host (`deploy-vps` ignores `zagros-assethub.yaml`,
`docker-compose.zagros.yml` and this directory).
## Pieces
| piece | where | listens |
|---|---|---|
| archive node `zagros-ah-archive` (systemd, `--state-pruning archive --blocks-pruning archive`, relay followed over RPC) | host | RPC 127.0.0.1:9955 |
| postgres 16 | compose | 127.0.0.1:5433 |
| subql-node, `zagros-assethub.yaml` | compose | 3101 (firewalled) |
| subql-query | compose | 3100 (firewalled); nginx exposes `POST /history/assethub` only |
## Build and start
```sh
git clone https://github.com/pezkuwichain/pezkuwi-subquery /opt/zagros-history
cd /opt/zagros-history
# Build the mapping (dist/) without installing Node on the host.
docker run --rm -v "$PWD":/w -w /w node:24-alpine sh -c \
'corepack enable && yarn install --immutable && yarn subql codegen zagros-assethub.yaml && yarn subql build zagros-assethub.yaml'
printf 'ZAGROS_DB_PASS=%s\n' "$(openssl rand -hex 24)" > .env.zagros && chmod 600 .env.zagros
docker compose -f docker-compose.zagros.yml --env-file .env.zagros up -d --build
```
## Check
```sh
curl -s -X POST 127.0.0.1:3100 -H 'content-type: application/json' \
-d '{"query":"{_metadata{lastProcessedHeight targetHeight}}"}'
```
`targetHeight - lastProcessedHeight` above 100 for ten minutes means the
indexer has stalled; the explorer then shows "on its way" for payments it has
not seen yet.
+99
View File
@@ -0,0 +1,99 @@
specVersion: 1.0.0
name: subquery-zagros-assethub
version: 1.0.0
runner:
node:
name: "@subql/node"
version: ">=4.6.6"
query:
name: "@subql/query"
version: "*"
description: Zagros Asset Hub SubQuery - history for explorer.pezkuwichain.io (same handlers as pezkuwi-assethub.yaml)
repository: https://github.com/pezkuwichain/pezkuwi-subquery
schema:
file: ./schema.graphql
network:
chainId: "0x063f739077881df9f291548de301b2e11d6a45cc545c24e7bf18d8a40f0ce182"
endpoint:
- ws://127.0.0.1:9955
dataSources:
- name: main
kind: substrate/Runtime
startBlock: 1
mapping:
file: ./dist/index.js
handlers:
# Block handler: initialize active pool stakers from chain state
- handler: handleBlock
kind: substrate/BlockHandler
# Signed extrinsics for history
- handler: handleHistoryElement
kind: substrate/CallHandler
filter:
isSigned: true
# Nomination Pools rewards
- handler: handlePoolReward
kind: substrate/EventHandler
filter:
module: nominationPools
method: PaidOut
# Pool member bonded (track active stakers)
- handler: handlePoolBonded
kind: substrate/EventHandler
filter:
module: nominationPools
method: Bonded
# Pool member unbonded (cleanup active stakers)
- handler: handlePoolUnbonded
kind: substrate/EventHandler
filter:
module: nominationPools
method: Unbonded
# Pool bonded slash
- handler: handlePoolBondedSlash
kind: substrate/EventHandler
filter:
module: nominationPools
method: PoolSlashed
# Pool unbonding slash
- handler: handlePoolUnbondingSlash
kind: substrate/EventHandler
filter:
module: nominationPools
method: UnbondingPoolSlashed
# Staking rewards on AH (validators + direct nominators)
- handler: handleAHRewarded
kind: substrate/EventHandler
filter:
module: staking
method: Rewarded
# Staking slashes on AH
- handler: handleAHSlashed
kind: substrate/EventHandler
filter:
module: staking
method: Slashed
# Era changes on AH (staking pallet lives here) - old format
- handler: handleAHNewEra
kind: substrate/EventHandler
filter:
module: staking
method: StakingElection
# Era changes on AH - new format (Polkadot 2.0)
- handler: handleAHStakersElected
kind: substrate/EventHandler
filter:
module: staking
method: StakersElected
# Native transfers
- handler: handleTransfer
kind: substrate/EventHandler
filter:
module: balances
method: Transfer
# Asset transfers
- handler: handleAssetTransfer
kind: substrate/EventHandler
filter:
module: assets
method: Transferred