diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index aacefb3f85c..b4c1ec69339 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -26,6 +26,7 @@ add_executable(test_bitcoin bloom_tests.cpp bswap_tests.cpp caches_tests.cpp + chain_tests.cpp chainstate_write_tests.cpp checkqueue_tests.cpp cluster_linearize_tests.cpp diff --git a/src/test/chain_tests.cpp b/src/test/chain_tests.cpp new file mode 100644 index 00000000000..a782e880f9f --- /dev/null +++ b/src/test/chain_tests.cpp @@ -0,0 +1,85 @@ +// Copyright (c) The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include + +#include + +BOOST_FIXTURE_TEST_SUITE(chain_tests, BasicTestingSetup) + +namespace { + +const CBlockIndex* NaiveGetAncestor(const CBlockIndex* a, int height) +{ + while (a->nHeight > height) { + a = a->pprev; + } + BOOST_REQUIRE_EQUAL(a->nHeight, height); + return a; +} + +const CBlockIndex* NaiveLastCommonAncestor(const CBlockIndex* a, const CBlockIndex* b) +{ + while (a->nHeight > b->nHeight) { + a = a->pprev; + } + while (b->nHeight > a->nHeight) { + b = b->pprev; + } + while (a != b) { + BOOST_REQUIRE_EQUAL(a->nHeight, b->nHeight); + a = a->pprev; + b = b->pprev; + } + BOOST_REQUIRE_EQUAL(a, b); + return a; +} + +} // namespace + +BOOST_AUTO_TEST_CASE(chain_test) +{ + FastRandomContext ctx; + std::vector> block_index; + // Run 10 iterations of the whole test. + for (int i = 0; i < 10; ++i) { + block_index.clear(); + // Create genesis block. + auto genesis = std::make_unique(); + genesis->nHeight = 0; + block_index.push_back(std::move(genesis)); + // Create 10000 more blocks. + for (int b = 0; b < 10000; ++b) { + auto new_index = std::make_unique(); + // 95% of blocks build on top of the last block; the others fork off randomly. + if (ctx.randrange(20) != 0) { + new_index->pprev = block_index.back().get(); + } else { + new_index->pprev = block_index[ctx.randrange(block_index.size())].get(); + } + new_index->nHeight = new_index->pprev->nHeight + 1; + new_index->BuildSkip(); + block_index.push_back(std::move(new_index)); + } + // Run 10000 random GetAncestor queries. + for (int q = 0; q < 10000; ++q) { + const CBlockIndex* block = block_index[ctx.randrange(block_index.size())].get(); + unsigned height = ctx.randrange(block->nHeight + 1); + const CBlockIndex* result = block->GetAncestor(height); + BOOST_CHECK(result == NaiveGetAncestor(block, height)); + } + // Run 10000 random LastCommonAncestor queries. + for (int q = 0; q < 10000; ++q) { + const CBlockIndex* block1 = block_index[ctx.randrange(block_index.size())].get(); + const CBlockIndex* block2 = block_index[ctx.randrange(block_index.size())].get(); + const CBlockIndex* result = LastCommonAncestor(block1, block2); + BOOST_CHECK(result == NaiveLastCommonAncestor(block1, block2)); + } + } +} + +BOOST_AUTO_TEST_SUITE_END()