-
Notifications
You must be signed in to change notification settings - Fork 38.7k
Use 512-bit arithmetic for difficulty retarget calculation. #6162
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
More details about the bug are posted here: https://bitcointalk.org/index.php?topic=1065504.0 |
|
Also reported in #5712. FYI I don't think this is possible to hit on testnet even if it were to be reset, because the starting difficulty is high enough to prevent overflow. Would be nice to fix this for regtest though... |
|
Correct. It can only be hit on regtest. |
|
You're right, testnet3 shares the same pow limit as mainnet. I'll edit my commit message to match. |
fe3bb44 to
fc0dd75
Compare
|
Fixed the protected members by declaring all other |
|
@jrick: wouldn't it make sense to provide a RPC test (maybe |
|
@jonasschnelli agree that exercising this with a test would be good to have. I can try my hand at the RPC test at it if no one else picks it up, but I am not familiar with python. Don't want to sidetrack the discussion, but writing tests in a different language that contributors might not know seems like a strange decision. Testing everything over RPC instead of calling the functions directly also complicates the RPC API by requiring exposing many internals that otherwise an RPC client should not need. |
|
@jrick: no need to expose internals over RPC. If you PR solves a real world problems (which this PR does IMO) you should be able to automate the steps-to-produce-the-error-you-solve by creating a RPC test. You don't need to know python. Just copy'n'paste from other tests and adapt your scenario. :) |
This prevents an integer overflow during the difficulty retarget calculation, and fixes a consensus-changing bug introduced by df9eb5e. While it is not possible to hit this consensus bug on mainnet or testnet3 due to the higher proof-of-work limits, it is easily hit on regtest after generating 2016 blocks, forcing the retarget.
fc0dd75 to
8aced21
Compare
|
Added RPC tests. |
qa/pull-tester/rpc-tests.sh
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test should be disabled in rpc-tests.sh because it mines serval hundred blocks and it's therefore not ideal for travis/CI (timeouts,etc.).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the command to run all RPC tests, including those disabled for the pull tester?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can't.
But there is a PR in this direction #6097
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should retarget-overflow.py not appear in rpc-tests.sh at all, or be commented out like forknotify.py?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO best practice (for the current state) is to add your test commented out in rpc-tests.sh.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
Tested (regtest only!). ACK. |
I'm also wary of this, if this is a problem that affects only testing code (regtest), it's unnecessary risk to change mainnet consensus code for it. Remind me: Why does it retarget difficulty on regtest at all? From what I've always understood, the difficulty was supposed to be fixed at the bare minimum to allow instant block generation. |
|
I can't speak for regtest, but @davecgh and I hit this issue while I was patching in support for btcd's simnet so I could do some testing against one of our private test networks. The difficulty retarget is needed in this case, or block generation timings on our network would not be as realistic as we need. In the past, whenever we've talked about simnet in #bitcoin-dev, we've been told "that sounds just like regtest, why not use that instead?", so there are some people who do expect regtest to also work for simulation testing and long-lived private networks. A network that always has the lowest possible difficulty would indeed be useful for some situations, but useless for others. Assumming the regtest retarget is kept, how would you incorporate the logic to use the 512-bit math only on regtest? I'm all for avoiding touching working mainnet code, but tests become less and less useful the more special cases are made for the test environment. In this case, I would think that sharing the difficulty retarget code on all networks is safest. |
|
I would also suggest that having a test for the retarget code which does not rely on special casing or branches specific to the network makes the most sense and is the least risky approach. This code path is currently uncovered by the test code. The block tester tool does not generate enough blocks to hit the retarget interval, and I haven't seen any test cases anywhere which otherwise cover it. Empirically, it works properly on mainnet and testnet, and naturally mainnet can be externally tested via an ASIC by disabling checkpoints, which are all good things. However, I personally don't think it's a good idea to solely rely on human testing for consensus-related code. |
8aced21 to
bfa0f38
Compare
|
It's probably better for the rpc tests to calculate the exact expected retarget difficulty, instead of simply checking that the change was within the expected bounds. |
|
Regtest does retarget just like mainnet, the only difference is that it starts off at a much lower difficulty. Given that part of the purpose of that regtest is covering code to be used by mainnet, I think it's important that they do use the same code. I'm not very keen on changing the code for mainnet, though - even if it shouldn't make any difference, so I don't really know what the best solution is... |
|
NACK, I would prefer regtest not to ever retarget as @laanwj suggests. |
|
Leaning towards closing. Seems unlikely to be merged anytime soon given current comments. |
|
[Weak] NACK. If it isn't an issue, IMHO, don't bother adding the code to calculate it, however, it would be nice to document and assert that assumption. |
|
Well regtest currently cannot deal with retargets. I believe that's a
significant limitation and reduces the usefulness of regtest (but bringing
it back ideally means using the same code for both).
|
|
As previously mentioned, it is in fact an issue on regtest. Retargets are not possible on regtest currently (and they used to be before commit df9eb5e). Unfortunately, there is currently no test coverage which exercise the retarget code and is why this was able to go through. Repeating what I said above, I would also suggest that having a test for the retarget code which does not rely on special casing or branches specific to the network makes the most sense and is the least risky approach. That is the approach this pull request takes. It would appear @sipa agrees as he commented that it "ideally means using the same code for both." This isn't a theoretical issue. We hit it because we were doing some testing with btcd and Bitcoin Core on regtest which involved retargets and noticed that btcd handles it correctly while Bitcoin Core does not even though they used to both handle it correctly in the past. This creates a situation where 3rd-party software can't properly be tested across retarget intervals on the regression test network with Bitcoin Core. |
|
As retargetting never worked on regtest I'd prefer it to be disabled completely, as from what I've gathered, people don't really expect the difficulty on regtest to ramp up. |
|
In that case I think we should add a boolean to Consensus::Params called
fNoRetargetting, that disables the logic entirely. Currently we just can't
create regtest chains longer than 2016 blocks...
|
|
@CodeShark maybe you should just fix it in your PR, or should there be a separate PR? |
|
For the record, I was in favor of this pull, but not strongly enough to continue advocating for it. |
|
I also ACKed this PR. If only the mainnet effects would be reduced by moving/encapsulating the changes from the PR in |
Actually there's currently some unittest for CalculateNextWorkRequired(), see https://github.com/bitcoin/bitcoin/blob/master/src/test/pow_tests.cpp. |
This prevents an integer overflow during the difficulty retarget
calculation, and fixes a consensus-changing bug introduced by
df9eb5e. While it is not possible to
hit this consensus bug on mainnet or testnet3 due to the higher
current difficulties, it is easily hit on regtest after generating
2016 blocks, forcing the retarget.
Note: to convert between the arith_uint256 and arith_uint512 classes, I created a new static function in the base_uint base class that copies the data from one to the other. However, to do this, I had to make the protected membersWIDTHandpnpublic, so they could be accessed. Not too happy with this, and I think that I need to usefriendto allow access, but I'm not sure exactly how to do that. Suggestions welcome.