Snowblossom Docs
Docs › Running software › Mining

Mining

Mining means finding a nonce whose Stoat hash is below the target. Because every attempt costs six random reads from the snow field, the decisive resource is storage IOPS (or RAM), not CPUs. This page covers the miners, the pool software and the two mining protocols.

Required field
9 · hippo
512 GiB + decks on local storage
Network hash rate
-
≈ 2diff / block time
Difficulty
-
next field at 45
Reward per block
-
+ fees, every ~10 min

Choosing a miner

ProgramWorks withBest for
PoolMinera poolAlmost everyone. One machine, field on SSD/NVMe or in RAM, steady PPLNS payouts in every pool block.
Arktikaa poolBig setups: the field split over several drives or several machines' RAM, joined over the LAN.
SurfMinera poolSlow sequential media (HDD arrays): reads the field in waves, needs lots of RAM for in-flight work.
SnowBlossomMineryour nodeSolo mining; only pays when you find a whole block (currently about 160 blocks/day across the whole network).
MrPlownodes + minersRunning your own pool.

What every miner needs

  • The activated snow field or a larger one under snow_path/snowblossom.N/ with its deck files. The miner refuses fields that fail its 64-proof self-test and tells you which fields it found (“Unable to select a field of at least N. Availible: […]”). Download via torrent from snowblossom.org/snowfields, or set auto_snow=true to generate in place (slow).
  • A 64-bit Java 17+. For memfield, a heap larger than the field (java -Xmx600g for hippo…).
  • An address to mine to: mine_to_address=snow:… (recommended) or mine_to_wallet=<dir> (a random address of that wallet is used).
  • Threads: each thread does blocking reads, so on disk-backed fields use many more threads than cores (threads=64256 on NVMe) to keep the queue depth up; in RAM, about one per core.

Reading the log: PoolMiner prints every 15 s 15 Second mining rate: R/sec - at this rate M minutes per share (diff D), then 1-min: … 5-min: … hour: … and Shares: N (rejected R) (blocks B). If the rate is 0 and there is no work unit it reconnects (“Stalled. No valid work unit, reconnecting to pool”). Expected hashes per share are 2D; per block 2difficulty.

PoolMiner

network=snowblossom
log_config_file=configs/logging.properties
pool_host=snowblossom.hamster.science     # or pool_uri=grpc+tls://pool.example:23382?key=node:…
#pool_port=23380
#pool_host_list=pool-a,pool-b             # failover list, first reachable wins
snow_path=snow
mine_to_address=snow:your-address
threads=64
#memfield=true                            # whole field in JVM heap
#memfield_precache_gb=200                 # first N GiB in RAM …
#min_depth_to_disk=2                      # … abandon attempts whose first 2 reads miss the cache
#auto_snow=true
#mining_client_id=rig-1                   # free-form id sent to the pool
#rate_limit=10000                         # hashes/s cap, for testing

Behaviour: it subscribes to the pool's GetWork stream, receives work units (a header template with a 4-byte work id in the nonce and a per-miner share target), hashes with random nonces that keep that prefix, and submits any result below the share target. Work units older than 45 s are discarded; templates are refreshed by the pool on every new block and every 20 s. The miner raises snow_field in the header to the field it actually uses. With pool_host_list or pool_uri (comma lists) it subscribes to all pools and works for the first one delivering fresh work, re-checking every 60 s (failover and fail-back take up to a minute). remark/vote_* in a pool-miner config are ignored - the pool sets the coinbase.

SnowBlossomMiner (solo)

network=snowblossom
node_host=localhost                        # or node_uri=grpc+tls://…
snow_path=snow
mine_to_address=snow:your-address
threads=64
#remark=hello from my basement            # coinbase remark (≤ 100 bytes)
#vote_yes=7
#vote_no=8                                # SIP votes (motions)
#memfield=true
#memfield_precache_gb=
#min_depth_to_disk=
#auto_snow=true
#rate_limit=

It calls SubscribeBlockTemplate on the node and receives full block templates (coinbase paying your address, mempool transactions, target computed for “now”). The node refuses templates until it is synced. Templates older than 75 s are dropped; a new one arrives on every block and at least every 30 s. On a hit the miner builds the six proofs and calls SubmitBlock; the reply is logged (“Block submit: success: true”). Stats every 45 s: Mining rate: R/sec - at this rate H hours per block. Whole reward + fees go to one address; there is no pay_ratios support in the solo miner.

Arktika

Arktika treats the field as 1 GiB chunks served by ordered layers. A hash in progress (PartialWork: nonce, context, passes done, next word index) is queued at the first layer holding the chunk of its next word; layers earlier in the list have priority, so you list RAM first, then SSD, then HDD or remote. Layer types: file (a directory with the blob or .snow.0000… chunk files; also the source of decks for proofs), mem (a chunk range loaded into the heap at start, 1 GiB each), remote (chunks fetched in batches of 1,024 requests from another Arktika's word server on port 2311), fake (random data, benchmarking only). Pool-only; mines one fixed selected_field and stops if the pool requires a higher one.

# three machines each hold a third of field 7 in RAM (example/arktika/node1.conf)
network=snowblossom
pool_host=snowday.fun
mine_to_address=snow:…
selected_field=7
layer_count=4
layer_0_type=mem
layer_0_threads=6
layer_0_range=0,42                 # chunks 0..42 inclusive, loaded into the heap
layer_1_type=remote
layer_1_threads=1
layer_1_range=43,85
layer_1_host=10.138.0.3            # another Arktika serving chunks 43..85 from RAM
layer_2_type=remote
layer_2_threads=1
layer_2_range=86,127
layer_2_host=10.138.0.4
layer_3_type=file
layer_3_threads=0
layer_3_path=/var/snow             # decks + proofs only
#listen_port=2311
#nolisten=true
#benchmark_layer=0
#benchmark_threads=32              # random-read benchmark of one layer, no mining

Notes: layer_N_range is start,end - inclusive for mem/remote, end-exclusive for file. Each layer has a queue of 10,000 partial works; when a slow layer saturates, the least-advanced work is discarded, and the Queues: {…} line in the 15-second stats shows which layer is the bottleneck. Per-layer lines report read_ops/s (hash rate ≈ read ops ÷ 6), read_bw, and for remote layers rpc_ops/s and network bandwidth. At least one local layer must have all deck files. Run with a heap sized for the mem layers (java -Xmx50g -jar Arktika_deploy.jar arktika.conf).

SurfMiner

Turns random reads into sequential ones: waves threads stream the field chunk by chunk (chunk_size_mb, default 1024) in a ring, and for each chunk process every queued attempt whose next word lies in it, then re-queue it under the chunk of its next index. Throughput depends on how many attempts are kept in flight: work_unit_mem_gb sets the RAM budget at 57 bytes per attempt. Required: snow_path, selected_field, waves, hash_threads, work_unit_mem_gb; pool options as PoolMiner. Each hash completes only when a wave reaches the chunk of its final index, so results lag by up to one sweep of the field. Stats every 60 s. Best suited to large HDD arrays where sequential bandwidth is plentiful and IOPS scarce.

MrPlow - running a pool

log_config_file=configs/logging.properties
node_uri=grpc://localhost,grpc+tls://snow-b.1209k.com    # ALL are used; best template wins
db_type=atomic_file
db_path=pool_db/mainnet
pool_address=snow:your-fee-address
pool_fee=0.005                 # 0.5 % of every block
pay_the_duck=0.01              # optional developer donation (1 %) to snow:crqls8qkumwg353sfgf5kw2lw2snpmhy450nqezr
min_diff=22                    # starting share difficulty
mining_pool_port=23380
#tls_mining_pool_port=23382
#tls_key_path=pool_db/tls
#remark=my pool
#vote_yes=
#vote_no=
#report_path=report.txt        # hash-rate report every 60 s
#rpc_port=8802                 # unauthenticated JSON-RPC: getstats, getfoundblocks, gettemplatestatus - keep on localhost

How it works:

  • Templates. One connection per node in node_uri, each subscribed with SubscribeBlockTemplateStreamExtended. Every 20 s (and on every new template) the pool picks the best template among those younger than 100 s: highest advances_shard, then highest reward per hash (Σ coinbase outputs ÷ 2difficulty), then lowest height. With sharding, listing nodes that track different shards lets the pool mine whichever shard pays best.
  • Work units. Each miner gets the template header with a unique 4-byte work id as nonce prefix and a report_target for its own difficulty. Shares are validated in order: known work id, field ≥ template's, hash below share target, nonce prefix, nonce not reused, then the full PoW proof check (checkBlockHeaderBasics ignoring the network target). A share that also beats the real target becomes a block and is submitted to every node tracking that shard (“SUBMITTING REAL BLOCK”).
  • Variable difficulty. Per miner, starting at min_diff (222 hashes per share): ≥ 12 shares in 2 minutes → difficulty +1; < 4 shares in 2 minutes (and 2 minutes since the last change) → −1, never below min_diff nor above network difficulty − 1. Small test setups should lower min_diff.
  • PPLNS. A share at difficulty d counts 2d − min_diff units. The share window is pruned to the expected number of shares for the last 5 blocks at current network difficulty. Pay ratios = each address's units in the window, plus fee weights chosen so the pool address receives exactly pool_fee (and the duck pay_the_duck).
  • Payout is in the coinbase. The ratios are sent to the node as pay_ratios; every block the pool finds pays every miner in the window directly as coinbase outputs (zero-flake shares are dropped, the rounding remainder goes to one random miner). No pool wallet, no balances, no minimum payout - look at any pool block on the explorer to see dozens of coinbase outputs.
  • State (pplns_state, blocks_found) is saved every 20 s; MrPlowDataMigrate moves it between database types.

The mining protocols

Pool protocol (protolib/mining_pool.proto)

service MiningPoolService {
  rpc GetWork    (GetWorkRequest)    returns (stream WorkUnit);
  rpc SubmitWork (WorkSubmitRequest) returns (SubmitReply);
}
message GetWorkRequest    { string client_id = 1; string pay_to_address = 2; }
message WorkUnit          { BlockHeader header = 1; int32 work_id = 2; bytes report_target = 3; }
message WorkSubmitRequest { BlockHeader header = 1; int32 work_id = 2; }
// Arktika word server:
service SharedMiningService { rpc GetWords(GetWordsRequest) returns (GetWordsResponce); }

Ports 23380 (plaintext) and 23382 (TLS, pinned like nodes with ?key=node:…). SubmitReply{success, error_message} is shared with the node API; rejections read e.g. “Hash larger than reporting target” or “Too low of snow field”.

Node template protocol

rpc SubscribeBlockTemplate(SubscribeBlockTemplateRequest) returns (stream Block);
rpc SubscribeBlockTemplateStream(stream SubscribeBlockTemplateRequest) returns (stream Block);
rpc SubscribeBlockTemplateStreamExtended(stream SubscribeBlockTemplateRequest) returns (stream BlockTemplate);
rpc SubmitBlock(Block) returns (SubmitReply);
message SubscribeBlockTemplateRequest {
  bytes pay_reward_to_spec_hash = 1;     // whole reward to one address, or …
  int64 refresh_delay = 2;               // ignored
  CoinbaseExtras extras = 3;             // remarks, motions_approved, motions_rejected
  map<string, double> pay_ratios = 4;    // … split by weight (pools)
}
message BlockTemplate { Block block = 1; int32 advances_shard = 2; }

The streaming variants let a pool change its pay ratios without reconnecting (required since 1.7). A “null template” (empty target / version 0) tells the miner to stop. The miner must fill nonce, snow_hash, six pow_proofs and may raise snow_field.

Economics and the calculator

Expected blocks per day for a miner with hash rate r against network rate R are 144 × r / (R + r) (your own hashes raise the network rate). The explorer's mining page has a live calculator and shows which pools found recent blocks and how coinbase remarks vote on proposals. Miners set votes with vote_yes=/vote_no= (pools vote for their miners) - see voting.

Pools

Pools announce themselves in coinbase remarks. The explorer lists which remarks (pools) found the last 1,000 blocks: live list. The community wiki maintains a list of known pools; entries seen there (fees as listed, verify before use): Hamster Pool (snowblossom.hamster.science, 0.5 %), Snowfox (pool.snowfox.world), SnowYday (snowyday.xyz), Snow-Pool (snow-pool.org), Snowypool (snowypool.com), Arctic Fox (arcticfox.cc, currently mining), findsnow, SNOWPLOUGH. Point pool_host at the host (port 23380 unless stated).

Docker

snowblossom/poolminer and snowblossom/pool images exist; the miner entrypoints default to auto_snow=true, threads=1 and rate_limit=10000, so pass snowblossom_pool_host, snowblossom_mine_to_address, snowblossom_threads, snowblossom_rate_limit= and mount the fields at /data/snowfields.