Skip to content

Conversation

@jrick
Copy link

@jrick jrick commented May 19, 2015

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 members WIDTH and pn public, so they could be accessed. Not too happy with this, and I think that I need to use friend to allow access, but I'm not sure exactly how to do that. Suggestions welcome.

@jrick
Copy link
Author

jrick commented May 19, 2015

More details about the bug are posted here: https://bitcointalk.org/index.php?topic=1065504.0

@sdaftuar
Copy link
Member

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...

@davecgh
Copy link
Contributor

davecgh commented May 19, 2015

Correct. It can only be hit on regtest.

@jrick
Copy link
Author

jrick commented May 19, 2015

You're right, testnet3 shares the same pow limit as mainnet. I'll edit my commit message to match.

@jrick jrick force-pushed the regtest_consensus_fix branch 2 times, most recently from fe3bb44 to fc0dd75 Compare May 19, 2015 17:05
@jrick
Copy link
Author

jrick commented May 19, 2015

Fixed the protected members by declaring all other base_uint classes to be friends of any base_uint<BITS>.

@jonasschnelli
Copy link
Contributor

@jrick: wouldn't it make sense to provide a RPC test (maybe qa/rpc-tests/reorg-overflow.py or so) where you could prove your implementation? The test should fail on current master and succeed with master+this PR on top.

@jrick
Copy link
Author

jrick commented May 20, 2015

@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.

@jonasschnelli
Copy link
Contributor

@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.
@jrick jrick force-pushed the regtest_consensus_fix branch from fc0dd75 to 8aced21 Compare May 20, 2015 20:51
@jrick
Copy link
Author

jrick commented May 20, 2015

Added RPC tests.

Copy link
Contributor

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.).

Copy link
Author

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?

Copy link
Contributor

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

Copy link
Author

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?

Copy link
Contributor

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.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Member

@sipa sipa May 21, 2015 via email

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

@sipa sipa May 21, 2015 via email

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jonasschnelli
Copy link
Contributor

Tested (regtest only!). ACK.
Changes look sane to me but i'm not sure if the changes in src/pow.cpp should go over chainparams (or something similar) so that this PR only affects regtest.

@laanwj
Copy link
Member

laanwj commented May 21, 2015

Changes look sane to me but i'm not sure if the changes in src/pow.cpp should go over chainparams (or something similar) so that this PR only affects regtest.

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.

@jrick
Copy link
Author

jrick commented May 21, 2015

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.

@davecgh
Copy link
Contributor

davecgh commented May 21, 2015

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.

@jrick jrick force-pushed the regtest_consensus_fix branch from 8aced21 to bfa0f38 Compare May 21, 2015 16:00
@jrick
Copy link
Author

jrick commented May 21, 2015

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.

@sipa
Copy link
Member

sipa commented Jun 14, 2015

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...

@jtimon
Copy link
Contributor

jtimon commented Aug 29, 2015

NACK, I would prefer regtest not to ever retarget as @laanwj suggests.

@jgarzik
Copy link
Contributor

jgarzik commented Sep 15, 2015

Leaning towards closing. Seems unlikely to be merged anytime soon given current comments.

@dcousens
Copy link
Contributor

[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.

@sipa
Copy link
Member

sipa commented Sep 16, 2015 via email

@davecgh
Copy link
Contributor

davecgh commented Sep 16, 2015

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.

@laanwj
Copy link
Member

laanwj commented Oct 19, 2015

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.

@laanwj laanwj closed this Oct 19, 2015
@sipa
Copy link
Member

sipa commented Oct 19, 2015 via email

@btcdrak
Copy link
Contributor

btcdrak commented Oct 19, 2015

@sipa I agree, that would be a much clearer solution. I know the versionbits integration tests are going to need the ability to generate more than 2016 blocks on regtestnet (afaik). refs #6816

@CodeShark
Copy link
Contributor

@sipa @btcdrak Regarding your fNoRetargetting, indeed! I had to force CheckProofOfWork to return true to actually run tests on #6816

@btcdrak
Copy link
Contributor

btcdrak commented Oct 19, 2015

@CodeShark maybe you should just fix it in your PR, or should there be a separate PR?

@davecgh
Copy link
Contributor

davecgh commented Oct 19, 2015

@laanwj: It is not true that retargetting never worked on regtest. It worked prior to commit df9eb5e.

@morcos
Copy link
Contributor

morcos commented Oct 19, 2015

For the record, I was in favor of this pull, but not strongly enough to continue advocating for it.

@jonasschnelli
Copy link
Contributor

I also ACKed this PR. If only the mainnet effects would be reduced by moving/encapsulating the changes from the PR in CalculateNextWorkRequired() somehow towards chainparams.cpp ...

@jtimon
Copy link
Contributor

jtimon commented Oct 19, 2015

This code path is currently uncovered by the test code.

Actually there's currently some unittest for CalculateNextWorkRequired(), see https://github.com/bitcoin/bitcoin/blob/master/src/test/pow_tests.cpp.
In fact, testing was the reason why CalculateNextWorkRequired() was separated from GetNextWorkRequired() in the first place (see 34e5015 ).

@bitcoin bitcoin locked as resolved and limited conversation to collaborators Sep 8, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.