|
4 | 4 |
|
5 | 5 | #include <blockfilter.h>
|
6 | 6 | #include <chainparams.h>
|
| 7 | +#include <consensus/validation.h> |
7 | 8 | #include <index/blockfilterindex.h>
|
| 9 | +#include <miner.h> |
| 10 | +#include <pow.h> |
8 | 11 | #include <test/test_bitcoin.h>
|
9 | 12 | #include <script/standard.h>
|
10 | 13 | #include <validation.h>
|
@@ -64,6 +67,49 @@ static bool CheckFilterLookups(BlockFilterIndex& filter_index, const CBlockIndex
|
64 | 67 | return true;
|
65 | 68 | }
|
66 | 69 |
|
| 70 | +static CBlock CreateBlock(const CBlockIndex* prev, |
| 71 | + const std::vector<CMutableTransaction>& txns, |
| 72 | + const CScript& scriptPubKey) |
| 73 | +{ |
| 74 | + const CChainParams& chainparams = Params(); |
| 75 | + std::unique_ptr<CBlockTemplate> pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey); |
| 76 | + CBlock& block = pblocktemplate->block; |
| 77 | + block.hashPrevBlock = prev->GetBlockHash(); |
| 78 | + block.nTime = prev->nTime + 1; |
| 79 | + |
| 80 | + // Replace mempool-selected txns with just coinbase plus passed-in txns: |
| 81 | + block.vtx.resize(1); |
| 82 | + for (const CMutableTransaction& tx : txns) { |
| 83 | + block.vtx.push_back(MakeTransactionRef(tx)); |
| 84 | + } |
| 85 | + // IncrementExtraNonce creates a valid coinbase and merkleRoot |
| 86 | + unsigned int extraNonce = 0; |
| 87 | + IncrementExtraNonce(&block, prev, extraNonce); |
| 88 | + |
| 89 | + while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce; |
| 90 | + |
| 91 | + return block; |
| 92 | +} |
| 93 | + |
| 94 | +static bool BuildChain(const CBlockIndex* pindex, const CScript& coinbase_script_pub_key, |
| 95 | + size_t length, std::vector<std::shared_ptr<CBlock>>& chain) |
| 96 | +{ |
| 97 | + std::vector<CMutableTransaction> no_txns; |
| 98 | + |
| 99 | + chain.resize(length); |
| 100 | + for (auto& block : chain) { |
| 101 | + block = std::make_shared<CBlock>(CreateBlock(pindex, no_txns, coinbase_script_pub_key)); |
| 102 | + CBlockHeader header = block->GetBlockHeader(); |
| 103 | + |
| 104 | + CValidationState state; |
| 105 | + if (!ProcessNewBlockHeaders({header}, state, Params(), &pindex, nullptr)) { |
| 106 | + return false; |
| 107 | + } |
| 108 | + } |
| 109 | + |
| 110 | + return true; |
| 111 | +} |
| 112 | + |
67 | 113 | BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, TestChain100Setup)
|
68 | 114 | {
|
69 | 115 | BlockFilterIndex filter_index(BlockFilterType::BASIC, 1 << 20, true);
|
@@ -114,31 +160,103 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, TestChain100Setup)
|
114 | 160 | }
|
115 | 161 | }
|
116 | 162 |
|
117 |
| - // Check that new blocks get indexed. |
118 |
| - for (int i = 0; i < 10; i++) { |
119 |
| - CScript coinbase_script_pub_key = GetScriptForDestination(coinbaseKey.GetPubKey().GetID()); |
120 |
| - std::vector<CMutableTransaction> no_txns; |
121 |
| - const CBlock& block = CreateAndProcessBlock(no_txns, coinbase_script_pub_key); |
| 163 | + // Create two forks. |
| 164 | + const CBlockIndex* tip; |
| 165 | + { |
| 166 | + LOCK(cs_main); |
| 167 | + tip = chainActive.Tip(); |
| 168 | + } |
| 169 | + CScript coinbase_script_pub_key = GetScriptForDestination(coinbaseKey.GetPubKey().GetID()); |
| 170 | + std::vector<std::shared_ptr<CBlock>> chainA, chainB; |
| 171 | + BOOST_REQUIRE(BuildChain(tip, coinbase_script_pub_key, 10, chainA)); |
| 172 | + BOOST_REQUIRE(BuildChain(tip, coinbase_script_pub_key, 10, chainB)); |
| 173 | + |
| 174 | + // Check that new blocks on chain A get indexed. |
| 175 | + uint256 chainA_last_header = last_header; |
| 176 | + for (size_t i = 0; i < 2; i++) { |
| 177 | + const auto& block = chainA[i]; |
| 178 | + BOOST_REQUIRE(ProcessNewBlock(Params(), block, true, nullptr)); |
| 179 | + |
122 | 180 | const CBlockIndex* block_index;
|
123 | 181 | {
|
124 | 182 | LOCK(cs_main);
|
125 |
| - block_index = LookupBlockIndex(block.GetHash()); |
| 183 | + block_index = LookupBlockIndex(block->GetHash()); |
126 | 184 | }
|
127 | 185 |
|
128 | 186 | BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
|
129 |
| - CheckFilterLookups(filter_index, block_index, last_header); |
| 187 | + CheckFilterLookups(filter_index, block_index, chainA_last_header); |
130 | 188 | }
|
131 | 189 |
|
| 190 | + // Reorg to chain B. |
| 191 | + uint256 chainB_last_header = last_header; |
| 192 | + for (size_t i = 0; i < 3; i++) { |
| 193 | + const auto& block = chainB[i]; |
| 194 | + BOOST_REQUIRE(ProcessNewBlock(Params(), block, true, nullptr)); |
| 195 | + |
| 196 | + const CBlockIndex* block_index; |
| 197 | + { |
| 198 | + LOCK(cs_main); |
| 199 | + block_index = LookupBlockIndex(block->GetHash()); |
| 200 | + } |
| 201 | + |
| 202 | + BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain()); |
| 203 | + CheckFilterLookups(filter_index, block_index, chainB_last_header); |
| 204 | + } |
| 205 | + |
| 206 | + // Check that filters for stale blocks on A can be retrieved. |
| 207 | + chainA_last_header = last_header; |
| 208 | + for (size_t i = 0; i < 2; i++) { |
| 209 | + const auto& block = chainA[i]; |
| 210 | + const CBlockIndex* block_index; |
| 211 | + { |
| 212 | + LOCK(cs_main); |
| 213 | + block_index = LookupBlockIndex(block->GetHash()); |
| 214 | + } |
| 215 | + |
| 216 | + BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain()); |
| 217 | + CheckFilterLookups(filter_index, block_index, chainA_last_header); |
| 218 | + } |
| 219 | + |
| 220 | + // Reorg back to chain A. |
| 221 | + for (size_t i = 2; i < 4; i++) { |
| 222 | + const auto& block = chainA[i]; |
| 223 | + BOOST_REQUIRE(ProcessNewBlock(Params(), block, true, nullptr)); |
| 224 | + } |
| 225 | + |
| 226 | + // Check that chain A and B blocks can be retrieved. |
| 227 | + chainA_last_header = last_header; |
| 228 | + chainB_last_header = last_header; |
| 229 | + for (size_t i = 0; i < 3; i++) { |
| 230 | + const CBlockIndex* block_index; |
| 231 | + |
| 232 | + { |
| 233 | + LOCK(cs_main); |
| 234 | + block_index = LookupBlockIndex(chainA[i]->GetHash()); |
| 235 | + } |
| 236 | + BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain()); |
| 237 | + CheckFilterLookups(filter_index, block_index, chainA_last_header); |
| 238 | + |
| 239 | + { |
| 240 | + LOCK(cs_main); |
| 241 | + block_index = LookupBlockIndex(chainB[i]->GetHash()); |
| 242 | + } |
| 243 | + BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain()); |
| 244 | + CheckFilterLookups(filter_index, block_index, chainB_last_header); |
| 245 | + } |
| 246 | + |
132 | 247 | // Test lookups for a range of filters/hashes.
|
133 | 248 | std::vector<BlockFilter> filters;
|
134 | 249 | std::vector<uint256> filter_hashes;
|
135 | 250 |
|
136 |
| - const CBlockIndex* block_index = chainActive.Tip(); |
137 |
| - BOOST_CHECK(filter_index.LookupFilterRange(0, block_index, filters)); |
138 |
| - BOOST_CHECK(filter_index.LookupFilterHashRange(0, block_index, filter_hashes)); |
| 251 | + { |
| 252 | + LOCK(cs_main); |
| 253 | + tip = chainActive.Tip(); |
| 254 | + } |
| 255 | + BOOST_CHECK(filter_index.LookupFilterRange(0, tip, filters)); |
| 256 | + BOOST_CHECK(filter_index.LookupFilterHashRange(0, tip, filter_hashes)); |
139 | 257 |
|
140 |
| - BOOST_CHECK_EQUAL(filters.size(), chainActive.Height() + 1); |
141 |
| - BOOST_CHECK_EQUAL(filter_hashes.size(), chainActive.Height() + 1); |
| 258 | + BOOST_CHECK_EQUAL(filters.size(), tip->nHeight + 1); |
| 259 | + BOOST_CHECK_EQUAL(filter_hashes.size(), tip->nHeight + 1); |
142 | 260 |
|
143 | 261 | filters.clear();
|
144 | 262 | filter_hashes.clear();
|
|
0 commit comments