aboutsummaryrefslogtreecommitdiff
path: root/src/test/blockfilter_index_tests.cpp
diff options
context:
space:
mode:
authorJim Posen <jim.posen@gmail.com>2018-08-28 09:04:09 -0700
committerJim Posen <jim.posen@gmail.com>2019-04-06 12:10:22 -0700
commit2bc90e4e7bf7fef56830b33b1fba678fd0dbd6d8 (patch)
tree11df4de2628d6a6edad4b8eda0383191cd5c1772 /src/test/blockfilter_index_tests.cpp
parent6bcf0998c0b4111cadb9f0d58454266d41fd758b (diff)
downloadbitcoin-2bc90e4e7bf7fef56830b33b1fba678fd0dbd6d8.tar.xz
test: Unit test for block filter index reorg handling.
Diffstat (limited to 'src/test/blockfilter_index_tests.cpp')
-rw-r--r--src/test/blockfilter_index_tests.cpp142
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();