From abf86243568af380c1384ac4e0bfcdcfd4dab085 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sat, 18 Jan 2020 06:49:14 -0800 Subject: Add custom vector-element formatter This allows a very compact notation for serialization of vectors whose elements are not serialized using their default encoding. --- src/serialize.h | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/serialize.h b/src/serialize.h index 8161f6c91f..fd0a20e346 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -596,6 +596,53 @@ public: template BigEndian WrapBigEndian(I& n) { return BigEndian(n); } +/** Formatter to serialize/deserialize vector elements using another formatter + * + * Example: + * struct X { + * std::vector v; + * SERIALIZE_METHODS(X, obj) { READWRITE(Using>(obj.v)); } + * }; + * will define a struct that contains a vector of uint64_t, which is serialized + * as a vector of VarInt-encoded integers. + * + * V is not required to be an std::vector type. It works for any class that + * exposes a value_type, size, reserve, push_back, and const iterators. + */ +template +struct VectorFormatter +{ + template + void Ser(Stream& s, const V& v) + { + WriteCompactSize(s, v.size()); + for (const typename V::value_type& elem : v) { + s << Using(elem); + } + } + + template + void Unser(Stream& s, V& v) + { + v.clear(); + size_t size = ReadCompactSize(s); + size_t allocated = 0; + while (allocated < size) { + // For DoS prevention, do not blindly allocate as much as the stream claims to contain. + // Instead, allocate in 5MiB batches, so that an attacker actually needs to provide + // X MiB of data to make us allocate X+5 Mib. + static_assert(sizeof(typename V::value_type) <= MAX_VECTOR_ALLOCATE, "Vector element size too large"); + allocated = std::min(size, allocated + MAX_VECTOR_ALLOCATE / sizeof(typename V::value_type)); + v.reserve(allocated); + while (v.size() < allocated) { + typename V::value_type val; + s >> Using(val); + v.push_back(std::move(val)); + } + } + }; +}; + /** * Forward declarations */ -- cgit v1.2.3