Git Product home page Git Product logo

Comments (10)

h4x3rotab avatar h4x3rotab commented on August 19, 2024 4

Here is the Python implementation of LWMA algo in Bitcoin Gold:

def BTG_LWMA(height, timestamp, target):
    # T=<target solvetime>

    T = 600

    # height -1 = most recently solved block number
    # target  = 1/difficulty/2^x where x is leading zeros in coin's max_target, I believe
    # Recommended N:

    N = 45 # int(45*(600/T)^0.3))

    # To get a more accurate solvetime to within +/- ~0.2%, use an adjustment factor.
    # This technique has been shown to be accurate in 4 coins.
    # In a formula:
# [edit by zawy: since he's using target method, adjust should be 0.998. This was my mistake. ]
    # adjust = 0.9989^(500/N)  
    # k = (N+1)/2 * adjust * T 
    k = 13632
    sumTarget = 0
    t = 0
    j = 0

    # Loop through N most recent blocks.  "< height", not "<=". 
    # height-1 = most recently solved rblock
    for i in range(height - N, height):
        solvetime = timestamp[i] - timestamp[i-1]
        j += 1
        t += solvetime * j
        sumTarget += target[i]

    # Keep t reasonable in case strange solvetimes occurred. 
    if t < N * k // 3:
        t = N * k // 3

    next_target = t * sumTarget // k // N // N
    return next_target

@zawy12 , please note that your original pseudocode has a mistake at the last line:

next_target = t * sumTarget / k

If I understand it correctly, it should be:

next_target = t * sumTarget / (k * N^2)

t is the weighted sum of solve time, which has the same order of T*N*(N+1) / 2; sumTarget is the sum of the target of the last N blocks, which equals to N*avg_target.

Given k is (N+1)/2 * adjust * T, ignoring adjust, which is approximate 1, if we sub the three variables to next_target = t * sumTarget / k, we will get:

next_target = T*N*(N+1) / 2 * N*avg_target / ((N+1)/2 * T) = N^2 * avg_target

Apparently, there's a superfluous factor N^2.

from difficulty-algorithms.

zawy12 avatar zawy12 commented on August 19, 2024 4

Important locations in BTC code:

FTL
MAX_FUTURE_BLOCK_TIME set in chain.h, validating here:
https://github.com/bitcoin/bitcoin/blob/40c6c85c05812ee8bf824b639307b1ac17a001c4/src/chain.h#L24

Median Peer time error allowed away from local time:
DEFAULT_MAX_TIME_ADJUSTMENT set in timedata.h, validation here:
https://github.com/bitcoin/bitcoin/blob/40c6c85c05812ee8bf824b639307b1ac17a001c4/src/timedata.h#L16

Here's another time setting that needs to be reduced 9x your block time if you want it to be like BTC:
https://github.com/bitcoin/bitcoin/blob/40c6c85c05812ee8bf824b639307b1ac17a001c4/src/chain.h#L40

LWMA for BTC / Zcash Clones

LWMA-1 (LWMA-3 used is deprecated)

This version does not allow "negative solvetimes" that the original BTG allowed. This increases stability.

// LWMA-1 for BTC & Zcash clones
// Copyright (c) 2017-2019 The Bitcoin Gold developers, Zawy, iamstenman (Microbitcoin)
// MIT License
// Algorithm by Zawy, a modification of WT-144 by Tom Harding
// For updates see
// https://github.com/zawy12/difficulty-algorithms/issues/3#issuecomment-442129791
// Do not use Zcash's / Digishield's method of ignoring the ~6 most recent 
// timestamps via the median past timestamp (MTP of 11).
// Changing MTP to 1 instead of 11 enforces sequential timestamps. Not doing this was the
// most serious, problematic, & fundamental consensus theory mistake made in bitcoin but
// this change may require changes elsewhere such as creating block headers or what pools do.
//  FTL should be lowered to about N*T/20.
//  FTL in BTC clones is MAX_FUTURE_BLOCK_TIME in chain.h.
//  FTL in Ignition, Numus, and others can be found in main.h as DRIFT.
//  FTL in Zcash & Dash clones need to change the 2*60*60 here:
//  if (block.GetBlockTime() > nAdjustedTime + 2 * 60 * 60)
//  which is around line 3700 in main.cpp in ZEC and validation.cpp in Dash
//  If your coin uses median network time instead of node's time, the "revert to 
//  node time" rule (70 minutes in BCH, ZEC, & BTC) should be reduced to FTL/2 
//  to prevent 33% Sybil attack that can manipulate difficulty via timestamps. See:
// https://github.com/zcash/zcash/issues/4021

unsigned int Lwma3CalculateNextWorkRequired(const CBlockIndex* pindexLast, const Consensus::Params& params)
{
    const int64_t T = params.nPowTargetSpacing;

   // For T=600 use N=288 (takes 2 days to fully respond to hashrate changes) and has 
  //  a StdDev of N^(-0.5) which will often be the change in difficulty in N/4 blocks when hashrate is 
  // constant. 10% of blocks will have an error >2x the StdDev above or below where D should be. 
  //  This N=288 is like N=144 in ASERT which is N=144*ln(2)=100 in 
  // terms of BCH's ASERT.  BCH's ASERT uses N=288 which is like 2*288/ln(2) = 831 = N for 
  // LWMA. ASERT and LWMA are almost indistinguishable once this adjustment to N is used. In other words,
  // 831/144 = 5.8 means my N=144 recommendation for T=600 is 5.8 times faster but SQRT(5.8) less 
  // stability than BCH's ASERT. The StdDev for 288 is 6%, so 12% accidental variation will be see in 10% of blocks.
  // Twice 288 is 576 which will have 4.2% StdDev and be 2x slower. This is reasonable for T=300 or less.
 // For T = 60, N=1,000 will have 3% StdDev & maybe plenty fast, but require 1M multiplications & additions per 
  // 1,000 blocks for validation which might be a consideration. I would not go over N=576 and prefer 360
 // so that it can respond in 6 hours to hashrate changes.

    const int64_t N = params.lwmaAveragingWindow;  

    // Define a k that will be used to get a proper average after weighting the solvetimes.
    const int64_t k = N * (N + 1) * T / 2; 

    const int64_t height = pindexLast->nHeight;
    const arith_uint256 powLimit = UintToArith256(params.powLimit);
    
   // New coins just "give away" first N blocks. It's better to guess
   // this value instead of using powLimit, but err on high side to not get stuck.
    if (height < N) { return powLimit.GetCompact(); }

    arith_uint256 avgTarget, nextTarget;
    int64_t thisTimestamp, previousTimestamp;
    int64_t sumWeightedSolvetimes = 0, j = 0;

    const CBlockIndex* blockPreviousTimestamp = pindexLast->GetAncestor(height - N);
    previousTimestamp = blockPreviousTimestamp->GetBlockTime();

    // Loop through N most recent blocks. 
    for (int64_t i = height - N + 1; i <= height; i++) {
        const CBlockIndex* block = pindexLast->GetAncestor(i);

        // Prevent solvetimes from being negative in a safe way. It must be done like this. 
        // Do not attempt anything like  if (solvetime < 1) {solvetime=1;}
        // The +1 ensures new coins do not calculate nextTarget = 0.
        thisTimestamp = (block->GetBlockTime() > previousTimestamp) ? 
                            block->GetBlockTime() : previousTimestamp + 1;

       // 6*T limit prevents large drops in diff from long solvetimes which would cause oscillations.
        int64_t solvetime = std::min(6 * T, thisTimestamp - previousTimestamp);

       // The following is part of "preventing negative solvetimes". 
        previousTimestamp = thisTimestamp;
       
       // Give linearly higher weight to more recent solvetimes.
        j++;
        sumWeightedSolvetimes += solvetime * j; 

        arith_uint256 target;
        target.SetCompact(block->nBits);
        avgTarget += target / N / k; // Dividing by k here prevents an overflow below.
    }
    nextTarget = avgTarget * sumWeightedSolvetimes; 

    if (nextTarget > powLimit) { nextTarget = powLimit; }

    return nextTarget.GetCompact();
}

from difficulty-algorithms.

zawy12 avatar zawy12 commented on August 19, 2024 1

This post included the original HTML code coins came up with on their own. It's here for my future reference. I've used HTML comment tag to hide the content because no one else should have an interest.

from difficulty-algorithms.

zawy12 avatar zawy12 commented on August 19, 2024 1

LWMA for BTC / Zcash Clones

// LWMA for BTC clones
// Copyright (c) 2017-2018 The Bitcoin Gold developers
// Copyright (c) 2018 Zawy (M.I.T license continued)
// Algorithm by zawy, a modification of WT-144 by Tom Harding
// Code by h4x3rotab of BTC Gold, modified/updated by zawy
// https://github.com/zawy12/difficulty-algorithms/issues/3#issuecomment-388386175
//  FTL must be changed to 300 or N*T/20 whichever is higher.
//  FTL in BTC clones is MAX_FUTURE_BLOCK_TIME in chain.h.
//  FTL in Ignition, Numus, and others can be found in main.h as DRIFT.
//  FTL in Zcash & Dash clones need to change the 2*60*60 here:
//  if (block.GetBlockTime() > nAdjustedTime + 2 * 60 * 60)
//  which is around line 3450 in main.cpp in ZEC and validation.cpp in Dash

unsigned int LwmaCalculateNextWorkRequired(const CBlockIndex* pindexLast, const Consensus::Params& params)
{   
    const int64_t T = params.nPowTargetSpacing;
    // N=45 for T=600.  N=60 for T=150.  N=90 for T=60. 
    const int64_ N = params.nZawyLwmaAveragingWindow; 
    const int64_t k = N*(N+1)*T/2; // BTG's code has a missing N here. They inserted it in the loop
    const int height = pindexLast->nHeight;
    assert(height > N);

    arith_uint256 sum_target;
    int64_t t = 0, j = 0, solvetime;

    // Loop through N most recent blocks. 
    for (int i = height - N+1; i <= height; i++) {
        const CBlockIndex* block = pindexLast->GetAncestor(i);
        const CBlockIndex* block_Prev = block->GetAncestor(i - 1);
        solvetime = block->GetBlockTime() - block_Prev->GetBlockTime();
        j++;
        t += solvetime * j;  // Weighted solvetime sum.
        arith_uint256 target;
        target.SetCompact(block->nBits);
        sum_target += target / (k * N); // BTG added the missing N back here.
    }
    // Keep t reasonable to >= 1/10 of expected t.
    if (t < k/10 ) {   t = k/10;  }
    arith_uint256 next_target = t * sum_target;
     if (next_target > powLimit) { next_target = powLimit; }
    return next_target.GetCompact();
}

LWMA-1 (&3)

Prevents negative solvetimes.

// LWMA-3 for BTC/Zcash clones
// Copyright (c) 2017-2018 The Bitcoin Gold developers
// MIT License
// Algorithm by Zawy, a modification of WT-144 by Tom Harding
// Code by h4x3rotab of BTC Gold, modified/updated by Zawy
// Updated to LWMA-3 by iamstenman (MicroBitcoin)
// For change/updates, see
// https://github.com/zawy12/difficulty-algorithms/issues/3#issuecomment-388386175
//  FTL must be changed to 300 or N*T/20 whichever is higher.
//  FTL in BTC clones is MAX_FUTURE_BLOCK_TIME in chain.h.
//  FTL in Ignition, Numus, and others can be found in main.h as DRIFT.
//  FTL in Zcash & Dash clones need to change the 2*60*60 here:
//  if (block.GetBlockTime() > nAdjustedTime + 2 * 60 * 60)
//  which is around line 3450 in main.cpp in ZEC and validation.cpp in Dash

unsigned int Lwma3CalculateNextWorkRequired(const CBlockIndex* pindexLast, const Consensus::Params& params)
{
    const int64_t T = params.nPowTargetSpacing;
    const int64_t N = params.lwmaAveragingWindow;
    const int64_t k = N * (N + 1) * T / 2;
    const int64_t height = pindexLast->nHeight;
    const arith_uint256 powLimit = UintToArith256(params.powLimit);
    
    if (height < N) { return powLimit.GetCompact(); }

    arith_uint256 sumTarget, previousDiff, nextTarget;
    int64_t thisTimestamp, previousTimestamp;
    int64_t t = 0, j = 0, solvetimeSum = 0;

    const CBlockIndex* blockPreviousTimestamp = pindexLast->GetAncestor(height - N);
    previousTimestamp = blockPreviousTimestamp->GetBlockTime();

    // Loop through N most recent blocks. 
    for (int64_t i = height - N + 1; i <= height; i++) {
        const CBlockIndex* block = pindexLast->GetAncestor(i);
        thisTimestamp = (block->GetBlockTime() > previousTimestamp) ? block->GetBlockTime() : previousTimestamp + 1;

        int64_t solvetime = std::min(6 * T, thisTimestamp - previousTimestamp);
        previousTimestamp = thisTimestamp;

        j++;
        t += solvetime * j; // Weighted solvetime sum.
        arith_uint256 target;
        target.SetCompact(block->nBits);
        sumTarget += target / (k * N);

      //  if (i > height - 3) { solvetimeSum += solvetime; } // deprecated
        if (i == height) { previousDiff = target.SetCompact(block->nBits); }
    }

    nextTarget = t * sumTarget;
    
    if (nextTarget > (previousDiff * 150) / 100) { nextTarget = (previousDiff * 150) / 100; }
    if ((previousDiff * 67) / 100 > nextTarget) { nextTarget = (previousDiff * 67)/100; }
   //  if (solvetimeSum < (8 * T) / 10) { nextTarget = previousDiff * 100 / 106; } // deprecated
    if (nextTarget > powLimit) { nextTarget = powLimit; }

    return nextTarget.GetCompact();
}

from difficulty-algorithms.

cryptforall avatar cryptforall commented on August 19, 2024 1

For safety reasons, I suggest inserting this line at the beginning of the code. @zawy12

assert(pindexLast != nullptr);

sir most btc/dash clones have it

unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params)
{
    assert( pindexLast != nullptr );
    int nHeight = pindexLast->nHeight + 1;

from difficulty-algorithms.

h4x3rotab avatar h4x3rotab commented on August 19, 2024

BTCGPU/BTCGPU@a3c8d1a

I'm on boarding :)

from difficulty-algorithms.

zawy12 avatar zawy12 commented on August 19, 2024

Thanks for the correction.

from difficulty-algorithms.

zawy12 avatar zawy12 commented on August 19, 2024

Hush (who has Zcash's digishield) has 3x the market capitalization of Masari (who has LWMA), so Hush should be less subject to hash attacks. One caveat is that HUSH is more liquid (it's on cryptopia). Another is that Masari has 120 second blocks verses Hush's 150, which gives Masari a slight advantage in reaction speed (it is able to collect more data points in the same time span to estimate hashrate). They're both about 20M total coins. Hush is $1 and Masari is $0.30. The following charts show LWMA is performing a lot better. The charts are scaled the same and show the most recent 30,000 blocks (40 days for Masari, 50 days for hush). Hush's best week on the "blocks stolen" metric was only a little better than Masari's worst week. Hush's best week on delays was 2x worse than Masaris worst week.

hush_30k_4-14-2018_ending_291k
masari_30k_new

from difficulty-algorithms.

cryptozeny avatar cryptozeny commented on August 19, 2024

For safety reasons, I suggest inserting this line at the beginning of the code. @zawy12

assert(pindexLast != nullptr);

from difficulty-algorithms.

neoncoin-project avatar neoncoin-project commented on August 19, 2024

Can you please make a version for the BTC clones in version 0.8.6? I try but is hard the timestam stuff.

from difficulty-algorithms.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.