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:
zkbot
2016-09-08 02:21:13 +00:00
9 changed files with 249 additions and 224 deletions

70
src/gtest/test_pow.cpp Normal file
View 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));
}

View File

@@ -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) {