Real-time validator monitoring for Gno.land (TM2) networks.
Hard fork of Tenderduty by blockpane, rewritten for Gno.land's Tendermint2 (TM2) architecture.
Tenderduty was designed for Cosmos SDK / Tendermint chains. Gno.land uses Tendermint2 (TM2), which has a different RPC response format, different validator address handling, and no WebSocket subscription support on public endpoints.
GnoDuty solves this by:
- Parsing TM2 block format (
precommitsinstead ofsignatures) - Using HTTP polling instead of WebSocket subscriptions
- Supporting bech32
g1...validator addresses natively - Querying TM2-specific endpoints (
/validators,/block)
- Real-time block monitoring - Track block signing with visual canvas display
- Validator status - Bonded, jailed, tombstoned, missed blocks, uptime percentage
- Multi-chain support - Monitor multiple Gno.land networks from a single instance
- Alert notifications - Discord, Telegram, Slack, PagerDuty
- Web dashboard - Dark theme, responsive, real-time updates
- Prometheus exporter - Metrics for Grafana integration
- Light/Dark mode - Toggle from the dashboard footer
- Go 1.21 or later (tested with 1.26)
- Linux (tested on Ubuntu 24.04)
- Ports 8889 (dashboard) and 28687 (Prometheus) must be open
If you use UFW, open the required ports before starting:
sudo ufw allow 8889/tcp comment "GnoDuty Dashboard"
sudo ufw allow 28687/tcp comment "GnoDuty Prometheus"A dedicated system user improves security by isolating GnoDuty from other services. Run this from your regular user account (with sudo access):
sudo useradd -r -s /bin/false -m -d /var/lib/gnoduty gnodutysudo -u gnoduty bash -c 'cd ~ && git clone https://github.com/AviaOne/gnoduty && cd gnoduty && go install'sudo -u gnoduty mkdir -p /var/lib/gnoduty/.gnoduty
sudo -u gnoduty cp /var/lib/gnoduty/gnoduty/example-config.yml /var/lib/gnoduty/.gnoduty/config.ymlEdit the configuration file:
sudo -u gnoduty nano /var/lib/gnoduty/.gnoduty/config.ymlThe most important settings to change:
chains:
# Display name shown on the dashboard (can be anything)
"Gno.land (test11)":
# Must match the chain ID from the RPC /status endpoint
chain_id: test11
# Your validator address in bech32 format (g1...)
valoper_address: g1_YOUR_VALIDATOR_ADDRESS
nodes:
- url: https://rpc.test11.testnets.gno.land:443
alert_if_down: yesTo verify your chain_id:
curl -s https://rpc.test11.testnets.gno.land/status | python3 -c "import json,sys; print(json.load(sys.stdin)['result']['node_info']['network'])"See example-config.yml for a complete configuration reference with all options.
GnoDuty supports alerts via Telegram, Discord, Slack, and PagerDuty when your validator misses blocks, goes offline, or gets jailed.
Important: Both global AND per-chain alert settings must be enabled. If either is disabled, no alerts will be sent.
Global settings (top of config.yml):
telegram:
enabled: yes
api_key: 'YOUR_BOT_API_KEY'
channel: "-YOUR_CHANNEL_ID"Per-chain settings (inside each chain's alerts: section):
alerts:
# ... alert thresholds ...
telegram:
enabled: yes
api_key: "" # leave empty to use global settings
channel: "" # leave empty to use global settingsIf the per-chain section is missing or enabled: no, alerts will NOT be sent for that chain even if the global setting is enabled.
Create /etc/systemd/system/gnoduty.service:
[Unit]
Description=GnoDuty - Gno.land Validator Monitor
After=network-online.target
Wants=network-online.target
[Service]
User=gnoduty
Group=gnoduty
Type=simple
WorkingDirectory=/var/lib/gnoduty/.gnoduty
ExecStart=/var/lib/gnoduty/go/bin/gnoduty -f /var/lib/gnoduty/.gnoduty/config.yml
Restart=always
RestartSec=5
LimitNOFILE=65535
[Install]
WantedBy=multi-user.targetsudo systemctl daemon-reload
sudo systemctl enable --now gnodutyThe dashboard will be available at http://YOUR_SERVER_IP:8889
# Start
sudo systemctl start gnoduty
# Stop
sudo systemctl stop gnoduty
# Restart
sudo systemctl restart gnoduty
# Status
sudo systemctl status gnoduty
# Live logs
sudo journalctl -u gnoduty --no-hostname -f- Docker and Docker Compose installed
- Ports 8889 (dashboard) and 28687 (Prometheus) must be open
mkdir gnoduty && cd gnoduty
git clone https://github.com/AviaOne/gnoduty .cp example-config.yml config.yml
cp example-docker-compose.yml docker-compose.ymlEdit config.yml with your validator address, RPC endpoint, and alert settings (see the "Configure alerts" section above).
docker-compose up -d
docker-compose logs -f --tail 20The dashboard will be available at http://YOUR_SERVER_IP:8889
# Stop
docker-compose down
# Restart
docker-compose restart
# View logs
docker-compose logs -f --tail 20
# Rebuild after update
docker-compose up -d --buildGnoDuty accepts command-line flags to override default file paths. This is useful if you want to store configuration or state files in custom locations:
$ gnoduty -h
Usage of gnoduty:
-f string
configuration file to use (default "config.yml")
-state string
file for storing state between restarts (default ".gnoduty-state.json")
-cc string
directory containing additional chain specific configurations (default "chains.d")
For validators with many chains, chain-specific configuration may be split into additional files and placed in the chains.d directory. This directory can be changed with the -cc option.
The user-friendly chain label will be taken from the name of the file:
chains.d/GnoMainnet.yml→ GnoMainnetchains.d/GnoTestnet.yml→ GnoTestnet
Configuration inside chains.d/Network.yml should be the YAML content starting directly with the chain details (without the outer chains: label):
chain_id: test11
valoper_address: g1_YOUR_VALIDATOR_ADDRESS
nodes:
- url: https://rpc.test11.testnets.gno.land:443
alert_if_down: yesGnoDuty is a hard fork with significant modifications to support Gno.land's TM2:
| Component | Tenderduty (Cosmos SDK) | GnoDuty (Gno.land TM2) |
|---|---|---|
| Block data | signatures field |
precommits field |
| Connectivity | WebSocket subscriptions | HTTP polling (5s interval) |
| Validator address | Hex / valoper | Bech32 g1... |
| Validator lookup | ABCI queries | /validators RPC endpoint |
| Signing check | last_commit.signatures |
last_commit.precommits |
Fork statistics:
- 2 new files created (462 lines) - TM2 polling engine and validator provider, written from scratch
- 8 files significantly rewritten (1,894 → 976 lines) - Over 900 lines removed and replaced with TM2-compatible code
- 20+ files removed - Cosmos SDK documentation, Docker configs, and assets replaced
- Directory restructured -
td2/→core/, full module path rewrite - ~40% of the original codebase was rewritten or removed
- 60% unchanged - Alert system, Prometheus, encryption, and dashboard inherited from Tenderduty
See CHANGELOG.md for a detailed breakdown of every file created, modified, and removed.
- Original: Tenderduty v2 by Todd G (blockpane), sponsored by the Osmosis Grants Program
- Fork: GnoDuty by AviaOne.com Adapted for Gno.land TM2.
The original Tenderduty project was developed with a $10,000 grant from the Osmosis Grants Program. GnoDuty is currently maintained only by AviaOne.com contribution with no funding or sponsorship.
While we strive for quality, we cannot guarantee the same level of support as a funded project. If you encounter bugs, please open an issue on GitHub, we will do our best to address them.
MIT License - See LICENSE for details.
Original © 2021 Todd G (blockpane) | Fork © 2026 AviaOne.com
