Skip to content

Commit f3a2b52

Browse files
committed
serialization: Support for multiple parameters
This commit makes a minimal change to the ParamsStream class to let it retrieve multiple parameters. Followup commits after this commit clean up code using ParamsStream and make it easier to set multiple parameters. Currently it is only possible to attach one serialization parameter to a stream at a time. For example, it is not possible to set a parameter controlling the transaction format and a parameter controlling the address format at the same time because one parameter will override the other. This limitation is inconvenient for multiprocess code since it is not possible to create just one type of stream and serialize any object to it. Instead it is necessary to create different streams for different object types, which requires extra boilerplate and makes using the new parameter fields a lot more awkward than the older version and type fields. Fix this problem by allowing an unlimited number of serialization stream parameters to be set, and allowing them to be requested by type. Later parameters will still override earlier parameters, but only if they have the same type. This change requires replacing the stream.GetParams() method with a stream.GetParams<T>() method in order for serialization code to retrieve the desired parameters. This change is more verbose, but probably a good thing for readability because previously it could be difficult to know what type the GetParams() method would return, and now it is more obvious.
1 parent 4ae5171 commit f3a2b52

File tree

5 files changed

+28
-31
lines changed

5 files changed

+28
-31
lines changed

src/netaddress.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ class CNetAddr
241241
template <typename Stream>
242242
void Serialize(Stream& s) const
243243
{
244-
if (s.GetParams().enc == Encoding::V2) {
244+
if (s.template GetParams<SerParams>().enc == Encoding::V2) {
245245
SerializeV2Stream(s);
246246
} else {
247247
SerializeV1Stream(s);
@@ -254,7 +254,7 @@ class CNetAddr
254254
template <typename Stream>
255255
void Unserialize(Stream& s)
256256
{
257-
if (s.GetParams().enc == Encoding::V2) {
257+
if (s.template GetParams<SerParams>().enc == Encoding::V2) {
258258
UnserializeV2Stream(s);
259259
} else {
260260
UnserializeV1Stream(s);

src/primitives/transaction.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ class CTransaction
326326

327327
template <typename Stream>
328328
inline void Serialize(Stream& s) const {
329-
SerializeTransaction(*this, s, s.GetParams());
329+
SerializeTransaction(*this, s, s.template GetParams<TransactionSerParams>());
330330
}
331331

332332
/** This deserializing constructor is provided instead of an Unserialize method.
@@ -386,12 +386,12 @@ struct CMutableTransaction
386386

387387
template <typename Stream>
388388
inline void Serialize(Stream& s) const {
389-
SerializeTransaction(*this, s, s.GetParams());
389+
SerializeTransaction(*this, s, s.template GetParams<TransactionSerParams>());
390390
}
391391

392392
template <typename Stream>
393393
inline void Unserialize(Stream& s) {
394-
UnserializeTransaction(*this, s, s.GetParams());
394+
UnserializeTransaction(*this, s, s.template GetParams<TransactionSerParams>());
395395
}
396396

397397
template <typename Stream>

src/protocol.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,9 +406,10 @@ class CAddress : public CService
406406
static constexpr SerParams V1_DISK{{CNetAddr::Encoding::V1}, Format::Disk};
407407
static constexpr SerParams V2_DISK{{CNetAddr::Encoding::V2}, Format::Disk};
408408

409-
SERIALIZE_METHODS_PARAMS(CAddress, obj, SerParams, params)
409+
SERIALIZE_METHODS(CAddress, obj)
410410
{
411411
bool use_v2;
412+
auto& params = SER_PARAMS(SerParams);
412413
if (params.fmt == Format::Disk) {
413414
// In the disk serialization format, the encoding (v1 or v2) is determined by a flag version
414415
// that's part of the serialization itself. ADDRV2_FORMAT in the stream version only determines

src/serialize.h

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -181,17 +181,17 @@ const Out& AsBase(const In& x)
181181
static void SerializationOps(Type& obj, Stream& s, Operation ser_action)
182182

183183
/**
184-
* Variant of FORMATTER_METHODS that supports a declared parameter type.
185-
*
186-
* If a formatter has a declared parameter type, it must be invoked directly or
184+
* Formatter methods can retrieve parameters attached to a stream using the
185+
* SER_PARAMS(type) macro as long as the stream is created directly or
187186
* indirectly with a parameter of that type. This permits making serialization
188187
* depend on run-time context in a type-safe way.
189188
*
190189
* Example use:
191190
* struct BarParameter { bool fancy; ... };
192191
* struct Bar { ... };
193192
* struct FooFormatter {
194-
* FORMATTER_METHODS(Bar, obj, BarParameter, param) {
193+
* FORMATTER_METHODS(Bar, obj) {
194+
* auto& param = SER_PARAMS(BarParameter);
195195
* if (param.fancy) {
196196
* READWRITE(VARINT(obj.value));
197197
* } else {
@@ -213,13 +213,7 @@ const Out& AsBase(const In& x)
213213
* Compilation will fail in any context where serialization is invoked but
214214
* no parameter of a type convertible to BarParameter is provided.
215215
*/
216-
#define FORMATTER_METHODS_PARAMS(cls, obj, paramcls, paramobj) \
217-
template <typename Stream> \
218-
static void Ser(Stream& s, const cls& obj) { SerializationOps(obj, s, ActionSerialize{}, s.GetParams()); } \
219-
template <typename Stream> \
220-
static void Unser(Stream& s, cls& obj) { SerializationOps(obj, s, ActionUnserialize{}, s.GetParams()); } \
221-
template <typename Stream, typename Type, typename Operation> \
222-
static void SerializationOps(Type& obj, Stream& s, Operation ser_action, const paramcls& paramobj)
216+
#define SER_PARAMS(type) (s.template GetParams<type>())
223217

224218
#define BASE_SERIALIZE_METHODS(cls) \
225219
template <typename Stream> \
@@ -246,15 +240,6 @@ const Out& AsBase(const In& x)
246240
BASE_SERIALIZE_METHODS(cls) \
247241
FORMATTER_METHODS(cls, obj)
248242

249-
/**
250-
* Variant of SERIALIZE_METHODS that supports a declared parameter type.
251-
*
252-
* See FORMATTER_METHODS_PARAMS for more information on parameters.
253-
*/
254-
#define SERIALIZE_METHODS_PARAMS(cls, obj, paramcls, paramobj) \
255-
BASE_SERIALIZE_METHODS(cls) \
256-
FORMATTER_METHODS_PARAMS(cls, obj, paramcls, paramobj)
257-
258243
// Templates for serializing to anything that looks like a stream,
259244
// i.e. anything that supports .read(Span<std::byte>) and .write(Span<const std::byte>)
260245
//
@@ -1134,9 +1119,19 @@ class ParamsStream
11341119
void ignore(size_t num) { m_substream.ignore(num); }
11351120
bool eof() const { return m_substream.eof(); }
11361121
size_t size() const { return m_substream.size(); }
1137-
const Params& GetParams() const { return m_params; }
11381122
int GetVersion() = delete; // Deprecated with Params usage
11391123
int GetType() = delete; // Deprecated with Params usage
1124+
1125+
//! Get reference to stream parameters.
1126+
template <typename P>
1127+
const auto& GetParams() const
1128+
{
1129+
if constexpr (std::is_convertible_v<Params, P>) {
1130+
return m_params;
1131+
} else {
1132+
return m_substream.template GetParams<P>();
1133+
}
1134+
}
11401135
};
11411136

11421137
/** Wrapper that serializes objects with the specified parameters. */
@@ -1176,7 +1171,7 @@ class ParamsWrapper
11761171
/** \
11771172
* Return a wrapper around t that (de)serializes it with specified parameter params. \
11781173
* \
1179-
* See FORMATTER_METHODS_PARAMS for more information on serialization parameters. \
1174+
* See SER_PARAMS for more information on serialization parameters. \
11801175
*/ \
11811176
template <typename T> \
11821177
auto operator()(T&& t) const \

src/test/serialize_tests.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ class Base
289289
template <typename Stream>
290290
void Serialize(Stream& s) const
291291
{
292-
if (s.GetParams().m_base_format == BaseFormat::RAW) {
292+
if (s.template GetParams<BaseFormat>().m_base_format == BaseFormat::RAW) {
293293
s << m_base_data;
294294
} else {
295295
s << Span{HexStr(Span{&m_base_data, 1})};
@@ -299,7 +299,7 @@ class Base
299299
template <typename Stream>
300300
void Unserialize(Stream& s)
301301
{
302-
if (s.GetParams().m_base_format == BaseFormat::RAW) {
302+
if (s.template GetParams<BaseFormat>().m_base_format == BaseFormat::RAW) {
303303
s >> m_base_data;
304304
} else {
305305
std::string hex{"aa"};
@@ -327,8 +327,9 @@ class Derived : public Base
327327
public:
328328
std::string m_derived_data;
329329

330-
SERIALIZE_METHODS_PARAMS(Derived, obj, DerivedAndBaseFormat, fmt)
330+
SERIALIZE_METHODS(Derived, obj)
331331
{
332+
auto& fmt = SER_PARAMS(DerivedAndBaseFormat);
332333
READWRITE(fmt.m_base_format(AsBase<Base>(obj)));
333334

334335
if (ser_action.ForRead()) {

0 commit comments

Comments
 (0)