Changeset View
Changeset View
Standalone View
Standalone View
src/blockencodings.h
| // Copyright (c) 2016 The Bitcoin Core developers | // Copyright (c) 2016 The Bitcoin Core developers | ||||
| // Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
| // file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
| #ifndef BITCOIN_BLOCKENCODINGS_H | #ifndef BITCOIN_BLOCKENCODINGS_H | ||||
| #define BITCOIN_BLOCKENCODINGS_H | #define BITCOIN_BLOCKENCODINGS_H | ||||
| #include <primitives/block.h> | #include <primitives/block.h> | ||||
| class Config; | class Config; | ||||
| class CTxMemPool; | class CTxMemPool; | ||||
| // Dumb helper to handle CTransaction compression at serialize-time | // Transaction compression schemes for compact block relay can be introduced by | ||||
| struct TransactionCompressor { | // writing an actual formatter here. | ||||
| private: | using TransactionCompression = DefaultFormatter; | ||||
| CTransactionRef &tx; | |||||
| public: | |||||
| explicit TransactionCompressor(CTransactionRef &txIn) : tx(txIn) {} | |||||
| ADD_SERIALIZE_METHODS; | |||||
| template <typename Stream, typename Operation> | |||||
| inline void SerializationOp(Stream &s, Operation ser_action) { | |||||
| // TODO: Compress tx encoding | |||||
| READWRITE(tx); | |||||
| } | |||||
| }; | |||||
| class DifferenceFormatter { | class DifferenceFormatter { | ||||
| uint64_t m_shift = 0; | uint64_t m_shift = 0; | ||||
| public: | public: | ||||
| template <typename Stream, typename I> void Ser(Stream &s, I v) { | template <typename Stream, typename I> void Ser(Stream &s, I v) { | ||||
| if (v < m_shift || v >= std::numeric_limits<uint64_t>::max()) { | if (v < m_shift || v >= std::numeric_limits<uint64_t>::max()) { | ||||
| throw std::ios_base::failure("differential value overflow"); | throw std::ios_base::failure("differential value overflow"); | ||||
| Show All 14 Lines | |||||
| }; | }; | ||||
| class BlockTransactionsRequest { | class BlockTransactionsRequest { | ||||
| public: | public: | ||||
| // A BlockTransactionsRequest message | // A BlockTransactionsRequest message | ||||
| BlockHash blockhash; | BlockHash blockhash; | ||||
| std::vector<uint32_t> indices; | std::vector<uint32_t> indices; | ||||
| ADD_SERIALIZE_METHODS; | SERIALIZE_METHODS(BlockTransactionsRequest, obj) { | ||||
| READWRITE(obj.blockhash, | |||||
| template <typename Stream, typename Operation> | Using<VectorFormatter<DifferenceFormatter>>(obj.indices)); | ||||
| inline void SerializationOp(Stream &s, Operation ser_action) { | |||||
| READWRITE(blockhash); | |||||
| uint64_t indices_size = uint64_t(indices.size()); | |||||
| READWRITE(COMPACTSIZE(indices_size)); | |||||
| if (ser_action.ForRead()) { | |||||
| size_t i = 0; | |||||
| while (indices.size() < indices_size) { | |||||
| indices.resize( | |||||
| std::min(uint64_t(1000 + indices.size()), indices_size)); | |||||
| for (; i < indices.size(); i++) { | |||||
| uint64_t n = 0; | |||||
| READWRITE(COMPACTSIZE(n)); | |||||
| if (n > std::numeric_limits<uint32_t>::max()) { | |||||
| throw std::ios_base::failure( | |||||
| "index overflowed 32 bits"); | |||||
| } | |||||
| indices[i] = n; | |||||
| } | |||||
| } | |||||
| uint64_t offset = 0; | |||||
| for (auto &index : indices) { | |||||
| if (uint64_t(index) + offset > | |||||
| std::numeric_limits<uint32_t>::max()) { | |||||
| throw std::ios_base::failure("indices overflowed 32 bits"); | |||||
| } | |||||
| index = index + offset; | |||||
| offset = uint64_t(index) + 1; | |||||
| } | |||||
| } else { | |||||
| for (size_t i = 0; i < indices.size(); i++) { | |||||
| uint64_t index = | |||||
| indices[i] - (i == 0 ? 0 : (indices[i - 1] + 1)); | |||||
| READWRITE(COMPACTSIZE(index)); | |||||
| } | |||||
| } | |||||
| } | } | ||||
| }; | }; | ||||
| class BlockTransactions { | class BlockTransactions { | ||||
| public: | public: | ||||
| // A BlockTransactions message | // A BlockTransactions message | ||||
| BlockHash blockhash; | BlockHash blockhash; | ||||
| std::vector<CTransactionRef> txn; | std::vector<CTransactionRef> txn; | ||||
| BlockTransactions() {} | BlockTransactions() {} | ||||
| explicit BlockTransactions(const BlockTransactionsRequest &req) | explicit BlockTransactions(const BlockTransactionsRequest &req) | ||||
| : blockhash(req.blockhash), txn(req.indices.size()) {} | : blockhash(req.blockhash), txn(req.indices.size()) {} | ||||
| ADD_SERIALIZE_METHODS; | SERIALIZE_METHODS(BlockTransactions, obj) { | ||||
| READWRITE(obj.blockhash, | |||||
| template <typename Stream, typename Operation> | Using<VectorFormatter<TransactionCompression>>(obj.txn)); | ||||
| 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])); | |||||
| } | |||||
| } | |||||
| } | } | ||||
| }; | }; | ||||
| // Dumb serialization/storage-helper for CBlockHeaderAndShortTxIDs and | // Dumb serialization/storage-helper for CBlockHeaderAndShortTxIDs and | ||||
| // PartiallyDownloadedBlock | // PartiallyDownloadedBlock | ||||
| struct PrefilledTransaction { | struct PrefilledTransaction { | ||||
| // Used as an offset since last prefilled tx in CBlockHeaderAndShortTxIDs, | // Used as an offset since last prefilled tx in CBlockHeaderAndShortTxIDs, | ||||
| // as a proper transaction-in-block-index in PartiallyDownloadedBlock | // as a proper transaction-in-block-index in PartiallyDownloadedBlock | ||||
| uint32_t index; | uint32_t index; | ||||
| CTransactionRef tx; | CTransactionRef tx; | ||||
| ADD_SERIALIZE_METHODS; | SERIALIZE_METHODS(PrefilledTransaction, obj) { | ||||
| READWRITE(COMPACTSIZE(obj.index), | |||||
| template <typename Stream, typename Operation> | Using<TransactionCompression>(obj.tx)); | ||||
| inline void SerializationOp(Stream &s, Operation ser_action) { | |||||
| uint64_t n = index; | |||||
| READWRITE(COMPACTSIZE(n)); | |||||
| if (n > std::numeric_limits<uint32_t>::max()) { | |||||
| throw std::ios_base::failure("index overflowed 32-bits"); | |||||
| } | |||||
| index = n; | |||||
| READWRITE(TransactionCompressor(tx)); | |||||
| } | } | ||||
| }; | }; | ||||
| typedef enum ReadStatus_t { | typedef enum ReadStatus_t { | ||||
| READ_STATUS_OK, | READ_STATUS_OK, | ||||
| // Invalid object, peer is sending bogus crap. | // Invalid object, peer is sending bogus crap. | ||||
| // FIXME: differenciate bogus crap from crap that do not fit our policy. | // FIXME: differenciate bogus crap from crap that do not fit our policy. | ||||
| READ_STATUS_INVALID, | READ_STATUS_INVALID, | ||||
| Show All 27 Lines | public: | ||||
| explicit CBlockHeaderAndShortTxIDs(const CBlock &block); | explicit CBlockHeaderAndShortTxIDs(const CBlock &block); | ||||
| uint64_t GetShortID(const TxHash &txhash) const; | uint64_t GetShortID(const TxHash &txhash) const; | ||||
| size_t BlockTxCount() const { | size_t BlockTxCount() const { | ||||
| return shorttxids.size() + prefilledtxn.size(); | return shorttxids.size() + prefilledtxn.size(); | ||||
| } | } | ||||
| ADD_SERIALIZE_METHODS; | SERIALIZE_METHODS(CBlockHeaderAndShortTxIDs, obj) { | ||||
| READWRITE( | |||||
| template <typename Stream, typename Operation> | obj.header, obj.nonce, | ||||
| inline void SerializationOp(Stream &s, Operation ser_action) { | Using<VectorFormatter<CustomUintFormatter<SHORTTXIDS_LENGTH>>>( | ||||
| READWRITE(header); | obj.shorttxids), | ||||
| READWRITE(nonce); | obj.prefilledtxn); | ||||
| uint64_t shorttxids_size = (uint64_t)shorttxids.size(); | |||||
| READWRITE(COMPACTSIZE(shorttxids_size)); | |||||
| if (ser_action.ForRead()) { | if (ser_action.ForRead()) { | ||||
| size_t i = 0; | if (obj.BlockTxCount() > std::numeric_limits<uint32_t>::max()) { | ||||
| 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 (uint64_t shortid : shorttxids) { | |||||
| uint32_t lsb = shortid & 0xffffffff; | |||||
| uint16_t msb = (shortid >> 32) & 0xffff; | |||||
| READWRITE(lsb); | |||||
| READWRITE(msb); | |||||
| } | |||||
| } | |||||
| READWRITE(prefilledtxn); | |||||
| if (BlockTxCount() > std::numeric_limits<uint32_t>::max()) { | |||||
| throw std::ios_base::failure("indices overflowed 32 bits"); | throw std::ios_base::failure("indices overflowed 32 bits"); | ||||
| } | } | ||||
| obj.FillShortTxIDSelector(); | |||||
| if (ser_action.ForRead()) { | |||||
| FillShortTxIDSelector(); | |||||
| } | } | ||||
| } | } | ||||
| }; | }; | ||||
| class PartiallyDownloadedBlock { | class PartiallyDownloadedBlock { | ||||
| protected: | protected: | ||||
| std::vector<CTransactionRef> txns_available; | std::vector<CTransactionRef> txns_available; | ||||
| size_t prefilled_count = 0, mempool_count = 0, extra_count = 0; | size_t prefilled_count = 0, mempool_count = 0, extra_count = 0; | ||||
| Show All 19 Lines | |||||