Inside Bitcoin
Opening the selected file…
Inside Bitcoin
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>6#include <test/util/common.h>7#include <test/util/random.h>8#include <test/util/setup_common.h>9#include <uint256.h>10#include <util/byte_units.h>11#include <util/string.h>13#include <fstream>14#include <memory>15#include <ranges>17#include <boost/test/unit_test.hpp>19using util::ToString;21BOOST_FIXTURE_TEST_SUITE(dbwrapper_tests, BasicTestingSetup)23BOOST_AUTO_TEST_CASE(dbwrapper)24{25// Perform tests both obfuscated and non-obfuscated.26for (const bool obfuscate : {false, true}) {27constexpr size_t CACHE_SIZE{1_MiB};28const fs::path path{m_args.GetDataDirBase() / "dbwrapper"};30Obfuscation obfuscation;31std::vector<std::pair<uint8_t, uint256>> key_values{};33// Write values34{35CDBWrapper dbw{{.path = path, .cache_bytes = CACHE_SIZE, .wipe_data = true, .obfuscate = obfuscate}};36BOOST_CHECK_EQUAL(obfuscate, !dbw.IsEmpty());38// Ensure that we're doing real obfuscation when obfuscate=true39obfuscation = dbwrapper_private::GetObfuscation(dbw);40BOOST_CHECK_EQUAL(obfuscate, dbwrapper_private::GetObfuscation(dbw));42for (uint8_t k{0}; k < 10; ++k) {43uint8_t key{k};44uint256 value{m_rng.rand256()};45dbw.Write(key, value);46key_values.emplace_back(key, value);47}48}50// Verify that the obfuscation key is never obfuscated51{52CDBWrapper dbw{{.path = path, .cache_bytes = CACHE_SIZE, .obfuscate = false}};53BOOST_CHECK_EQUAL(obfuscation, dbwrapper_private::GetObfuscation(dbw));54}56// Read back the values57{58CDBWrapper dbw{{.path = path, .cache_bytes = CACHE_SIZE, .obfuscate = obfuscate}};60// Ensure obfuscation is read back correctly61BOOST_CHECK_EQUAL(obfuscation, dbwrapper_private::GetObfuscation(dbw));62BOOST_CHECK_EQUAL(obfuscate, dbwrapper_private::GetObfuscation(dbw));64// Verify all written values65for (const auto& [key, expected_value] : key_values) {66uint256 read_value{};67BOOST_CHECK(dbw.Read(key, read_value));68BOOST_CHECK_EQUAL(read_value, expected_value);69}70}71}72}74BOOST_AUTO_TEST_CASE(dbwrapper_basic_data)75{76// Perform tests both obfuscated and non-obfuscated.77for (bool obfuscate : {false, true}) {78fs::path ph = m_args.GetDataDirBase() / (obfuscate ? "dbwrapper_1_obfuscate_true" : "dbwrapper_1_obfuscate_false");79CDBWrapper dbw({.path = ph, .cache_bytes = 1_MiB, .memory_only = false, .wipe_data = true, .obfuscate = obfuscate});81uint256 res;82uint32_t res_uint_32;83bool res_bool;85// Ensure that we're doing real obfuscation when obfuscate=true86BOOST_CHECK_EQUAL(obfuscate, dbwrapper_private::GetObfuscation(dbw));88//Simulate block raw data - "b + block hash"89std::string key_block = "b" + m_rng.rand256().ToString();91uint256 in_block = m_rng.rand256();92dbw.Write(key_block, in_block);93BOOST_CHECK(dbw.Read(key_block, res));94BOOST_CHECK_EQUAL(res.ToString(), in_block.ToString());96//Simulate file raw data - "f + file_number"97std::string key_file = strprintf("f%04x", m_rng.rand32());99uint256 in_file_info = m_rng.rand256();100dbw.Write(key_file, in_file_info);101BOOST_CHECK(dbw.Read(key_file, res));102BOOST_CHECK_EQUAL(res.ToString(), in_file_info.ToString());104//Simulate transaction raw data - "t + transaction hash"105std::string key_transaction = "t" + m_rng.rand256().ToString();107uint256 in_transaction = m_rng.rand256();108dbw.Write(key_transaction, in_transaction);109BOOST_CHECK(dbw.Read(key_transaction, res));110BOOST_CHECK_EQUAL(res.ToString(), in_transaction.ToString());112//Simulate UTXO raw data - "c + transaction hash"113std::string key_utxo = "c" + m_rng.rand256().ToString();115uint256 in_utxo = m_rng.rand256();116dbw.Write(key_utxo, in_utxo);117BOOST_CHECK(dbw.Read(key_utxo, res));118BOOST_CHECK_EQUAL(res.ToString(), in_utxo.ToString());120//Simulate last block file number - "l"121uint8_t key_last_blockfile_number{'l'};122uint32_t lastblockfilenumber = m_rng.rand32();123dbw.Write(key_last_blockfile_number, lastblockfilenumber);124BOOST_CHECK(dbw.Read(key_last_blockfile_number, res_uint_32));125BOOST_CHECK_EQUAL(lastblockfilenumber, res_uint_32);127//Simulate Is Reindexing - "R"128uint8_t key_IsReindexing{'R'};129bool isInReindexing = m_rng.randbool();130dbw.Write(key_IsReindexing, isInReindexing);131BOOST_CHECK(dbw.Read(key_IsReindexing, res_bool));132BOOST_CHECK_EQUAL(isInReindexing, res_bool);134//Simulate last block hash up to which UXTO covers - 'B'135uint8_t key_lastblockhash_uxto{'B'};136uint256 lastblock_hash = m_rng.rand256();137dbw.Write(key_lastblockhash_uxto, lastblock_hash);138BOOST_CHECK(dbw.Read(key_lastblockhash_uxto, res));139BOOST_CHECK_EQUAL(lastblock_hash, res);141//Simulate file raw data - "F + filename_number + filename"142std::string file_option_tag = "F";143uint8_t filename_length = m_rng.randbits(8);144std::string filename = "randomfilename";145std::string key_file_option = strprintf("%s%01x%s", file_option_tag, filename_length, filename);147bool in_file_bool = m_rng.randbool();148dbw.Write(key_file_option, in_file_bool);149BOOST_CHECK(dbw.Read(key_file_option, res_bool));150BOOST_CHECK_EQUAL(res_bool, in_file_bool);151}152}154// Test batch operations155BOOST_AUTO_TEST_CASE(dbwrapper_batch)156{157// Perform tests both obfuscated and non-obfuscated.158for (const bool obfuscate : {false, true}) {159fs::path ph = m_args.GetDataDirBase() / (obfuscate ? "dbwrapper_batch_obfuscate_true" : "dbwrapper_batch_obfuscate_false");160CDBWrapper dbw({.path = ph, .cache_bytes = 1_MiB, .memory_only = true, .wipe_data = false, .obfuscate = obfuscate});162uint8_t key{'i'};163uint256 in = m_rng.rand256();164uint8_t key2{'j'};165uint256 in2 = m_rng.rand256();166uint8_t key3{'k'};167uint256 in3 = m_rng.rand256();169uint256 res;170CDBBatch batch(dbw);172batch.Write(key, in);173batch.Write(key2, in2);174batch.Write(key3, in3);176// Remove key3 before it's even been written177batch.Erase(key3);179dbw.WriteBatch(batch);181BOOST_CHECK(dbw.Read(key, res));182BOOST_CHECK_EQUAL(res.ToString(), in.ToString());183BOOST_CHECK(dbw.Read(key2, res));184BOOST_CHECK_EQUAL(res.ToString(), in2.ToString());186// key3 should've never been written187BOOST_CHECK(dbw.Read(key3, res) == false);189batch.Clear();190batch.Write(key3, in3);191dbw.WriteBatch(batch);193BOOST_CHECK(dbw.Read(key3, res));194BOOST_CHECK_EQUAL(res.ToString(), in3.ToString());195}196}198// Verify that Read() returns false (without throwing) when the stored value199// fails to be deserialized200BOOST_AUTO_TEST_CASE(dbwrapper_read_returns_false_on_deserialization_error)201{202for (const bool obfuscate : {false, true}) {203const fs::path path{m_args.GetDataDirBase() / (obfuscate ? "dbwrapper_deser_obf" : "dbwrapper_deser_noobf")};204CDBWrapper dbw({.path = path, .cache_bytes = 1 << 20, .wipe_data = true, .obfuscate = obfuscate});206constexpr uint8_t key{'X'};208// Write a single byte. uint256 requires 32 bytes, so reading this key209// as uint256 must trigger a deserialization error inside Read()210dbw.Write(key, uint8_t{0xFF});211BOOST_CHECK(dbw.Exists(key));213// Read() must catch the deserialization exception and return false,214// the same as if the key were absent215uint256 result;216BOOST_CHECK(!dbw.Read(key, result));217}218}220// Verify Read() throws dbwrapper_error due to an internal db error221BOOST_AUTO_TEST_CASE(dbwrapper_read_throws_on_db_error)222{223const fs::path path{m_args.GetDataDirBase() / "dbwrapper_db_error"};224constexpr uint8_t key{'Y'};226const auto make_db = [] (const fs::path& path, const bool force_compact) {227return CDBWrapper({.path = path, .cache_bytes = 1 << 20, .obfuscate = false,228.options = {.force_compact = force_compact}});229};231// Write a value and close the database232make_db(path, /*force_compact=*/false).Write(key, m_rng.rand256());234// Force compaction to ensure the data is written into the .ldb files235// rather than left in the WAL.236(void)make_db(path, /*force_compact=*/true);238// Corrupt every table so any subsequent Read() fails239for (const auto& entry : fs::directory_iterator(path)) {240if (entry.path().extension() == ".ldb") {241std::ofstream{entry.path(), std::ios::binary | std::ios::trunc}242.write("\xff", 1);243}244}246// Read() should detect the issue now and throw247const auto db{make_db(path, /*force_compact=*/false)};248uint256 result;249BOOST_CHECK_EXCEPTION(db.Read(key, result), dbwrapper_error, HasReason("Fatal LevelDB error"));
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.