Comments (10)
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.
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.
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.
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.
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.
I'm on boarding :)
from difficulty-algorithms.
Thanks for the correction.
from difficulty-algorithms.
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.
from difficulty-algorithms.
For safety reasons, I suggest inserting this line at the beginning of the code. @zawy12
assert(pindexLast != nullptr);
from difficulty-algorithms.
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)
- Detecting & Empowering Dedicated Miners In 51% Attacks
- Self-Hashing Transactions to Generate Coin
- Smooth Coin-Emission Formula
- Correcting Chain Work
- Importing Chain Work with Notarizations HOT 2
- New Selfish Mining Attack?
- ASERT / NEFDA is the perfect DA? HOT 22
- EMA for BCH (part 2) HOT 159
- Confirmation time, long averaging windows, a history
- Quantifying the Consensus Trilemma
- Verge Attack, February 15, 2021 HOT 1
- Multishield's geometric mean to get chain work in Multi-POW coins
- Easier-to-remember Seed Words HOT 3
- Installation HOT 3
- WTEMA / ASERT as an RC filter
- what is latest solution for Lwma? HOT 6
- Difficulty algorithm for interesting hashes instead of lowest target
- Maybe you can help me with go Implemetation this version of lwma HOT 1
- Best Difficulty Algorithm, Timestamp Rules, Selfish Mining, Selecting N
- Estimating Chain Work Based on Lowest Hashes
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from difficulty-algorithms.