Skip to content

Commit a654626

Browse files
committed
Merge #17896: Serialization improvements (step 2)
9b66083 Convert chain to new serialization (Pieter Wuille) 2f1b2f4 Convert VARINT to the formatter/Using approach (Pieter Wuille) ca62563 Add a generic approach for (de)serialization of objects using code in other classes (Pieter Wuille) Pull request description: This is a second carve-out from #10785. This introduces a const-correct generic approach for serializing objects using custom serializers (defined separately from the object being serialized), then converts VARINT to use that approach, and then converts chain.h to the new framework (including the new const-correct VARINT macro). ACKs for top commit: jamesob: ACK 9b66083 ([`jamesob/ackr/17896.1.sipa.serialization_improvemen`](https://github.com/jamesob/bitcoin/tree/ackr/17896.1.sipa.serialization_improvemen)) ryanofsky: Code review ACK 9b66083. Only change since last review is suggested lvalue reference tweak Tree-SHA512: 2da4af1754699cb223d6beae44c587555e39ef6951448488a04783c92e2dfd4a305934f71cc3a75d06faf6d722723d8cdbd5ccb12039783f8d62039b83987bb8
2 parents 0deba68 + 9b66083 commit a654626

File tree

2 files changed

+61
-50
lines changed

2 files changed

+61
-50
lines changed

src/chain.h

Lines changed: 25 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -48,17 +48,15 @@ class CBlockFileInfo
4848
uint64_t nTimeFirst; //!< earliest time of block in file
4949
uint64_t nTimeLast; //!< latest time of block in file
5050

51-
ADD_SERIALIZE_METHODS;
52-
53-
template <typename Stream, typename Operation>
54-
inline void SerializationOp(Stream& s, Operation ser_action) {
55-
READWRITE(VARINT(nBlocks));
56-
READWRITE(VARINT(nSize));
57-
READWRITE(VARINT(nUndoSize));
58-
READWRITE(VARINT(nHeightFirst));
59-
READWRITE(VARINT(nHeightLast));
60-
READWRITE(VARINT(nTimeFirst));
61-
READWRITE(VARINT(nTimeLast));
51+
SERIALIZE_METHODS(CBlockFileInfo, obj)
52+
{
53+
READWRITE(VARINT(obj.nBlocks));
54+
READWRITE(VARINT(obj.nSize));
55+
READWRITE(VARINT(obj.nUndoSize));
56+
READWRITE(VARINT(obj.nHeightFirst));
57+
READWRITE(VARINT(obj.nHeightLast));
58+
READWRITE(VARINT(obj.nTimeFirst));
59+
READWRITE(VARINT(obj.nTimeLast));
6260
}
6361

6462
void SetNull() {
@@ -332,31 +330,25 @@ class CDiskBlockIndex : public CBlockIndex
332330
hashPrev = (pprev ? pprev->GetBlockHash() : uint256());
333331
}
334332

335-
ADD_SERIALIZE_METHODS;
336-
337-
template <typename Stream, typename Operation>
338-
inline void SerializationOp(Stream& s, Operation ser_action) {
333+
SERIALIZE_METHODS(CDiskBlockIndex, obj)
334+
{
339335
int _nVersion = s.GetVersion();
340-
if (!(s.GetType() & SER_GETHASH))
341-
READWRITE(VARINT(_nVersion, VarIntMode::NONNEGATIVE_SIGNED));
342-
343-
READWRITE(VARINT(nHeight, VarIntMode::NONNEGATIVE_SIGNED));
344-
READWRITE(VARINT(nStatus));
345-
READWRITE(VARINT(nTx));
346-
if (nStatus & (BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO))
347-
READWRITE(VARINT(nFile, VarIntMode::NONNEGATIVE_SIGNED));
348-
if (nStatus & BLOCK_HAVE_DATA)
349-
READWRITE(VARINT(nDataPos));
350-
if (nStatus & BLOCK_HAVE_UNDO)
351-
READWRITE(VARINT(nUndoPos));
336+
if (!(s.GetType() & SER_GETHASH)) READWRITE(VARINT(_nVersion, VarIntMode::NONNEGATIVE_SIGNED));
337+
338+
READWRITE(VARINT(obj.nHeight, VarIntMode::NONNEGATIVE_SIGNED));
339+
READWRITE(VARINT(obj.nStatus));
340+
READWRITE(VARINT(obj.nTx));
341+
if (obj.nStatus & (BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO)) READWRITE(VARINT(obj.nFile, VarIntMode::NONNEGATIVE_SIGNED));
342+
if (obj.nStatus & BLOCK_HAVE_DATA) READWRITE(VARINT(obj.nDataPos));
343+
if (obj.nStatus & BLOCK_HAVE_UNDO) READWRITE(VARINT(obj.nUndoPos));
352344

353345
// block header
354-
READWRITE(this->nVersion);
355-
READWRITE(hashPrev);
356-
READWRITE(hashMerkleRoot);
357-
READWRITE(nTime);
358-
READWRITE(nBits);
359-
READWRITE(nNonce);
346+
READWRITE(obj.nVersion);
347+
READWRITE(obj.hashPrev);
348+
READWRITE(obj.hashMerkleRoot);
349+
READWRITE(obj.nTime);
350+
READWRITE(obj.nBits);
351+
READWRITE(obj.nNonce);
360352
}
361353

362354
uint256 GetBlockHash() const

src/serialize.h

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -442,26 +442,48 @@ I ReadVarInt(Stream& is)
442442
}
443443
}
444444

445-
#define VARINT(obj, ...) WrapVarInt<__VA_ARGS__>(REF(obj))
446-
#define COMPACTSIZE(obj) CCompactSize(REF(obj))
447-
#define LIMITED_STRING(obj,n) LimitedString< n >(REF(obj))
448-
449-
template<VarIntMode Mode, typename I>
450-
class CVarInt
445+
/** Simple wrapper class to serialize objects using a formatter; used by Using(). */
446+
template<typename Formatter, typename T>
447+
class Wrapper
451448
{
449+
static_assert(std::is_lvalue_reference<T>::value, "Wrapper needs an lvalue reference type T");
452450
protected:
453-
I &n;
451+
T m_object;
454452
public:
455-
explicit CVarInt(I& nIn) : n(nIn) { }
453+
explicit Wrapper(T obj) : m_object(obj) {}
454+
template<typename Stream> void Serialize(Stream &s) const { Formatter().Ser(s, m_object); }
455+
template<typename Stream> void Unserialize(Stream &s) { Formatter().Unser(s, m_object); }
456+
};
456457

457-
template<typename Stream>
458-
void Serialize(Stream &s) const {
459-
WriteVarInt<Stream,Mode,I>(s, n);
458+
/** Cause serialization/deserialization of an object to be done using a specified formatter class.
459+
*
460+
* To use this, you need a class Formatter that has public functions Ser(stream, const object&) for
461+
* serialization, and Unser(stream, object&) for deserialization. Serialization routines (inside
462+
* READWRITE, or directly with << and >> operators), can then use Using<Formatter>(object).
463+
*
464+
* This works by constructing a Wrapper<Formatter, T>-wrapped version of object, where T is
465+
* const during serialization, and non-const during deserialization, which maintains const
466+
* correctness.
467+
*/
468+
template<typename Formatter, typename T>
469+
static inline Wrapper<Formatter, T&> Using(T&& t) { return Wrapper<Formatter, T&>(t); }
470+
471+
#define VARINT(obj, ...) Using<VarIntFormatter<__VA_ARGS__>>(obj)
472+
#define COMPACTSIZE(obj) CCompactSize(REF(obj))
473+
#define LIMITED_STRING(obj,n) LimitedString< n >(REF(obj))
474+
475+
/** Serialization wrapper class for integers in VarInt format. */
476+
template<VarIntMode Mode=VarIntMode::DEFAULT>
477+
struct VarIntFormatter
478+
{
479+
template<typename Stream, typename I> void Ser(Stream &s, I v)
480+
{
481+
WriteVarInt<Stream,Mode,typename std::remove_cv<I>::type>(s, v);
460482
}
461483

462-
template<typename Stream>
463-
void Unserialize(Stream& s) {
464-
n = ReadVarInt<Stream,Mode,I>(s);
484+
template<typename Stream, typename I> void Unser(Stream& s, I& v)
485+
{
486+
v = ReadVarInt<Stream,Mode,typename std::remove_cv<I>::type>(s);
465487
}
466488
};
467489

@@ -546,9 +568,6 @@ class LimitedString
546568
}
547569
};
548570

549-
template<VarIntMode Mode=VarIntMode::DEFAULT, typename I>
550-
CVarInt<Mode, I> WrapVarInt(I& n) { return CVarInt<Mode, I>{n}; }
551-
552571
template<typename I>
553572
BigEndian<I> WrapBigEndian(I& n) { return BigEndian<I>(n); }
554573

0 commit comments

Comments
 (0)