Skip to content

Commit

Permalink
Convert blockencodings.h to new serialization framework
Browse files Browse the repository at this point in the history
  • Loading branch information
sipa committed Feb 13, 2020
1 parent 82d590e commit f3480e0
Showing 1 changed file with 84 additions and 102 deletions.
186 changes: 84 additions & 102 deletions src/blockencodings.h
Original file line number Diff line number Diff line change
@@ -11,17 +11,60 @@
class CTxMemPool;

// Dumb helper to handle CTransaction compression at serialize-time
struct TransactionCompressor {
private:
CTransactionRef& tx;
public:
explicit TransactionCompressor(CTransactionRef& txIn) : tx(txIn) {}
struct TransactionCompression
{
template<typename Stream> void Ser(Stream& s, const CTransactionRef& tx) { s << tx; }
template<typename Stream> void Unser(Stream& s, CTransactionRef& tx) { s >> tx; }
};

struct Uint48Formatter
{
template <typename Stream, typename I> void Ser(Stream& s, I v)
{
static_assert(std::is_unsigned<I>::value, "Uint48Formatter needs an unsigned integer");
static_assert(sizeof(I) >= 6, "Uint48Formatter needs a 48+ bit type");

uint32_t lsb = v & 0xffffffff;
uint16_t msb = (v >> 32) & 0xffff;
s << lsb << msb;
}

ADD_SERIALIZE_METHODS;
template <typename Stream, typename I> void Unser(Stream& s, I& v)
{
static_assert(std::is_unsigned<I>::value, "Uint48Formatter needs an unsigned integer");
static_assert(sizeof(I) >= 6, "Uint48Formatter needs a 48+ bit type");

template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(tx); //TODO: Compress tx encoding
uint32_t lsb;
uint16_t msb;
s >> lsb >> msb;
v = (uint64_t(msb) << 32) | uint64_t(lsb);
}
};

struct DifferentialSerTransform
{
uint16_t m_subtract = 0;

uint16_t operator()(uint16_t val)
{
uint16_t tmp = val - m_subtract;
m_subtract = uint16_t(val + 1);
return tmp;
}
};

struct DifferentialUnserTransform
{
bool m_first = true;
uint16_t m_add = 0;

uint16_t operator()(uint16_t val)
{
uint16_t tmp = uint16_t(val + m_add);
if (!m_first && tmp <= val) throw std::ios_base::failure("differential value overflow");
m_first = false;
m_add = uint16_t(tmp + 1);
return tmp;
}
};

@@ -31,39 +74,9 @@ class BlockTransactionsRequest {
uint256 blockhash;
std::vector<uint16_t> indexes;

ADD_SERIALIZE_METHODS;

template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(blockhash);
uint64_t indexes_size = (uint64_t)indexes.size();
READWRITE(COMPACTSIZE(indexes_size));
if (ser_action.ForRead()) {
size_t i = 0;
while (indexes.size() < indexes_size) {
indexes.resize(std::min((uint64_t)(1000 + indexes.size()), indexes_size));
for (; i < indexes.size(); i++) {
uint64_t index = 0;
READWRITE(COMPACTSIZE(index));
if (index > std::numeric_limits<uint16_t>::max())
throw std::ios_base::failure("index overflowed 16 bits");
indexes[i] = index;
}
}

int32_t offset = 0;
for (size_t j = 0; j < indexes.size(); j++) {
if (int32_t(indexes[j]) + offset > std::numeric_limits<uint16_t>::max())
throw std::ios_base::failure("indexes overflowed 16 bits");
indexes[j] = indexes[j] + offset;
offset = int32_t(indexes[j]) + 1;
}
} else {
for (size_t i = 0; i < indexes.size(); i++) {
uint64_t index = indexes[i] - (i == 0 ? 0 : (indexes[i - 1] + 1));
READWRITE(COMPACTSIZE(index));
}
}
SERIALIZE_METHODS(BlockTransactionsRequest, obj)
{
READWRITE(obj.blockhash, Using<VectorFormatter<CompactSizeFormatter, DifferentialSerTransform, DifferentialUnserTransform>>(obj.indexes));
}
};

@@ -77,24 +90,9 @@ class BlockTransactions {
explicit BlockTransactions(const BlockTransactionsRequest& req) :
blockhash(req.blockhash), txn(req.indexes.size()) {}

ADD_SERIALIZE_METHODS;

template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(blockhash);
uint64_t txn_size = (uint64_t)txn.size();
READWRITE(COMPACTSIZE(txn_size));
if (ser_action.ForRead()) {
size_t i = 0;
while (txn.size() < txn_size) {
txn.resize(std::min((uint64_t)(1000 + txn.size()), txn_size));
for (; i < txn.size(); i++)
READWRITE(TransactionCompressor(txn[i]));
}
} else {
for (size_t i = 0; i < txn.size(); i++)
READWRITE(TransactionCompressor(txn[i]));
}
SERIALIZE_METHODS(BlockTransactions, obj)
{
READWRITE(obj.blockhash, Using<VectorFormatter<TransactionCompression>>(obj.txn));
}
};

@@ -105,16 +103,22 @@ struct PrefilledTransaction {
uint16_t index;
CTransactionRef tx;

ADD_SERIALIZE_METHODS;
template<typename Stream>
void Serialize(Stream& s) const
{
s << COMPACTSIZE(index) << Using<TransactionCompression>(tx);
}

template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
uint64_t idx = index;
READWRITE(COMPACTSIZE(idx));
if (idx > std::numeric_limits<uint16_t>::max())
template<typename Stream>
void Unserialize(Stream& s)
{
uint64_t idx;
s >> COMPACTSIZE(idx);
if (idx > std::numeric_limits<uint16_t>::max()) {
throw std::ios_base::failure("index overflowed 16-bits");
}
index = idx;
READWRITE(TransactionCompressor(tx));
s >> Using<TransactionCompression>(tx);
}
};

@@ -153,43 +157,21 @@ class CBlockHeaderAndShortTxIDs {

size_t BlockTxCount() const { return shorttxids.size() + prefilledtxn.size(); }

ADD_SERIALIZE_METHODS;

template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(header);
READWRITE(nonce);

uint64_t shorttxids_size = (uint64_t)shorttxids.size();
READWRITE(COMPACTSIZE(shorttxids_size));
if (ser_action.ForRead()) {
size_t i = 0;
while (shorttxids.size() < shorttxids_size) {
shorttxids.resize(std::min((uint64_t)(1000 + shorttxids.size()), shorttxids_size));
for (; i < shorttxids.size(); i++) {
uint32_t lsb = 0; uint16_t msb = 0;
READWRITE(lsb);
READWRITE(msb);
shorttxids[i] = (uint64_t(msb) << 32) | uint64_t(lsb);
static_assert(SHORTTXIDS_LENGTH == 6, "shorttxids serialization assumes 6-byte shorttxids");
}
}
} else {
for (size_t i = 0; i < shorttxids.size(); i++) {
uint32_t lsb = shorttxids[i] & 0xffffffff;
uint16_t msb = (shorttxids[i] >> 32) & 0xffff;
READWRITE(lsb);
READWRITE(msb);
}
}

READWRITE(prefilledtxn);
template <typename Stream>
void Serialize(Stream& s) const
{
s << header << nonce << Using<VectorFormatter<Uint48Formatter>>(shorttxids) << prefilledtxn;
}

if (BlockTxCount() > std::numeric_limits<uint16_t>::max())
template <typename Stream>
inline void Unserialize(Stream& s)
{
static_assert(SHORTTXIDS_LENGTH == 6, "shorttxids serialization assumes 6-byte shorttxids");
s >> header >> nonce >> Using<VectorFormatter<Uint48Formatter>>(shorttxids) >> prefilledtxn;
if (BlockTxCount() > std::numeric_limits<uint16_t>::max()) {
throw std::ios_base::failure("indexes overflowed 16 bits");

if (ser_action.ForRead())
FillShortTxIDSelector();
}
FillShortTxIDSelector();
}
};

0 comments on commit f3480e0

Please sign in to comment.