retrofit setgenerate function for solomining

This commit is contained in:
barrystyle
2019-05-29 06:08:47 +08:00
parent a09a38567a
commit eed5784acb
6 changed files with 243 additions and 0 deletions
+11
View File
@@ -60,6 +60,17 @@ typedef unsigned int SOCKET;
#define SOCKET_ERROR -1
#endif
#ifndef WIN32
// PRIO_MAX is not defined on Solaris
#ifndef PRIO_MAX
#define PRIO_MAX 20
#endif
#define THREAD_PRIORITY_LOWEST PRIO_MAX
#define THREAD_PRIORITY_BELOW_NORMAL 2
#define THREAD_PRIORITY_NORMAL 0
#define THREAD_PRIORITY_ABOVE_NORMAL (-2)
#endif
#ifdef WIN32
#ifndef S_IRUSR
#define S_IRUSR 0400
+170
View File
@@ -24,11 +24,14 @@
#include <util/moneystr.h>
#include <util/system.h>
#include <validationinterface.h>
#include <wallet/wallet.h>
#include <algorithm>
#include <queue>
#include <utility>
#include <boost/thread.hpp>
int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
{
int64_t nOldTime = pblock->nTime;
@@ -445,3 +448,170 @@ void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned
pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase));
pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
}
static bool ProcessBlockFound(const std::shared_ptr<const CBlock> &pblock, const CChainParams& chainparams)
{
LogPrintf("%s\n", pblock->ToString());
LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0]->vout[0].nValue));
// Found a solution
{
LOCK(cs_main);
if (pblock->hashPrevBlock != chainActive.Tip()->GetBlockHash())
return error("ProcessBlockFound -- generated block is stale");
}
// Process this block the same as if we had received it from another node
if (!ProcessNewBlock(chainparams, pblock, true, nullptr))
return error("ProcessBlockFound -- ProcessNewBlock() failed, block not accepted");
return true;
}
void static NYC3Miner(const CChainParams& chainparams, CConnman& connman)
{
LogPrintf("NYC3miner -- started\n");
SetThreadPriority(THREAD_PRIORITY_LOWEST);
RenameThread("NYC3-miner");
std::vector<std::shared_ptr<CWallet>> wallets = GetWallets();
CWallet * const pwallet = (wallets.size() > 0) ? wallets[0].get() : nullptr;
if (!pwallet)
return;
unsigned int nExtraNonce = 0;
std::shared_ptr<CReserveScript> coinbaseScript;
pwallet->GetScriptForMining(coinbaseScript);
while (true)
{
try {
MilliSleep(1000);
// Throw an error if no script was provided. This can happen
// due to some internal error but also if the keypool is empty.
// In the latter case, already the pointer is NULL.
if (!coinbaseScript || coinbaseScript->reserveScript.empty())
throw std::runtime_error("No coinbase script available (mining requires a wallet)");
do {
bool fvNodesEmpty = connman.GetNodeCount(CConnman::CONNECTIONS_ALL) == 0;
if (!fvNodesEmpty && !IsInitialBlockDownload())
break;
MilliSleep(1000);
} while (true);
//
// Create new block
//
unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
CBlockIndex* pindexPrev = chainActive.Tip();
if(!pindexPrev) break;
BlockAssembler assembler(chainparams);
auto pblocktemplate = assembler.CreateNewBlock(coinbaseScript->reserveScript);
auto pblock = std::make_shared<CBlock>(pblocktemplate->block);
IncrementExtraNonce(pblock.get(), pindexPrev, nExtraNonce);
LogPrintf("NYC3Miner -- Running miner with %u transactions in block (%u bytes)\n", pblock->vtx.size(),
::GetSerializeSize(*pblock, PROTOCOL_VERSION));
// check if block is valid
CValidationState state;
if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) {
throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, FormatStateMessage(state)));
}
//
// Search
//
int64_t nStart = GetTime();
arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits);
while (true)
{
unsigned int nHashesDone = 0;
uint256 hash;
while (true)
{
hash = pblock->GetPoWHash();
if (UintToArith256(hash) <= hashTarget)
{
// Found a solution
SetThreadPriority(THREAD_PRIORITY_NORMAL);
LogPrintf("NYC3miner:\n proof-of-work found\n hash: %s\n target: %s\n", hash.GetHex(), hashTarget.GetHex());
ProcessBlockFound(pblock, chainparams);
SetThreadPriority(THREAD_PRIORITY_LOWEST);
coinbaseScript->KeepScript();
// In regression test mode, stop mining after a block is found. This
// allows developers to controllably generate a block on demand.
if (chainparams.MineBlocksOnDemand())
throw boost::thread_interrupted();
break;
}
pblock->nNonce += 1;
nHashesDone += 1;
if ((pblock->nNonce & 0xFF) == 0)
break;
}
// Check for stop or if block needs to be rebuilt
boost::this_thread::interruption_point();
// Regtest mode doesn't require peers
if (connman.GetNodeCount(CConnman::CONNECTIONS_ALL) == 0)
break;
if (pblock->nNonce >= 0xffff0000)
break;
if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60)
break;
if (pindexPrev != chainActive.Tip())
break;
// Update nTime every few seconds
if (UpdateTime(pblock.get(), chainparams.GetConsensus(), pindexPrev) < 0)
break; // Recreate the block if the clock has run backwards,
// so that we can use the correct time.
if (chainparams.GetConsensus().fPowAllowMinDifficultyBlocks)
{
// Changing pblock->nTime can change work required on testnet:
hashTarget.SetCompact(pblock->nBits);
}
}
}
catch (const boost::thread_interrupted&)
{
LogPrintf("NYC3Miner -- terminated\n");
throw;
}
catch (const std::runtime_error &e)
{
LogPrintf("NYC3miner -- runtime error: %s\n", e.what());
}
}
}
void GenerateNYC3s(bool fGenerate, int nThreads, const CChainParams& chainparams, CConnman &connman)
{
static boost::thread_group* minerThreads = NULL;
if (nThreads < 0)
nThreads = GetNumCores();
if (minerThreads != NULL)
{
minerThreads->interrupt_all();
delete minerThreads;
minerThreads = NULL;
}
if (nThreads == 0 || !fGenerate)
return;
minerThreads = new boost::thread_group();
for (int i = 0; i < nThreads; i++)
minerThreads->create_thread(boost::bind(&NYC3Miner, boost::cref(chainparams), boost::ref(connman)));
}
+4
View File
@@ -20,6 +20,7 @@
class CBlockIndex;
class CChainParams;
class CScript;
class CWallet;
namespace Consensus { struct Params; };
@@ -202,4 +203,7 @@ private:
void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev);
/** Run the miner threads */
void GenerateNYC3s(bool fGenerate, int nThreads, const CChainParams& chainparams, CConnman &connman);
#endif // BITCOIN_MINER_H
+44
View File
@@ -972,6 +972,49 @@ static UniValue estimaterawfee(const JSONRPCRequest& request)
return result;
}
static UniValue setgenerate(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
throw std::runtime_error(
"setgenerate generate ( genproclimit )\n"
"\nSet 'generate' true or false to turn generation on or off.\n"
"Generation is limited to 'genproclimit' processors, -1 is unlimited.\n"
"See the getgenerate call for the current setting.\n"
"\nArguments:\n"
"1. generate (boolean, required) Set to true to turn on generation, false to turn off.\n"
"2. genproclimit (numeric, optional) Set the processor limit for when generation is on. Can be -1 for unlimited.\n"
"\nExamples:\n"
"\nSet the generation on with a limit of one processor\n"
+ HelpExampleCli("setgenerate", "true 1") +
"\nCheck the setting\n"
+ HelpExampleCli("getgenerate", "") +
"\nTurn off generation\n"
+ HelpExampleCli("setgenerate", "false") +
"\nUsing json rpc\n"
+ HelpExampleRpc("setgenerate", "true, 1")
);
if (Params().MineBlocksOnDemand())
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Use the generate method instead of setgenerate on this network");
const auto& params = request.params;
bool fGenerate = true;
if (params.size() > 0)
fGenerate = params[0].get_bool();
int nGenProcLimit = 1;
if (params.size() > 1)
{
nGenProcLimit = params[1].get_int();
if (nGenProcLimit == 0)
fGenerate = false;
}
GenerateNYC3s(fGenerate, nGenProcLimit, Params(), *g_connman);
return fGenerate ? std::string("Mining started") : std::string("Mining stopped");
}
// clang-format off
static const CRPCCommand commands[] =
{ // category name actor (function) argNames
@@ -982,6 +1025,7 @@ static const CRPCCommand commands[] =
{ "mining", "getblocktemplate", &getblocktemplate, {"template_request"} },
{ "mining", "submitblock", &submitblock, {"hexdata","dummy"} },
{ "mining", "submitheader", &submitheader, {"hexdata"} },
{ "mining", "setgenerate", &setgenerate, {"generate", "genproclimit"} },
{ "generating", "generatetoaddress", &generatetoaddress, {"nblocks","address","maxtries"} },
+13
View File
@@ -783,6 +783,19 @@ fs::path GetConfigFile(const std::string& confPath)
return AbsPathForConfigVal(fs::path(confPath), false);
}
void SetThreadPriority(int nPriority)
{
#ifdef WIN32
SetThreadPriority(GetCurrentThread(), nPriority);
#else // WIN32
#ifdef PRIO_THREAD
setpriority(PRIO_THREAD, 0, nPriority);
#else // PRIO_THREAD
setpriority(PRIO_PROCESS, 0, nPriority);
#endif // PRIO_THREAD
#endif // WIN32
}
static std::string TrimString(const std::string& str, const std::string& pattern)
{
std::string::size_type front = str.find_first_not_of(pattern);
+1
View File
@@ -55,6 +55,7 @@ inline std::string _(const char* psz)
void SetupEnvironment();
bool SetupNetworking();
void SetThreadPriority(int nPriority);
template<typename... Args>
bool error(const char* fmt, const Args&... args)