unsigned int GetNextWorkRequiredV4(const CBlockIndex* pindexLast, const Consensus::Params& params, int algo) { // find first block in averaging interval // Go back by what we want to be nAveragingInterval blocks per algo const CBlockIndex* pindexFirst = pindexLast; for (int i = 0; pindexFirst && i < NUM_ALGOS*params.nAveragingInterval; i++) { pindexFirst = pindexFirst->pprev; } const CBlockIndex* pindexPrevAlgo = GetLastBlockIndexForAlgo(pindexLast, params, algo); if (pindexPrevAlgo == nullptr || pindexFirst == nullptr) { return InitialDifficulty(params, algo); } // Limit adjustment step // Use medians to prevent time-warp attacks int64_t nActualTimespan = pindexLast-> GetMedianTimePast() - pindexFirst->GetMedianTimePast(); nActualTimespan = params.nAveragingTargetTimespanV4 + (nActualTimespan - params.nAveragingTargetTimespanV4)/4; if (nActualTimespan < params.nMinActualTimespanV4) nActualTimespan = params.nMinActualTimespanV4; if (nActualTimespan > params.nMaxActualTimespanV4) nActualTimespan = params.nMaxActualTimespanV4; //Global retarget arith_uint256 bnNew; bnNew.SetCompact(pindexPrevAlgo->nBits); bnNew *= nActualTimespan; bnNew /= params.nAveragingTargetTimespanV4; //Per-algo retarget int nAdjustments = pindexPrevAlgo->nHeight + NUM_ALGOS - 1 - pindexLast->nHeight; if (nAdjustments > 0) { for (int i = 0; i < nAdjustments; i++) { bnNew *= 100; bnNew /= (100 + params.nLocalTargetAdjustment); } } else if (nAdjustments < 0)//make it easier { for (int i = 0; i < -nAdjustments; i++) { bnNew *= (100 + params.nLocalTargetAdjustment); bnNew /= 100; } } if (bnNew > UintToArith256(params.powLimit)) { bnNew = UintToArith256(params.powLimit); } return bnNew.GetCompact(); }
unsigned int GetNextWorkRequiredV2(const CBlockIndex* pindexLast, const Consensus::Params& params, int algo) { LogPrintf("Height (Before): %s\n", pindexLast->nHeight); // find previous block with same algo const CBlockIndex* pindexPrev = GetLastBlockIndexForAlgo(pindexLast, params, algo); // find first block in averaging interval // Go back by what we want to be nAveragingInterval blocks const CBlockIndex* pindexFirst = pindexPrev; for (int i = 0; pindexFirst && i < params.nAveragingInterval - 1; i++) { pindexFirst = pindexFirst->pprev; pindexFirst = GetLastBlockIndexForAlgo(pindexFirst, params, algo); } if (pindexFirst == nullptr) { LogPrintf("Use default POW Limit\n"); return InitialDifficulty(params, algo); } // Limit adjustment step int64_t nActualTimespan = pindexPrev->GetBlockTime() - pindexFirst->GetBlockTime(); if (nActualTimespan < params.nMinActualTimespan) nActualTimespan = params.nMinActualTimespan; if (nActualTimespan > params.nMaxActualTimespan) nActualTimespan = params.nMaxActualTimespan; // Retarget arith_uint256 bnNew; bnNew.SetCompact(pindexPrev->nBits); bnNew *= nActualTimespan; bnNew /= params.nAveragingTargetTimespan; if (bnNew > UintToArith256(params.powLimit)) { bnNew = UintToArith256(params.powLimit); } return bnNew.GetCompact(); }
unsigned int KimotoGravityWell(const CBlockIndex* pindexLast, int algo) { unsigned int nProofOfWorkLimit = Params().ProofOfWorkLimit(algo).GetCompact(); if (fDebug){ LogPrintf("Proof Of Work Limit For Algo %i, is % i\n", algo, nProofOfWorkLimit); } // Genesis block if (pindexLast == NULL){ LogPrintf("Genesis Block Difficulty"); return nProofOfWorkLimit; } const CBlockIndex* pindexPrevAlgo = GetLastBlockIndexForAlgo(pindexLast, algo); if (pindexPrevAlgo == NULL){ LogPrintf("pindexPrevAlgo == NULL for Algo %i, is % i\n", algo, nProofOfWorkLimit); return nProofOfWorkLimit; } /* Franko Multi Algo Gravity Well */ const CBlockIndex *BlockLastSolved = pindexPrevAlgo; const CBlockIndex *BlockReading = pindexPrevAlgo; unsigned int AlgoCounter = 0; uint64_t PastBlocksMass = 0; int64_t PastRateActualSeconds = 0; int64_t PastRateTargetSeconds = 0; double PastRateAdjustmentRatio = double(1); uint256 PastDifficultyAverage; uint256 PastDifficultyAveragePrev; uint256 BlockReadingDifficulty; double EventHorizonDeviation; double EventHorizonDeviationFast; double EventHorizonDeviationSlow; static const int64_t TargetBlockSpacing = 60; // == 1 minute unsigned int TimeDaySeconds = 60 * 60 * 24; int64_t PastSecondsMin = TimeDaySeconds * 0.25; // == 6300 Seconds int64_t PastSecondsMax = TimeDaySeconds * 7; // == 604800 Seconds uint64_t PastBlocksMin = PastSecondsMin / TargetBlockSpacing; // == 360 blocks uint64_t PastBlocksMax = PastSecondsMax / TargetBlockSpacing; // == 10080 blocks //loop through and count the blocks found by the algo for (unsigned int i = 1; BlockReading && BlockReading->nHeight > 0; i++) { if (PastBlocksMax > 0 && i > PastBlocksMax) { break; } // Makes sure we are only calculating blocks from the specified algo if (BlockReading->GetAlgo() != algo){ BlockReading = BlockReading->pprev; continue; } AlgoCounter++; BlockReading = BlockReading->pprev; } if (BlockLastSolved == NULL || BlockLastSolved->nHeight == 0 || (uint64_t)BlockLastSolved->nHeight < PastBlocksMin || AlgoCounter < PastBlocksMin) { return Params().ProofOfWorkLimit(algo).GetCompact(); } int64_t LatestBlockTime = BlockLastSolved->GetBlockTime(); BlockReading = pindexPrevAlgo; for (unsigned int i = 1; BlockReading && BlockReading->nHeight > 0; i++) { if (PastBlocksMax > 0 && i > AlgoCounter) { break; } // Makes sure we are only calculating blocks from the specified algo if (BlockReading->GetAlgo() != algo){ BlockReading = BlockReading->pprev; continue; } PastBlocksMass++; if (i == 1) { PastDifficultyAverage.SetCompact(BlockReading->nBits); } else { BlockReadingDifficulty.SetCompact(BlockReading->nBits); if (BlockReadingDifficulty > PastDifficultyAveragePrev) { PastDifficultyAverage = PastDifficultyAveragePrev + ((BlockReadingDifficulty - PastDifficultyAveragePrev) / i); } else { PastDifficultyAverage = PastDifficultyAveragePrev - ((PastDifficultyAveragePrev - BlockReadingDifficulty) / i); } } PastDifficultyAveragePrev = PastDifficultyAverage; if (LatestBlockTime < BlockReading->GetBlockTime()) { LatestBlockTime = BlockReading->GetBlockTime(); } PastRateActualSeconds = LatestBlockTime - BlockReading->GetBlockTime(); PastRateTargetSeconds = TargetBlockSpacing * PastBlocksMass; PastRateAdjustmentRatio = double(1); if (PastRateActualSeconds < 1) { PastRateActualSeconds = 1; } if (PastRateActualSeconds != 0 && PastRateTargetSeconds != 0) { PastRateAdjustmentRatio = double(PastRateTargetSeconds) / double(PastRateActualSeconds); } EventHorizonDeviation = 1 + (0.7084 * pow((double(PastBlocksMass)/double(144)), -1.228)); EventHorizonDeviationFast = EventHorizonDeviation; EventHorizonDeviationSlow = 1 / EventHorizonDeviation; if (PastBlocksMass >= PastBlocksMin) { if ((PastRateAdjustmentRatio <= EventHorizonDeviationSlow) || (PastRateAdjustmentRatio >= EventHorizonDeviationFast)) { assert(BlockReading); break; } } if (BlockReading->pprev == NULL) { assert(BlockReading); break; } BlockReading = BlockReading->pprev; } uint256 bnNew(PastDifficultyAverage); if (PastRateActualSeconds != 0 && PastRateTargetSeconds != 0) { bnNew *= PastRateActualSeconds; bnNew /= PastRateTargetSeconds; } if (bnNew > Params().ProofOfWorkLimit(algo)) { bnNew = Params().ProofOfWorkLimit(algo); } // debug print if (fDebug){ LogPrintf("Franko Multi Algo Gravity Well\n"); LogPrintf("PastRateAdjustmentRatio = %g PastRateTargetSeconds = %d PastRateActualSeconds = %d\n", PastRateAdjustmentRatio, PastRateTargetSeconds, PastRateActualSeconds); LogPrintf("Before: %08x %s\n", BlockLastSolved->nBits, uint256().SetCompact(BlockLastSolved->nBits).ToString()); LogPrintf("After: %08x %s\n", bnNew.GetCompact(), bnNew.ToString()); } return bnNew.GetCompact(); }
unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, int algo, const Consensus::Params& params) { unsigned int nProofOfWorkLimit = UintToArith256(params.powLimit).GetCompact(); // Genesis block if (pindexLast == NULL) return nProofOfWorkLimit; if (params.fPowAllowMinDifficultyBlocks) { // Special difficulty rule for testnet: // If the new block's timestamp is more than 2* 10 minutes // then allow mining of a min-difficulty block. // TODO Myriadcoin: enable this at the next hard fork for testnet /* if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.nPowTargetSpacing*2) return nProofOfWorkLimit; */ } // find previous block with same algo const CBlockIndex* pindexPrev = GetLastBlockIndexForAlgo(pindexLast, algo); // Genesis block check again if (pindexPrev == NULL) return nProofOfWorkLimit; const CBlockIndex* pindexFirst = NULL; if( (pindexLast->nHeight >= params.nBlockTimeWarpPreventStart1) && (pindexLast->nHeight < params.nBlockTimeWarpPreventStart2) ) { // find first block in averaging interval // Go back by what we want to be nAveragingInterval blocks pindexFirst = pindexPrev; for (int i = 0; pindexFirst && i < params.nAveragingInterval - 1; i++) { pindexFirst = pindexFirst->pprev; pindexFirst = GetLastBlockIndexForAlgo(pindexFirst, algo); } if (pindexFirst == NULL) return nProofOfWorkLimit; // not nAveragingInterval blocks of this algo available // check block before first block for time warp const CBlockIndex* pindexFirstPrev = pindexFirst->pprev; if (pindexFirstPrev == NULL) return nProofOfWorkLimit; pindexFirstPrev = GetLastBlockIndexForAlgo(pindexFirstPrev, algo); if (pindexFirstPrev == NULL) return nProofOfWorkLimit; // take previous block if block times are out of order if (pindexFirstPrev->GetBlockTime() > pindexFirst->GetBlockTime()) { LogPrintf(" First blocks out of order times, swapping: %d %d\n", pindexFirstPrev->GetBlockTime(), pindexFirst->GetBlockTime()); pindexFirst = pindexFirstPrev; } } else if ( (pindexLast->nHeight >= params.nBlockTimeWarpPreventStart2) && (pindexLast->nHeight < params.nBlockTimeWarpPreventStart3) ) { // find first block in averaging interval // Go back by what we want to be nAveragingInterval blocks pindexFirst = pindexPrev; for (int i = 0; pindexFirst && i < params.nAveragingInterval - 1; i++) { pindexFirst = pindexFirst->pprev; pindexFirst = GetLastBlockIndexForAlgo(pindexFirst, algo); } if (pindexFirst == NULL) return nProofOfWorkLimit; // not nAveragingInterval blocks of this algo available const CBlockIndex* pindexFirstPrev; for ( ;; ) { // check blocks before first block for time warp pindexFirstPrev = pindexFirst->pprev; if (pindexFirstPrev == NULL) return nProofOfWorkLimit; pindexFirstPrev = GetLastBlockIndexForAlgo(pindexFirstPrev, algo); if (pindexFirstPrev == NULL) return nProofOfWorkLimit; // take previous block if block times are out of order if (pindexFirstPrev->GetBlockTime() > pindexFirst->GetBlockTime()) { LogPrintf(" First blocks out of order times, swapping: %d %d\n", pindexFirstPrev->GetBlockTime(), pindexFirst->GetBlockTime()); pindexFirst = pindexFirstPrev; } else break; } } else { // find first block in averaging interval // Go back by what we want to be nAveragingInterval blocks pindexFirst = pindexPrev; for (int i = 0; pindexFirst && i < params.nAveragingInterval - 1; i++) { pindexFirst = pindexFirst->pprev; pindexFirst = GetLastBlockIndexForAlgo(pindexFirst, algo); if (pindexFirst == NULL) { if(fDebug) { LogPrintf("pindexFirst is null. returning nProofOfWorkLimit\n"); } return nProofOfWorkLimit; } } } int64_t nActualTimespan; if (pindexLast->nHeight >= params.nBlockTimeWarpPreventStart3) { nActualTimespan = pindexPrev->GetMedianTimePast() - pindexFirst->GetMedianTimePast(); if(fDebug) { LogPrintf(" nActualTimespan = %d before bounds %d %d\n", nActualTimespan, pindexPrev->GetMedianTimePast(), pindexFirst->GetMedianTimePast()); } } else { nActualTimespan = pindexPrev->GetBlockTime() - pindexFirst->GetBlockTime(); if(fDebug) { LogPrintf(" nActualTimespan = %d before bounds %d %d\n", nActualTimespan, pindexPrev->GetBlockTime(), pindexFirst->GetBlockTime()); } } // Time warp mitigation: Don't adjust difficulty if time is negative if ( (pindexLast->nHeight >= params.nBlockTimeWarpPreventStart1) && (pindexLast->nHeight < params.nBlockTimeWarpPreventStart2) ) { if (nActualTimespan < 0) { if(fDebug) { LogPrintf(" nActualTimespan negative %d\n", nActualTimespan); LogPrintf(" Keeping: %08x \n", pindexPrev->nBits); } return pindexPrev->nBits; } } if (pindexLast->nHeight >= params.Phase2Timespan_Start) { return CalculateNextWorkRequiredV2(pindexPrev, pindexFirst, params, algo, nActualTimespan); } else { return CalculateNextWorkRequiredV1(pindexPrev, pindexFirst, params, algo, nActualTimespan, pindexLast->nHeight); } }