partial merge #19032: Serialization improvements: final step

71f016c6eb42e1ac2c905e04ba4d20c2009e533f Remove old serialization primitives (Pieter Wuille)
92beff15d3ae2646c00bd78146d7592a7097ce9c Convert LimitedString to formatter (Pieter Wuille)
ef17c03e074b6c3f185afa4eff572ba687c2a171 Convert wallet to new serialization (Pieter Wuille)
65c589e45e8b8914698a0fd25cd5aafdda30869c Convert Qt to new serialization (Pieter Wuille)

Pull request description:

  This is the final step 🥳 of the serialization improvements extracted from #10785.

  It converts the LimitedString wrapper to a new-style formatter, and updates the wallet and Qt code to use the new serialization framework. Finally all remaining old primitives are removed.

ACKs for top commit:
  jonatack:
    ACK 71f016c6eb42e1ac2 reviewed diff, builds/tests/re-fuzzed.
  laanwj:
    Code review ACK 71f016c6eb42e1ac2c905e04ba4d20c2009e533f

Tree-SHA512: d952194bc73259f6510bd4ab1348a1febbbf9862af30f905991812fb0e1f23f15948cdb3fc662be54d648e8f6d95b11060055d2e7a8c2cb5bf008224870b1ea1
This commit is contained in:
Wladimir J. van der Laan 2021-05-27 17:53:41 +03:00 committed by UdjinM6
parent 6e5210adeb
commit 9029448233
No known key found for this signature in database
GPG Key ID: 83592BD1400D58D9
6 changed files with 59 additions and 123 deletions

View File

@ -22,19 +22,11 @@ public:
QDateTime date; QDateTime date;
SendCoinsRecipient recipient; SendCoinsRecipient recipient;
ADD_SERIALIZE_METHODS; SERIALIZE_METHODS(RecentRequestEntry, obj) {
unsigned int date_timet;
template <typename Stream, typename Operation> SER_WRITE(obj, date_timet = obj.date.toTime_t());
inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(obj.nVersion, obj.id, date_timet, obj.recipient);
unsigned int nDate = date.toTime_t(); SER_READ(obj, obj.date = QDateTime::fromTime_t(date_timet));
READWRITE(this->nVersion);
READWRITE(id);
READWRITE(nDate);
READWRITE(recipient);
if (ser_action.ForRead())
date = QDateTime::fromTime_t(nDate);
} }
}; };

View File

@ -70,34 +70,28 @@ public:
static const int CURRENT_VERSION = 1; static const int CURRENT_VERSION = 1;
int nVersion; int nVersion;
ADD_SERIALIZE_METHODS; SERIALIZE_METHODS(SendCoinsRecipient, obj)
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
std::string sAddress = address.toStdString();
std::string sLabel = label.toStdString();
std::string sMessage = message.toStdString();
std::string sPaymentRequest;
if (!ser_action.ForRead() && paymentRequest.IsInitialized())
paymentRequest.SerializeToString(&sPaymentRequest);
std::string sAuthenticatedMerchant = authenticatedMerchant.toStdString();
READWRITE(this->nVersion);
READWRITE(sAddress);
READWRITE(sLabel);
READWRITE(amount);
READWRITE(sMessage);
READWRITE(sPaymentRequest);
READWRITE(sAuthenticatedMerchant);
if (ser_action.ForRead())
{ {
address = QString::fromStdString(sAddress); std::string address_str, label_str, message_str, auth_merchant_str, sPaymentRequest;
label = QString::fromStdString(sLabel); PaymentRequestPlus paymentRequest;
message = QString::fromStdString(sMessage);
if (!sPaymentRequest.empty()) SER_WRITE(obj, address_str = obj.address.toStdString());
paymentRequest.parse(QByteArray::fromRawData(sPaymentRequest.data(), sPaymentRequest.size())); SER_WRITE(obj, label_str = obj.label.toStdString());
authenticatedMerchant = QString::fromStdString(sAuthenticatedMerchant); SER_WRITE(obj, message_str = obj.message.toStdString());
SER_WRITE(obj, auth_merchant_str = obj.authenticatedMerchant.toStdString());
SER_WRITE(obj, paymentRequest = obj.paymentRequest);
if (paymentRequest.IsInitialized()) {
paymentRequest.SerializeToString(&sPaymentRequest);
}
READWRITE(obj.nVersion, address_str, label_str, obj.amount, message_str, sPaymentRequest, auth_merchant_str);
SER_READ(obj, obj.address = QString::fromStdString(address_str));
SER_READ(obj, obj.label = QString::fromStdString(label_str));
SER_READ(obj, obj.message = QString::fromStdString(message_str));
SER_READ(obj, obj.authenticatedMerchant = QString::fromStdString(auth_merchant_str));
if (!sPaymentRequest.empty()) {
SER_READ(obj, obj.paymentRequest.parse(QByteArray::fromRawData(sPaymentRequest.data(), sPaymentRequest.size())));
} }
} }
}; };

View File

@ -46,26 +46,6 @@ static const unsigned int MAX_VECTOR_ALLOCATE = 5000000;
struct deserialize_type {}; struct deserialize_type {};
constexpr deserialize_type deserialize {}; constexpr deserialize_type deserialize {};
/**
* Used to bypass the rule against non-const reference to temporary
* where it makes sense with wrappers.
*/
template<typename T>
inline T& REF(const T& val)
{
return const_cast<T&>(val);
}
/**
* Used to acquire a non-const pointer "this" to generate bodies
* of const serialization operations from a template
*/
template<typename T>
inline T* NCONST_PTR(const T* val)
{
return const_cast<T*>(val);
}
//! Safely convert odd char pointer types to standard ones. //! Safely convert odd char pointer types to standard ones.
inline char* CharCast(char* c) { return c; } inline char* CharCast(char* c) { return c; }
inline char* CharCast(unsigned char* c) { return (char*)c; } inline char* CharCast(unsigned char* c) { return (char*)c; }
@ -192,22 +172,6 @@ template<typename X> const X& ReadWriteAsHelper(const X& x) { return x; }
#define SER_READ(obj, code) ::SerRead(s, ser_action, obj, [&](Stream& s, typename std::remove_const<Type>::type& obj) { code; }) #define SER_READ(obj, code) ::SerRead(s, ser_action, obj, [&](Stream& s, typename std::remove_const<Type>::type& obj) { code; })
#define SER_WRITE(obj, code) ::SerWrite(s, ser_action, obj, [&](Stream& s, const Type& obj) { code; }) #define SER_WRITE(obj, code) ::SerWrite(s, ser_action, obj, [&](Stream& s, const Type& obj) { code; })
/**
* Implement three methods for serializable objects. These are actually wrappers over
* "SerializationOp" template, which implements the body of each class' serialization
* code. Adding "ADD_SERIALIZE_METHODS" in the body of the class causes these wrappers to be
* added as members.
*/
#define ADD_SERIALIZE_METHODS \
template<typename Stream> \
void Serialize(Stream& s) const { \
NCONST_PTR(this)->SerializationOp(s, CSerActionSerialize()); \
} \
template<typename Stream> \
void Unserialize(Stream& s) { \
SerializationOp(s, CSerActionUnserialize()); \
}
/** /**
* Implement the Ser and Unser methods needed for implementing a formatter (see Using below). * Implement the Ser and Unser methods needed for implementing a formatter (see Using below).
* *
@ -507,7 +471,7 @@ static inline Wrapper<Formatter, T&> Using(T&& t) { return Wrapper<Formatter, T&
#define AUTOBITSET(obj, size) CAutoBitSet(REF(obj), (size)) #define AUTOBITSET(obj, size) CAutoBitSet(REF(obj), (size))
#define VARINT(obj, ...) Using<VarIntFormatter<__VA_ARGS__>>(obj) #define VARINT(obj, ...) Using<VarIntFormatter<__VA_ARGS__>>(obj)
#define COMPACTSIZE(obj) Using<CompactSizeFormatter>(obj) #define COMPACTSIZE(obj) Using<CompactSizeFormatter>(obj)
#define LIMITED_STRING(obj,n) LimitedString< n >(REF(obj)) #define LIMITED_STRING(obj,n) Using<LimitedStringFormatter<n>>(obj)
class CFixedBitSet class CFixedBitSet
{ {
@ -748,31 +712,23 @@ struct CompactSizeFormatter
}; };
template<size_t Limit> template<size_t Limit>
class LimitedString struct LimitedStringFormatter
{ {
protected:
std::string& string;
public:
explicit LimitedString(std::string& _string) : string(_string) {}
template<typename Stream> template<typename Stream>
void Unserialize(Stream& s) void Unser(Stream& s, std::string& v)
{ {
size_t size = ReadCompactSize(s); size_t size = ReadCompactSize(s);
if (size > Limit) { if (size > Limit) {
throw std::ios_base::failure("String length limit exceeded"); throw std::ios_base::failure("String length limit exceeded");
} }
string.resize(size); v.resize(size);
if (size != 0) if (size != 0) s.read((char*)v.data(), size);
s.read((char*)string.data(), size);
} }
template<typename Stream> template<typename Stream>
void Serialize(Stream& s) const void Ser(Stream& s, const std::string& v)
{ {
WriteCompactSize(s, string.size()); s << v;
if (!string.empty())
s.write((char*)string.data(), string.size());
} }
}; };
@ -1330,7 +1286,7 @@ void Unserialize(Stream& is, std::shared_ptr<T>& p)
/** /**
* Support for ADD_SERIALIZE_METHODS and READWRITE macro * Support for SERIALIZE_METHODS and READWRITE macro.
*/ */
struct CSerActionSerialize struct CSerActionSerialize
{ {

View File

@ -44,15 +44,9 @@ public:
//! such as the various parameters to scrypt //! such as the various parameters to scrypt
std::vector<unsigned char> vchOtherDerivationParameters; std::vector<unsigned char> vchOtherDerivationParameters;
ADD_SERIALIZE_METHODS; SERIALIZE_METHODS(CMasterKey, obj)
{
template <typename Stream, typename Operation> READWRITE(obj.vchCryptedKey, obj.vchSalt, obj.nDerivationMethod, obj.nDeriveIterations, obj.vchOtherDerivationParameters);
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(vchCryptedKey);
READWRITE(vchSalt);
READWRITE(nDerivationMethod);
READWRITE(nDeriveIterations);
READWRITE(vchOtherDerivationParameters);
} }
CMasterKey() CMasterKey()

View File

@ -116,29 +116,32 @@ public:
CKeyPool(); CKeyPool();
CKeyPool(const CPubKey& vchPubKeyIn, bool fInternalIn); CKeyPool(const CPubKey& vchPubKeyIn, bool fInternalIn);
ADD_SERIALIZE_METHODS; template<typename Stream>
void Serialize(Stream& s) const
template <typename Stream, typename Operation> {
inline void SerializationOp(Stream& s, Operation ser_action) {
int nVersion = s.GetVersion(); int nVersion = s.GetVersion();
if (!(s.GetType() & SER_GETHASH)) if (!(s.GetType() & SER_GETHASH)) {
READWRITE(nVersion); s << nVersion;
READWRITE(nTime);
READWRITE(vchPubKey);
if (ser_action.ForRead()) {
try {
READWRITE(fInternal);
} }
catch (std::ios_base::failure&) { s << nTime << vchPubKey << fInternal;
}
template<typename Stream>
void Unserialize(Stream& s)
{
int nVersion = s.GetVersion();
if (!(s.GetType() & SER_GETHASH)) {
s >> nVersion;
}
s >> nTime >> vchPubKey;
try {
s >> fInternal;
} catch (std::ios_base::failure&) {
/* flag as external address if we can't read the internal boolean /* flag as external address if we can't read the internal boolean
(this will be the case for any wallet before the HD chain split version) */ (this will be the case for any wallet before the HD chain split version) */
fInternal = false; fInternal = false;
} }
} }
else {
READWRITE(fInternal);
}
}
}; };
/** Address book data */ /** Address book data */

View File

@ -74,12 +74,9 @@ public:
nCreateTime = nCreateTime_; nCreateTime = nCreateTime_;
} }
ADD_SERIALIZE_METHODS; SERIALIZE_METHODS(CKeyMetadata, obj)
{
template <typename Stream, typename Operation> READWRITE(obj.nVersion, obj.nCreateTime);
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(this->nVersion);
READWRITE(nCreateTime);
} }
void SetNull() void SetNull()