diff --git a/src/Makefile.test.include b/src/Makefile.test.include --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -37,6 +37,7 @@ test/base58_tests.cpp \ test/base64_tests.cpp \ test/bip32_tests.cpp \ + test/blockchain_tests.cpp \ test/blockcheck_tests.cpp \ test/blockencodings_tests.cpp \ test/blockfilter_tests.cpp \ diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h --- a/src/rpc/blockchain.h +++ b/src/rpc/blockchain.h @@ -15,8 +15,7 @@ UniValue getblockchaininfo(const Config &config, const JSONRPCRequest &request); /** - * Get the difficulty of the net wrt the given block index, or the chain tip - * if not provided. + * Get the required difficulty of the next block w/r/t the given block index. * * @return A floating point number that is a multiple of the main net minimum * difficulty (4295032833 hashes). diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -42,15 +42,19 @@ static std::condition_variable cond_blockchange; static CUpdatedBlock latestblock; -static double GetDifficultyFromBits(uint32_t nBits) { - int nShift = (nBits >> 24) & 0xff; - double dDiff = 0x0000ffff / double(nBits & 0x00ffffff); +/** + * Calculate the difficulty for a given block index. + */ +double GetDifficulty(const CBlockIndex *blockindex) { + assert(blockindex); + + int nShift = (blockindex->nBits >> 24) & 0xff; + double dDiff = double(0x0000ffff) / double(blockindex->nBits & 0x00ffffff); while (nShift < 29) { dDiff *= 256.0; nShift++; } - while (nShift > 29) { dDiff /= 256.0; nShift--; @@ -59,12 +63,6 @@ return dDiff; } -double GetDifficulty(const CBlockIndex *blockindex) { - assert(blockindex); - - return GetDifficultyFromBits(blockindex->nBits); -} - static int ComputeNextBlockAndDepth(const CBlockIndex *tip, const CBlockIndex *blockindex, const CBlockIndex *&next) { diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -55,6 +55,7 @@ base58_tests.cpp base64_tests.cpp bip32_tests.cpp + blockchain_tests.cpp blockcheck_tests.cpp blockencodings_tests.cpp blockfilter_tests.cpp diff --git a/src/test/blockchain_tests.cpp b/src/test/blockchain_tests.cpp new file mode 100644 --- /dev/null +++ b/src/test/blockchain_tests.cpp @@ -0,0 +1,69 @@ +#include + +#include + +#include + +#include + +#include + +/** + * Equality between doubles is imprecise. Comparison should be done + * with a small threshold of tolerance, rather than exact equality. + */ +static bool DoubleEquals(double a, double b, double epsilon) { + return std::abs(a - b) < epsilon; +} + +static CBlockIndex *CreateBlockIndexWithNbits(uint32_t nbits) { + CBlockIndex *block_index = new CBlockIndex(); + block_index->nHeight = 46367; + block_index->nTime = 1269211443; + block_index->nBits = nbits; + return block_index; +} + +static void RejectDifficultyMismatch(double difficulty, + double expected_difficulty) { + BOOST_CHECK_MESSAGE(DoubleEquals(difficulty, expected_difficulty, 0.00001), + "Difficulty was " + std::to_string(difficulty) + + " but was expected to be " + + std::to_string(expected_difficulty)); +} + +/** + * Given a BlockIndex with the provided nbits, + * verify that the expected difficulty results. + */ +static void TestDifficulty(uint32_t nbits, double expected_difficulty) { + CBlockIndex *block_index = CreateBlockIndexWithNbits(nbits); + double difficulty = GetDifficulty(block_index); + delete block_index; + + RejectDifficultyMismatch(difficulty, expected_difficulty); +} + +BOOST_FIXTURE_TEST_SUITE(blockchain_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(get_difficulty_for_very_low_target) { + TestDifficulty(0x1f111111, 0.000001); +} + +BOOST_AUTO_TEST_CASE(get_difficulty_for_low_target) { + TestDifficulty(0x1ef88f6f, 0.000016); +} + +BOOST_AUTO_TEST_CASE(get_difficulty_for_mid_target) { + TestDifficulty(0x1df88f6f, 0.004023); +} + +BOOST_AUTO_TEST_CASE(get_difficulty_for_high_target) { + TestDifficulty(0x1cf88f6f, 1.029916); +} + +BOOST_AUTO_TEST_CASE(get_difficulty_for_very_high_target) { + TestDifficulty(0x12345678, 5913134931067755359633408.0); +} + +BOOST_AUTO_TEST_SUITE_END()