test: Unit test for block filter index reorg handling.
This commit is contained in:
parent
6bcf0998c0
commit
2bc90e4e7b
1 changed files with 130 additions and 12 deletions
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue