Skip to content

Commit e703360

Browse files
committed
Merge bitcoin/bitcoin#32997: index: Deduplicate HashKey / HeightKey handling
5646e6c index: restrict index helper function to namespace (Martin Zumsande) 032f350 index, refactor: deduplicate LookUpOne (Martin Zumsande) a67d3eb index: deduplicate Hash / Height handling (Martin Zumsande) Pull request description: The logic for `DBHashKey` / `DBHeightKey` handling and lookup of entries is shared by `coinstatsindex` and `blockfilterindex`, leading to many lines of duplicated code. De-duplicate this by moving the logic to `index/db_key.h` (using templates for the index-specific `DBVal`). ACKs for top commit: fjahr: re-ACK 5646e6c furszy: utACK 5646e6c sedited: ACK 5646e6c Tree-SHA512: 6f41684d6a9fd9bb01239e9f2e39a12837554f247a677eadcc242f0c1a2d44a79979f87249c4e0305ef1aa708d7056e56dfc40e1509c6d6aec2714f202fd2e09
2 parents ec4ff99 + 5646e6c commit e703360

File tree

3 files changed

+135
-188
lines changed

3 files changed

+135
-188
lines changed

src/index/blockfilterindex.cpp

Lines changed: 12 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <flatfile.h>
1212
#include <hash.h>
1313
#include <index/base.h>
14+
#include <index/db_key.h>
1415
#include <interfaces/chain.h>
1516
#include <interfaces/types.h>
1617
#include <logging.h>
@@ -25,7 +26,6 @@
2526

2627
#include <cerrno>
2728
#include <exception>
28-
#include <ios>
2929
#include <map>
3030
#include <optional>
3131
#include <span>
@@ -46,12 +46,8 @@
4646
* disk location of the next block filter to be written (represented as a FlatFilePos) is stored
4747
* under the DB_FILTER_POS key.
4848
*
49-
* Keys for the height index have the type [DB_BLOCK_HEIGHT, uint32 (BE)]. The height is represented
50-
* as big-endian so that sequential reads of filters by height are fast.
51-
* Keys for the hash index have the type [DB_BLOCK_HASH, uint256].
49+
* The logic for keys is shared with other indexes, see index/db_key.h.
5250
*/
53-
constexpr uint8_t DB_BLOCK_HASH{'s'};
54-
constexpr uint8_t DB_BLOCK_HEIGHT{'t'};
5551
constexpr uint8_t DB_FILTER_POS{'P'};
5652

5753
constexpr unsigned int MAX_FLTR_FILE_SIZE = 0x1000000; // 16 MiB
@@ -74,45 +70,6 @@ struct DBVal {
7470
SERIALIZE_METHODS(DBVal, obj) { READWRITE(obj.hash, obj.header, obj.pos); }
7571
};
7672

77-
struct DBHeightKey {
78-
int height;
79-
80-
explicit DBHeightKey(int height_in) : height(height_in) {}
81-
82-
template<typename Stream>
83-
void Serialize(Stream& s) const
84-
{
85-
ser_writedata8(s, DB_BLOCK_HEIGHT);
86-
ser_writedata32be(s, height);
87-
}
88-
89-
template<typename Stream>
90-
void Unserialize(Stream& s)
91-
{
92-
const uint8_t prefix{ser_readdata8(s)};
93-
if (prefix != DB_BLOCK_HEIGHT) {
94-
throw std::ios_base::failure("Invalid format for block filter index DB height key");
95-
}
96-
height = ser_readdata32be(s);
97-
}
98-
};
99-
100-
struct DBHashKey {
101-
uint256 hash;
102-
103-
explicit DBHashKey(const uint256& hash_in) : hash(hash_in) {}
104-
105-
SERIALIZE_METHODS(DBHashKey, obj) {
106-
uint8_t prefix{DB_BLOCK_HASH};
107-
READWRITE(prefix);
108-
if (prefix != DB_BLOCK_HASH) {
109-
throw std::ios_base::failure("Invalid format for block filter index DB hash key");
110-
}
111-
112-
READWRITE(obj.hash);
113-
}
114-
};
115-
11673
}; // namespace
11774

11875
static std::map<BlockFilterType, BlockFilterIndex> g_filter_indexes;
@@ -278,7 +235,7 @@ size_t BlockFilterIndex::WriteFilterToDisk(FlatFilePos& pos, const BlockFilter&
278235
std::optional<uint256> BlockFilterIndex::ReadFilterHeader(int height, const uint256& expected_block_hash)
279236
{
280237
std::pair<uint256, DBVal> read_out;
281-
if (!m_db->Read(DBHeightKey(height), read_out)) {
238+
if (!m_db->Read(index_util::DBHeightKey(height), read_out)) {
282239
return std::nullopt;
283240
}
284241

@@ -311,35 +268,12 @@ bool BlockFilterIndex::Write(const BlockFilter& filter, uint32_t block_height, c
311268
value.second.header = filter_header;
312269
value.second.pos = m_next_filter_pos;
313270

314-
m_db->Write(DBHeightKey(block_height), value);
271+
m_db->Write(index_util::DBHeightKey(block_height), value);
315272

316273
m_next_filter_pos.nPos += bytes_written;
317274
return true;
318275
}
319276

320-
[[nodiscard]] static bool CopyHeightIndexToHashIndex(CDBIterator& db_it, CDBBatch& batch,
321-
const std::string& index_name, int height)
322-
{
323-
DBHeightKey key(height);
324-
db_it.Seek(key);
325-
326-
if (!db_it.GetKey(key) || key.height != height) {
327-
LogError("unexpected key in %s: expected (%c, %d)",
328-
index_name, DB_BLOCK_HEIGHT, height);
329-
return false;
330-
}
331-
332-
std::pair<uint256, DBVal> value;
333-
if (!db_it.GetValue(value)) {
334-
LogError("unable to read value in %s at key (%c, %d)",
335-
index_name, DB_BLOCK_HEIGHT, height);
336-
return false;
337-
}
338-
339-
batch.Write(DBHashKey(value.first), std::move(value.second));
340-
return true;
341-
}
342-
343277
bool BlockFilterIndex::CustomRemove(const interfaces::BlockInfo& block)
344278
{
345279
CDBBatch batch(*m_db);
@@ -348,7 +282,7 @@ bool BlockFilterIndex::CustomRemove(const interfaces::BlockInfo& block)
348282
// During a reorg, we need to copy block filter that is getting disconnected from the
349283
// height index to the hash index so we can still find it when the height index entry
350284
// is overwritten.
351-
if (!CopyHeightIndexToHashIndex(*db_it, batch, m_name, block.height)) {
285+
if (!index_util::CopyHeightIndexToHashIndex<DBVal>(*db_it, batch, m_name, block.height)) {
352286
return false;
353287
}
354288

@@ -363,24 +297,6 @@ bool BlockFilterIndex::CustomRemove(const interfaces::BlockInfo& block)
363297
return true;
364298
}
365299

366-
static bool LookupOne(const CDBWrapper& db, const CBlockIndex* block_index, DBVal& result)
367-
{
368-
// First check if the result is stored under the height index and the value there matches the
369-
// block hash. This should be the case if the block is on the active chain.
370-
std::pair<uint256, DBVal> read_out;
371-
if (!db.Read(DBHeightKey(block_index->nHeight), read_out)) {
372-
return false;
373-
}
374-
if (read_out.first == block_index->GetBlockHash()) {
375-
result = std::move(read_out.second);
376-
return true;
377-
}
378-
379-
// If value at the height index corresponds to an different block, the result will be stored in
380-
// the hash index.
381-
return db.Read(DBHashKey(block_index->GetBlockHash()), result);
382-
}
383-
384300
static bool LookupRange(CDBWrapper& db, const std::string& index_name, int start_height,
385301
const CBlockIndex* stop_index, std::vector<DBVal>& results)
386302
{
@@ -397,9 +313,9 @@ static bool LookupRange(CDBWrapper& db, const std::string& index_name, int start
397313
size_t results_size = static_cast<size_t>(stop_index->nHeight - start_height + 1);
398314
std::vector<std::pair<uint256, DBVal>> values(results_size);
399315

400-
DBHeightKey key(start_height);
316+
index_util::DBHeightKey key(start_height);
401317
std::unique_ptr<CDBIterator> db_it(db.NewIterator());
402-
db_it->Seek(DBHeightKey(start_height));
318+
db_it->Seek(index_util::DBHeightKey(start_height));
403319
for (int height = start_height; height <= stop_index->nHeight; ++height) {
404320
if (!db_it->Valid() || !db_it->GetKey(key) || key.height != height) {
405321
return false;
@@ -408,7 +324,7 @@ static bool LookupRange(CDBWrapper& db, const std::string& index_name, int start
408324
size_t i = static_cast<size_t>(height - start_height);
409325
if (!db_it->GetValue(values[i])) {
410326
LogError("unable to read value in %s at key (%c, %d)",
411-
index_name, DB_BLOCK_HEIGHT, height);
327+
index_name, index_util::DB_BLOCK_HEIGHT, height);
412328
return false;
413329
}
414330

@@ -430,9 +346,9 @@ static bool LookupRange(CDBWrapper& db, const std::string& index_name, int start
430346
continue;
431347
}
432348

433-
if (!db.Read(DBHashKey(block_hash), results[i])) {
349+
if (!db.Read(index_util::DBHashKey(block_hash), results[i])) {
434350
LogError("unable to read value in %s at key (%c, %s)",
435-
index_name, DB_BLOCK_HASH, block_hash.ToString());
351+
index_name, index_util::DB_BLOCK_HASH, block_hash.ToString());
436352
return false;
437353
}
438354
}
@@ -443,7 +359,7 @@ static bool LookupRange(CDBWrapper& db, const std::string& index_name, int start
443359
bool BlockFilterIndex::LookupFilter(const CBlockIndex* block_index, BlockFilter& filter_out) const
444360
{
445361
DBVal entry;
446-
if (!LookupOne(*m_db, block_index, entry)) {
362+
if (!index_util::LookUpOne(*m_db, {block_index->GetBlockHash(), block_index->nHeight}, entry)) {
447363
return false;
448364
}
449365

@@ -466,7 +382,7 @@ bool BlockFilterIndex::LookupFilterHeader(const CBlockIndex* block_index, uint25
466382
}
467383

468384
DBVal entry;
469-
if (!LookupOne(*m_db, block_index, entry)) {
385+
if (!index_util::LookUpOne(*m_db, {block_index->GetBlockHash(), block_index->nHeight}, entry)) {
470386
return false;
471387
}
472388

src/index/coinstatsindex.cpp

Lines changed: 7 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <crypto/muhash.h>
1414
#include <dbwrapper.h>
1515
#include <index/base.h>
16+
#include <index/db_key.h>
1617
#include <interfaces/chain.h>
1718
#include <interfaces/types.h>
1819
#include <kernel/coinstats.h>
@@ -28,7 +29,6 @@
2829
#include <validation.h>
2930

3031
#include <compare>
31-
#include <ios>
3232
#include <limits>
3333
#include <span>
3434
#include <string>
@@ -40,8 +40,6 @@ using kernel::CCoinsStats;
4040
using kernel::GetBogoSize;
4141
using kernel::RemoveCoinHash;
4242

43-
static constexpr uint8_t DB_BLOCK_HASH{'s'};
44-
static constexpr uint8_t DB_BLOCK_HEIGHT{'t'};
4543
static constexpr uint8_t DB_MUHASH{'M'};
4644

4745
namespace {
@@ -85,47 +83,6 @@ struct DBVal {
8583
SER_READ(obj, obj.total_coinbase_amount = UintToArith256(coinbase));
8684
}
8785
};
88-
89-
struct DBHeightKey {
90-
int height;
91-
92-
explicit DBHeightKey(int height_in) : height(height_in) {}
93-
94-
template <typename Stream>
95-
void Serialize(Stream& s) const
96-
{
97-
ser_writedata8(s, DB_BLOCK_HEIGHT);
98-
ser_writedata32be(s, height);
99-
}
100-
101-
template <typename Stream>
102-
void Unserialize(Stream& s)
103-
{
104-
const uint8_t prefix{ser_readdata8(s)};
105-
if (prefix != DB_BLOCK_HEIGHT) {
106-
throw std::ios_base::failure("Invalid format for coinstatsindex DB height key");
107-
}
108-
height = ser_readdata32be(s);
109-
}
110-
};
111-
112-
struct DBHashKey {
113-
uint256 block_hash;
114-
115-
explicit DBHashKey(const uint256& hash_in) : block_hash(hash_in) {}
116-
117-
SERIALIZE_METHODS(DBHashKey, obj)
118-
{
119-
uint8_t prefix{DB_BLOCK_HASH};
120-
READWRITE(prefix);
121-
if (prefix != DB_BLOCK_HASH) {
122-
throw std::ios_base::failure("Invalid format for coinstatsindex DB hash key");
123-
}
124-
125-
READWRITE(obj.block_hash);
126-
}
127-
};
128-
12986
}; // namespace
13087

13188
std::unique_ptr<CoinStatsIndex> g_coin_stats_index;
@@ -253,30 +210,7 @@ bool CoinStatsIndex::CustomAppend(const interfaces::BlockInfo& block)
253210

254211
// Intentionally do not update DB_MUHASH here so it stays in sync with
255212
// DB_BEST_BLOCK, and the index is not corrupted if there is an unclean shutdown.
256-
m_db->Write(DBHeightKey(block.height), value);
257-
return true;
258-
}
259-
260-
[[nodiscard]] static bool CopyHeightIndexToHashIndex(CDBIterator& db_it, CDBBatch& batch,
261-
const std::string& index_name, int height)
262-
{
263-
DBHeightKey key{height};
264-
db_it.Seek(key);
265-
266-
if (!db_it.GetKey(key) || key.height != height) {
267-
LogError("unexpected key in %s: expected (%c, %d)",
268-
index_name, DB_BLOCK_HEIGHT, height);
269-
return false;
270-
}
271-
272-
std::pair<uint256, DBVal> value;
273-
if (!db_it.GetValue(value)) {
274-
LogError("unable to read value in %s at key (%c, %d)",
275-
index_name, DB_BLOCK_HEIGHT, height);
276-
return false;
277-
}
278-
279-
batch.Write(DBHashKey(value.first), value.second);
213+
m_db->Write(index_util::DBHeightKey(block.height), value);
280214
return true;
281215
}
282216

@@ -287,7 +221,7 @@ bool CoinStatsIndex::CustomRemove(const interfaces::BlockInfo& block)
287221

288222
// During a reorg, copy the block's hash digest from the height index to the hash index,
289223
// ensuring it's still accessible after the height index entry is overwritten.
290-
if (!CopyHeightIndexToHashIndex(*db_it, batch, m_name, block.height)) {
224+
if (!index_util::CopyHeightIndexToHashIndex<DBVal>(*db_it, batch, m_name, block.height)) {
291225
return false;
292226
}
293227

@@ -300,32 +234,13 @@ bool CoinStatsIndex::CustomRemove(const interfaces::BlockInfo& block)
300234
return true;
301235
}
302236

303-
static bool LookUpOne(const CDBWrapper& db, const interfaces::BlockRef& block, DBVal& result)
304-
{
305-
// First check if the result is stored under the height index and the value
306-
// there matches the block hash. This should be the case if the block is on
307-
// the active chain.
308-
std::pair<uint256, DBVal> read_out;
309-
if (!db.Read(DBHeightKey(block.height), read_out)) {
310-
return false;
311-
}
312-
if (read_out.first == block.hash) {
313-
result = std::move(read_out.second);
314-
return true;
315-
}
316-
317-
// If value at the height index corresponds to an different block, the
318-
// result will be stored in the hash index.
319-
return db.Read(DBHashKey(block.hash), result);
320-
}
321-
322237
std::optional<CCoinsStats> CoinStatsIndex::LookUpStats(const CBlockIndex& block_index) const
323238
{
324239
CCoinsStats stats{block_index.nHeight, block_index.GetBlockHash()};
325240
stats.index_used = true;
326241

327242
DBVal entry;
328-
if (!LookUpOne(*m_db, {block_index.GetBlockHash(), block_index.nHeight}, entry)) {
243+
if (!index_util::LookUpOne(*m_db, {block_index.GetBlockHash(), block_index.nHeight}, entry)) {
329244
return std::nullopt;
330245
}
331246

@@ -360,7 +275,7 @@ bool CoinStatsIndex::CustomInit(const std::optional<interfaces::BlockRef>& block
360275

361276
if (block) {
362277
DBVal entry;
363-
if (!LookUpOne(*m_db, *block, entry)) {
278+
if (!index_util::LookUpOne(*m_db, *block, entry)) {
364279
LogError("Cannot read current %s state; index may be corrupted",
365280
GetName());
366281
return false;
@@ -415,7 +330,7 @@ bool CoinStatsIndex::RevertBlock(const interfaces::BlockInfo& block)
415330

416331
// Ignore genesis block
417332
if (block.height > 0) {
418-
if (!m_db->Read(DBHeightKey(block.height - 1), read_out)) {
333+
if (!m_db->Read(index_util::DBHeightKey(block.height - 1), read_out)) {
419334
return false;
420335
}
421336

@@ -424,7 +339,7 @@ bool CoinStatsIndex::RevertBlock(const interfaces::BlockInfo& block)
424339
LogWarning("previous block header belongs to unexpected block %s; expected %s",
425340
read_out.first.ToString(), expected_block_hash.ToString());
426341

427-
if (!m_db->Read(DBHashKey(expected_block_hash), read_out)) {
342+
if (!m_db->Read(index_util::DBHashKey(expected_block_hash), read_out)) {
428343
LogError("previous block header not found; expected %s",
429344
expected_block_hash.ToString());
430345
return false;

0 commit comments

Comments
 (0)