Skip to content

Commit 1ea430c

Browse files
Use difficulty target cache with mutex
1 parent f0dec3e commit 1ea430c

File tree

1 file changed

+71
-85
lines changed

1 file changed

+71
-85
lines changed

src/pow.cpp

Lines changed: 71 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@
1010
#include <chain.h>
1111
//#include <logging.h>
1212
#include <primitives/block.h>
13+
#include <sync.h>
1314
#include <uint256.h>
1415

15-
#include <atomic>
16+
#include <mutex>
17+
18+
RecursiveMutex cs_target_cache;
1619

1720
// peercoin: find last block index up to pindex
1821
static inline const CBlockIndex* GetLastBlockIndex(const CBlockIndex* pindex, const bool fProofOfStake)
@@ -186,19 +189,6 @@ unsigned int WeightedTargetExponentialMovingAverage(const CBlockIndex* pindexLas
186189
return bnNew.GetCompactRounded();
187190
}
188191

189-
static inline void Arith256ToAtomic(const arith_uint256& arith, std::atomic<uint64_t>& first, std::atomic<uint64_t>& second, std::atomic<uint64_t>& third, std::atomic<uint64_t>& fourth)
190-
{
191-
first.store(arith.GetLow64());
192-
second.store((arith >> 64).GetLow64());
193-
third.store((arith >> 128).GetLow64());
194-
fourth.store((arith >> 192).GetLow64());
195-
}
196-
197-
static inline void AtomicToArith256(arith_uint256& arith, const std::atomic<uint64_t>& first, const std::atomic<uint64_t>& second, const std::atomic<uint64_t>& third, const std::atomic<uint64_t>& fourth)
198-
{
199-
arith = arith_uint256(first.load()) | (arith_uint256(second.load()) << 64) | (arith_uint256(third.load()) << 128) | (arith_uint256(fourth.load()) << 192);
200-
}
201-
202192
unsigned int AverageTargetASERT(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params)
203193
{
204194
const int algo = CBlockHeader::GetAlgo(pblock->nVersion);
@@ -244,69 +234,65 @@ unsigned int AverageTargetASERT(const CBlockIndex* pindexLast, const CBlockHeade
244234
arith_uint256 refBlockTarget;
245235

246236
// We don't want to recalculate the average of several days' worth of block targets here every single time, so instead we cache the average and start height
247-
const bool fUseCache = false;
248-
arith_uint256 refBlockTargetCache;
249-
// For lack of a better way to store an atomic uint256 at the moment
250-
static std::atomic<uint64_t> targetCacheOne{0};
251-
static std::atomic<uint64_t> targetCacheTwo{0};
252-
static std::atomic<uint64_t> targetCacheThree{0};
253-
static std::atomic<uint64_t> targetCacheFour{0};
254-
static std::atomic_int nTargetCacheHeight{-1};
255-
static std::atomic_int nTargetCacheAlgo{CBlockHeader::ALGO_COUNT};
256-
if (fUseCache)
257-
AtomicToArith256(refBlockTargetCache, targetCacheOne, targetCacheTwo, targetCacheThree, targetCacheFour);
258-
259-
if (nASERTBlockTargetsToAverage > 0 && nHeight >= nASERTStartHeight + nASERTBlockTargetsToAverage && nHeightDiff >= nASERTBlockTargetsToAverage) {
260-
if (!fUseCache || nTargetCacheHeight.load() != (int)(nHeightDiff / nASERTBlockTargetsToAverage) || nTargetCacheAlgo.load() != algo || refBlockTargetCache == arith_uint256() || algo == -1) {
261-
const uint32_t nBlocksToSkip = nHeightDiff % nASERTBlockTargetsToAverage;
262-
const CBlockIndex* pindex = pindexPrev;
263-
//LogPrintf("nBlocksToSkip = %u\n", nBlocksToSkip);
264-
265-
for (unsigned int i = 0; i < nBlocksToSkip; i++) {
266-
pindex = algo == -1 ? GetLastBlockIndex(pindex->pprev, fProofOfStake) : GetLastBlockIndexForAlgo(pindex->pprev, algo);
267-
}
268-
//LogPrintf("begin pindex->nHeight = %i\n", pindex->nHeight);
269-
270-
//unsigned int nBlocksAveraged = 0;
271-
for (int i = 0; i < (int)nASERTBlockTargetsToAverage; i++) {
272-
if (pindex->nBits != (nProofOfWorkLimit - 1) || !params.fPowAllowMinDifficultyBlocks) { // Don't add min difficulty targets to the average
273-
arith_uint256 bnTarget = arith_uint256().SetCompact(pindex->nBits);
274-
refBlockTarget += bnTarget / nASERTBlockTargetsToAverage;
275-
//nBlocksAveraged++;
276-
//if (pindex->GetBlockHash() == params.hashGenesisBlock)
277-
//LogPrintf("Averaging genesis block target\n");
278-
} else
279-
i--; // Average one more block to make up for the one we skipped
280-
pindex = algo == -1 ? GetLastBlockIndex(pindex->pprev, fProofOfStake) : GetLastBlockIndexForAlgo(pindex->pprev, algo);
281-
if (!pindex)
282-
break;
283-
}
284-
//LogPrintf("nBlocksAveraged = %u\n", nBlocksAveraged);
285-
//assert(nBlocksAveraged == nASERTBlockTargetsToAverage);
286-
//if (pindex)
287-
//LogPrintf("end pindex->nHeight = %i\n", pindex->nHeight);
288-
if (fUseCache) {
289-
Arith256ToAtomic(refBlockTarget, targetCacheOne, targetCacheTwo, targetCacheThree, targetCacheFour);
290-
nTargetCacheHeight.store(nHeightDiff / nASERTBlockTargetsToAverage);
291-
nTargetCacheAlgo.store(algo);
292-
//LogPrintf("Set average target cache at nHeight = %u with algo = %i\n", nHeight, algo);
237+
const bool fUseCache = true;
238+
{
239+
LOCK(cs_target_cache);
240+
241+
static arith_uint256 refBlockTargetCache;
242+
static int nTargetCacheHeight = -1;
243+
static int nTargetCacheAlgo = CBlockHeader::ALGO_COUNT;
244+
245+
if (nASERTBlockTargetsToAverage > 0 && nHeight >= nASERTStartHeight + nASERTBlockTargetsToAverage && nHeightDiff >= nASERTBlockTargetsToAverage) {
246+
if (!fUseCache || nTargetCacheHeight != (int)(nHeightDiff / nASERTBlockTargetsToAverage) || nTargetCacheAlgo != algo || refBlockTargetCache == arith_uint256() || algo == -1) {
247+
const uint32_t nBlocksToSkip = nHeightDiff % nASERTBlockTargetsToAverage;
248+
const CBlockIndex* pindex = pindexPrev;
249+
//LogPrintf("nBlocksToSkip = %u\n", nBlocksToSkip);
250+
251+
for (unsigned int i = 0; i < nBlocksToSkip; i++) {
252+
pindex = algo == -1 ? GetLastBlockIndex(pindex->pprev, fProofOfStake) : GetLastBlockIndexForAlgo(pindex->pprev, algo);
253+
}
254+
//LogPrintf("begin pindex->nHeight = %i\n", pindex->nHeight);
255+
256+
//unsigned int nBlocksAveraged = 0;
257+
for (int i = 0; i < (int)nASERTBlockTargetsToAverage; i++) {
258+
if (pindex->nBits != (nProofOfWorkLimit - 1) || !params.fPowAllowMinDifficultyBlocks) { // Don't add min difficulty targets to the average
259+
arith_uint256 bnTarget = arith_uint256().SetCompact(pindex->nBits);
260+
refBlockTarget += bnTarget / nASERTBlockTargetsToAverage;
261+
//nBlocksAveraged++;
262+
//if (pindex->GetBlockHash() == params.hashGenesisBlock)
263+
//LogPrintf("Averaging genesis block target\n");
264+
} else
265+
i--; // Average one more block to make up for the one we skipped
266+
pindex = algo == -1 ? GetLastBlockIndex(pindex->pprev, fProofOfStake) : GetLastBlockIndexForAlgo(pindex->pprev, algo);
267+
if (!pindex)
268+
break;
269+
}
270+
//LogPrintf("nBlocksAveraged = %u\n", nBlocksAveraged);
271+
//assert(nBlocksAveraged == nASERTBlockTargetsToAverage);
272+
//if (pindex)
273+
//LogPrintf("end pindex->nHeight = %i\n", pindex->nHeight);
274+
if (fUseCache) {
275+
refBlockTargetCache = refBlockTarget;
276+
nTargetCacheHeight = nHeightDiff / nASERTBlockTargetsToAverage;
277+
nTargetCacheAlgo = algo;
278+
//LogPrintf("Set average target cache at nHeight = %u with algo = %i\n", nHeight, algo);
279+
}
280+
} else {
281+
refBlockTarget = refBlockTargetCache;
282+
//LogPrintf("Using average target cache at nHeight = %u with algo = %i\n", nHeight, algo);
293283
}
294284
} else {
295-
refBlockTarget = refBlockTargetCache;
296-
//LogPrintf("Using average target cache at nHeight = %u with algo = %i\n", nHeight, algo);
285+
if (fUseCache && algo != -1) {
286+
if (nTargetCacheHeight != -1 || nTargetCacheAlgo != algo || refBlockTargetCache == arith_uint256()) {
287+
refBlockTargetCache = arith_uint256().SetCompact(pindexReferenceBlock->nBits);
288+
nTargetCacheHeight = -1;
289+
nTargetCacheAlgo = algo;
290+
//LogPrintf("Set ref target cache at nHeight = %u with algo = %i\n", nHeight, algo);
291+
}
292+
refBlockTarget = refBlockTargetCache;
293+
} else
294+
refBlockTarget = arith_uint256().SetCompact(pindexReferenceBlock->nBits);
297295
}
298-
} else {
299-
if (fUseCache && algo != -1) {
300-
if (nTargetCacheAlgo.load() != algo || refBlockTargetCache == arith_uint256()) {
301-
refBlockTargetCache = arith_uint256().SetCompact(pindexReferenceBlock->nBits);
302-
Arith256ToAtomic(refBlockTargetCache, targetCacheOne, targetCacheTwo, targetCacheThree, targetCacheFour);
303-
nTargetCacheHeight.store(-1);
304-
nTargetCacheAlgo.store(algo);
305-
//LogPrintf("Set ref target cache at nHeight = %u with algo = %i\n", nHeight, algo);
306-
}
307-
refBlockTarget = refBlockTargetCache;
308-
} else
309-
refBlockTarget = arith_uint256().SetCompact(pindexReferenceBlock->nBits);
310296
}
311297

312298
//LogPrintf("nHeight = %u, algo = %i, refBlockTarget = %s\n", nHeight, algo, refBlockTarget.ToString().c_str());
@@ -316,9 +302,9 @@ unsigned int AverageTargetASERT(const CBlockIndex* pindexLast, const CBlockHeade
316302
const uint32_t divisor = params.nPowTargetTimespan; // Must be positive
317303
const int exponent = dividend / divisor; // Note: this integer division rounds down positive and rounds up negative numbers via truncation, but the truncated fractional part is handled by the approximation below
318304
const uint32_t remainder = fPositive ? dividend % divisor : -dividend % divisor; // Must be positive
319-
// We are using uint256 rather than uint64_t here because a nPowTargetTimespan of more than 3 days in the divisor may cause the following cubic approximation to overflow a uint64_t
320-
arith_uint256 numerator = 1;
321-
arith_uint256 denominator = 1;
305+
// We are using uint512 rather than uint64_t here because a nPowTargetTimespan of more than 3 days in the divisor may cause the following cubic approximation to overflow a uint64_t
306+
arith_uint512 numerator = 1;
307+
arith_uint512 denominator = 1;
322308
// Alternatively, ensure that the nPowTargetTimespan (divisor) is small enough such that (2*2*2) * (4 + 11 + 35 + 50) * (divisor)^3 < (2^64 - 1) which is the uint64_t maximum value to leave some room and make overflow extremely unlikely
323309
//assert(divisor <= (3 * 24 * 60 * 60));
324310
// Keep in mind that a large exponent due to being extremely far ahead or behind schedule, especially in case of reviving an abandoned chain, will also lead to overflowing the numerator, so a less accurate approximation should be used in this case
@@ -334,12 +320,12 @@ unsigned int AverageTargetASERT(const CBlockIndex* pindexLast, const CBlockHeade
334320
//numerator *= remainder + divisor; // x+1
335321
//denominator *= divisor;
336322

337-
const arith_uint256 bnDivisor(divisor);
338-
const arith_uint256 bnRemainder(remainder);
323+
const arith_uint512 bnDivisor(divisor);
324+
const arith_uint512 bnRemainder(remainder);
339325
numerator = numerator * ((4 * bnRemainder*bnRemainder*bnRemainder) + (11 * bnRemainder*bnRemainder * bnDivisor) + (35 * bnRemainder * bnDivisor*bnDivisor) + (50 * bnDivisor*bnDivisor*bnDivisor));
340326
denominator = denominator * (50 * bnDivisor*bnDivisor*bnDivisor);
341-
//numerator = numerator * ((4ull * remainder*remainder*remainder) + (11ull * remainder*remainder * divisor) + (35ull * remainder * divisor*divisor) + (50ull * divisor*divisor*divisor));
342-
//denominator = denominator * (50ull * divisor*divisor*divisor);
327+
//numerator = numerator * ((4lu * remainder*remainder*remainder) + (11lu * remainder*remainder * divisor) + (35lu * remainder * divisor*divisor) + (50lu * divisor*divisor*divisor));
328+
//denominator = denominator * (50lu * divisor*divisor*divisor);
343329
}
344330
} else {
345331
for (int i = 0; i > exponent; i--)
@@ -349,12 +335,12 @@ unsigned int AverageTargetASERT(const CBlockIndex* pindexLast, const CBlockHeade
349335
//numerator *= divisor;
350336
//denominator *= remainder + divisor; // x+1
351337

352-
const arith_uint256 bnDivisor(divisor);
353-
const arith_uint256 bnRemainder(remainder);
338+
const arith_uint512 bnDivisor(divisor);
339+
const arith_uint512 bnRemainder(remainder);
354340
numerator = numerator * (50 * bnDivisor*bnDivisor*bnDivisor);
355341
denominator = denominator * ((4 * bnRemainder*bnRemainder*bnRemainder) + (11 * bnRemainder*bnRemainder * bnDivisor) + (35 * bnRemainder * bnDivisor*bnDivisor) + (50 * bnDivisor*bnDivisor*bnDivisor));
356-
//numerator = numerator * (50ull * divisor*divisor*divisor);
357-
//denominator = denominator * ((4ull * remainder*remainder*remainder) + (11ull * remainder*remainder * divisor) + (35ull * remainder * divisor*divisor) + (50ull * divisor*divisor*divisor));
342+
//numerator = numerator * (50lu * divisor*divisor*divisor);
343+
//denominator = denominator * ((4lu * remainder*remainder*remainder) + (11lu * remainder*remainder * divisor) + (35lu * remainder * divisor*divisor) + (50lu * divisor*divisor*divisor));
358344
}
359345
}
360346

0 commit comments

Comments
 (0)