diff --git a/src/test/blockindex_tests.cpp b/src/test/blockindex_tests.cpp --- a/src/test/blockindex_tests.cpp +++ b/src/test/blockindex_tests.cpp @@ -87,6 +87,27 @@ } } +BOOST_AUTO_TEST_CASE(get_block_hash) { + CBlockIndex index = CBlockIndex(); + + /* Test with all 0 hash */ + const uint256 zeroHash = uint256(); + index.phashBlock = &zeroHash; + uint256 hash = index.GetBlockHash(); + BOOST_CHECK(hash == zeroHash); + + /* Test with a random hash */ + std::vector hashBytes(32); + + std::generate(hashBytes.begin(), hashBytes.end(), + []() { return uint8_t(rand() % 255); }); + + const uint256 randomHash = uint256(hashBytes); + index.phashBlock = &randomHash; + hash = index.GetBlockHash(); + BOOST_CHECK(hash == randomHash); +} + BOOST_AUTO_TEST_CASE(received_time) { // Set to UINT32_MAX because that's the maximum value header.nTime can hold const int64_t expectedBlockTime = std::numeric_limits::max(); @@ -163,6 +184,81 @@ } } +BOOST_AUTO_TEST_CASE(to_string) { + CBlockHeader header = CBlockHeader(); + header.hashMerkleRoot = uint256(); + + CBlockIndex index = CBlockIndex(header); + const uint256 hashBlock = uint256(); + index.phashBlock = &hashBlock; + index.nHeight = 123; + + CBlockIndex indexPrev = CBlockIndex(); + + std::string expectedString = ""; + std::string indexString = ""; + + /* CASE 1 : pprev is null */ + expectedString = + "CBlockIndex(pprev=0, nHeight=123, " + "merkle=" + "0000000000000000000000000000000000000000000000000000000000000000, " + "hashBlock=" + "0000000000000000000000000000000000000000000000000000000000000000)"; + index.pprev = nullptr; + indexString = index.ToString(); + BOOST_CHECK(indexString == expectedString); + + /* CASE 2 : pprev is indexPrev */ + expectedString = strprintf( + "CBlockIndex(pprev=%p, nHeight=123, " + "merkle=" + "0000000000000000000000000000000000000000000000000000000000000000, " + "hashBlock=" + "0000000000000000000000000000000000000000000000000000000000000000)", + &indexPrev); + index.pprev = &indexPrev; + indexString = index.ToString(); + BOOST_CHECK(indexString == expectedString); + + /* CASE 3 : height is max(int) */ + expectedString = strprintf( + "CBlockIndex(pprev=%p, nHeight=2147483647, " + "merkle=" + "0000000000000000000000000000000000000000000000000000000000000000, " + "hashBlock=" + "0000000000000000000000000000000000000000000000000000000000000000)", + &indexPrev); + index.nHeight = INT32_MAX; + indexString = index.ToString(); + BOOST_CHECK(indexString == expectedString); + + /* CASE 4 : set some Merkle root hash */ + expectedString = strprintf( + "CBlockIndex(pprev=%p, nHeight=2147483647, " + "merkle=" + "0000000000000000000000000000000000000000000000000123456789abcdef, " + "hashBlock=" + "0000000000000000000000000000000000000000000000000000000000000000)", + &indexPrev); + index.hashMerkleRoot = uint256S("0123456789ABCDEF"); + indexString = index.ToString(); + BOOST_CHECK(indexString == expectedString); + + /* CASE 5 : set some block hash */ + expectedString = strprintf( + "CBlockIndex(pprev=%p, nHeight=2147483647, " + "merkle=" + "0000000000000000000000000000000000000000000000000123456789abcdef, " + "hashBlock=" + "000000000000000000000000000000000000000000000000fedcba9876543210)", + &indexPrev); + const uint256 emptyHashBlock = uint256S("FEDCBA9876543210"); + index.phashBlock = &emptyHashBlock; + indexString = index.ToString(); + BOOST_CHECK(indexString == expectedString); +} + BOOST_AUTO_TEST_CASE(index_validity_tests) { CBlockIndex index; @@ -220,4 +316,108 @@ } } +BOOST_AUTO_TEST_CASE(index_ancestors) { + std::array indexes; + + /* Check the skip pointer don't build when there is no precedence */ + for (size_t i = 0; i < indexes.size(); i++) { + indexes[i] = CBlockIndex(); + indexes[i].nHeight = i; + + indexes[i].pprev = nullptr; + indexes[i].pskip = nullptr; + + indexes[i].BuildSkip(); + + /* Check that skip not rebuilt if there is no preceding index */ + BOOST_CHECK(indexes[i].pskip == nullptr); + } + + for (size_t i = 0; i < indexes.size(); i++) { + if (i > 0) { + indexes[i].pprev = &indexes[i - 1]; + indexes[i].BuildSkip(); + + /* Check that skip is built */ + BOOST_CHECK(indexes[i].pskip != nullptr); + + /* + * Starting from height 2, pskip should be more efficient that + * pprev. + * Ensure pskip.nHeight < pprev.nHeight + */ + if (i > 1) { + BOOST_CHECK(indexes[i].pskip->nHeight < + indexes[i].pprev->nHeight); + } + + /* Find an ancestor 16 indexes behind */ + if (i > 16) { + CBlockIndex *ancestor = + indexes[i].GetAncestor(indexes[i].nHeight - 16); + BOOST_CHECK(ancestor != nullptr); + BOOST_CHECK(ancestor->nHeight == (indexes[i].nHeight - 16)); + } + } + } + + /* + * Reorder these indexes to setup multiple branches: + * + * (248)->(...)->(255) + * / + * (128)->(...)->(191)->(...)->(247) + * / + * (0)->(...)->(63)->(...)->(127) + */ + for (size_t i = 0; i < indexes.size(); i++) { + /* Build the tree */ + indexes[i].pskip = nullptr; + if (i > 0) { + indexes[i].pprev = &indexes[i - 1]; + } + if (i < 128) { + indexes[i].nHeight = i; + } else if (i < 248) { + /* Branch at 128 */ + if (i == 128) { + indexes[i].pprev = &indexes[63]; + } + indexes[i].nHeight = i - 64; + } else { + /* Branch at 248 */ + if (i == 248) { + indexes[i].pprev = &indexes[191]; + } + indexes[i].nHeight = i - 128 + 8; + } + + /* Build and test skip pointer */ + if (i > 0) { + indexes[i].BuildSkip(); + + /* Check that skip is built */ + BOOST_CHECK(indexes[i].pskip != nullptr); + + /* + * Starting from height 2, pskip should be more efficient that + * pprev. + * Ensure pskip.nHeight < pprev.nHeight + */ + if (i > 1) { + BOOST_CHECK(indexes[i].pskip->nHeight < + indexes[i].pprev->nHeight); + } + } + + /* Find an ancestor 37 indexes behind */ + if (i > 37) { + CBlockIndex *ancestor = + indexes[i].GetAncestor(indexes[i].nHeight - 37); + BOOST_CHECK(ancestor != nullptr); + BOOST_CHECK(ancestor->nHeight == (indexes[i].nHeight - 37)); + } + } +} + BOOST_AUTO_TEST_SUITE_END()