Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Mining on Testnet with s-nomp

The Zcash Foundation’s s-nomp fork connects Equihash miners to Zebra through Stratum, a protocol for distributing mining jobs and collecting solutions. This is an experimental Testnet setup, not a production pool: custom coinbase construction and pool-fee outputs are disabled, and this procedure disables worker payments. All miner rewards go to [mining] miner_address in Zebra. A worker’s Stratum username does not select a payment recipient.

Compatibility and limitations

The public fork’s default branch is zebra-mining. Its package version is 0.0.9; the source revision used below is 49fd89bf. Use Node.js 10.24.1 and Python 3.10, selected by the fork’s container recipe, not the README’s Node.js 8.11. Node.js 12 and later have incompatible Equihash native-module APIs.

The pool’s stratum-pool dependency passes Zebra’s coinbasetxn.data and coinbasetxn.hash through unchanged. Its block assembly forwards the supplied transactions and uses the legacy finalsaplingroothash field, which Zebra fills with the current block commitment. This bypasses the obsolete custom coinbase builder. It provides neither a current transaction parser nor a payment implementation.

The fork supplies pool_configs/zcash_testnet.json for native use. Its container entrypoint generates a separate configuration but omits two settings required for this deployment:

  • The missing switching object causes Object.keys(portalConfig.switching) to fail at startup.
  • Its generated Stratum port omits tls: false. The dependency selects TLS unless that field is explicitly false, so a plain-TCP miner cannot use the generated default.

Use the fork’s container build with Zebra’s s-nomp-entrypoint.sh. The wrapper supplies both settings. The repository Compose stack has separate Zebra startup defects.

Prepare the sources

Use a Linux x86-64 host with Docker, Git, and jq. Keep this old pool runtime on a dedicated Docker network. Do not expose its Redis, RPC, web interface, or Stratum listener to untrusted clients.

Clone the sources into a working directory:

git clone --branch v7.0.0 --depth 1 https://github.com/ZcashFoundation/zebra.git zebra
git clone --branch zebra-mining https://github.com/ZcashFoundation/s-nomp.git s-nomp
git -C s-nomp checkout --detach 49fd89bf32fac6fe2440143d16622650e061e5a0

In s-nomp/package.json, pin the stratum-pool dependency:

"stratum-pool": "git+https://github.com/upbqdn/node-stratum-pool.git#7fbb0685f8895abf1b746d6682de30dd814b9382"

Build the pool image:

docker build -f s-nomp/Dockerfile.arch -t zebra-s-nomp s-nomp

The Dockerfile installs Boost, libsodium, GMP, Redis, and native build tools, sets CXXFLAGS=-std=gnu++17, and patches the RPC transport. Other npm dependencies and the Arch base image remain unpinned; this is not a reproducible dependency build.

The transport patch adds "jsonrpc":"2.0" to the startup batch, as required by Zebra’s batch protocol. A plain npm install leaves that batch incompatible.

Install, run, and sync Zebra

Set MINER_ADDRESS in the shell to a transparent Testnet address that you control. This recipe also uses it for s-nomp’s transparent-address startup check, even though Zebra itself supports additional miner address kinds.

Create a dedicated network and start Zebra:

docker network create zebra-mining

docker run -d --name zebra-testnet \
  --network zebra-mining \
  -e ZEBRA_NETWORK__NETWORK=Testnet \
  -e "ZEBRA_MINING__MINER_ADDRESS=${MINER_ADDRESS:?Set a Testnet MINER_ADDRESS}" \
  -e ZEBRA_RPC__LISTEN_ADDR=0.0.0.0:18232 \
  -e ZEBRA_RPC__ENABLE_COOKIE_AUTH=false \
  -p 18233:18233 \
  -v zebra-testnet-mining-cache:/home/zebra/.cache/zebra \
  zfnd/zebra:7.0.0

The pool’s generated daemon credentials are the fixed strings x and x; it does not load Zebra’s cookie. This example therefore disables RPC authentication but does not publish port 18232. Attach only trusted containers to this network. The authenticated setup in Mining with Docker is preferable for pool software that supports it.

Inspect synchronization:

docker logs --follow zebra-testnet

Before starting s-nomp, request a template from inside the node container:

docker exec zebra-testnet curl --fail-with-body --silent --show-error \
  --header 'Content-Type: application/json' \
  --data '{"jsonrpc":"2.0","id":1,"method":"getblocktemplate","params":[]}' \
  http://127.0.0.1:18232/ | jq

Wait for a result containing a template, not an RPC error; see the sync requirements. The supplied coinbase handles NU7 funding-stream and NSM fee accounting.

Run s-nomp

Run these commands from the directory containing the zebra and s-nomp checkouts:

docker run -d --name s-nomp-testnet \
  --network zebra-mining \
  -e NETWORK=Testnet \
  -e ZEBRA_HOST=zebra-testnet \
  -e ZEBRA_RPC_PORT=18232 \
  -e STRATUM_PORT=3333 \
  -e "POOL_ADDRESS=${MINER_ADDRESS:?Set a Testnet MINER_ADDRESS}" \
  -p 127.0.0.1:3333:3333 \
  -p 127.0.0.1:8080:8080 \
  --mount "type=bind,source=$PWD/zebra/docker/mining/s-nomp-entrypoint.sh,target=/app/s-nomp-entrypoint.sh,readonly" \
  --entrypoint /bin/bash \
  zebra-s-nomp /app/s-nomp-entrypoint.sh

docker logs --follow s-nomp-testnet

The entrypoint generates /app/config.json and /app/pool_configs/zcash.json, selects coins/testnet/zec.json, disables payment processing, starts Redis on local port 6379, and runs node init.js.

The pool polls for block templates every 500 milliseconds. Its website is available on the host at http://127.0.0.1:8080. The pool’s startup message Stratum Pool Server Started indicates that it has created a job and started the listener; it does not establish that the pool has mined an accepted block.

The entrypoint overwrites generated configuration on each start. Do not edit those files expecting the changes to survive a container restart.

Install and run a CPU miner

The Zcash Foundation’s nheqminer fork supplies a Dockerfile for a CPU-only build with the Xenoncat solver. This solver requires an x86-64 CPU with AVX support; it selects AVX2 when available. The following revision is from the zebra-mining branch:

git clone --branch zebra-mining https://github.com/ZcashFoundation/nheqminer.git nheqminer
git -C nheqminer checkout --detach 72e320aacaa49c9e170be62d28a4189957767d3c
docker build -t zebra-nheqminer nheqminer

docker run -d --name nheqminer-testnet \
  --network zebra-mining \
  zebra-nheqminer \
  -l s-nomp-testnet:3333 \
  -u "${MINER_ADDRESS:?Set a Testnet MINER_ADDRESS}.worker1" \
  -t 1

docker logs --follow nheqminer-testnet

The miner’s -t 1 option selects one CPU thread. A native Equihash miner on the same host can instead connect to 127.0.0.1:3333. Do not use port 18232 as a Stratum endpoint; it belongs to Zebra’s JSON-RPC server.

A share accepted by the pool is not necessarily a block: it can meet the pool’s easier share target without meeting the network target. Check Zebra’s submitblock outcome and best chain when evaluating a mined block.

Diagnose failures

SymptomCheck
Missing config.json or no enabled poolsStart through the entrypoint; npm start alone does not generate configuration.
Unauthorized RPC accessThe generated x credentials do not authenticate against Zebra’s default cookie authentication. Do not solve this by exposing unauthenticated RPC.
Error -10 from getblocktemplateWait for Zebra to synchronize.
Mining-parameters error from getblocktemplateCheck Zebra’s reward address, selected network, and memo length.
Block rejected after changing coinbase or transactionsRestore the supplied template or implement current coinbase, commitment, and NU7 rules.
Website logs Could not dumpprivkeyThe website calls this unsupported wallet RPC even with payments disabled. Zebra holds no wallet keys; this error concerns the website’s mining-key page, not block-template generation.

Stop the experiment

Stop the miner before the pool and node:

docker stop --timeout -1 nheqminer-testnet s-nomp-testnet zebra-testnet

The Zebra state volume remains available for reuse. The pool recipe does not mount a persistent Redis volume; do not treat its share statistics as durable payment records.