Inside Bitcoin
Opening the selected file…
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2012-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#ifndef BITCOIN_DBWRAPPER_H6#define BITCOIN_DBWRAPPER_H8#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/expected.h>15#include <util/fs.h>16#include <util/obfuscation.h>18#include <cstddef>19#include <cstdint>20#include <exception>21#include <memory>22#include <optional>23#include <span>24#include <stdexcept>25#include <string>27namespace leveldb {28class Env;29} // namespace leveldb31inline constexpr size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64;32inline constexpr size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024;33inline constexpr size_t DBWRAPPER_MAX_FILE_SIZE{32_MiB};35//! User-controlled performance and debug options.36struct DBOptions {37//! Compact database on startup.38bool force_compact = false;39};41//! Application-specific storage settings.42struct DBParams {43//! Location in the filesystem where leveldb data will be stored.44fs::path path;45//! Configures various leveldb cache settings.46uint64_t cache_bytes;47//! If true, use leveldb's memory environment.48bool memory_only = false;49//! If true, remove all existing data.50bool wipe_data = false;51//! If true, store data obfuscated via simple XOR. If false, XOR with a52//! zero'd byte array.53bool obfuscate = false;54//! If true, build a LevelDB bloom filter to accelerate point lookups.55bool bloom_filter = true;56//! Passed-through options.57DBOptions options{};58//! If non-null, use this as the leveldb::Env instead of the default.59//! Caller retains ownership.60leveldb::Env* testing_env = nullptr;61//! Maximum LevelDB SST file size. Larger values reduce the frequency62//! of compactions but increase their duration.63size_t max_file_size = DBWRAPPER_MAX_FILE_SIZE;64};66class dbwrapper_error : public std::runtime_error67{68public:69explicit dbwrapper_error(const std::string& msg) : std::runtime_error(msg) {}70};72class CDBWrapper;74/** These should be considered an implementation detail of the specific database.75*/76namespace dbwrapper_private {78/** Work around circular dependency, as well as for testing in dbwrapper_tests.79* Database obfuscation should be considered an implementation detail of the80* specific database.81*/82const Obfuscation& GetObfuscation(const CDBWrapper&);83}; // namespace dbwrapper_private85bool DestroyDB(const std::string& path_str);87/** Batch of changes queued to be written to a CDBWrapper */88class CDBBatch89{90friend class CDBWrapper;92private:93const CDBWrapper &parent;95struct WriteBatchImpl;96const std::unique_ptr<WriteBatchImpl> m_impl_batch;98DataStream m_key_scratch{};99DataStream m_value_scratch{};101void WriteImpl(std::span<const std::byte> key, DataStream& value);102void EraseImpl(std::span<const std::byte> key);104public:105/**106* @param[in] _parent CDBWrapper that this batch is to be submitted to107*/108explicit CDBBatch(const CDBWrapper& _parent);109~CDBBatch();110void Clear();112template <typename K, typename V>113void Write(const K& key, const V& value)114{115ScopedDataStreamUsage scoped_key{m_key_scratch}, scoped_value{m_value_scratch};116m_key_scratch << key;117m_value_scratch << value;118WriteImpl(m_key_scratch, m_value_scratch);119}121template <typename K>122void Erase(const K& key)123{124ScopedDataStreamUsage scoped_key{m_key_scratch};125m_key_scratch << key;126EraseImpl(m_key_scratch);127}129size_t ApproximateSize() const;130};132class CDBIterator133{134public:135struct IteratorImpl;137private:138const CDBWrapper &parent;139const std::unique_ptr<IteratorImpl> m_impl_iter;140DataStream m_scratch{};142void SeekImpl(std::span<const std::byte> key);143std::span<const std::byte> GetKeyImpl() const;144std::span<const std::byte> GetValueImpl() const;146public:148/**149* @param[in] _parent Parent CDBWrapper instance.150* @param[in] _piter The original leveldb iterator.151*/152CDBIterator(const CDBWrapper& _parent, std::unique_ptr<IteratorImpl> _piter);153~CDBIterator();155bool Valid() const;157void SeekToFirst();159template<typename K> void Seek(const K& key) {160ScopedDataStreamUsage scoped_scratch{m_scratch};161m_scratch << key;162SeekImpl(m_scratch);163}165void Next();167template<typename K> bool GetKey(K& key) {168try {169SpanReader ssKey{GetKeyImpl()};170ssKey >> key;171} catch (const std::exception&) {172return false;173}174return true;175}177template<typename V> bool GetValue(V& value) {178try {179ScopedDataStreamUsage scoped_scratch{m_scratch};180m_scratch.write(GetValueImpl());181dbwrapper_private::GetObfuscation(parent)(m_scratch);182m_scratch >> value;183} catch (const std::exception&) {184return false;185}186return true;187}188};190struct LevelDBContext;192class CDBWrapper193{194friend const Obfuscation& dbwrapper_private::GetObfuscation(const CDBWrapper&);195private:196//! holds all leveldb-specific fields of this class197std::unique_ptr<LevelDBContext> m_db_context;199//! the name of this database200std::string m_name;202//! optional XOR-obfuscation of the database203Obfuscation m_obfuscation;205//! obfuscation key storage key, null-prefixed to avoid collisions206inline static const std::string OBFUSCATION_KEY{"\000obfuscate_key", 14}; // explicit size to avoid truncation at leading \0208std::optional<std::string> ReadImpl(std::span<const std::byte> key) const;209bool ExistsImpl(std::span<const std::byte> key) const;210size_t EstimateSizeImpl(std::span<const std::byte> key1, std::span<const std::byte> key2) const;211auto& DBContext() const LIFETIMEBOUND { return *Assert(m_db_context); }213public:214CDBWrapper(const DBParams& params);215~CDBWrapper();217CDBWrapper(const CDBWrapper&) = delete;218CDBWrapper& operator=(const CDBWrapper&) = delete;220struct ReadFailure {221enum class Code {222DeserializationError, //!< Key exists but value could not be deserialized.223DatabaseError, //!< Unexpected internal DB error.224};226Code status;227std::string err_msg;228};230using ReadStatus = util::Expected<bool, ReadFailure>;232/**233* Read and deserialize a value from the database, with explicit error discrimination.234*235* Unlike Read(), this method distinguishes between a missing key, a deserialization236* failure (DeserializationError), and an internal DB error (DatabaseError),237* enabling callers to treat data corruption differently from an absent entry.238*239* @note Callers are expected to provide well-formed keys; key serialization240* is the only operation that may throw.241*242* @param[in] key The key to look up.243* @param[out] value Populated with the deserialized value when the returned244* Expected holds true; indeterminate otherwise.245* @return On success, true if the key was found (value populated) or false if246* the key was absent. On failure, a ReadFailure describing the error.247*/248template <typename K, typename V>249[[nodiscard]] ReadStatus TryRead(const K& key, V& value) const250{