Bitcoin Forum
October 11, 2026, 02:07:54 PM *
News: Serious possible issue involving Ledger hardware wallets and CryptoBilis
 
   Home   Help Search Login Register More  
Pages: [1]
  Print  
Author Topic: CPU coin lessons: hashrate hopping, difficulty retarget and pool bugs  (Read 24 times)
parniancoin (OP)
Newbie
*
Offline

Activity: 26
Merit: 0


View Profile
October 10, 2026, 02:14:41 AM
 #1

CPU coin lessons: hashrate hopping, difficulty retarget and pool bugs

Disclosure: I'm the developer of ParnianCoin (PARC), a CPU-mined PascalCoin fork (RandomHash2). Everything below comes from running our own nodes and pools over the past few weeks. I'm sharing it because most of these problems apply to any small CPU-mined coin, and I wish I had read something like this before launch.



1. Hashrate hopping can stall a small network for hours

On a small chain, a single rented or profit-switching miner can be several times larger than the entire regular hashrate.

What we observed in one day:
  • Pool hashrate climbed from ~350 kH/s to over 1 MH/s within about an hour as a large worker joined.
  • At the peak, around 60 blocks were found in ~2.5 hours, roughly one every 2–3 minutes (target: 5 minutes).
  • Difficulty climbed ~1% per block, about 2.3x in total.
  • Then the large miners left at almost the same time. Hashrate dropped to ~100 kH/s, and block times jumped to 20–60 minutes.

The hopper collects cheap blocks, then leaves everyone else to pay for the difficulty it created.



2. Your retarget algorithm decides how long the pain lasts

We inherited PascalCoin's retarget logic, which compares two windows: the last 100 blocks and the last 10 blocks.
  • If both windows agree (both too fast or both too slow), difficulty moves normally: up to ~1% up or ~2% down per block.
  • If they disagree, a "slow movement" mode kicks in and caps the change at ~0.5% per block.

This is designed to prevent oscillation, and on a large network it works well. But right after a hopping event, the 100-block window is still full of fast blocks ("too fast") while the last 10 blocks are 30+ minutes ("too slow"). The windows disagree, so difficulty drops only 0.5% per block.

In our case, the slow mode lasted 9 blocks (~4.7 hours). Once enough slow blocks had entered the long window, both windows agreed, and difficulty started dropping ~2% per block. About 15 hours after the hashrate left, difficulty was back to roughly half of its peak.

Lesson: if you launch a small CPU coin, think about this before launch. Options include faster-responding algorithms (e.g. LWMA-style), or an emergency rule when recent block times are several times the target. Any change here is a consensus change, so it needs a planned activation height on all nodes.



3. Test your pool with nonces above 2^31

For weeks, a large share of our pool-found blocks were orphaned (over one week: ~2,650 orphans vs ~2,040 confirmed blocks). Clock sync, forks between nodes and stale jobs were all suspects. None of them was the cause.

The real cause: the node's JSON parser stored numbers in a signed 32-bit integer. The nonce is an unsigned 32-bit value, so any valid solution with a nonce above 2,147,483,647 (about half of all solutions) raised an exception during parsing. The submission was silently dropped, while the pool logged "Block found" and later marked it orphaned.

Clues that pointed to it:
  • Orphans at a given height had smaller (stronger) hashes than the block that was eventually accepted, so it was not a PoW problem.
  • After "Block found", the pool kept receiving work for the same height, so the node had rejected the block, not reorged it.
  • The node log showed "'2684641225' is not a valid integer value" at the exact second of each lost block.

After switching the parser to 64-bit integers: in the ~280 most recent blocks we reviewed, there was a single orphan (a duplicate solution submitted in the same second, which is expected).

Lesson: if you fork an older codebase, especially across compilers or platforms, grep for every place a nonce, timestamp or amount passes through a 32-bit signed type.



4. "CPU-only" does not automatically mean decentralized

CPU mining lowers the hardware barrier, but on a small network a few server-grade or rented machines can still hold a large share of the hashrate. Botnets are a further concern for every CPU-mineable coin. There is no perfect fix. Transparent hashrate stats and a growing base of small, independent miners are the realistic defenses.



Open question for other devs and miners:
How have other small CPU coins handled hashrate hopping? Did an emergency difficulty rule or LWMA actually solve it in practice, or did it introduce new problems?
parniancoin (OP)
Newbie
*
Offline

Activity: 26
Merit: 0


View Profile
October 10, 2026, 11:15:22 PM
 #2

CPU coin lessons, part 2: redundant pools, miner failover, payouts and onboarding

Disclosure: I'm the developer of ParnianCoin (PARC), a CPU-mined PascalCoin fork (RandomHash2). This is a follow-up to my earlier post on hashrate hopping, difficulty retarget and pool bugs. Again, everything here comes from running our own infrastructure, and most of it applies to any small coin.



1. Two independent pools beat one "highly available" pool

On a small network, the pool is often the single point of failure for most miners. Our first instinct was a clustered setup with shared state. We ended up doing the opposite: two physically separate machines, in different locations, on different ISPs with different public IPs, each running its own node, pool and stratum.

  • They share nothing except the blockchain itself. No shared database, no shared payout queue.
  • If one site loses power or internet, the other keeps finding blocks and paying its own miners.
  • A bug or bad config on one node cannot silently corrupt the other.

The trade-off: miners' shares and balances are split between two pools. For us that was acceptable. Simple and independent was easier to reason about than "clever and shared".



2. Put failover in the miner, not in DNS

DNS-based failover sounds easy, but TTLs, resolver caching and long-lived stratum connections make it slow and unpredictable. Instead, our miner takes a failover stratum address (-fo). If the primary stratum stops responding, it switches to the backup on its own.

Two related lessons:
  • Keep the web portal and the stratum endpoint on different hostnames. Our pool.* hosts are web-only; miners only ever point at stratum.* hosts. This lets you put the website behind a CDN/proxy while stratum stays a direct TCP connection (free CDN tiers generally don't proxy raw stratum traffic).
  • Publish both stratum addresses in every guide and every ready-made config. A failover feature nobody configures is useless.



3. A watchdog keeps you up, but it can also hide bugs

We run a watchdog that restarts the node if it is not responding for about a minute. This saved us several times.

But a watchdog also makes failures invisible: the chart looks fine while the node restarts quietly in the background. Log every restart with a timestamp and the last lines of the node log. In my previous post, the integer overflow bug was found because the node log was kept, not because anything visibly crashed.



4. Pay only for mature blocks

Our pools pay out every 10 minutes, but only for blocks that have reached 100 confirmations. Pool fee is 0.5%.

Miners sometimes ask why they have to wait. Our orphan problem answered that question: during the weeks when about half of our "found" blocks were actually orphaned, no one was paid for a block that didn't exist. If we had paid immediately on "Block found", the pool would have paid out coins it never earned, and the loss would have been permanent.

Lesson: if your coin is small and young, be conservative with block maturity. You can always shorten it later; you cannot take back payouts.



5. Account-based chains have an onboarding problem

PascalCoin-style chains don't use addresses. To receive coins, you need an account (a numbered account linked to your public key), and new accounts are created only when blocks are mined. A brand-new miner who wants to try your coin often has nowhere to receive their payout.

What worked for us:
  • A web wallet, so nobody has to install a desktop client just to try the coin. Keys are created and encrypted in the browser.
  • An account faucet: a pool of empty (zero-balance) accounts that are given away for free and transferred to the new user's public key.
  • Ready-made miner packages (including HiveOS and mmpOS), so the path is: get a free account → paste the number into the config → start mining.

If your coin uses an account model, solve this before launch. Every extra step between "I want to try this" and "I'm mining" costs you miners.



Open question for pool operators:
For small coins, do you prefer independent pools (like ours), or a shared backend with multiple stratum servers? If you run a shared setup, how do you handle payouts when one node is on a different chain tip?
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!