Coverage Report

Created: 2026-07-30 14:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/root/bitcoin/src/dbwrapper.h
Line
Count
Source
1
// Copyright (c) 2012-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_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/byte_units.h>
13
#include <util/check.h>
14
#include <util/fs.h>
15
#include <util/obfuscation.h>
16
17
#include <cstddef>
18
#include <cstdint>
19
#include <exception>
20
#include <memory>
21
#include <optional>
22
#include <span>
23
#include <stdexcept>
24
#include <string>
25
26
namespace leveldb {
27
class Env;
28
} // namespace leveldb
29
30
static const size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64;
31
static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024;
32
static const size_t DBWRAPPER_MAX_FILE_SIZE{32_MiB};
33
34
//! User-controlled performance and debug options.
35
struct DBOptions {
36
    //! Compact database on startup.
37
    bool force_compact = false;
38
};
39
40
//! Application-specific storage settings.
41
struct DBParams {
42
    //! Location in the filesystem where leveldb data will be stored.
43
    fs::path path;
44
    //! Configures various leveldb cache settings.
45
    uint64_t cache_bytes;
46
    //! If true, use leveldb's memory environment.
47
    bool memory_only = false;
48
    //! If true, remove all existing data.
49
    bool wipe_data = false;
50
    //! If true, store data obfuscated via simple XOR. If false, XOR with a
51
    //! zero'd byte array.
52
    bool obfuscate = false;
53
    //! If true, build a LevelDB bloom filter to accelerate point lookups.
54
    bool bloom_filter = true;
55
    //! Passed-through options.
56
    DBOptions options{};
57
    //! If non-null, use this as the leveldb::Env instead of the default.
58
    //! Caller retains ownership.
59
    leveldb::Env* testing_env = nullptr;
60
    //! Maximum LevelDB SST file size. Larger values reduce the frequency
61
    //! of compactions but increase their duration.
62
    size_t max_file_size = DBWRAPPER_MAX_FILE_SIZE;
63
};
64
65
class dbwrapper_error : public std::runtime_error
66
{
67
public:
68
0
    explicit dbwrapper_error(const std::string& msg) : std::runtime_error(msg) {}
69
};
70
71
class CDBWrapper;
72
73
/** These should be considered an implementation detail of the specific database.
74
 */
75
namespace dbwrapper_private {
76
77
/** Work around circular dependency, as well as for testing in dbwrapper_tests.
78
 * Database obfuscation should be considered an implementation detail of the
79
 * specific database.
80
 */
81
const Obfuscation& GetObfuscation(const CDBWrapper&);
82
}; // namespace dbwrapper_private
83
84
bool DestroyDB(const std::string& path_str);
85
86
/** Batch of changes queued to be written to a CDBWrapper */
87
class CDBBatch
88
{
89
    friend class CDBWrapper;
90
91
private:
92
    const CDBWrapper &parent;
93
94
    struct WriteBatchImpl;
95
    const std::unique_ptr<WriteBatchImpl> m_impl_batch;
96
97
    DataStream m_key_scratch{};
98
    DataStream m_value_scratch{};
99
100
    void WriteImpl(std::span<const std::byte> key, DataStream& value);
101
    void EraseImpl(std::span<const std::byte> key);
102
103
public:
104
    /**
105
     * @param[in] _parent   CDBWrapper that this batch is to be submitted to
106
     */
107
    explicit CDBBatch(const CDBWrapper& _parent);
108
    ~CDBBatch();
109
    void Clear();
110
111
    template <typename K, typename V>
112
    void Write(const K& key, const V& value)
113
0
    {
114
0
        ScopedDataStreamUsage scoped_key{m_key_scratch}, scoped_value{m_value_scratch};
115
0
        m_key_scratch << key;
116
0
        m_value_scratch << value;
117
0
        WriteImpl(m_key_scratch, m_value_scratch);
118
0
    }
Unexecuted instantiation: _ZN8CDBBatch5WriteItSt6vectorIhSaIhEEEEvRKT_RKT0_
Unexecuted instantiation: _ZN8CDBBatch5WriteINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE11ObfuscationEEvRKT_RKT0_
Unexecuted instantiation: _ZN8CDBBatch5WriteIhhEEvRKT_RKT0_
Unexecuted instantiation: _ZN8CDBBatch5WriteISt4pairIhiEN6kernel14CBlockFileInfoEEEvRKT_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: _ZN8CDBBatch5WriteIh11FlatFilePosEEvRKT_RKT0_
Unexecuted instantiation: blockfilterindex.cpp:_ZN8CDBBatch5WriteIN10index_util11DBHeightKeyESt4pairI7uint256N12_GLOBAL__N_15DBValEEEEvRKT_RKT0_
Unexecuted instantiation: blockfilterindex.cpp:_ZN8CDBBatch5WriteIN10index_util9DBHashKeyEN12_GLOBAL__N_15DBValEEEvRKT_RKT0_
Unexecuted instantiation: coinstatsindex.cpp:_ZN8CDBBatch5WriteIN10index_util11DBHeightKeyESt4pairI7uint256N12_GLOBAL__N_15DBValEEEEvRKT_RKT0_
Unexecuted instantiation: coinstatsindex.cpp:_ZN8CDBBatch5WriteIN10index_util9DBHashKeyEN12_GLOBAL__N_15DBValEEEvRKT_RKT0_
Unexecuted instantiation: _ZN8CDBBatch5WriteIh10MuHash3072EEvRKT_RKT0_
Unexecuted instantiation: _ZN8CDBBatch5WriteISt4pairIh7uint256E10CDiskTxPosEEvRKT_RKT0_
Unexecuted instantiation: _ZN8CDBBatch5WriteIA12_cSt4pairImmEEEvRKT_RKT0_
Unexecuted instantiation: _ZN8CDBBatch5WriteI5DBKeySt4spanIKSt4byteLm18446744073709551615EEEEvRKT_RKT0_
119
120
    template <typename K>
121
    void Erase(const K& key)
122
0
    {
123
0
        ScopedDataStreamUsage scoped_key{m_key_scratch};
124
0
        m_key_scratch << key;
125
0
        EraseImpl(m_key_scratch);
126
0
    }
Unexecuted instantiation: _ZN8CDBBatch5EraseItEEvRKT_
Unexecuted instantiation: _ZN8CDBBatch5EraseIhEEvRKT_
Unexecuted instantiation: txdb.cpp:_ZN8CDBBatch5EraseIN12_GLOBAL__N_19CoinEntryEEEvRKT_
Unexecuted instantiation: _ZN8CDBBatch5EraseI5DBKeyEEvRKT_
127
128
    size_t ApproximateSize() const;
129
};
130
131
class CDBIterator
132
{
133
public:
134
    struct IteratorImpl;
135
136
private:
137
    const CDBWrapper &parent;
138
    const std::unique_ptr<IteratorImpl> m_impl_iter;
139
    DataStream m_scratch{};
140
141
    void SeekImpl(std::span<const std::byte> key);
142
    std::span<const std::byte> GetKeyImpl() const;
143
    std::span<const std::byte> GetValueImpl() const;
144
145
public:
146
147
    /**
148
     * @param[in] _parent          Parent CDBWrapper instance.
149
     * @param[in] _piter           The original leveldb iterator.
150
     */
151
    CDBIterator(const CDBWrapper& _parent, std::unique_ptr<IteratorImpl> _piter);
152
    ~CDBIterator();
153
154
    bool Valid() const;
155
156
    void SeekToFirst();
157
158
0
    template<typename K> void Seek(const K& key) {
159
0
        ScopedDataStreamUsage scoped_scratch{m_scratch};
160
0
        m_scratch << key;
161
0
        SeekImpl(m_scratch);
162
0
    }
Unexecuted instantiation: _ZN11CDBIterator4SeekItEEvRKT_
Unexecuted instantiation: _ZN11CDBIterator4SeekISt4pairIh7uint256EEEvRKT_
Unexecuted instantiation: _ZN11CDBIterator4SeekIhEEvRKT_
Unexecuted instantiation: _ZN11CDBIterator4SeekIN10index_util11DBHeightKeyEEEvRKT_
Unexecuted instantiation: _ZN11CDBIterator4SeekISt4pairIhmEEEvRKT_
163
164
    void Next();
165
166
0
    template<typename K> bool GetKey(K& key) {
167
0
        try {
168
0
            SpanReader ssKey{GetKeyImpl()};
169
0
            ssKey >> key;
170
0
        } catch (const std::exception&) {
171
0
            return false;
172
0
        }
173
0
        return true;
174
0
    }
Unexecuted instantiation: _ZN11CDBIterator6GetKeyINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEbRT_
Unexecuted instantiation: _ZN11CDBIterator6GetKeyItEEbRT_
Unexecuted instantiation: _ZN11CDBIterator6GetKeyISt4pairIh7uint256EEEbRT_
Unexecuted instantiation: txdb.cpp:_ZN11CDBIterator6GetKeyIN12_GLOBAL__N_19CoinEntryEEEbRT_
Unexecuted instantiation: _ZN11CDBIterator6GetKeyIN10index_util11DBHeightKeyEEEbRT_
Unexecuted instantiation: _ZN11CDBIterator6GetKeyI5DBKeyEEbRT_
175
176
0
    template<typename V> bool GetValue(V& value) {
177
0
        try {
178
0
            ScopedDataStreamUsage scoped_scratch{m_scratch};
179
0
            m_scratch.write(GetValueImpl());
180
0
            dbwrapper_private::GetObfuscation(parent)(m_scratch);
181
0
            m_scratch >> value;
182
0
        } catch (const std::exception&) {
183
0
            return false;
184
0
        }
185
0
        return true;
186
0
    }
Unexecuted instantiation: _ZN11CDBIterator8GetValueISt6vectorIhSaIhEEEEbRT_
Unexecuted instantiation: _ZN11CDBIterator8GetValueI15CDiskBlockIndexEEbRT_
Unexecuted instantiation: _ZN11CDBIterator8GetValueI4CoinEEbRT_
Unexecuted instantiation: blockfilterindex.cpp:_ZN11CDBIterator8GetValueISt4pairI7uint256N12_GLOBAL__N_15DBValEEEEbRT_
Unexecuted instantiation: coinstatsindex.cpp:_ZN11CDBIterator8GetValueISt4pairI7uint256N12_GLOBAL__N_15DBValEEEEbRT_
187
};
188
189
struct LevelDBContext;
190
191
class CDBWrapper
192
{
193
    friend const Obfuscation& dbwrapper_private::GetObfuscation(const CDBWrapper&);
194
private:
195
    //! holds all leveldb-specific fields of this class
196
    std::unique_ptr<LevelDBContext> m_db_context;
197
198
    //! the name of this database
199
    std::string m_name;
200
201
    //! optional XOR-obfuscation of the database
202
    Obfuscation m_obfuscation;
203
204
    //! obfuscation key storage key, null-prefixed to avoid collisions
205
    inline static const std::string OBFUSCATION_KEY{"\000obfuscate_key", 14}; // explicit size to avoid truncation at leading \0
206
207
    std::optional<std::string> ReadImpl(std::span<const std::byte> key) const;
208
    bool ExistsImpl(std::span<const std::byte> key) const;
209
    size_t EstimateSizeImpl(std::span<const std::byte> key1, std::span<const std::byte> key2) const;
210
29.3k
    auto& DBContext() const LIFETIMEBOUND { return *Assert(m_db_context); }
211
212
public:
213
    CDBWrapper(const DBParams& params);
214
    ~CDBWrapper();
215
216
    CDBWrapper(const CDBWrapper&) = delete;
217
    CDBWrapper& operator=(const CDBWrapper&) = delete;
218
219
    template <typename K, typename V>
220
    bool Read(const K& key, V& value) const
221
14.6k
    {
222
14.6k
        DataStream ssKey{};
223
14.6k
        ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
224
14.6k
        ssKey << key;
225
14.6k
        std::optional<std::string> strValue{ReadImpl(ssKey)};
226
14.6k
        if (!strValue) {
  Branch (226:13): [True: 0, False: 0]
  Branch (226:13): [True: 0, False: 0]
  Branch (226:13): [True: 0, False: 0]
  Branch (226:13): [True: 0, False: 0]
  Branch (226:13): [True: 0, False: 0]
  Branch (226:13): [True: 0, False: 0]
  Branch (226:13): [True: 14.6k, False: 0]
  Branch (226:13): [True: 0, False: 0]
  Branch (226:13): [True: 0, False: 0]
  Branch (226:13): [True: 0, False: 0]
  Branch (226:13): [True: 0, False: 0]
  Branch (226:13): [True: 0, False: 0]
  Branch (226:13): [True: 0, False: 0]
  Branch (226:13): [True: 0, False: 0]
  Branch (226:13): [True: 0, False: 0]
  Branch (226:13): [True: 0, False: 0]
  Branch (226:13): [True: 0, False: 0]
  Branch (226:13): [True: 0, False: 0]
  Branch (226:13): [True: 0, False: 0]
227
14.6k
            return false;
228
14.6k
        }
229
0
        try {
230
0
            std::span ssValue{MakeWritableByteSpan(*strValue)};
231
0
            m_obfuscation(ssValue);
232
0
            SpanReader{ssValue} >> value;
233
0
        } catch (const std::exception&) {
234
0
            return false;
235
0
        }
236
0
        return true;
237
0
    }
Unexecuted instantiation: _ZNK10CDBWrapper4ReadItSt6vectorIhSaIhEEEEbRKT_RT0_
Unexecuted instantiation: dbwrapper.cpp:_ZNK10CDBWrapper4ReadItN12_GLOBAL__N_115FailUnserializeEEEbRKT_RT0_
Unexecuted instantiation: _ZNK10CDBWrapper4ReadINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE11ObfuscationEEbRKT_RT0_
Unexecuted instantiation: _ZNK10CDBWrapper4ReadISt4pairIhiEN6kernel14CBlockFileInfoEEEbRKT_RT0_
Unexecuted instantiation: _ZNK10CDBWrapper4ReadIhiEEbRKT_RT0_
Unexecuted instantiation: _ZNK10CDBWrapper4ReadISt4pairIhNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEhEEbRKT_RT0_
txdb.cpp:_ZNK10CDBWrapper4ReadIN12_GLOBAL__N_19CoinEntryE4CoinEEbRKT_RT0_
Line
Count
Source
221
14.6k
    {
222
14.6k
        DataStream ssKey{};
223
14.6k
        ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
224
14.6k
        ssKey << key;
225
14.6k
        std::optional<std::string> strValue{ReadImpl(ssKey)};
226
14.6k
        if (!strValue) {
  Branch (226:13): [True: 14.6k, False: 0]
227
14.6k
            return false;
228
14.6k
        }
229
0
        try {
230
0
            std::span ssValue{MakeWritableByteSpan(*strValue)};
231
0
            m_obfuscation(ssValue);
232
0
            SpanReader{ssValue} >> value;
233
0
        } catch (const std::exception&) {
234
0
            return false;
235
0
        }
236
0
        return true;
237
0
    }
Unexecuted instantiation: _ZNK10CDBWrapper4ReadIh7uint256EEbRKT_RT0_
Unexecuted instantiation: _ZNK10CDBWrapper4ReadIhSt6vectorI7uint256SaIS2_EEEEbRKT_RT0_
Unexecuted instantiation: _ZNK10CDBWrapper4ReadIh13CBlockLocatorEEbRKT_RT0_
Unexecuted instantiation: blockfilterindex.cpp:_ZNK10CDBWrapper4ReadIN10index_util9DBHashKeyEN12_GLOBAL__N_15DBValEEEbRKT_RT0_
Unexecuted instantiation: _ZNK10CDBWrapper4ReadIh11FlatFilePosEEbRKT_RT0_
Unexecuted instantiation: blockfilterindex.cpp:_ZNK10CDBWrapper4ReadIN10index_util11DBHeightKeyESt4pairI7uint256N12_GLOBAL__N_15DBValEEEEbRKT_RT0_
Unexecuted instantiation: coinstatsindex.cpp:_ZNK10CDBWrapper4ReadIN10index_util9DBHashKeyEN12_GLOBAL__N_15DBValEEEbRKT_RT0_
Unexecuted instantiation: _ZNK10CDBWrapper4ReadIh10MuHash3072EEbRKT_RT0_
Unexecuted instantiation: coinstatsindex.cpp:_ZNK10CDBWrapper4ReadIN10index_util11DBHeightKeyESt4pairI7uint256N12_GLOBAL__N_15DBValEEEEbRKT_RT0_
Unexecuted instantiation: coinstatsindex.cpp:_ZNK10CDBWrapper4ReadIN10index_util9DBHashKeyESt4pairI7uint256N12_GLOBAL__N_15DBValEEEEbRKT_RT0_
Unexecuted instantiation: _ZNK10CDBWrapper4ReadISt4pairIh7uint256E10CDiskTxPosEEbRKT_RT0_
Unexecuted instantiation: _ZNK10CDBWrapper4ReadIA12_cSt4pairImmEEEbRKT_RT0_
238
239
    template <typename K, typename V>
240
    void Write(const K& key, const V& value, bool fSync = false)
241
0
    {
242
0
        CDBBatch batch(*this);
243
0
        batch.Write(key, value);
244
0
        WriteBatch(batch, fSync);
245
0
    }
Unexecuted instantiation: _ZN10CDBWrapper5WriteItSt6vectorIhSaIhEEEEvRKT_RKT0_b
Unexecuted instantiation: _ZN10CDBWrapper5WriteINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE11ObfuscationEEvRKT_RKT0_b
Unexecuted instantiation: _ZN10CDBWrapper5WriteIhhEEvRKT_RKT0_b
Unexecuted instantiation: _ZN10CDBWrapper5WriteISt4pairIhNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEhEEvRKT_RKT0_b
Unexecuted instantiation: blockfilterindex.cpp:_ZN10CDBWrapper5WriteIN10index_util11DBHeightKeyESt4pairI7uint256N12_GLOBAL__N_15DBValEEEEvRKT_RKT0_b
Unexecuted instantiation: coinstatsindex.cpp:_ZN10CDBWrapper5WriteIN10index_util11DBHeightKeyESt4pairI7uint256N12_GLOBAL__N_15DBValEEEEvRKT_RKT0_b
Unexecuted instantiation: _ZN10CDBWrapper5WriteIA12_cSt4pairImmEEEvRKT_RKT0_b
246
247
    template <typename K>
248
    bool Exists(const K& key) const
249
0
    {
250
0
        DataStream ssKey{};
251
0
        ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
252
0
        ssKey << key;
253
0
        return ExistsImpl(ssKey);
254
0
    }
Unexecuted instantiation: _ZNK10CDBWrapper6ExistsItEEbRKT_
Unexecuted instantiation: _ZNK10CDBWrapper6ExistsIhEEbRKT_
Unexecuted instantiation: txdb.cpp:_ZNK10CDBWrapper6ExistsIN12_GLOBAL__N_19CoinEntryEEEbRKT_
255
256
    template <typename K>
257
    void Erase(const K& key, bool fSync = false)
258
0
    {
259
0
        CDBBatch batch(*this);
260
0
        batch.Erase(key);
261
0
        WriteBatch(batch, fSync);
262
0
    }
Unexecuted instantiation: _ZN10CDBWrapper5EraseItEEvRKT_b
Unexecuted instantiation: _ZN10CDBWrapper5EraseIhEEvRKT_b
263
264
    void WriteBatch(CDBBatch& batch, bool fSync = false);
265
266
    //! Perform a blocking full compaction of the underlying LevelDB.
267
    void CompactFull();
268
269
    //! Return a LevelDB property value, if available.
270
    std::optional<std::string> GetProperty(const std::string& property) const;
271
272
    // Get an estimate of LevelDB memory usage (in bytes).
273
    size_t DynamicMemoryUsage() const;
274
275
    CDBIterator* NewIterator();
276
277
    /**
278
     * Return true if the database managed by this class contains no entries.
279
     */
280
    bool IsEmpty();
281
282
    template<typename K>
283
    size_t EstimateSize(const K& key_begin, const K& key_end) const
284
0
    {
285
0
        DataStream ssKey1{}, ssKey2{};
286
0
        ssKey1.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
287
0
        ssKey2.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
288
0
        ssKey1 << key_begin;
289
0
        ssKey2 << key_end;
290
0
        return EstimateSizeImpl(ssKey1, ssKey2);
291
0
    }
Unexecuted instantiation: _ZNK10CDBWrapper12EstimateSizeItEEmRKT_S3_
Unexecuted instantiation: _ZNK10CDBWrapper12EstimateSizeIhEEmRKT_S3_
292
};
293
294
#endif // BITCOIN_DBWRAPPER_H