mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-16 13:01:19 +02:00
Merge #19032: Serialization improvements: final step
71f016c6ebRemove old serialization primitives (Pieter Wuille)92beff15d3Convert LimitedString to formatter (Pieter Wuille)ef17c03e07Convert wallet to new serialization (Pieter Wuille)65c589e45eConvert 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: ACK71f016c6ebreviewed diff, builds/tests/re-fuzzed. laanwj: Code review ACK71f016c6ebTree-SHA512: d952194bc73259f6510bd4ab1348a1febbbf9862af30f905991812fb0e1f23f15948cdb3fc662be54d648e8f6d95b11060055d2e7a8c2cb5bf008224870b1ea1
This commit is contained in:
commit
dcacea096e
8 changed files with 88 additions and 165 deletions
|
|
@ -24,19 +24,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);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,30 +44,21 @@ public:
|
||||||
static const int CURRENT_VERSION = 1;
|
static const int CURRENT_VERSION = 1;
|
||||||
int nVersion;
|
int nVersion;
|
||||||
|
|
||||||
ADD_SERIALIZE_METHODS;
|
SERIALIZE_METHODS(SendCoinsRecipient, obj)
|
||||||
|
{
|
||||||
|
std::string address_str, label_str, message_str, auth_merchant_str;
|
||||||
|
|
||||||
template <typename Stream, typename Operation>
|
SER_WRITE(obj, address_str = obj.address.toStdString());
|
||||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
SER_WRITE(obj, label_str = obj.label.toStdString());
|
||||||
std::string sAddress = address.toStdString();
|
SER_WRITE(obj, message_str = obj.message.toStdString());
|
||||||
std::string sLabel = label.toStdString();
|
SER_WRITE(obj, auth_merchant_str = obj.authenticatedMerchant.toStdString());
|
||||||
std::string sMessage = message.toStdString();
|
|
||||||
std::string sAuthenticatedMerchant = authenticatedMerchant.toStdString();
|
|
||||||
|
|
||||||
READWRITE(this->nVersion);
|
READWRITE(obj.nVersion, address_str, label_str, obj.amount, message_str, obj.sPaymentRequest, auth_merchant_str);
|
||||||
READWRITE(sAddress);
|
|
||||||
READWRITE(sLabel);
|
|
||||||
READWRITE(amount);
|
|
||||||
READWRITE(sMessage);
|
|
||||||
READWRITE(sPaymentRequest);
|
|
||||||
READWRITE(sAuthenticatedMerchant);
|
|
||||||
|
|
||||||
if (ser_action.ForRead())
|
SER_READ(obj, obj.address = QString::fromStdString(address_str));
|
||||||
{
|
SER_READ(obj, obj.label = QString::fromStdString(label_str));
|
||||||
address = QString::fromStdString(sAddress);
|
SER_READ(obj, obj.message = QString::fromStdString(message_str));
|
||||||
label = QString::fromStdString(sLabel);
|
SER_READ(obj, obj.authenticatedMerchant = QString::fromStdString(auth_merchant_str));
|
||||||
message = QString::fromStdString(sMessage);
|
|
||||||
authenticatedMerchant = QString::fromStdString(sAuthenticatedMerchant);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,26 +43,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; }
|
||||||
|
|
@ -193,22 +173,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).
|
||||||
*
|
*
|
||||||
|
|
@ -503,7 +467,7 @@ static inline Wrapper<Formatter, T&> Using(T&& t) { return Wrapper<Formatter, T&
|
||||||
#define VARINT_MODE(obj, mode) Using<VarIntFormatter<mode>>(obj)
|
#define VARINT_MODE(obj, mode) Using<VarIntFormatter<mode>>(obj)
|
||||||
#define VARINT(obj) Using<VarIntFormatter<VarIntMode::DEFAULT>>(obj)
|
#define VARINT(obj) Using<VarIntFormatter<VarIntMode::DEFAULT>>(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)
|
||||||
|
|
||||||
/** Serialization wrapper class for integers in VarInt format. */
|
/** Serialization wrapper class for integers in VarInt format. */
|
||||||
template<VarIntMode Mode>
|
template<VarIntMode Mode>
|
||||||
|
|
@ -588,31 +552,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());
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1012,7 +968,7 @@ void Unserialize(Stream& is, std::shared_ptr<const T>& p)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Support for ADD_SERIALIZE_METHODS and READWRITE macro
|
* Support for SERIALIZE_METHODS and READWRITE macro.
|
||||||
*/
|
*/
|
||||||
struct CSerActionSerialize
|
struct CSerActionSerialize
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
|
||||||
{
|
{
|
||||||
CDataStream data_stream{SER_NETWORK, INIT_PROTO_VERSION};
|
CDataStream data_stream{SER_NETWORK, INIT_PROTO_VERSION};
|
||||||
std::string s;
|
std::string s;
|
||||||
LimitedString<10> limited_string = LIMITED_STRING(s, 10);
|
auto limited_string = LIMITED_STRING(s, 10);
|
||||||
data_stream << random_string_1;
|
data_stream << random_string_1;
|
||||||
try {
|
try {
|
||||||
data_stream >> limited_string;
|
data_stream >> limited_string;
|
||||||
|
|
@ -108,7 +108,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
CDataStream data_stream{SER_NETWORK, INIT_PROTO_VERSION};
|
CDataStream data_stream{SER_NETWORK, INIT_PROTO_VERSION};
|
||||||
const LimitedString<10> limited_string = LIMITED_STRING(random_string_1, 10);
|
const auto limited_string = LIMITED_STRING(random_string_1, 10);
|
||||||
data_stream << limited_string;
|
data_stream << limited_string;
|
||||||
std::string deserialized_string;
|
std::string deserialized_string;
|
||||||
data_stream >> deserialized_string;
|
data_stream >> deserialized_string;
|
||||||
|
|
|
||||||
|
|
@ -43,15 +43,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()
|
||||||
|
|
|
||||||
|
|
@ -112,36 +112,37 @@ public:
|
||||||
CKeyPool();
|
CKeyPool();
|
||||||
CKeyPool(const CPubKey& vchPubKeyIn, bool internalIn);
|
CKeyPool(const CPubKey& vchPubKeyIn, bool internalIn);
|
||||||
|
|
||||||
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&) {
|
|
||||||
/* 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) */
|
|
||||||
fInternal = false;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
READWRITE(m_pre_split);
|
|
||||||
}
|
|
||||||
catch (std::ios_base::failure&) {
|
|
||||||
/* flag as postsplit address if we can't read the m_pre_split boolean
|
|
||||||
(this will be the case for any wallet that upgrades to HD chain split)*/
|
|
||||||
m_pre_split = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
s << nTime << vchPubKey << fInternal << m_pre_split;
|
||||||
READWRITE(fInternal);
|
}
|
||||||
READWRITE(m_pre_split);
|
|
||||||
|
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
|
||||||
|
(this will be the case for any wallet before the HD chain split version) */
|
||||||
|
fInternal = false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
s >> m_pre_split;
|
||||||
|
} catch (std::ios_base::failure&) {
|
||||||
|
/* flag as postsplit address if we can't read the m_pre_split boolean
|
||||||
|
(this will be the case for any wallet that upgrades to HD chain split) */
|
||||||
|
m_pre_split = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -98,15 +98,13 @@ public:
|
||||||
int nVersion;
|
int nVersion;
|
||||||
|
|
||||||
CHDChain() { SetNull(); }
|
CHDChain() { SetNull(); }
|
||||||
ADD_SERIALIZE_METHODS;
|
|
||||||
template <typename Stream, typename Operation>
|
SERIALIZE_METHODS(CHDChain, obj)
|
||||||
inline void SerializationOp(Stream& s, Operation ser_action)
|
|
||||||
{
|
{
|
||||||
READWRITE(this->nVersion);
|
READWRITE(obj.nVersion, obj.nExternalChainCounter, obj.seed_id);
|
||||||
READWRITE(nExternalChainCounter);
|
if (obj.nVersion >= VERSION_HD_CHAIN_SPLIT) {
|
||||||
READWRITE(seed_id);
|
READWRITE(obj.nInternalChainCounter);
|
||||||
if (this->nVersion >= VERSION_HD_CHAIN_SPLIT)
|
}
|
||||||
READWRITE(nInternalChainCounter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetNull()
|
void SetNull()
|
||||||
|
|
@ -147,21 +145,16 @@ 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) {
|
if (obj.nVersion >= VERSION_WITH_HDDATA) {
|
||||||
READWRITE(this->nVersion);
|
READWRITE(obj.hdKeypath, obj.hd_seed_id);
|
||||||
READWRITE(nCreateTime);
|
|
||||||
if (this->nVersion >= VERSION_WITH_HDDATA)
|
|
||||||
{
|
|
||||||
READWRITE(hdKeypath);
|
|
||||||
READWRITE(hd_seed_id);
|
|
||||||
}
|
}
|
||||||
if (this->nVersion >= VERSION_WITH_KEY_ORIGIN)
|
if (obj.nVersion >= VERSION_WITH_KEY_ORIGIN)
|
||||||
{
|
{
|
||||||
READWRITE(key_origin);
|
READWRITE(obj.key_origin);
|
||||||
READWRITE(has_key_origin);
|
READWRITE(obj.has_key_origin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -98,26 +98,22 @@ public:
|
||||||
int32_t next_index = 0; // Position of the next item to generate
|
int32_t next_index = 0; // Position of the next item to generate
|
||||||
DescriptorCache cache;
|
DescriptorCache cache;
|
||||||
|
|
||||||
ADD_SERIALIZE_METHODS;
|
void DeserializeDescriptor(const std::string& str)
|
||||||
|
{
|
||||||
template <typename Stream, typename Operation>
|
std::string error;
|
||||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
FlatSigningProvider keys;
|
||||||
if (ser_action.ForRead()) {
|
descriptor = Parse(str, keys, error, true);
|
||||||
std::string desc;
|
if (!descriptor) {
|
||||||
std::string error;
|
throw std::ios_base::failure("Invalid descriptor: " + error);
|
||||||
READWRITE(desc);
|
|
||||||
FlatSigningProvider keys;
|
|
||||||
descriptor = Parse(desc, keys, error, true);
|
|
||||||
if (!descriptor) {
|
|
||||||
throw std::ios_base::failure("Invalid descriptor: " + error);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
READWRITE(descriptor->ToString());
|
|
||||||
}
|
}
|
||||||
READWRITE(creation_time);
|
}
|
||||||
READWRITE(next_index);
|
|
||||||
READWRITE(range_start);
|
SERIALIZE_METHODS(WalletDescriptor, obj)
|
||||||
READWRITE(range_end);
|
{
|
||||||
|
std::string descriptor_str;
|
||||||
|
SER_WRITE(obj, descriptor_str = obj.descriptor->ToString());
|
||||||
|
READWRITE(descriptor_str, obj.creation_time, obj.next_index, obj.range_start, obj.range_end);
|
||||||
|
SER_READ(obj, obj.DeserializeDescriptor(descriptor_str));
|
||||||
}
|
}
|
||||||
|
|
||||||
WalletDescriptor() {}
|
WalletDescriptor() {}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue