Skip to content

Commit

Permalink
Optimize -regtest setgenerate block generation
Browse files Browse the repository at this point in the history
Speed up generating blocks in regression test mode, by moving
block-creating and nonce-finding directly into the setgenerate
RPC call (instead of starting up a mining thread and waiting for
it to find a block).

This makes the forknotify RPC test three times quicker, for
example (10 seconds runtime instead of 30 seconds, assuming
the initial blockchain cache is already built).
  • Loading branch information
gavinandresen committed Nov 14, 2014
1 parent 3d3ce74 commit 1837987
Showing 1 changed file with 22 additions and 8 deletions.
30 changes: 22 additions & 8 deletions src/rpcmining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ Value setgenerate(const Array& params, bool fHelp)
"1. generate (boolean, required) Set to true to turn on generation, off to turn off.\n"
"2. genproclimit (numeric, optional) Set the processor limit for when generation is on. Can be -1 for unlimited.\n"
" Note: in -regtest mode, genproclimit controls how many blocks are generated immediately.\n"
"\nResult\n"
"[ blockhashes ] (array, -regtest only) hashes of blocks generated\n"
"\nExamples:\n"
"\nSet the generation on with a limit of one processor\n"
+ HelpExampleCli("setgenerate", "true 1") +
Expand Down Expand Up @@ -154,26 +156,38 @@ Value setgenerate(const Array& params, bool fHelp)
int nHeightEnd = 0;
int nHeight = 0;
int nGenerate = (nGenProcLimit > 0 ? nGenProcLimit : 1);
CReserveKey reservekey(pwalletMain);

{ // Don't keep cs_main locked
LOCK(cs_main);
nHeightStart = chainActive.Height();
nHeight = nHeightStart;
nHeightEnd = nHeightStart+nGenerate;
}
int nHeightLast = -1;
unsigned int nExtraNonce = 0;
Array blockHashes;
while (nHeight < nHeightEnd)
{
if (nHeightLast != nHeight)
auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlockWithKey(reservekey));
if (!pblocktemplate.get())
throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet keypool empty");
CBlock *pblock = &pblocktemplate->block;
{
nHeightLast = nHeight;
GenerateBitcoins(fGenerate, pwalletMain, 1);
}
MilliSleep(1);
{ // Don't keep cs_main locked
LOCK(cs_main);
nHeight = chainActive.Height();
IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce);
}
while (!CheckProofOfWork(pblock->GetHash(), pblock->nBits)) {
// Yes, there is a chance every nonce could fail to satisfy the -regtest
// target -- 1 in 2^(2^32). That ain't gonna happen.
++pblock->nNonce;
}
CValidationState state;
if (!ProcessNewBlock(state, NULL, pblock))
throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
++nHeight;
blockHashes.push_back(pblock->GetHash().GetHex());
}
return blockHashes;
}
else // Not -regtest: start generate thread, return immediately
{
Expand Down

1 comment on commit 1837987

@jtimon
Copy link
Contributor

@jtimon jtimon commented on 1837987 Nov 27, 2014

Choose a reason for hiding this comment

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

I missed this.
As I pointed out in #4423 removing the miner optimization could actually be an optimization for the regtest case. We concluded there or in #4793 that we only care about the miner for testing. I would still be happy to remove the mining optimization if people agree.
Let's recapitulate:

  1. The miner only makes sense for testing.
  2. The miner optimization doesn't make sense for regtest.
    The logical conclusion is that the miner optimization doesn't make sense. Let's remove it to simplify that part of the code. Less code to maintain and no drawbacks.

Please sign in to comment.