// Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Copyright (c) Flo Developers 2013-2018 // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "pow.h" #include "arith_uint256.h" #include "chain.h" #include "primitives/block.h" #include "uint256.h" #include "util.h" #include unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params) { assert(pindexLast != nullptr); unsigned int nProofOfWorkLimit = UintToArith256(params.powLimit).GetCompact(); // Only change once per difficulty adjustment interval if ((pindexLast->nHeight+1) % params.DifficultyAdjustmentInterval(pindexLast->nHeight+1) != 0) { 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. if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.TargetTimespan(pindexLast->nHeight+1)*2) return nProofOfWorkLimit; else { // Return the last non-special-min-difficulty-rules-block const CBlockIndex* pindex = pindexLast; while (pindex->pprev && pindex->nHeight % params.DifficultyAdjustmentInterval(pindex->nHeight+1) != 0 && pindex->nBits == nProofOfWorkLimit) pindex = pindex->pprev; return pindex->nBits; } } return pindexLast->nBits; } int averagingInterval = params.AveragingInterval(pindexLast->nHeight+1); // Go back by what we want to be 14 days worth of blocks // FLO: This fixes an issue where a 51% attack can change difficulty at will. // Go back the full period unless it's the first retarget after genesis. Code courtesy of Art Forz int blockstogoback = averagingInterval-1; if ((pindexLast->nHeight+1) != averagingInterval) blockstogoback = averagingInterval; // Go back by what we want to be 14 days worth of blocks const CBlockIndex* pindexFirst = pindexLast; for (int i = 0; pindexFirst && i < blockstogoback; i++) pindexFirst = pindexFirst->pprev; assert(pindexFirst); return CalculateNextWorkRequired(pindexLast, pindexFirst->GetBlockTime(), params); } unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params& params) { if (params.fPowNoRetargeting) return pindexLast->nBits; const int64_t nMinActualTimespan = params.MinActualTimespan(pindexLast->nHeight+1); const int64_t nMaxActualTimespan = params.MaxActualTimespan(pindexLast->nHeight+1); // Limit adjustment step int64_t nActualTimespan = pindexLast->GetBlockTime() - nFirstBlockTime; if (nActualTimespan < nMinActualTimespan) nActualTimespan = nMinActualTimespan; if (nActualTimespan > nMaxActualTimespan) nActualTimespan = nMaxActualTimespan; // Retarget arith_uint256 bnNew; arith_uint256 bnOld; bnNew.SetCompact(pindexLast->nBits); bnOld = bnNew; // FLO: intermediate uint256 can overflow by 1 bit const arith_uint256 bnPowLimit = UintToArith256(params.powLimit); bool fShift = bnNew.bits() > bnPowLimit.bits() - 1; if (fShift) bnNew >>= 1; bnNew *= nActualTimespan; bnNew /= params.AveragingInterval(pindexLast->nHeight+1) * params.nPowTargetSpacing; if (fShift) bnNew <<= 1; if (bnNew > bnPowLimit) bnNew = bnPowLimit; // /// debug print // LogPrintf("GetNextWorkRequired RETARGET\n"); // LogPrintf("Params().TargetTimespan() = %d nActualTimespan = %d\n", params.TargetTimespan(pindexLast->nHeight+1), nActualTimespan); // LogPrintf("Before: %08x %s\n", pindexLast->nBits, bnOld.ToString()); // LogPrintf("After: %08x %s\n", bnNew.GetCompact(), bnNew.ToString()); return bnNew.GetCompact(); } bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params& params) { bool fNegative; bool fOverflow; arith_uint256 bnTarget; bnTarget.SetCompact(nBits, &fNegative, &fOverflow); // Check range if (fNegative || bnTarget == 0 || fOverflow || bnTarget > UintToArith256(params.powLimit)) return false; // uint256 target=ArithToUint256(bnTarget); // std::cout << "target: " << target.ToString() << "\thash: " << hash.ToString() << "\n"; // Check proof of work matches claimed amount if (UintToArith256(hash) > bnTarget) return false; return true; }