So, imagine we wanna bring back difficulty adjustments for regtest, just to check if mining is functioning correctly. Here's how we can pull it off:
Now, let's see if we can generate regtest blocks using just a CPU in an endless bash loop to keep it straightforward:
Initially, the regtest difficulty is set to "207fffff", and we can spot that when checking blocks up to block number 143:
But when we look at the hash for the next block, it suddenly has way more leading zeroes than we expected if the difficulty was just raised fourfold:
It jumped from "207fffff" to "1f00be2e", which isn’t just a "four times harder" situation (the max adjustment) but more like "at least 44108 times harder":
Any thoughts on why this happened? The following adjustments aren’t as drastic, for instance:
And if we tally how many times it actually increased:
Just four times, like we anticipated. So what’s up with that first adjustment?
Sudden spike in regtest difficulty
6 replies 44 views
gr3g.0rbitHero Member
Posts: 1025 · Reputation: 2646
#2Mar 16, 2020, 11:36 AM
Could be because RegTest has "fPowAllowMinDifficultyBlocks = true" parameter, which can cause it to pass the permitted difficulty transition limits.
github.com/bitcoin/bitcoin/blob/7cc9a087069bfcdb79a08ce77eb3a60adf9483af/src/pow.cpp#L91
The exact reason how it came up with that value however, I can't tell.
No, it only allows mining blocks with minimal difficulty after 20 minutes, just like it is possible in testnet3 and testnet4.
However, I am still curious, why the real network difficulty is changed in that way. And it also bounces back and forth, when blocks have 15 minutes of delay between each other, without reaching the minimal value, as it should.
diamond_ledgerFull Member
Posts: 35 · Reputation: 295
#4Mar 16, 2020, 05:35 PM
Since you mined 144 blocks in zero seconds, the retarget math didnt just give you 4x it gave you 144x600÷elapsedtime which came out ~44k. Then the ±4x kicked back in on the next window.
It's averaged but the first blocks have nothing to baseline against. You also made it more aggressive going 2016 to 144.
tldr you gamed your own system and got punished.
This is the default value for regtest. I guess I should replace it with 2016.
The difficulty can be trivially lowered, just by using more than 20 minutes of delay between regtest blocks, no matter how huge the network difficulty will be. Another interesting thing is if the difficulty will be bumped for example from 0x207fffff to 0x1f00be2e, then guess what: even if you use hours between blocks, then it won't decrease back to 0x207fffff. Do you know why? And why it bounces back and forth, even if the time between blocks is set to 15 minutes, instead of constantly decreasing?
diamond_ledgerFull Member
Posts: 35 · Reputation: 295
#6Mar 17, 2020, 04:46 PM
It retargets at 288 if it theoretically takes 1-2 months on your same settings after you hit block 288. (Stick with the punishment and see how it corrects)
It should agressivley retarget possibly even lower than your target.
It looks like your algo's doing what you told it to. Your deterministic variables are elapsed time. ± is overshoot or undershoot. You just way undershot it , and I think you got the book thrown at you.
paul.ninjaFull Member
Posts: 152 · Reputation: 539
#7Mar 17, 2020, 05:18 PM
Good experiment. What you're seeing on the first retarget is expected once you look at what the code actually uses for the window and the timestamps.
The first jump is way more than 4x because the retarget formula is , with the 4x clamp applied to actualTimespan (min = target/4, max = target*4).
actualTimespan is computed from MedianTimePast (MTP): MTP(last) - MTP(first_in_window).
In your loop you're blasting blocks as fast as the CPU can make them, so many consecutive blocks share nearly the same timestamp (or advance by 1). That makes the first window's actualTimespan tiny.
Because you re-enabled retargeting on regtest starting from the powLimit (bits = 0x207fffff) and mined the entire first window at that max target, the computed new_target gets pushed far below 1/4 of the old target before the compact encoding, and after Compact rounding the exponent drops from 0x20 to 0x1f (your 0x1f00be2e). That exponent drop alone is a ~256x step; combined with the tiny timespan you end up with the ~44108x you measured.
After that first "snap," subsequent windows have less extreme MTP deltas (and you're no longer right at the powLimit boundary), so the clamp bites and you see the normal ×4 behavior.
How to see/prove it quickly:
Inspect MTPs across your first window:
Compare heights 0, 143, 144. You'll find MTP(last) - MTP(first) is very small on that first window.
Convert bits to targets to see the exponent drop (20h→1Fh) exactly matches your ~44108 ratio.
Some ways to make regtest adjustments behave "boring" are:
Step time forward while mining:
Use setmocktime (or just sleep) so each block advances ~nPowTargetSpacing. Example:
Disable the special-min-difficulty path while testing retargeting:
Set fPowAllowMinDifficultyBlocks = false on regtest if you want pure mainnet-like difficulty math.
Keep params consistent, ensure DifficultyAdjustmentInterval == nPowTargetTimespan / nPowTargetSpacing. Mismatched values give non-intuitive jumps when windows roll.
The 4x bound is on time, not on the compact-encoded bits. If your first window's MTP barely moves and you start at powLimit, the first compact normalization can cross an exponent boundary and look like a mega-jump. After the first window, things stabilize.
Related topics
- Bitcoin Core displaying coins (UTXOs) in a new tab 13
- Are you in favor of BIP-110? Let's get a Bitcoin poll going. 0
- Erlay seems to have some issues here’s a better proposal for a bitcoin protocol without invites 3
- New Optional Hourglass Implementation is Live 3
- Ways to earn some sats by contributing to bitcoin core development 5
- Exploring the Potential and Challenges of a Kardashev-Scale Bitcoin Network 3