unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params) { int64_t nTargetSpacing = 60; // 60 seconds per block int64_t nAveragingInterval = 10; // 10 blocks int64_t nAveragingTargetTimespan = nAveragingInterval * nTargetSpacing; // 600 seconds, 10 minutes int64_t nMaxAdjustDown = 4; // 4% adjustment down int64_t nMaxAdjustUp = 4; // 4% adjustment up int64_t nMinActualTimespan = nAveragingTargetTimespan * (100 - nMaxAdjustUp) / 100; int64_t nMaxActualTimespan = nAveragingTargetTimespan * (100 + nMaxAdjustDown) / 100; const arith_uint256 nProofOfWorkLimit = UintToArith256(params.powLimit); // Genesis block if (pindexLast == NULL) return nProofOfWorkLimit.GetCompact(); const CBlockIndex* pindexFirst = pindexLast; // Go back by what we want to be nAveragingInterval blocks for (int i = 0; pindexFirst && i < nAveragingInterval - 1; i++) { pindexFirst = pindexFirst->pprev; if (pindexFirst == NULL) { return nProofOfWorkLimit.GetCompact(); } } int64_t nActualTimespan = pindexLast->GetMedianTimePast() - pindexFirst->GetMedianTimePast(); LogPrintf(" nActualTimespan = %d before bounds %d %d\n", nActualTimespan, pindexLast->GetBlockTime(), pindexFirst->GetBlockTime()); if (nActualTimespan < nMinActualTimespan) nActualTimespan = nMinActualTimespan; if (nActualTimespan > nMaxActualTimespan) nActualTimespan = nMaxActualTimespan; LogPrintf(" nActualTimespan = %d after bounds %d %d\n", nActualTimespan, nMinActualTimespan, nMaxActualTimespan); arith_uint256 bnNew; arith_uint256 bnOld; bnNew.SetCompact(pindexLast->nBits); bnOld = bnNew; bnNew *= nActualTimespan; bnNew /= nAveragingTargetTimespan; if (bnNew > nProofOfWorkLimit) bnNew = nProofOfWorkLimit; /// debug print LogPrintf("GetNextWorkRequired RETARGET\n"); LogPrintf("nTargetTimespan = %d nActualTimespan = %d\n", nAveragingTargetTimespan, nActualTimespan); LogPrintf("Before: %08x %s\n", pindexLast->nBits, bnOld.ToString()); LogPrintf("After: %08x %s\n", bnNew.GetCompact(), bnNew.ToString()); return bnNew.GetCompact(); }
unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg, int64_t nLastBlockTime, int64_t nFirstBlockTime, const Consensus::Params& params) { // Limit adjustment step // Use medians to prevent time-warp attacks int64_t nActualTimespan = nLastBlockTime - nFirstBlockTime; LogPrint("pow", " nActualTimespan = %d before dampening\n", nActualTimespan); nActualTimespan = params.AveragingWindowTimespan() + (nActualTimespan - params.AveragingWindowTimespan())/4; LogPrint("pow", " nActualTimespan = %d before bounds\n", nActualTimespan); if (nActualTimespan < params.MinActualTimespan()) nActualTimespan = params.MinActualTimespan(); if (nActualTimespan > params.MaxActualTimespan()) nActualTimespan = params.MaxActualTimespan(); // Retarget const arith_uint256 bnPowLimit = UintToArith256(params.powLimit); arith_uint256 bnNew {bnAvg}; bnNew /= params.AveragingWindowTimespan(); bnNew *= nActualTimespan; if (bnNew > bnPowLimit) bnNew = bnPowLimit; /// debug print LogPrint("pow", "GetNextWorkRequired RETARGET\n"); LogPrint("pow", "params.AveragingWindowTimespan() = %d nActualTimespan = %d\n", params.AveragingWindowTimespan(), nActualTimespan); LogPrint("pow", "Current average: %08x %s\n", bnAvg.GetCompact(), bnAvg.ToString()); LogPrint("pow", "After: %08x %s\n", bnNew.GetCompact(), bnNew.ToString()); return bnNew.GetCompact(); }
unsigned int static DarkGravityWave(const CBlockIndex* pindexLast, const Consensus::Params& params) { /* current difficulty formula, gridcoin - DarkGravity v3, written by Evan Duffield - [email protected] */ const arith_uint256 bnPowLimit = UintToArith256(params.powLimit); int64_t nPastBlocks = 24; // make sure we have at least (nPastBlocks + 1) blocks, otherwise just return powLimit if (!pindexLast || pindexLast->nHeight < nPastBlocks) { return bnPowLimit.GetCompact(); } const CBlockIndex *pindex = pindexLast; arith_uint256 bnPastTargetAvg; for (unsigned int nCountBlocks = 1; nCountBlocks <= nPastBlocks; nCountBlocks++) { arith_uint256 bnTarget = arith_uint256().SetCompact(pindex->nBits); if (nCountBlocks == 1) { bnPastTargetAvg = bnTarget; } else { // NOTE: that's not an average really... bnPastTargetAvg = (bnPastTargetAvg * nCountBlocks + bnTarget) / (nCountBlocks + 1); } if(nCountBlocks != nPastBlocks) { assert(pindex->pprev); // should never fail pindex = pindex->pprev; } } arith_uint256 bnNew(bnPastTargetAvg); int64_t nActualTimespan = pindexLast->GetBlockTime() - pindex->GetBlockTime(); // NOTE: is this accurate? nActualTimespan counts it for (nPastBlocks - 1) blocks only... int64_t nTargetTimespan = nPastBlocks * params.nPowTargetSpacing; if (nActualTimespan < nTargetTimespan/3) nActualTimespan = nTargetTimespan/3; if (nActualTimespan > nTargetTimespan*3) nActualTimespan = nTargetTimespan*3; // Retarget bnNew *= nActualTimespan; bnNew /= nTargetTimespan; if (bnNew > bnPowLimit) { bnNew = bnPowLimit; } return bnNew.GetCompact(); }
// SYSCOIN DGW diff algo unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params& params) { /* current difficulty formula, dash - DarkGravity v3, written by Evan Duffield - [email protected] */ // Genesis block const arith_uint256 nProofOfWorkLimit = UintToArith256(params.powLimit); if (params.fPowNoRetargeting) return pindexLast->nBits; const CBlockIndex *BlockLastSolved = pindexLast; const CBlockIndex *BlockReading = pindexLast; int64_t nActualTimespan = 0; int64_t LastBlockTime = 0; int64_t PastBlocksMin = 24; int64_t PastBlocksMax = 24; int64_t CountBlocks = 0; arith_uint256 PastDifficultyAverage; arith_uint256 PastDifficultyAveragePrev; // 110 needed for snapshot unit test if (BlockLastSolved == NULL || BlockLastSolved->nHeight == 0 || BlockLastSolved->nHeight < 200) { return nProofOfWorkLimit.GetCompact(); } for (unsigned int i = 1; BlockReading && BlockReading->nHeight > 0; i++) { if (PastBlocksMax > 0 && i > PastBlocksMax) { break; } CountBlocks++; if(CountBlocks <= PastBlocksMin) { if (CountBlocks == 1) { PastDifficultyAverage.SetCompact(BlockReading->nBits); } else { PastDifficultyAverage = ((PastDifficultyAveragePrev * CountBlocks) + (arith_uint256().SetCompact(BlockReading->nBits))) / (CountBlocks + 1); } PastDifficultyAveragePrev = PastDifficultyAverage; } if(LastBlockTime > 0){ int64_t Diff = (LastBlockTime - BlockReading->GetBlockTime()); nActualTimespan += Diff; } LastBlockTime = BlockReading->GetBlockTime(); if (BlockReading->pprev == NULL) { assert(BlockReading); break; } BlockReading = BlockReading->pprev; } arith_uint256 bnNew(PastDifficultyAverage); int64_t _nTargetTimespan = CountBlocks * params.nPowTargetSpacing; if (nActualTimespan < _nTargetTimespan/3) nActualTimespan = _nTargetTimespan/3; if (nActualTimespan > _nTargetTimespan*3) nActualTimespan = _nTargetTimespan*3; // Retarget bnNew *= nActualTimespan; bnNew /= _nTargetTimespan; if (bnNew > nProofOfWorkLimit){ bnNew = nProofOfWorkLimit; } return bnNew.GetCompact(); }
BOOST_FIXTURE_TEST_CASE (auxpow_pow, BasicTestingSetup) { /* Use regtest parameters to allow mining with easy difficulty. */ SelectParams (CBaseChainParams::REGTEST); const Consensus::Params& params = Params ().GetConsensus (); const arith_uint256 target = (~arith_uint256 (0) >> 1); CBlockHeader block; block.nBits = target.GetCompact (); /* Verify the block version checks. */ block.nVersion = 1; mineBlock (block, true); BOOST_CHECK (CheckProofOfWork (block, params)); block.nVersion = 2; mineBlock (block, true); BOOST_CHECK (!CheckProofOfWork (block, params)); block.SetBaseVersion (2, params.nAuxpowChainId); mineBlock (block, true); BOOST_CHECK (CheckProofOfWork (block, params)); block.SetChainId (params.nAuxpowChainId + 1); mineBlock (block, true); BOOST_CHECK (!CheckProofOfWork (block, params)); /* Check the case when the block does not have auxpow (this is true right now). */ block.SetChainId (params.nAuxpowChainId); block.SetAuxpowVersion (true); mineBlock (block, true); BOOST_CHECK (!CheckProofOfWork (block, params)); block.SetAuxpowVersion (false); mineBlock (block, true); BOOST_CHECK (CheckProofOfWork (block, params)); mineBlock (block, false); BOOST_CHECK (!CheckProofOfWork (block, params)); /* ****************************************** */ /* Check the case that the block has auxpow. */ CAuxpowBuilder builder(5, 42); CAuxPow auxpow; const int32_t ourChainId = params.nAuxpowChainId; const unsigned height = 3; const int nonce = 7; const int index = CAuxPow::getExpectedIndex (nonce, ourChainId, height); valtype auxRoot, data; /* Valid auxpow, PoW check of parent block. */ block.SetAuxpowVersion (true); auxRoot = builder.buildAuxpowChain (block.GetHash (), height, index); data = CAuxpowBuilder::buildCoinbaseData (true, auxRoot, height, nonce); builder.setCoinbase (CScript () << data); mineBlock (builder.parentBlock, false, block.nBits); block.SetAuxpow (builder.getUnique ()); BOOST_CHECK (!CheckProofOfWork (block, params)); mineBlock (builder.parentBlock, true, block.nBits); block.SetAuxpow (builder.getUnique ()); BOOST_CHECK (CheckProofOfWork (block, params)); /* Mismatch between auxpow being present and block.nVersion. Note that block.SetAuxpow sets also the version and that we want to ensure that the block hash itself doesn't change due to version changes. This requires some work arounds. */ block.SetAuxpowVersion (false); const uint256 hashAux = block.GetHash (); auxRoot = builder.buildAuxpowChain (hashAux, height, index); data = CAuxpowBuilder::buildCoinbaseData (true, auxRoot, height, nonce); builder.setCoinbase (CScript () << data); mineBlock (builder.parentBlock, true, block.nBits); block.SetAuxpow (builder.getUnique ()); BOOST_CHECK (hashAux != block.GetHash ()); block.SetAuxpowVersion (false); BOOST_CHECK (hashAux == block.GetHash ()); BOOST_CHECK (!CheckProofOfWork (block, params)); /* Modifying the block invalidates the PoW. */ block.SetAuxpowVersion (true); auxRoot = builder.buildAuxpowChain (block.GetHash (), height, index); data = CAuxpowBuilder::buildCoinbaseData (true, auxRoot, height, nonce); builder.setCoinbase (CScript () << data); mineBlock (builder.parentBlock, true, block.nBits); block.SetAuxpow (builder.getUnique ()); BOOST_CHECK (CheckProofOfWork (block, params)); tamperWith (block.hashMerkleRoot); BOOST_CHECK (!CheckProofOfWork (block, params)); }
unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params) { const arith_uint256 powLimit = UintToArith256(params.powLimit); unsigned int nProofOfWorkLimit = powLimit.GetCompact(); // Genesis block if (pindexLast == NULL) return nProofOfWorkLimit; if (params.fPowNoRetargeting) return pindexLast->nBits; const int height = pindexLast->nHeight + 1; //okay, maybe not this line if (height < 14640) return GetNextWorkRequired_OLD(pindexLast, params); //hardcoded switch to 256.0 difficulty at block 14639 if (height == 14640) return 0x1C00FFFF; // Only change once per interval const int64_t nInterval = params.DifficultyAdjustmentInterval(); const int64_t nTargetSpacing = params.nPowTargetSpacing; if ((pindexLast->nHeight+1) % nInterval != 0) { // Special difficulty rule for testnet: if (params.fPowAllowMinDifficultyBlocks) { // If the new block's timestamp is more than 2* 10 minutes // then allow mining of a min-difficulty block. if (pblock->nTime > pindexLast->nTime + nTargetSpacing*2) return nProofOfWorkLimit; else { // Return the last non-special-min-difficulty-rules-block const CBlockIndex* pindex = pindexLast; while (pindex->pprev && pindex->nHeight % nInterval != 0 && pindex->nBits == nProofOfWorkLimit) pindex = pindex->pprev; return pindex->nBits; } } return pindexLast->nBits; } // 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 // Patch modified from Litecoin. int blockstogoback = nInterval-1; if (height >= 150000 && height != nInterval) blockstogoback = nInterval; // 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); // Limit adjustment step const int64_t nTargetTimespan = params.nPowTargetTimespan; int64_t nActualTimespan = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime(); // assymmetric retarget (slow difficulty rise / fast difficulty drop) can be // abused to make a 51% attack more profitable than it should be, // therefore we adopt (starting at block 895000) a symmetric algorithm based // on bitcoin's algorithm. // // we retarget at most by a factor of 4^(120/2016) = 1.086 if (height < 895000) { // use the old retarget algorithm const int64_t nTwoPercent = nTargetTimespan/50; if (nActualTimespan < nTargetTimespan) //is time taken for a block less than 3minutes? { //limit increase to a much lower amount than dictates to get past the pump-n-dump mining phase //due to retargets being done more often it also needs to be lowered significantly from the 4x increase if(nActualTimespan<(nTwoPercent*16)) //less than a minute? nActualTimespan=(nTwoPercent*45); //pretend it was only 10% faster than desired else if(nActualTimespan<(nTwoPercent*32)) //less than 2 minutes? nActualTimespan=(nTwoPercent*47); //pretend it was only 6% faster than desired else nActualTimespan=(nTwoPercent*49); //pretend it was only 2% faster than desired //int64 nTime=nTargetTimespan-nActualTimespan; //nActualTimespan = nTargetTimespan/2; } else if (nActualTimespan > nTargetTimespan*4) nActualTimespan = nTargetTimespan*4; } else { // new algorithm // use integer aritmmetic to make sure that // all architectures return the exact same answers, // so instead of: // // foo < bar/1.086 we do foo < (1000*bar)/1086 // foo = bar/1.086 we do foo = (1000*bar)/1086 // foo > bar*1.086 we do foo > (1086*bar)/1000 // foo = bar*1.086 we do foo = (1086*bar)/1000 // // (parentheses to stress desired operator precedence) // // risk of overflow? no way; bar is quite small and // we have it under control, it is defined as 3*60*60 if (nActualTimespan < (1000*nTargetTimespan)/1086) nActualTimespan = (1000*nTargetTimespan)/1086; else if (nActualTimespan > (1086*nTargetTimespan)/1000) nActualTimespan = (1086*nTargetTimespan)/1000; } // Retarget arith_uint256 bnNew; bnNew.SetCompact(pindexLast->nBits); bnNew *= nActualTimespan; bnNew /= nTargetTimespan; if (bnNew > powLimit) bnNew = powLimit; /// debug print LogPrintf("GetNextWorkRequired RETARGET\n"); LogPrintf("nTargetTimespan = %ld nActualTimespan = %ld\n", nTargetTimespan, nActualTimespan); LogPrintf("Before: %08x\n", pindexLast->nBits); LogPrintf("After: %08x\n", bnNew.GetCompact()); return bnNew.GetCompact(); }
// Return the target (difficulty) to the new block based on the pindexLast block unsigned int static GetNextWorkRequired_OLD(const CBlockIndex* pindexLast, const Consensus::Params& params) { const arith_uint256 powLimit = UintToArith256(params.powLimit); /* these values shadow the global ones with the same name * this function is only used for blocks before 14640... */ const int64_t nTargetTimespan = 7 * 24 * 60 * 60; // one week const int64_t nTargetSpacing = 5 * 60; const int64_t nInterval = nTargetTimespan / nTargetSpacing; // Genesis block if (pindexLast == NULL) return powLimit.GetCompact(); int64_t nRemaining = (pindexLast->nHeight+1) % nInterval; // Only change once per interval if ( nRemaining != 0) { /* const CBlockIndex* pindexFirst = pindexLast; for (int i = 0; pindexFirst && i < nRemaining-1; i++) pindexFirst = pindexFirst->pprev; assert(pindexFirst); int64 rema = GetAdjustedTime() - pindexFirst->GetBlockTime(); if(rema < nTargetTimespan) */ return pindexLast->nBits; } // Go back by what we want to be 7 days worth of blocks const CBlockIndex* pindexFirst = pindexLast; for (int i = 0; pindexFirst && i < nInterval-1; i++) pindexFirst = pindexFirst->pprev; assert(pindexFirst); // Limit adjustment step int64_t nActualTimespan = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime(); LogPrintf(" nActualTimespan = %ld before bounds\n", nActualTimespan); if (nActualTimespan < nTargetTimespan/4) nActualTimespan = nTargetTimespan/4; if (nActualTimespan > nTargetTimespan*4) nActualTimespan = nTargetTimespan*4; // Retarget arith_uint256 bnNew; bnNew.SetCompact(pindexLast->nBits); bnNew *= nActualTimespan; bnNew /= nTargetTimespan; if (bnNew > powLimit) bnNew = powLimit; /// debug print LogPrintf("GetNextWorkRequired RETARGET\n"); LogPrintf("nTargetTimespan = %ld nActualTimespan = %ld\n", nTargetTimespan, nActualTimespan); LogPrintf("Before: %08x\n", pindexLast->nBits); LogPrintf("After: %08x\n", bnNew.GetCompact()); return bnNew.GetCompact(); }
unsigned int static DarkGravityWave(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params) { /* current difficulty formula, dash - DarkGravity v3, written by Evan Duffield - [email protected] */ const arith_uint256 bnPowLimit = UintToArith256(params.powLimit); int64_t nPastBlocks = 24; // make sure we have at least (nPastBlocks + 1) blocks, otherwise just return powLimit if (!pindexLast || pindexLast->nHeight < nPastBlocks) { return bnPowLimit.GetCompact(); } if (params.fPowAllowMinDifficultyBlocks && ( // testnet ... (params.hashDevnetGenesisBlock.IsNull() && pindexLast->nChainWork >= UintToArith256(uint256S("0x000000000000000000000000000000000000000000000000003e9ccfe0e03e01"))) || // or devnet !params.hashDevnetGenesisBlock.IsNull())) { // NOTE: 000000000000000000000000000000000000000000000000003e9ccfe0e03e01 is the work of the "wrong" chain, // so this rule activates there immediately and new blocks with high diff from that chain are going // to be rejected by updated nodes. Note, that old nodes are going to reject blocks from updated nodes // after the "right" chain reaches this amount of work too. This is a temporary condition which should // be removed when we decide to hard-fork testnet again. // TODO: remove "testnet+work OR devnet" part on next testnet hard-fork // Special difficulty rule for testnet/devnet: // If the new block's timestamp is more than 2* 2.5 minutes // then allow mining of a min-difficulty block. // start using smoother adjustment on testnet when total work hits // 000000000000000000000000000000000000000000000000003ff00000000000 if (pindexLast->nChainWork >= UintToArith256(uint256S("0x000000000000000000000000000000000000000000000000003ff00000000000")) // and immediately on devnet || !params.hashDevnetGenesisBlock.IsNull()) { // recent block is more than 2 hours old if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + 2 * 60 * 60) { return bnPowLimit.GetCompact(); } // recent block is more than 10 minutes old if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.nPowTargetSpacing*4) { arith_uint256 bnNew = arith_uint256().SetCompact(pindexLast->nBits) * 10; if (bnNew > bnPowLimit) { bnNew = bnPowLimit; } return bnNew.GetCompact(); } } else { // old stuff if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.nPowTargetSpacing*2) { return bnPowLimit.GetCompact(); } } } const CBlockIndex *pindex = pindexLast; arith_uint256 bnPastTargetAvg; for (unsigned int nCountBlocks = 1; nCountBlocks <= nPastBlocks; nCountBlocks++) { arith_uint256 bnTarget = arith_uint256().SetCompact(pindex->nBits); if (nCountBlocks == 1) { bnPastTargetAvg = bnTarget; } else { // NOTE: that's not an average really... bnPastTargetAvg = (bnPastTargetAvg * nCountBlocks + bnTarget) / (nCountBlocks + 1); } if(nCountBlocks != nPastBlocks) { assert(pindex->pprev); // should never fail pindex = pindex->pprev; } } arith_uint256 bnNew(bnPastTargetAvg); int64_t nActualTimespan = pindexLast->GetBlockTime() - pindex->GetBlockTime(); // NOTE: is this accurate? nActualTimespan counts it for (nPastBlocks - 1) blocks only... int64_t nTargetTimespan = nPastBlocks * params.nPowTargetSpacing; if (nActualTimespan < nTargetTimespan/3) nActualTimespan = nTargetTimespan/3; if (nActualTimespan > nTargetTimespan*3) nActualTimespan = nTargetTimespan*3; // Retarget bnNew *= nActualTimespan; bnNew /= nTargetTimespan; if (bnNew > bnPowLimit) { bnNew = bnPowLimit; } return bnNew.GetCompact(); }