/root/bitcoin/src/dbwrapper.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) 2012-2022 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_DBWRAPPER_H |
6 | | #define BITCOIN_DBWRAPPER_H |
7 | | |
8 | | #include <attributes.h> |
9 | | #include <serialize.h> |
10 | | #include <span.h> |
11 | | #include <streams.h> |
12 | | #include <util/check.h> |
13 | | #include <util/fs.h> |
14 | | |
15 | | #include <cstddef> |
16 | | #include <exception> |
17 | | #include <memory> |
18 | | #include <optional> |
19 | | #include <stdexcept> |
20 | | #include <string> |
21 | | #include <vector> |
22 | | |
23 | | static const size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64; |
24 | | static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024; |
25 | | |
26 | | //! User-controlled performance and debug options. |
27 | | struct DBOptions { |
28 | | //! Compact database on startup. |
29 | | bool force_compact = false; |
30 | | }; |
31 | | |
32 | | //! Application-specific storage settings. |
33 | | struct DBParams { |
34 | | //! Location in the filesystem where leveldb data will be stored. |
35 | | fs::path path; |
36 | | //! Configures various leveldb cache settings. |
37 | | size_t cache_bytes; |
38 | | //! If true, use leveldb's memory environment. |
39 | | bool memory_only = false; |
40 | | //! If true, remove all existing data. |
41 | | bool wipe_data = false; |
42 | | //! If true, store data obfuscated via simple XOR. If false, XOR with a |
43 | | //! zero'd byte array. |
44 | | bool obfuscate = false; |
45 | | //! Passed-through options. |
46 | | DBOptions options{}; |
47 | | }; |
48 | | |
49 | | class dbwrapper_error : public std::runtime_error |
50 | | { |
51 | | public: |
52 | 0 | explicit dbwrapper_error(const std::string& msg) : std::runtime_error(msg) {} |
53 | | }; |
54 | | |
55 | | class CDBWrapper; |
56 | | |
57 | | /** These should be considered an implementation detail of the specific database. |
58 | | */ |
59 | | namespace dbwrapper_private { |
60 | | |
61 | | /** Work around circular dependency, as well as for testing in dbwrapper_tests. |
62 | | * Database obfuscation should be considered an implementation detail of the |
63 | | * specific database. |
64 | | */ |
65 | | const std::vector<unsigned char>& GetObfuscateKey(const CDBWrapper &w); |
66 | | |
67 | | }; // namespace dbwrapper_private |
68 | | |
69 | | bool DestroyDB(const std::string& path_str); |
70 | | |
71 | | /** Batch of changes queued to be written to a CDBWrapper */ |
72 | | class CDBBatch |
73 | | { |
74 | | friend class CDBWrapper; |
75 | | |
76 | | private: |
77 | | const CDBWrapper &parent; |
78 | | |
79 | | struct WriteBatchImpl; |
80 | | const std::unique_ptr<WriteBatchImpl> m_impl_batch; |
81 | | |
82 | | DataStream ssKey{}; |
83 | | DataStream ssValue{}; |
84 | | |
85 | | size_t size_estimate{0}; |
86 | | |
87 | | void WriteImpl(Span<const std::byte> key, DataStream& ssValue); |
88 | | void EraseImpl(Span<const std::byte> key); |
89 | | |
90 | | public: |
91 | | /** |
92 | | * @param[in] _parent CDBWrapper that this batch is to be submitted to |
93 | | */ |
94 | | explicit CDBBatch(const CDBWrapper& _parent); |
95 | | ~CDBBatch(); |
96 | | void Clear(); |
97 | | |
98 | | template <typename K, typename V> |
99 | | void Write(const K& key, const V& value) |
100 | 0 | { |
101 | 0 | ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); |
102 | 0 | ssValue.reserve(DBWRAPPER_PREALLOC_VALUE_SIZE); |
103 | 0 | ssKey << key; |
104 | 0 | ssValue << value; |
105 | 0 | WriteImpl(ssKey, ssValue); |
106 | 0 | ssKey.clear(); |
107 | 0 | ssValue.clear(); |
108 | 0 | } Unexecuted instantiation: _ZN8CDBBatch5WriteINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt6vectorIhSaIhEEEEvRKT_RKT0_ Unexecuted instantiation: _ZN8CDBBatch5WriteIhhEEvRKT_RKT0_ Unexecuted instantiation: _ZN8CDBBatch5WriteISt4pairIhiE14CBlockFileInfoEEvRKT_RKT0_ Unexecuted instantiation: _ZN8CDBBatch5WriteIhiEEvRKT_RKT0_ Unexecuted instantiation: _ZN8CDBBatch5WriteISt4pairIh7uint256E15CDiskBlockIndexEEvRKT_RKT0_ Unexecuted instantiation: _ZN8CDBBatch5WriteISt4pairIhNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEhEEvRKT_RKT0_ Unexecuted instantiation: _ZN8CDBBatch5WriteIhSt6vectorI7uint256SaIS2_EEEEvRKT_RKT0_ Unexecuted instantiation: txdb.cpp:_ZN8CDBBatch5WriteIN12_GLOBAL__N_19CoinEntryE4CoinEEvRKT_RKT0_ Unexecuted instantiation: _ZN8CDBBatch5WriteIh7uint256EEvRKT_RKT0_ Unexecuted instantiation: _ZN8CDBBatch5WriteIh13CBlockLocatorEEvRKT_RKT0_ Unexecuted instantiation: blockfilterindex.cpp:_ZN8CDBBatch5WriteIN12_GLOBAL__N_19DBHashKeyENS1_5DBValEEEvRKT_RKT0_ Unexecuted instantiation: _ZN8CDBBatch5WriteIh11FlatFilePosEEvRKT_RKT0_ Unexecuted instantiation: blockfilterindex.cpp:_ZN8CDBBatch5WriteIN12_GLOBAL__N_111DBHeightKeyESt4pairI7uint256NS1_5DBValEEEEvRKT_RKT0_ Unexecuted instantiation: coinstatsindex.cpp:_ZN8CDBBatch5WriteIN12_GLOBAL__N_19DBHashKeyENS1_5DBValEEEvRKT_RKT0_ Unexecuted instantiation: coinstatsindex.cpp:_ZN8CDBBatch5WriteIN12_GLOBAL__N_111DBHeightKeyESt4pairI7uint256NS1_5DBValEEEEvRKT_RKT0_ Unexecuted instantiation: _ZN8CDBBatch5WriteIh10MuHash3072EEvRKT_RKT0_ Unexecuted instantiation: _ZN8CDBBatch5WriteISt4pairIh7uint256E10CDiskTxPosEEvRKT_RKT0_ |
109 | | |
110 | | template <typename K> |
111 | | void Erase(const K& key) |
112 | 0 | { |
113 | 0 | ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); |
114 | 0 | ssKey << key; |
115 | 0 | EraseImpl(ssKey); |
116 | 0 | ssKey.clear(); |
117 | 0 | } Unexecuted instantiation: _ZN8CDBBatch5EraseIhEEvRKT_ Unexecuted instantiation: txdb.cpp:_ZN8CDBBatch5EraseIN12_GLOBAL__N_19CoinEntryEEEvRKT_ |
118 | | |
119 | 0 | size_t SizeEstimate() const { return size_estimate; } |
120 | | }; |
121 | | |
122 | | class CDBIterator |
123 | | { |
124 | | public: |
125 | | struct IteratorImpl; |
126 | | |
127 | | private: |
128 | | const CDBWrapper &parent; |
129 | | const std::unique_ptr<IteratorImpl> m_impl_iter; |
130 | | |
131 | | void SeekImpl(Span<const std::byte> key); |
132 | | Span<const std::byte> GetKeyImpl() const; |
133 | | Span<const std::byte> GetValueImpl() const; |
134 | | |
135 | | public: |
136 | | |
137 | | /** |
138 | | * @param[in] _parent Parent CDBWrapper instance. |
139 | | * @param[in] _piter The original leveldb iterator. |
140 | | */ |
141 | | CDBIterator(const CDBWrapper& _parent, std::unique_ptr<IteratorImpl> _piter); |
142 | | ~CDBIterator(); |
143 | | |
144 | | bool Valid() const; |
145 | | |
146 | | void SeekToFirst(); |
147 | | |
148 | 0 | template<typename K> void Seek(const K& key) { |
149 | 0 | DataStream ssKey{}; |
150 | 0 | ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); |
151 | 0 | ssKey << key; |
152 | 0 | SeekImpl(ssKey); |
153 | 0 | } Unexecuted instantiation: _ZN11CDBIterator4SeekISt4pairIh7uint256EEEvRKT_ Unexecuted instantiation: _ZN11CDBIterator4SeekIhEEvRKT_ Unexecuted instantiation: blockfilterindex.cpp:_ZN11CDBIterator4SeekIN12_GLOBAL__N_111DBHeightKeyEEEvRKT_ Unexecuted instantiation: coinstatsindex.cpp:_ZN11CDBIterator4SeekIN12_GLOBAL__N_111DBHeightKeyEEEvRKT_ |
154 | | |
155 | | void Next(); |
156 | | |
157 | 0 | template<typename K> bool GetKey(K& key) { |
158 | 0 | try { |
159 | 0 | DataStream ssKey{GetKeyImpl()}; |
160 | 0 | ssKey >> key; |
161 | 0 | } catch (const std::exception&) { |
162 | 0 | return false; |
163 | 0 | } |
164 | 0 | return true; |
165 | 0 | } Unexecuted instantiation: _ZN11CDBIterator6GetKeyISt4pairIh7uint256EEEbRT_ Unexecuted instantiation: txdb.cpp:_ZN11CDBIterator6GetKeyIN12_GLOBAL__N_19CoinEntryEEEbRT_ Unexecuted instantiation: blockfilterindex.cpp:_ZN11CDBIterator6GetKeyIN12_GLOBAL__N_111DBHeightKeyEEEbRT_ Unexecuted instantiation: coinstatsindex.cpp:_ZN11CDBIterator6GetKeyIN12_GLOBAL__N_111DBHeightKeyEEEbRT_ |
166 | | |
167 | 0 | template<typename V> bool GetValue(V& value) { |
168 | 0 | try { |
169 | 0 | DataStream ssValue{GetValueImpl()}; |
170 | 0 | ssValue.Xor(dbwrapper_private::GetObfuscateKey(parent)); |
171 | 0 | ssValue >> value; |
172 | 0 | } catch (const std::exception&) { |
173 | 0 | return false; |
174 | 0 | } |
175 | 0 | return true; |
176 | 0 | } Unexecuted instantiation: _ZN11CDBIterator8GetValueI15CDiskBlockIndexEEbRT_ Unexecuted instantiation: _ZN11CDBIterator8GetValueI4CoinEEbRT_ Unexecuted instantiation: blockfilterindex.cpp:_ZN11CDBIterator8GetValueISt4pairI7uint256N12_GLOBAL__N_15DBValEEEEbRT_ Unexecuted instantiation: coinstatsindex.cpp:_ZN11CDBIterator8GetValueISt4pairI7uint256N12_GLOBAL__N_15DBValEEEEbRT_ |
177 | | }; |
178 | | |
179 | | struct LevelDBContext; |
180 | | |
181 | | class CDBWrapper |
182 | | { |
183 | | friend const std::vector<unsigned char>& dbwrapper_private::GetObfuscateKey(const CDBWrapper &w); |
184 | | private: |
185 | | //! holds all leveldb-specific fields of this class |
186 | | std::unique_ptr<LevelDBContext> m_db_context; |
187 | | |
188 | | //! the name of this database |
189 | | std::string m_name; |
190 | | |
191 | | //! a key used for optional XOR-obfuscation of the database |
192 | | std::vector<unsigned char> obfuscate_key; |
193 | | |
194 | | //! the key under which the obfuscation key is stored |
195 | | static const std::string OBFUSCATE_KEY_KEY; |
196 | | |
197 | | //! the length of the obfuscate key in number of bytes |
198 | | static const unsigned int OBFUSCATE_KEY_NUM_BYTES; |
199 | | |
200 | | std::vector<unsigned char> CreateObfuscateKey() const; |
201 | | |
202 | | //! path to filesystem storage |
203 | | const fs::path m_path; |
204 | | |
205 | | //! whether or not the database resides in memory |
206 | | bool m_is_memory; |
207 | | |
208 | | std::optional<std::string> ReadImpl(Span<const std::byte> key) const; |
209 | | bool ExistsImpl(Span<const std::byte> key) const; |
210 | | size_t EstimateSizeImpl(Span<const std::byte> key1, Span<const std::byte> key2) const; |
211 | 0 | auto& DBContext() const LIFETIMEBOUND { return *Assert(m_db_context); } |
212 | | |
213 | | public: |
214 | | CDBWrapper(const DBParams& params); |
215 | | ~CDBWrapper(); |
216 | | |
217 | | CDBWrapper(const CDBWrapper&) = delete; |
218 | | CDBWrapper& operator=(const CDBWrapper&) = delete; |
219 | | |
220 | | template <typename K, typename V> |
221 | | bool Read(const K& key, V& value) const |
222 | 0 | { |
223 | 0 | DataStream ssKey{}; |
224 | 0 | ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); |
225 | 0 | ssKey << key; |
226 | 0 | std::optional<std::string> strValue{ReadImpl(ssKey)}; |
227 | 0 | if (!strValue) { |
228 | 0 | return false; |
229 | 0 | } |
230 | 0 | try { |
231 | 0 | DataStream ssValue{MakeByteSpan(*strValue)}; |
232 | 0 | ssValue.Xor(obfuscate_key); |
233 | 0 | ssValue >> value; |
234 | 0 | } catch (const std::exception&) { |
235 | 0 | return false; |
236 | 0 | } |
237 | 0 | return true; |
238 | 0 | } Unexecuted instantiation: _ZNK10CDBWrapper4ReadINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt6vectorIhSaIhEEEEbRKT_RT0_ Unexecuted instantiation: _ZNK10CDBWrapper4ReadISt4pairIhiE14CBlockFileInfoEEbRKT_RT0_ Unexecuted instantiation: _ZNK10CDBWrapper4ReadIhiEEbRKT_RT0_ Unexecuted instantiation: _ZNK10CDBWrapper4ReadISt4pairIhNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEhEEbRKT_RT0_ Unexecuted instantiation: txdb.cpp:_ZNK10CDBWrapper4ReadIN12_GLOBAL__N_19CoinEntryE4CoinEEbRKT_RT0_ Unexecuted instantiation: _ZNK10CDBWrapper4ReadIh7uint256EEbRKT_RT0_ Unexecuted instantiation: _ZNK10CDBWrapper4ReadIhSt6vectorI7uint256SaIS2_EEEEbRKT_RT0_ Unexecuted instantiation: _ZNK10CDBWrapper4ReadIh13CBlockLocatorEEbRKT_RT0_ Unexecuted instantiation: blockfilterindex.cpp:_ZNK10CDBWrapper4ReadIN12_GLOBAL__N_19DBHashKeyENS1_5DBValEEEbRKT_RT0_ Unexecuted instantiation: _ZNK10CDBWrapper4ReadIh11FlatFilePosEEbRKT_RT0_ Unexecuted instantiation: blockfilterindex.cpp:_ZNK10CDBWrapper4ReadIN12_GLOBAL__N_111DBHeightKeyESt4pairI7uint256NS1_5DBValEEEEbRKT_RT0_ Unexecuted instantiation: coinstatsindex.cpp:_ZNK10CDBWrapper4ReadIN12_GLOBAL__N_19DBHashKeyENS1_5DBValEEEbRKT_RT0_ Unexecuted instantiation: coinstatsindex.cpp:_ZNK10CDBWrapper4ReadIN12_GLOBAL__N_111DBHeightKeyESt4pairI7uint256NS1_5DBValEEEEbRKT_RT0_ Unexecuted instantiation: coinstatsindex.cpp:_ZNK10CDBWrapper4ReadIN12_GLOBAL__N_19DBHashKeyESt4pairI7uint256NS1_5DBValEEEEbRKT_RT0_ Unexecuted instantiation: _ZNK10CDBWrapper4ReadIh10MuHash3072EEbRKT_RT0_ Unexecuted instantiation: _ZNK10CDBWrapper4ReadISt4pairIh7uint256E10CDiskTxPosEEbRKT_RT0_ |
239 | | |
240 | | template <typename K, typename V> |
241 | | bool Write(const K& key, const V& value, bool fSync = false) |
242 | 0 | { |
243 | 0 | CDBBatch batch(*this); |
244 | 0 | batch.Write(key, value); |
245 | 0 | return WriteBatch(batch, fSync); |
246 | 0 | } Unexecuted instantiation: _ZN10CDBWrapper5WriteINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt6vectorIhSaIhEEEEbRKT_RKT0_b Unexecuted instantiation: _ZN10CDBWrapper5WriteIhhEEbRKT_RKT0_b Unexecuted instantiation: _ZN10CDBWrapper5WriteISt4pairIhNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEhEEbRKT_RKT0_b Unexecuted instantiation: blockfilterindex.cpp:_ZN10CDBWrapper5WriteIN12_GLOBAL__N_111DBHeightKeyESt4pairI7uint256NS1_5DBValEEEEbRKT_RKT0_b Unexecuted instantiation: coinstatsindex.cpp:_ZN10CDBWrapper5WriteIN12_GLOBAL__N_111DBHeightKeyESt4pairI7uint256NS1_5DBValEEEEbRKT_RKT0_b |
247 | | |
248 | | //! @returns filesystem path to the on-disk data. |
249 | 0 | std::optional<fs::path> StoragePath() { |
250 | 0 | if (m_is_memory) { |
251 | 0 | return {}; |
252 | 0 | } |
253 | 0 | return m_path; |
254 | 0 | } |
255 | | |
256 | | template <typename K> |
257 | | bool Exists(const K& key) const |
258 | 0 | { |
259 | 0 | DataStream ssKey{}; |
260 | 0 | ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); |
261 | 0 | ssKey << key; |
262 | 0 | return ExistsImpl(ssKey); |
263 | 0 | } Unexecuted instantiation: _ZNK10CDBWrapper6ExistsIhEEbRKT_ Unexecuted instantiation: txdb.cpp:_ZNK10CDBWrapper6ExistsIN12_GLOBAL__N_19CoinEntryEEEbRKT_ |
264 | | |
265 | | template <typename K> |
266 | | bool Erase(const K& key, bool fSync = false) |
267 | 0 | { |
268 | 0 | CDBBatch batch(*this); |
269 | 0 | batch.Erase(key); |
270 | 0 | return WriteBatch(batch, fSync); |
271 | 0 | } |
272 | | |
273 | | bool WriteBatch(CDBBatch& batch, bool fSync = false); |
274 | | |
275 | | // Get an estimate of LevelDB memory usage (in bytes). |
276 | | size_t DynamicMemoryUsage() const; |
277 | | |
278 | | CDBIterator* NewIterator(); |
279 | | |
280 | | /** |
281 | | * Return true if the database managed by this class contains no entries. |
282 | | */ |
283 | | bool IsEmpty(); |
284 | | |
285 | | template<typename K> |
286 | | size_t EstimateSize(const K& key_begin, const K& key_end) const |
287 | 0 | { |
288 | 0 | DataStream ssKey1{}, ssKey2{}; |
289 | 0 | ssKey1.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); |
290 | 0 | ssKey2.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); |
291 | 0 | ssKey1 << key_begin; |
292 | 0 | ssKey2 << key_end; |
293 | 0 | return EstimateSizeImpl(ssKey1, ssKey2); |
294 | 0 | } |
295 | | }; |
296 | | |
297 | | #endif // BITCOIN_DBWRAPPER_H |