Skip to content

Commit 19fefc2

Browse files
committed
Rework on ZawyLwma
1 parent 73867bf commit 19fefc2

11 files changed

+129
-81
lines changed

src/chainparams.cpp

+16-4
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,12 @@ class CMainParams : public CChainParams {
9595
consensus.nLegacyLwmaForkHeight = 600000;
9696
consensus.nLegacyLwmaAveragingWindow = 60;
9797
consensus.nLegacyPowTargetSpacing = 10 * 60;
98-
consensus.nLwmaForkHeight = std::numeric_limits<int>::max();
99-
consensus.nLwmaAveragingWindow = 120;
98+
consensus.nLwmaForkHeight = 765949;
99+
consensus.nLwmaAveragingWindow = 45;
100+
consensus.nLwmaAdjustedWeight = 3443;
101+
consensus.nLwmaMinDenominator = 10;
102+
consensus.fLwmaSolvetimeLimitation = true;
103+
100104
consensus.nPowTargetSpacing = 2.5 * 60;
101105

102106
consensus.fPowAllowMinDifficultyBlocks = false;
@@ -263,7 +267,11 @@ class CTestNetParams : public CChainParams {
263267
consensus.nLegacyLwmaAveragingWindow = 60;
264268
consensus.nLegacyPowTargetSpacing = 10 * 60;
265269
consensus.nLwmaForkHeight = 7000;
266-
consensus.nLwmaAveragingWindow = 120;
270+
consensus.nLwmaAveragingWindow = 45;
271+
consensus.nLwmaAdjustedWeight = 3443;
272+
consensus.nLwmaMinDenominator = 10;
273+
consensus.fLwmaSolvetimeLimitation = true;
274+
267275
consensus.nPowTargetSpacing = 2.5 * 60;
268276

269277
consensus.fPowAllowMinDifficultyBlocks = false;
@@ -406,7 +414,11 @@ class CRegTestParams : public CChainParams {
406414
consensus.nLegacyLwmaAveragingWindow = 60;
407415
consensus.nLegacyPowTargetSpacing = 10 * 60;
408416
consensus.nLwmaForkHeight = -1; // Activated on regtest
409-
consensus.nLwmaAveragingWindow = 120;
417+
consensus.nLwmaAveragingWindow = 45;
418+
consensus.nLwmaAdjustedWeight = 3443;
419+
consensus.nLwmaMinDenominator = 10;
420+
consensus.fLwmaSolvetimeLimitation = true;
421+
410422
consensus.nPowTargetSpacing = 2.5 * 60;
411423

412424
consensus.fPowAllowMinDifficultyBlocks = true;

src/consensus/params.h

+4
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@ struct Params {
195195

196196
// Params for Lwma difficulty adjustment algorithm.
197197
int64_t nLwmaAveragingWindow;
198+
int64_t nLwmaAdjustedWeight; // k = (N+1)/2 * 0.998 * T
199+
int64_t nLwmaMinDenominator;
200+
bool fLwmaSolvetimeLimitation;
201+
198202
int64_t nPowTargetSpacing;
199203

200204
uint256 nMinimumChainWork;

src/miner.cpp

+5-4
Original file line numberDiff line numberDiff line change
@@ -168,10 +168,11 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
168168
pblocktemplate->vTxFees[0] = -nFees;
169169

170170
// Update the Sapling commitment tree.
171-
for (const CTransactionRef& ptx : pblock->vtx) {
172-
const CTransaction& tx = *ptx;
173-
for (const OutputDescription& odesc : tx.vShieldedOutput) {
174-
sapling_tree.append(odesc.cm);
171+
for (unsigned int i = 0; i < pblock->vtx.size(); i++)
172+
{
173+
const CTransaction &tx = *(pblock->vtx[i]);
174+
for (const OutputDescription &outputDescription : tx.vShieldedOutput) {
175+
sapling_tree.append(outputDescription.cm);
175176
}
176177
}
177178

src/pow.cpp

+83-45
Original file line numberDiff line numberDiff line change
@@ -119,72 +119,110 @@ unsigned int DigishieldCalculateNextWorkRequired(const CBlockIndex* pindexLast,
119119

120120
unsigned int LwmaGetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params, bool fLegacy)
121121
{
122-
int64_t nPowTargetSpacing = params.nPowTargetSpacing;
123-
int64_t nLwmaAveragingWindow = params.nLwmaAveragingWindow;
124-
125-
if (fLegacy) {
126-
nPowTargetSpacing = params.nLegacyPowTargetSpacing;
127-
nLwmaAveragingWindow = params.nLegacyLwmaAveragingWindow;
128-
}
129-
130122
// Special difficulty rule for testnet:
131123
// If the new block's timestamp is more than 2 * 10 minutes
132124
// then allow mining of a min-difficulty block.
133125
if (params.fPowAllowMinDifficultyBlocks &&
134-
pblock->GetBlockTime() > pindexLast->GetBlockTime() + nPowTargetSpacing * 2) {
126+
pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.nPowTargetSpacing * 2) {
135127
return UintToArith256(params.powLimit).GetCompact();
136128
}
137-
return LwmaCalculateNextWorkRequired(pindexLast, params, nPowTargetSpacing, nLwmaAveragingWindow);
129+
return LwmaCalculateNextWorkRequired(pindexLast, params, fLegacy);
138130
}
139131

140-
unsigned int LwmaCalculateNextWorkRequired(const CBlockIndex* pindexLast, const Consensus::Params& params, const int64_t T, const int64_t N)
132+
unsigned int LwmaCalculateNextWorkRequired(const CBlockIndex* pindexLast, const Consensus::Params& params, bool fLegacy)
141133
{
142-
// Define a k that will be used to get a proper average after weighting the solvetimes.
143-
const int64_t k = N * (N + 1) * T / 2;
144-
145-
const int64_t height = pindexLast->nHeight;
146134
const arith_uint256 powLimit = UintToArith256(params.powLimit);
135+
arith_uint256 nextTarget;
136+
arith_uint256 avgTarget;
147137

148-
// New coins just "give away" first N blocks. It's better to guess
149-
// this value instead of using powLimit, but err on high side to not get stuck.
150-
if (height < N) { return powLimit.GetCompact(); }
138+
if (fLegacy) {
139+
// Define a k that will be used to get a proper average after weighting the solvetimes.
140+
const int64_t T = params.nLegacyPowTargetSpacing;
141+
const int64_t N = params.nLegacyLwmaAveragingWindow;
142+
const int64_t k = N * (N + 1) * T / 2;
151143

152-
arith_uint256 avgTarget, nextTarget;
153-
int64_t thisTimestamp, previousTimestamp;
154-
int64_t sumWeightedSolvetimes = 0, j = 0;
144+
const int64_t height = pindexLast->nHeight;
155145

156-
const CBlockIndex* blockPreviousTimestamp = pindexLast->GetAncestor(height - N);
157-
previousTimestamp = blockPreviousTimestamp->GetBlockTime();
146+
// New coins just "give away" first N blocks. It's better to guess
147+
// this value instead of using powLimit, but err on high side to not get stuck.
148+
if (height < N) { return powLimit.GetCompact(); }
158149

159-
// Loop through N most recent blocks.
160-
for (int64_t i = height - N + 1; i <= height; i++) {
161-
const CBlockIndex* block = pindexLast->GetAncestor(i);
150+
int64_t thisTimestamp, previousTimestamp;
151+
int64_t sumWeightedSolvetimes = 0, j = 0;
162152

163-
// Prevent solvetimes from being negative in a safe way. It must be done like this.
164-
// Do not attempt anything like if (solvetime < 1) {solvetime=1;}
165-
// The +1 ensures new coins do not calculate nextTarget = 0.
166-
thisTimestamp = (block->GetBlockTime() > previousTimestamp) ? block->GetBlockTime() : previousTimestamp + 1;
153+
const CBlockIndex* blockPreviousTimestamp = pindexLast->GetAncestor(height - N);
154+
previousTimestamp = blockPreviousTimestamp->GetBlockTime();
167155

168-
// 6*T limit prevents large drops in diff from long solvetimes which would cause oscillations.
169-
int64_t solvetime = std::min(6 * T, thisTimestamp - previousTimestamp);
156+
// Loop through N most recent blocks.
157+
for (int64_t i = height - N + 1; i <= height; i++) {
158+
const CBlockIndex* block = pindexLast->GetAncestor(i);
170159

171-
// The following is part of "preventing negative solvetimes".
172-
previousTimestamp = thisTimestamp;
160+
// Prevent solvetimes from being negative in a safe way. It must be done like this.
161+
// Do not attempt anything like if (solvetime < 1) {solvetime=1;}
162+
// The +1 ensures new coins do not calculate nextTarget = 0.
163+
thisTimestamp = (block->GetBlockTime() > previousTimestamp) ? block->GetBlockTime() : previousTimestamp + 1;
173164

174-
// Give linearly higher weight to more recent solvetimes.
175-
j++;
176-
sumWeightedSolvetimes += solvetime * j;
165+
// 6*T limit prevents large drops in diff from long solvetimes which would cause oscillations.
166+
int64_t solvetime = std::min(6 * T, thisTimestamp - previousTimestamp);
177167

178-
arith_uint256 target;
179-
target.SetCompact(block->nBits);
180-
avgTarget += target / N / k; // Dividing by k here prevents an overflow below.
181-
}
168+
// The following is part of "preventing negative solvetimes".
169+
previousTimestamp = thisTimestamp;
182170

183-
// Desired equation in next line was nextTarget = avgTarget * sumWeightSolvetimes / k
184-
// but 1/k was moved to line above to prevent overflow in new coins
185-
nextTarget = avgTarget * sumWeightedSolvetimes;
171+
// Give linearly higher weight to more recent solvetimes.
172+
j++;
173+
sumWeightedSolvetimes += solvetime * j;
174+
175+
arith_uint256 target;
176+
target.SetCompact(block->nBits);
177+
avgTarget += target / N / k; // Dividing by k here prevents an overflow below.
178+
}
186179

187-
if (nextTarget > powLimit) { nextTarget = powLimit; }
180+
// Desired equation in next line was nextTarget = avgTarget * sumWeightSolvetimes / k
181+
// but 1/k was moved to line above to prevent overflow in new coins
182+
nextTarget = avgTarget * sumWeightedSolvetimes;
183+
} else {
184+
const int height = pindexLast->nHeight + 1;
185+
const int64_t T = params.nPowTargetSpacing;
186+
const int N = params.nLwmaAveragingWindow;
187+
const int k = params.nLwmaAdjustedWeight;
188+
const int dnorm = params.nLwmaMinDenominator;
189+
const bool limit_st = params.fLwmaSolvetimeLimitation;
190+
assert(height > N);
191+
192+
int t = 0, j = 0;
193+
194+
// Loop through N most recent blocks.
195+
for (int i = height - N; i < height; i++) {
196+
const CBlockIndex* block = pindexLast->GetAncestor(i);
197+
const CBlockIndex* block_Prev = block->GetAncestor(i - 1);
198+
int64_t solvetime = block->GetBlockTime() - block_Prev->GetBlockTime();
199+
200+
if (limit_st && solvetime > 6 * T) {
201+
solvetime = 6 * T;
202+
}
203+
204+
j++;
205+
t += solvetime * j; // Weighted solvetime sum.
206+
207+
// Target sum divided by a factor, (k N^2).
208+
// The factor is a part of the final equation. However we divide avgTarget here to avoid
209+
// potential overflow.
210+
arith_uint256 target;
211+
target.SetCompact(block->nBits);
212+
avgTarget += target / (k * N * N);
213+
}
214+
215+
// Keep t reasonable in case strange solvetimes occurred.
216+
if (t < N * k / dnorm) {
217+
t = N * k / dnorm;
218+
}
219+
220+
nextTarget = avgTarget * t;
221+
}
222+
223+
if (nextTarget > powLimit) {
224+
nextTarget = powLimit;
225+
}
188226

189227
return nextTarget.GetCompact();
190228
}

src/pow.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ unsigned int DigishieldCalculateNextWorkRequired(const CBlockIndex* pindexLast,
2626

2727
/** Zawy's LWMA */
2828
unsigned int LwmaGetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params&, bool fLegacy);
29-
unsigned int LwmaCalculateNextWorkRequired(const CBlockIndex* pindexLast, const Consensus::Params& params, const int64_t T, const int64_t N);
29+
unsigned int LwmaCalculateNextWorkRequired(const CBlockIndex* pindexLast, const Consensus::Params& params, bool fLegacy);
3030

3131
/** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */
3232
bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&);

src/rpc/blockchain.cpp

+12-13
Original file line numberDiff line numberDiff line change
@@ -62,19 +62,18 @@ static CUpdatedBlock latestblock;
6262

6363
/* Calculate the difficulty for a given block index.
6464
*/
65-
double GetDifficulty(const CBlockIndex* blockindex)
65+
double GetDifficulty(const CBlockIndex* blockindex, bool networkDifficulty)
6666
{
6767
// Floating point number that is a multiple of the minimum difficulty,
6868
// minimum difficulty = 1.0.
69-
if (blockindex == nullptr)
70-
{
71-
if (::ChainActive().Tip() == nullptr)
72-
return 1.0;
73-
else
74-
blockindex = ::ChainActive().Tip();
69+
70+
uint32_t bits;
71+
if (networkDifficulty) {
72+
bits = GetNextWorkRequired(blockindex, nullptr, Params().GetConsensus());
73+
} else {
74+
bits = blockindex->nBits;
7575
}
7676

77-
uint32_t bits = blockindex->nBits;
7877
uint32_t powLimit = UintToArith256(Params().GetConsensus().powLimit).GetCompact();
7978

8079
int nShift = (bits >> 24) & 0xff;
@@ -142,7 +141,7 @@ UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex
142141
result.pushKV("nonce", blockindex->nNonce.GetHex());
143142
result.pushKV("solution", HexStr(blockindex->nSolution));
144143
result.pushKV("bits", strprintf("%08x", blockindex->nBits));
145-
result.pushKV("difficulty", GetDifficulty(blockindex));
144+
result.pushKV("difficulty", GetDifficulty(blockindex, false));
146145
result.pushKV("chainwork", blockindex->nChainWork.GetHex());
147146
result.pushKV("arrivaltime", blockindex->GetBlockArrivalTime());
148147
result.pushKV("nTx", (uint64_t)blockindex->nTx);
@@ -232,7 +231,7 @@ UniValue blockToDeltasJSON(const CBlock& block, const CBlockIndex* tip, const CB
232231
result.pushKV("nonceUint32", (uint64_t)((uint32_t)block.nNonce.GetUint64(0)));
233232
result.pushKV("nonce", block.nNonce.GetHex());
234233
result.pushKV("bits", strprintf("%08x", block.nBits));
235-
result.pushKV("difficulty", GetDifficulty(blockindex));
234+
result.pushKV("difficulty", GetDifficulty(blockindex, false));
236235
result.pushKV("chainwork", blockindex->nChainWork.GetHex());
237236

238237
if (blockindex->pprev)
@@ -278,7 +277,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn
278277
result.pushKV("nonce", block.nNonce.GetHex());
279278
result.pushKV("solution", HexStr(block.nSolution));
280279
result.pushKV("bits", strprintf("%08x", block.nBits));
281-
result.pushKV("difficulty", GetDifficulty(blockindex));
280+
result.pushKV("difficulty", GetDifficulty(blockindex, false));
282281
result.pushKV("chainwork", blockindex->nChainWork.GetHex());
283282
result.pushKV("nTx", (uint64_t)blockindex->nTx);
284283

@@ -498,7 +497,7 @@ static UniValue getdifficulty(const JSONRPCRequest& request)
498497
}.Check(request);
499498

500499
LOCK(cs_main);
501-
return GetDifficulty(::ChainActive().Tip());
500+
return GetDifficulty(::ChainActive().Tip(), true);
502501
}
503502

504503
static std::string EntryDescriptionString()
@@ -1575,7 +1574,7 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
15751574
obj.pushKV("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1);
15761575
obj.pushKV("synced", !::ChainstateActive().IsInitialBlockDownload());
15771576
obj.pushKV("bestblockhash", tip->GetBlockHash().GetHex());
1578-
obj.pushKV("difficulty", (double)GetDifficulty(tip));
1577+
obj.pushKV("difficulty", (double)GetDifficulty(tip, true));
15791578
obj.pushKV("mediantime", (int64_t)tip->GetMedianTimePast());
15801579
obj.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), tip));
15811580
obj.pushKV("initialblockdownload", ::ChainstateActive().IsInitialBlockDownload());

src/rpc/blockchain.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ static constexpr int NUM_GETBLOCKSTATS_PERCENTILES = 5;
2727
* @return A floating point number that is a multiple of the main net minimum
2828
* difficulty (4295032833 hashes).
2929
*/
30-
double GetDifficulty(const CBlockIndex* blockindex);
30+
double GetDifficulty(const CBlockIndex* blockindex, bool networkDifficulty);
3131

3232
/** Callback for when block tip changed. */
3333
void RPCNotifyBlockChange(bool ibd, const CBlockIndex *);

src/rpc/mining.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ static UniValue getmininginfo(const JSONRPCRequest& request)
298298
obj.pushKV("blocks", (int)::ChainActive().Height());
299299
if (BlockAssembler::m_last_block_weight) obj.pushKV("currentblockweight", *BlockAssembler::m_last_block_weight);
300300
if (BlockAssembler::m_last_block_num_txs) obj.pushKV("currentblocktx", *BlockAssembler::m_last_block_num_txs);
301-
obj.pushKV("difficulty", (double)GetDifficulty(::ChainActive().Tip()));
301+
obj.pushKV("difficulty", (double)GetDifficulty(::ChainActive().Tip(), false));
302302
obj.pushKV("localsolps", getlocalsolps(request));
303303
obj.pushKV("networksolps", getnetworksolps(request));
304304
obj.pushKV("networkhashps", getnetworkhashps(request));

src/rpc/misc.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ UniValue getinfo(const JSONRPCRequest& request)
112112
if(g_connman)
113113
obj.pushKV("connections", (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL));
114114
obj.pushKV("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : std::string()));
115-
obj.pushKV("difficulty", (double)GetDifficulty(::ChainActive().Tip()));
115+
obj.pushKV("difficulty", (double)GetDifficulty(::ChainActive().Tip(), false));
116116
obj.pushKV("testnet", Params().NetworkIDString() == CBaseChainParams::TESTNET);
117117
#ifdef ENABLE_WALLET
118118
if (pwallet) {

src/test/blockchain_tests.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ static void RejectDifficultyMismatch(double difficulty, double expected_difficul
4141
static void TestDifficulty(uint32_t nbits, double expected_difficulty)
4242
{
4343
CBlockIndex* block_index = CreateBlockIndexWithNbits(nbits);
44-
double difficulty = GetDifficulty(block_index);
44+
double difficulty = GetDifficulty(block_index, false);
4545
delete block_index;
4646

4747
RejectDifficultyMismatch(difficulty, expected_difficulty);

src/test/pow_tests.cpp

+4-10
Original file line numberDiff line numberDiff line change
@@ -150,19 +150,16 @@ BOOST_AUTO_TEST_CASE(LegacyLwmaCalculateNextWorkRequired_test)
150150
const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);
151151
const auto params = chainParams->GetConsensus();
152152

153-
int64_t nPowTargetSpacing = params.nLegacyPowTargetSpacing;
154-
int64_t nLwmaAveragingWindow = params.nLegacyLwmaAveragingWindow;
155-
156153
std::vector<CBlockIndex> blocks(50);
157154
for (int i = 0; i < 50; i++) {
158155
blocks[i].pprev = i ? &blocks[i - 1] : nullptr;
159156
blocks[i].nHeight = i;
160-
blocks[i].nTime = 1269211443 + i * nPowTargetSpacing;
157+
blocks[i].nTime = 1269211443 + i * params.nPowTargetSpacing;
161158
blocks[i].nBits = 0x1d00ffff;
162159
blocks[i].nChainWork = i ? blocks[i - 1].nChainWork + GetBlockProof(blocks[i - 1]) : arith_uint256(0);
163160
}
164161

165-
int bits = LwmaCalculateNextWorkRequired(&blocks.back(), params, nPowTargetSpacing, nLwmaAveragingWindow);
162+
int bits = LwmaCalculateNextWorkRequired(&blocks.back(), params, true);
166163
BOOST_CHECK_EQUAL(bits, 0x1d010084);
167164
}
168165

@@ -171,19 +168,16 @@ BOOST_AUTO_TEST_CASE(LwmaCalculateNextWorkRequired_test)
171168
const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);
172169
const auto params = chainParams->GetConsensus();
173170

174-
int64_t nPowTargetSpacing = params.nPowTargetSpacing;
175-
int64_t nLwmaAveragingWindow = params.nLwmaAveragingWindow;
176-
177171
std::vector<CBlockIndex> blocks(50);
178172
for (int i = 0; i < 50; i++) {
179173
blocks[i].pprev = i ? &blocks[i - 1] : nullptr;
180174
blocks[i].nHeight = i;
181-
blocks[i].nTime = 1269211443 + i * nPowTargetSpacing;
175+
blocks[i].nTime = 1269211443 + i * params.nPowTargetSpacing;
182176
blocks[i].nBits = 0x1d00ffff;
183177
blocks[i].nChainWork = i ? blocks[i - 1].nChainWork + GetBlockProof(blocks[i - 1]) : arith_uint256(0);
184178
}
185179

186-
int bits = LwmaCalculateNextWorkRequired(&blocks.back(), params, nPowTargetSpacing, nLwmaAveragingWindow);
180+
int bits = LwmaCalculateNextWorkRequired(&blocks.back(), params, false);
187181
BOOST_CHECK_EQUAL(bits, 0x1d010084);
188182
}
189183

0 commit comments

Comments
 (0)