Ejemplo n.º 1
0
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();
}
Ejemplo n.º 2
0
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();
}
Ejemplo n.º 3
0
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();
}
Ejemplo n.º 4
0
// 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();
}
Ejemplo n.º 5
0
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));
}
Ejemplo n.º 6
0
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();
}
Ejemplo n.º 7
0
// 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();
}
Ejemplo n.º 8
0
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();
}