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) 2009-2010 Satoshi Nakamoto2// Copyright (c) 2009-present The Bitcoin Core developers3// Distributed under the MIT software license, see the accompanying4// file COPYING or http://www.opensource.org/licenses/mit-license.php.6#ifndef BITCOIN_STREAMS_H7#define BITCOIN_STREAMS_H9#include <serialize.h>10#include <span.h>11#include <support/allocators/zeroafterfree.h>12#include <util/check.h>13#include <util/log.h>14#include <util/obfuscation.h>15#include <util/overflow.h>16#include <util/syserror.h>18#include <algorithm>19#include <cassert>20#include <cstddef>21#include <cstdint>22#include <cstdio>23#include <cstring>24#include <ios>25#include <limits>26#include <optional>27#include <string>28#include <vector>30/* Minimal stream for overwriting and/or appending to an existing byte vector31*32* The referenced vector will grow as necessary33*/34class VectorWriter35{36public:37/*38* @param[in] vchDataIn Referenced byte vector to overwrite/append39* @param[in] nPosIn Starting position. Vector index where writes should start. The vector will initially40* grow as necessary to max(nPosIn, vec.size()). So to append, use vec.size().41*/42VectorWriter(std::vector<unsigned char>& vchDataIn, size_t nPosIn) : vchData{vchDataIn}, nPos{nPosIn}43{44if(nPos > vchData.size())45vchData.resize(nPos);46}47/*48* (other params same as above)49* @param[in] args A list of items to serialize starting at nPosIn.50*/51template <typename... Args>52VectorWriter(std::vector<unsigned char>& vchDataIn, size_t nPosIn, Args&&... args) : VectorWriter{vchDataIn, nPosIn}53{54::SerializeMany(*this, std::forward<Args>(args)...);55}56void write(std::span<const std::byte> src)57{58assert(nPos <= vchData.size());59size_t nOverwrite = std::min(src.size(), vchData.size() - nPos);60if (nOverwrite) {61memcpy(vchData.data() + nPos, src.data(), nOverwrite);62}63if (nOverwrite < src.size()) {64vchData.insert(vchData.end(), UCharCast(src.data()) + nOverwrite, UCharCast(src.data() + src.size()));65}66nPos += src.size();67}68template <typename T>69VectorWriter& operator<<(const T& obj)70{71::Serialize(*this, obj);72return (*this);73}75private:76std::vector<unsigned char>& vchData;77size_t nPos;78};80/** Minimal stream for reading from an existing byte array by std::span.81*/82class SpanReader83{84private:85std::span<const std::byte> m_data;87public:88/**89* @param[in] data Referenced byte vector to overwrite/append90*/91explicit SpanReader(std::span<const unsigned char> data) : m_data{std::as_bytes(data)} {}92explicit SpanReader(std::span<const std::byte> data) : m_data{data} {}94template<typename T>95SpanReader& operator>>(T&& obj)96{97::Unserialize(*this, obj);98return (*this);99}101size_t size() const { return m_data.size(); }102bool empty() const { return m_data.empty(); }104void read(std::span<std::byte> dst)105{106if (dst.size() == 0) {107return;108}110// Read from the beginning of the buffer111if (dst.size() > m_data.size()) {112throw std::ios_base::failure("SpanReader::read(): end of data");113}114memcpy(dst.data(), m_data.data(), dst.size());115m_data = m_data.subspan(dst.size());116}118void ignore(size_t n)119{120if (n > m_data.size()) {121throw std::ios_base::failure("SpanReader::ignore(): end of data");122}123m_data = m_data.subspan(n);124}125};127/** Minimal stream for writing to an existing span of bytes.128*/129class SpanWriter130{131private:132std::span<std::byte> m_dest;134public:135explicit SpanWriter(std::span<std::byte> dest) : m_dest{dest} {}136template <typename... Args>137SpanWriter(std::span<std::byte> dest, Args&&... args) : SpanWriter{dest}138{139::SerializeMany(*this, std::forward<Args>(args)...);140}142void write(std::span<const std::byte> src)143{144if (src.size() > m_dest.size()) {145throw std::ios_base::failure("SpanWriter::write(): exceeded buffer size");146}147memcpy(m_dest.data(), src.data(), src.size());148m_dest = m_dest.subspan(src.size());149}151template<typename T>152SpanWriter& operator<<(const T& obj)153{154::Serialize(*this, obj);155return *this;156}157};159/** Double ended buffer combining vector and stream-like interfaces.160*161* >> and << read and write unformatted data using the above serialization templates.162* Fills with data in linear time; some stringstream implementations take N^2 time.163*/164class DataStream165{166protected:167using vector_type = SerializeData;168vector_type vch;169vector_type::size_type m_read_pos{0};171public:172typedef vector_type::allocator_type allocator_type;173typedef vector_type::size_type size_type;174typedef vector_type::difference_type difference_type;175typedef vector_type::reference reference;176typedef vector_type::const_reference const_reference;177typedef vector_type::value_type value_type;178typedef vector_type::iterator iterator;179typedef vector_type::const_iterator const_iterator;180typedef vector_type::reverse_iterator reverse_iterator;182explicit DataStream() = default;183explicit DataStream(std::span<const uint8_t> sp) : DataStream{std::as_bytes(sp)} {}184explicit DataStream(std::span<const value_type> sp) : vch(sp.data(), sp.data() + sp.size()) {}186std::string str() const187{188return std::string{UCharCast(data()), UCharCast(data() + size())};189}191//192// Vector subset193//194const_iterator begin() const { return vch.begin() + m_read_pos; }195iterator begin() { return vch.begin() + m_read_pos; }196const_iterator end() const { return vch.end(); }197iterator end() { return vch.end(); }198size_type size() const { return vch.size() - m_read_pos; }199bool empty() const { return vch.size() == m_read_pos; }200void resize(size_type n, value_type c = value_type{}) { vch.resize(n + m_read_pos, c); }201void reserve(size_type n) { vch.reserve(n + m_read_pos); }202const_reference operator[](size_type pos) const { return vch[pos + m_read_pos]; }203reference operator[](size_type pos) { return vch[pos + m_read_pos]; }204void clear() { vch.clear(); m_read_pos = 0; }205value_type* data() { return vch.data() + m_read_pos; }206const value_type* data() const { return vch.data() + m_read_pos; }208//209// Stream subset210//211void read(std::span<value_type> dst)212{213if (dst.size() == 0) return;215// Read from the beginning of the buffer216auto next_read_pos{CheckedAdd(m_read_pos, dst.size())};217if (!next_read_pos.has_value() || next_read_pos.value() > vch.size()) {218throw std::ios_base::failure("DataStream::read(): end of data");219}220memcpy(dst.data(), &vch[m_read_pos], dst.size());221if (next_read_pos.value() == vch.size()) {222// If fully consumed, reset to empty state.223clear();224return;225}226m_read_pos = next_read_pos.value();227}229void ignore(size_t num_ignore)230{231// Ignore from the beginning of the buffer232auto next_read_pos{CheckedAdd(m_read_pos, num_ignore)};233if (!next_read_pos.has_value() || next_read_pos.value() > vch.size()) {234throw std::ios_base::failure("DataStream::ignore(): end of data");235}236if (next_read_pos.value() == vch.size()) {237// If all bytes are ignored, reset to empty state.238clear();239return;240}241m_read_pos = next_read_pos.value();242}244void write(std::span<const value_type> src)245{246// Write to the end of the buffer247vch.insert(vch.end(), src.begin(), src.end());248}250template<typename T>