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.
251// TryRead() must return DatabaseError (without throwing).252CDBWrapper::ReadStatus status = db.TryRead(key, result);253BOOST_REQUIRE(!status);254BOOST_CHECK(status.error().status == CDBWrapper::ReadFailure::Code::DatabaseError);255BOOST_CHECK(status.error().err_msg.find("Fatal LevelDB error") != std::string::npos);256}258// Exercise TryRead() return values directly: found, absent and DeserializationError.259// DatabaseError is tested inside 'dbwrapper_read_throws_on_db_error' test260BOOST_AUTO_TEST_CASE(dbwrapper_tryread)261{262for (const bool obfuscate : {false, true}) {263const fs::path path{m_args.GetDataDirBase() / (obfuscate ? "dbwrapper_tryread_obf" : "dbwrapper_tryread_noobf")};264CDBWrapper dbw({.path = path, .cache_bytes = 1 << 20, .wipe_data = true, .obfuscate = obfuscate});266constexpr uint8_t key_ok{'A'};267constexpr uint8_t key_missing{'B'};268constexpr uint8_t key_bad{'C'};270uint256 written_value{m_rng.rand256()};271dbw.Write(key_ok, written_value);272dbw.Write(key_bad, uint8_t{0xFF});274// Found: key exists, value deserializes correctly275{276uint256 read_value;277CDBWrapper::ReadStatus status = dbw.TryRead(key_ok, read_value);278BOOST_REQUIRE(status);279BOOST_CHECK(status.value());280BOOST_CHECK_EQUAL(read_value, written_value);281}283// Absent: key does not exist284{285uint256 read_value;286CDBWrapper::ReadStatus status = dbw.TryRead(key_missing, read_value);287BOOST_REQUIRE(status);288BOOST_CHECK(!status.value());289}291// DeserializationError: key exists but stored value is too short292{293uint256 read_value;294CDBWrapper::ReadStatus status = dbw.TryRead(key_bad, read_value);295BOOST_REQUIRE(!status);296BOOST_CHECK(status.error().status == CDBWrapper::ReadFailure::Code::DeserializationError);297BOOST_CHECK(!status.error().err_msg.empty());298}299}300}302BOOST_AUTO_TEST_CASE(dbwrapper_iterator)303{304// Perform tests both obfuscated and non-obfuscated.305for (const bool obfuscate : {false, true}) {306fs::path ph = m_args.GetDataDirBase() / (obfuscate ? "dbwrapper_iterator_obfuscate_true" : "dbwrapper_iterator_obfuscate_false");307CDBWrapper dbw({.path = ph, .cache_bytes = 1_MiB, .memory_only = true, .wipe_data = false, .obfuscate = obfuscate});309// The two keys are intentionally chosen for ordering310uint8_t key{'j'};311uint256 in = m_rng.rand256();312dbw.Write(key, in);313uint8_t key2{'k'};314uint256 in2 = m_rng.rand256();315dbw.Write(key2, in2);317std::unique_ptr<CDBIterator> it(dbw.NewIterator());319// Be sure to seek past the obfuscation key (if it exists)320it->Seek(key);322// A failed key decode must not consume the current iterator entry.323uint16_t key_too_large{0};324BOOST_CHECK(!it->GetKey(key_too_large));326uint8_t key_res;328BOOST_REQUIRE(it->GetKey(key_res));329BOOST_CHECK_EQUAL(key_res, key);330// A failed value decode must not leave the iterator's scratch stream dirty.331std::pair<uint256, uint8_t> value_too_large;332BOOST_CHECK(!it->GetValue(value_too_large));334uint256 val_res;335BOOST_REQUIRE(it->GetValue(val_res));336BOOST_CHECK_EQUAL(val_res.ToString(), in.ToString());338it->Seek(key2);340BOOST_REQUIRE(it->GetKey(key_res));341BOOST_CHECK_EQUAL(key_res, key2);342BOOST_REQUIRE(it->GetValue(val_res));343BOOST_CHECK_EQUAL(val_res.ToString(), in2.ToString());345it->Seek(key);347BOOST_REQUIRE(it->GetKey(key_res));348BOOST_CHECK_EQUAL(key_res, key);349BOOST_REQUIRE(it->GetValue(val_res));350BOOST_CHECK_EQUAL(val_res.ToString(), in.ToString());352it->Next();354BOOST_REQUIRE(it->GetKey(key_res));355BOOST_CHECK_EQUAL(key_res, key2);356BOOST_REQUIRE(it->GetValue(val_res));357BOOST_CHECK_EQUAL(val_res.ToString(), in2.ToString());359it->Next();360BOOST_CHECK_EQUAL(it->Valid(), false);361}362}364// Test that we do not obfuscation if there is existing data.365BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)366{367// We're going to share this fs::path between two wrappers368fs::path ph = m_args.GetDataDirBase() / "existing_data_no_obfuscate";369fs::create_directories(ph);371// Set up a non-obfuscated wrapper to write some initial data.372std::unique_ptr<CDBWrapper> dbw = std::make_unique<CDBWrapper>(DBParams{.path = ph, .cache_bytes = 1 << 10, .memory_only = false, .wipe_data = false, .obfuscate = false});373uint8_t key{'k'};374uint256 in = m_rng.rand256();375uint256 res;377dbw->Write(key, in);378BOOST_CHECK(dbw->Read(key, res));379BOOST_CHECK_EQUAL(res.ToString(), in.ToString());381// Call the destructor to free leveldb LOCK382dbw.reset();384// Now, set up another wrapper that wants to obfuscate the same directory385CDBWrapper odbw({.path = ph, .cache_bytes = 1 << 10, .memory_only = false, .wipe_data = false, .obfuscate = true});387// Check that the key/val we wrote with unobfuscated wrapper exists and388// is readable.389uint256 res2;390BOOST_CHECK(odbw.Read(key, res2));391BOOST_CHECK_EQUAL(res2.ToString(), in.ToString());393BOOST_CHECK(!odbw.IsEmpty());394BOOST_CHECK(!dbwrapper_private::GetObfuscation(odbw)); // The key should be an empty string396uint256 in2 = m_rng.rand256();397uint256 res3;399// Check that we can write successfully400odbw.Write(key, in2);401BOOST_CHECK(odbw.Read(key, res3));402BOOST_CHECK_EQUAL(res3.ToString(), in2.ToString());403}405// Ensure that we start obfuscating during a reindex.406BOOST_AUTO_TEST_CASE(existing_data_reindex)407{408// We're going to share this fs::path between two wrappers409fs::path ph = m_args.GetDataDirBase() / "existing_data_reindex";410fs::create_directories(ph);412// Set up a non-obfuscated wrapper to write some initial data.413std::unique_ptr<CDBWrapper> dbw = std::make_unique<CDBWrapper>(DBParams{.path = ph, .cache_bytes = 1 << 10, .memory_only = false, .wipe_data = false, .obfuscate = false});414uint8_t key{'k'};415uint256 in = m_rng.rand256();416uint256 res;418dbw->Write(key, in);419BOOST_CHECK(dbw->Read(key, res));420BOOST_CHECK_EQUAL(res.ToString(), in.ToString());422// Call the destructor to free leveldb LOCK423dbw.reset();425// Simulate a -reindex by wiping the existing data store426CDBWrapper odbw({.path = ph, .cache_bytes = 1 << 10, .memory_only = false, .wipe_data = true, .obfuscate = true});428// Check that the key/val we wrote with unobfuscated wrapper doesn't exist429uint256 res2;430BOOST_CHECK(!odbw.Read(key, res2));431BOOST_CHECK(dbwrapper_private::GetObfuscation(odbw));433uint256 in2 = m_rng.rand256();434uint256 res3;436// Check that we can write successfully437odbw.Write(key, in2);438BOOST_CHECK(odbw.Read(key, res3));439BOOST_CHECK_EQUAL(res3.ToString(), in2.ToString());440}442BOOST_AUTO_TEST_CASE(iterator_ordering)443{444fs::path ph = m_args.GetDataDirBase() / "iterator_ordering";445CDBWrapper dbw({.path = ph, .cache_bytes = 1_MiB, .memory_only = true, .wipe_data = false, .obfuscate = false});446for (int x=0x00; x<256; ++x) {447uint8_t key = x;448uint32_t value = x*x;449if (!(x & 1)) dbw.Write(key, value);450}452// Check that creating an iterator creates a snapshot453std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper&>(dbw).NewIterator());455for (unsigned int x=0x00; x<256; ++x) {456uint8_t key = x;457uint32_t value = x*x;458if (x & 1) dbw.Write(key, value);459}461for (const int seek_start : {0x00, 0x80}) {462it->Seek((uint8_t)seek_start);463for (unsigned int x=seek_start; x<255; ++x) {464uint8_t key;465uint32_t value;466BOOST_CHECK(it->Valid());467if (!it->Valid()) // Avoid spurious errors about invalid iterator's key and value in case of failure468break;469BOOST_CHECK(it->GetKey(key));470if (x & 1) {471BOOST_CHECK_EQUAL(key, x + 1);472continue;473}474BOOST_CHECK(it->GetValue(value));475BOOST_CHECK_EQUAL(key, x);476BOOST_CHECK_EQUAL(value, x*x);477it->Next();478}479BOOST_CHECK(!it->Valid());480}481}483struct StringContentsSerializer {484// Used to make two serialized objects the same while letting them have different lengths485// This is a terrible idea486std::string str;487StringContentsSerializer() = default;488explicit StringContentsSerializer(const std::string& inp) : str(inp) {}490template<typename Stream>491void Serialize(Stream& s) const492{493for (size_t i = 0; i < str.size(); i++) {494s << uint8_t(str[i]);495}496}498template<typename Stream>499void Unserialize(Stream& s)500{
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.