Merge remote-tracking branch 'upstream/master'

master
Thomas Baumbach 2013-08-24 21:27:34 +02:00
commit c535367514
10 changed files with 486 additions and 323 deletions

View File

@ -212,8 +212,8 @@ static const CRPCCommand vRPCCommands[] =
{ "setgenerate", &setgenerate, true, false },
{ "getsievepercentage", &getsievepercentage, true, false },
{ "setsievepercentage", &setsievepercentage, true, false },
{ "getroundsievepercentage",&getroundsievepercentage,true,false },
{ "setroundsievepercentage",&setroundsievepercentage,true,false },
{ "getsieveextensions", &getsieveextensions, true, false },
{ "setsieveextensions", &setsieveextensions, true, false },
{ "getprimespersec", &getprimespersec, true, false },
{ "getchainspermin", &getchainspermin, true, false },
{ "getinfo", &getinfo, true, false },
@ -273,6 +273,7 @@ static const CRPCCommand vRPCCommands[] =
{ "lockunspent", &lockunspent, false, false },
{ "listlockunspent", &listlockunspent, false, false },
{ "listprimerecords", &listprimerecords, false, false },
{ "listtopprimes", &listtopprimes, false, false },
};
CRPCTable::CRPCTable()
@ -1221,7 +1222,7 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri
if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
if (strMethod == "setsievepercentage" && n > 0) ConvertTo<boost::int64_t>(params[0]);
if (strMethod == "setroundsievepercentage" && n > 0) ConvertTo<boost::int64_t>(params[0]);
if (strMethod == "setsieveextensions" && n > 0) ConvertTo<boost::int64_t>(params[0]);
if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
@ -1268,6 +1269,7 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri
if (strMethod == "lockunspent" && n > 1) ConvertTo<Array>(params[1]);
if (strMethod == "importprivkey" && n > 2) ConvertTo<bool>(params[2]);
if (strMethod == "listprimerecords" && n > 0) ConvertTo<boost::int64_t>(params[0]);
if (strMethod == "listtopprimes" && n > 0) ConvertTo<boost::int64_t>(params[0]);
return params;
}

View File

@ -151,8 +151,8 @@ extern json_spirit::Value getgenerate(const json_spirit::Array& params, bool fHe
extern json_spirit::Value setgenerate(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getsievepercentage(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value setsievepercentage(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getroundsievepercentage(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value setroundsievepercentage(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getsieveextensions(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value setsieveextensions(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getprimespersec(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getchainspermin(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getmininginfo(const json_spirit::Array& params, bool fHelp);
@ -210,5 +210,6 @@ extern json_spirit::Value getblock(const json_spirit::Array& params, bool fHelp)
extern json_spirit::Value gettxoutsetinfo(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value gettxout(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value listprimerecords(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value listtopprimes(const json_spirit::Array& params, bool fHelp);
#endif

View File

@ -158,6 +158,11 @@ bool WriteSyncCheckpoint(const uint256& hashCheckpoint)
return true;
}
bool IsSyncCheckpointEnforced()
{
return (GetBoolArg("-checkpointenforce", false) || mapArgs.count("-checkpointkey")); // checkpoint master node is always enforced
}
bool AcceptPendingSyncCheckpoint()
{
LOCK(cs_hashSyncCheckpoint);
@ -171,7 +176,7 @@ bool AcceptPendingSyncCheckpoint()
}
CBlockIndex* pindexCheckpoint = mapBlockIndex[hashPendingCheckpoint];
if (!pindexCheckpoint->IsInMainChain())
if (IsSyncCheckpointEnforced() && !pindexCheckpoint->IsInMainChain())
{
CValidationState state;
if (!SetBestChain(state, pindexCheckpoint))
@ -434,7 +439,7 @@ bool CSyncCheckpoint::ProcessSyncCheckpoint(CNode* pfrom)
return false;
CBlockIndex* pindexCheckpoint = mapBlockIndex[hashCheckpoint];
if (!pindexCheckpoint->IsInMainChain())
if (IsSyncCheckpointEnforced() && !pindexCheckpoint->IsInMainChain())
{
// checkpoint chain received but not yet main chain
CValidationState state;
@ -474,7 +479,7 @@ Value getcheckpoint(const Array& params, bool fHelp)
result.push_back(Pair("height", pindexCheckpoint->nHeight));
result.push_back(Pair("timestamp", (boost::int64_t) pindexCheckpoint->GetBlockTime()));
}
result.push_back(Pair("subscribemode", (GetBoolArg("-checkpointenforce", false) || mapArgs.count("-checkpointkey")? "enforce" : "advisory")));
result.push_back(Pair("subscribemode", IsSyncCheckpointEnforced()? "enforce" : "advisory"));
if (mapArgs.count("-checkpointkey"))
result.push_back(Pair("checkpointmaster", true));
@ -507,7 +512,7 @@ Value sendcheckpoint(const Array& params, bool fHelp)
result.push_back(Pair("height", pindexCheckpoint->nHeight));
result.push_back(Pair("timestamp", (boost::int64_t) pindexCheckpoint->GetBlockTime()));
}
result.push_back(Pair("subscribemode", (GetBoolArg("-checkpointenforce", false) || mapArgs.count("-checkpointkey")? "enforce" : "advisory")));
result.push_back(Pair("subscribemode", IsSyncCheckpointEnforced()? "enforce" : "advisory"));
if (mapArgs.count("-checkpointkey"))
result.push_back(Pair("checkpointmaster", true));

View File

@ -23,6 +23,7 @@ extern std::string strCheckpointWarning;
CBlockIndex* GetLastSyncCheckpoint();
bool WriteSyncCheckpoint(const uint256& hashCheckpoint);
bool IsSyncCheckpointEnforced();
bool AcceptPendingSyncCheckpoint();
uint256 AutoSelectSyncCheckpoint();
bool CheckSyncCheckpoint(const uint256& hashBlock, const CBlockIndex* pindexPrev);

View File

@ -1868,7 +1868,7 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
strMiscWarning = _("Warning: This version is obsolete, upgrade required!");
}
if (!(GetBoolArg("-checkpointenforce", false) || mapArgs.count("-checkpointkey"))) // checkpoint advisory mode
if (!IsSyncCheckpointEnforced()) // checkpoint advisory mode
{
if (pindexBest->pprev && !CheckSyncCheckpoint(pindexBest->GetBlockHash(), pindexBest->pprev))
strCheckpointWarning = _("Warning: checkpoint on different blockchain fork, contact developers to resolve the issue");
@ -2146,7 +2146,7 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp)
return state.DoS(100, error("AcceptBlock() : rejected by checkpoint lock-in at %d", nHeight));
// ppcoin: check that the block satisfies synchronized checkpoint
if ((GetBoolArg("-checkpointenforce", false) || mapArgs.count("-checkpointkey")) // checkpoint enforce mode
if (IsSyncCheckpointEnforced() // checkpoint enforce mode
&& !CheckSyncCheckpoint(hash, pindexPrev))
return error("AcceptBlock() : rejected by synchronized checkpoint");
@ -4585,7 +4585,7 @@ void BitcoinMiner(CWallet *pwallet, CBlockProvider *block_provider)
unsigned int nExtraNonce = 0; //^
unsigned int nPrimorialMultiplier = nPrimorialHashFactor;
double nTimeExpected = 0; // time expected to prime chain (micro-second)
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
@ -4790,17 +4790,18 @@ void BitcoinMiner(CWallet *pwallet, CBlockProvider *block_provider)
{
// 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);
nTimeExpected = (double) nRoundTime / nCalcRoundTests;
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);
nTimeExpected = nTimeExpected / max(0.01, dPrimeProbability);
dTimeExpected = dTimeExpected / max(0.01, dPrimeProbability);
dRoundChainExpected *= dPrimeProbability;
}
dChainExpected += dRoundChainExpected;
@ -4809,7 +4810,7 @@ void BitcoinMiner(CWallet *pwallet, CBlockProvider *block_provider)
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, ((nTimeExpected/1000000.0))/86400.0, dRoundChainExpected);
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
@ -4842,11 +4843,8 @@ void BitcoinMiner(CWallet *pwallet, CBlockProvider *block_provider)
// Primecoin: reset sieve+primality round timer
nPrimeTimerStart = GetTimeMicros();
// Adjust primorial so that sieve generation takes a set percentage of round time
if (nSieveGenTime >= nRoundSievePercentage * nRoundTime / 100)
fIncrementPrimorial = true;
else
fIncrementPrimorial = false;
if (dTimeExpected > dTimeExpectedPrev)
fIncrementPrimorial = !fIncrementPrimorial;
// Primecoin: primorial always needs to be incremented if only 0 primes were found
if (nRoundPrimesHit == 0)

View File

@ -13,20 +13,20 @@
std::vector<unsigned int> vPrimes;
unsigned int nSieveSize = nDefaultSieveSize;
unsigned int nSievePercentage = nDefaultSievePercentage;
unsigned int nRoundSievePercentage = nDefaultRoundSievePercentage;
unsigned int nSieveExtensions = nDefaultSieveExtensions;
static unsigned int int_invert(unsigned int a, unsigned int nPrime);
void GeneratePrimeTable()
{
unsigned int nDefaultRSPercentage = (fTestNet) ? nDefaultRoundSievePercentageTestnet : nDefaultRoundSievePercentage;
nRoundSievePercentage = (unsigned int)GetArg("-roundsievepercentage", nDefaultRSPercentage);
nRoundSievePercentage = std::max(std::min(nRoundSievePercentage, nMaxRoundSievePercentage), nMinRoundSievePercentage);
const unsigned int nDefaultSieveExt = (fTestNet) ? nDefaultSieveExtensionsTestnet : nDefaultSieveExtensions;
nSieveExtensions = (unsigned int)GetArg("-sieveextensions", nDefaultSieveExt);
nSieveExtensions = std::max(std::min(nSieveExtensions, nMaxSieveExtensions), nMinSieveExtensions);
nSievePercentage = (unsigned int)GetArg("-sievepercentage", nDefaultSievePercentage);
nSievePercentage = std::max(std::min(nSievePercentage, nMaxSievePercentage), nMinSievePercentage);
nSieveSize = (unsigned int)GetArg("-sievesize", nDefaultSieveSize);
nSieveSize = std::max(std::min(nSieveSize, nMaxSieveSize), nMinSieveSize);
printf("GeneratePrimeTable() : setting nRoundSievePercentage = %u, nSievePercentage = %u, nSieveSize = %u\n", nRoundSievePercentage, nSievePercentage, nSieveSize);
printf("GeneratePrimeTable() : setting nSieveExtensions = %u, nSievePercentage = %u, nSieveSize = %u\n", nSieveExtensions, nSievePercentage, nSieveSize);
const unsigned nPrimeTableLimit = nSieveSize;
vPrimes.clear();
// Generate prime table using sieve of Eratosthenes
@ -510,9 +510,6 @@ unsigned int EstimateWorkTransition(unsigned int nPrevWorkTransition, unsigned i
/* PRIMECOIN MINING */
/********************/
// Number of primes to test with fast divisibility testing
static const unsigned int nFastDivPrimes = 60;
class CPrimalityTestParams
{
public:
@ -526,11 +523,6 @@ public:
mpz_class mpzOriginPlusOne;
mpz_class N;
// Big divisors for fast div test
std::vector<unsigned long> vFastDivisors;
std::vector<unsigned int> vFastDivSeq;
unsigned int nFastDivisorsSize;
// Values specific to a round
unsigned int nBits;
unsigned int nPrimorialSeq;
@ -560,31 +552,12 @@ public:
// Check Fermat probable primality test (2-PRP): 2 ** (n-1) = 1 (mod n)
// true: n is probable prime
// false: n is composite; set fractional length in the nLength output
static bool FermatProbablePrimalityTestFast(const mpz_class& n, unsigned int& nLength, CPrimalityTestParams& testParams, bool fFastDiv = false, bool fFastFail = false)
static bool FermatProbablePrimalityTestFast(const mpz_class& n, unsigned int& nLength, CPrimalityTestParams& testParams, bool fFastFail = false)
{
// Faster GMP version
mpz_t& mpzE = testParams.mpzE;
mpz_t& mpzR = testParams.mpzR;
if (fFastDiv)
{
// Fast divisibility tests
// Divide n by a large divisor
// Use the remainder to test divisibility by small primes
const unsigned int nDivSize = testParams.nFastDivisorsSize;
for (unsigned int i = 0; i < nDivSize; i++)
{
unsigned long lRemainder = mpz_tdiv_ui(n.get_mpz_t(), testParams.vFastDivisors[i]);
unsigned int nPrimeSeq = testParams.vFastDivSeq[i];
const unsigned int nPrimeSeqEnd = testParams.vFastDivSeq[i + 1];
for (; nPrimeSeq < nPrimeSeqEnd; nPrimeSeq++)
{
if (lRemainder % vPrimes[nPrimeSeq] == 0)
return false; // returning here skips the fractional length calculation!
}
}
}
mpz_sub_ui(mpzE, n.get_mpz_t(), 1);
mpz_powm(mpzR, mpzTwo.get_mpz_t(), mpzE, n.get_mpz_t());
if (mpz_cmp_ui(mpzR, 1) == 0)
@ -670,7 +643,7 @@ static bool ProbableCunninghamChainTestFast(const mpz_class& n, bool fSophieGerm
nProbableChainLength = 0;
// Fermat test for n first
if (!FermatProbablePrimalityTestFast(n, nProbableChainLength, testParams, true, true))
if (!FermatProbablePrimalityTestFast(n, nProbableChainLength, testParams, true))
return false;
// Euler-Lagrange-Lifchitz test for the following numbers in chain
@ -767,7 +740,7 @@ bool MineProbablePrimeChain(CBlock& block, mpz_class& mpzFixedMultiplier, bool&
{
// Build sieve
nStart = GetTimeMicros();
lpsieve = new CSieveOfEratosthenes(nSieveSize, nBits, mpzHash, mpzFixedMultiplier, pindexPrev);
lpsieve = new CSieveOfEratosthenes(nSieveSize, nSievePercentage, nSieveExtensions, nBits, mpzHash, mpzFixedMultiplier, pindexPrev);
while (lpsieve->Weave() && pindexPrev == pindexBest);
nSieveGenTime = GetTimeMicros() - nStart;
if (fDebug && GetBoolArg("-printmining"))
@ -787,35 +760,6 @@ bool MineProbablePrimeChain(CBlock& block, mpz_class& mpzFixedMultiplier, bool&
// Allocate GMP variables for primality tests
CPrimalityTestParams testParams(nBits, nPrimorialSeq);
// Compute parameters for fast div test
{
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();
}
nStart = GetTimeMicros();
// References to test parameters
@ -846,6 +790,7 @@ bool MineProbablePrimeChain(CBlock& block, mpz_class& mpzFixedMultiplier, bool&
CBigNum bnPrimeChainMultiplier;
bnPrimeChainMultiplier.SetHex(mpzPrimeChainMultiplier.get_str(16));
block.bnPrimeChainMultiplier = bnPrimeChainMultiplier;
printf("nTriedMultiplier = %u\n", nTriedMultiplier); // Debugging
printf("Probable prime chain found for block=%s!!\n Target: %s\n Chain: %s\n", block.GetHash().GetHex().c_str(),
TargetToString(block.nBits).c_str(), GetPrimeChainName(nCandidateType, nChainLength).c_str());
nProbableChainLength = nChainLength;
@ -856,6 +801,13 @@ bool MineProbablePrimeChain(CBlock& block, mpz_class& mpzFixedMultiplier, bool&
nPrimesHit++;
if(TargetGetLength(nProbableChainLength) >= nStatsChainLength)
nChainsHit++;
// Debugging
#if 0
if(TargetGetLength(nProbableChainLength) >= 1)
printf("Multiplier %u gave a prime\n", nTriedMultiplier);
else
printf("Multiplier %u gave nothing\n", nTriedMultiplier);
#endif
}
//if (fDebug && GetBoolArg("-printmining"))
@ -913,17 +865,34 @@ static unsigned int int_invert(unsigned int a, unsigned int nPrime)
return (inverse + nPrime) % nPrime;
}
void CSieveOfEratosthenes::AddMultiplier(unsigned int *vMultipliers, const unsigned int nPrimeSeq, const unsigned int nSolvedMultiplier)
void CSieveOfEratosthenes::ProcessMultiplier(sieve_word_t *vfComposites, const unsigned int nMinMultiplier, const unsigned int nMaxMultiplier, const std::vector<unsigned int>& vPrimes, unsigned int *vMultipliers, unsigned int nLayerSeq)
{
// Eliminate duplicates
for (unsigned int i = 0; i < nHalfChainLength; i++)
// Wipe the part of the array first
if (nMinMultiplier < nMaxMultiplier)
memset(vfComposites + GetWordNum(nMinMultiplier), 0, (nMaxMultiplier - nMinMultiplier + nWordBits - 1) / nWordBits * sizeof(sieve_word_t));
for (unsigned int nPrimeSeq = 1; nPrimeSeq < nPrimes; nPrimeSeq++)
{
unsigned int nStoredMultiplier = vMultipliers[nPrimeSeq * nHalfChainLength + i];
if (nStoredMultiplier == 0xFFFFFFFF || nStoredMultiplier == nSolvedMultiplier)
const unsigned int nPrime = vPrimes[nPrimeSeq];
unsigned int nVariableMultiplier = vMultipliers[nPrimeSeq * nSieveLayers + nLayerSeq];
if (nVariableMultiplier < nMinMultiplier)
nVariableMultiplier += (nMinMultiplier - nVariableMultiplier + nPrime - 1) / nPrime * nPrime;
#ifdef USE_ROTATE
const unsigned int nRotateBits = nPrime % nWordBits;
sieve_word_t lBitMask = GetBitMask(nVariableMultiplier);
for (; nVariableMultiplier < nMaxMultiplier; nVariableMultiplier += nPrime)
{
vMultipliers[nPrimeSeq * nHalfChainLength + i] = nSolvedMultiplier;
break;
vfComposites[GetWordNum(nVariableMultiplier)] |= lBitMask;
lBitMask = (lBitMask << nRotateBits) | (lBitMask >> (nWordBits - nRotateBits));
}
vMultipliers[nPrimeSeq * nSieveLayers + nLayerSeq] = nVariableMultiplier;
#else
for (; nVariableMultiplier < nMaxMultiplier; nVariableMultiplier += nPrime)
{
vfComposites[GetWordNum(nVariableMultiplier)] |= GetBitMask(nVariableMultiplier);
}
vMultipliers[nPrimeSeq * nSieveLayers + nLayerSeq] = nVariableMultiplier;
#endif
}
}
@ -933,42 +902,16 @@ void CSieveOfEratosthenes::AddMultiplier(unsigned int *vMultipliers, const unsig
// False - sieve already completed
bool CSieveOfEratosthenes::Weave()
{
// Faster GMP version
this->nChainLength = TargetGetLength(nBits);
this->nHalfChainLength = (nChainLength + 1) / 2;
const unsigned int nMultiplierBytes = nPrimes * nSieveLayers * sizeof(unsigned int);
unsigned int *vCunningham1Multipliers = (unsigned int *)malloc(nMultiplierBytes);
unsigned int *vCunningham2Multipliers = (unsigned int *)malloc(nMultiplierBytes);
// Keep all variables local for max performance
const unsigned int nChainLength = this->nChainLength;
const unsigned int nHalfChainLength = this->nHalfChainLength;
CBlockIndex* pindexPrev = this->pindexPrev;
unsigned int nSieveSize = this->nSieveSize;
const unsigned int nTotalPrimes = vPrimes.size();
mpz_class mpzHash = this->mpzHash;
mpz_class mpzFixedMultiplier = this->mpzFixedMultiplier;
// Process only a set percentage of the primes
// Most composites are still found
const unsigned int nPrimes = (uint64)nTotalPrimes * nSievePercentage / 100;
this->nPrimes = nPrimes;
const unsigned int nMultiplierBytes = nPrimes * nHalfChainLength * sizeof(unsigned int);
unsigned int *vCunningham1AMultipliers = (unsigned int *)malloc(nMultiplierBytes);
unsigned int *vCunningham1BMultipliers = (unsigned int *)malloc(nMultiplierBytes);
unsigned int *vCunningham2AMultipliers = (unsigned int *)malloc(nMultiplierBytes);
unsigned int *vCunningham2BMultipliers = (unsigned int *)malloc(nMultiplierBytes);
memset(vCunningham1AMultipliers, 0xFF, nMultiplierBytes);
memset(vCunningham1BMultipliers, 0xFF, nMultiplierBytes);
memset(vCunningham2AMultipliers, 0xFF, nMultiplierBytes);
memset(vCunningham2BMultipliers, 0xFF, nMultiplierBytes);
memset(vCunningham1Multipliers, 0xFF, nMultiplierBytes);
memset(vCunningham2Multipliers, 0xFF, nMultiplierBytes);
// bitsets that can be combined to obtain the final bitset of candidates
sieve_word_t *vfCompositeCunningham1A = (sieve_word_t *)malloc(nCandidatesBytes);
sieve_word_t *vfCompositeCunningham1B = (sieve_word_t *)malloc(nCandidatesBytes);
sieve_word_t *vfCompositeCunningham2A = (sieve_word_t *)malloc(nCandidatesBytes);
sieve_word_t *vfCompositeCunningham2B = (sieve_word_t *)malloc(nCandidatesBytes);
sieve_word_t *vfCandidates = this->vfCandidates;
sieve_word_t *vfCompositeLayerCC1 = (sieve_word_t *)malloc(nCandidatesBytes);
sieve_word_t *vfCompositeLayerCC2 = (sieve_word_t *)malloc(nCandidatesBytes);
// Check whether fixed multiplier fits in an unsigned long
bool fUseLongForFixedMultiplier = mpzFixedMultiplier < ULONG_MAX;
@ -982,12 +925,12 @@ bool CSieveOfEratosthenes::Weave()
unsigned int nCombinedEndSeq = 1;
unsigned int nFixedFactorCombinedMod = 0;
for (unsigned int nPrimeSeq = 1; nPrimeSeq < nPrimes; nPrimeSeq++)
for (unsigned int nPrimeSeqLocal = 1; nPrimeSeqLocal < nPrimes; nPrimeSeqLocal++)
{
if (pindexPrev != pindexBest)
break; // new block
unsigned int nPrime = vPrimes[nPrimeSeq];
if (nPrimeSeq >= nCombinedEndSeq)
unsigned int nPrime = vPrimes[nPrimeSeqLocal];
if (nPrimeSeqLocal >= nCombinedEndSeq)
{
// Combine multiple primes to produce a big divisor
unsigned int nPrimeCombined = 1;
@ -1015,7 +958,7 @@ bool CSieveOfEratosthenes::Weave()
// Find the modulo inverse of fixed factor
unsigned int nFixedInverse = int_invert(nFixedFactorMod, nPrime);
if (!nFixedInverse)
return error("CSieveOfEratosthenes::Weave(): int_invert of fixed factor failed for prime #%u=%u", nPrimeSeq, vPrimes[nPrimeSeq]);
return error("CSieveOfEratosthenes::Weave(): int_invert of fixed factor failed for prime #%u=%u", nPrimeSeqLocal, vPrimes[nPrimeSeqLocal]);
unsigned int nTwoInverse = (nPrime + 1) / 2;
// Check whether 32-bit arithmetic can be used for nFixedInverse
@ -1024,145 +967,165 @@ bool CSieveOfEratosthenes::Weave()
if (fUse32BArithmetic)
{
// Weave the sieve for the prime
unsigned int nBiTwinSeq;
for (nBiTwinSeq = 0; nBiTwinSeq < nChainLength; nBiTwinSeq++)
for (unsigned int nChainSeq = 0; nChainSeq < nSieveLayers; nChainSeq++)
{
if (nBiTwinSeq % 2 == 0)
{
// Find the first number that's divisible by this prime
unsigned int nSolvedMultiplier = nFixedInverse;
AddMultiplier(vCunningham1AMultipliers, nPrimeSeq, nSolvedMultiplier);
}
else
{
// Find the first number that's divisible by this prime
unsigned int nSolvedMultiplier = nPrime - nFixedInverse;
AddMultiplier(vCunningham2AMultipliers, nPrimeSeq, nSolvedMultiplier);
// Find the first number that's divisible by this prime
vCunningham1Multipliers[nPrimeSeqLocal * nSieveLayers + nChainSeq] = nFixedInverse;
vCunningham2Multipliers[nPrimeSeqLocal * nSieveLayers + nChainSeq] = nPrime - nFixedInverse;
// For next number in chain
nFixedInverse = nFixedInverse * nTwoInverse % nPrime;
}
}
for (; nBiTwinSeq < 2 * nChainLength; nBiTwinSeq++)
{
if (nBiTwinSeq % 2 == 0)
{
// Find the first number that's divisible by this prime
unsigned int nSolvedMultiplier = nFixedInverse;
AddMultiplier(vCunningham1BMultipliers, nPrimeSeq, nSolvedMultiplier);
}
else
{
// Find the first number that's divisible by this prime
unsigned int nSolvedMultiplier = nPrime - nFixedInverse;
AddMultiplier(vCunningham2BMultipliers, nPrimeSeq, nSolvedMultiplier);
// For next number in chain
nFixedInverse = nFixedInverse * nTwoInverse % nPrime;
}
// For next number in chain
nFixedInverse = nFixedInverse * nTwoInverse % nPrime;
}
}
else
{
// Weave the sieve for the prime
unsigned int nBiTwinSeq;
for (nBiTwinSeq = 0; nBiTwinSeq < nChainLength; nBiTwinSeq++)
for (unsigned int nChainSeq = 0; nChainSeq < nSieveLayers; nChainSeq++)
{
if (nBiTwinSeq % 2 == 0)
{
// Find the first number that's divisible by this prime
unsigned int nSolvedMultiplier = nFixedInverse;
AddMultiplier(vCunningham1AMultipliers, nPrimeSeq, nSolvedMultiplier);
}
else
{
// Find the first number that's divisible by this prime
unsigned int nSolvedMultiplier = nPrime - nFixedInverse;
AddMultiplier(vCunningham2AMultipliers, nPrimeSeq, nSolvedMultiplier);
// Find the first number that's divisible by this prime
vCunningham1Multipliers[nPrimeSeqLocal * nSieveLayers + nChainSeq] = nFixedInverse;
vCunningham2Multipliers[nPrimeSeqLocal * nSieveLayers + nChainSeq] = nPrime - nFixedInverse;
// For next number in chain
nFixedInverse = (uint64)nFixedInverse * nTwoInverse % nPrime;
}
}
for (; nBiTwinSeq < 2 * nChainLength; nBiTwinSeq++)
{
if (nBiTwinSeq % 2 == 0)
{
// Find the first number that's divisible by this prime
unsigned int nSolvedMultiplier = nFixedInverse;
AddMultiplier(vCunningham1BMultipliers, nPrimeSeq, nSolvedMultiplier);
}
else
{
// Find the first number that's divisible by this prime
unsigned int nSolvedMultiplier = nPrime - nFixedInverse;
AddMultiplier(vCunningham2BMultipliers, nPrimeSeq, nSolvedMultiplier);
// For next number in chain
nFixedInverse = (uint64)nFixedInverse * nTwoInverse % nPrime;
}
// For next number in chain
nFixedInverse = (uint64)nFixedInverse * nTwoInverse % nPrime;
}
}
}
// Number of elements that are likely to fit in L1 cache
const unsigned int nL1CacheElements = 200000;
// NOTE: This needs to be a multiple of nWordBits
const unsigned int nL1CacheElements = 224000;
const unsigned int nArrayRounds = (nSieveSize + nL1CacheElements - 1) / nL1CacheElements;
// Calculate the number of CC1 and CC2 layers needed for BiTwin candidates
const unsigned int nBiTwinCC1Layers = (nChainLength + 1) / 2;
const unsigned int nBiTwinCC2Layers = nChainLength / 2;
// Only 50% of the array is used in extensions
const unsigned int nExtensionsMinMultiplier = nSieveSize / 2;
const unsigned int nExtensionsMinWord = nExtensionsMinMultiplier / nWordBits;
// Loop over each array one at a time for optimal L1 cache performance
for (unsigned int j = 0; j < nArrayRounds; j++)
{
const unsigned int nMinMultiplier = nL1CacheElements * j;
const unsigned int nMaxMultiplier = std::min(nL1CacheElements * (j + 1), nSieveSize);
const unsigned int nExtMinMultiplier = std::max(nMinMultiplier, nExtensionsMinMultiplier);
const unsigned int nMinWord = nMinMultiplier / nWordBits;
const unsigned int nMaxWord = (nMaxMultiplier + nWordBits - 1) / nWordBits;
const unsigned int nExtMinWord = std::max(nMinWord, nExtensionsMinWord);
if (pindexPrev != pindexBest)
break; // new block
ProcessMultiplier(vfCompositeCunningham1A, nMinMultiplier, nMaxMultiplier, vPrimes, vCunningham1AMultipliers);
ProcessMultiplier(vfCompositeCunningham1B, nMinMultiplier, nMaxMultiplier, vPrimes, vCunningham1BMultipliers);
ProcessMultiplier(vfCompositeCunningham2A, nMinMultiplier, nMaxMultiplier, vPrimes, vCunningham2AMultipliers);
ProcessMultiplier(vfCompositeCunningham2B, nMinMultiplier, nMaxMultiplier, vPrimes, vCunningham2BMultipliers);
// Combine all the bitsets
// vfCompositeCunningham1 = vfCompositeCunningham1A | vfCompositeCunningham1B
// vfCompositeCunningham2 = vfCompositeCunningham2A | vfCompositeCunningham2B
// vfCompositeBiTwin = vfCompositeCunningham1A | vfCompositeCunningham2A
// vfCandidates = ~(vfCompositeCunningham1 & vfCompositeCunningham2 & vfCompositeBiTwin)
{
// Fast version
const unsigned int nBytes = (nMaxMultiplier - nMinMultiplier + 7) / 8;
sieve_word_t *pCandidates = (sieve_word_t *)vfCandidates + (nMinMultiplier / nWordBits);
sieve_word_t *pCandidateBiTwin = (sieve_word_t *)vfCandidateBiTwin + (nMinMultiplier / nWordBits);
sieve_word_t *pCandidateCunningham1 = (sieve_word_t *)vfCandidateCunningham1 + (nMinMultiplier / nWordBits);
sieve_word_t *pCompositeCunningham1A = (sieve_word_t *)vfCompositeCunningham1A + (nMinMultiplier / nWordBits);
sieve_word_t *pCompositeCunningham1B = (sieve_word_t *)vfCompositeCunningham1B + (nMinMultiplier / nWordBits);
sieve_word_t *pCompositeCunningham2A = (sieve_word_t *)vfCompositeCunningham2A + (nMinMultiplier / nWordBits);
sieve_word_t *pCompositeCunningham2B = (sieve_word_t *)vfCompositeCunningham2B + (nMinMultiplier / nWordBits);
const unsigned int nWords = (nBytes + sizeof(sieve_word_t) - 1) / sizeof(sieve_word_t);
for (unsigned int i = 0; i < nWords; i++)
// Loop over the layers
for (unsigned int nLayerSeq = 0; nLayerSeq < nSieveLayers; nLayerSeq++) {
if (pindexPrev != pindexBest)
break; // new block
if (nLayerSeq < nChainLength)
{
const sieve_word_t lCompositeCunningham1 = pCompositeCunningham1A[i] | pCompositeCunningham1B[i];
const sieve_word_t lCompositeCunningham2 = pCompositeCunningham2A[i] | pCompositeCunningham2B[i];
const sieve_word_t lCompositeBiTwin = pCompositeCunningham1A[i] | pCompositeCunningham2A[i];
pCandidateBiTwin[i] = ~lCompositeBiTwin;
pCandidateCunningham1[i] = ~lCompositeCunningham1;
pCandidates[i] = ~(lCompositeCunningham1 & lCompositeCunningham2 & lCompositeBiTwin);
ProcessMultiplier(vfCompositeLayerCC1, nMinMultiplier, nMaxMultiplier, vPrimes, vCunningham1Multipliers, nLayerSeq);
ProcessMultiplier(vfCompositeLayerCC2, nMinMultiplier, nMaxMultiplier, vPrimes, vCunningham2Multipliers, nLayerSeq);
}
else
{
// Optimize: First halves of the arrays are not needed in the extensions
ProcessMultiplier(vfCompositeLayerCC1, nExtMinMultiplier, nMaxMultiplier, vPrimes, vCunningham1Multipliers, nLayerSeq);
ProcessMultiplier(vfCompositeLayerCC2, nExtMinMultiplier, nMaxMultiplier, vPrimes, vCunningham2Multipliers, nLayerSeq);
}
// Apply the layer to the primary sieve arrays
if (nLayerSeq < nChainLength)
{
if (nLayerSeq < nBiTwinCC1Layers && nLayerSeq < nBiTwinCC2Layers)
{
for (unsigned int nWord = nMinWord; nWord < nMaxWord; nWord++)
{
vfCompositeCunningham1[nWord] |= vfCompositeLayerCC1[nWord];
vfCompositeCunningham2[nWord] |= vfCompositeLayerCC2[nWord];
vfCompositeBiTwin[nWord] |= vfCompositeLayerCC1[nWord] | vfCompositeLayerCC2[nWord];
}
}
else if (nLayerSeq < nBiTwinCC2Layers)
{
for (unsigned int nWord = nMinWord; nWord < nMaxWord; nWord++)
{
vfCompositeCunningham1[nWord] |= vfCompositeLayerCC1[nWord];
vfCompositeCunningham2[nWord] |= vfCompositeLayerCC2[nWord];
vfCompositeBiTwin[nWord] |= vfCompositeLayerCC1[nWord];
}
}
else
{
for (unsigned int nWord = nMinWord; nWord < nMaxWord; nWord++)
{
vfCompositeCunningham1[nWord] |= vfCompositeLayerCC1[nWord];
vfCompositeCunningham2[nWord] |= vfCompositeLayerCC2[nWord];
}
}
}
// Apply the layer to extensions
for (unsigned int nExtensionSeq = 0; nExtensionSeq < nSieveExtensions; nExtensionSeq++)
{
const unsigned int nLayerOffset = nExtensionSeq + 1;
if (nLayerSeq >= nLayerOffset && nLayerSeq < nChainLength + nLayerOffset)
{
const unsigned int nLayerExtendedSeq = nLayerSeq - nLayerOffset;
sieve_word_t *vfExtCC1 = vfExtendedCompositeCunningham1 + nExtensionSeq * nCandidatesWords;
sieve_word_t *vfExtCC2 = vfExtendedCompositeCunningham2 + nExtensionSeq * nCandidatesWords;
sieve_word_t *vfExtTWN = vfExtendedCompositeBiTwin + nExtensionSeq * nCandidatesWords;
if (nLayerExtendedSeq < nBiTwinCC1Layers && nLayerExtendedSeq < nBiTwinCC2Layers)
{
for (unsigned int nWord = nExtMinWord; nWord < nMaxWord; nWord++)
{
vfExtCC1[nWord] |= vfCompositeLayerCC1[nWord];
vfExtCC2[nWord] |= vfCompositeLayerCC2[nWord];
vfExtTWN[nWord] |= vfCompositeLayerCC1[nWord] | vfCompositeLayerCC2[nWord];
}
}
else if (nLayerExtendedSeq < nBiTwinCC2Layers)
{
for (unsigned int nWord = nExtMinWord; nWord < nMaxWord; nWord++)
{
vfExtCC1[nWord] |= vfCompositeLayerCC1[nWord];
vfExtCC2[nWord] |= vfCompositeLayerCC2[nWord];
vfExtTWN[nWord] |= vfCompositeLayerCC1[nWord];
}
}
else
{
for (unsigned int nWord = nExtMinWord; nWord < nMaxWord; nWord++)
{
vfExtCC1[nWord] |= vfCompositeLayerCC1[nWord];
vfExtCC2[nWord] |= vfCompositeLayerCC2[nWord];
}
}
}
}
}
// Combine the bitsets
// vfCandidates = ~(vfCompositeCunningham1 & vfCompositeCunningham2 & vfCompositeBiTwin)
for (unsigned int i = nMinWord; i < nMaxWord; i++)
vfCandidates[i] = ~(vfCompositeCunningham1[i] & vfCompositeCunningham2[i] & vfCompositeBiTwin[i]);
// Combine the extended bitsets
for (unsigned int j = 0; j < nSieveExtensions; j++)
for (unsigned int i = nExtMinWord; i < nMaxWord; i++)
vfExtendedCandidates[j * nCandidatesWords + i] = ~(
vfExtendedCompositeCunningham1[j * nCandidatesWords + i] &
vfExtendedCompositeCunningham2[j * nCandidatesWords + i] &
vfExtendedCompositeBiTwin[j * nCandidatesWords + i]);
}
// The sieve has been partially weaved
this->nPrimeSeq = nPrimes - 1;
free(vfCompositeCunningham1A);
free(vfCompositeCunningham1B);
free(vfCompositeCunningham2A);
free(vfCompositeCunningham2B);
free(vCunningham1AMultipliers);
free(vCunningham1BMultipliers);
free(vCunningham2AMultipliers);
free(vCunningham2BMultipliers);
free(vfCompositeLayerCC1);
free(vfCompositeLayerCC2);
free(vCunningham1Multipliers);
free(vCunningham2Multipliers);
return false;
}
@ -1195,5 +1158,15 @@ double EstimateCandidatePrimeProbability(unsigned int nPrimorialMultiplier, unsi
dFixedMultiplier *= vPrimes[i];
for (unsigned int i = 0; vPrimes[i] <= nPrimorialHashFactor; i++)
dFixedMultiplier /= vPrimes[i];
return (1.781072 * log((double)std::max(1u, nSieveWeaveOptimalPrime)) / (255.0 * dLogTwo + dLogOneAndHalf + log(dFixedMultiplier) + log(nAverageCandidateMultiplier) + dLogTwo * nChainPrimeNum));
double dExtendedSieveWeightedSum = nSieveSize * 1.0;
double dExtendedSieveCandidates = nSieveSize;
for (unsigned int i = 0; i < nSieveExtensions; i++)
{
dExtendedSieveWeightedSum += nSieveSize / 2 * (2 << i);
dExtendedSieveCandidates += nSieveSize / 2;
}
const double dExtendedSieveAverageMultiplier = dExtendedSieveWeightedSum / dExtendedSieveCandidates;
return (1.781072 * log((double)std::max(1u, nSieveWeaveOptimalPrime)) / (255.0 * dLogTwo + dLogOneAndHalf + log(dFixedMultiplier) + log(nAverageCandidateMultiplier) + dLogTwo * nChainPrimeNum + log(dExtendedSieveAverageMultiplier)));
}

View File

@ -29,11 +29,12 @@ public:
/* PRIMECOIN PROTOCOL */
/**********************/
static const unsigned int nMaxRoundSievePercentage = 100;
static const unsigned int nDefaultRoundSievePercentage = 70;
static const unsigned int nDefaultRoundSievePercentageTestnet = 30;
static const unsigned int nMinRoundSievePercentage = 1;
extern unsigned int nRoundSievePercentage;
extern std::vector<unsigned int> vPrimes;
static const unsigned int nMaxSieveExtensions = 20;
static const unsigned int nMinSieveExtensions = 0;
static const unsigned int nDefaultSieveExtensions = 6;
static const unsigned int nDefaultSieveExtensionsTestnet = 4;
extern unsigned int nSieveExtensions;
static const unsigned int nMaxSievePercentage = 100;
static const unsigned int nDefaultSievePercentage = 10;
static const unsigned int nMinSievePercentage = 1;
@ -136,18 +137,43 @@ double EstimateCandidatePrimeProbability(unsigned int nPrimorialMultiplier, unsi
typedef unsigned long sieve_word_t;
// Sieve of Eratosthenes for proof-of-work mining
//
// Includes the sieve extension feature from jhPrimeminer by jh000
//
// A layer of the sieve determines whether the CC1 or CC2 chain members near the
// origin fixed_multiplier * candidate_multiplier * 2^k are known to be
// composites.
//
// The default sieve is composed of layers 1 .. nChainLength.
//
// An extension i is composed of layers i .. i + nChainLength. The candidates
// indexes from the extensions are multiplied by 2^i. The first half of the
// candidates are covered by the default sieve and previous extensions.
//
// The larger numbers in the extensions have a slightly smaller probability of
// being primes and take slightly longer to test but they can be calculated very
// efficiently because the layers overlap.
class CSieveOfEratosthenes
{
unsigned int nSieveSize; // size of the sieve
unsigned int nSievePercentage; // weave up to a percentage of primes
unsigned int nSieveExtensions; // extend the sieve a given number of times
unsigned int nBits; // target of the prime chain to search for
mpz_class mpzHash; // hash of the block header
mpz_class mpzFixedMultiplier; // fixed round multiplier
// final set of candidates for probable primality checking
sieve_word_t *vfCandidates;
sieve_word_t *vfCandidateBiTwin;
sieve_word_t *vfCandidateCunningham1;
sieve_word_t *vfCompositeBiTwin;
sieve_word_t *vfCompositeCunningham1;
sieve_word_t *vfCompositeCunningham2;
// extended sets
sieve_word_t *vfExtendedCandidates;
sieve_word_t *vfExtendedCompositeBiTwin;
sieve_word_t *vfExtendedCompositeCunningham1;
sieve_word_t *vfExtendedCompositeCunningham2;
static const unsigned int nWordBits = 8 * sizeof(sieve_word_t);
unsigned int nCandidatesWords;
unsigned int nCandidatesBytes;
@ -155,64 +181,32 @@ class CSieveOfEratosthenes
unsigned int nPrimeSeq; // prime sequence number currently being processed
unsigned int nCandidateCount; // cached total count of candidates
unsigned int nCandidateMultiplier; // current candidate for power test
unsigned int nChainLength;
unsigned int nHalfChainLength;
unsigned int nPrimes;
unsigned int nCandidateIndex; // internal candidate index
bool fCandidateIsExtended; // is the current candidate in the extended part
unsigned int nCandidateActiveExtension; // which extension is active
unsigned int nChainLength; // target chain length
unsigned int nSieveLayers; // sieve layers
unsigned int nPrimes; // number of times to weave the sieve
CBlockIndex* pindexPrev;
unsigned int GetWordNum(unsigned int nBitNum) {
return nBitNum / nWordBits;
}
sieve_word_t GetBitMask(unsigned int nBitNum) {
return (sieve_word_t)1 << (nBitNum % nWordBits);
}
void AddMultiplier(unsigned int *vMultipliers, const unsigned int nPrimeSeq, const unsigned int nSolvedMultiplier);
void ProcessMultiplier(sieve_word_t *vfComposites, const unsigned int nMinMultiplier, const unsigned int nMaxMultiplier, const std::vector<unsigned int>& vPrimes, unsigned int *vMultipliers)
{
// Wipe the part of the array first
memset(vfComposites + GetWordNum(nMinMultiplier), 0, (nMaxMultiplier - nMinMultiplier + nWordBits - 1) / nWordBits * sizeof(sieve_word_t));
for (unsigned int nPrimeSeq = 1; nPrimeSeq < nPrimes; nPrimeSeq++)
{
const unsigned int nPrime = vPrimes[nPrimeSeq];
#ifdef USE_ROTATE
const unsigned int nRotateBits = nPrime % nWordBits;
for (unsigned int i = 0; i < nHalfChainLength; i++)
{
unsigned int nVariableMultiplier = vMultipliers[nPrimeSeq * nHalfChainLength + i];
if (nVariableMultiplier == 0xFFFFFFFF) break;
sieve_word_t lBitMask = GetBitMask(nVariableMultiplier);
for (; nVariableMultiplier < nMaxMultiplier; nVariableMultiplier += nPrime)
{
vfComposites[GetWordNum(nVariableMultiplier)] |= lBitMask;
lBitMask = (lBitMask << nRotateBits) | (lBitMask >> (nWordBits - nRotateBits));
}
vMultipliers[nPrimeSeq * nHalfChainLength + i] = nVariableMultiplier;
}
#else
for (unsigned int i = 0; i < nHalfChainLength; i++)
{
unsigned int nVariableMultiplier = vMultipliers[nPrimeSeq * nHalfChainLength + i];
if (nVariableMultiplier == 0xFFFFFFFF) break;
for (; nVariableMultiplier < nMaxMultiplier; nVariableMultiplier += nPrime)
{
vfComposites[GetWordNum(nVariableMultiplier)] |= GetBitMask(nVariableMultiplier);
}
vMultipliers[nPrimeSeq * nHalfChainLength + i] = nVariableMultiplier;
}
#endif
}
}
void ProcessMultiplier(sieve_word_t *vfComposites, const unsigned int nMinMultiplier, const unsigned int nMaxMultiplier, const std::vector<unsigned int>& vPrimes, unsigned int *vMultipliers, unsigned int nLayerSeq);
public:
CSieveOfEratosthenes(unsigned int nSieveSize, unsigned int nBits, mpz_class& mpzHash, mpz_class& mpzFixedMultiplier, CBlockIndex* pindexPrev)
CSieveOfEratosthenes(unsigned int nSieveSize, unsigned int nSievePercentage, unsigned int nSieveExtensions, unsigned int nBits, mpz_class& mpzHash, mpz_class& mpzFixedMultiplier, CBlockIndex* pindexPrev)
{
this->nSieveSize = nSieveSize;
this->nSievePercentage = nSievePercentage;
this->nSieveExtensions = nSieveExtensions;
this->nBits = nBits;
this->mpzHash = mpzHash;
this->mpzFixedMultiplier = mpzFixedMultiplier;
@ -220,21 +214,46 @@ public:
nPrimeSeq = 0;
nCandidateCount = 0;
nCandidateMultiplier = 0;
nCandidateIndex = 0;
fCandidateIsExtended = false;
nCandidateActiveExtension = 0;
nCandidatesWords = (nSieveSize + nWordBits - 1) / nWordBits;
nCandidatesBytes = nCandidatesWords * sizeof(sieve_word_t);
vfCandidates = (sieve_word_t *)malloc(nCandidatesBytes);
vfCandidateBiTwin = (sieve_word_t *)malloc(nCandidatesBytes);
vfCandidateCunningham1 = (sieve_word_t *)malloc(nCandidatesBytes);
vfCompositeBiTwin = (sieve_word_t *)malloc(nCandidatesBytes);
vfCompositeCunningham1 = (sieve_word_t *)malloc(nCandidatesBytes);
vfCompositeCunningham2 = (sieve_word_t *)malloc(nCandidatesBytes);
memset(vfCandidates, 0, nCandidatesBytes);
memset(vfCandidateBiTwin, 0, nCandidatesBytes);
memset(vfCandidateCunningham1, 0, nCandidatesBytes);
memset(vfCompositeBiTwin, 0, nCandidatesBytes);
memset(vfCompositeCunningham1, 0, nCandidatesBytes);
memset(vfCompositeCunningham2, 0, nCandidatesBytes);
vfExtendedCandidates = (sieve_word_t *)malloc(nSieveExtensions * nCandidatesBytes);
vfExtendedCompositeBiTwin = (sieve_word_t *)malloc(nSieveExtensions * nCandidatesBytes);
vfExtendedCompositeCunningham1 = (sieve_word_t *)malloc(nSieveExtensions * nCandidatesBytes);
vfExtendedCompositeCunningham2 = (sieve_word_t *)malloc(nSieveExtensions * nCandidatesBytes);
memset(vfExtendedCandidates, 0, nSieveExtensions * nCandidatesBytes);
memset(vfExtendedCompositeBiTwin, 0, nSieveExtensions * nCandidatesBytes);
memset(vfExtendedCompositeCunningham1, 0, nSieveExtensions * nCandidatesBytes);
memset(vfExtendedCompositeCunningham2, 0, nSieveExtensions * nCandidatesBytes);
nChainLength = TargetGetLength(nBits);
nSieveLayers = nChainLength + nSieveExtensions;
// Process only a set percentage of the primes
// Most composites are still found
const unsigned int nTotalPrimes = vPrimes.size();
nPrimes = (uint64)nTotalPrimes * nSievePercentage / 100;
}
~CSieveOfEratosthenes()
{
free(vfCandidates);
free(vfCandidateBiTwin);
free(vfCandidateCunningham1);
free(vfCompositeBiTwin);
free(vfCompositeCunningham1);
free(vfCompositeCunningham2);
free(vfExtendedCandidates);
free(vfExtendedCompositeBiTwin);
free(vfExtendedCompositeCunningham1);
free(vfExtendedCompositeCunningham2);
}
// Get total number of candidates for power test
@ -246,9 +265,10 @@ public:
unsigned int nCandidates = 0;
#ifdef __GNUC__
for (unsigned int i = 0; i < nCandidatesWords; i++)
{
nCandidates += __builtin_popcountl(vfCandidates[i]);
}
for (unsigned int j = 0; j < nSieveExtensions; j++)
for (unsigned int i = nCandidatesWords / 2; i < nCandidatesWords; i++)
nCandidates += __builtin_popcountl(vfExtendedCandidates[j * nCandidatesWords + i]);
#else
for (unsigned int i = 0; i < nCandidatesWords; i++)
{
@ -259,6 +279,18 @@ public:
lBits >>= 1;
}
}
for (unsigned int j = 0; j < nSieveExtensions; j++)
{
for (unsigned int i = nCandidatesWords / 2; i < nCandidatesWords; i++)
{
sieve_word_t lBits = vfExtendedCandidates[j * nCandidatesWords + i];
for (unsigned int j = 0; j < nWordBits; j++)
{
nCandidates += (lBits & 1);
lBits >>= 1;
}
}
}
#endif
nCandidateCount = nCandidates;
return nCandidates;
@ -270,31 +302,92 @@ public:
// False - scan complete, no more candidate and reset scan
bool GetNextCandidateMultiplier(unsigned int& nVariableMultiplier, unsigned int& nCandidateType)
{
sieve_word_t lBits = vfCandidates[GetWordNum(nCandidateMultiplier)];
sieve_word_t *vfActiveCandidates;
sieve_word_t *vfActiveCompositeTWN;
sieve_word_t *vfActiveCompositeCC1;
if (fCandidateIsExtended)
{
vfActiveCandidates = vfExtendedCandidates + nCandidateActiveExtension * nCandidatesWords;
vfActiveCompositeTWN = vfExtendedCompositeBiTwin + nCandidateActiveExtension * nCandidatesWords;
vfActiveCompositeCC1 = vfExtendedCompositeCunningham1 + nCandidateActiveExtension * nCandidatesWords;
}
else
{
vfActiveCandidates = vfCandidates;
vfActiveCompositeTWN = vfCompositeBiTwin;
vfActiveCompositeCC1 = vfCompositeCunningham1;
}
// Acquire the current word from the bitmap
sieve_word_t lBits = vfActiveCandidates[GetWordNum(nCandidateIndex)];
loop
{
nCandidateMultiplier++;
if (nCandidateMultiplier >= nSieveSize)
nCandidateIndex++;
if (nCandidateIndex >= nSieveSize)
{
nCandidateMultiplier = 0;
return false;
// Check if extensions are available
if (!fCandidateIsExtended && nSieveExtensions > 0)
{
fCandidateIsExtended = true;
nCandidateActiveExtension = 0;
nCandidateIndex = nSieveSize / 2;
}
else if (fCandidateIsExtended && nCandidateActiveExtension + 1 < nSieveExtensions)
{
nCandidateActiveExtension++;
nCandidateIndex = nSieveSize / 2;
}
else
{
// Out of candidates
fCandidateIsExtended = false;
nCandidateActiveExtension = 0;
nCandidateIndex = 0;
nCandidateMultiplier = 0;
return false;
}
// Fix the pointers
if (fCandidateIsExtended)
{
vfActiveCandidates = vfExtendedCandidates + nCandidateActiveExtension * nCandidatesWords;
vfActiveCompositeTWN = vfExtendedCompositeBiTwin + nCandidateActiveExtension * nCandidatesWords;
vfActiveCompositeCC1 = vfExtendedCompositeCunningham1 + nCandidateActiveExtension * nCandidatesWords;
}
else
{
vfActiveCandidates = vfCandidates;
vfActiveCompositeTWN = vfCompositeBiTwin;
vfActiveCompositeCC1 = vfCompositeCunningham1;
}
}
if (nCandidateMultiplier % nWordBits == 0)
if (nCandidateIndex % nWordBits == 0)
{
lBits = vfCandidates[GetWordNum(nCandidateMultiplier)];
// Update the current word
lBits = vfActiveCandidates[GetWordNum(nCandidateIndex)];
// Check if any bits are set
if (lBits == 0)
{
// Skip an entire word
nCandidateMultiplier += nWordBits - 1;
nCandidateIndex += nWordBits - 1;
continue;
}
}
if (lBits & GetBitMask(nCandidateMultiplier))
if (lBits & GetBitMask(nCandidateIndex))
{
if (fCandidateIsExtended)
nCandidateMultiplier = nCandidateIndex * (2 << nCandidateActiveExtension);
else
nCandidateMultiplier = nCandidateIndex;
nVariableMultiplier = nCandidateMultiplier;
if (vfCandidateBiTwin[GetWordNum(nCandidateMultiplier)] & GetBitMask(nCandidateMultiplier))
if (~vfActiveCompositeTWN[GetWordNum(nCandidateIndex)] & GetBitMask(nCandidateIndex))
nCandidateType = PRIME_CHAIN_BI_TWIN;
else if (vfCandidateCunningham1[GetWordNum(nCandidateMultiplier)] & GetBitMask(nCandidateMultiplier))
else if (~vfActiveCompositeCC1[GetWordNum(nCandidateIndex)] & GetBitMask(nCandidateIndex))
nCandidateType = PRIME_CHAIN_CUNNINGHAM1;
else
nCandidateType = PRIME_CHAIN_CUNNINGHAM2;

View File

@ -275,3 +275,90 @@ Value listprimerecords(const Array& params, bool fHelp)
return ret;
}
// Primecoin: list top prime chain within primecoin network
Value listtopprimes(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"listtopprimes <primechain length> [primechain type]\n"
"Returns the list of top prime chains in primecoin network.\n"
"<primechain length> is integer like 10, 11, 12 etc.\n"
"[primechain type] is optional type, among 1CC, 2CC and TWN");
int nPrimeChainLength = params[0].get_int();
unsigned int nPrimeChainType = 0;
if (params.size() > 1)
{
std::string strPrimeChainType = params[1].get_str();
if (strPrimeChainType.compare("1CC") == 0)
nPrimeChainType = PRIME_CHAIN_CUNNINGHAM1;
else if (strPrimeChainType.compare("2CC") == 0)
nPrimeChainType = PRIME_CHAIN_CUNNINGHAM2;
else if (strPrimeChainType.compare("TWN") == 0)
nPrimeChainType = PRIME_CHAIN_BI_TWIN;
else
throw runtime_error("Prime chain type must be 1CC, 2CC or TWN.");
}
// Search for top prime chains
unsigned int nRankingSize = 10; // ranking list size
unsigned int nSortVectorSize = 64; // vector size for sort operation
CBigNum bnPrimeQualify = 0; // minimum qualify value for ranking list
vector<pair<CBigNum, uint256> > vSortedByOrigin;
for (CBlockIndex* pindex = pindexGenesisBlock; pindex; pindex = pindex->pnext)
{
if (nPrimeChainLength != (int) TargetGetLength(pindex->nPrimeChainLength))
continue; // length not matching, next block
if (nPrimeChainType && nPrimeChainType != pindex->nPrimeChainType)
continue; // type not matching, next block
CBlock block;
block.ReadFromDisk(pindex); // read block
CBigNum bnPrimeChainOrigin = CBigNum(block.GetHeaderHash()) * block.bnPrimeChainMultiplier; // compute prime chain origin
if (bnPrimeChainOrigin > bnPrimeQualify)
vSortedByOrigin.push_back(make_pair(bnPrimeChainOrigin, block.GetHash()));
if (vSortedByOrigin.size() >= nSortVectorSize)
{
// Sort prime chain candidates
sort(vSortedByOrigin.begin(), vSortedByOrigin.end());
reverse(vSortedByOrigin.begin(), vSortedByOrigin.end());
// Truncate candidate list
while (vSortedByOrigin.size() > nRankingSize)
vSortedByOrigin.pop_back();
// Update minimum qualify value for top prime chains
bnPrimeQualify = vSortedByOrigin.back().first;
}
}
// Final sort of prime chain candidates
sort(vSortedByOrigin.begin(), vSortedByOrigin.end());
reverse(vSortedByOrigin.begin(), vSortedByOrigin.end());
// Truncate candidate list
while (vSortedByOrigin.size() > nRankingSize)
vSortedByOrigin.pop_back();
// Output top prime chains
Array ret;
BOOST_FOREACH(const PAIRTYPE(CBigNum, uint256)& item, vSortedByOrigin)
{
CBigNum bnPrimeChainOrigin = item.first;
CBlockIndex* pindex = mapBlockIndex[item.second];
CBlock block;
block.ReadFromDisk(pindex); // read block
Object entry;
entry.push_back(Pair("time", DateTimeStrFormat("%Y-%m-%d %H:%M:%S UTC", pindex->GetBlockTime()).c_str()));
entry.push_back(Pair("epoch", (boost::int64_t) pindex->GetBlockTime()));
entry.push_back(Pair("height", pindex->nHeight));
entry.push_back(Pair("ismine", pwalletMain->IsMine(block.vtx[0])));
entry.push_back(Pair("primedigit", (int) bnPrimeChainOrigin.ToString().length()));
entry.push_back(Pair("primechain", GetPrimeChainName(pindex->nPrimeChainType, pindex->nPrimeChainLength).c_str()));
entry.push_back(Pair("primeorigin", bnPrimeChainOrigin.ToString().c_str()));
entry.push_back(Pair("primorialform", GetPrimeOriginPrimorialForm(bnPrimeChainOrigin).c_str()));
ret.push_back(entry);
}
return ret;
}

View File

@ -72,35 +72,38 @@ Value setsievepercentage(const Array& params, bool fHelp)
if (params.size() > 0)
nPercentage = params[0].get_int();
nPercentage = std::max(std::min(nPercentage, nMaxSievePercentage), nMinSievePercentage);
nSievePercentage = nPercentage;
return Value::null;
}
Value getroundsievepercentage(const Array& params, bool fHelp)
Value getsieveextensions(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getroundsievepercentage\n"
"Returns the current sieve generation time percentage used by the mining algorithm.");
"getsieveextensions\n"
"Returns the number of times the sieve is extended.");
return (boost::int64_t)nRoundSievePercentage;
return (boost::int64_t)nSieveExtensions;
}
Value setroundsievepercentage(const Array& params, bool fHelp)
Value setsieveextensions(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 1)
throw runtime_error(
"setroundsievepercentage <roundsievepercentage>\n"
"<roundsievepercentage> determines much time should be spent generating the sieve of candidate multipliers.\n"
"The round primorial is dynamically adjusted based on this value.");
"setsieveextensions <sieveextensions>\n"
"<sieveextensions> determines the number of times the sieve will be extended.");
unsigned int nPercentage = nDefaultRoundSievePercentage;
unsigned int nExtensions = (fTestNet) ? nDefaultSieveExtensionsTestnet : nDefaultSieveExtensions;
if (params.size() > 0)
nPercentage = params[0].get_int();
nExtensions = params[0].get_int();
nRoundSievePercentage = nPercentage;
nExtensions = std::max(std::min(nExtensions, nMaxSieveExtensions), nMinSieveExtensions);
nSieveExtensions = nExtensions;
return Value::null;
}
@ -147,9 +150,9 @@ Value getmininginfo(const Array& params, bool fHelp)
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("roundsievepercentage",(int)nRoundSievePercentage));
obj.push_back(Pair("primespersec", getprimespersec(params, false)));
obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
obj.push_back(Pair("sieveextensions",(int)nSieveExtensions));
obj.push_back(Pair("sievepercentage",(int)nSievePercentage));
obj.push_back(Pair("sievesize", (int)nSieveSize));
obj.push_back(Pair("testnet", fTestNet));

View File

@ -12,7 +12,7 @@
const std::string CLIENT_NAME("Satoshi");
// Client version number
#define CLIENT_VERSION_SUFFIX "-beta-hp9"
#define CLIENT_VERSION_SUFFIX "-beta-hp10"
// The following part of the code determines the CLIENT_BUILD variable.