void* Reap_CPU_V1(void* param)
{
	Reap_CPU_param* state = (Reap_CPU_param*)param;

	Work tempwork;
	tempwork.time = 13371337;

	uint8_t tempdata[512];
	memset(tempdata, 0, 512);

	uint8_t finalhash[32];
	uint8_t hash_results[1] = {};

	uint32_t current_server_id;

	while(!shutdown_now)
	{
		if (current_work.old)
		{
			Wait_ms(20);
			continue;
		}
		if (tempwork.time != current_work.time)
		{
			pthread_mutex_lock(&current_work_mutex);
			tempwork = current_work;
			pthread_mutex_unlock(&current_work_mutex);
			memcpy(tempdata, &tempwork.data[0], 128);
			*(uint32_t*)&tempdata[100] = state->thread_id;
			current_server_id = tempwork.server_id;
		}

		*(uint64_t*)&tempdata[76] = tempwork.ntime_at_getwork + (ticker()-tempwork.time)/1000;

		for(uint32_t h=0; h<CPU_BATCH_SIZE; ++h)
		{
			BlockHash_1_mine_V1(tempdata, finalhash, hash_results);
			if (hash_results[0])
			{
				BlockHash_1(tempdata, finalhash);
				if (finalhash[30] != 0 || finalhash[31] != 0)
					cpu_shares_hwinvalid++;
				else
					cpu_shares_hwvalid++;
				if (CPU_Hash_Below_Target(finalhash, &tempwork.target_share[0]))
					CPU_Got_share(state,tempdata,tempwork.target_share,current_server_id);
			}
			++*(uint32_t*)&tempdata[108];
		}
		state->hashes += CPU_BATCH_SIZE;
	}
	pthread_exit(NULL);
	return NULL;
}
bool MinePrime(Reap_CPU_param* state, Work& tempwork)
{
	uchar* tempdata = &tempwork.data[0];
	uchar hash[32];
	mysha256(hash,tempdata,80);
	mysha256(hash,hash,32);
	
	//does this need byte flipping?
	uint bits = *(uint*)&tempdata[72];
	
	if (!(hash[31] & 0x80))
		return false; //hash is too small, abort

	Mpz_w hashnum;
	
	set_mpz_to_hash(&hashnum.n, hash);
	if (mpz_fdiv_ui(hashnum.n, 2*3) != 0)
		return false;
	
	bool found=false;

	
	//5431526412865007455
	mpz_t factor; mpz_init_set_str(factor, "5431526412865007455", 10);
	mpz_mul(hashnum.n,hashnum.n,factor);
	
	uint remainders[MAX_SIEVE_AMOUNT] = {};
	for(int i=0; i<MAX_SIEVE_AMOUNT; ++i)
	{
		remainders[i] = mpz_fdiv_ui(hashnum.n,Primes::v[i]);
	}
	
	mpz_t newhashnum; mpz_init(newhashnum);
	for(uint h=1; h<500; ++h)
	{
		mpz_add(newhashnum,newhashnum,hashnum.n);
		uint c1=0,c2=0,tw=0;

		uint sievenumber = 0;
		for(uint i=16; i<MAX_SIEVE_AMOUNT; ++i)
		{
			sievenumber |= Sieve::Get(i,remainders[i]*h%Primes::v[i])^3;
		}
		sievenumber ^= 3;
		//cout << sievenumber << endl;;
		if (sievenumber == 0)
			continue;
		
		//TODO: fix second parameter, it should be bits!
		AllChainTest(&newhashnum, 0, true, &c1, &c2, &tw, sievenumber);

		uint c1_i = TargetGetLength(c1);
		uint c2_i = TargetGetLength(c2);
		uint tw_i = TargetGetLength(tw);

		const int minlength=5;

		/*{
			if (c1_i >= minlength)
				cout << "First kind: " << c1_i << endl;
			if (c2_i >= minlength)
				cout << "Second kind: " << c2_i << endl;
			if (tw_i >= minlength)
				cout << "Twin kind: " << tw_i << endl;
		}*/
			
		
		++chainspersec[c1_i];
		++chainspersec[c2_i];
		++chainspersec[tw_i];
		++totalpersec;

		found = (c1_i >= minlength || c2_i >= minlength || tw_i >= minlength);
		if (found)
		{
			mpz_mul_ui(factor,factor,h);
			vector<uchar> auxdata = XPM_create_auxdata(&factor);
			Share share;
			
			CPU_Got_share(state,tempwork,auxdata);//tempdata,tempwork.target_share,current_server_id,tempwork.dataid,auxdata);
		}
	}

	return found;
}
// Mine probable prime chain of form: n = h * p# +/- 1
bool MineProbablePrimeChain(Reap_CPU_param* state, Work& tempwork, CSieveOfEratosthenes& psieve, mpz_class& mpzFixedMultiplier, bool& fNewBlock, unsigned int& nTriedMultiplier, unsigned int& nProbableChainLength, unsigned int& nTests, unsigned int& nPrimesHit, unsigned int& nChainsHit, mpz_class& mpzHash, unsigned int nPrimorialMultiplier)
{
    nProbableChainLength = 0;
    nPrimesHit = 0;
    nChainsHit = 0;
    //const unsigned int nBits = block.nBits;
	const unsigned int nBits = *(uint*)&tempwork.data[72];
	
	bool use_gpu_fermat_test = globalconfs.coin.config.GetValue<bool>("use_gpu_fermat_test");

    if (fNewBlock && psieve.inited)
    {
        // Must rebuild the sieve
		psieve.Deinit();
    }
    fNewBlock = false;

    int64 nStart; // microsecond timer
    if (!psieve.inited)
    {
        // Build sieve
        nStart = ticker()*1000;
		psieve.InitAndWeave(state, nSieveSize, nBits, mpzHash, mpzFixedMultiplier);
        if (globalconfs.coin.config.GetValue<bool>("debug"))
            printf("MineProbablePrimeChain() : new sieve (%lu/%u) ready in %uus\n", psieve.CandidateList.size(), nSieveSize, (unsigned int) (ticker()*1000 - nStart));
    }

    mpz_class mpzHashMultiplier = mpzHash * mpzFixedMultiplier;
    mpz_class mpzChainOrigin;

    // Determine the sequence number of the round primorial
    unsigned int nPrimorialSeq = 0;
    while (vPrimes[nPrimorialSeq + 1] <= nPrimorialMultiplier)
        nPrimorialSeq++;

    // Allocate GMP variables for primality tests
    CPrimalityTestParams testParams(nBits, nPrimorialSeq);
    nStart = ticker()*1000;

    // References to counters;
    unsigned int& nChainLengthCunningham1 = testParams.nChainLengthCunningham1;
    unsigned int& nChainLengthCunningham2 = testParams.nChainLengthCunningham2;
    unsigned int& nChainLengthBiTwin = testParams.nChainLengthBiTwin;
	
	//cout << "PSIEVIOSIE" << psieve.CandidateList.size() << endl;
	
	for(uint i=0; i<psieve.CandidateList.size(); ++i)
    {
		nTriedMultiplier = psieve.CandidateList[i]&0x3FFFFFFFU;
		uint sievenumber = psieve.CandidateList[i]>>30;
		if (sievenumber == 0)
			sievenumber=3;
		if (nTriedMultiplier == 0) //will crash otherwise
			continue;
		++nTests;
		if (tempwork.time != current_work.time)
		{
			//cout << "Tempwork.time != curnetopqi" << tempwork.time << " " << current_work.time << endl;
			break;
		}
        mpzChainOrigin = mpzHashMultiplier * (nTriedMultiplier&0x3FFFFFFFU);
        nChainLengthCunningham1 = 0;
        nChainLengthCunningham2 = 0;
        nChainLengthBiTwin = 0;
        if (ProbablePrimeChainTestFast(mpzChainOrigin, testParams, sievenumber, use_gpu_fermat_test))
        {
			mpz_t mpzPrimeChainMultiplier; mpz_init(mpzPrimeChainMultiplier);
			mpz_mul_ui(mpzPrimeChainMultiplier,mpzFixedMultiplier.get_mpz_t(),nTriedMultiplier);
			{
				//gmp_printf("Found chain! Mult: %Zx\n",mpzPrimeChainMultiplier);
				vector<uchar> auxdata = XPM_create_auxdata(&mpzPrimeChainMultiplier);
				CPU_Got_share(state,tempwork,auxdata);
			}
			mpz_clear(mpzPrimeChainMultiplier);

            nProbableChainLength = std::max(std::max(nChainLengthCunningham1, nChainLengthCunningham2), nChainLengthBiTwin);
            return true;
        }
        nProbableChainLength = std::max(std::max(nChainLengthCunningham1, nChainLengthCunningham2), nChainLengthBiTwin);
        if(TargetGetLength(nProbableChainLength) >= 1)
            nPrimesHit++;
        if(TargetGetLength(nProbableChainLength) >= nStatsChainLength)
            nChainsHit++;
    }

	// power tests completed for the sieve
	//if (fDebug && GetBoolArg("-printmining"))
		//printf("MineProbablePrimeChain() : %u tests (%u primes and %u %d-chains) in %uus\n", nTests, nPrimesHit, nChainsHit, nStatsChainLength, (unsigned int) (GetTimeMicros() - nStart));
	psieve.Deinit();
	fNewBlock = true; // notify caller to change nonce
	return false; // stop as new block arrived
}