First, I want to point out that I'm only reporting this here because it can't be used to fork mainnet or testnet. However, this is a problem for the regression test network if any of the tests actually had more than 2016 blocks to exercise the retarget code.
While doing some testing using our simulation test network in btcd, Josh Rickmar and I noticed that Bitcoin Core improperly calculates the difficulty readjustment due to an overflow which occurs on the regtest network. This is different behavior from all versions of Bitcoin Core prior to commit
https://github.com/bitcoin/bitcoin/commit/df9eb5e14fa8072bc8a82b59e712c2ba36f13f4c.
The issue is that previously the calculations used the CBigNum class, which in turn used arbitrary precision OpenSSL bignums, are now limited to 256-bit integers. For reference, here is the difficulty readjustment calculations in pow.cpp:
const arith_uint256 bnPowLimit = UintToArith256(params.powLimit);
arith_uint256 bnNew;
arith_uint256 bnOld;
bnNew.SetCompact(pindexLast->nBits);
bnOld = bnNew;
bnNew *= nActualTimespan;
bnNew /= params.nPowTargetTimespan;
if (bnNew > bnPowLimit)
bnNew = bnPowLimit;
Notice that readjustment is calculated by multiplying the old difficulty (converted from its compact representation to a uint256) by the adjusted time span (which is limited to a max of the target time span * 4 and min of target time span / 4). The result is then divided by the target time span and converted back to compact form. Unfortunately, this means that using the new uint256s introduced with the aforementioned commit causes the result of the `bnNew *= nActualTimespan;` line to overflow, whereas previously it was arbitrary precision and would not.
Using real numbers for regtest, the forking condition becomes clear.
First, let's do the math using the old arbitrary precision based arithmetic. For the sake of simplicity and to illustrate the issue, we'll assume that first 2016 blocks are found fast enough such that the minimum possible multiplication case gets hit.
Compact Bits for regtest genesis block: 0x207fffff
Converted to a uint256: 0x7fffff0000000000000000000000000000000000000000000000000000000000
nTargetTimespan: 14 * 24 * 60 * 60 = 1209600 = 0x127500
nActualTimespan = nTargetTimespan/4 = 302400 = 0x49d40 (minimum possible multiplier for sake of simplicity)
bnNew.SetCompact(pindexLast->nBits) --> 0x7fffff0000000000000000000000000000000000000000000000000000000000
bnNew *= nActualTimespan --> 0x7fffff0000000000000000000000000000000000000000000000000000000000 * 0x49d40 = 0x24e9ffb62c00000000000000000000000000000000000000000000000000000000000
*** Notice how the previous line overflows max uint256, but is fine because of the arbitrary precision arithmetic of OpenSSL ***
bnNew /= Params().TargetTimespan() --> 0x24e9ffb62c00000000000000000000000000000000000000000000000000000000000 / 0x127500 = 0x1fffffc000000000000000000000000000000000000000000000000000000000
Old Expected difficulty bits: 0x201fffffNow, let's repeat the math using the
current code in Bitcoin Core:
bnNew.SetCompact(pindexLast->nBits) --> 0x7fffff0000000000000000000000000000000000000000000000000000000000
bnNew *= nActualTimespan --> 0x7fffff0000000000000000000000000000000000000000000000000000000000 * 0x49d40 = 0xfb62c00000000000000000000000000000000000000000000000000000000000
*** Notice how the previous line overflows max uint256, but is now 2s complement wrapped and thus is not the same as above ***
bnNew /= Params().TargetTimespan() --> 0x7fffff0000000000000000000000000000000000000000000000000000000000 / 0x127500 = 0xd9ebbc99a778556334111eefccdaab889667445223000ddebbc99a77855
New Expected difficulty bits: 0x1e0d9ebbNotice how the calculated value is much lower than it should be as compared to the previous behavior and therefore leads to the required proof of work being ~154000 times more difficult than it should be.
A little more math shows that since the maximum multiplier is nTargetTimespan*4 = 4838400 = 0x49d400, this overflow condition can occur so long as the difficulty is >= 0x377aef2669de1558cd0447bbf336aae22599d11488c00377aef2669de15 (compact bits: 0x1e0377ae).
A simple fix is using higher precision arithmetic for the intermediate results. Josh Rickmar is working on a patch which does this.