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 <flatfile.h>6#include <node/blockstorage.h>7#include <streams.h>8#include <test/util/common.h>9#include <test/util/random.h>10#include <test/util/setup_common.h>11#include <util/fs.h>12#include <util/obfuscation.h>13#include <util/strencodings.h>15#include <boost/test/unit_test.hpp>17using namespace std::string_literals;18using namespace util::hex_literals;20BOOST_FIXTURE_TEST_SUITE(streams_tests, BasicTestingSetup)22// Check optimized obfuscation with random offsets and sizes to ensure proper23// handling of key wrapping. Also verify it roundtrips.24BOOST_AUTO_TEST_CASE(xor_random_chunks)25{26auto apply_random_xor_chunks{[&](std::span<std::byte> target, const Obfuscation& obfuscation) {27for (size_t offset{0}; offset < target.size();) {28const size_t chunk_size{1 + m_rng.randrange(target.size() - offset)};29obfuscation(target.subspan(offset, chunk_size), offset);30offset += chunk_size;31}32}};34for (size_t test{0}; test < 100; ++test) {35const size_t write_size{1 + m_rng.randrange(100U)};36const std::vector original{m_rng.randbytes<std::byte>(write_size)};37std::vector roundtrip{original};39const auto key_bytes{m_rng.randbool() ? m_rng.randbytes<Obfuscation::KEY_SIZE>() : std::array<std::byte, Obfuscation::KEY_SIZE>{}};40const Obfuscation obfuscation{key_bytes};41apply_random_xor_chunks(roundtrip, obfuscation);42BOOST_CHECK_EQUAL(roundtrip.size(), original.size());43for (size_t i{0}; i < original.size(); ++i) {44BOOST_CHECK_EQUAL(roundtrip[i], original[i] ^ key_bytes[i % Obfuscation::KEY_SIZE]);45}47apply_random_xor_chunks(roundtrip, obfuscation);48BOOST_CHECK_EQUAL_COLLECTIONS(roundtrip.begin(), roundtrip.end(), original.begin(), original.end());49}50}52BOOST_AUTO_TEST_CASE(obfuscation_hexkey)53{54const auto key_bytes{m_rng.randbytes<Obfuscation::KEY_SIZE>()};56const Obfuscation obfuscation{key_bytes};57BOOST_CHECK_EQUAL(obfuscation.HexKey(), HexStr(key_bytes));58}60BOOST_AUTO_TEST_CASE(obfuscation_serialize)61{62Obfuscation obfuscation{};63BOOST_CHECK(!obfuscation);65// Test loading a key.66std::vector key_in{m_rng.randbytes<std::byte>(Obfuscation::KEY_SIZE)};67DataStream ds_in;68ds_in << key_in;69BOOST_CHECK_EQUAL(ds_in.size(), 1 + Obfuscation::KEY_SIZE); // serialized as a vector70ds_in >> obfuscation;72// Test saving the key.73std::vector<std::byte> key_out;74DataStream ds_out;75ds_out << obfuscation;76ds_out >> key_out;78// Make sure saved key is the same.79BOOST_CHECK_EQUAL_COLLECTIONS(key_in.begin(), key_in.end(), key_out.begin(), key_out.end());80}82BOOST_AUTO_TEST_CASE(obfuscation_empty)83{84const Obfuscation null_obf{};85BOOST_CHECK(!null_obf);87const Obfuscation non_null_obf{"ff00ff00ff00ff00"_hex};88BOOST_CHECK(non_null_obf);89}91BOOST_AUTO_TEST_CASE(streams_scoped_data_stream_usage)92{93DataStream stream{};94{95ScopedDataStreamUsage usage{stream};96stream << uint8_t{42};97BOOST_CHECK_GT(stream.size(), 0U);98}99BOOST_CHECK(stream.empty());101{102ScopedDataStreamUsage usage{stream};103stream << uint16_t{42};104BOOST_CHECK_GT(stream.size(), 0U);105}106BOOST_CHECK(stream.empty());107}109BOOST_AUTO_TEST_CASE(xor_file)110{111fs::path xor_path{m_args.GetDataDirBase() / "test_xor.bin"};112auto raw_file{[&](const auto& mode) { return fsbridge::fopen(xor_path, mode); }};113const std::vector<uint8_t> test1{1, 2, 3};114const std::vector<uint8_t> test2{4, 5};115const Obfuscation obfuscation{"ff00ff00ff00ff00"_hex};117{118// Check errors for missing file119AutoFile xor_file{raw_file("rb"), obfuscation};120BOOST_CHECK_EXCEPTION(xor_file << std::byte{}, std::ios_base::failure, HasReason{"AutoFile::write: file handle is nullptr"});121BOOST_CHECK_EXCEPTION(xor_file >> std::byte{}, std::ios_base::failure, HasReason{"AutoFile::read: file handle is nullptr"});122BOOST_CHECK_EXCEPTION(xor_file.ignore(1), std::ios_base::failure, HasReason{"AutoFile::ignore: file handle is nullptr"});123BOOST_CHECK_EXCEPTION(xor_file.size(), std::ios_base::failure, HasReason{"AutoFile::size: file handle is nullptr"});124}125{126#ifdef __MINGW64__127// Temporary workaround for https://github.com/bitcoin/bitcoin/issues/30210128const char* mode = "wb";129#else130const char* mode = "wbx";131#endif132AutoFile xor_file{raw_file(mode), obfuscation};133xor_file << test1 << test2;134BOOST_CHECK_EQUAL(xor_file.size(), 7);135BOOST_REQUIRE_EQUAL(xor_file.fclose(), 0);136}137{138// Read raw from disk139AutoFile non_xor_file{raw_file("rb")};140std::vector<std::byte> raw(7);141non_xor_file >> std::span{raw};142BOOST_CHECK_EQUAL(HexStr(raw), "fc01fd03fd04fa");143// Check that no padding exists144BOOST_CHECK_EXCEPTION(non_xor_file.ignore(1), std::ios_base::failure, HasReason{"AutoFile::ignore: end of file"});145BOOST_CHECK_EQUAL(non_xor_file.size(), 7);146}147{148AutoFile xor_file{raw_file("rb"), obfuscation};149std::vector<std::byte> read1, read2;150xor_file >> read1 >> read2;151BOOST_CHECK_EQUAL(HexStr(read1), HexStr(test1));152BOOST_CHECK_EQUAL(HexStr(read2), HexStr(test2));153// Check that eof was reached154BOOST_CHECK_EXCEPTION(xor_file >> std::byte{}, std::ios_base::failure, HasReason{"AutoFile::read: end of file"});155BOOST_CHECK_EQUAL(xor_file.size(), 7);156}157{158AutoFile xor_file{raw_file("rb"), obfuscation};159std::vector<std::byte> read2;160// Check that ignore works161xor_file.ignore(4);162xor_file >> read2;163BOOST_CHECK_EQUAL(HexStr(read2), HexStr(test2));164// Check that ignore and read fail now165BOOST_CHECK_EXCEPTION(xor_file.ignore(1), std::ios_base::failure, HasReason{"AutoFile::ignore: end of file"});166BOOST_CHECK_EXCEPTION(xor_file >> std::byte{}, std::ios_base::failure, HasReason{"AutoFile::read: end of file"});167BOOST_CHECK_EQUAL(xor_file.size(), 7);168}169}171BOOST_AUTO_TEST_CASE(streams_vector_writer)172{173unsigned char a(1);174unsigned char b(2);175unsigned char bytes[] = {3, 4, 5, 6};176std::vector<unsigned char> vch;178// Each test runs twice. Serializing a second time at the same starting179// point should yield the same results, even if the first test grew the180// vector.182VectorWriter{vch, 0, a, b};183BOOST_CHECK((vch == std::vector<unsigned char>{{1, 2}}));184VectorWriter{vch, 0, a, b};185BOOST_CHECK((vch == std::vector<unsigned char>{{1, 2}}));186vch.clear();188VectorWriter{vch, 2, a, b};189BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2}}));190VectorWriter{vch, 2, a, b};191BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2}}));192vch.clear();194vch.resize(5, 0);195VectorWriter{vch, 2, a, b};196BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2, 0}}));197VectorWriter{vch, 2, a, b};198BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 1, 2, 0}}));199vch.clear();201vch.resize(4, 0);202VectorWriter{vch, 3, a, b};203BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 1, 2}}));204VectorWriter{vch, 3, a, b};205BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 1, 2}}));206vch.clear();208vch.resize(4, 0);209VectorWriter{vch, 4, a, b};210BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 0, 1, 2}}));211VectorWriter{vch, 4, a, b};212BOOST_CHECK((vch == std::vector<unsigned char>{{0, 0, 0, 0, 1, 2}}));213vch.clear();215VectorWriter{vch, 0, bytes};216BOOST_CHECK((vch == std::vector<unsigned char>{{3, 4, 5, 6}}));217VectorWriter{vch, 0, bytes};218BOOST_CHECK((vch == std::vector<unsigned char>{{3, 4, 5, 6}}));219vch.clear();221vch.resize(4, 8);222VectorWriter{vch, 2, a, bytes, b};223BOOST_CHECK((vch == std::vector<unsigned char>{{8, 8, 1, 3, 4, 5, 6, 2}}));224VectorWriter{vch, 2, a, bytes, b};225BOOST_CHECK((vch == std::vector<unsigned char>{{8, 8, 1, 3, 4, 5, 6, 2}}));226vch.clear();227}229BOOST_AUTO_TEST_CASE(streams_span_writer)230{231unsigned char a(1);232unsigned char b(2);233unsigned char bytes[] = {3, 4, 5, 6};234std::array<std::byte, 8> arr{};236// Test operator<<237SpanWriter writer{arr};238writer << a << b;239BOOST_CHECK_EQUAL(HexStr(arr), "0102000000000000");241// Use variadic constructor and write to subspan.242SpanWriter{std::span{arr}.subspan(2), a, bytes, b};243BOOST_CHECK_EQUAL(HexStr(arr), "0102010304050602");245// Writing past the end throws246std::array<std::byte, 1> small{};247BOOST_CHECK_THROW(SpanWriter(std::span{small}, a, b), std::ios_base::failure);248BOOST_CHECK_THROW(SpanWriter(std::span{small}) << a << b, std::ios_base::failure);249}
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.