예제 #1
0
void BitcoinMiner(primecoinBlock_t* primecoinBlock, sint32 threadIndex)
{
	//printf("PrimecoinMiner started\n");
	//SetThreadPriority(THREAD_PRIORITY_LOWEST);
	//RenameThread("primecoin-miner");
	if( pctx == NULL )
		pctx = BN_CTX_new();
	// Each thread has its own key and counter
	//CReserveKey reservekey(pwallet);
	unsigned int nExtraNonce = 0;

	static const unsigned int nPrimorialHashFactor = 7;
	unsigned int nPrimorialMultiplierStart = 7;

	static int startFactorList[4] =
	{
		107,107,107,107
		//131,131,131,131
	};
	// there is a much better way to do all the primorial and fixedMutliplier calculation, but this has to suffice for now...
	nPrimorialMultiplierStart = startFactorList[(threadIndex&3)];

	unsigned int nPrimorialMultiplier = nPrimorialMultiplierStart;
	int64 nTimeExpected = 0;   // time expected to prime chain (micro-second)
	int64 nTimeExpectedPrev = 0; // time expected to prime chain last time
	bool fIncrementPrimorial = true; // increase or decrease primorial factor

	CSieveOfEratosthenes* psieve = NULL;

	primecoinBlock->nonce = 0;

	//uint32 nTime = GetTickCount() + 1000*60;
	
	// note: originally a wanted to loop as long as (primecoinBlock->workDataHash != jhMiner_getCurrentWorkHash()) did not happen
	//		 but I noticed it might be smarter to just check if the blockHeight has changed, since that is what is really important
	nPrimorialMultiplier = nPrimorialMultiplierStart;
	uint32 loopCount = 0;

	mpz_class bnHashFactor;
	Primorial(nPrimorialHashFactor, bnHashFactor);

	time_t unixTimeStart;
	time(&unixTimeStart);
	uint32 nTimeRollStart = primecoinBlock->timestamp;

	while( primecoinBlock->serverData.blockHeight == jhMiner_getCurrentWorkBlockHeight(primecoinBlock->threadIndex) )
	{

		if( primecoinBlock->xptMode )
		{
			// when using x.pushthrough, roll time
			time_t unixTimeCurrent;
			time(&unixTimeCurrent);
			uint32 timeDif = unixTimeCurrent - unixTimeStart;
			uint32 newTimestamp = nTimeRollStart + timeDif;
			if( newTimestamp != primecoinBlock->timestamp )
			{
				primecoinBlock->timestamp = newTimestamp;
				primecoinBlock->nonce = 0;
				nPrimorialMultiplierStart = startFactorList[(threadIndex&3)];
			}
		}

		primecoinBlock_generateHeaderHash(primecoinBlock, primecoinBlock->blockHeaderHash.begin());
		//
		// Search
		//
		bool fNewBlock = true;
		unsigned int nTriedMultiplier = 0;
		uint256 phash = primecoinBlock->blockHeaderHash;
        mpz_class mpzHash;
        mpz_set_uint256(mpzHash.get_mpz_t(), phash);
		// Primecoin: try to find hash divisible by primorial
		while ((phash < hashBlockHeaderLimit || (mpzHash % bnHashFactor != 0)) && primecoinBlock->nonce < 0xffff0000)
		{
			primecoinBlock->nonce++;
			primecoinBlock_generateHeaderHash(primecoinBlock, primecoinBlock->blockHeaderHash.begin());
			phash = primecoinBlock->blockHeaderHash;
			mpz_set_uint256(mpzHash.get_mpz_t(), phash);
		}
		//printf("Use nonce %d\n", primecoinBlock->nonce);
		if (primecoinBlock->nonce >= 0xffff0000)
		{
			printf("Nonce overflow\n");
			break;
		}
		// Primecoin: primorial fixed multiplier
		mpz_class bnPrimorial;
		unsigned int nRoundTests = 0;
		unsigned int nRoundPrimesHit = 0;
		//int64 nPrimeTimerStart = GetTimeMicros();
		//if (nTimeExpected > nTimeExpectedPrev)
		//	fIncrementPrimorial = !fIncrementPrimorial;
		//nTimeExpectedPrev = nTimeExpected;
		//// 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");
		//}

		//if( loopCount > 0 )
		//{
		//	primecoinBlock->nonce++;
		///*	if (!PrimeTableGetNextPrime(&nPrimorialMultiplier))
		//		error("PrimecoinMiner() : primorial increment overflow");*/
		//}

		Primorial(nPrimorialMultiplier, bnPrimorial);

		unsigned int nTests = 0;
		unsigned int nPrimesHit = 0;
		

		mpz_class bnMultiplierMin = bnPrimeMin * bnHashFactor / mpzHash + 2;
		while (bnPrimorial < bnMultiplierMin )
		{
			if (!PrimeTableGetNextPrime(&nPrimorialMultiplier))
				error("PrimecoinMiner() : primorial minimum overflow");
			Primorial(nPrimorialMultiplier, bnPrimorial);
		}
		mpz_class bnFixedMultiplier;
		if(bnPrimorial > bnHashFactor){
			bnFixedMultiplier = bnPrimorial / bnHashFactor;
		}else{
			bnFixedMultiplier = 1;
		}
		//printf("fixedMultiplier: %d nPrimorialMultiplier: %d\n", BN_get_word(&bnFixedMultiplier), nPrimorialMultiplier);
		// Primecoin: mine for prime chain
		unsigned int nProbableChainLength;
		if (MineProbablePrimeChain(&psieve, primecoinBlock, bnFixedMultiplier, fNewBlock, nTriedMultiplier, nProbableChainLength, nTests, nPrimesHit))
		{
			// do nothing here, share is already submitted in MineProbablePrimeChain()
			break;
		}
		//psieve = NULL;
		nRoundTests += nTests;
		nRoundPrimesHit += nPrimesHit;
		// added this
		/*if( nPrimorialMultiplier >= 800 )
		{
			primecoinBlock->nonce++;
			nPrimorialMultiplier = nPrimorialMultiplierStart;
		}*/

		//if( nPrimorialMultiplier >= 800 )
		//{
		//	primecoinBlock->nonce++;
		//	nPrimorialMultiplier = nPrimorialMultiplierStart;
		//}

		//if( primecoinBlock->nonce >= 0x100 )
		//{
		//	printf("Base reset\n");
		//	primecoinBlock->nonce = 0;
		//	nPrimorialMultiplier = nPrimorialMultiplierStart;
		//}

		primecoinBlock->nonce++;
		loopCount++;
	}
	
}
예제 #2
0
bool BitcoinMiner(primecoinBlock_t* primecoinBlock, CSieveOfEratosthenes*& psieve, unsigned int threadIndex, unsigned int nonceStep) {
	if (pctx == NULL) { pctx = BN_CTX_new(); }

	primecoinBlock->nonce = 1+threadIndex;
	const unsigned long maxNonce = 0xFFFFFFFF;

	uint32 nTime = getTimeMilliseconds() + 1000*600;
	uint32 loopCount = 0;


	mpz_class mpzHashFactor = 2310; //11 Hash Factor

	time_t unixTimeStart;
	time(&unixTimeStart);
	uint32 nTimeRollStart = primecoinBlock->timestamp - 5;
   uint32 nLastRollTime = getTimeMilliseconds();
	uint32 nCurrentTick = nLastRollTime;
	while( nCurrentTick < nTime && primecoinBlock->serverData.blockHeight == jhMiner_getCurrentWorkBlockHeight(primecoinBlock->threadIndex) )
			{
		nCurrentTick = getTimeMilliseconds();
      // Roll Time stamp every 10 secs.
		if ((primecoinBlock->xptMode) && (nCurrentTick < nLastRollTime || (nLastRollTime - nCurrentTick >= 10000)))
		{
			// when using x.pushthrough, roll time
			time_t unixTimeCurrent;
			time(&unixTimeCurrent);
			uint32 timeDif = unixTimeCurrent - unixTimeStart;
			uint32 newTimestamp = nTimeRollStart + timeDif;
			if( newTimestamp != primecoinBlock->timestamp )
			{
				primecoinBlock->timestamp = newTimestamp;
				primecoinBlock->nonce = 1+threadIndex;
			}
         nLastRollTime = nCurrentTick;
		}

		primecoinBlock_generateHeaderHash(primecoinBlock, primecoinBlock->blockHeaderHash.begin());

		bool fNewBlock = true;
		unsigned int nTriedMultiplier = 0;
		// Primecoin: try to find hash divisible by primorial
        uint256 phash = primecoinBlock->blockHeaderHash;
        mpz_class mpzHash;
        mpz_set_uint256(mpzHash.get_mpz_t(), phash);
        
		while ((phash < hashBlockHeaderLimit || !mpz_divisible_p(mpzHash.get_mpz_t(), mpzHashFactor.get_mpz_t())) && primecoinBlock->nonce < maxNonce) {
			primecoinBlock->nonce += nonceStep;
			if (primecoinBlock->nonce >= maxNonce) { primecoinBlock->nonce = 2+threadIndex; }
			primecoinBlock_generateHeaderHash(primecoinBlock, primecoinBlock->blockHeaderHash.begin());
            phash = primecoinBlock->blockHeaderHash;
            mpz_set_uint256(mpzHash.get_mpz_t(), phash);
		}

		mpz_class mpzPrimorial;mpz_class mpzFixedMultiplier;
		unsigned int nRoundTests = 0;unsigned int nRoundPrimesHit = 0;
		unsigned int nTests = 0;unsigned int nPrimesHit = 0;

		unsigned int nProbableChainLength;
		if (primeStats.tSplit) {
			unsigned int nPrimorialMultiplier = primeStats.nPrimorials[threadIndex%primeStats.nPrimorialsSize];
			Primorial(nPrimorialMultiplier, mpzPrimorial);
			mpzFixedMultiplier = mpzPrimorial / mpzHashFactor;
			MineProbablePrimeChain(psieve, primecoinBlock, mpzFixedMultiplier, fNewBlock, nTriedMultiplier, nProbableChainLength, nTests, nPrimesHit, threadIndex, mpzHash, nPrimorialMultiplier);
		} else {
			unsigned int nPrimorialMultiplier = primeStats.nPrimorials[threadSNum];
			Primorial(nPrimorialMultiplier, mpzPrimorial);
			mpzFixedMultiplier = mpzPrimorial / mpzHashFactor;
		MineProbablePrimeChain(psieve, primecoinBlock, mpzFixedMultiplier, fNewBlock, nTriedMultiplier, nProbableChainLength, nTests, nPrimesHit, threadIndex, mpzHash, nPrimorialMultiplier);
			threadSNum++;if (threadSNum>=primeStats.nPrimorialsSize) { threadSNum = 0; }
#ifdef _WIN32
		threadHearthBeat[threadIndex] = getTimeMilliseconds();
#endif
		if (appQuitSignal)
		{
			printf( "Shutting down mining thread %d.\n", threadIndex);
			return false;
		}
		}
		
	if (appQuitSignal) { printf( "Shutting down mining thread %d.\n", threadIndex);return false; }

		nRoundTests += nTests;
		nRoundPrimesHit += nPrimesHit;

		primecoinBlock->nonce += nonceStep;
		loopCount++;
	}
	
	return true;
}
예제 #3
0
bool BitcoinMiner2_mineProbableChain(primecoinBlock_t* block, mpz_class& mpzFixedMultiplier, bool& fNewBlock, unsigned int& nTriedMultiplier, unsigned int& nProbableChainLength, 
										 unsigned int& nTests, unsigned int& nPrimesHit, sint32 threadIndex, mpz_class& mpzHash, unsigned int nPrimorialMultiplier)
{
	mpz_class mpzChainOrigin;
	mpz_class mpzFinalFixedMultiplier = mpzFixedMultiplier * mpzHash;
	mpz_class mpzTemp;
	uint32 nTime = GetTickCount();
	cSieve_prepare(mpzFinalFixedMultiplier, block->nBits>>24);
	nTime = GetTickCount()-nTime;
	//printf("cSieve prep time: %d\n", nTime);

	unsigned int nPrimorialSeq = 0;
	while (vPrimes[nPrimorialSeq + 1] <= nPrimorialMultiplier)
		nPrimorialSeq++;
	// Allocate GMP variables for primality tests
	CPrimalityTestParams testParams(block->nBits, nPrimorialSeq);
	{
		unsigned long lDivisor = 1;
		unsigned int i;
		testParams.vFastDivSeq.push_back(nPrimorialSeq);
		for (i = 1; i <= nFastDivPrimes; i++)
		{
			// Multiply primes together until the result won't fit an unsigned long
			if (lDivisor < ULONG_MAX / vPrimes[nPrimorialSeq + i])
				lDivisor *= vPrimes[nPrimorialSeq + i];
			else
			{
				testParams.vFastDivisors.push_back(lDivisor);
				testParams.vFastDivSeq.push_back(nPrimorialSeq + i);
				lDivisor = 1;
			}
		}

		// Finish off by multiplying as many primes as possible
		while (lDivisor < ULONG_MAX / vPrimes[nPrimorialSeq + i])
		{
			lDivisor *= vPrimes[nPrimorialSeq + i];
			i++;
		}
		testParams.vFastDivisors.push_back(lDivisor);
		testParams.vFastDivSeq.push_back(nPrimorialSeq + i);
		testParams.nFastDivisorsSize = testParams.vFastDivisors.size();
	}
	// References to counters;
	unsigned int& nChainLengthCunningham1 = testParams.nChainLengthCunningham1;
	unsigned int& nChainLengthCunningham2 = testParams.nChainLengthCunningham2;
	unsigned int& nChainLengthBiTwin = testParams.nChainLengthBiTwin;

	uint32 debugStats_primes = 0;
	uint32 debugStats_multipliersTested = 0;
	
	while( block->serverData.blockHeight == jhMiner_getCurrentWorkBlockHeight(block->threadIndex) )
	{
		uint32 sieveFlags;
		uint32 multiplier = cSieve_findNextMultiplier(&sieveFlags);
		if( multiplier == 0 )
		{
			// mix in next layer
			//printf("Layer finished [%d]\n", cSieve->currentSieveLayerIdx);
			if( cSieve_sieveNextLayer() == false )
				break;
			mpzFinalFixedMultiplier = cSieve->mpzFixedMultiplier;
			//printf("[%02d] debugStats_multipliersTested: %d\n", cSieve->currentSieveLayerIdx, debugStats_multipliersTested);
			//printf("[%02d] debugStats_primes: %d\n", cSieve->currentSieveLayerIdx, debugStats_primes);
			//double primality = (double)debugStats_primes / (double)debugStats_multipliersTested;
			//printf("[%02d] debugStats_primality: %lf\n", cSieve->currentSieveLayerIdx, primality);
			debugStats_primes = 0;
			debugStats_multipliersTested = 0;
			continue;
		}
		 
		//// test for sieve bugs C1
		//if( (sieveFlags&SIEVE_FLAG_C1_COMPOSITE)==0 && (rand()%10)==0 )
		//{
		//	// test c1
		//	for(uint32 lt=0; lt<cSieve->chainLength; lt++)
		//	{
		//		uint32 aMult = 1<<lt;
		//		mpzChainOrigin = mpzFinalFixedMultiplier * multiplier * aMult - 1;	
		//		for(uint32 f=0; f<cSieve->numPrimeFactors; f++)
		//		{
		//			uint32 mod = mpz_mod_ui(mpzTemp.get_mpz_t(), mpzChainOrigin.get_mpz_t(), vPrimes[f]);
		//			if( mod == 0 )
		//				printf("c1 div by %d possible\n", vPrimes[f]);//__debugbreak();
		//		}
		//	}
		//}
		//// test for sieve bugs C2
		//if( (sieveFlags&SIEVE_FLAG_C2_COMPOSITE)==0 && (rand()%10)==0 )
		//{
		//	// test c1
		//	for(uint32 lt=0; lt<cSieve->chainLength; lt++)
		//	{
		//		uint32 aMult = 1<<lt;
		//		mpzChainOrigin = mpzFinalFixedMultiplier * multiplier * aMult + 1;	
		//		for(uint32 f=0; f<cSieve->numPrimeFactors; f++)
		//		{
		//			uint32 mod = mpz_mod_ui(mpzTemp.get_mpz_t(), mpzChainOrigin.get_mpz_t(), vPrimes[f]);
		//			if( mod == 0 )
		//				printf("c2 div by %d possible\n", vPrimes[f]);//__debugbreak();
		//		}
		//	}
		//}
		// test for sieve bugs BT
		//if( (sieveFlags&SIEVE_FLAG_BT_COMPOSITE)==0 )
		//{
		//	// test c1
		//	mpzChainOrigin = mpzFinalFixedMultiplier * multiplier + 1;	
		//	for(uint32 f=0; f<cSieve->numPrimeFactors; f++)
		//	{
		//		uint32 mod = mpz_mod_ui(mpzTemp.get_mpz_t(), mpzChainOrigin.get_mpz_t(), vPrimes[f]);
		//		if( mod == 0 )
		//			printf("bt-c2 div by %d possible\n", vPrimes[f]);
		//	}
		//	// test c2
		//	mpzChainOrigin = mpzFinalFixedMultiplier * multiplier - 1;	
		//	for(uint32 f=0; f<cSieve->numPrimeFactors; f++)
		//	{
		//		uint32 mod = mpz_mod_ui(mpzTemp.get_mpz_t(), mpzChainOrigin.get_mpz_t(), vPrimes[f]);
		//		if( mod == 0 )
		//			printf("bt-c2 div by %d possible\n", vPrimes[f]);
		//	}
		//}

		//mpzChainOrigin = mpzFinalFixedMultiplier * multiplier;		
		mpz_mul_ui(mpzChainOrigin.get_mpz_t(), mpzFinalFixedMultiplier.get_mpz_t(), multiplier);
		nChainLengthCunningham1 = 0;
		nChainLengthCunningham2 = 0;
		nChainLengthBiTwin = 0;

		bool canSubmitAsShare = ProbablePrimeChainTestFast2(mpzChainOrigin, testParams, sieveFlags, multiplier);
		nProbableChainLength = max(max(nChainLengthCunningham1, nChainLengthCunningham2), nChainLengthBiTwin);

		if( nProbableChainLength >= 0x01000000 )
			debugStats_primes++;
		debugStats_multipliersTested++;
		//bool canSubmitAsShare = ProbablePrimeChainTestFast(mpzChainOrigin, testParams);
		//CBigNum bnChainOrigin;
		//bnChainOrigin.SetHex(mpzChainOrigin.get_str(16));
		//bool canSubmitAsShare = ProbablePrimeChainTestBN(bnChainOrigin, block->serverData.nBitsForShare, false, nChainLengthCunningham1, nChainLengthCunningham2, nChainLengthBiTwin);
		


		if( nProbableChainLength >= 0x04000000 )
		{
			sint32 chainDif = (nProbableChainLength>>24) - 7;
			primeStats.nChainHit += pow(8, (float)chainDif);
			//primeStats.nChainHit += pow(8, ((float)((double)nProbableChainLength  / (double)0x1000000))-7.0);
			//primeStats.nChainHit += pow(8, floor((float)((double)nProbableChainLength  / (double)0x1000000)) - 7);
			nTests = 0;
			primeStats.fourChainCount ++;
			if (nProbableChainLength >= 0x5000000)
			{
				primeStats.fiveChainCount ++;
				if (nProbableChainLength >= 0x6000000)
				{
					primeStats.sixChainCount ++;
					if (nProbableChainLength >= 0x7000000)
						primeStats.sevenChainCount ++;
				}
			}
		}
		//if( nBitsGen >= 0x03000000 )
		//	printf("%08X\n", nBitsGen);
		primeStats.primeChainsFound++;
		//if( nProbableChainLength > 0x03000000 )
		//	primeStats.qualityPrimesFound++;
		if( nProbableChainLength > primeStats.bestPrimeChainDifficulty )
			primeStats.bestPrimeChainDifficulty = nProbableChainLength;
		
		if(nProbableChainLength >= block->serverData.nBitsForShare)
		{
			// note: mpzPrimeChainMultiplier does not include the blockHash multiplier
			mpz_div(block->mpzPrimeChainMultiplier.get_mpz_t(), mpzChainOrigin.get_mpz_t(), mpzHash.get_mpz_t());
			//mpz_lsh(block->mpzPrimeChainMultiplier.get_mpz_t(), mpzFixedMultiplier.get_mpz_t(), multiplier);
			// update server data
			block->serverData.client_shareBits = nProbableChainLength;
			// generate block raw data
			uint8 blockRawData[256] = {0};
			memcpy(blockRawData, block, 80);
			uint32 writeIndex = 80;
			sint32 lengthBN = 0;
			CBigNum bnPrimeChainMultiplier;
			bnPrimeChainMultiplier.SetHex(block->mpzPrimeChainMultiplier.get_str(16));
			std::vector<unsigned char> bnSerializeData = bnPrimeChainMultiplier.getvch();
			lengthBN = bnSerializeData.size();
			*(uint8*)(blockRawData+writeIndex) = (uint8)lengthBN; // varInt (we assume it always has a size low enough for 1 byte)
			writeIndex += 1;
			memcpy(blockRawData+writeIndex, &bnSerializeData[0], lengthBN);
			writeIndex += lengthBN;	
			// switch endianness
			for(uint32 f=0; f<256/4; f++)
			{
				*(uint32*)(blockRawData+f*4) = _swapEndianessU32(*(uint32*)(blockRawData+f*4));
			}
			time_t now = time(0);
			struct tm * timeinfo;
			timeinfo = localtime (&now);
			char sNow [80];
			strftime (sNow, 80, "%x - %X",timeinfo);

			printf("%s - SHARE FOUND !!! (Th#: %u Multiplier: %d Layer: %d) ---  DIFF: %f    %s    %s\n", 
				sNow, threadIndex, multiplier, cSieve->currentSieveLayerIdx, (float)((double)nProbableChainLength  / (double)0x1000000), 
				nProbableChainLength >= 0x6000000 ? ">6":"", nProbableChainLength >= 0x7000000 ? ">7":"");

			// submit this share
			if (jhMiner_pushShare_primecoin(blockRawData, block))
				primeStats.foundShareCount ++;
			//printf("Probable prime chain found for block=%s!!\n  Target: %s\n  Length: (%s %s %s)\n", block.GetHash().GetHex().c_str(),TargetToString(block.nBits).c_str(), TargetToString(nChainLengthCunningham1).c_str(), TargetToString(nChainLengthCunningham2).c_str(), TargetToString(nChainLengthBiTwin).c_str());
			//nProbableChainLength = max(max(nChainLengthCunningham1, nChainLengthCunningham2), nChainLengthBiTwin);
			// since we are using C structs here we have to make sure the memory for the CBigNum in the block is freed again
			//delete *psieve;
			//*psieve = NULL;
			//block->bnPrimeChainMultiplier = NULL;
			RtlZeroMemory(blockRawData, 256);
			//delete *psieve;
			//*psieve = NULL;
			// dont quit if we find a share, there could be other shares in the remaining prime candidates
			nTests = 0;   // tehere is a good chance to find more shares so search a litle more.
			//block->nonce++;
			//return true;
			//break;
			//if (multipleShare)
		}
	}
예제 #4
0
bool BitcoinMiner(primecoinBlock_t* primecoinBlock, CSieveOfEratosthenes*& psieve, const sint32 threadIndex, const unsigned int nonceStep)
{
	//JLR DBG
	//printf("PrimecoinMiner started\n");
	//SetThreadPriority(THREAD_PRIORITY_LOWEST);
	//RenameThread("primecoin-miner");
	if( pctx == NULL )
		pctx = BN_CTX_new();
	// Each thread has its own key and counter
	//CReserveKey reservekey(pwallet);
//	unsigned int nExtraNonce = 0;  unused?

   static const unsigned int MAX_NONCE = 0xFFFF0000; // From Primecoind sources.
	static const unsigned int nPrimorialHashFactor = 7;
//	const unsigned int nPrimorialMultiplierStart = 61;   unused?
//	const unsigned int nPrimorialMultiplierMax = 79;  unused?

	unsigned int nPrimorialMultiplier = primeStats.nPrimorialMultiplier;
//	uint64_t nTimeExpected = 0;   // time expected to prime chain (micro-second)   unused?
//	uint64_t nTimeExpectedPrev = 0; // time expected to prime chain last time   unused?
//	bool fIncrementPrimorial = true; // increase or decrease primorial factor   unused?
//	uint64_t nSieveGenTime = 0;   unused?
	

	// Generate a thread specific nonce.
	primecoinBlock->nonce = threadIndex;

	uint64 nTime = getTimeMilliseconds() + 1000*600;
//	uint64 nStatTime = getTimeMilliseconds() + 2000;  unused?
	
	// note: originally a wanted to loop as long as (primecoinBlock->workDataHash != jhMiner_getCurrentWorkHash()) did not happen
	//		 but I noticed it might be smarter to just check if the blockHeight has changed, since that is what is really important
	uint32 loopCount = 0;

	//mpz_class mpzHashFactor;
	//Primorial(nPrimorialHashFactor, mpzHashFactor);
	unsigned int nHashFactor = PrimorialFast(nPrimorialHashFactor);

	time_t unixTimeStart;
	time(&unixTimeStart);
	uint32 nTimeRollStart = primecoinBlock->timestamp - 5;
   uint32 nLastRollTime = getTimeMilliseconds();
	uint32 nCurrentTick = nLastRollTime;
	while( nCurrentTick < nTime && primecoinBlock->serverData.blockHeight == jhMiner_getCurrentWorkBlockHeight(primecoinBlock->threadIndex) )
			{
		nCurrentTick = getTimeMilliseconds();
      // Roll Time stamp every 10 secs.
		if ((primecoinBlock->xptMode) && (nCurrentTick < nLastRollTime || (nLastRollTime - nCurrentTick >= 10000)))
		{
			// when using x.pushthrough, roll time
			time_t unixTimeCurrent;
			time(&unixTimeCurrent);
			uint32 timeDif = unixTimeCurrent - unixTimeStart;
			uint32 newTimestamp = nTimeRollStart + timeDif;
			if( newTimestamp != primecoinBlock->timestamp )
			{
				primecoinBlock->timestamp = newTimestamp;
				primecoinBlock->nonce = threadIndex;
				//nPrimorialMultiplierStart = startFactorList[(threadIndex&3)];
		      //nPrimorialMultiplier = nPrimorialMultiplierStart;
			}
			nLastRollTime = nCurrentTick;
		}

		primecoinBlock_generateHeaderHash(primecoinBlock, primecoinBlock->blockHeaderHash.begin());
		//
		// Search
		//
		bool fNewBlock = true;
		unsigned int nTriedMultiplier = 0;
		// Primecoin: try to find hash divisible by primorial
        uint256 phash = primecoinBlock->blockHeaderHash;
        mpz_class mpzHash;
        mpz_set_uint256(mpzHash.get_mpz_t(), phash);
        
		while ((phash < hashBlockHeaderLimit || !mpz_divisible_ui_p(mpzHash.get_mpz_t(), nHashFactor)) && primecoinBlock->nonce < MAX_NONCE) {
			primecoinBlock->nonce += nonceStep;
			primecoinBlock_generateHeaderHash(primecoinBlock, primecoinBlock->blockHeaderHash.begin());
            phash = primecoinBlock->blockHeaderHash;
            mpz_set_uint256(mpzHash.get_mpz_t(), phash);
		}
		//JLR DBG
		//printf("Use nonce %d\n", primecoinBlock->nonce);
		if (primecoinBlock->nonce >= MAX_NONCE)
		{
			//JLR DBG
			printf("Nonce overflow\n");
			break;
		}
		// Primecoin: primorial fixed multiplier
		mpz_class mpzPrimorial;
		unsigned int nRoundTests = 0;
		unsigned int nRoundPrimesHit = 0;
//		uint64 nPrimeTimerStart = getTimeMilliseconds();   unused?
		
		//if( loopCount > 0 )
		//{
		//	//primecoinBlock->nonce++;
		//	if (!PrimeTableGetNextPrime(nPrimorialMultiplier))
		//		error("PrimecoinMiner() : primorial increment overflow");
		//}

		Primorial(nPrimorialMultiplier, mpzPrimorial);

		unsigned int nTests = 0;
		unsigned int nPrimesHit = 0;
		
		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;
        }		
	//JLR DBG
	//printf("fixedMultiplier: %d nPrimorialMultiplier: %d\n", BN_get_word(&bnFixedMultiplier), nPrimorialMultiplier);
		// Primecoin: mine for prime chain
		unsigned int nProbableChainLength;
		MineProbablePrimeChain(psieve, primecoinBlock, mpzFixedMultiplier, fNewBlock, nTriedMultiplier, nProbableChainLength, nTests, nPrimesHit, threadIndex, mpzHash, nPrimorialMultiplier);
#ifdef _WIN32
		threadHearthBeat[threadIndex] = getTimeMilliseconds();
#endif
		if (appQuitSignal)
		{
			printf( "Shutting down mining thread %d.\n", threadIndex);
			return false;
		}
		//{
		//	// do nothing here, share is already submitted in MineProbablePrimeChain()
		//	//primecoinBlock->nonce += 0x00010000;
		//	primecoinBlock->nonce++;
		//	nPrimorialMultiplier = primeStats.nPrimorialMultiplier;
		//	//break;
		//}
		//psieve = NULL;
		nRoundTests += nTests;
		nRoundPrimesHit += nPrimesHit;
		nPrimorialMultiplier = primeStats.nPrimorialMultiplier;
		// added this
		//if (fNewBlock)
		//{
		//}


		primecoinBlock->nonce += nonceStep;
		//primecoinBlock->timestamp = max(primecoinBlock->timestamp, (unsigned int) time(NULL));
		loopCount++;
	}
	
	return true;
}