Post
Topic
Board Service Announcements (Altcoins)
Re: [ANN] Launch-time charts - 50 currencies - cryptometer.org
by
canoe
on 31/01/2014, 22:17:14 UTC
Could you add MemoryCoin (MMC).

They used a bad parameter at the beginning which resulted in quite a big funny fluctuation, they then changed the algorithm, it's smooth now. Could be interesting.


Added MemoryCoin charts to the site:
http://cryptometer.org/memorycoin_96_hour_charts.html
http://cryptometer.org/memorycoin_90_day_charts.html

Yes, that's interesting.  You can see the fluctuation on the first chart.  I guess they hard-forked at Hour 71?  Sounds stressful!  I'm going to read that giant thread and see what parameter they changed.


I found the fix in github.  They replaced the entire algorithm.  It's not a simple parameter change.  I also compared the old algorithm in MemoryCoin with the current algorithms in Unobtanium and Zetacoin.  They are the same.  So that's the problem and how to fix it.

https://github.com/memorycoin/memorycoin/commit/05d26375cb17804bf2fa233678d0bb2dbea6321f

The old algorithm:
Code:
unsigned int static OldGetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock)
{
    unsigned int nProofOfWorkLimit = bnProofOfWorkLimit.GetCompact();

    // Genesis block
    if (pindexLast == NULL)
        return nProofOfWorkLimit;

    //Change difficulty every block based on the previous nInterval blocks

    //Timewarp bug fix
        // Go back the full period unless it's the first retarget after genesis. Code courtesy of Art Forz
     int nBlocksBack = nInterval-1;
    if((pindexLast->nHeight+1) != nInterval)
        nBlocksBack = nInterval;

     const CBlockIndex* pindexFirst = pindexLast;
    for (int i = 0; pindexFirst && i < nBlocksBack; i++)
         pindexFirst = pindexFirst->pprev;

     //assert(pindexFirst);
        if(pindexFirst==NULL){
        return nProofOfWorkLimit;
        }

    // Limit adjustment step
    int64 nActualTimespan = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime();
    printf("  nActualTimespan = %"PRI64d"  before bounds\n", nActualTimespan);

    if (nActualTimespan < nTargetTimespan*0.8)
        nActualTimespan = nTargetTimespan*0.8;

    if (nActualTimespan > nTargetTimespan*1.2)
        nActualTimespan = nTargetTimespan*1.2;

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

    if (bnNew > bnProofOfWorkLimit)
        bnNew = bnProofOfWorkLimit;

    /// debug print
    //printf("\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("GetNextWorkRequired RETARGET After:  %08x  %s\n", bnNew.GetCompact(), bnNew.getuint256().ToString().c_str());

    return bnNew.GetCompact();
}

The new algorithm:
Code:
unsigned int static KimotoGravityWell(const CBlockIndex* pindexLast, const CBlockHeader *pblock, uint64 TargetBlocksSpacingSeconds, uint64 PastBlocksMin, uint64 PastBlocksMax) {
    /* current difficulty formula, Anoncoin - kimoto gravity well */
    const CBlockIndex *BlockLastSolved = pindexLast;
    const CBlockIndex *BlockReading = pindexLast;
    const CBlockHeader *BlockCreating = pblock;
BlockCreating = BlockCreating;
    uint64 PastBlocksMass = 0;
    int64 PastRateActualSeconds = 0;
    int64 PastRateTargetSeconds = 0;
    double PastRateAdjustmentRatio = double(1);
    CBigNum PastDifficultyAverage;
    CBigNum PastDifficultyAveragePrev;
    double EventHorizonDeviation;
    double EventHorizonDeviationFast;
    double EventHorizonDeviationSlow;

    if (BlockLastSolved == NULL || BlockLastSolved->nHeight == 0 || (uint64)BlockLastSolved->nHeight < PastBlocksMin) { return bnProofOfWorkLimit.GetCompact(); }

    for (unsigned int i = 1; BlockReading && BlockReading->nHeight > 0; i++) {
        if (PastBlocksMax > 0 && i > PastBlocksMax) { break; }
        PastBlocksMass++;

        if (i == 1) { PastDifficultyAverage.SetCompact(BlockReading->nBits); }
        else { PastDifficultyAverage = ((CBigNum().SetCompact(BlockReading->nBits) - PastDifficultyAveragePrev) / i) + PastDifficultyAveragePrev; }
        PastDifficultyAveragePrev = PastDifficultyAverage;

        PastRateActualSeconds = BlockLastSolved->GetBlockTime() - BlockReading->GetBlockTime();
        PastRateTargetSeconds = TargetBlocksSpacingSeconds * PastBlocksMass;
        PastRateAdjustmentRatio = double(1);
        if (PastRateActualSeconds < 0) { PastRateActualSeconds = 0; }
        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;
    }

    CBigNum bnNew(PastDifficultyAverage);
    if (PastRateActualSeconds != 0 && PastRateTargetSeconds != 0) {
        bnNew *= PastRateActualSeconds;
        bnNew /= PastRateTargetSeconds;
    }
    if (bnNew > bnProofOfWorkLimit) { bnNew = bnProofOfWorkLimit; }

    /// debug print
    printf("Difficulty Retarget - Kimoto Gravity Well\n");
    printf("PastRateAdjustmentRatio = %g\n", PastRateAdjustmentRatio);
    printf("Before: %08x %s\n", BlockLastSolved->nBits, CBigNum().SetCompact(BlockLastSolved->nBits).getuint256().ToString().c_str());
    printf("After: %08x %s\n", bnNew.GetCompact(), bnNew.getuint256().ToString().c_str());


    return bnNew.GetCompact();
}

unsigned int static NeoGetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock)
{
    static const int64 BlocksTargetSpacing = 6 * 60; // 6 minutes
    unsigned int TimeDaySeconds = 60 * 60 * 24;
    int64 PastSecondsMin = TimeDaySeconds*0.25;
    int64 PastSecondsMax = TimeDaySeconds*1;
    uint64 PastBlocksMin = PastSecondsMin / BlocksTargetSpacing;
    uint64 PastBlocksMax = PastSecondsMax / BlocksTargetSpacing;

    return KimotoGravityWell(pindexLast, pblock, BlocksTargetSpacing, PastBlocksMin, PastBlocksMax);
}