ReserveGrid OS is a policy driven verification, mining gateway, and observability stack for Bitcoin mining pools. It sits between the template source and miners, inspecting candidate block templates against operator defined policy and routing Stratum V2 work to connected workers. Operators get a full dashboard with live metrics, structured logs, and Prometheus instrumentation out of the box.
Built in Rust. Ships as a native macOS/Linux desktop app (rg-desktop) with embedded dashboard, or as a docker compose up server stack for headless deployment.
Current version: v1.0.2
- Website: https://veldra.org
- Contact: jarrondeng@veldra.org
- Evaluates candidate block templates against a configurable
policy.toml - Returns accept/reject verdicts with stable machine readable reason codes and policy context
- Runs a full Stratum V2 gateway (Noise NX encrypted) that distributes work to miners
- Tracks per channel hashrate with a sliding window estimator
- Enforces consensus safety checks: weight ratio, template age, sigops budget, coinbase sigops
- Supports dynamic fee tiers driven by mempool conditions
- Provides an operator dashboard with live service health, verdicts, miners, policy editor, and settings
- Ships Prometheus metrics on all core services
- Includes a complete auth system: registration, email verification, admin approval, forgot/reset password
- Exposes health and readiness probes on every service
- It does not mine blocks
- It does not replace a pool payout system
- It does not force policy on chain
- It is not a consensus change
ReserveGrid OS is an ops layer control surface. Pools remain in control.
ReserveGrid OS supports three deployment modes for progressive rollout:
Shadow evaluates templates in parallel without affecting mining. The feed stack (rg-demo-feed or rg-feed-server, rg-feed-adapter) replays or proxies real pool traffic so the verifier can score templates without any operational risk.
Observe connects to a live bitcoind but does not enforce policy. The gateway distributes jobs to miners regardless of the verdict. Operators see what the verifier would reject without blocking any work.
Inline enforces policy. The gateway only distributes jobs that the verifier accepts. Rejected templates are held until a passing template arrives or a configurable stale hold timer expires. A dual prevhash buffer holds two pending templates simultaneously during block transitions, with a 50ms verdict window so miners never stall on a prevhash switch.
Inline / Observe mode:
bitcoind (regtest or mainnet)
|
v
template-manager pool-verifier
(fetch templates) ------> (evaluate policy)
| |
v v
sv2-gateway rg-desktop (native app)
(SV2 Noise NX, ├─ rg-dashboard (operator UI)
dual prevhash buffer) └─ IPC · auto-update · license
|
v
miners (SV2)
Shadow mode (non-invasive evaluation):
rg-demo-feed or rg-feed-server
| (WebSocket GBT stream)
v
rg-feed-adapter
(WS -> JSON-RPC bridge)
|
v
template-manager -------> pool-verifier -------> rg-desktop
The backend services run in Docker Compose. The rg-desktop native app (built with Tauri) wraps the dashboard, manages licensing, and includes an in-app auto-updater. For headless server deployments, rg-dashboard can run standalone in Docker without the desktop shell. Prometheus scrapes metrics from pool-verifier, template-manager, and sv2-gateway.
TCP server that receives TemplatePropose messages and returns TemplateVerdict. Evaluates templates against the active policy. Serves the HTTP API for stats, verdicts, policy, and exports. Built in TLS termination and API key auth.
Fetches block templates from bitcoind (getblocktemplate) or a Stratum bridge and forwards them to the verifier. Exposes mempool stats for the verifier fee tier logic. Supports runtime settings updates.
Stratum V2 mining gateway with Noise NX encryption. Accepts miner connections, opens channels, distributes NewMiningJob messages, and validates submitted shares. Tracks per channel state including a sliding window hashrate estimator. Exposes channel snapshots via HTTP for the miners page.
Native desktop application (macOS/Linux) built with Tauri. Wraps rg-dashboard in a native window with IPC commands for license management, system tray integration, and in-app auto-updates (signed, with Tauri updater). The desktop app is the primary distribution format for operators. For headless or Docker deployments, rg-dashboard runs standalone.
Operator dashboard and API proxy. Vite/React frontend with live polling. Pages: overview, verdicts, templates, policy editor, miners, and settings. Proxies all API calls to the appropriate backend service. Includes the full auth gate (login, register, verify, forgot password, reset password). Embedded inside rg-desktop for native deployments.
Authentication service. Argon2id password hashing, session tokens, email verification, admin approval workflow, forgot/reset password. Sends email via any STARTTLS SMTP provider. Falls back to stdout in dev mode when SMTP is not configured.
Shared protocol structs and versioning. TemplatePropose and TemplateVerdict message types. Canonical VerdictReason enum and reason code string mappings.
Shared utilities: reason code enums, redacted secret types, common configuration helpers.
Synthetic GBT (getblocktemplate) source for shadow mode testing. Generates realistic block template streams over WebSocket without requiring a real bitcoind. Ships multiple scenarios (normal, empty, fee sweep, reorg, stale).
WebSocket to JSON-RPC bridge. Connects to rg-demo-feed or rg-feed-server over WebSocket, receives GBT frames, and serves them as getblocktemplate JSON-RPC responses to template-manager. Includes reconnection with exponential backoff and a health endpoint.
Authenticated WebSocket relay for real pool template data. Accepts connections from rg-feed-adapter instances, authenticates via bearer token, and broadcasts live GBT frames received from an upstream bitcoind or pool relay.
Performance testing harness for the verifier. Spawns concurrent connections, submits templates at configurable rates, and reports latency percentiles. Used to validate CL-01 (sub-100ms verdict latency) and CL-02 (zero drops under load).
Regtest validation tool. Connects to sv2-gateway over Noise NX, opens a standard mining channel, submits shares with random nonces, then exits. Includes a configurable --job-timeout-secs (default 60) to prevent hangs. Activated via docker compose --profile test up.
services/
pool-verifier/ TCP verifier, HTTP API, policy evaluation
template-manager/ template fetching, mempool stats
sv2-gateway/ Stratum V2 gateway, share validation, hashrate
rg-desktop/ native desktop app (Tauri), license, auto-update
rg-dashboard/ operator UI (Vite + React), API proxy
rg-auth/ authentication, email, sessions
rg-demo-feed/ synthetic GBT source for shadow testing
rg-feed-adapter/ WebSocket to JSON-RPC bridge
rg-feed-server/ authenticated WebSocket relay for live feeds
rg-load-test/ verifier performance testing harness
rg-protocol/ shared message types, reason codes
reservegrid-common/ shared utilities
reservegrid-gateway/ gateway shared library
sv2-bridge/ Stratum V2 bridge (legacy)
test-miner/ regtest share submission tool
config/ policy TOML files
dev/ docker-compose overrides and dev TOML configs
deploy/ production deployment profiles
scripts/ dev, regtest, and CI helper scripts
docs/ architecture and protocol contract docs
supply-chain/ cargo-vet audit configuration
Download the latest .dmg (macOS) or .AppImage (Linux) from the GitHub releases page. The desktop app bundles the dashboard, license management, system tray, and in-app auto-updates. It connects to backend services running in Docker.
- Docker and Docker Compose
- A
.envfile at repo root (copy from.env.example)
-
Copy the environment template:
cp .env.example .env -
Fill in the required values in
.env:VELDRA_BITCOIND_RPC_PASS=<any-password-for-regtest>For email delivery (optional, emails print to stdout without this):
VELDRA_AUTH_SMTP_HOST=smtp.example.com VELDRA_AUTH_SMTP_PORT=587 VELDRA_AUTH_SMTP_USER=you@yourdomain.com VELDRA_AUTH_SMTP_PASS=<your-email-password> VELDRA_AUTH_SMTP_FROM=you@yourdomain.com VELDRA_AUTH_ADMIN_EMAIL=you@yourdomain.com -
Start the stack:
docker compose up --build -
Bootstrap bitcoind (first run only, in a separate terminal):
docker compose exec bitcoind bitcoin-cli -regtest \ -rpcuser=reservegrid -rpcpassword=<your-rpc-pass> \ createwallet "default" docker compose exec bitcoind bitcoin-cli -regtest \ -rpcuser=reservegrid -rpcpassword=<your-rpc-pass> \ -generate 1 -
Open the dashboard at
http://localhost:8084(Docker) or via the desktop app
| Service | Port | Purpose |
|---|---|---|
| rg-dashboard | 8084 | Operator UI |
| sv2-gateway | 3333 | Stratum V2 (miners connect here) |
| sv2-gateway | 8080 | Gateway HTTP API and metrics |
| pool-verifier | 8081 | Verifier HTTP API |
| pool-verifier | 9090 | Verifier TCP (internal) |
| template-manager | 8082 | Template HTTP API |
| rg-auth | 3030 | Auth HTTP API |
| bitcoind | 18443 | Bitcoin RPC (regtest) |
| prometheus | 9091 | Metrics UI (monitoring profile) |
docker compose --profile test up test-miner
Connects to sv2-gateway, opens a channel, submits 5 shares at 2 second intervals, then exits. Shares and hashrate appear on the miners page.
docker compose --profile monitoring up prometheus
Scrapes metrics from pool-verifier, template-manager, and sv2-gateway.
The verifier reads policy from VELDRA_POLICY_FILE (TOML) at startup. The dashboard policy editor can apply changes at runtime.
The verifier fetches mempool tx count from template-manager and selects a fee tier based on configurable thresholds. When the mempool endpoint is unreachable, a conservative tier is used based on the unknown_mempool_as_high setting.
[policy]
protocol_version = 2
required_prevhash_len = 64
min_avg_fee_lo = 1
min_avg_fee_mid = 2000
min_avg_fee_hi = 5000
low_mempool_tx = 0
high_mempool_tx = 50
min_total_fees = 0
max_tx_count = 10000
reject_empty_templates = true
reject_coinbase_zero = true
unknown_mempool_as_high = true
max_weight_ratio = 0.999
max_template_age_secs = 30
max_sigops_cost = 80000
max_coinbase_sigops = 20000Every rejected template carries a stable reason_code (snake_case). These are the canonical contract; UI labels may change.
Source of truth: rg-protocol and reservegrid-common reason enums.
Verdict reason codes (policy): protocol_version_mismatch, invalid_prev_hash, prev_hash_len_mismatch, coinbase_value_zero_rejected, empty_template_rejected, tx_count_exceeded, total_fees_below_minimum, avg_fee_below_minimum, weight_ratio_exceeded, template_too_old, sigops_budget_exceeded, coinbase_sigops_exceeded, policy_load_error, mempool_backend_unavailable, internal_error.
Gateway share codes: share_difficulty_below_target, share_replay_detected, share_rate_limited, ntime_out_of_range, share_invalid_job_id, share_invalid_nonce, version_bit_violation, share_forward_failed, share_upstream_rejected, share_dropped_queue_full, process_crash_recovery.
Connection and protocol codes: noise_handshake_failed, noise_handshake_timeout, unsupported_protocol_version, frame_decode_error, frame_too_large, connection_rate_limited, peer_quota_exceeded, channel_open_rejected, channel_limit_exceeded, extended_channel_unsupported, miner_unauthorized, shutdown_drain.
The full canonical list lives in reservegrid-common/src/reason.rs (GatewayReason enum) and rg-protocol (VerdictReason enum).
All secrets and credentials are loaded from environment variables. See .env.example for the complete list with documentation.
Key groups:
VELDRA_BITCOIND_RPC_*— Bitcoin Core RPC credentialsVELDRA_AUTH_SMTP_*— SMTP email configuration for rg-authVELDRA_API_SECRET— API key for protected endpointsVELDRA_TLS_*— TLS certificate and key pathsVELDRA_NOISE_*— Noise NX key and cert paths for sv2-gatewayVELDRA_LOG_*— Log format and filter level
No secrets should appear in TOML config files, docker-compose.yml, or source code. The .env file is gitignored.
- All credentials come from
.envor a secrets manager, never from config files - Passwords are hashed with argon2id
- Session tokens are cryptographically random, expire after 7 days
- Password reset tokens expire after 1 hour
- Rate limiting on auth endpoints (3 to 10 requests per minute per IP, scalable via
VELDRA_AUTH_RATE_LIMIT_MULTIPLIER) - Forgot password endpoint does not reveal whether an email is registered
- SV2 connections use Noise NX encryption
- API key auth on protected verifier endpoints with automatic localhost bypass
- Built in TLS termination (file based or self signed dev mode)
- Desktop app auto-updater uses signed releases with a pinned public key
- Per-IP connection limits on all WebSocket services (rg-feed-server, rg-demo-feed, sv2-gateway)
- Non-loopback bind blocked by default; requires explicit
VELDRA_ALLOW_NON_LOOPBACK=1override
Expected on first boot before any blocks exist. Fix:
docker compose exec bitcoind bitcoin-cli -regtest \
-rpcuser=reservegrid -rpcpassword=<your-rpc-pass> \
createwallet "default"
docker compose exec bitcoind bitcoin-cli -regtest \
-rpcuser=reservegrid -rpcpassword=<your-rpc-pass> \
-generate 1
If SMTP env vars are not set, rg-auth falls back to printing emails to stdout with [email-stub] prefix. Check container logs:
docker compose logs rg-auth
The pool-verifier /ready endpoint returns 503 when policy failed to load or no mempool fetch succeeded in the last 30 seconds. Verify VELDRA_POLICY_FILE points to valid TOML and template-manager is healthy.
Mempool is empty or blocks are mined too aggressively. Regtest requires deliberate mempool maintenance to exercise fee policy.
VELDRA SOURCE AVAILABLE LICENSE (see LICENSE)
Veldra, Inc. Jarron Deng — jarrondeng@veldra.org