2019-12-30 22:39:22 +13:00
// Copyright (c) 2016-2019 The Bitcoin Core developers
2016-04-15 12:23:57 -07:00
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2018-03-22 15:19:44 +01:00
# ifndef BITCOIN_BLOCKENCODINGS_H
# define BITCOIN_BLOCKENCODINGS_H
2016-04-15 12:23:57 -07:00
2017-11-10 13:57:53 +13:00
# include <primitives/block.h>
2016-04-15 12:23:57 -07:00
class CTxMemPool ;
// Dumb helper to handle CTransaction compression at serialize-time
struct TransactionCompressor {
private :
2016-11-10 17:34:17 -08:00
CTransactionRef & tx ;
2016-04-15 12:23:57 -07:00
public :
2017-08-01 12:22:41 +02:00
explicit TransactionCompressor ( CTransactionRef & txIn ) : tx ( txIn ) { }
2016-04-15 12:23:57 -07:00
ADD_SERIALIZE_METHODS ;
template < typename Stream , typename Operation >
2016-10-28 16:29:17 -07:00
inline void SerializationOp ( Stream & s , Operation ser_action ) {
2016-04-15 12:23:57 -07:00
READWRITE ( tx ) ; //TODO: Compress tx encoding
}
} ;
2020-02-15 19:05:11 -08:00
class DifferenceFormatter
{
uint64_t m_shift = 0 ;
public :
template < typename Stream , typename I >
void Ser ( Stream & s , I v )
{
if ( v < m_shift | | v > = std : : numeric_limits < uint64_t > : : max ( ) ) throw std : : ios_base : : failure ( " differential value overflow " ) ;
WriteCompactSize ( s , v - m_shift ) ;
m_shift = uint64_t ( v ) + 1 ;
}
template < typename Stream , typename I >
void Unser ( Stream & s , I & v )
{
uint64_t n = ReadCompactSize ( s ) ;
m_shift + = n ;
if ( m_shift < n | | m_shift > = std : : numeric_limits < uint64_t > : : max ( ) | | m_shift < std : : numeric_limits < I > : : min ( ) | | m_shift > std : : numeric_limits < I > : : max ( ) ) throw std : : ios_base : : failure ( " differential value overflow " ) ;
v = I ( m_shift + + ) ;
}
} ;
2016-04-15 12:23:57 -07:00
class BlockTransactionsRequest {
public :
// A BlockTransactionsRequest message
uint256 blockhash ;
std : : vector < uint16_t > indexes ;
ADD_SERIALIZE_METHODS ;
template < typename Stream , typename Operation >
2016-10-28 16:29:17 -07:00
inline void SerializationOp ( Stream & s , Operation ser_action ) {
2016-04-15 12:23:57 -07:00
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 ;
}
}
2018-11-07 12:39:44 -08:00
int32_t offset = 0 ;
2016-08-03 19:45:24 +02:00
for ( size_t j = 0 ; j < indexes . size ( ) ; j + + ) {
2018-11-07 12:39:44 -08:00
if ( int32_t ( indexes [ j ] ) + offset > std : : numeric_limits < uint16_t > : : max ( ) )
2016-04-15 12:23:57 -07:00
throw std : : ios_base : : failure ( " indexes overflowed 16 bits " ) ;
2016-08-03 19:45:24 +02:00
indexes [ j ] = indexes [ j ] + offset ;
2018-11-07 12:39:44 -08:00
offset = int32_t ( indexes [ j ] ) + 1 ;
2016-04-15 12:23:57 -07:00
}
} 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 ) ) ;
}
}
}
} ;
class BlockTransactions {
public :
// A BlockTransactions message
uint256 blockhash ;
2016-11-10 17:34:17 -08:00
std : : vector < CTransactionRef > txn ;
2016-04-15 12:23:57 -07:00
BlockTransactions ( ) { }
2017-08-01 12:22:41 +02:00
explicit BlockTransactions ( const BlockTransactionsRequest & req ) :
2016-04-15 12:23:57 -07:00
blockhash ( req . blockhash ) , txn ( req . indexes . size ( ) ) { }
ADD_SERIALIZE_METHODS ;
template < typename Stream , typename Operation >
2016-10-28 16:29:17 -07:00
inline void SerializationOp ( Stream & s , Operation ser_action ) {
2016-04-15 12:23:57 -07:00
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 + + )
2017-07-07 19:09:55 -07:00
READWRITE ( TransactionCompressor ( txn [ i ] ) ) ;
2016-04-15 12:23:57 -07:00
}
} else {
for ( size_t i = 0 ; i < txn . size ( ) ; i + + )
2017-07-07 19:09:55 -07:00
READWRITE ( TransactionCompressor ( txn [ i ] ) ) ;
2016-04-15 12:23:57 -07:00
}
}
} ;
2017-01-18 16:15:37 +01:00
// Dumb serialization/storage-helper for CBlockHeaderAndShortTxIDs and PartiallyDownloadedBlock
2016-04-15 12:23:57 -07:00
struct PrefilledTransaction {
// Used as an offset since last prefilled tx in CBlockHeaderAndShortTxIDs,
// as a proper transaction-in-block-index in PartiallyDownloadedBlock
uint16_t index ;
2016-11-10 17:34:17 -08:00
CTransactionRef tx ;
2016-04-15 12:23:57 -07:00
ADD_SERIALIZE_METHODS ;
template < typename Stream , typename Operation >
2016-10-28 16:29:17 -07:00
inline void SerializationOp ( Stream & s , Operation ser_action ) {
2016-04-15 12:23:57 -07:00
uint64_t idx = index ;
READWRITE ( COMPACTSIZE ( idx ) ) ;
if ( idx > std : : numeric_limits < uint16_t > : : max ( ) )
throw std : : ios_base : : failure ( " index overflowed 16-bits " ) ;
index = idx ;
2017-07-07 19:09:55 -07:00
READWRITE ( TransactionCompressor ( tx ) ) ;
2016-04-15 12:23:57 -07:00
}
} ;
typedef enum ReadStatus_t
{
READ_STATUS_OK ,
READ_STATUS_INVALID , // Invalid object, peer is sending bogus crap
READ_STATUS_FAILED , // Failed to process object
2016-10-31 10:03:49 -04:00
READ_STATUS_CHECKBLOCK_FAILED , // Used only by FillBlock to indicate a
// failure in CheckBlock.
2016-04-15 12:23:57 -07:00
} ReadStatus ;
class CBlockHeaderAndShortTxIDs {
private :
mutable uint64_t shorttxidk0 , shorttxidk1 ;
uint64_t nonce ;
void FillShortTxIDSelector ( ) const ;
friend class PartiallyDownloadedBlock ;
static const int SHORTTXIDS_LENGTH = 6 ;
protected :
std : : vector < uint64_t > shorttxids ;
std : : vector < PrefilledTransaction > prefilledtxn ;
public :
CBlockHeader header ;
// Dummy for deserialization
CBlockHeaderAndShortTxIDs ( ) { }
2016-06-25 19:17:45 +02:00
CBlockHeaderAndShortTxIDs ( const CBlock & block , bool fUseWTXID ) ;
2016-04-15 12:23:57 -07:00
uint64_t GetShortID ( const uint256 & txhash ) const ;
size_t BlockTxCount ( ) const { return shorttxids . size ( ) + prefilledtxn . size ( ) ; }
ADD_SERIALIZE_METHODS ;
template < typename Stream , typename Operation >
2016-10-28 16:29:17 -07:00
inline void SerializationOp ( Stream & s , Operation ser_action ) {
2016-04-15 12:23:57 -07:00
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 ) ;
2018-11-13 12:40:22 -08:00
if ( BlockTxCount ( ) > std : : numeric_limits < uint16_t > : : max ( ) )
throw std : : ios_base : : failure ( " indexes overflowed 16 bits " ) ;
2016-04-15 12:23:57 -07:00
if ( ser_action . ForRead ( ) )
FillShortTxIDSelector ( ) ;
}
} ;
class PartiallyDownloadedBlock {
protected :
2016-11-10 17:34:17 -08:00
std : : vector < CTransactionRef > txn_available ;
2017-01-12 12:19:14 -08:00
size_t prefilled_count = 0 , mempool_count = 0 , extra_count = 0 ;
2016-04-15 12:23:57 -07:00
CTxMemPool * pool ;
public :
CBlockHeader header ;
2017-08-01 12:22:41 +02:00
explicit PartiallyDownloadedBlock ( CTxMemPool * poolIn ) : pool ( poolIn ) { }
2016-04-15 12:23:57 -07:00
2016-12-04 20:44:37 -08:00
// extra_txn is a list of extra transactions to look at, in <witness hash, reference> form
2017-01-12 12:20:11 -08:00
ReadStatus InitData ( const CBlockHeaderAndShortTxIDs & cmpctblock , const std : : vector < std : : pair < uint256 , CTransactionRef > > & extra_txn ) ;
2016-04-15 12:23:57 -07:00
bool IsTxAvailable ( size_t index ) const ;
2016-11-11 13:01:27 -08:00
ReadStatus FillBlock ( CBlock & block , const std : : vector < CTransactionRef > & vtx_missing ) ;
2016-04-15 12:23:57 -07:00
} ;
2018-03-22 15:19:44 +01:00
# endif // BITCOIN_BLOCKENCODINGS_H