Пример #1
0
int LitecoinChain::nextWorkRequired(BlockIterator blk) const {
    const int64_t nTargetTimespan = 3.5 * 24 * 60 * 60; // two weeks
    const int64_t nTargetSpacing = 2.5 * 60;
    const int64_t nInterval = nTargetTimespan / nTargetSpacing;
    
    // Genesis block
    int h = blk.height();
    if (h == 0) // trick to test that it is asking for the genesis block
        return _genesisBlock.getBits(); // proofOfWorkLimit().GetCompact(); Actually not for the genesisblock - here it is 0x1e0ffff0, not 0x1e0fffff
    
    // Only change once per interval
    if ((h + 1) % nInterval != 0)
        return blk->bits;
    
    // Litecoin: 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 = nInterval-1;
    if ((h + 1) != nInterval)
        blockstogoback = nInterval;
    
    // Go back by what we want to be 3.5 days worth of blocks
    BlockIterator former = blk - blockstogoback;
    
    // Limit adjustment step
    int nActualTimespan = blk->time - former->time;
    log_debug("  nActualTimespan = %"PRI64d"  before bounds", nActualTimespan);
    if (nActualTimespan < nTargetTimespan/4)
        nActualTimespan = nTargetTimespan/4;
    if (nActualTimespan > nTargetTimespan*4)
        nActualTimespan = nTargetTimespan*4;
    
    // Retarget
    CBigNum bnNew;
    bnNew.SetCompact(blk->bits);
    bnNew *= nActualTimespan;
    bnNew /= nTargetTimespan;
    
    if (bnNew > proofOfWorkLimit())
        bnNew = proofOfWorkLimit();
    
    /// debug print
    log_info("GetNextWorkRequired RETARGET");
    log_info("\tnTargetTimespan = %"PRI64d"    nActualTimespan = %"PRI64d"", nTargetTimespan, nActualTimespan);
    log_info("\tBefore: %08x  %s", blk->bits, CBigNum().SetCompact(blk->bits).getuint256().toString().c_str());
    log_info("\tAfter:  %08x  %s", bnNew.GetCompact(), bnNew.getuint256().toString().c_str());
    
    return bnNew.GetCompact();
}
Пример #2
0
int TestNet3Chain::nextWorkRequired(BlockIterator blk) const {
    const int64_t nTargetTimespan = 14 * 24 * 60 * 60; // two weeks
    const int64_t nTargetSpacing = 10 * 60;
    const int64_t nInterval = nTargetTimespan / nTargetSpacing;
    
    // Genesis block
    int h = blk.height();
    if (h == 0) // trick to test that it is asking for the genesis block
        return proofOfWorkLimit().GetCompact();
    
    // Only change once per interval
    if ((h + 1) % nInterval != 0) {
        // Return the last non-special-min-difficulty-rules-block
        while (blk.height() % nInterval != 0 && blk->bits == proofOfWorkLimit().GetCompact())
            blk--;
        return blk->bits;
    }
    
    // Go back by what we want to be 14 days worth of blocks
    BlockIterator former = blk - (nInterval-1);
    
    // Limit adjustment step
    int nActualTimespan = blk->time - former->time;
    log_debug("  nActualTimespan = %"PRI64d"  before bounds", nActualTimespan);
    if (nActualTimespan < nTargetTimespan/4)
        nActualTimespan = nTargetTimespan/4;
    if (nActualTimespan > nTargetTimespan*4)
        nActualTimespan = nTargetTimespan*4;
    
    // Retarget
    CBigNum bnNew;
    bnNew.SetCompact(blk->bits);
    bnNew *= nActualTimespan;
    bnNew /= nTargetTimespan;
    
    if (bnNew > proofOfWorkLimit())
        bnNew = proofOfWorkLimit();
    
    /// debug print
    log_info("GetNextWorkRequired RETARGET");
    log_info("\tnTargetTimespan = %"PRI64d"    nActualTimespan = %"PRI64d"", nTargetTimespan, nActualTimespan);
    log_info("\tBefore: %08x  %s", blk->bits, CBigNum().SetCompact(blk->bits).getuint256().toString().c_str());
    log_info("\tAfter:  %08x  %s", bnNew.GetCompact(), bnNew.getuint256().toString().c_str());
    
    return bnNew.GetCompact();
}
Пример #3
0
unsigned int BitcoinChain::nextWorkRequired(const CBlockIndex* pindexLast) const {
    const int64 nTargetTimespan = 14 * 24 * 60 * 60; // two weeks
    const int64 nTargetSpacing = 10 * 60;
    const int64 nInterval = nTargetTimespan / nTargetSpacing;

    // Genesis block
    if (pindexLast == NULL)
        return proofOfWorkLimit().GetCompact();

    // Only change once per interval
    if ((pindexLast->nHeight+1) % nInterval != 0)
        return pindexLast->nBits;

    // Go back by what we want to be 14 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 nActualTimespan = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime();
    printf("  nActualTimespan = %"PRI64d"  before bounds\n", nActualTimespan);
    if (nActualTimespan < nTargetTimespan/4)
        nActualTimespan = nTargetTimespan/4;
    if (nActualTimespan > nTargetTimespan*4)
        nActualTimespan = nTargetTimespan*4;

    // Retarget
    CBigNum bnNew;
    bnNew.SetCompact(pindexLast->nBits);
    bnNew *= nActualTimespan;
    bnNew /= nTargetTimespan;

    if (bnNew > proofOfWorkLimit())
        bnNew = proofOfWorkLimit();

    /// debug print
    printf("GetNextWorkRequired RETARGET\n");
    printf("nTargetTimespan = %"PRI64d"    nActualTimespan = %"PRI64d"\n", nTargetTimespan, nActualTimespan);
    printf("Before: %08x  %s\n", pindexLast->nBits, CBigNum().SetCompact(pindexLast->nBits).getuint256().toString().c_str());
    printf("After:  %08x  %s\n", bnNew.GetCompact(), bnNew.getuint256().toString().c_str());

    return bnNew.GetCompact();
}
Пример #4
0
int TerracoinChain::nextWorkRequired(BlockIterator blk) const {
    const int64_t nTargetTimespan = 60 * 60; // one hour weeks
    const int64_t nTargetSpacing = 2 * 60; // new block every two minutes
    const int64_t nInterval = nTargetTimespan / nTargetSpacing;
    
    // Genesis block
    int h = blk.height();
    if (h == 0) // trick to test that it is asking for the genesis block
        return proofOfWorkLimit().GetCompact();
    
    // Only change once per interval
    if ((h + 1) % nInterval != 0)
        return blk->bits;
    
    // Go back by what we want to be 14 days worth of blocks
    BlockIterator former = blk - (nInterval-1);
    
    // Limit adjustment step
    int nActualTimespan = blk->time - former->time;
    log_debug("  nActualTimespan = %"PRI64d"  before bounds", nActualTimespan);
    if (nActualTimespan < nTargetTimespan/4)
        nActualTimespan = nTargetTimespan/4;
    if (nActualTimespan > nTargetTimespan*4)
        nActualTimespan = nTargetTimespan*4;
    
    // Retarget
    CBigNum bnNew;
    bnNew.SetCompact(blk->bits);
    bnNew *= nActualTimespan;
    bnNew /= nTargetTimespan;
    
    if (bnNew > proofOfWorkLimit())
        bnNew = proofOfWorkLimit();
    
    /// debug print
    log_info("GetNextWorkRequired RETARGET");
    log_info("nTargetTimespan = %"PRI64d"    nActualTimespan = %"PRI64d"", nTargetTimespan, nActualTimespan);
    log_info("Before: %08x  %s", blk->bits, CBigNum().SetCompact(blk->bits).getuint256().toString().c_str());
    log_info("After:  %08x  %s", bnNew.GetCompact(), bnNew.getuint256().toString().c_str());
    
    return bnNew.GetCompact();
}
Пример #5
0
bool CreateCoinStake( CBlock &blocknew, CKey &key,
    vector<const CWalletTx*> &StakeInputs, uint64_t &CoinAge,
    CWallet &wallet, CBlockIndex* pindexPrev )
{
    int64_t CoinWeight;
    CBigNum StakeKernelHash;
    CTxDB txdb("r");
    int64_t StakeWeightSum = 0;
    double StakeValueSum = 0;
    int64_t StakeWeightMin=MAX_MONEY;
    int64_t StakeWeightMax=0;
    uint64_t StakeCoinAgeSum=0;
    double StakeDiffSum = 0;
    double StakeDiffMax = 0;
    CTransaction &txnew = blocknew.vtx[1]; // second tx is coinstake

    //initialize the transaction
    txnew.nTime = blocknew.nTime & (~STAKE_TIMESTAMP_MASK);
    txnew.vin.clear();
    txnew.vout.clear();

    // Choose coins to use
    set <pair <const CWalletTx*,unsigned int> > CoinsToStake;

    int64_t BalanceToStake = wallet.GetBalance();
    int64_t nValueIn = 0;
    //Request all the coins here, check reserve later

    if ( BalanceToStake<=0
        || !wallet.SelectCoinsForStaking(BalanceToStake*2, txnew.nTime, CoinsToStake, nValueIn) )
    {
        LOCK(MinerStatus.lock);
        MinerStatus.ReasonNotStaking+=_("No coins; ");
        if (fDebug) LogPrintf("CreateCoinStake: %s",MinerStatus.ReasonNotStaking);
        return false;
    }
    BalanceToStake -= nReserveBalance;

    if(fDebug2) LogPrintf("\nCreateCoinStake: Staking nTime/16= %d Bits= %u",
    txnew.nTime/16,blocknew.nBits);

    for(const auto& pcoin : CoinsToStake)
    {
        const CTransaction &CoinTx =*pcoin.first; //transaction that produced this coin
        unsigned int CoinTxN =pcoin.second; //index of this coin inside it

        CTxIndex txindex;
        {
            LOCK2(cs_main, wallet.cs_wallet);
            if (!txdb.ReadTxIndex(pcoin.first->GetHash(), txindex))
                continue; //error?
        }

        CBlock CoinBlock; //Block which contains CoinTx
        {
            LOCK2(cs_main, wallet.cs_wallet);
            if (!CoinBlock.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false))
                continue;
        }

        // only count coins meeting min age requirement
        if (CoinBlock.GetBlockTime() + nStakeMinAge > txnew.nTime)
            continue;

        if (CoinTx.vout[CoinTxN].nValue > BalanceToStake)
            continue;

        {
            int64_t nStakeValue= CoinTx.vout[CoinTxN].nValue;
            StakeValueSum += nStakeValue /(double)COIN;
            //crazy formula...
            // todo: clean this
            // todo reuse calculated value for interst
            CBigNum bn = CBigNum(nStakeValue) * (blocknew.nTime-CoinTx.nTime) / CENT;
            bn = bn * CENT / COIN / (24 * 60 * 60);
            StakeCoinAgeSum += bn.getuint64();
        }

        if(blocknew.nVersion==7)
        {
            NetworkTimer();
            CoinWeight = CalculateStakeWeightV3(CoinTx,CoinTxN,GlobalCPUMiningCPID);
            StakeKernelHash= CalculateStakeHashV3(CoinBlock,CoinTx,CoinTxN,txnew.nTime,GlobalCPUMiningCPID,mdPORNonce);
        }
        else
        {
            uint64_t StakeModifier = 0;
            if(!FindStakeModifierRev(StakeModifier,pindexPrev))
                continue;
            CoinWeight = CalculateStakeWeightV8(CoinTx,CoinTxN,GlobalCPUMiningCPID);
            StakeKernelHash= CalculateStakeHashV8(CoinBlock,CoinTx,CoinTxN,txnew.nTime,StakeModifier,GlobalCPUMiningCPID);
        }

        CBigNum StakeTarget;
        StakeTarget.SetCompact(blocknew.nBits);
        StakeTarget*=CoinWeight;
        StakeWeightSum += CoinWeight;
        StakeWeightMin=std::min(StakeWeightMin,CoinWeight);
        StakeWeightMax=std::max(StakeWeightMax,CoinWeight);
        double StakeKernelDiff = GetBlockDifficulty(StakeKernelHash.GetCompact())*CoinWeight;
        StakeDiffSum += StakeKernelDiff;
        StakeDiffMax = std::max(StakeDiffMax,StakeKernelDiff);

        if (fDebug2) {
            int64_t RSA_WEIGHT = GetRSAWeightByBlock(GlobalCPUMiningCPID);
            LogPrintf(
"CreateCoinStake: V%d Time %.f, Por_Nonce %.f, Bits %jd, Weight %jd\n"
" RSA_WEIGHT %.f\n"
" Stk %72s\n"
" Trg %72s\n"
" Diff %0.7f of %0.7f\n",
            blocknew.nVersion,
            (double)txnew.nTime, mdPORNonce,
            (intmax_t)blocknew.nBits,(intmax_t)CoinWeight,
            (double)RSA_WEIGHT,
            StakeKernelHash.GetHex().c_str(), StakeTarget.GetHex().c_str(),
            StakeKernelDiff, GetBlockDifficulty(blocknew.nBits)
            );
        }

        if( StakeKernelHash <= StakeTarget )
        {
            // Found a kernel
            LogPrintf("\nCreateCoinStake: Found Kernel;\n");
            blocknew.nNonce= mdPORNonce;
            vector<valtype> vSolutions;
            txnouttype whichType;
            CScript scriptPubKeyOut;
            CScript scriptPubKeyKernel;
            scriptPubKeyKernel = CoinTx.vout[CoinTxN].scriptPubKey;
            if (!Solver(scriptPubKeyKernel, whichType, vSolutions))
            {
                LogPrintf("CreateCoinStake: failed to parse kernel\n");
                break;
            }
            if (whichType == TX_PUBKEYHASH) // pay to address type
            {
                // convert to pay to public key type
                if (!wallet.GetKey(uint160(vSolutions[0]), key))
                {
                    LogPrintf("CreateCoinStake: failed to get key for kernel type=%d\n", whichType);
                    break;  // unable to find corresponding public key
                }
                scriptPubKeyOut << key.GetPubKey() << OP_CHECKSIG;
            }
            else if (whichType == TX_PUBKEY)  // pay to public key type
            {
                valtype& vchPubKey = vSolutions[0];
                if (!wallet.GetKey(Hash160(vchPubKey), key)
                    || key.GetPubKey() != vchPubKey)
                {
                    LogPrintf("CreateCoinStake: failed to get key for kernel type=%d\n", whichType);
                    break;  // unable to find corresponding public key
                }

                scriptPubKeyOut = scriptPubKeyKernel;
            }
            else
            {
                LogPrintf("CreateCoinStake: no support for kernel type=%d\n", whichType);
                break;  // only support pay to public key and pay to address
            }

            txnew.vin.push_back(CTxIn(CoinTx.GetHash(), CoinTxN));
            StakeInputs.push_back(pcoin.first);
            if (!txnew.GetCoinAge(txdb, CoinAge))
                return error("CreateCoinStake: failed to calculate coin age");
            int64_t nCredit = CoinTx.vout[CoinTxN].nValue;

            txnew.vout.push_back(CTxOut(0, CScript())); // First Must be empty
            txnew.vout.push_back(CTxOut(nCredit, scriptPubKeyOut));
            //txnew.vout.push_back(CTxOut(0, scriptPubKeyOut));

            LogPrintf("CreateCoinStake: added kernel type=%d credit=%f\n", whichType,CoinToDouble(nCredit));

            LOCK(MinerStatus.lock);
            MinerStatus.KernelsFound++;
            MinerStatus.KernelDiffMax = 0;
            MinerStatus.KernelDiffSum = StakeDiffSum;
            return true;
        }
    }

    LOCK(MinerStatus.lock);
    MinerStatus.WeightSum = StakeWeightSum;
    MinerStatus.ValueSum = StakeValueSum;
    MinerStatus.WeightMin=StakeWeightMin;
    MinerStatus.WeightMax=StakeWeightMax;
    MinerStatus.CoinAgeSum=StakeCoinAgeSum;
    MinerStatus.KernelDiffMax = std::max(MinerStatus.KernelDiffMax,StakeDiffMax);
    MinerStatus.KernelDiffSum = StakeDiffSum;
    MinerStatus.nLastCoinStakeSearchInterval= txnew.nTime;
    return false;
}
Пример #6
0
unsigned int RetargetGPU(const CBlockIndex* pindex, bool output)
{

    /** Get the Last Block Index [1st block back in Channel]. **/
    const CBlockIndex* pindexFirst = GetLastChannelIndex(pindex, 2);
    if (pindexFirst->pprev == NULL)
        return bnProofOfWorkStart[2].GetCompact();


    /** Get Last Block Index [2nd block back in Channel]. **/
    const CBlockIndex* pindexLast = GetLastChannelIndex(pindexFirst->pprev, 2);
    if (pindexLast->pprev == NULL)
        return bnProofOfWorkStart[2].GetCompact();


    /** Get the Block Times with Minimum of 1 to Prevent Time Warps. **/
    int64 nBlockTime = ((pindex->nVersion >= 4) ? GetWeightedTimes(pindexFirst, 5) : max(pindexFirst->GetBlockTime() - pindexLast->GetBlockTime(), (int64) 1));
    int64 nBlockTarget = nTargetTimespan;


    /** Get the Chain Modular from Reserves. **/
    double nChainMod = GetFractionalSubsidy(GetChainAge(pindexFirst->GetBlockTime()), 0, ((pindex->nVersion >= 3) ? 40.0 : 20.0)) / (pindexFirst->nReleasedReserve[0] + 1);
    nChainMod = min(nChainMod, 1.0);
    nChainMod = max(nChainMod, (pindex->nVersion == 1) ? 0.75 : 0.5);


    /** Enforce Block Version 2 Rule. Chain mod changes block time requirements, not actual mod after block times. **/
    if(pindex->nVersion >= 2)
        nBlockTarget *= nChainMod;


    /** The Upper and Lower Bound Adjusters. **/
    int64 nUpperBound = nBlockTarget;
    int64 nLowerBound = nBlockTarget;


    /** Handle for Version 3 Blocks. Mod determined by time multiplied by max / min. **/
    if(pindex->nVersion >= 3)
    {

        /** If the time is above target, reduce difficulty by modular
        	of one interval past timespan multiplied by maximum decrease. **/
        if(nBlockTime >= nBlockTarget)
        {
            /** Take the Minimum overlap of Target Timespan to make that maximum interval. **/
            uint64 nOverlap = (uint64)min((nBlockTime - nBlockTarget), (nBlockTarget * 2));

            /** Get the Mod from the Proportion of Overlap in one Interval. **/
            double nProportions = (double)nOverlap / (nBlockTarget * 2);

            /** Get Mod from Maximum Decrease Equation with Decimal portions multiplied by Propotions. **/
            double nMod = 1.0 - (((pindex->nVersion >= 4) ? 0.15 : 0.75) * nProportions);
            nLowerBound = nBlockTarget * nMod;
        }

        /** If the time is below target, increase difficulty by modular
        	of interval of 1 - Block Target with time of 1 being maximum increase **/
        else
        {
            /** Get the overlap in reference from Target Timespan. **/
            uint64 nOverlap = nBlockTarget - nBlockTime;

            /** Get the mod from overlap proportion. Time of 1 will be closest to mod of 1. **/
            double nProportions = (double) nOverlap / nBlockTarget;

            /** Get the Mod from the Maximum Increase Equation with Decimal portion multiplied by Proportions. **/
            double nMod = 1.0 + (nProportions * 0.075);
            nLowerBound = nBlockTarget * nMod;
        }
    }


    /** Handle for Version 2 Difficulty Adjustments. **/
    else
    {
        double nBlockMod = (double) nBlockTarget / nBlockTime;
        nBlockMod = min(nBlockMod, 1.125);
        nBlockMod = max(nBlockMod, 0.75);

        /** Calculate the Lower Bounds. **/
        nLowerBound = nBlockTarget * nBlockMod;

        /** Version 1 Blocks Change Lower Bound from Chain Modular. **/
        if(pindex->nVersion == 1)
            nLowerBound *= nChainMod;

        /** Set Maximum [difficulty] up to 8%, and Minimum [difficulty] down to 50% **/
        nLowerBound = min(nLowerBound, (int64)(nUpperBound + (nUpperBound / 8)));
        nLowerBound = max(nLowerBound, (3 * nUpperBound ) / 4);
    }


    /** Get the Difficulty Stored in Bignum Compact. **/
    CBigNum bnNew;
    bnNew.SetCompact(pindexFirst->nBits);


    /** Change Number from Upper and Lower Bounds. **/
    bnNew *= nUpperBound;
    bnNew /= nLowerBound;


    /** Don't allow Difficulty to decrease below minimum. **/
    if (bnNew > bnProofOfWorkLimit[2])
        bnNew = bnProofOfWorkLimit[2];


    /** Console Output if Flagged. **/
    if(output)
    {
        int64 nDays, nHours, nMinutes;
        GetChainTimes(GetChainAge(pindexFirst->GetBlockTime()), nDays, nHours, nMinutes);

        printf("RETARGET[GPU] weighted time=%"PRId64" actual time %"PRId64" [%f %%]\n\tchain time: [%"PRId64" / %"PRId64"]\n\treleased reward: %"PRId64" [%f %%]\n\tdifficulty: [%f to %f]\n\tGPU height: %"PRId64" [AGE %"PRId64" days, %"PRId64" hours, %"PRId64" minutes]\n\n",
               nBlockTime, max(pindexFirst->GetBlockTime() - pindexLast->GetBlockTime(), (int64) 1), (100.0 * nLowerBound) / nUpperBound, nBlockTarget, nBlockTime, pindexFirst->nReleasedReserve[0] / COIN, 100.0 * nChainMod, GetDifficulty(pindexFirst->nBits, 2), GetDifficulty(bnNew.GetCompact(), 2), pindexFirst->nChannelHeight, nDays, nHours, nMinutes);
    }

    return bnNew.GetCompact();
}
Пример #7
0
/** Proof of Stake Retargeting: Modulate Difficulty based on production rate. **/
unsigned int RetargetPOS(const CBlockIndex* pindex, bool output)
{

    /** Get Last Block Index [1st block back in Channel]. **/
    const CBlockIndex* pindexFirst = GetLastChannelIndex(pindex, 0);
    if (pindexFirst->pprev == NULL)
        return bnProofOfWorkStart[0].GetCompact();


    /** Get Last Block Index [2nd block back in Channel]. **/
    const CBlockIndex* pindexLast = GetLastChannelIndex(pindexFirst->pprev, 0);
    if (pindexLast->pprev == NULL)
        return bnProofOfWorkStart[0].GetCompact();


    /** Get the Block Time and Target Spacing. **/
    int64 nBlockTime = GetWeightedTimes(pindexFirst, 5);
    int64 nBlockTarget = STAKE_TARGET_SPACING;


    /** The Upper and Lower Bound Adjusters. **/
    int64 nUpperBound = nBlockTarget;
    int64 nLowerBound = nBlockTarget;


    /** If the time is above target, reduce difficulty by modular
    	of one interval past timespan multiplied by maximum decrease. **/
    if(nBlockTime >= nBlockTarget)
    {
        /** Take the Minimum overlap of Target Timespan to make that maximum interval. **/
        uint64 nOverlap = (uint64)min((nBlockTime - nBlockTarget), (nBlockTarget * 2));

        /** Get the Mod from the Proportion of Overlap in one Interval. **/
        double nProportions = (double)nOverlap / (nBlockTarget * 2);

        /** Get Mod from Maximum Decrease Equation with Decimal portions multiplied by Propotions. **/
        double nMod = 1.0 - (0.15 * nProportions);
        nLowerBound = nBlockTarget * nMod;
    }

    /** If the time is below target, increase difficulty by modular
    	of interval of 1 - Block Target with time of 1 being maximum increase **/
    else
    {
        /** Get the overlap in reference from Target Timespan. **/
        uint64 nOverlap = nBlockTarget - nBlockTime;

        /** Get the mod from overlap proportion. Time of 1 will be closest to mod of 1. **/
        double nProportions = (double) nOverlap / nBlockTarget;

        /** Get the Mod from the Maximum Increase Equation with Decimal portion multiplied by Proportions. **/
        double nMod = 1.0 + (nProportions * 0.075);
        nLowerBound = nBlockTarget * nMod;
    }

    /** Get the Difficulty Stored in Bignum Compact. **/
    CBigNum bnNew;
    bnNew.SetCompact(pindexFirst->nBits);


    /** Change Number from Upper and Lower Bounds. **/
    bnNew *= nUpperBound;
    bnNew /= nLowerBound;


    /** Don't allow Difficulty to decrease below minimum. **/
    if (bnNew > bnProofOfWorkLimit[0])
        bnNew = bnProofOfWorkLimit[0];


    if(output)
    {
        int64 nDays, nHours, nMinutes;
        GetChainTimes(GetChainAge(pindexFirst->GetBlockTime()), nDays, nHours, nMinutes);

        printf("CHECK[POS] weighted time=%"PRId64" actual time =%"PRId64"[%f %%]\n\tchain time: [%"PRId64" / %"PRId64"]\n\tdifficulty: [%f to %f]\n\tPOS height: %"PRId64" [AGE %"PRId64" days, %"PRId64" hours, %"PRId64" minutes]\n\n",
               nBlockTime, max(pindexFirst->GetBlockTime() - pindexLast->GetBlockTime(), (int64) 1), ((100.0 * nLowerBound) / nUpperBound), nBlockTarget, nBlockTime, GetDifficulty(pindexFirst->nBits, 0), GetDifficulty(bnNew.GetCompact(), 0), pindexFirst->nChannelHeight, nDays, nHours, nMinutes);
    }

    return bnNew.GetCompact();
}