diff --git a/src/llmq/quorums_commitment.h b/src/llmq/quorums_commitment.h index 835dcb07f9..c4fb8abb0b 100644 --- a/src/llmq/quorums_commitment.h +++ b/src/llmq/quorums_commitment.h @@ -54,20 +54,19 @@ public: bool VerifySizes(const Consensus::LLMQParams& params) const; public: - ADD_SERIALIZE_METHODS - - template - inline void SerializationOp(Stream& s, Operation ser_action) + SERIALIZE_METHODS(CFinalCommitment, obj) { - READWRITE(nVersion); - READWRITE(llmqType); - READWRITE(quorumHash); - READWRITE(DYNBITSET(signers)); - READWRITE(DYNBITSET(validMembers)); - READWRITE(quorumPublicKey); - READWRITE(quorumVvecHash); - READWRITE(quorumSig); - READWRITE(membersSig); + READWRITE( + obj.nVersion, + obj.llmqType, + obj.quorumHash, + DYNBITSET(obj.signers), + DYNBITSET(obj.validMembers), + obj.quorumPublicKey, + obj.quorumVvecHash, + obj.quorumSig, + obj.membersSig + ); } public: diff --git a/src/llmq/quorums_dkgsession.h b/src/llmq/quorums_dkgsession.h index 7ccde6e5a8..a08b50a854 100644 --- a/src/llmq/quorums_dkgsession.h +++ b/src/llmq/quorums_dkgsession.h @@ -95,17 +95,16 @@ public: CDKGComplaint() = default; explicit CDKGComplaint(const Consensus::LLMQParams& params); - ADD_SERIALIZE_METHODS - - template - inline void SerializationOp(Stream& s, Operation ser_action) + SERIALIZE_METHODS(CDKGComplaint, obj) { - READWRITE(llmqType); - READWRITE(quorumHash); - READWRITE(proTxHash); - READWRITE(DYNBITSET(badMembers)); - READWRITE(DYNBITSET(complainForMembers)); - READWRITE(sig); + READWRITE( + obj.llmqType, + obj.quorumHash, + obj.proTxHash, + DYNBITSET(obj.badMembers), + DYNBITSET(obj.complainForMembers), + obj.sig + ); } uint256 GetSignHash() const @@ -174,19 +173,18 @@ public: } public: - ADD_SERIALIZE_METHODS - - template - inline void SerializationOp(Stream& s, Operation ser_action) + SERIALIZE_METHODS(CDKGPrematureCommitment, obj) { - READWRITE(llmqType); - READWRITE(quorumHash); - READWRITE(proTxHash); - READWRITE(DYNBITSET(validMembers)); - READWRITE(quorumPublicKey); - READWRITE(quorumVvecHash); - READWRITE(quorumSig); - READWRITE(sig); + READWRITE( + obj.llmqType, + obj.quorumHash, + obj.proTxHash, + DYNBITSET(obj.validMembers), + obj.quorumPublicKey, + obj.quorumVvecHash, + obj.quorumSig, + obj.sig + ); } uint256 GetSignHash() const diff --git a/src/llmq/quorums_signing_shares.h b/src/llmq/quorums_signing_shares.h index bb4b5fec1f..0146458ce8 100644 --- a/src/llmq/quorums_signing_shares.h +++ b/src/llmq/quorums_signing_shares.h @@ -98,16 +98,13 @@ public: std::vector inv; public: - ADD_SERIALIZE_METHODS - - template - inline void SerializationOp(Stream& s, Operation ser_action) + SERIALIZE_METHODS(CSigSharesInv, obj) { - uint64_t invSize = inv.size(); - - READWRITE(VARINT(sessionId)); - READWRITE(COMPACTSIZE(invSize)); - READWRITE(AUTOBITSET(inv, (size_t)invSize)); + uint64_t invSize = obj.inv.size(); + READWRITE(VARINT(obj.sessionId), COMPACTSIZE(invSize)); + autobitset_t bitset = std::make_pair(obj.inv, (size_t)invSize); + READWRITE(AUTOBITSET(bitset)); + SER_READ(obj, obj.inv = bitset.first); } void Init(size_t size); diff --git a/src/serialize.h b/src/serialize.h index 3dad1ff64f..399f660075 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -439,6 +439,143 @@ I ReadVarInt(Stream& is) } } +/** TODO: describe FixedBitSet */ +inline unsigned int GetSizeOfFixedBitSet(size_t size) +{ + return (size + 7) / 8; +} + +template +void WriteFixedBitSet(Stream& s, const std::vector& vec, size_t size) +{ + std::vector vBytes((size + 7) / 8); + size_t ms = std::min(size, vec.size()); + for (size_t p = 0; p < ms; p++) + vBytes[p / 8] |= vec[p] << (p % 8); + s.write((char*)vBytes.data(), vBytes.size()); +} + +template +void ReadFixedBitSet(Stream& s, std::vector& vec, size_t size) +{ + vec.resize(size); + + std::vector vBytes((size + 7) / 8); + s.read((char*)vBytes.data(), vBytes.size()); + for (size_t p = 0; p < size; p++) + vec[p] = (vBytes[p / 8] & (1 << (p % 8))) != 0; + if (vBytes.size() * 8 != size) { + size_t rem = vBytes.size() * 8 - size; + uint8_t m = ~(uint8_t)(0xff >> rem); + if (vBytes[vBytes.size() - 1] & m) { + throw std::ios_base::failure("Out-of-range bits set"); + } + } +} + +/** + * Stores a fixed size bitset as a series of VarInts. Each VarInt is an offset from the last entry and the sum of the + * last entry and the offset gives an index into the bitset for a set bit. The series of VarInts ends with a 0. + */ +template +void WriteFixedVarIntsBitSet(Stream& s, const std::vector& vec, size_t size) +{ + int32_t last = -1; + for (int32_t i = 0; i < (int32_t)vec.size(); i++) { + if (vec[i]) { + WriteVarInt(s, (uint32_t)(i - last)); + last = i; + } + } + WriteVarInt(s, 0); // stopper +} + +template +void ReadFixedVarIntsBitSet(Stream& s, std::vector& vec, size_t size) +{ + vec.assign(size, false); + + int32_t last = -1; + while(true) { + uint32_t offset = ReadVarInt(s); + if (offset == 0) { + break; + } + int32_t idx = last + offset; + if (idx >= size) { + throw std::ios_base::failure("out of bounds index"); + } + if (last != -1 && idx <= last) { + throw std::ios_base::failure("offset overflow"); + } + vec[idx] = true; + last = idx; + } +} + +/** + * Serializes either as a CFixedBitSet or CFixedVarIntsBitSet, depending on which would give a smaller size + */ +typedef std::pair, size_t> autobitset_t; + +struct CFixedBitSet +{ + const std::vector& vec; + size_t size; + CFixedBitSet(const std::vector& vecIn, size_t sizeIn) : vec(vecIn), size(sizeIn) {} + template + void Serialize(Stream& s) const { WriteFixedBitSet(s, vec, size); } +}; + +struct CFixedVarIntsBitSet +{ + const std::vector& vec; + size_t size; + CFixedVarIntsBitSet(const std::vector& vecIn, size_t sizeIn) : vec(vecIn), size(sizeIn) {} + template + void Serialize(Stream& s) const { WriteFixedVarIntsBitSet(s, vec, vec.size()); } +}; + +template +void WriteAutoBitSet(Stream& s, const autobitset_t& item) +{ + auto& vec = item.first; + auto& size = item.second; + + assert(vec.size() == size); + + size_t size1 = ::GetSerializeSize(s, CFixedBitSet(vec, size)); + size_t size2 = ::GetSerializeSize(s, CFixedVarIntsBitSet(vec, size)); + + assert(size1 == GetSizeOfFixedBitSet(size)); + + if (size1 < size2) { + ser_writedata8(s, 0); + WriteFixedBitSet(s, vec, vec.size()); + } else { + ser_writedata8(s, 1); + WriteFixedVarIntsBitSet(s, vec, vec.size()); + } +} + +template +void ReadAutoBitSet(Stream& s, autobitset_t& item) +{ + uint8_t isVarInts = ser_readdata8(s); + if (isVarInts != 0 && isVarInts != 1) { + throw std::ios_base::failure("invalid value for isVarInts byte"); + } + + auto& vec = item.first; + auto& size = item.second; + + if (!isVarInts) { + ReadFixedBitSet(s, vec, size); + } else { + ReadFixedVarIntsBitSet(s, vec, size); + } +} + /** Simple wrapper class to serialize objects using a formatter; used by Using(). */ template class Wrapper @@ -465,167 +602,44 @@ public: template static inline Wrapper Using(T&& t) { return Wrapper(t); } -#define FIXEDBITSET(obj, size) CFixedBitSet(REF(obj), (size)) -#define DYNBITSET(obj) CDynamicBitSet(REF(obj)) -#define FIXEDVARINTSBITSET(obj, size) CFixedVarIntsBitSet(REF(obj), (size)) -#define AUTOBITSET(obj, size) CAutoBitSet(REF(obj), (size)) +#define DYNBITSET(obj) Using(obj) +#define AUTOBITSET(obj) Using(obj) #define VARINT(obj, ...) Using>(obj) #define COMPACTSIZE(obj) Using(obj) #define LIMITED_STRING(obj,n) Using>(obj) -class CFixedBitSet +/** TODO: describe DynamicBitSet */ +struct DynamicBitSetFormatter { -protected: - std::vector& vec; - size_t size; - -public: - CFixedBitSet(std::vector& vecIn, size_t sizeIn) : vec(vecIn), size(sizeIn) {} - template - void Serialize(Stream& s) const - { - std::vector vBytes((size + 7) / 8); - size_t ms = std::min(size, vec.size()); - for (size_t p = 0; p < ms; p++) - vBytes[p / 8] |= vec[p] << (p % 8); - s.write((char*)vBytes.data(), vBytes.size()); - } - - template - void Unserialize(Stream& s) - { - vec.resize(size); - - std::vector vBytes((size + 7) / 8); - s.read((char*)vBytes.data(), vBytes.size()); - for (size_t p = 0; p < size; p++) - vec[p] = (vBytes[p / 8] & (1 << (p % 8))) != 0; - if (vBytes.size() * 8 != size) { - size_t rem = vBytes.size() * 8 - size; - uint8_t m = ~(uint8_t)(0xff >> rem); - if (vBytes[vBytes.size() - 1] & m) { - throw std::ios_base::failure("Out-of-range bits set"); - } - } - } -}; - -class CDynamicBitSet -{ -protected: - std::vector& vec; - -public: - explicit CDynamicBitSet(std::vector& vecIn) : vec(vecIn) {} - - template - void Serialize(Stream& s) const + void Ser(Stream& s, const std::vector& vec) const { WriteCompactSize(s, vec.size()); - CFixedBitSet(REF(vec), vec.size()).Serialize(s); + WriteFixedBitSet(s, vec, vec.size()); } template - void Unserialize(Stream& s) + void Unser(Stream& s, std::vector& vec) { - vec.resize(ReadCompactSize(s)); - CFixedBitSet(vec, vec.size()).Unserialize(s); - } -}; - -/** - * Stores a fixed size bitset as a series of VarInts. Each VarInt is an offset from the last entry and the sum of the - * last entry and the offset gives an index into the bitset for a set bit. The series of VarInts ends with a 0. - */ -class CFixedVarIntsBitSet -{ -protected: - std::vector& vec; - size_t size; - -public: - CFixedVarIntsBitSet(std::vector& vecIn, size_t sizeIn) : vec(vecIn), size(sizeIn) {} - - template - void Serialize(Stream& s) const - { - int32_t last = -1; - for (int32_t i = 0; i < (int32_t)vec.size(); i++) { - if (vec[i]) { - WriteVarInt(s, (uint32_t)(i - last)); - last = i; - } - } - WriteVarInt(s, 0); // stopper - } - - template - void Unserialize(Stream& s) - { - vec.assign(size, false); - - int32_t last = -1; - while(true) { - uint32_t offset = ReadVarInt(s); - if (offset == 0) { - break; - } - int32_t idx = last + offset; - if (idx >= size) { - throw std::ios_base::failure("out of bounds index"); - } - if (last != -1 && idx <= last) { - throw std::ios_base::failure("offset overflow"); - } - vec[idx] = true; - last = idx; - } + ReadFixedBitSet(s, vec, ReadCompactSize(s)); } }; /** * Serializes either as a CFixedBitSet or CFixedVarIntsBitSet, depending on which would give a smaller size */ -class CAutoBitSet +struct AutoBitSetFormatter { -protected: - std::vector& vec; - size_t size; - -public: - explicit CAutoBitSet(std::vector& vecIn, size_t sizeIn) : vec(vecIn), size(sizeIn) {} - template - void Serialize(Stream& s) const + void Ser(Stream& s, const autobitset_t& item) const { - assert(vec.size() == size); - - size_t size1 = ::GetSerializeSize(s, CFixedBitSet(vec, size)); - size_t size2 = ::GetSerializeSize(s, CFixedVarIntsBitSet(vec, size)); - - if (size1 < size2) { - ser_writedata8(s, 0); - s << FIXEDBITSET(vec, vec.size()); - } else { - ser_writedata8(s, 1); - s << FIXEDVARINTSBITSET(vec, vec.size()); - } + WriteAutoBitSet(s, item); } template - void Unserialize(Stream& s) + void Unser(Stream& s, autobitset_t& item) { - uint8_t isVarInts = ser_readdata8(s); - if (isVarInts != 0 && isVarInts != 1) { - throw std::ios_base::failure("invalid value for isVarInts byte"); - } - - if (!isVarInts) { - s >> FIXEDBITSET(vec, size); - } else { - s >> FIXEDVARINTSBITSET(vec, size); - } + ReadAutoBitSet(s, item); } };