Operator tools and monitoring scripts for DigiByte DigiDollar Oracle nodes.
Maintained by digibyte-maxi (Oracle Slot 17) — see contact at the bottom.
| File | Purpose |
|---|---|
| oracle-monitor.sh | Bash health monitor v2.6.3 — 12 checks (daemon, oracle, chain sync, peers, consensus price, disk, memory, swap pressure, service status, version, NTP, quorum margin). Dual-channel alerts: Discord webhook + email (v2.6.0, closes #17) fire on the same red/yellow/green triggers plus the 12-hour summary. Email via curl SMTP (built into stock Ubuntu — no mailx/postfix/sendmail), config-driven with EMAIL_ENABLED, EMAIL_TO, SMTP_SERVER/PORT/USER/PASS/FROM, subjects prefixed with [ALERT]/[WARNING]/[RESOLVED]/[INFO] plus NETWORK_LABEL, --test-email flag with inline diagnostics. Auto update-check (v2.6.0) fetches the published script header from GitHub main once per day, silently adds a ⬆️ vX.Y.Z available footer line to every Discord card and email when a newer version exists. Quorum tracking via getdigidollardeploymentinfo + getoracles with MuSig2 session health. Counts online oracles by heartbeat (stable across round transitions). Anti-flap: cooldown timer + hysteresis buffer prevent alert spam during volatile periods. --config /path for dual-instance monitoring (testnet + mainnet). DigiDollar BIP9 pre-activation guard downgrades oracle checks to standby INFO before activation. Auto-detects either digibyted (headless) or digibyte-qt (Qt wallet) so operators running either binary get correct alerts. Card titles carry NETWORK_LABEL, footer stamps monitor version + oracle identity. Disk line shows free/total/used%; the Low Disk alert names your configurable DATADIR so you know exactly where to clean up (v2.5.5). MuSig2 line carries its own ✅/ℹ️/ℹ️ DigiByte: v9.26.4 instead of ℹ️ /DigiByte:9.26.4/), switches the email Time: line to UTC for operators on VPS in different timezones than their home, and pressure-gates the swap alert so a stale swap fill left over from a past reindex no longer fires a false red (only alerts on real current pressure via Linux PSI or a RAM-headroom threshold). v2.6.3 makes the version line update-aware — ✅ green when running the latest DigiByte Core release, ℹ️ blue — vX.Y.Z available when a newer release is out (GitHub releases/latest, cached daily) — and adds a SERVICE_NAME="none" escape hatch for operators running headless without systemd. External config file, --dry-run mode, jq-based JSON parsing. State files prevent repeat alerts. |
| oracle-network-status.sh | Gitter network status bot v1.6.5 — posts automated oracle network health summaries to the DigiDollar Gitter channel every 12 hours via Matrix API. See file for full description. |
| oracle-roster.template | Template for the oracle-to-Gitter-handle mapping file used by the @ mention feature. Copy to ~/.oracle-monitor/oracle-roster.conf and populate with real Matrix IDs. The populated file stays on VPS only — never push to GitHub. |
| config.template | Configuration template for oracle-monitor.sh and oracle-network-status.sh. Copy to ~/.oracle-monitor/config and set your oracle ID, webhook URL, alert thresholds, quorum margin thresholds, anti-flap settings, network label, and Matrix API credentials for the Gitter bot. v2.6.0 additions: email SMTP settings (Gmail App Password and Outlook examples; Brevo relay walkthrough in CROSS_PLATFORM_SETUP.md), update-check toggle + TTL. |
| ORACLE_SETUP_QUICKSTART.md | Quick-start checklist for new oracle operators. Covers download, config, key generation, and posting to Gitter. |
| ORACLE_SETUP_TUTORIAL.md | Full step-by-step tutorial for all platforms (Linux, Windows, macOS). Posted by shenger in the DigiDollar Gitter community. |
| ORACLE_HARDENING_GUIDE.md | VPS security hardening guide v1.4.1 — SSH, UFW, Fail2Ban, kernel hardening, systemd, resource isolation and OOM protection. Step-by-step, based on my live oracle setup. |
| HOME_ORACLE_HARDENING_GUIDE.md | Home network security hardening guide — Linux, Windows, macOS. Three tiers (Essential, Recommended, Advanced). Covers firewall, port forwarding, NTP, router hardening, UPS, VLANs, WireGuard. Network diagrams: Tier 1 · Tier 2 · Tier 3. Community-requested by Aussie Epic. |
| oracle-monitor.ps1 | Windows PowerShell port v2.6.3-win.1 — full logic parity with Linux v2.6.3, including the v2.6.0 email + auto update-check features, the v2.6.1 cosmetic spacing fix, the v2.6.2 version-line cleanup + UTC email timestamp + pressure-gated swap alert, and the v2.6.3 update-aware DigiByte version line + SERVICE_NAME="none" escape hatch. PS 5.1 and PS 7 compatible, zero external dependencies (native JSON parsing, .NET's built-in System.Net.Mail.SmtpClient for email). Includes watch mode (-Watch), -Config for dual-instance monitoring, and -TestEmail for SMTP diagnostics. Ships UTF-8 with BOM. |
| config.template.ps1 | Windows configuration template for oracle-monitor.ps1. v2.6.0-win.1: email + update-check sections mirror the Linux template. |
| oracle-monitor-macos.sh | macOS port v2.6.3-macos.1 — stock bash 3.2 compatible, jq is the only dependency (curl SMTP support ships with modern macOS). Full logic parity with Linux v2.6.3 (v2.6.0 email + update-check + v2.6.1 spacing fix + v2.6.2 version-line cleanup + UTC email timestamp + pressure-gated swap alert + v2.6.3 update-aware version line + LAUNCHD_LABEL="none" escape hatch). Includes watch mode (--watch), --config for dual-instance monitoring, and --test-email for SMTP diagnostics. |
| config-macos.template | macOS configuration template for oracle-monitor-macos.sh. v2.6.0-macos.1: email + update-check sections mirror the Linux template. |
| CROSS_PLATFORM_SETUP.md | Setup guide for Windows and macOS ports — installation, config, Task Scheduler/cron, watch mode, email SMTP setup per platform, troubleshooting. |
The Windows and macOS ports ship with parallel isolated test harnesses for verifying check_daemon + check_services behavior on your box before scheduling the monitor. Nine scenarios each — auto-detect for headless vs Qt, override honored, service check appropriately skipped when Qt is the running daemon, and so on.
| Harness | Purpose |
|---|---|
| test-macos-daemon-services.sh | Mocks pgrep, launchctl, and $CLI — runs 9 scenarios in isolation. Verifies parity with the Linux logic before you point the monitor at a live oracle. |
| test-win-daemon-services.ps1 | Mocks Get-Process, Get-Service, and Invoke-DGBCli — runs 9 scenarios under Windows PowerShell 5.1 or 7. Verifies PS-specific behavior including auto-detect candidate loop and Windows Service Qt-skip. Ships UTF-8 with BOM. |
Neither harness sends Discord alerts, touches state files, or runs against a real node — they're safe to run on any box, even without DigiByte installed.
More tools will be added as the DigiDollar testnet matures toward mainnet activation. Roadmap: See open issues for planned features — bundle signer detection, oracle deselection alerts, price deviation alerts, and more.
The monitor runs natively on all three major platforms. Same 12 checks, same DigiDollar BIP9 pre-activation guard, same quorum state machine, same anti-flap logic, same Qt/headless auto-detect, same Discord card format, and — as of v2.6.0 — the same dual-channel email + Discord alerts and the same daily update-check. Only the platform plumbing underneath differs.
| Platform | Script | Config template | Version |
|---|---|---|---|
| Linux | oracle-monitor.sh |
config.template |
2.6.3 |
| Windows 10/11 | oracle-monitor.ps1 |
config.template.ps1 |
2.6.3-win.1 |
| macOS | oracle-monitor-macos.sh |
config-macos.template |
2.6.3-macos.1 |
Windows needs no dependencies at all (PowerShell parses JSON natively; .NET's built-in SmtpClient handles email). macOS needs only jq and runs on the stock bash 3.2 every Mac ships with (curl SMTP support ships with modern macOS). Setup for both is in CROSS_PLATFORM_SETUP.md. The rest of this README documents the Linux version; the ports behave identically.
digibyteddaemon process alive (auto-detects headlessdigibytedor Qt walletdigibyte-qt— configurable viaDAEMON_PROCESSoverride)- Oracle is
runninginlistoracle - Chain sync (
blocksvsheadersfromgetblockchaininfo— alerts when the node falls more thanMAX_CHAIN_BEHINDblocks behind) - Peer count (default min: 3)
- Price freshness (
is_staleflag ongetoracleprice) - Degraded consensus detection (
status!=okongetoracleprice) - Disk space — free, total, and used% (default min: 5GB free); the Low Disk alert names your
DATADIRon its own line so you know exactly where to clean up (v2.5.5) - Memory usage
- Swap pressure — alerts when swap usage exceeds threshold (default 100 MB). On a properly tuned box with
swappiness=10, any meaningful swap usage signals real memory pressure before things get critical (v2.4) digibyted.serviceand oracle process status vialistoracleRPC — systemd unit check auto-skips with an INFO line when the Qt wallet is the running daemon (Qt operators typically run outside systemd)- Binary version drift detection via RPC (
getnetworkinfo→.subversion) — works identically for Qt and headless (v2.5) - NTP time synchronization
- Quorum margin tracking — counts online oracles via
getoracles trueusingheartbeat_status(stable across MuSig2 round transitions, matches dashboard's "Online Heartbeats" metric), compares against on-chain quorum threshold fromgetdigidollardeploymentinfo, reports MuSig2 session health. Anti-flap: cooldown timer throttles recovery alerts during volatile periods, hysteresis buffer prevents oscillation at band boundaries
Email notifications (closes #17). Every red/yellow/green state change and the 12-hour summary now fires on Discord AND email, off the same triggers. Off by default — flip EMAIL_ENABLED=true in your config and set EMAIL_TO/SMTP_SERVER/SMTP_PORT/SMTP_USER/SMTP_PASS/SMTP_FROM. Sends via curl's built-in SMTP (no mailx, no postfix, no sendmail — stock Ubuntu ships SMTP-capable curl). Subjects carry the severity ([ALERT]/[WARNING]/[RESOLVED]/[INFO]) so inbox scanning works without opening cards, and the NETWORK_LABEL prefix (dual-instance parity with the v2.5.3 Discord titles) means testnet + mainnet emails from one VPS never look ambiguous. Port 587 STARTTLS by default (Gmail/Outlook/Brevo), port 465 implicit TLS supported for legacy setups.
Two setup notes. Gmail requires an App Password (2FA → App passwords, never your account password). And if your email provider blocks SMTP submission from datacenter or VPS IPs, route through an SMTP relay. Big telco and ISP email providers (Rogers, Telus, AT&T, Verizon, T-Mobile, and the like) commonly reject a VPS IP with 535 5.7.0 "Authentication disabled due to threshold limitation" even when your credentials are correct, because the block is IP-based, not password-based. Brevo is the relay I recommend (free tier 300/day, IP-lockable keys, STARTTLS on 587, and it's what runs in production on my own VPS); Mailjet and SendGrid are equivalent alternatives. Full per-platform setup, including the exact Brevo walkthrough, is in CROSS_PLATFORM_SETUP.md.
New flag: ./oracle-monitor.sh --test-email verifies your SMTP settings with inline diagnostics for the common failure modes (wrong App Password, wrong port, ISP block, missing curl SMTP support).
Auto update-check. The monitor now fetches its own published header from raw.githubusercontent.com/BaumerCrypto/digidollar-oracle-tools/main/oracle-monitor.sh once per day (per instance, cached in STATE_DIR), compares the published SCRIPT_VERSION against what's running, and — when a newer version exists — adds a second footer line to every Discord card and email: ⬆️ vX.Y.Z available — https://github.com/BaumerCrypto/digidollar-oracle-tools. Silent on every failure mode (no curl, timeout, offline, parse fail): the footer stays one line and the monitor itself is completely unaffected. Set UPDATE_CHECK="no" to disable. Never fetches and never writes the cache in --dry-run (v2.5.4 dry-run-touches-nothing discipline).
v2.6.1 cosmetic fix (caught by Aussie Epic). --dry-run and --watch output renders. Discord and email are visually unaffected (both render these as full-width emoji so the extra space just reads as padding). Shipped cross-platform as 2.6.1 / 2.6.1-win.1 / 2.6.1-macos.1.
v2.6.2 three operator-suggested fixes (two cosmetic, one alert-logic). First: the node version line in every health summary now reads ℹ️ DigiByte: v9.26.4 instead of ℹ️ /DigiByte:9.26.4/. getnetworkinfo → .subversion returns the bitcoin-legacy /Name:Version/ user-agent format — the slashes matter to network peers as a message-boundary marker but are noise to operators reading a health card. check_version now strips the wrapper via a single sed pass (regex-transform in PowerShell), matching the format oracle-network-status.sh has always used in its Gitter Software section. RC builds and hash suffixes come through cleanly (/DigiByte:9.26.0rc46/ → DigiByte: v9.26.0rc46). Second: the Time: line in the email body now uses UTC (date -u on Linux/macOS, (Get-Date).ToUniversalTime() in PowerShell) instead of the VPS-local timezone. Matches Discord card timestamps (which have always used the ISO-8601 embed timestamp field that Discord renders to viewer-local automatically). Operators running a VPS in a different timezone from their home — very common — no longer need to mentally convert CEST/PST/AEST to their local clock when scanning the email. No config change; automatic.
Third (caught by Aussie Epic): the swap alert is now pressure-gated, fixing a false positive. A filled swap is not the same as memory pressure. After a -reindex — or any heavy transient — the kernel can page several GB out to swap and never page it back in; the fill just sits there, stale, long after the pressure ended. On a node upgraded from 16GB to 32GB RAM this produced a permanent red swap alert while RAM sat at 40% used and nothing was actually stalling. When swap is filled, check_swap now gates the alert on current pressure using two independent signals — either one firing raises the alert: Linux PSI (/proc/pressure/memory "some avg10" > PSI_SWAP_THRESHOLD, the kernel's real stall-time meter) or RAM headroom (RAM usage ≥ SWAP_MEM_HEADROOM_PCT). macOS and Windows have no PSI, so they use the RAM-headroom signal alone. If both signals are quiet the fill is shown as an informational ℹ️ Swap: … (stale — RAM 40%, PSI 0.00) line — not a warning, and it no longer inflates the warning count. If neither signal can be measured the monitor fails safe and alerts exactly as it did before. Two new config keys (SWAP_MEM_HEADROOM_PCT, default 70; PSI_SWAP_THRESHOLD, default 5.0) let operators tune it; real memory pressure still alerts exactly as in v2.4. Shipped cross-platform as 2.6.2 / 2.6.2-win.1 / 2.6.2-macos.1.
v2.6.3 two operator-suggested additions. First: the DigiByte version line is now update-aware. Until now the node-version line always rendered as a blue ℹ️ regardless of whether the running version was current, because the monitor never asked GitHub what the latest DigiByte Core release was. Now check_version compares the running version against the latest release (GitHub releases/latest, cached once per day per instance) and colours the icon: ✅ DigiByte: v9.26.4 when you're on the latest release (or newer — an RC ahead of the last release stays green), and ℹ️ DigiByte: v9.26.3 — v9.26.4 available when a newer release is out. It falls back to the plain blue line when GitHub is unreachable or the check is disabled, and — because this runs inside a health check that also executes under --dry-run — it never fetches or writes its cache during a dry run. releases/latest only ever points at a real (non-prerelease) release, so operators are never nudged toward an RC. New config keys DIGIBYTE_UPDATE_CHECK (default "yes") and DIGIBYTE_UPDATE_TTL (default 86400) on all three platforms. Second: SERVICE_NAME="none" escape hatch. Operators who deliberately run headless without a service manager (tmux/screen, Docker, runit, a hand-started digibyted -daemon) can set SERVICE_NAME="none" (also "skip"/"disabled") so the service/systemd check reports an informational ℹ️ Systemd: check disabled line instead of a red on a unit that isn't there — the node and oracle-process checks still run. On macOS the parity twin is LAUNCHD_LABEL="none". Shipped cross-platform as 2.6.3 / 2.6.3-win.1 / 2.6.3-macos.1.
Testnet26 Health Summary — red status with issues detected:
Mainnet Health Summary — green all-clear (pre-activation standby pattern), with the auto update-check footer line active:
Both cards carry the NETWORK_LABEL subject prefix, the severity tag, and the same footer stamp as the Discord cards. When a newer version exists on GitHub main, the footer gains its second line automatically (the ⬆️ vX.Y.Z available — https://github.com/BaumerCrypto/digidollar-oracle-tools line) — no config change needed. The https:// scheme is included so email clients auto-linkify the URL universally, including Outlook desktop and corporate gateways that only linkify explicit-scheme URLs (v2.6.1).
Before DigiDollar BIP9 activates on your target chain, the oracle RPCs (listoracle, getoracleprice, getoracles) return no data — the deployment simply isn't live yet. Without special handling, a monitor pointed at a mainnet node right now would fire red alerts every 5 minutes for oracle down, price unknown, and quorum unavailable, even though nothing is actually broken.
The v2.5+ monitors solve this with a pre-flight check. A check_digidollar_active function runs first on every pass, reads getdigidollardeploymentinfo for the current deployment status, and sets a DD_ACTIVE global that the four oracle-dependent checks (check_oracle, check_price, check_services, check_quorum) consult before deciding whether to alert.
When DD_ACTIVE=false, those four checks downgrade "no data" to a blue ℹ️ standby INFO line instead of a red alert — showing something like ℹ️ Oracle: standby (DigiDollar deployment: started) in the health summary. The other 8 checks (daemon, chain, peers, disk, memory, swap, service, NTP, version) continue to alert normally on real problems. Result: your Discord channel stays quiet until DigiDollar activates, then automatically switches to full oracle alerting once DD_ACTIVE=true.
This is why a pre-activation mainnet monitor shows an all-green health summary with four ℹ️ standby lines — that's correct pre-activation behavior, not a bug. It flips to full oracle data automatically the moment BIP9 locks in.
Discord embeds and (v2.6.0+) plain-text emails — color-coded / severity-tagged:
- 🔴 Red /
[ALERT]— critical (daemon down, oracle stopped, chain stuck, quorum at edge or lost) - 🟡 Yellow /
[WARNING]— warnings (low peers, low disk, stale price, degraded consensus, NTP desync, quorum getting thin, swap pressure) - 🟢 Green /
[RESOLVED]— recovery confirmations (quorum healthy, margin improving) - 🔵 Blue /
[INFO]— 12-hour status summary, plus ℹ️ INFO lines for pre-activation standby state - Card titles and email Subject lines carry the
NETWORK_LABELfrom your config on every alert — health summaries (Testnet26 Health Summary), individual checks (Mainnet — 🔴 Node Down), and the--testalert — so dual-instance operators can tell which daemon fired an alert at a glance without opening the card (v2.5.3, mirrored into emails at thesend_emailchokepoint in v2.6.0) - Footer stamps the monitor version and your oracle identity on every card (e.g.
Oracle Monitor v2.6.3 — digibyte-maxi (ID 17)). When an update is available, the footer gains a second line:⬆️ v2.6.x available — https://github.com/BaumerCrypto/digidollar-oracle-tools(v2.6.0)
State files in ~/.oracle-monitor/ prevent the same alert firing every 5 minutes — you get notified once when something breaks and once again when it recovers. Quorum tracking uses a single quorum_state file that stores the current band and timestamp, with cooldown and hysteresis to prevent alert flapping during network volatility.
All timestamps inside alerts are in UTC for unambiguous reading across timezones. Discord's footer time auto-converts to each viewer's local time; email footers include an explicit local-time Time: line.
Health summary with quorum tracking and MuSig2 session status:
Quorum state transition alerts — red/yellow/green as oracle count changes:
The Quorum1 image is a current Testnet26 health summary — the day-to-day view most operators see. The Quorum2 image (quorum state transitions) is older and will be refreshed when an organic quorum event provides a fresh capture, likely post-mainnet activation — see issue #29.
- Linux (tested on Ubuntu 24.04 LTS) — for Windows and macOS, see Platform support above
- DigiByte Core v9.26.4 (also compatible with v9.26.2/v9.26.3 and RC44–RC46 — uses
listoracle,getoracleprice,getdigidollardeploymentinfo,getoraclesRPCs) jq(for JSON parsing — install withsudo apt install jq)curlwith SMTP support (stock Ubuntu ships this — verify withcurl --version | grep smtp)- A Discord webhook URL — create one at: Server Settings → Integrations → Webhooks → New Webhook
- (Optional, for email) SMTP credentials — Gmail App Password, Outlook, Brevo relay, or your own provider
- Download the script and config template to your oracle VPS:
wget https://raw.githubusercontent.com/BaumerCrypto/digidollar-oracle-tools/main/oracle-monitor.sh
wget https://raw.githubusercontent.com/BaumerCrypto/digidollar-oracle-tools/main/config.template
chmod +x oracle-monitor.sh- Create your config file from the template:
mkdir -p ~/.oracle-monitor
cp config.template ~/.oracle-monitor/config
chmod 600 ~/.oracle-monitor/config # keep SMTP password out of world-readable files- Edit the config file with your settings:
nano ~/.oracle-monitor/configSet your Discord webhook URL, oracle ID, and oracle name. For mainnet, change CLI="digibyte-cli". To enable email, set EMAIL_ENABLED=true and fill in the SMTP block. The template's inline docs cover Gmail App Password and Outlook; for the Brevo relay setup, see CROSS_PLATFORM_SETUP.md.
- Test with
--dry-run(runs all checks, prints to terminal, skips Discord + email):
./oracle-monitor.sh --dry-run- Test the webhook:
./oracle-monitor.sh --testYou should see a test alert appear in your Discord channel. If email is also enabled, a test email lands in your inbox at the same time.
- Test email alone (v2.6.0):
./oracle-monitor.sh --test-emailSends a test email through your configured SMTP. Reports success or one of the common failure modes with a diagnostic hint.
- Test a full health summary:
./oracle-monitor.sh --summary- Add to cron (
crontab -e):
*/5 * * * * $HOME/oracle-monitor.sh 2>/dev/null
0 */12 * * * $HOME/oracle-monitor.sh --summary 2>/dev/null| Flag | What it does |
|---|---|
| (none) | Normal health check — alerts only on problems or recovery |
--summary |
Full status summary — always sends to Discord + email |
--dry-run |
Runs all checks, prints to terminal, skips Discord + email, no state changes |
--test |
Sends a test embed to Discord to verify webhook (also fires the email test if EMAIL_ENABLED=true) |
--test-email |
Sends a test email to verify SMTP settings — inline diagnostics for the common failure modes (v2.6.0) |
--config /path |
Use alternate config file — enables dual-instance monitoring (v2.3+) |
All thresholds are configurable in ~/.oracle-monitor/config. The script uses built-in defaults if a value isn't set.
| Setting | Default | Description |
|---|---|---|
DISCORD_WEBHOOK |
(empty) | Discord webhook URL for alerts |
EMAIL_ENABLED |
false |
Set to true to fire the same alerts as Discord to EMAIL_TO via SMTP (v2.6.0) |
EMAIL_TO |
(empty) | Recipient email address (v2.6.0) |
SMTP_SERVER |
smtp.gmail.com |
SMTP server hostname (v2.6.0) |
SMTP_PORT |
587 |
587 for STARTTLS (Gmail/Outlook/Brevo default), 465 for implicit TLS (v2.6.0) |
SMTP_USER |
(empty) | SMTP login — usually your full email address (v2.6.0) |
SMTP_PASS |
(empty) | SMTP password. Gmail: App Password, not account password (v2.6.0) |
SMTP_FROM |
(empty) | "Display Name <you@example.com>" — empty = use SMTP_USER (v2.6.0) |
UPDATE_CHECK |
yes |
Set to no to disable the daily GitHub version check (v2.6.0) |
UPDATE_CHECK_TTL |
86400 |
Seconds between GitHub fetches — default 1 day (v2.6.0) |
ORACLE_ID |
0 |
Your oracle slot ID |
ORACLE_NAME |
my-oracle |
Your oracle name (shown in Discord embeds and email footer) |
CLI |
digibyte-cli -testnet |
RPC command. Use digibyte-cli for mainnet |
WALLET_FLAG |
-rpcwallet=oracle |
Wallet flag for RPC calls |
MIN_PEERS |
3 |
Minimum peer count before alerting |
MIN_DISK_GB |
5 |
Minimum free disk space (GB) |
DISK_PATH |
/home |
Path whose filesystem is watched for free space. Point it at the mount holding your datadir if that isn't under /home (v2.5.4) |
DATADIR |
$HOME/.digibyte |
DigiByte datadir named in the Low Disk alert. Display-only — never read or written. Dual-instance operators set it per config so each alert names its own datadir (v2.5.5) |
MEM_THRESHOLD |
90 |
Memory usage % above which to alert |
SWAP_THRESHOLD_MB |
100 |
Swap usage in MB above which to alert. On a swappiness=10 box, any meaningful swap means real pressure (v2.4) |
MAX_CHAIN_BEHIND |
10 |
Blocks behind before alerting |
QUORUM_GREEN |
12 |
Oracles reporting at/above this = healthy (no alert). Tuned in v2.5.1 — the old 20/12 defaults fired "getting thin" at 2x the 7-of-35 quorum floor. Testnet suggestion: 10 |
QUORUM_YELLOW |
10 |
Below green but at/above this = "getting thin" warning. Testnet suggestion: 8 |
QUORUM_COOLDOWN |
30 |
Minutes between quorum recovery alerts. Escalation (worse) always fires immediately. Set to 0 to disable (v2.1+) |
QUORUM_HYSTERESIS |
3 |
Recovery buffer — must exceed threshold by this many oracles to recover. Prevents flapping at boundaries. Set to 0 to disable (v2.1+) |
The quorum minimum (oracle_consensus_required, currently 7) comes from the chain itself via getdigidollardeploymentinfo — it's not configurable. Below that threshold, DigiDollar signing halts regardless of your config settings.
The disk line shows the full picture — ✅ Disk: 156GB free of 200GB (22% used) — and when disk runs low, the red alert names the datadir to clean up, on its own line so it's a clean copy target on mobile:
🔴 Low Disk Space
Only 3GB free of 200GB (98% used).
Clean up old logs or unused chain data in:
/home/YOU/.digibyte/
That path comes from the DATADIR config variable. No RPC returns the datadir, so the monitor can't discover it — you declare it. Single-instance operators leave the default and never think about it again.
Dual-instance operators (testnet + mainnet on one box via --config) should set DATADIR per config file — left at the default, both instances name the same path and the two alerts are ambiguous. Set per config (testnet: DATADIR="$HOME/.digibyte/testnet26", mainnet: DATADIR="$HOME/.digibyte"), the same full disk produces two distinct, actionable cards:
Testnet26 — 🔴 Low Disk Space
Only 3GB free of 200GB (98% used).
Clean up old logs or unused chain data in:
/home/YOU/.digibyte/testnet26/
Mainnet — 🔴 Low Disk Space
Only 3GB free of 200GB (98% used).
Clean up old logs or unused chain data in:
/home/YOU/.digibyte/
Testnet26 dual-instance Low Disk alert — escalation and recovery pair with NETWORK_LABEL prefix and DATADIR path call-out:
Same disk, same numbers — but each card tells you which daemon fired (NETWORK_LABEL, v2.5.3) and exactly which directory to prune (DATADIR, v2.5.5). Both v2.5.5 disk enhancements were suggested by Aussie Epic. Mainnet chain data lives at the datadir top level; testnet data lives in a subdirectory named for the current testnet reset (testnet26, testnet27, ...) — bump your testnet DATADIR when the testnet resets.
| Active oracles | Status | Escalation alert | Recovery alert |
|---|---|---|---|
| 🟢 12+ | Comfortable | — | ✅ Quorum Healthy |
| 🟡 10–11 | Getting thin | ⚠️ Quorum Getting Thin |
✅ Quorum Improved — Getting Thin → Healthy |
| 🔴 7–9 | At quorum edge | 🚨 Quorum at Edge |
✅ Quorum Improved — At Edge → Getting Thin |
| 💀 Below 7 | DD signing halted | 🚨 QUORUM LOST |
✅ Quorum Recovered — LOST → At Edge |
Escalation (count drops into a worse band) always fires immediately. Recovery (count rises into a better band) is throttled by QUORUM_COOLDOWN and requires the count to exceed the threshold by QUORUM_HYSTERESIS oracles. This prevents a single oracle bouncing around a boundary from generating a stream of alerts.
| Recovery to | Threshold | Required count |
|---|---|---|
| 🟢 Healthy | QUORUM_GREEN (12) |
12 + 3 = 15 |
| 🟡 Getting thin | QUORUM_YELLOW (10) |
10 + 3 = 13 |
| 🔴 At edge | oracle_consensus_required (7) |
7 + 3 = 10 |
With QUORUM_HYSTERESIS=0, recovery fires at the exact threshold (v2.0 behavior).
Both scripts parse specific fields from DigiByte Core RPCs. If a future RC renames a field, these scripts may need updates. Known field names as of RC46:
| RPC | Field used |
|---|---|
listoracle |
running (not is_running) |
listoracle |
price_usd (not last_price_usd) |
getoracleprice |
price_usd, is_stale, status, oracle_count |
getdigidollardeploymentinfo |
oracle_consensus_required, oracle_total_slots, musig2_session.state, musig2_session.epoch, musig2_session.nonce_count, musig2_session.partial_sig_count |
getoracles true |
last_price_usd, status, heartbeat_status (v2.2: "fresh" = online within 30 min), heartbeat_age_seconds, heartbeat_timestamp, software_version (used by oracle-network-status.sh) |
getblockchaininfo |
chain (used by oracle-network-status.sh v1.4 for network label auto-detection) |
getoraclesigners |
bundle_count, bundles[].height, bundles[].signer_count, bundles[].signer_ids (used by oracle-network-status.sh) |
RC45 new RPCs (not used by these scripts yet but available):
| RPC | Purpose |
|---|---|
exportoracleprivkey |
Export oracle signing key from wallet (wallet-context, usable before activation) |
importoracleprivkey |
Import oracle signing key into wallet (wallet-context, usable before activation) |
Community-facing Gitter bot that posts oracle network health summaries to the DigiDollar Gitter channel every 12 hours. Unlike oracle-monitor.sh (which watches your own node and alerts you privately via Discord + email), this script monitors the entire oracle network and reports publicly.
- Network label — which chain the report covers (e.g. "Testnet26" or "Mainnet"), auto-detected from
getblockchaininfoor set viaNETWORK_LABELin config (v1.4) - Fresh Heartbeats — active oracle count vs roster size, quorum health status (healthy / thin / critical / lost)
- Consensus price — current DGB/USD price and oracle price feed status
- MuSig2 session — current epoch, signing state, nonce and signature counts
- BIP9 activation — deployment status and signaling bit
- Last bundle — most recent on-chain price bundle block height and signer count
- Software versions (v1.6+) — all versions with compliance icons per
ACCEPTED_VERSIONSwhitelist. Compliant versions (✅) sorted by count first, non-compliant versions (⚠️ ) sorted by count next, "No version reported" bucket pinned at the end. RC46 long/short hash-variant clutter collapses to one canonical line per base version. - Upgrade nudge (v1.6+, 📢) — fresh operators running non-compliant versions get a light @ mention. Same 6-ping cap as the stale/inactive nudges (no spam). Skipped for stale/inactive operators since they're already pinged in those sections.
- Stale oracles (
⚠️ ) — were running, went down (liveness concern). Operators are @ mentioned in Gitter for up to 6 cycles (3 days), then suppressed but still listed. - Inactive oracles (❌) — have key or wallet issues on the current network. Same @ mention behavior as stale.
The bot has four operating modes decided at runtime based on chain, DD BIP9 activation state, and the --endgame-only flag:
- FULL — regular network status post. Always used on testnet (DD active since block 600). Used on mainnet post-activation. This is what the "What it reports" section above describes.
- STANDBY — mainnet + DD not yet active. Posts a compact countdown with current block, activation block, blocks remaining, day/hour granularity, and calendar UTC ETA. Skips the full status data (which isn't available pre-activation anyway). Inside the final 24h it defers to the hourly endgame ticker (59-minute dedup window, v1.6.3) so the room gets one countdown per hour instead of near-duplicates 5 minutes apart.
- BIRTH — mainnet + DD just flipped to ACTIVE + no prior birth-state file. Fires a one-shot announcement with
m.mentionsnotifications to Jared (slot 0) and DigiSwarm (slot 15). State-file dedup prevents double-fire from the endgame vs 12hr cron collision window. - ENDGAME — silent-exit variant of STANDBY that fires from the hourly
--endgame-onlycron. Only posts when inside the 24h band before activation. Silent exit outside that band so hourly cron doesn't spam.
🟢 Oracle Network Status, Testnet26, 2026-07-13 00:29 UTC
Fresh Heartbeats: 16/35 (quorum healthy, threshold: 7)
Consensus price: $0.002529 (status: active)
MuSig2: epoch 3061, complete, 7/7 nonces, 7/7 sigs
BIP9: active (bit 23)
Last bundle: block 122446, signed by 7 oracles
Software (accepted: v9.26.2 / v9.26.3 / v9.26.4):
✅ v9.26.4: 7 operators
✅ v9.26.3: 5 operators
✅ v9.26.2: 1 operator
⚠️ v9.26.0rc46 (pre-release): 12 operators
⚠️ v9.26.1-pre2 (pre-release): 1 operator
⚠️ No version reported: 9 operators
📢 Please upgrade to v9.26.2 or newer:
— ID 9 Ogilvie @ogilvie:gitter.im
— ID 18 Anthony @usascholar:gitter.im
— ID 26 HashedMax @hashedmax:gitter.im
— ID 29 medgborsole3452 @eps8sap:gitter.im
⚠️ Stale (10):
— ID 4 Shenger @shenger:gitter.im
— ID 5 Ycagel @ycagel-60c7a14b6da03739847edeeb:gitter.im
— ID 10 ChopperBrian @chopperbrian-610ed4a86da037398482ada7:gitter.im
(...)
❌ Inactive (9):
— ID 7 LookInto @lookintomyeyes:gitter.im
(...)
🟢 Oracle Network Status, Mainnet, 2026-07-13 00:10 UTC
📅 DigiDollar Mainnet Activation: PENDING
Current stage: LOCKED_IN (bit 23)
Current block: 23,843,024
Activation block: 23,869,440
Blocks remaining: 26,416
Time to activation: ~4 days 14 hours
Estimated activation: 2026-07-17 ~14:12 UTC
Roster: 35 slots configured, 7-of-35 quorum threshold
Signing status: standby, mainnet oracles begin publishing at BIP9 ACTIVE
This bot will resume full network status posts (fresh heartbeats,
consensus price, MuSig2, upgrade nudges) automatically at activation.
| RPC | What it provides |
|---|---|
getblockchaininfo |
Chain identification — auto-detects "test" → Testnet, "main" → Mainnet for header label (v1.4). Current block height for countdown math (v1.6). |
getdeploymentinfo |
BIP9 standard deployment info — bip9.since + statistics.period gives activation-height math that works pre-activation on mainnet (v1.6.2). In ACTIVE state Core drops statistics and since alone is the activation height (v1.6.3). |
getdigidollardeploymentinfo |
DGB-specific extras — quorum config, MuSig2 session state, BIP9 status. Returns partial data pre-activation but the needed fields are populated. |
getoracles true |
Per-oracle heartbeat status — fresh, stale, and offline lists (FULL mode only, pre-activation returns error). |
getoracleprice |
Consensus price, feed status, oracle count (FULL mode only). |
getoraclesigners 50 |
Recent bundle signer participation, 50-block window covers at least one full 40-block round (FULL mode only). |
v1.6.2 splits these into two phases: Phase 1 (getblockchaininfo, getdeploymentinfo, getdigidollardeploymentinfo) always runs. Phase 2 (getoracles, getoracleprice, getoraclesigners) only runs in FULL mode. This prevents pre-activation mainnet daemons from erroring on RPCs that require DD to be active.
- Linux (tested on Ubuntu 24.04 LTS)
- DigiByte Core v9.26.4 (also compatible with v9.26.2/v9.26.3 and RC44–RC46)
jq,curl- A Matrix bot account joined to
#digidollar:gitter.im
- Create a Matrix bot account at Element (e.g.
@digidollar-oracle-bot:matrix.org) - Join
#digidollar:gitter.imfrom the bot account - Generate an access token on the VPS:
curl -s -X POST "https://matrix.org/_matrix/client/v3/login" \
-H "Content-Type: application/json" \
-d '{"type":"m.login.password","identifier":{"type":"m.id.user","user":"YOUR_BOT_USERNAME"},"password":"YOUR_PASSWORD"}' \
| jq -r '.access_token'- Get the room ID (Element → Room Settings → Advanced → Internal room ID)
- Add to
~/.oracle-monitor/config:
MATRIX_ACCESS_TOKEN="your_token_here"
MATRIX_ROOM_ID="!your_room_id:gitter.im"- Set the network label (optional — auto-detected from chain if not set):
NETWORK_LABEL="Testnet26"- For @ mentions (optional): populate the roster mapping file:
wget https://raw.githubusercontent.com/BaumerCrypto/digidollar-oracle-tools/main/oracle-roster.template
cp oracle-roster.template ~/.oracle-monitor/oracle-roster.conf
nano ~/.oracle-monitor/oracle-roster.conf
# Fill in oracle ID to Gitter Matrix ID mappings — see template for format- Test:
./oracle-network-status.sh --dry-run - Test:
./oracle-network-status.sh --test - Test mentions:
./oracle-network-status.sh --test-mention - Add to cron:
5 */12 * * * /home/YOUR_USER/oracle-network-status.sh 2>/dev/null
| Flag | What it does |
|---|---|
| (none) | Collect data and post to Gitter |
--dry-run |
Collect data, print to terminal, skip Gitter post |
--test |
Send a test message to Gitter to verify Matrix API |
--test-mention |
Send a test @ mention to verify Gitter notifications work |
--config /path |
Use alternate config file, enables dual-instance monitoring (v1.4) |
--endgame-only |
Endgame countdown mode (v1.6.2, mainnet). Posts only if LOCKED_IN + inside the 24h band, or ACTIVE + birth-announcement not yet fired. Silent-exit otherwise. Designed for hourly cron alongside the regular 12hr cron. |
When mainnet launches, run two independent instances from the same script using --config:
# Testnet 12hr status pulse (default config)
5 */12 * * * /home/YOUR_USER/oracle-network-status.sh 2>/dev/null
# Mainnet 12hr status pulse (custom config)
10 */12 * * * /home/YOUR_USER/oracle-network-status.sh --config ~/.oracle-monitor-mainnet/config 2>/dev/null
# Mainnet hourly endgame countdown ticker (v1.6.2, silent-exit outside 24h band)
15 * * * * /home/YOUR_USER/oracle-network-status.sh --config ~/.oracle-monitor-mainnet/config --endgame-only 2>/dev/nullEach instance uses its own config file and tracks mention state independently. The roster file is shared by default (same 35 operators on both networks). The endgame ticker cost is negligible outside the 24h band (silent-exit after Phase 1 RPCs). Setup:
mkdir -p ~/.oracle-monitor-mainnet
cp ~/.oracle-monitor/config ~/.oracle-monitor-mainnet/config
# Edit mainnet config: CLI="digibyte-cli", NETWORK_LABEL="Mainnet"
ln -s ~/.oracle-monitor/oracle-roster.conf ~/.oracle-monitor-mainnet/oracle-roster.conf--config combines with action flags in any order: --config /path --dry-run or --dry-run --config /path.
This script is the reference implementation for the Gitter network status bot posting to #digidollar:gitter.im. First deployed 2026-06-16 (v1.2, GitHub issue #18), maintained and iterated continuously since. Currently at v1.6.5 with dual-instance testnet + mainnet monitoring running under my authorship.
ONE bot per network is sufficient to serve the room. Running a second instance against the same Gitter channel produces duplicate posts, splits @ mention tracking, and confuses operators. My testnet + mainnet instances (using --config for dual-instance) currently cover the network and coordinate with Jared and DigiSwarm on cadence and content.
If you want to monitor your own oracle privately, use oracle-monitor.sh with a Discord webhook and/or SMTP credentials to your own channel/inbox. That's the intended pair: oracle-monitor.sh for private per-operator alerts (Discord + email), oracle-network-status.sh for the shared community status feed.
If you have ideas to improve the reference implementation (compliance rules, new sections, additional RPC data, better formatting), open an issue or PR on this repo. Contributions have shaped every version since v1.2, and I welcome more. Bastian's "any v9.26 will do" rule became the default ACCEPTED_VERSIONS list in v1.6. Aussie Epic's suggestions shaped the disk alert phrasing in the monitor. That collaboration is the point.
If you want to run a modified version for personal testing or as a backup:
- Change the author signature line (search for
digibyte-maxithroughout the file) to your own identity, so nobody thinks your instance is mine - Change the Matrix bot account so posts are visibly from a different sender in Gitter
- Coordinate in
#digidollar:gitter.imbefore posting to the shared room, so we don't produce duplicate output - Reach out on GitHub issues if you hit ecosystem-specific bugs or field-name changes
The MIT license grants full rights to fork, modify, and redistribute. This coordination note is about ecosystem stewardship, not permission.
| Component | Version |
|---|---|
| OS | Linux (Ubuntu 24.04 LTS), Windows 10/11 (PowerShell 5.1+), macOS (bash 3.2+) |
| DigiByte Core | v9.26.4 (also compatible with v9.26.2, v9.26.3, and RC44/RC45/RC46) |
| Chain | testnet26 |
| Oracle protocol | v0x03 MuSig2 bundle |
| oracle-monitor.sh | v2.6.3 |
| oracle-monitor.ps1 | v2.6.3-win.1 |
| oracle-monitor-macos.sh | v2.6.3-macos.1 |
| oracle-network-status.sh | v1.6.5 |
If you're running a different release and something breaks, please open an issue.
Pull requests welcome. If you spot a bug, run into a field-name change on a newer RC, or want to add a check, open an issue or PR.
digibyte-maxi — DigiDollar oracle operator (Slot 17)
- GitHub: BaumerCrypto (display name: BaumerCrypto2.0)
- X/Twitter: @BaumerCrypto2_0
- Gitter:
digibyte-maxiin #digidollar
MIT — use, fork, modify, share. Credit appreciated but not required.
These scripts are provided as-is for the DigiByte community. The DigiDollar protocol is live on testnet26; mainnet activation is in progress via miner signaling (BIP9 bit 23, signaling window opened June 1, 2026). Always test on testnet first and back up your oracle wallet.




