Grin

GRIN Solo Mining — Setup

About this pool — free & open source

This page is a live demo of the free, open-source solo Grin mining pool I built into the Grin Node Toolkit (Script 07). If you like it, you're welcome to point your miners here as a donation — there's no obligation.

With the Grin Node Toolkit you can stand up your own solo Grin pool in minutes with a single bash script. My intention is to let newcomers be independent from the big mining pools and keep Grin mining more decentralized — and since it's your own pool, you pay no fee to join anyone else's.

If you want more privacy, the pool can be protected with a username / password. The whole script is open source — audit, fork, clone or refactor it however you wish: github.com/noobvie/Grin-Node-Toolkit.

Point your miner here

This node runs Grin's built-in stratum server. Connect a Cuckatoo32 (C32) miner to it. There is no registration and no per-miner account — the block reward goes to the wallet configured on the node, not to your worker login. Your worker name is just a label so each rig shows up separately on the stats page.

ASIC — iPollo G1 Minisupported recommended for solo mining ASIC — iPollo G1supported same setup as the G1 Mini GPU minersto be defined not yet tested — instructions pending

Connection details — iPollo G1 Mini / G1

Open the miner's web panel in a browser (its IP on your LAN), log in, then go to Miners → Pool Configuration. The G1 takes up to three pools and uses them in order — set Pool 1 to this solo pool, and point Pool 2 / Pool 3 at public pools so the rig keeps earning if your node goes offline.

Pool 1 — this solo pool primary

Pick exactly one — IP or domain — for Pool 1. Both addresses reach the same node; you only put one of them in the Pool 1 slot.
  • Option A · IP recommended — the node's raw public IP. Stratum is plain TCP straight to the node (never proxied), so the IP is always the most reliable target. Use this unless you have a specific reason not to.
  • Option B · domain optional — a friendlier alias, handy if the node's IP ever changes. It only works when the domain's A record points straight at the node's public IP. If it shows 🔴 unreachable (or ⚠ Cloudflare?), fall back to the IP.
Use the copy button next to whichever one you choose to grab the exact stratum+tcp://… URL.

Pool 2 / Pool 3 — public backups failover

Pool 2check details at gaeapool.com Pool 3check details at grin.2miners.com
Worker naming — nickname.NN. Pick a nickname for yourself (e.g. alpha) and a two-digit number per rig: alpha.01, alpha.02, … alpha.NN. Each unique worker name shows as its own row on the stats page, so number every machine differently if you want to tell them apart.
Pool 2 / Pool 3 are failover. The G1 falls back to them, in order, only when Pool 1 is unreachable — so if your node or this pool goes down, the rig keeps earning on a public pool instead of idling. They're independent pools, so their worker is your own GRIN payout address (not nickname.NN) and the password is whatever that pool asks for — grab the exact stratum URL, port, and worker format from each pool's own getting-started page. Pool 1's password is ignored.

Save the config and reboot the miner if possible. It reconnects to Pool 1 within a few seconds — confirm under CGMiner Status that the pool shows as Alive and shares are accepted.

GPU miners

to be defined

Set a GPU rig up the same way as the iPollo above — point it at the same Pool URL, with worker nickname.NN and any password. The creator hasn't tested GPU mining (Cuckatoo32) against this node, though, so no verified miner flags are published here — treat it as unverified until this section is filled in.

Verify it's working

  1. On the stats page, the Wallet Listener tile should read listening — the node needs the wallet up to build coinbase rewards.
  2. Once your miner connects and submits a share, Active Miners ticks up and your worker (e.g. alpha.01) appears in the Miners table with a 15m hashrate.
  3. On the server, the node log shows Got share at height … per accepted share, and Solution Found for block … when you mine a block.
If your worker never appears but the miner says the pool is Alive, the node's file_log_level is probably not INFO. Shares are logged at INFO; set file_log_level = "INFO" in grin-server.toml and restart the node. (Found blocks still record regardless — those log at WARN.)
Check you're on Pool 1, not a backup. Because Pool 2 / Pool 3 are public pools, a rig that can't reach Pool 1 quietly fails over and keeps hashing there — so Alive alone doesn't prove it's on your solo pool. The definitive check is that your worker shows in the Miners table on this stats page; a rig that fell through to gaeapool/2miners won't. In CGMiner Status, confirm Pool 1 (priority 0) is the active pool. (If Pool 1 is Alive and the worker still doesn't appear, that's the file_log_level issue above — not failover.)

Server-side checklist

Coinbase rewards are immature for 1440 blocks (~24 h) before they're spendable. The stats page Coinbase Maturing tile tracks how many of your found blocks are still maturing.

High availability — keep mining during node maintenance ⚠ to be tested

Solo mining stops the instant your node does — so rebooting the box or patching the OS means lost hashing time unless something picks up the slack. Two ways to cover that gap, easiest first.

Easiest — fail over to a public pool (already set up above)

This needs no extra servers: Pool 2 / Pool 3 in the setup above already point at gaeapool.com and grin.2miners.com. When your node goes down the G1 falls through to them within seconds and keeps earning — paid to your own GRIN address. The only downside is you're not solo while the node is offline. For most people this is enough.

Advanced — a second solo node (true HA)

To stay solo through a reboot, run a second grin node and let the miner fail over between the two. The G1 has three pool slots tried in order, so the natural mapping is two of your own nodes first, then a public pool as last resort:

iPollo G1 — three pool slots, tried in order ───────────────────────────────────────────── Pool 1 → node-A : 3416 your two solo nodes; Pool 2 → node-B : 3416 both set wallet_listener_url Pool 3 → gaeapool / 2miners to the SAME wallet (public = last resort) rig fails over Pool 1 → 2 → 3 within seconds │ ▼ Wallet server (the one box you do NOT reboot during maintenance) • wallet listener : 3420 ← node-A and node-B send the coinbase here • local grin node : 3413 ← this wallet's check_node_api_http_addr points at a co-located, always-up synced node — NOT the remote mining nodes

The whole trick is that both nodes pay the same wallet, so it doesn't matter which one solves the block — the reward lands in the same place. Reboot node-A and the rig keeps mining solo on node-B; only when both are down does it drop to the public Pool 3.

The three links to wire up

1. Each node — grin-server.toml (identical on node-A and node-B):

[server.stratum_mining_config] enable_stratum_server = true stratum_server_addr = "0.0.0.0:3416" # bind public so remote miners reach it wallet_listener_url = "http://WALLET_HOST:3420" # SAME wallet on both nodes (combined listener port)
Combined listener rides the Owner port. The toolkit wallet now runs grin-wallet -p <pass> owner_api with owner_api_include_foreign = true, so build_coinbase is served on the Owner port 3420 — not the old standalone Foreign listener on 3415. On a single box this is all localhost and needs nothing extra. For this remote two-node layout, the wallet must accept off-box connections, which means setting owner_api_listen_interface = "0.0.0.0" in grin-wallet.toml — and because the Owner API (send/spend) shares that port, keep the wallet server and mining nodes on a trusted private network or a WireGuard/SSH tunnel; never expose 3420 to the public internet.

2. Wallet server — grin-wallet.toml:

check_node_api_http_addr = "http://127.0.0.1:3413" # a local, always-up, synced node
grin-wallet has no built-in node failover. check_node_api_http_addr is a single value — it won't rotate to a second node on its own. That's why the wallet points at a co-located local node instead of the remote mining nodes: that local node stays up regardless of which mining node you're rebooting. (The alternative — a single hostname over a health-checked TCP load balancer like nginx-stream/HAProxy in front of both nodes' 3413 — also works but adds more moving parts.)

3. iPollo — Pool Configuration:

Pool 1 stratum+tcp://node-A:3416 worker nickname.NN pass 123 Pool 2 stratum+tcp://node-B:3416 worker nickname.NN pass 123 Pool 3 gaeapool / 2miners worker = your GRIN payout address
A node you fail over to must be fully synced first. A freshly-restarted node opens the stratum port before it has caught up to the tip and will hand out stale block templates — wasted hashrate. Confirm sync_status is no_sync via the node Owner API (get_status) before trusting node-B. Only one node needs to be up at a time for mining to continue.
Not tested in production yet. The creator hasn't had time to run this two-node setup end-to-end — the single-node + public-pool failover above is the proven path. If you try the two-node HA and get it working (or hit snags), help would be hugely appreciated: please open an issue or PR on the Grin Node Toolkit repo so this section can be marked verified.

Additional info

How the stats update

Per-miner stats need file_log_level = "INFO" on the node — shares are logged at INFO. Set it in grin-server.toml and restart the node. (Found blocks record regardless — those log at WARN.)

Harmless wallet-log errors you can ignore

The wallet log may repeat lines like these:

ERROR grin_wallet_impls::node_clients::http - Error calling get_version: Request error: Cannot make request: error sending request for url (http://127.0.0.1:3413/v2/foreign): operation timed out ERROR grin_wallet_impls::node_clients::http - Unable to contact Node to get version info: ...
Safe to ignore for solo mining. This is the wallet's periodic version probe to the node's Foreign API on port 3413 (wallet → node). Solo mining does not use that direction to receive payment: your block rewards land because the node calls the wallet listener on port 3420 (build_coinbase, a local operation on the combined owner_api listener) — that path is independent of the failing probe. So coinbase keeps arriving even while these errors repeat. It only affects on-demand balance refresh and spending; if you later want those, make sure the node is running and reachable on 127.0.0.1:3413.

External pollers

Pool stats are also published as a machine-readable JSON feed for external tools and dashboards. Copy the endpoint:

data/poolstats_main.json

The feed is refreshed by the collector and carries both pool and network figures:

Submit this pool to miningpoolstats.stream/grin. The feed is built in their expected shape, so you can register this endpoint with MiningPoolStats to have the pool listed in the public Grin pool rankings. Testnet uses data/poolstats_test.json.