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#include <dbwrapper.h>7#include <leveldb/cache.h>8#include <leveldb/db.h>9#include <leveldb/env.h>10#include <leveldb/filter_policy.h>11#include <leveldb/helpers/memenv/memenv.h>12#include <leveldb/iterator.h>13#include <leveldb/options.h>14#include <leveldb/slice.h>15#include <leveldb/status.h>16#include <leveldb/write_batch.h>17#include <random.h>18#include <serialize.h>19#include <span.h>20#include <streams.h>21#include <util/byte_units.h>22#include <util/fs.h>23#include <util/fs_helpers.h>24#include <util/log.h>25#include <util/obfuscation.h>26#include <util/strencodings.h>28#include <algorithm>29#include <cassert>30#include <cstdarg>31#include <cstdint>32#include <cstdio>33#include <memory>34#include <optional>35#include <utility>37static auto CharCast(const std::byte* data) { return reinterpret_cast<const char*>(data); }39bool DestroyDB(const std::string& path_str)40{41return leveldb::DestroyDB(path_str, {}).ok();42}44/** Handle database error by throwing dbwrapper_error exception.45*/46static void HandleError(const leveldb::Status& status)47{48if (status.ok())49return;50const std::string errmsg = "Fatal LevelDB error: " + status.ToString();51LogError("%s", errmsg);52LogInfo("You can use -debug=leveldb to get more complete diagnostic messages");53throw dbwrapper_error(errmsg);54}56class CBitcoinLevelDBLogger : public leveldb::Logger {57public:58// This code is adapted from posix_logger.h, which is why it is using vsprintf.59// Please do not do this in normal code60void Logv(const char * format, va_list ap) override {61if (!util::log::ShouldDebugLog(BCLog::LEVELDB)) {62return;63}64char buffer[500];65for (int iter = 0; iter < 2; iter++) {66char* base;67int bufsize;68if (iter == 0) {69bufsize = sizeof(buffer);70base = buffer;71}72else {73bufsize = 30000;74base = new char[bufsize];75}76char* p = base;77char* limit = base + bufsize;79// Print the message80if (p < limit) {81va_list backup_ap;82va_copy(backup_ap, ap);83// Do not use vsnprintf elsewhere in bitcoin source code, see above.84p += vsnprintf(p, limit - p, format, backup_ap);85va_end(backup_ap);86}88// Truncate to available space if necessary89if (p >= limit) {90if (iter == 0) {91continue; // Try again with larger buffer92}93else {94p = limit - 1;95}96}98// Add newline if necessary99if (p == base || p[-1] != '\n') {100*p++ = '\n';101}103assert(p <= limit);104base[std::min(bufsize - 1, (int)(p - base))] = '\0';105LogDebug(BCLog::LEVELDB, "%s\n", util::RemoveSuffixView(base, "\n"));106if (base != buffer) {107delete[] base;108}109break;110}111}112};114static void SetMaxOpenFiles(leveldb::Options *options) {115// On most platforms the default setting of max_open_files (which is 1000)116// is optimal. On Windows using a large file count is OK because the handles117// do not interfere with select() loops. On 64-bit Unix hosts this value is118// also OK, because up to that amount LevelDB will use an mmap119// implementation that does not use extra file descriptors (the fds are120// closed after being mmap'ed).121//122// Increasing the value beyond the default is dangerous because LevelDB will123// fall back to a non-mmap implementation when the file count is too large.124// On 32-bit Unix host we should decrease the value because the handles use125// up real fds, and we want to avoid fd exhaustion issues.126//127// See PR #12495 for further discussion.129int default_open_files = options->max_open_files;130#ifndef WIN32131if (sizeof(void*) < 8) {132options->max_open_files = 64;133}134#endif135LogDebug(BCLog::LEVELDB, "LevelDB using max_open_files=%d (default=%d)\n",136options->max_open_files, default_open_files);137}139static leveldb::Options GetOptions(size_t nCacheSize, bool bloom_filter)140{141leveldb::Options options;142options.block_cache = leveldb::NewLRUCache(nCacheSize / 2);143options.write_buffer_size = nCacheSize / 4; // up to two write buffers may be held in memory simultaneously144options.filter_policy = bloom_filter ? leveldb::NewBloomFilterPolicy(10) : nullptr;145options.compression = leveldb::kNoCompression;146options.info_log = new CBitcoinLevelDBLogger();147if (leveldb::kMajorVersion > 1 || (leveldb::kMajorVersion == 1 && leveldb::kMinorVersion >= 16)) {148// LevelDB versions before 1.16 consider short writes to be corruption. Only trigger error149// on corruption in later versions.150options.paranoid_checks = true;151}152SetMaxOpenFiles(&options);153return options;154}156bool CDBWrapper::HasKeyStartingWith(const fs::path& path, uint8_t prefix)157{158if (!fs::exists(path / "CURRENT")) return false;160CBitcoinLevelDBLogger logger;161leveldb::Options options;162options.paranoid_checks = true;163// Avoid creating or rotating LevelDB's LOG files during this probe.164options.info_log = &logger;166leveldb::DB* raw_db;167HandleError(leveldb::DB::Open(options, fs::PathToString(path), &raw_db));168const std::unique_ptr<leveldb::DB> db{raw_db};170leveldb::ReadOptions iteroptions;171iteroptions.verify_checksums = true;172iteroptions.fill_cache = false;173const std::unique_ptr<leveldb::Iterator> it{db->NewIterator(iteroptions)};174const leveldb::Slice prefix_slice{reinterpret_cast<const char*>(&prefix), sizeof(prefix)};175it->Seek(prefix_slice);176HandleError(it->status());177return it->Valid() && it->key().starts_with(prefix_slice);178}180struct CDBBatch::WriteBatchImpl {181leveldb::WriteBatch batch;182};184CDBBatch::CDBBatch(const CDBWrapper& _parent)185: parent{_parent},186m_impl_batch{std::make_unique<CDBBatch::WriteBatchImpl>()}187{188m_key_scratch.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);189m_value_scratch.reserve(DBWRAPPER_PREALLOC_VALUE_SIZE);190Clear();191};193CDBBatch::~CDBBatch() = default;195void CDBBatch::Clear()196{197m_impl_batch->batch.Clear();198assert(m_key_scratch.empty());199assert(m_value_scratch.empty());200}202void CDBBatch::WriteImpl(std::span<const std::byte> key, DataStream& value)203{204leveldb::Slice slKey(CharCast(key.data()), key.size());205dbwrapper_private::GetObfuscation(parent)(value);206leveldb::Slice slValue(CharCast(value.data()), value.size());207m_impl_batch->batch.Put(slKey, slValue);208}210void CDBBatch::EraseImpl(std::span<const std::byte> key)211{212leveldb::Slice slKey(CharCast(key.data()), key.size());213m_impl_batch->batch.Delete(slKey);214}216size_t CDBBatch::ApproximateSize() const217{218return m_impl_batch->batch.ApproximateSize();219}221struct LevelDBContext {222//! custom environment this database is using (may be nullptr in case of default environment)223leveldb::Env* penv;225//! database options used226leveldb::Options options;228//! options used when reading from the database229leveldb::ReadOptions readoptions;231//! options used when iterating over values of the database232leveldb::ReadOptions iteroptions;234//! options used when writing to the database235leveldb::WriteOptions writeoptions;237//! options used when sync writing to the database238leveldb::WriteOptions syncoptions;240//! the database itself241leveldb::DB* pdb;242};244CDBWrapper::CDBWrapper(const DBParams& params)245: m_db_context{std::make_unique<LevelDBContext>()}, m_name{fs::PathToString(params.path.stem())}246{247DBContext().penv = nullptr;248DBContext().readoptions.verify_checksums = true;249DBContext().iteroptions.verify_checksums = true;250DBContext().iteroptions.fill_cache = false;
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.