diff options
author | Jim Posen <jim.posen@gmail.com> | 2018-08-28 09:04:09 -0700 |
---|---|---|
committer | Jim Posen <jim.posen@gmail.com> | 2019-04-06 12:10:22 -0700 |
commit | 2bc90e4e7bf7fef56830b33b1fba678fd0dbd6d8 (patch) | |
tree | 11df4de2628d6a6edad4b8eda0383191cd5c1772 /src/test | |
parent | 6bcf0998c0b4111cadb9f0d58454266d41fd758b (diff) | |
download | bitcoin-2bc90e4e7bf7fef56830b33b1fba678fd0dbd6d8.tar.xz |
test: Unit test for block filter index reorg handling.
Diffstat (limited to 'src/test')
-rw-r--r-- | src/test/blockfilter_index_tests.cpp | 142 |
1 files changed, 130 insertions, 12 deletions
diff --git a/src/test/blockfilter_index_tests.cpp b/src/test/blockfilter_index_tests.cpp index 5d2c1f1139..5893030971 100644 --- a/src/test/blockfilter_index_tests.cpp +++ b/src/test/blockfilter_index_tests.cpp @@ -4,7 +4,10 @@ #include <blockfilter.h> #include <chainparams.h> +#include <consensus/validation.h> #include <index/blockfilterindex.h> +#include <miner.h> +#include <pow.h> #include <test/test_bitcoin.h> #include <script/standard.h> #include <validation.h> @@ -64,6 +67,49 @@ static bool CheckFilterLookups(BlockFilterIndex& filter_index, const CBlockIndex return true; } +static CBlock CreateBlock(const CBlockIndex* prev, + const std::vector<CMutableTransaction>& txns, + const CScript& scriptPubKey) +{ + const CChainParams& chainparams = Params(); + std::unique_ptr<CBlockTemplate> pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey); + CBlock& block = pblocktemplate->block; + block.hashPrevBlock = prev->GetBlockHash(); + block.nTime = prev->nTime + 1; + + // Replace mempool-selected txns with just coinbase plus passed-in txns: + block.vtx.resize(1); + for (const CMutableTransaction& tx : txns) { + block.vtx.push_back(MakeTransactionRef(tx)); + } + // IncrementExtraNonce creates a valid coinbase and merkleRoot + unsigned int extraNonce = 0; + IncrementExtraNonce(&block, prev, extraNonce); + + while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce; + + return block; +} + +static bool BuildChain(const CBlockIndex* pindex, const CScript& coinbase_script_pub_key, + size_t length, std::vector<std::shared_ptr<CBlock>>& chain) +{ + std::vector<CMutableTransaction> no_txns; + + chain.resize(length); + for (auto& block : chain) { + block = std::make_shared<CBlock>(CreateBlock(pindex, no_txns, coinbase_script_pub_key)); + CBlockHeader header = block->GetBlockHeader(); + + CValidationState state; + if (!ProcessNewBlockHeaders({header}, state, Params(), &pindex, nullptr)) { + return false; + } + } + + return true; +} + BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, TestChain100Setup) { BlockFilterIndex filter_index(BlockFilterType::BASIC, 1 << 20, true); @@ -114,31 +160,103 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, TestChain100Setup) } } - // Check that new blocks get indexed. - for (int i = 0; i < 10; i++) { - CScript coinbase_script_pub_key = GetScriptForDestination(coinbaseKey.GetPubKey().GetID()); - std::vector<CMutableTransaction> no_txns; - const CBlock& block = CreateAndProcessBlock(no_txns, coinbase_script_pub_key); + // Create two forks. + const CBlockIndex* tip; + { + LOCK(cs_main); + tip = chainActive.Tip(); + } + CScript coinbase_script_pub_key = GetScriptForDestination(coinbaseKey.GetPubKey().GetID()); + std::vector<std::shared_ptr<CBlock>> chainA, chainB; + BOOST_REQUIRE(BuildChain(tip, coinbase_script_pub_key, 10, chainA)); + BOOST_REQUIRE(BuildChain(tip, coinbase_script_pub_key, 10, chainB)); + + // Check that new blocks on chain A get indexed. + uint256 chainA_last_header = last_header; + for (size_t i = 0; i < 2; i++) { + const auto& block = chainA[i]; + BOOST_REQUIRE(ProcessNewBlock(Params(), block, true, nullptr)); + const CBlockIndex* block_index; { LOCK(cs_main); - block_index = LookupBlockIndex(block.GetHash()); + block_index = LookupBlockIndex(block->GetHash()); } BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain()); - CheckFilterLookups(filter_index, block_index, last_header); + CheckFilterLookups(filter_index, block_index, chainA_last_header); } + // Reorg to chain B. + uint256 chainB_last_header = last_header; + for (size_t i = 0; i < 3; i++) { + const auto& block = chainB[i]; + BOOST_REQUIRE(ProcessNewBlock(Params(), block, true, nullptr)); + + const CBlockIndex* block_index; + { + LOCK(cs_main); + block_index = LookupBlockIndex(block->GetHash()); + } + + BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain()); + CheckFilterLookups(filter_index, block_index, chainB_last_header); + } + + // Check that filters for stale blocks on A can be retrieved. + chainA_last_header = last_header; + for (size_t i = 0; i < 2; i++) { + const auto& block = chainA[i]; + const CBlockIndex* block_index; + { + LOCK(cs_main); + block_index = LookupBlockIndex(block->GetHash()); + } + + BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain()); + CheckFilterLookups(filter_index, block_index, chainA_last_header); + } + + // Reorg back to chain A. + for (size_t i = 2; i < 4; i++) { + const auto& block = chainA[i]; + BOOST_REQUIRE(ProcessNewBlock(Params(), block, true, nullptr)); + } + + // Check that chain A and B blocks can be retrieved. + chainA_last_header = last_header; + chainB_last_header = last_header; + for (size_t i = 0; i < 3; i++) { + const CBlockIndex* block_index; + + { + LOCK(cs_main); + block_index = LookupBlockIndex(chainA[i]->GetHash()); + } + BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain()); + CheckFilterLookups(filter_index, block_index, chainA_last_header); + + { + LOCK(cs_main); + block_index = LookupBlockIndex(chainB[i]->GetHash()); + } + BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain()); + CheckFilterLookups(filter_index, block_index, chainB_last_header); + } + // Test lookups for a range of filters/hashes. std::vector<BlockFilter> filters; std::vector<uint256> filter_hashes; - const CBlockIndex* block_index = chainActive.Tip(); - BOOST_CHECK(filter_index.LookupFilterRange(0, block_index, filters)); - BOOST_CHECK(filter_index.LookupFilterHashRange(0, block_index, filter_hashes)); + { + LOCK(cs_main); + tip = chainActive.Tip(); + } + BOOST_CHECK(filter_index.LookupFilterRange(0, tip, filters)); + BOOST_CHECK(filter_index.LookupFilterHashRange(0, tip, filter_hashes)); - BOOST_CHECK_EQUAL(filters.size(), chainActive.Height() + 1); - BOOST_CHECK_EQUAL(filter_hashes.size(), chainActive.Height() + 1); + BOOST_CHECK_EQUAL(filters.size(), tip->nHeight + 1); + BOOST_CHECK_EQUAL(filter_hashes.size(), tip->nHeight + 1); filters.clear(); filter_hashes.clear(); |