From eed5784acbede60f8220b1978e191fc6c4880edf Mon Sep 17 00:00:00 2001 From: barrystyle Date: Wed, 29 May 2019 06:08:47 +0800 Subject: [PATCH] retrofit setgenerate function for solomining --- src/compat.h | 11 +++ src/miner.cpp | 170 ++++++++++++++++++++++++++++++++++++++++++++ src/miner.h | 4 ++ src/rpc/mining.cpp | 44 ++++++++++++ src/util/system.cpp | 13 ++++ src/util/system.h | 1 + 6 files changed, 243 insertions(+) diff --git a/src/compat.h b/src/compat.h index 68f6eb692..4d6ff8335 100644 --- a/src/compat.h +++ b/src/compat.h @@ -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 diff --git a/src/miner.cpp b/src/miner.cpp index 80a2f8f01..0b9c1dd20 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -24,11 +24,14 @@ #include #include #include +#include #include #include #include +#include + 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 &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> wallets = GetWallets(); + CWallet * const pwallet = (wallets.size() > 0) ? wallets[0].get() : nullptr; + + if (!pwallet) + return; + + unsigned int nExtraNonce = 0; + std::shared_ptr 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(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))); +} diff --git a/src/miner.h b/src/miner.h index 7c4c45507..8b072bfe7 100644 --- a/src/miner.h +++ b/src/miner.h @@ -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 diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 6625a03bb..3976a9586 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -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"} }, diff --git a/src/util/system.cpp b/src/util/system.cpp index 6e82de743..93c2e50a0 100644 --- a/src/util/system.cpp +++ b/src/util/system.cpp @@ -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); diff --git a/src/util/system.h b/src/util/system.h index 69ae11d1e..ec48932a0 100644 --- a/src/util/system.h +++ b/src/util/system.h @@ -55,6 +55,7 @@ inline std::string _(const char* psz) void SetupEnvironment(); bool SetupNetworking(); +void SetThreadPriority(int nPriority); template bool error(const char* fmt, const Args&... args)