@ -7,61 +7,90 @@
# define BITCOIN_UNDO_H
# define BITCOIN_UNDO_H
# include "compressor.h"
# include "compressor.h"
# include "consensus/consensus.h"
# include "primitives/transaction.h"
# include "primitives/transaction.h"
# include "serialize.h"
# include "serialize.h"
/** Undo information for a CTxIn
/** Undo information for a CTxIn
*
*
* Contains the prevout ' s CTxOut being spent , and its metadata as well
* Contains the prevout ' s CTxOut being spent , and its metadata as well
* ( coinbase or not , height ) . Earlier versions also stored the transaction
* ( coinbase or not , height ) . The serialization contains a dummy value of
* version .
* zero . This is be compatible with older versions which expect to see
* the transaction version there .
*/
*/
class C TxInUndo
class TxInUndoSerializer
{
{
public :
const Coin * txout ;
CTxOut txout ; // the txout data before being spent
bool fCoinBase ; // if the outpoint was the last unspent: whether it belonged to a coinbase
unsigned int nHeight ; // if the outpoint was the last unspent: its height
CTxInUndo ( ) : txout ( ) , fCoinBase ( false ) , nHeight ( 0 ) { }
CTxInUndo ( const CTxOut & txoutIn , bool fCoinBaseIn = false , unsigned int nHeightIn = 0 ) : txout ( txoutIn ) , fCoinBase ( fCoinBaseIn ) , nHeight ( nHeightIn ) { }
public :
template < typename Stream >
template < typename Stream >
void Serialize ( Stream & s ) const {
void Serialize ( Stream & s ) const {
: : Serialize ( s , VARINT ( nHeight * 2 + ( fCoinBase ? 1 : 0 ) ) ) ;
: : Serialize ( s , VARINT ( txout - > nHeight * 2 + ( txout - > fCoinBase ? 1 : 0 ) ) ) ;
if ( nHeight > 0 ) {
if ( txout - > nHeight > 0 ) {
int nVersionDummy = 0 ;
// Required to maintain compatibility with older undo format.
: : Serialize ( s , VARINT ( nVersionDummy ) ) ;
: : Serialize ( s , ( unsigned char ) 0 ) ;
}
}
: : Serialize ( s , CTxOutCompressor ( REF ( txout ) ) ) ;
: : Serialize ( s , CTxOutCompressor ( REF ( txout - > out ) ) ) ;
}
}
TxInUndoSerializer ( const Coin * coin ) : txout ( coin ) { }
} ;
class TxInUndoDeserializer
{
Coin * txout ;
public :
template < typename Stream >
template < typename Stream >
void Unserialize ( Stream & s ) {
void Unserialize ( Stream & s ) {
unsigned int nCode = 0 ;
unsigned int nCode = 0 ;
: : Unserialize ( s , VARINT ( nCode ) ) ;
: : Unserialize ( s , VARINT ( nCode ) ) ;
nHeight = nCode / 2 ;
txout - > nHeight = nCode / 2 ;
fCoinBase = nCode & 1 ;
txout - > fCoinBase = nCode & 1 ;
if ( nHeight > 0 ) {
if ( txout - > nHeight > 0 ) {
// Old versions stored the version number for the last spend of
// a transaction's outputs. Non-final spends were indicated with
// height = 0.
int nVersionDummy ;
int nVersionDummy ;
: : Unserialize ( s , VARINT ( nVersionDummy ) ) ;
: : Unserialize ( s , VARINT ( nVersionDummy ) ) ;
}
}
: : Unserialize ( s , REF ( CTxOutCompressor ( REF ( txout ) ) ) ) ;
: : Unserialize ( s , REF ( CTxOutCompressor ( REF ( txout - > out ) ) ) ) ;
}
}
TxInUndoDeserializer ( Coin * coin ) : txout ( coin ) { }
} ;
} ;
static const size_t MAX_INPUTS_PER_BLOCK = MAX_BLOCK_BASE_SIZE / : : GetSerializeSize ( CTxIn ( ) , SER_NETWORK , PROTOCOL_VERSION ) ;
/** Undo information for a CTransaction */
/** Undo information for a CTransaction */
class CTxUndo
class CTxUndo
{
{
public :
public :
// undo information for all txins
// undo information for all txins
std : : vector < CTxInUndo > vprevout ;
std : : vector < Coin > vprevout ;
ADD_SERIALIZE_METHODS ;
template < typename Stream >
void Serialize ( Stream & s ) const {
// TODO: avoid reimplementing vector serializer
uint64_t count = vprevout . size ( ) ;
: : Serialize ( s , COMPACTSIZE ( REF ( count ) ) ) ;
for ( const auto & prevout : vprevout ) {
: : Serialize ( s , REF ( TxInUndoSerializer ( & prevout ) ) ) ;
}
}
template < typename Stream , typename Operation >
template < typename Stream >
inline void SerializationOp ( Stream & s , Operation ser_action ) {
void Unserialize ( Stream & s ) {
READWRITE ( vprevout ) ;
// TODO: avoid reimplementing vector deserializer
uint64_t count = 0 ;
: : Unserialize ( s , COMPACTSIZE ( count ) ) ;
if ( count > MAX_INPUTS_PER_BLOCK ) {
throw std : : ios_base : : failure ( " Too many input undo records " ) ;
}
vprevout . resize ( count ) ;
for ( auto & prevout : vprevout ) {
: : Unserialize ( s , REF ( TxInUndoDeserializer ( & prevout ) ) ) ;
}
}
}
} ;
} ;