/bitcoin/src/index/db_key.h
Line | Count | Source |
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 <serialize.h> |
11 | | #include <uint256.h> |
12 | | #include <util/log.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 | 93.9k | explicit DBHeightKey(int height_in) : height(height_in) {} |
36 | | |
37 | | template<typename Stream> |
38 | | void Serialize(Stream& s) const |
39 | 90.6k | { |
40 | 90.6k | ser_writedata8(s, DB_BLOCK_HEIGHT); |
41 | 90.6k | ser_writedata32be(s, height); |
42 | 90.6k | } |
43 | | |
44 | | template<typename Stream> |
45 | | void Unserialize(Stream& s) |
46 | 369k | { |
47 | 369k | const uint8_t prefix{ser_readdata8(s)}; |
48 | 369k | if (prefix != DB_BLOCK_HEIGHT) { Branch (48:13): [True: 0, False: 369k]
|
49 | 0 | throw std::ios_base::failure("Invalid format for index DB height key"); |
50 | 0 | } |
51 | 369k | height = ser_readdata32be(s); |
52 | 369k | } |
53 | | }; |
54 | | |
55 | | struct DBHashKey { |
56 | | uint256 hash; |
57 | | |
58 | 21.5k | explicit DBHashKey(const uint256& hash_in) : hash(hash_in) {} |
59 | | |
60 | 21.5k | SERIALIZE_METHODS(DBHashKey, obj) { |
61 | 21.5k | uint8_t prefix{DB_BLOCK_HASH}; |
62 | 21.5k | READWRITE(prefix); |
63 | 21.5k | if (prefix != DB_BLOCK_HASH) { Branch (63:13): [True: 0, False: 21.5k]
|
64 | 0 | throw std::ios_base::failure("Invalid format for index DB hash key"); |
65 | 0 | } |
66 | | |
67 | 21.5k | READWRITE(obj.hash); |
68 | 21.5k | } |
69 | | }; |
70 | | |
71 | | template <typename DBVal> |
72 | | [[nodiscard]] static bool CopyHeightIndexToHashIndex(CDBIterator& db_it, CDBBatch& batch, |
73 | | const std::string& index_name, int height) |
74 | 21.4k | { |
75 | 21.4k | DBHeightKey key(height); |
76 | 21.4k | db_it.Seek(key); |
77 | | |
78 | 21.4k | if (!db_it.GetKey(key) || key.height != height) { Branch (78:9): [True: 0, False: 0]
Branch (78:31): [True: 0, False: 0]
Branch (78:9): [True: 0, False: 21.4k]
Branch (78:31): [True: 0, False: 21.4k]
|
79 | 0 | LogError("unexpected key in %s: expected (%c, %d)", |
80 | 0 | index_name, DB_BLOCK_HEIGHT, height); |
81 | 0 | return false; |
82 | 0 | } |
83 | | |
84 | 21.4k | std::pair<uint256, DBVal> value; |
85 | 21.4k | if (!db_it.GetValue(value)) { Branch (85:9): [True: 0, False: 0]
Branch (85:9): [True: 0, False: 21.4k]
|
86 | 0 | LogError("unable to read value in %s at key (%c, %d)", |
87 | 0 | index_name, DB_BLOCK_HEIGHT, height); |
88 | 0 | return false; |
89 | 0 | } |
90 | | |
91 | 21.4k | batch.Write(DBHashKey(value.first), value.second); |
92 | 21.4k | return true; |
93 | 21.4k | } Unexecuted instantiation: coinstatsindex.cpp:bool index_util::CopyHeightIndexToHashIndex<(anonymous namespace)::DBVal>(CDBIterator&, CDBBatch&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int) blockfilterindex.cpp:bool index_util::CopyHeightIndexToHashIndex<(anonymous namespace)::DBVal>(CDBIterator&, CDBBatch&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int) Line | Count | Source | 74 | 21.4k | { | 75 | 21.4k | DBHeightKey key(height); | 76 | 21.4k | db_it.Seek(key); | 77 | | | 78 | 21.4k | if (!db_it.GetKey(key) || key.height != height) { Branch (78:9): [True: 0, False: 21.4k]
Branch (78:31): [True: 0, False: 21.4k]
| 79 | 0 | LogError("unexpected key in %s: expected (%c, %d)", | 80 | 0 | index_name, DB_BLOCK_HEIGHT, height); | 81 | 0 | return false; | 82 | 0 | } | 83 | | | 84 | 21.4k | std::pair<uint256, DBVal> value; | 85 | 21.4k | if (!db_it.GetValue(value)) { Branch (85:9): [True: 0, False: 21.4k]
| 86 | 0 | LogError("unable to read value in %s at key (%c, %d)", | 87 | 0 | index_name, DB_BLOCK_HEIGHT, height); | 88 | 0 | return false; | 89 | 0 | } | 90 | | | 91 | 21.4k | batch.Write(DBHashKey(value.first), value.second); | 92 | 21.4k | return true; | 93 | 21.4k | } |
|
94 | | |
95 | | template <typename DBVal> |
96 | | static bool LookUpOne(const CDBWrapper& db, const interfaces::BlockRef& block, DBVal& result) |
97 | 1.30k | { |
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 | 1.30k | std::pair<uint256, DBVal> read_out; |
102 | 1.30k | if (!db.Read(DBHeightKey(block.height), read_out)) { Branch (102:9): [True: 0, False: 0]
Branch (102:9): [True: 0, False: 1.30k]
|
103 | 0 | return false; |
104 | 0 | } |
105 | 1.30k | if (read_out.first == block.hash) { Branch (105:9): [True: 0, False: 0]
Branch (105:9): [True: 1.30k, False: 0]
|
106 | 1.30k | result = std::move(read_out.second); |
107 | 1.30k | return true; |
108 | 1.30k | } |
109 | | |
110 | | // If value at the height index corresponds to an different block, the |
111 | | // result will be stored in the hash index. |
112 | 0 | return db.Read(DBHashKey(block.hash), result); |
113 | 1.30k | } Unexecuted instantiation: coinstatsindex.cpp:bool index_util::LookUpOne<(anonymous namespace)::DBVal>(CDBWrapper const&, interfaces::BlockRef const&, (anonymous namespace)::DBVal&) blockfilterindex.cpp:bool index_util::LookUpOne<(anonymous namespace)::DBVal>(CDBWrapper const&, interfaces::BlockRef const&, (anonymous namespace)::DBVal&) Line | Count | Source | 97 | 1.30k | { | 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 | 1.30k | std::pair<uint256, DBVal> read_out; | 102 | 1.30k | if (!db.Read(DBHeightKey(block.height), read_out)) { Branch (102:9): [True: 0, False: 1.30k]
| 103 | 0 | return false; | 104 | 0 | } | 105 | 1.30k | if (read_out.first == block.hash) { Branch (105:9): [True: 1.30k, False: 0]
| 106 | 1.30k | result = std::move(read_out.second); | 107 | 1.30k | return true; | 108 | 1.30k | } | 109 | | | 110 | | // If value at the height index corresponds to an different block, the | 111 | | // result will be stored in the hash index. | 112 | 0 | return db.Read(DBHashKey(block.hash), result); | 113 | 1.30k | } |
|
114 | | } // namespace index_util |
115 | | |
116 | | #endif // BITCOIN_INDEX_DB_KEY_H |