diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 54d0ae8ba6..93b4d035d6 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -208,6 +208,9 @@ static const CRPCCommand vRPCCommands[] = { "getaddednodeinfo", &getaddednodeinfo, true, true }, { "getdifficulty", &getdifficulty, true, false }, { "getnetworkhashps", &getnetworkhashps, true, false }, + { "getgenerate", &getgenerate, true, false }, + { "setgenerate", &setgenerate, true, false }, + { "gethashespersec", &gethashespersec, true, false }, { "getinfo", &getinfo, true, false }, { "getmininginfo", &getmininginfo, true, false }, { "getnewaddress", &getnewaddress, true, false }, @@ -1143,6 +1146,8 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector 0) ConvertTo(params[0]); if (strMethod == "getaddednodeinfo" && n > 0) ConvertTo(params[0]); + if (strMethod == "setgenerate" && n > 0) ConvertTo(params[0]); + if (strMethod == "setgenerate" && n > 1) ConvertTo(params[1]); if (strMethod == "getnetworkhashps" && n > 0) ConvertTo(params[0]); if (strMethod == "getnetworkhashps" && n > 1) ConvertTo(params[1]); if (strMethod == "sendtoaddress" && n > 1) ConvertTo(params[1]); diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h index 7614cdfff6..f7f06c671b 100644 --- a/src/bitcoinrpc.h +++ b/src/bitcoinrpc.h @@ -140,7 +140,10 @@ extern json_spirit::Value getaddednodeinfo(const json_spirit::Array& params, boo extern json_spirit::Value dumpprivkey(const json_spirit::Array& params, bool fHelp); // in rpcdump.cpp extern json_spirit::Value importprivkey(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value getgenerate(const json_spirit::Array& params, bool fHelp); // in rpcmining.cpp +extern json_spirit::Value setgenerate(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getnetworkhashps(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value gethashespersec(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getmininginfo(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getworkex(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getwork(const json_spirit::Array& params, bool fHelp); diff --git a/src/init.cpp b/src/init.cpp index d0bdd23e05..38034241f3 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -306,6 +306,7 @@ std::string HelpMessage() " -? " + _("This help message") + "\n" + " -conf= " + _("Specify configuration file (default: litecoin.conf)") + "\n" + " -pid= " + _("Specify pid file (default: litecoind.pid)") + "\n" + + " -gen " + _("Generate coins (default: 0)") + "\n" + " -datadir= " + _("Specify data directory") + "\n" + " -dbcache= " + _("Set database cache size in megabytes (default: 25)") + "\n" + " -timeout= " + _("Specify connection timeout in milliseconds (default: 5000)") + "\n" + @@ -1137,6 +1138,9 @@ bool AppInit2(boost::thread_group& threadGroup) if (fServer) StartRPCThreads(); + // Generate coins in the background + GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain); + // ********************************************************* Step 12: finished uiInterface.InitMessage(_("Done loading")); diff --git a/src/main.cpp b/src/main.cpp index c6f01357f8..9a2aad3c66 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4081,9 +4081,22 @@ bool SendMessages(CNode* pto, bool fSendTrickle) return true; } + + + + + + + + + + + + + ////////////////////////////////////////////////////////////////////////////// // -// LitecoinMiner +// BitcoinMiner // int static FormatHashBlocks(void* pbuffer, unsigned int len) @@ -4490,7 +4503,7 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) return false; //// debug print - printf("Litecoin RPCMiner:\n"); + printf("BitcoinMiner:\n"); printf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str()); pblock->print(); printf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue).c_str()); @@ -4499,7 +4512,7 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) { LOCK(cs_main); if (pblock->hashPrevBlock != hashBestChain) - return error("LitecoinMiner : generated block is stale"); + return error("BitcoinMiner : generated block is stale"); // Remove key from key pool reservekey.KeepKey(); @@ -4513,12 +4526,165 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) // Process this block the same as if we had received it from another node CValidationState state; if (!ProcessBlock(state, NULL, pblock)) - return error("LitecoinMiner : ProcessBlock, block not accepted"); + return error("BitcoinMiner : ProcessBlock, block not accepted"); } return true; } +void static BitcoinMiner(CWallet *pwallet) +{ + printf("BitcoinMiner started\n"); + SetThreadPriority(THREAD_PRIORITY_LOWEST); + RenameThread("bitcoin-miner"); + + // Each thread has its own key and counter + CReserveKey reservekey(pwallet); + unsigned int nExtraNonce = 0; + + try { loop { + while (vNodes.empty()) + MilliSleep(1000); + + // + // Create new block + // + unsigned int nTransactionsUpdatedLast = nTransactionsUpdated; + CBlockIndex* pindexPrev = pindexBest; + + auto_ptr pblocktemplate(CreateNewBlock(reservekey)); + if (!pblocktemplate.get()) + return; + CBlock *pblock = &pblocktemplate->block; + IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); + + printf("Running BitcoinMiner with %"PRIszu" transactions in block (%u bytes)\n", pblock->vtx.size(), + ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION)); + + // + // Pre-build hash buffers + // + char pmidstatebuf[32+16]; char* pmidstate = alignup<16>(pmidstatebuf); + char pdatabuf[128+16]; char* pdata = alignup<16>(pdatabuf); + char phash1buf[64+16]; char* phash1 = alignup<16>(phash1buf); + + FormatHashBuffers(pblock, pmidstate, pdata, phash1); + + unsigned int& nBlockTime = *(unsigned int*)(pdata + 64 + 4); + unsigned int& nBlockBits = *(unsigned int*)(pdata + 64 + 8); + unsigned int& nBlockNonce = *(unsigned int*)(pdata + 64 + 12); + + + // + // Search + // + int64 nStart = GetTime(); + uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); + loop + { + unsigned int nHashesDone = 0; + + uint256 thash; + char scratchpad[SCRYPT_SCRATCHPAD_SIZE]; + loop + { + scrypt_1024_1_1_256_sp(BEGIN(pblock->nVersion), BEGIN(thash), scratchpad); + + if (thash <= hashTarget) + { + // Found a solution + SetThreadPriority(THREAD_PRIORITY_NORMAL); + CheckWork(pblock, *pwalletMain, reservekey); + SetThreadPriority(THREAD_PRIORITY_LOWEST); + break; + } + pblock->nNonce += 1; + nHashesDone += 1; + if ((pblock->nNonce & 0xFF) == 0) + break; + } + + // Meter hashes/sec + static int64 nHashCounter; + if (nHPSTimerStart == 0) + { + nHPSTimerStart = GetTimeMillis(); + nHashCounter = 0; + } + else + nHashCounter += nHashesDone; + if (GetTimeMillis() - nHPSTimerStart > 4000) + { + static CCriticalSection cs; + { + LOCK(cs); + if (GetTimeMillis() - nHPSTimerStart > 4000) + { + dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart); + nHPSTimerStart = GetTimeMillis(); + nHashCounter = 0; + static int64 nLogTime; + if (GetTime() - nLogTime > 30 * 60) + { + nLogTime = GetTime(); + printf("hashmeter %6.0f khash/s\n", dHashesPerSec/1000.0); + } + } + } + } + + // Check for stop or if block needs to be rebuilt + boost::this_thread::interruption_point(); + if (vNodes.empty()) + break; + if (pblock->nNonce >= 0xffff0000) + break; + if (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60) + break; + if (pindexPrev != pindexBest) + break; + + // Update nTime every few seconds + pblock->UpdateTime(pindexPrev); + nBlockTime = ByteReverse(pblock->nTime); + if (fTestNet) + { + // Changing pblock->nTime can change work required on testnet: + nBlockBits = ByteReverse(pblock->nBits); + hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); + } + } + } } + catch (boost::thread_interrupted) + { + printf("BitcoinMiner terminated\n"); + throw; + } +} + +void GenerateBitcoins(bool fGenerate, CWallet* pwallet) +{ + static boost::thread_group* minerThreads = NULL; + + int nThreads = GetArg("-genproclimit", -1); + if (nThreads < 0) + nThreads = boost::thread::hardware_concurrency(); + + 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(&BitcoinMiner, pwallet)); +} + // Amount compression: // * If the amount is 0, output 0 // * first, divide the amount (in base units) by the largest power of 10 possible; call the exponent e (e is max 9) diff --git a/src/main.h b/src/main.h index 417343a826..3c69cc2e3c 100644 --- a/src/main.h +++ b/src/main.h @@ -154,6 +154,8 @@ bool ProcessMessages(CNode* pfrom); bool SendMessages(CNode* pto, bool fSendTrickle); /** Run an instance of the script checking thread */ void ThreadScriptCheck(); +/** Run the miner threads */ +void GenerateBitcoins(bool fGenerate, CWallet* pwallet); /** Generate a new block, without valid proof-of-work */ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey); /** Modify the extranonce in a block */ diff --git a/src/net.cpp b/src/net.cpp index 6239c9ac01..f6c5548a4d 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1873,6 +1873,7 @@ void StartNode(boost::thread_group& threadGroup) bool StopNode() { printf("StopNode()\n"); + GenerateBitcoins(false, NULL); MapPort(false); nTransactionsUpdated++; if (semOutbound) diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 4a1a2b3320..9b62e84dcc 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -63,6 +63,57 @@ Value getnetworkhashps(const Array& params, bool fHelp) return GetNetworkHashPS(params.size() > 0 ? params[0].get_int() : 120, params.size() > 1 ? params[1].get_int() : -1); } + +Value getgenerate(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "getgenerate\n" + "Returns true or false."); + + return GetBoolArg("-gen"); +} + + +Value setgenerate(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "setgenerate [genproclimit]\n" + " is true or false to turn generation on or off.\n" + "Generation is limited to [genproclimit] processors, -1 is unlimited."); + + bool fGenerate = true; + if (params.size() > 0) + fGenerate = params[0].get_bool(); + + if (params.size() > 1) + { + int nGenProcLimit = params[1].get_int(); + mapArgs["-genproclimit"] = itostr(nGenProcLimit); + if (nGenProcLimit == 0) + fGenerate = false; + } + mapArgs["-gen"] = (fGenerate ? "1" : "0"); + + GenerateBitcoins(fGenerate, pwalletMain); + return Value::null; +} + + +Value gethashespersec(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "gethashespersec\n" + "Returns a recent hashes per second performance measurement while generating."); + + if (GetTimeMillis() - nHPSTimerStart > 8000) + return (boost::int64_t)0; + return (boost::int64_t)dHashesPerSec; +} + + Value getmininginfo(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) @@ -76,6 +127,9 @@ Value getmininginfo(const Array& params, bool fHelp) obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx)); obj.push_back(Pair("difficulty", (double)GetDifficulty())); obj.push_back(Pair("errors", GetWarnings("statusbar"))); + obj.push_back(Pair("generate", GetBoolArg("-gen"))); + obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1))); + obj.push_back(Pair("hashespersec", gethashespersec(params, false))); obj.push_back(Pair("networkhashps", getnetworkhashps(params, false))); obj.push_back(Pair("pooledtx", (uint64_t)mempool.size())); obj.push_back(Pair("testnet", fTestNet));