Convert bitset serializationis to use formatters

This commit is contained in:
UdjinM6 2021-05-27 18:04:17 +03:00
parent 64d4a48a09
commit d60a6d1729
No known key found for this signature in database
GPG Key ID: 83592BD1400D58D9
4 changed files with 188 additions and 180 deletions

View File

@ -54,20 +54,19 @@ public:
bool VerifySizes(const Consensus::LLMQParams& params) const; bool VerifySizes(const Consensus::LLMQParams& params) const;
public: public:
ADD_SERIALIZE_METHODS SERIALIZE_METHODS(CFinalCommitment, obj)
template<typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action)
{ {
READWRITE(nVersion); READWRITE(
READWRITE(llmqType); obj.nVersion,
READWRITE(quorumHash); obj.llmqType,
READWRITE(DYNBITSET(signers)); obj.quorumHash,
READWRITE(DYNBITSET(validMembers)); DYNBITSET(obj.signers),
READWRITE(quorumPublicKey); DYNBITSET(obj.validMembers),
READWRITE(quorumVvecHash); obj.quorumPublicKey,
READWRITE(quorumSig); obj.quorumVvecHash,
READWRITE(membersSig); obj.quorumSig,
obj.membersSig
);
} }
public: public:

View File

@ -95,17 +95,16 @@ public:
CDKGComplaint() = default; CDKGComplaint() = default;
explicit CDKGComplaint(const Consensus::LLMQParams& params); explicit CDKGComplaint(const Consensus::LLMQParams& params);
ADD_SERIALIZE_METHODS SERIALIZE_METHODS(CDKGComplaint, obj)
template<typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action)
{ {
READWRITE(llmqType); READWRITE(
READWRITE(quorumHash); obj.llmqType,
READWRITE(proTxHash); obj.quorumHash,
READWRITE(DYNBITSET(badMembers)); obj.proTxHash,
READWRITE(DYNBITSET(complainForMembers)); DYNBITSET(obj.badMembers),
READWRITE(sig); DYNBITSET(obj.complainForMembers),
obj.sig
);
} }
uint256 GetSignHash() const uint256 GetSignHash() const
@ -174,19 +173,18 @@ public:
} }
public: public:
ADD_SERIALIZE_METHODS SERIALIZE_METHODS(CDKGPrematureCommitment, obj)
template<typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action)
{ {
READWRITE(llmqType); READWRITE(
READWRITE(quorumHash); obj.llmqType,
READWRITE(proTxHash); obj.quorumHash,
READWRITE(DYNBITSET(validMembers)); obj.proTxHash,
READWRITE(quorumPublicKey); DYNBITSET(obj.validMembers),
READWRITE(quorumVvecHash); obj.quorumPublicKey,
READWRITE(quorumSig); obj.quorumVvecHash,
READWRITE(sig); obj.quorumSig,
obj.sig
);
} }
uint256 GetSignHash() const uint256 GetSignHash() const

View File

@ -98,16 +98,13 @@ public:
std::vector<bool> inv; std::vector<bool> inv;
public: public:
ADD_SERIALIZE_METHODS SERIALIZE_METHODS(CSigSharesInv, obj)
template<typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action)
{ {
uint64_t invSize = inv.size(); uint64_t invSize = obj.inv.size();
READWRITE(VARINT(obj.sessionId), COMPACTSIZE(invSize));
READWRITE(VARINT(sessionId)); autobitset_t bitset = std::make_pair(obj.inv, (size_t)invSize);
READWRITE(COMPACTSIZE(invSize)); READWRITE(AUTOBITSET(bitset));
READWRITE(AUTOBITSET(inv, (size_t)invSize)); SER_READ(obj, obj.inv = bitset.first);
} }
void Init(size_t size); void Init(size_t size);

View File

@ -439,6 +439,143 @@ I ReadVarInt(Stream& is)
} }
} }
/** TODO: describe FixedBitSet */
inline unsigned int GetSizeOfFixedBitSet(size_t size)
{
return (size + 7) / 8;
}
template<typename Stream>
void WriteFixedBitSet(Stream& s, const std::vector<bool>& vec, size_t size)
{
std::vector<unsigned char> 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<typename Stream>
void ReadFixedBitSet(Stream& s, std::vector<bool>& vec, size_t size)
{
vec.resize(size);
std::vector<unsigned char> 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<typename Stream>
void WriteFixedVarIntsBitSet(Stream& s, const std::vector<bool>& vec, size_t size)
{
int32_t last = -1;
for (int32_t i = 0; i < (int32_t)vec.size(); i++) {
if (vec[i]) {
WriteVarInt<Stream, VarIntMode::DEFAULT, uint32_t>(s, (uint32_t)(i - last));
last = i;
}
}
WriteVarInt<Stream, VarIntMode::DEFAULT, uint32_t>(s, 0); // stopper
}
template<typename Stream>
void ReadFixedVarIntsBitSet(Stream& s, std::vector<bool>& vec, size_t size)
{
vec.assign(size, false);
int32_t last = -1;
while(true) {
uint32_t offset = ReadVarInt<Stream, VarIntMode::DEFAULT, uint32_t>(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<std::vector<bool>, size_t> autobitset_t;
struct CFixedBitSet
{
const std::vector<bool>& vec;
size_t size;
CFixedBitSet(const std::vector<bool>& vecIn, size_t sizeIn) : vec(vecIn), size(sizeIn) {}
template<typename Stream>
void Serialize(Stream& s) const { WriteFixedBitSet(s, vec, size); }
};
struct CFixedVarIntsBitSet
{
const std::vector<bool>& vec;
size_t size;
CFixedVarIntsBitSet(const std::vector<bool>& vecIn, size_t sizeIn) : vec(vecIn), size(sizeIn) {}
template<typename Stream>
void Serialize(Stream& s) const { WriteFixedVarIntsBitSet(s, vec, vec.size()); }
};
template<typename Stream>
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<typename Stream>
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(). */ /** Simple wrapper class to serialize objects using a formatter; used by Using(). */
template<typename Formatter, typename T> template<typename Formatter, typename T>
class Wrapper class Wrapper
@ -465,167 +602,44 @@ public:
template<typename Formatter, typename T> template<typename Formatter, typename T>
static inline Wrapper<Formatter, T&> Using(T&& t) { return Wrapper<Formatter, T&>(t); } static inline Wrapper<Formatter, T&> Using(T&& t) { return Wrapper<Formatter, T&>(t); }
#define FIXEDBITSET(obj, size) CFixedBitSet(REF(obj), (size)) #define DYNBITSET(obj) Using<DynamicBitSetFormatter>(obj)
#define DYNBITSET(obj) CDynamicBitSet(REF(obj)) #define AUTOBITSET(obj) Using<AutoBitSetFormatter>(obj)
#define FIXEDVARINTSBITSET(obj, size) CFixedVarIntsBitSet(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) Using<LimitedStringFormatter<n>>(obj) #define LIMITED_STRING(obj,n) Using<LimitedStringFormatter<n>>(obj)
class CFixedBitSet /** TODO: describe DynamicBitSet */
struct DynamicBitSetFormatter
{ {
protected:
std::vector<bool>& vec;
size_t size;
public:
CFixedBitSet(std::vector<bool>& vecIn, size_t sizeIn) : vec(vecIn), size(sizeIn) {}
template<typename Stream> template<typename Stream>
void Serialize(Stream& s) const void Ser(Stream& s, const std::vector<bool>& vec) const
{
std::vector<unsigned char> 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<typename Stream>
void Unserialize(Stream& s)
{
vec.resize(size);
std::vector<unsigned char> 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<bool>& vec;
public:
explicit CDynamicBitSet(std::vector<bool>& vecIn) : vec(vecIn) {}
template<typename Stream>
void Serialize(Stream& s) const
{ {
WriteCompactSize(s, vec.size()); WriteCompactSize(s, vec.size());
CFixedBitSet(REF(vec), vec.size()).Serialize(s); WriteFixedBitSet(s, vec, vec.size());
} }
template<typename Stream> template<typename Stream>
void Unserialize(Stream& s) void Unser(Stream& s, std::vector<bool>& vec)
{ {
vec.resize(ReadCompactSize(s)); ReadFixedBitSet(s, vec, 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<bool>& vec;
size_t size;
public:
CFixedVarIntsBitSet(std::vector<bool>& vecIn, size_t sizeIn) : vec(vecIn), size(sizeIn) {}
template<typename Stream>
void Serialize(Stream& s) const
{
int32_t last = -1;
for (int32_t i = 0; i < (int32_t)vec.size(); i++) {
if (vec[i]) {
WriteVarInt<Stream, VarIntMode::DEFAULT, uint32_t>(s, (uint32_t)(i - last));
last = i;
}
}
WriteVarInt<Stream, VarIntMode::DEFAULT, uint32_t>(s, 0); // stopper
}
template<typename Stream>
void Unserialize(Stream& s)
{
vec.assign(size, false);
int32_t last = -1;
while(true) {
uint32_t offset = ReadVarInt<Stream, VarIntMode::DEFAULT, uint32_t>(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 * Serializes either as a CFixedBitSet or CFixedVarIntsBitSet, depending on which would give a smaller size
*/ */
class CAutoBitSet struct AutoBitSetFormatter
{ {
protected:
std::vector<bool>& vec;
size_t size;
public:
explicit CAutoBitSet(std::vector<bool>& vecIn, size_t sizeIn) : vec(vecIn), size(sizeIn) {}
template<typename Stream> template<typename Stream>
void Serialize(Stream& s) const void Ser(Stream& s, const autobitset_t& item) const
{ {
assert(vec.size() == size); WriteAutoBitSet(s, item);
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());
}
} }
template<typename Stream> template<typename Stream>
void Unserialize(Stream& s) void Unser(Stream& s, autobitset_t& item)
{ {
uint8_t isVarInts = ser_readdata8(s); ReadAutoBitSet(s, item);
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);
}
} }
}; };