Any projects which want to use Hush code from now on will need to be licensed as GPLv3 or we will send the lawyers: https://www.softwarefreedom.org/ Notably, Komodo (KMD) is licensed as GPLv2 and is no longer compatible to receive code changes, without causing legal issues. MIT projects, such as Zcash, also cannot pull in changes from the Hush Full Node without permission from The Hush Developers, which may in some circumstances grant an MIT license on a case-by-case basis.
115 lines
5.2 KiB
C++
115 lines
5.2 KiB
C++
// Copyright (c) 2019-2020 The Hush developers
|
|
// Distributed under the GPLv3 software license, see the accompanying
|
|
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
|
|
#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].SetHeight(i);
|
|
blocks[i].nTime = 1269211443 + i * params.nPowTargetSpacing;
|
|
blocks[i].nBits = 0x1e7fffff; /* target 0x007fffff000... */
|
|
blocks[i].chainPower = i ? (CChainPower(&blocks[i]) + blocks[i - 1].chainPower) + GetBlockProof(blocks[i - 1]) : CChainPower(&blocks[i]);
|
|
}
|
|
|
|
// 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));
|
|
}
|
|
|
|
TEST(PoW, MinDifficultyRules) {
|
|
SelectParams(CBaseChainParams::TESTNET);
|
|
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 = params.nPowAllowMinDifficultyBlocksAfterHeight.get() + 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);
|
|
}
|
|
|
|
// Create a new block at the target spacing
|
|
CBlockHeader next;
|
|
next.nTime = blocks[lastBlk].nTime + params.nPowTargetSpacing;
|
|
|
|
// Result should be unchanged, modulo integer division precision loss
|
|
arith_uint256 bnRes;
|
|
bnRes.SetCompact(0x1e7fffff);
|
|
bnRes /= params.AveragingWindowTimespan();
|
|
bnRes *= params.AveragingWindowTimespan();
|
|
EXPECT_EQ(GetNextWorkRequired(&blocks[lastBlk], &next, params), bnRes.GetCompact());
|
|
|
|
// Delay last block up to the edge of the min-difficulty limit
|
|
next.nTime += params.nPowTargetSpacing * 5;
|
|
|
|
// Result should be unchanged, modulo integer division precision loss
|
|
EXPECT_EQ(GetNextWorkRequired(&blocks[lastBlk], &next, params), bnRes.GetCompact());
|
|
|
|
// Delay last block over the min-difficulty limit
|
|
next.nTime += 1;
|
|
|
|
// Result should be the minimum difficulty
|
|
EXPECT_EQ(GetNextWorkRequired(&blocks[lastBlk], &next, params),
|
|
UintToArith256(params.powLimit).GetCompact());
|
|
}
|