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.
501struct VarIntFormatter502{503template<typename Stream, typename I> void Ser(Stream &s, I v)504{505WriteVarInt<Stream,Mode, std::remove_cv_t<I>>(s, v);506}508template<typename Stream, typename I> void Unser(Stream& s, I& v)509{510v = ReadVarInt<Stream,Mode, std::remove_cv_t<I>>(s);511}512};514/** Serialization wrapper class for custom integers and enums.515*516* It permits specifying the serialized size (1 to 8 bytes) and endianness.517*518* Use the big endian mode for values that are stored in memory in native519* byte order, but serialized in big endian notation. This is only intended520* to implement serializers that are compatible with existing formats, and521* its use is not recommended for new data structures.522*/523template<int Bytes, bool BigEndian = false>524struct CustomUintFormatter525{526static_assert(Bytes > 0 && Bytes <= 8, "CustomUintFormatter Bytes out of range");527static constexpr uint64_t MAX = 0xffffffffffffffff >> (8 * (8 - Bytes));529template <typename Stream, typename I> void Ser(Stream& s, I v)530{531if (v < 0 || v > MAX) throw std::ios_base::failure("CustomUintFormatter value out of range");532if (BigEndian) {533uint64_t raw = htobe64_internal(v);534s.write(std::as_bytes(std::span{&raw, 1}).last(Bytes));535} else {536uint64_t raw = htole64_internal(v);537s.write(std::as_bytes(std::span{&raw, 1}).first(Bytes));538}539}541template <typename Stream, typename I> void Unser(Stream& s, I& v)542{543using U = typename std::conditional_t<std::is_enum_v<I>, std::underlying_type<I>, std::common_type<I>>::type;544static_assert(std::numeric_limits<U>::max() >= MAX && std::numeric_limits<U>::min() <= 0, "Assigned type too small");545uint64_t raw = 0;546if (BigEndian) {547s.read(std::as_writable_bytes(std::span{&raw, 1}).last(Bytes));548v = static_cast<I>(be64toh_internal(raw));549} else {550s.read(std::as_writable_bytes(std::span{&raw, 1}).first(Bytes));551v = static_cast<I>(le64toh_internal(raw));552}553}554};556template<int Bytes> using BigEndianFormatter = CustomUintFormatter<Bytes, true>;558/** Formatter for integers in CompactSize format. */559template<bool RangeCheck>560struct CompactSizeFormatter561{562template<typename Stream, typename I>563void Unser(Stream& s, I& v)564{565uint64_t n = ReadCompactSize<Stream>(s, RangeCheck);566if (n < std::numeric_limits<I>::min() || n > std::numeric_limits<I>::max()) {567throw std::ios_base::failure("CompactSize exceeds limit of type");568}569v = n;570}572template<typename Stream, typename I>573void Ser(Stream& s, I v)574{575static_assert(std::is_unsigned_v<I>, "CompactSize only supported for unsigned integers");576static_assert(std::numeric_limits<I>::max() <= std::numeric_limits<uint64_t>::max(), "CompactSize only supports 64-bit integers and below");578WriteCompactSize<Stream>(s, v);579}580};582template <typename U, bool LOSSY = false>583struct ChronoFormatter {584template <typename Stream, typename Tp>585void Unser(Stream& s, Tp& tp)586{587U u;588s >> u;589// Lossy deserialization does not make sense, so force Wnarrowing590tp = Tp{typename Tp::duration{typename Tp::duration::rep{u}}};591}592template <typename Stream, typename Tp>593void Ser(Stream& s, Tp tp)594{595if constexpr (LOSSY) {596s << U(tp.time_since_epoch().count());597} else {598s << U{tp.time_since_epoch().count()};599}600}601};602template <typename U>603using LossyChronoFormatter = ChronoFormatter<U, true>;605class CompactSizeReader606{607protected:608uint64_t& n;609public:610explicit CompactSizeReader(uint64_t& n_in) : n(n_in) {}612template<typename Stream>613void Unserialize(Stream &s) const {614n = ReadCompactSize<Stream>(s);615}616};618class CompactSizeWriter619{620protected:621uint64_t n;622public:623explicit CompactSizeWriter(uint64_t n_in) : n(n_in) { }625template<typename Stream>626void Serialize(Stream &s) const {627WriteCompactSize<Stream>(s, n);628}629};631template<size_t Limit>632struct LimitedStringFormatter633{634template<typename Stream>635void Unser(Stream& s, std::string& v)636{637size_t size = ReadCompactSize(s);638if (size > Limit) {639throw std::ios_base::failure("String length limit exceeded");640}641v.resize(size);642if (size != 0) s.read(MakeWritableByteSpan(v));643}645template<typename Stream>646void Ser(Stream& s, const std::string& v)647{648s << v;649}650};652/** Formatter to serialize/deserialize vector elements using another formatter653*654* Example:655* struct X {656* std::vector<uint64_t> v;657* SERIALIZE_METHODS(X, obj) { READWRITE(Using<VectorFormatter<VarInt>>(obj.v)); }658* };659* will define a struct that contains a vector of uint64_t, which is serialized660* as a vector of VarInt-encoded integers.661*662* V is not required to be an std::vector type. It works for any class that663* exposes a value_type, size, reserve, emplace_back, back, and const iterators.664*/665template<class Formatter>666struct VectorFormatter667{668template<typename Stream, typename V>669void Ser(Stream& s, const V& v)670{671Formatter formatter;672WriteCompactSize(s, v.size());673for (const typename V::value_type& elem : v) {674formatter.Ser(s, elem);675}676}678template<typename Stream, typename V>679void Unser(Stream& s, V& v)680{681Formatter formatter;682v.clear();683size_t size = ReadCompactSize(s);684size_t allocated = 0;685while (allocated < size) {686// For DoS prevention, do not blindly allocate as much as the stream claims to contain.687// Instead, allocate in 5MiB batches, so that an attacker actually needs to provide688// X MiB of data to make us allocate X+5 Mib.689static_assert(sizeof(typename V::value_type) <= MAX_VECTOR_ALLOCATE, "Vector element size too large");690allocated = std::min(size, allocated + MAX_VECTOR_ALLOCATE / sizeof(typename V::value_type));691v.reserve(allocated);692while (v.size() < allocated) {693v.emplace_back();694formatter.Unser(s, v.back());695}696}697};698};700/**701* Forward declarations702*/704/**705* string706*/707template<typename Stream, typename C> void Serialize(Stream& os, const std::basic_string<C>& str);708template<typename Stream, typename C> void Unserialize(Stream& is, std::basic_string<C>& str);710/**711* string_view712*/713template<typename Stream, typename C> void Serialize(Stream& os, const std::basic_string_view<C>& str);714template<typename Stream, typename C> void Unserialize(Stream& is, std::basic_string_view<C>& str) = delete;716/**717* prevector718*/719template<typename Stream, unsigned int N, typename T> inline void Serialize(Stream& os, const prevector<N, T>& v);720template<typename Stream, unsigned int N, typename T> inline void Unserialize(Stream& is, prevector<N, T>& v);722/**723* vector724*/725template<typename Stream, typename T, typename A> inline void Serialize(Stream& os, const std::vector<T, A>& v);726template<typename Stream, typename T, typename A> inline void Unserialize(Stream& is, std::vector<T, A>& v);728/**729* pair730*/731template<typename Stream, typename K, typename T> void Serialize(Stream& os, const std::pair<K, T>& item);732template<typename Stream, typename K, typename T> void Unserialize(Stream& is, std::pair<K, T>& item);734/**735* map736*/737template<typename Stream, typename K, typename T, typename Pred, typename A> void Serialize(Stream& os, const std::map<K, T, Pred, A>& m);738template<typename Stream, typename K, typename T, typename Pred, typename A> void Unserialize(Stream& is, std::map<K, T, Pred, A>& m);740/**741* set742*/743template<typename Stream, typename K, typename Pred, typename A> void Serialize(Stream& os, const std::set<K, Pred, A>& m);744template<typename Stream, typename K, typename Pred, typename A> void Unserialize(Stream& is, std::set<K, Pred, A>& m);746/**747* shared_ptr748*/749template<typename Stream, typename T> void Serialize(Stream& os, const std::shared_ptr<const T>& p);750template<typename Stream, typename T> void Unserialize(Stream& os, std::shared_ptr<const T>& p);