00 The two paths
A — Work path
- Miner's hardware
SHA-256 miner
Any SHA-256 ASIC. Logs in as
<payout address>.<worker>. Submits shares. - Pool
Stratum mining server
ckpool fork. Hands out jobs, validates shares, records them by payout address.
- Node
Spearmint Core
getblocktemplate/submitblock. RPC bound to localhost only. - Network
Spearmint blockchain
Block accepted by the decentralised network under its consensus rules.
B — Reward path
- From the chain
Mined block reward
Coinbase output to the pool's operational address. Unspendable for 100 blocks.
- Pool
Reward calculation
PPLNS over the window; 1% pool fee deducted; one allocation per payout address.
- Pool
Automatic distribution
Daily run at 00:00 UTC; mature allocations ≥ 1 SPMTC batched into one transaction.
- Miner's own keys
External Spearmint address
The address the shares were mined under. The pool never holds its keys.
— There is no customer-deposit arrow. Nothing enters this system from a miner except shares. —
01 Components
| Component | Role | Exposure |
|---|---|---|
| Stratum server | ckpool fork. Job distribution, share validation, variable difficulty, share recording. | Public: 3333 (tcp), 3334 (tls). Rate-limited. |
| Share database | Append-only store of shares, blocks, allocations, payout runs, payouts. | Internal only. |
| Reward calculator | Runs on each block find; computes the PPLNS window and per-address allocations; re-runs on maturity or orphan. | Internal only. |
| Payout daemon | Daily run; builds and signs the batch transaction on the isolated signing host; records txid. | Internal; signing host air-gapped from the public hosts. |
| Spearmint Core node(s) | Templates for the Stratum server; block submission; a separate node backs the read-only stats API. | P2P 9333 only. RPC on localhost. |
| Read-only stats API | Serves dashboard data by payout address, block list, payout-run txids, network statistics. | Public, read-only, cached. |
| Static website | This site. No server-side session, no login. | Public. |
02 Data model
The schema is small on purpose. Every table describes mining or its results.
| Table | Columns | Notes |
|---|---|---|
workers | payout_address, worker_name, first_seen, last_seen | Created on first valid login. No password column exists. |
shares | ts, payout_address, worker, difficulty, result (valid / stale / rejected), block_hash (if solved) | Append-only. Exportable per payout_address. |
blocks | height, hash, coinbase_txid, reward, fees, found_ts, matured_ts, status (pending / mature / orphaned) | Status driven by the node, not by an operator. |
reward_allocations | block_id, payout_address, share_weight, gross, fee, net | One row per address per block. Reversed (not deleted) on orphan. |
payout_runs | run_ts, txid, total, network_fee | One row per daily run. |
payouts | run_id, payout_address, amount, fee_share, status | One output of the batch transaction per row. |
notification_registrations | payout_address, email, signed_message, ts | Optional. Proof of address control by signature; no password. |
compliance_events | ts, type, payout_address or ip_country, decision, reason, actor | Sanctions gate decisions, holds, releases. Append-only. |
balances table, no transfers table, no deposits table, and no
user-to-user relation anywhere. The only money-like column is reward_allocations.net. Summed per
address, it is the pending mining reward; it exists to be paid out, and the payout daemon's job is to make it zero.
03 Operational keys
- The private key for the pool's coinbase address lives on an isolated signing host that is not reachable from the public hosts. The payout daemon submits an unsigned batch to it; it returns a signed transaction.
- The hot amount at that address is kept minimal by the daily run. What remains after a run is the pool's own fee income plus allocations below the threshold and not-yet-mature rewards.
- Anything above operational need is moved to a cold key held offline. Key generation is done in a documented ceremony with two people present and encrypted backups in separate locations.
The coinbase output is the operator's own mined reward at the moment it is created, before apportionment. The pool apportions and distributes it under the published methodology. It is not miner property taken into custody; it is a reward the pool has committed, in advance and in writing, to split in a known way.
04 Failure modes
| Event | Effect | Visible as |
|---|---|---|
| Block orphaned before maturity | All allocations for that block are reversed; pending mining reward decreases for affected addresses. | Block status "orphaned"; dashboard shows the decrease with reason. |
| Payout batch fails to confirm | Run marked failed; payouts remain pending; retried in the next run. | Payout history row "failed — retrying"; logged. |
| Node detects a competing chain / reorg in progress | Payout runs paused until the node is back on a single best chain; allocations recomputed if any block changed status. | Notice on /network/; updates page if longer than one run. |
| Stratum server outage | No shares recorded during outage; nothing is credited that was not worked. | Incident notice; post-mortem on the build log. |
| Signing host unreachable | Run skipped; retried hourly until it succeeds. | Delay shown in payout history. |
05 Boundaries
Interfaces that do not exist, and are not to be added without a new legal review (see regulatory change control):
- No deposit address per miner. The pool has one address, its own, and it is the coinbase destination.
- No internal ledger between miners. Allocations are per address per block and cannot reference another address.
- No API, form, or admin action that moves an allocation from one payout address to another.
- No key generation, key display, or key storage on behalf of miners.
- No endpoint that accepts an inbound transaction as input to anything.