diff --git a/src/bitcoinminer.cpp b/src/bitcoinminer.cpp new file mode 100644 index 00000000..23aaea97 --- /dev/null +++ b/src/bitcoinminer.cpp @@ -0,0 +1,327 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Copyright (c) 2011-2013 PPCoin developers +// Copyright (c) 2013 Primecoin developers +// Distributed under conditional MIT/X11 software license, +// see the accompanying file COPYING + +#include "prime.h" +#include "json/json_spirit_value.h" +//#include +//#include +//#include + +using namespace std; +using namespace boost; + +CBlockIndex* pindexBest = NULL; +int64 nHPSTimerStart = 0; + +void BitcoinMiner(CBlockProvider *block_provider, unsigned int thread_id) +{ + printf("PrimecoinMiner started\n"); + SetThreadPriority(THREAD_PRIORITY_LOWEST); + RenameThread("primecoin-miner"); + + // Each thread has its own kcd ey and counter + unsigned int nExtraNonce = 0; //^ + + unsigned int nPrimorialMultiplier = nPrimorialHashFactor; + double dTimeExpected = 0; // time expected to prime chain (micro-second) + int64 nSieveGenTime = 0; // how many milliseconds sieve generation took + bool fIncrementPrimorial = true; // increase or decrease primorial factor + + CBlock *pblock = NULL; + uint256 old_hash; + unsigned int old_nonce = 0; + + try { loop { + // + // Create new block + // + CBlockIndex* pindexPrev = pindexBest; + + auto_ptr pblocktemplate; + if ((pblock = block_provider->getBlock(thread_id, pblock == NULL ? 0 : pblock->nTime)) == NULL) { //server not reachable? + MilliSleep(20000); + continue; + } else if (old_hash == pblock->GetHeaderHash()) { + if (old_nonce >= 0xffff0000) { + MilliSleep(100); + //TODO: FORCE a new getblock! + if (fDebug && GetBoolArg("-printmining")) + printf("Nothing to do --- uh ih uh ah ah bing bang!!\n"); + continue; + } else + pblock->nNonce = old_nonce; + } else { + old_hash = pblock->GetHeaderHash(); + old_nonce = 0; + } + + if (fDebug && GetBoolArg("-printmining")) + printf("Running PrimecoinMiner with %"PRIszu" transactions in block (%u bytes)\n", pblock->vtx.size(), + ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION)); + + // + // Search + // + int64 nStart = GetTime(); + bool fNewBlock = true; + unsigned int nTriedMultiplier = 0; + + // Primecoin: try to find hash divisible by primorial + unsigned int nHashFactor = PrimorialFast(nPrimorialHashFactor); + + // Based on mustyoshi's patch from https://bitcointalk.org/index.php?topic=251850.msg2689981#msg2689981 + uint256 phash; + mpz_class mpzHash; + loop { + // Fast loop + if (pblock->nNonce >= 0xffff0000) + break; + + // Check that the hash meets the minimum + phash = pblock->GetHeaderHash(); + if (phash < hashBlockHeaderLimit) { + pblock->nNonce++; + continue; + } + + // Check that the hash is divisible by the fixed primorial + mpz_set_uint256(mpzHash.get_mpz_t(), phash); + if (!mpz_divisible_ui_p(mpzHash.get_mpz_t(), nHashFactor)) { + pblock->nNonce++; + continue; + } + + // Use the hash that passed the tests + break; + } + if (pblock->nNonce >= 0xffff0000) { + old_nonce = 0xffff0000; + continue; + } + // Primecoin: primorial fixed multiplier + mpz_class mpzPrimorial; + unsigned int nRoundTests = 0; + unsigned int nRoundPrimesHit = 0; + int64 nPrimeTimerStart = GetTimeMicros(); + Primorial(nPrimorialMultiplier, mpzPrimorial); + + loop + { + unsigned int nTests = 0; + unsigned int nPrimesHit = 0; + unsigned int nChainsHit = 0; + + // Primecoin: adjust round primorial so that the generated prime candidates meet the minimum + mpz_class mpzMultiplierMin = mpzPrimeMin * nHashFactor / mpzHash + 1; + while (mpzPrimorial < mpzMultiplierMin) + { + if (!PrimeTableGetNextPrime(nPrimorialMultiplier)) + error("PrimecoinMiner() : primorial minimum overflow"); + Primorial(nPrimorialMultiplier, mpzPrimorial); + } + mpz_class mpzFixedMultiplier; + if (mpzPrimorial > nHashFactor) { + mpzFixedMultiplier = mpzPrimorial / nHashFactor; + } else { + mpzFixedMultiplier = 1; + } + + // Primecoin: mine for prime chain + unsigned int nProbableChainLength; + if (MineProbablePrimeChain(*pblock, mpzFixedMultiplier, fNewBlock, nTriedMultiplier, nProbableChainLength, nTests, nPrimesHit, nChainsHit, mpzHash, nPrimorialMultiplier, nSieveGenTime, pindexPrev, block_provider != NULL)) + { + SetThreadPriority(THREAD_PRIORITY_NORMAL); + block_provider->submitBlock(pblock); + SetThreadPriority(THREAD_PRIORITY_LOWEST); + old_nonce = pblock->nNonce + 1; + break; + } + + /// + /// ENABLE the following code, if you need data for the perftool + /// + /*if (nProbableChainLength > 0 && nTests > 10) + { + static CCriticalSection cs; + { + LOCK(cs); + + std::ofstream output_file("miner_data"); + std::ofstream output_file_block("miner_data.blk", std::ofstream::out | std::ofstream::binary); + + ::Serialize(output_file_block, *pblock, 0, 0); //writeblock + + output_file << mpzFixedMultiplier.get_str(10) << std::endl; + output_file << fNewBlock << std::endl; + output_file << nTriedMultiplier << std::endl; + output_file << nPrimorialMultiplier << std::endl; + output_file << mpzHash.get_str(10) << std::endl; + + output_file.close(); + output_file_block.close(); + } + }*/ + + nRoundTests += nTests; + nRoundPrimesHit += nPrimesHit; + + // Meter primes/sec + static volatile int64 nPrimeCounter; + static volatile int64 nTestCounter; + static volatile int64 nChainCounter; + static double dChainExpected; + int64 nMillisNow = GetTimeMillis(); + if (nHPSTimerStart == 0) + { + nHPSTimerStart = nMillisNow; + nPrimeCounter = 0; + nTestCounter = 0; + nChainCounter = 0; + dChainExpected = 0; + } + else + { +#ifdef __GNUC__ + // Use atomic increment + __sync_add_and_fetch(&nPrimeCounter, nPrimesHit); + __sync_add_and_fetch(&nTestCounter, nTests); + __sync_add_and_fetch(&nChainCounter, nChainsHit); +#else + nPrimeCounter += nPrimesHit; + nTestCounter += nTests; + nChainCounter += nChainsHit; +#endif + } + if (nMillisNow - nHPSTimerStart > 60000) + { + static CCriticalSection cs; + { + LOCK(cs); + if (nMillisNow - nHPSTimerStart > 60000) + { + double dPrimesPerMinute = 60000.0 * nPrimeCounter / (nMillisNow - nHPSTimerStart); + double dPrimesPerSec = dPrimesPerMinute / 60.0; + double dTestsPerSec = 1000.0 * nTestCounter / (nMillisNow - nHPSTimerStart); + double dChainsPerMinute = 60000.0 * nChainCounter / (nMillisNow - nHPSTimerStart); + double dChainsPerDay = 86400000.0 * dChainExpected / (GetTimeMillis() - nHPSTimerStart); + nHPSTimerStart = nMillisNow; + nPrimeCounter = 0; + nTestCounter = 0; + nChainCounter = 0; + dChainExpected = 0; + static int64 nLogTime = 0; + if (nMillisNow - nLogTime > 59000) + { + nLogTime = nMillisNow; + printf("[STATS] %s | %4.0f primes/s, %4.0f tests/s, %4.0f %d-chains/h, %3.3f chains/d\n", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", nLogTime / 1000).c_str(), dPrimesPerSec, dTestsPerSec, dChainsPerMinute * 60.0, nStatsChainLength, dChainsPerDay); + } + } + } + } + + old_nonce = pblock->nNonce; + + // Check for stop or if block needs to be rebuilt + boost::this_thread::interruption_point(); + if (pblock->nNonce >= 0xffff0000) + break; + if (pindexPrev != pindexBest/* || (block_provider != NULL && GetTime() - nStart > 200)*/) + break; + if (thread_id == 0 && block_provider != NULL && (GetTime() - nStart) > 300) { //5 minutes no update? something's wrong -> reconnect! + block_provider->forceReconnect(); + nStart = GetTime(); + } + if (fNewBlock) //aka: sieve's done, we need a updated nonce + { + // Primecoin: a sieve+primality round completes + // Primecoin: estimate time to block + const double dTimeExpectedPrev = dTimeExpected; + unsigned int nCalcRoundTests = max(1u, nRoundTests); + // Make sure the estimated time is very high if only 0 primes were found + if (nRoundPrimesHit == 0) + nCalcRoundTests *= 1000; + int64 nRoundTime = (GetTimeMicros() - nPrimeTimerStart); + dTimeExpected = (double) nRoundTime / nCalcRoundTests; + double dRoundChainExpected = (double) nRoundTests; + for (unsigned int n = 0, nTargetLength = TargetGetLength(pblock->nBits); n < nTargetLength; n++) + { + double dPrimeProbability = EstimateCandidatePrimeProbability(nPrimorialMultiplier, n); + dTimeExpected = dTimeExpected / max(0.01, dPrimeProbability); + dRoundChainExpected *= dPrimeProbability; + } + dChainExpected += dRoundChainExpected; + if (fDebug && GetBoolArg("-printmining")) + { + double dPrimeProbabilityBegin = EstimateCandidatePrimeProbability(nPrimorialMultiplier, 0); + unsigned int nTargetLength = TargetGetLength(pblock->nBits); + double dPrimeProbabilityEnd = EstimateCandidatePrimeProbability(nPrimorialMultiplier, nTargetLength - 1); + printf("PrimecoinMiner() : Round primorial=%u tests=%u primes=%u time=%uus pprob=%1.6f pprob2=%1.6f tochain=%6.3fd expect=%3.9f\n", nPrimorialMultiplier, nRoundTests, nRoundPrimesHit, (unsigned int) nRoundTime, dPrimeProbabilityBegin, dPrimeProbabilityEnd, ((dTimeExpected/1000000.0))/86400.0, dRoundChainExpected); + } + + // Primecoin: update time and nonce + //pblock->nTime = max(pblock->nTime, (unsigned int) GetAdjustedTime()); + pblock->nTime = max(pblock->nTime, block_provider->GetAdjustedTimeWithOffset(thread_id)); + pblock->nNonce++; + loop { + // Fast loop + if (pblock->nNonce >= 0xffff0000) + break; + + // Check that the hash meets the minimum + phash = pblock->GetHeaderHash(); + if (phash < hashBlockHeaderLimit) { + pblock->nNonce++; + continue; + } + + // Check that the hash is divisible by the fixed primorial + mpz_set_uint256(mpzHash.get_mpz_t(), phash); + if (!mpz_divisible_ui_p(mpzHash.get_mpz_t(), nHashFactor)) { + pblock->nNonce++; + continue; + } + + // Use the hash that passed the tests + break; + } + if (pblock->nNonce >= 0xffff0000) + break; + + // Primecoin: reset sieve+primality round timer + nPrimeTimerStart = GetTimeMicros(); + if (dTimeExpected > dTimeExpectedPrev) + fIncrementPrimorial = !fIncrementPrimorial; + + // Primecoin: primorial always needs to be incremented if only 0 primes were found + if (nRoundPrimesHit == 0) + fIncrementPrimorial = true; + + nRoundTests = 0; + nRoundPrimesHit = 0; + + // Primecoin: dynamic adjustment of primorial multiplier + if (fIncrementPrimorial) + { + if (!PrimeTableGetNextPrime(nPrimorialMultiplier)) + error("PrimecoinMiner() : primorial increment overflow"); + } + else if (nPrimorialMultiplier > nPrimorialHashFactor) + { + if (!PrimeTableGetPreviousPrime(nPrimorialMultiplier)) + error("PrimecoinMiner() : primorial decrement overflow"); + } + Primorial(nPrimorialMultiplier, mpzPrimorial); + } + } + } } + catch (boost::thread_interrupted) + { + printf("PrimecoinMiner terminated\n"); + throw; + } +} + diff --git a/src/main_poolminer.cpp b/src/main_poolminer.cpp index c363fa85..17c33774 100644 --- a/src/main_poolminer.cpp +++ b/src/main_poolminer.cpp @@ -26,10 +26,7 @@ // be compatible to original code (not actually used!) #include "txdb.h" -#include "walletdb.h" -#include "wallet.h" #include "ui_interface.h" -CWallet *pwalletMain; CClientUIInterface uiInterface; void StartShutdown() { exit(0); @@ -41,8 +38,7 @@ void StartShutdown() { *********************************/ extern CBlockIndex *pindexBest; -extern void BitcoinMiner(CWallet *pwallet, - CBlockProvider *CBlockProvider, +extern void BitcoinMiner(CBlockProvider *CBlockProvider, unsigned int thread_id); extern bool fPrintToConsole; extern bool fDebug; @@ -216,7 +212,7 @@ public: _master->wait_for_master(); std::cout << "[WORKER" << _id << "] GoGoGo!" << std::endl; boost::this_thread::sleep(boost::posix_time::seconds(2)); - BitcoinMiner(NULL, _bprovider, _id); + BitcoinMiner(_bprovider, _id); std::cout << "[WORKER" << _id << "] Bye Bye!" << std::endl; } diff --git a/src/makefile.unix b/src/makefile.unix index 0a45c819..92b3c058 100644 --- a/src/makefile.unix +++ b/src/makefile.unix @@ -121,45 +121,18 @@ DEBUGFLAGS= # CXXFLAGS can be specified on the make command line, so we use xCXXFLAGS that only # adds some defaults in front. Unfortunately, CXXFLAGS=... $(CXXFLAGS) does not work. xCXXFLAGS=-O2 -pthread -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter \ - $(DEBUGFLAGS) $(DEFS) $(HARDENING) $(CXXFLAGS) + $(DEBUGFLAGS) $(DEFS) $(HARDENING) $(CXXFLAGS) -march=native # LDFLAGS can be specified on the make command line, so we use xLDFLAGS that only # adds some defaults in front. Unfortunately, LDFLAGS=... $(LDFLAGS) does not work. xLDFLAGS=$(LDHARDENING) $(LDFLAGS) OBJS= \ - leveldb/libleveldb.a \ - obj/alert.o \ obj/version.o \ - obj/checkpoints.o \ obj/netbase.o \ - obj/addrman.o \ - obj/crypter.o \ - obj/key.o \ - obj/db.o \ - obj/keystore.o \ - obj/main.o \ - obj/net.o \ - obj/protocol.o \ - obj/bitcoinrpc.o \ - obj/rpcdump.o \ - obj/rpcnet.o \ - obj/rpcmining.o \ - obj/rpcwallet.o \ - obj/rpcblockchain.o \ - obj/rpcrawtransaction.o \ - obj/script.o \ - obj/sync.o \ obj/util.o \ - obj/wallet.o \ - obj/walletdb.o \ - obj/hash.o \ - obj/bloom.o \ - obj/noui.o \ - obj/leveldb.o \ - obj/txdb.o \ obj/prime.o \ - obj/checkpointsync.o + obj/bitcoinminer.o all: primeminer @@ -170,11 +143,11 @@ test check: test_primecoin FORCE # LevelDB support # MAKEOVERRIDES = -LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a -DEFS += $(addprefix -I,$(CURDIR)/leveldb/include) -DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers) -leveldb/libleveldb.a: - @echo "Building LevelDB ..." && cd leveldb && $(MAKE) CC=$(CC) CXX=$(CXX) OPT="$(xCXXFLAGS)" libleveldb.a libmemenv.a && cd .. +#LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a +#DEFS += $(addprefix -I,$(CURDIR)/leveldb/include) +#DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers) +#leveldb/libleveldb.a: +# @echo "Building LevelDB ..." && cd leveldb && $(MAKE) CC=$(CC) CXX=$(CXX) OPT="$(xCXXFLAGS)" libleveldb.a libmemenv.a && cd .. # auto-generated dependencies: -include obj/*.P