Auto merge of #1338 - str4d:147-tweak-difficulty-adjustment-algorithm, r=ebfull
Tweaks to difficulty adjustment algorithm This PR changes the difficulty algorithm to adjust from the average difficulty over the block window instead of from the last difficulty. It also removes the special rules for the testnet, which are incompatible with difficulty averaging. Closes #147 again.
This commit is contained in:
70
src/gtest/test_pow.cpp
Normal file
70
src/gtest/test_pow.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "chain.h"
|
||||
#include "chainparams.h"
|
||||
#include "pow.h"
|
||||
#include "random.h"
|
||||
|
||||
TEST(PoW, DifficultyAveraging) {
|
||||
SelectParams(CBaseChainParams::MAIN);
|
||||
const Consensus::Params& params = Params().GetConsensus();
|
||||
size_t lastBlk = 2*params.nPowAveragingWindow;
|
||||
size_t firstBlk = lastBlk - params.nPowAveragingWindow;
|
||||
|
||||
// Start with blocks evenly-spaced and equal difficulty
|
||||
std::vector<CBlockIndex> blocks(lastBlk+1);
|
||||
for (int i = 0; i <= lastBlk; i++) {
|
||||
blocks[i].pprev = i ? &blocks[i - 1] : nullptr;
|
||||
blocks[i].nHeight = i;
|
||||
blocks[i].nTime = 1269211443 + i * params.nPowTargetSpacing;
|
||||
blocks[i].nBits = 0x1e7fffff; /* target 0x007fffff000... */
|
||||
blocks[i].nChainWork = i ? blocks[i - 1].nChainWork + GetBlockProof(blocks[i - 1]) : arith_uint256(0);
|
||||
}
|
||||
|
||||
// Result should be the same as if last difficulty was used
|
||||
arith_uint256 bnAvg;
|
||||
bnAvg.SetCompact(blocks[lastBlk].nBits);
|
||||
EXPECT_EQ(CalculateNextWorkRequired(bnAvg,
|
||||
blocks[lastBlk].GetMedianTimePast(),
|
||||
blocks[firstBlk].GetMedianTimePast(),
|
||||
params),
|
||||
GetNextWorkRequired(&blocks[lastBlk], nullptr, params));
|
||||
// Result should be unchanged, modulo integer division precision loss
|
||||
arith_uint256 bnRes;
|
||||
bnRes.SetCompact(0x1e7fffff);
|
||||
bnRes /= params.AveragingWindowTimespan();
|
||||
bnRes *= params.AveragingWindowTimespan();
|
||||
EXPECT_EQ(bnRes.GetCompact(), GetNextWorkRequired(&blocks[lastBlk], nullptr, params));
|
||||
|
||||
// Randomise the final block time (plus 1 to ensure it is always different)
|
||||
blocks[lastBlk].nTime += GetRand(params.nPowTargetSpacing/2) + 1;
|
||||
|
||||
// Result should be the same as if last difficulty was used
|
||||
bnAvg.SetCompact(blocks[lastBlk].nBits);
|
||||
EXPECT_EQ(CalculateNextWorkRequired(bnAvg,
|
||||
blocks[lastBlk].GetMedianTimePast(),
|
||||
blocks[firstBlk].GetMedianTimePast(),
|
||||
params),
|
||||
GetNextWorkRequired(&blocks[lastBlk], nullptr, params));
|
||||
// Result should not be unchanged
|
||||
EXPECT_NE(0x1e7fffff, GetNextWorkRequired(&blocks[lastBlk], nullptr, params));
|
||||
|
||||
// Change the final block difficulty
|
||||
blocks[lastBlk].nBits = 0x1e0fffff;
|
||||
|
||||
// Result should not be the same as if last difficulty was used
|
||||
bnAvg.SetCompact(blocks[lastBlk].nBits);
|
||||
EXPECT_NE(CalculateNextWorkRequired(bnAvg,
|
||||
blocks[lastBlk].GetMedianTimePast(),
|
||||
blocks[firstBlk].GetMedianTimePast(),
|
||||
params),
|
||||
GetNextWorkRequired(&blocks[lastBlk], nullptr, params));
|
||||
|
||||
// Result should be the same as if the average difficulty was used
|
||||
arith_uint256 average = UintToArith256(uint256S("0000796968696969696969696969696969696969696969696969696969696969"));
|
||||
EXPECT_EQ(CalculateNextWorkRequired(average,
|
||||
blocks[lastBlk].GetMedianTimePast(),
|
||||
blocks[firstBlk].GetMedianTimePast(),
|
||||
params),
|
||||
GetNextWorkRequired(&blocks[lastBlk], nullptr, params));
|
||||
}
|
||||
@@ -10,33 +10,6 @@
|
||||
#include "streams.h"
|
||||
#include "utilstrencodings.h"
|
||||
|
||||
TEST(rpc, GetDifficultyTestnetRules) {
|
||||
SelectParams(CBaseChainParams::TESTNET);
|
||||
|
||||
CBlockIndex prev;
|
||||
prev.nTime = 1472700000;
|
||||
prev.nBits = 0x201fffff;
|
||||
|
||||
CBlockIndex curr;
|
||||
curr.pprev = &prev;
|
||||
curr.nTime = 1472700300;
|
||||
curr.nBits = 0x207fffff;
|
||||
|
||||
// Time interval is within 5 minutes, so the min-difficulty block should be
|
||||
// interpreted as a valid network difficulty.
|
||||
EXPECT_EQ(1, GetDifficulty(&curr));
|
||||
EXPECT_EQ(1, GetNetworkDifficulty(&curr));
|
||||
|
||||
curr.nTime += 1;
|
||||
|
||||
// Time interval is over 5 minutes, so the min-difficulty block should be
|
||||
// ignored for network difficulty determination.
|
||||
EXPECT_EQ(1, GetDifficulty(&curr));
|
||||
// We have to check this directly, because of some combination of rounding
|
||||
// and truncation issues that result in Google Test displaying 4 != 4
|
||||
EXPECT_EQ((double)0x7fffff/(double)0x1fffff, GetNetworkDifficulty(&curr));
|
||||
}
|
||||
|
||||
extern json_spirit::Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false);
|
||||
|
||||
TEST(rpc, check_blockToJSON_returns_minified_solution) {
|
||||
|
||||
Reference in New Issue
Block a user