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;
public:
ADD_SERIALIZE_METHODS
template<typename Stream, typename Operation>
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:

View File

@ -95,17 +95,16 @@ public:
CDKGComplaint() = default;
explicit CDKGComplaint(const Consensus::LLMQParams& params);
ADD_SERIALIZE_METHODS
template<typename Stream, typename Operation>
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<typename Stream, typename Operation>
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

View File

@ -98,16 +98,13 @@ public:
std::vector<bool> inv;
public:
ADD_SERIALIZE_METHODS
template<typename Stream, typename Operation>
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);

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(). */
template<typename Formatter, typename T>
class Wrapper
@ -465,167 +602,44 @@ public:
template<typename Formatter, typename 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) CDynamicBitSet(REF(obj))
#define FIXEDVARINTSBITSET(obj, size) CFixedVarIntsBitSet(REF(obj), (size))
#define AUTOBITSET(obj, size) CAutoBitSet(REF(obj), (size))
#define DYNBITSET(obj) Using<DynamicBitSetFormatter>(obj)
#define AUTOBITSET(obj) Using<AutoBitSetFormatter>(obj)
#define VARINT(obj, ...) Using<VarIntFormatter<__VA_ARGS__>>(obj)
#define COMPACTSIZE(obj) Using<CompactSizeFormatter>(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>
void Serialize(Stream& s) 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
void Ser(Stream& s, const std::vector<bool>& vec) const
{
WriteCompactSize(s, vec.size());
CFixedBitSet(REF(vec), vec.size()).Serialize(s);
WriteFixedBitSet(s, vec, vec.size());
}
template<typename Stream>
void Unserialize(Stream& s)
void Unser(Stream& s, std::vector<bool>& 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<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;
}
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<bool>& vec;
size_t size;
public:
explicit CAutoBitSet(std::vector<bool>& vecIn, size_t sizeIn) : vec(vecIn), size(sizeIn) {}
template<typename Stream>
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<typename Stream>
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);
}
};