/root/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 <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 | 0 | explicit DBHeightKey(int height_in) : height(height_in) {} |
36 | | |
37 | | template<typename Stream> |
38 | | void Serialize(Stream& s) const |
39 | 0 | { |
40 | 0 | ser_writedata8(s, DB_BLOCK_HEIGHT); |
41 | 0 | ser_writedata32be(s, height); |
42 | 0 | } |
43 | | |
44 | | template<typename Stream> |
45 | | void Unserialize(Stream& s) |
46 | 0 | { |
47 | 0 | const uint8_t prefix{ser_readdata8(s)}; |
48 | 0 | if (prefix != DB_BLOCK_HEIGHT) { |
49 | 0 | throw std::ios_base::failure("Invalid format for index DB height key"); |
50 | 0 | } |
51 | 0 | height = ser_readdata32be(s); |
52 | 0 | } |
53 | | }; |
54 | | |
55 | | struct DBHashKey { |
56 | | uint256 hash; |
57 | | |
58 | 0 | explicit DBHashKey(const uint256& hash_in) : hash(hash_in) {} |
59 | | |
60 | 0 | SERIALIZE_METHODS(DBHashKey, obj) { |
61 | 0 | uint8_t prefix{DB_BLOCK_HASH}; |
62 | 0 | READWRITE(prefix); Line | Count | Source | 146 | 0 | #define READWRITE(...) (ser_action.SerReadWriteMany(s, __VA_ARGS__)) |
|
63 | 0 | if (prefix != DB_BLOCK_HASH) { |
64 | 0 | throw std::ios_base::failure("Invalid format for index DB hash key"); |
65 | 0 | } |
66 | | |
67 | 0 | READWRITE(obj.hash); Line | Count | Source | 146 | 0 | #define READWRITE(...) (ser_action.SerReadWriteMany(s, __VA_ARGS__)) |
|
68 | 0 | } |
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 | 0 | { |
75 | 0 | DBHeightKey key(height); |
76 | 0 | db_it.Seek(key); |
77 | |
|
78 | 0 | if (!db_it.GetKey(key) || key.height != height) { |
79 | 0 | LogError("unexpected key in %s: expected (%c, %d)",Line | Count | Source | 97 | 0 | #define LogError(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Error, /*should_ratelimit=*/true, __VA_ARGS__) Line | Count | Source | 89 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(SourceLocation{__func__}, category, level, should_ratelimit, __VA_ARGS__) |
|
| LogError("unexpected key in %s: expected (%c, %d)",Line | Count | Source | 97 | 0 | #define LogError(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Error, /*should_ratelimit=*/true, __VA_ARGS__) Line | Count | Source | 89 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(SourceLocation{__func__}, category, level, should_ratelimit, __VA_ARGS__) |
|
|
80 | 0 | index_name, DB_BLOCK_HEIGHT, height); |
81 | 0 | return false; |
82 | 0 | } |
83 | | |
84 | 0 | std::pair<uint256, DBVal> value; |
85 | 0 | if (!db_it.GetValue(value)) { |
86 | 0 | LogError("unable to read value in %s at key (%c, %d)",Line | Count | Source | 97 | 0 | #define LogError(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Error, /*should_ratelimit=*/true, __VA_ARGS__) Line | Count | Source | 89 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(SourceLocation{__func__}, category, level, should_ratelimit, __VA_ARGS__) |
|
| LogError("unable to read value in %s at key (%c, %d)",Line | Count | Source | 97 | 0 | #define LogError(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Error, /*should_ratelimit=*/true, __VA_ARGS__) Line | Count | Source | 89 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(SourceLocation{__func__}, category, level, should_ratelimit, __VA_ARGS__) |
|
|
87 | 0 | index_name, DB_BLOCK_HEIGHT, height); |
88 | 0 | return false; |
89 | 0 | } |
90 | | |
91 | 0 | batch.Write(DBHashKey(value.first), value.second); |
92 | 0 | return true; |
93 | 0 | } Unexecuted instantiation: 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) 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) |
94 | | |
95 | | template <typename DBVal> |
96 | | static bool LookUpOne(const CDBWrapper& db, const interfaces::BlockRef& block, DBVal& result) |
97 | 0 | { |
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 | 0 | std::pair<uint256, DBVal> read_out; |
102 | 0 | if (!db.Read(DBHeightKey(block.height), read_out)) { |
103 | 0 | return false; |
104 | 0 | } |
105 | 0 | if (read_out.first == block.hash) { |
106 | 0 | result = std::move(read_out.second); |
107 | 0 | return true; |
108 | 0 | } |
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 | 0 | } Unexecuted instantiation: blockfilterindex.cpp:bool index_util::LookUpOne<(anonymous namespace)::DBVal>(CDBWrapper const&, interfaces::BlockRef const&, (anonymous namespace)::DBVal&) Unexecuted instantiation: coinstatsindex.cpp:bool index_util::LookUpOne<(anonymous namespace)::DBVal>(CDBWrapper const&, interfaces::BlockRef const&, (anonymous namespace)::DBVal&) |
114 | | } // namespace index_util |
115 | | |
116 | | #endif // BITCOIN_INDEX_DB_KEY_H |