Branch data Line data Source code
1 : : // Copyright (c) 2025-present The Bitcoin Core developers
2 : : // Distributed under the MIT software license, see the accompanying
3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 : :
5 : : #ifndef BITCOIN_INDEX_DB_KEY_H
6 : : #define BITCOIN_INDEX_DB_KEY_H
7 : :
8 : : #include <dbwrapper.h>
9 : : #include <interfaces/types.h>
10 : : #include <logging.h>
11 : : #include <serialize.h>
12 : : #include <uint256.h>
13 : :
14 : : #include <cstdint>
15 : : #include <ios>
16 : : #include <string>
17 : : #include <utility>
18 : :
19 : : namespace index_util {
20 : : /*
21 : : * This file includes the logic for the db keys used by blockfilterindex and coinstatsindex.
22 : : * Index data is usually indexed by height, but in case of a reorg, entries of blocks no
23 : : * longer in the main chain will be copied to a hash index by which they can still be queried.
24 : : * Keys for the height index have the type [DB_BLOCK_HEIGHT, uint32 (BE)]. The height is represented
25 : : * as big-endian so that sequential reads of filters by height are fast.
26 : : * Keys for the hash index have the type [DB_BLOCK_HASH, uint256].
27 : : */
28 : :
29 : : static constexpr uint8_t DB_BLOCK_HASH{'s'};
30 : : static constexpr uint8_t DB_BLOCK_HEIGHT{'t'};
31 : :
32 : : struct DBHeightKey {
33 : : int height;
34 : :
35 [ + - + - ]: 751 : explicit DBHeightKey(int height_in) : height(height_in) {}
36 : :
37 : : template<typename Stream>
38 : 1191 : void Serialize(Stream& s) const
39 : : {
40 : 1191 : ser_writedata8(s, DB_BLOCK_HEIGHT);
41 : 1191 : ser_writedata32be(s, height);
42 : 1191 : }
43 : :
44 : : template<typename Stream>
45 : 443 : void Unserialize(Stream& s)
46 : : {
47 : 443 : const uint8_t prefix{ser_readdata8(s)};
48 [ - + ]: 443 : if (prefix != DB_BLOCK_HEIGHT) {
49 [ # # ]: 0 : throw std::ios_base::failure("Invalid format for index DB height key");
50 : : }
51 : 443 : height = ser_readdata32be(s);
52 : 443 : }
53 : : };
54 : :
55 : : struct DBHashKey {
56 : : uint256 hash;
57 : :
58 [ + - ]: 10 : explicit DBHashKey(const uint256& hash_in) : hash(hash_in) {}
59 : :
60 : 25 : SERIALIZE_METHODS(DBHashKey, obj) {
61 : 25 : uint8_t prefix{DB_BLOCK_HASH};
62 : 25 : READWRITE(prefix);
63 [ - + ]: 25 : if (prefix != DB_BLOCK_HASH) {
64 [ # # ]: 0 : throw std::ios_base::failure("Invalid format for index DB hash key");
65 : : }
66 : :
67 : 25 : READWRITE(obj.hash);
68 : 25 : }
69 : : };
70 : :
71 : : template <typename DBVal>
72 : 5 : [[nodiscard]] static bool CopyHeightIndexToHashIndex(CDBIterator& db_it, CDBBatch& batch,
73 : : const std::string& index_name, int height)
74 : : {
75 : 5 : DBHeightKey key(height);
76 : 5 : db_it.Seek(key);
77 : :
78 [ + - + - ]: 5 : if (!db_it.GetKey(key) || key.height != height) {
79 : 0 : LogError("unexpected key in %s: expected (%c, %d)",
80 : : index_name, DB_BLOCK_HEIGHT, height);
81 : 0 : return false;
82 : : }
83 : :
84 : 5 : std::pair<uint256, DBVal> value;
85 [ - + ]: 5 : if (!db_it.GetValue(value)) {
86 : 0 : LogError("unable to read value in %s at key (%c, %d)",
87 : : index_name, DB_BLOCK_HEIGHT, height);
88 : 0 : return false;
89 : : }
90 : :
91 : 5 : batch.Write(DBHashKey(value.first), value.second);
92 : 5 : return true;
93 : : }
94 : :
95 : : template <typename DBVal>
96 : 435 : static bool LookUpOne(const CDBWrapper& db, const interfaces::BlockRef& block, DBVal& result)
97 : : {
98 : : // First check if the result is stored under the height index and the value
99 : : // there matches the block hash. This should be the case if the block is on
100 : : // the active chain.
101 : 435 : std::pair<uint256, DBVal> read_out;
102 [ + + ]: 435 : if (!db.Read(DBHeightKey(block.height), read_out)) {
103 : : return false;
104 : : }
105 [ + + ]: 232 : if (read_out.first == block.hash) {
106 : 222 : result = std::move(read_out.second);
107 : 222 : return true;
108 : : }
109 : :
110 : : // If value at the height index corresponds to an different block, the
111 : : // result will be stored in the hash index.
112 : 10 : return db.Read(DBHashKey(block.hash), result);
113 : : }
114 : : } // namespace index_util
115 : :
116 : : #endif // BITCOIN_INDEX_DB_KEY_H
|