@ -337,7 +337,7 @@ public:
scriptPubKey . clear ( ) ;
scriptPubKey . clear ( ) ;
}
}
bool IsNull ( )
bool IsNull ( ) const
{
{
return ( nValue = = - 1 ) ;
return ( nValue = = - 1 ) ;
}
}
@ -673,6 +673,238 @@ public:
} ) ; )
} ) ; )
} ;
} ;
/** pruned version of CTransaction: only retains metadata and unspent transaction outputs
*
* Serialized format :
* - VARINT ( nVersion )
* - VARINT ( nCode )
* - unspentness bitvector , for vout [ 2 ] and further ; least significant byte first
* - the non - spent CTxOuts ( via CTxOutCompressor )
* - VARINT ( nHeight )
*
* The nCode value consists of :
* - bit 1 : IsCoinBase ( )
* - bit 2 : vout [ 0 ] is not spent
* - bit 4 : vout [ 1 ] is not spent
* - The higher bits encode N , the number of non - zero bytes in the following bitvector .
* - In case both bit 2 and bit 4 are unset , they encode N - 1 , as there must be at
* least one non - spent output ) .
*
* Example : 0104835800816115944e077 fe7c803cfa57f29b36bf87c1d358bb85e
* < > < > < - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - > < - - - - >
* | \ | /
* version code vout [ 1 ] height
*
* - version = 1
* - code = 4 ( vout [ 1 ] is not spent , and 0 non - zero bytes of bitvector follow )
* - unspentness bitvector : as 0 non - zero bytes follow , it has length 0
* - vout [ 1 ] : 835800816115944e077 fe7c803cfa57f29b36bf87c1d35
* * 8358 : compact amount representation for 60000000000 ( 600 BTC )
* * 00 : special txout type pay - to - pubkey - hash
* * 816115944e077 fe7c803cfa57f29b36bf87c1d35 : address uint160
* - height = 203998
*
*
* Example : 010 9044086 ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4eebbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa486af3b
* < > < > < - - > < - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - > < - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - > < - - - - >
* / \ \ | | /
* version code unspentness vout [ 4 ] vout [ 16 ] height
*
* - version = 1
* - code = 9 ( coinbase , neither vout [ 0 ] or vout [ 1 ] are unspent ,
* 2 ( 1 , + 1 because both bit 2 and bit 4 are unset ) non - zero bitvector bytes follow )
* - unspentness bitvector : bits 2 ( 0x04 ) and 14 ( 0x4000 ) are set , so vout [ 2 + 2 ] and vout [ 14 + 2 ] are unspent
* - vout [ 4 ] : 86 ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4ee
* * 86 ef97d579 : compact amount representation for 234925952 ( 2.35 BTC )
* * 00 : special txout type pay - to - pubkey - hash
* * 61 b01caab50f1b8e9c50a5057eb43c2d9563a4ee : address uint160
* - vout [ 16 ] : bbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa4
* * bbd123 : compact amount representation for 110397 ( 0.001 BTC )
* * 00 : special txout type pay - to - pubkey - hash
* * 8 c988f1a4a4de2161e0f50aac7f17e7f9555caa4 : address uint160
* - height = 120891
*/
class CCoins
{
public :
// whether transaction is a coinbase
bool fCoinBase ;
// unspent transaction outputs; spent outputs are .IsNull(); spent outputs at the end of the array are dropped
std : : vector < CTxOut > vout ;
// at which height this transaction was included in the active blockchain
int nHeight ;
// version of the CTransaction; accesses to this value should probably check for nHeight as well,
// as new tx version will probably only be introduced at certain heights
int nVersion ;
// construct a CCoins from a CTransaction, at a given height
CCoins ( const CTransaction & tx , int nHeightIn ) : fCoinBase ( tx . IsCoinBase ( ) ) , vout ( tx . vout ) , nHeight ( nHeightIn ) , nVersion ( tx . nVersion ) { }
// empty constructor
CCoins ( ) : fCoinBase ( false ) , vout ( 0 ) , nHeight ( 0 ) , nVersion ( 0 ) { }
// remove spent outputs at the end of vout
void Cleanup ( ) {
while ( vout . size ( ) > 0 & & vout . back ( ) . IsNull ( ) )
vout . pop_back ( ) ;
}
// equality test
friend bool operator = = ( const CCoins & a , const CCoins & b ) {
return a . fCoinBase = = b . fCoinBase & &
a . nHeight = = b . nHeight & &
a . nVersion = = b . nVersion & &
a . vout = = b . vout ;
}
friend bool operator ! = ( const CCoins & a , const CCoins & b ) {
return ! ( a = = b ) ;
}
// calculate number of bytes for the bitmask, and its number of non-zero bytes
// each bit in the bitmask represents the availability of one output, but the
// availabilities of the first two outputs are encoded separately
void CalcMaskSize ( unsigned int & nBytes , unsigned int & nNonzeroBytes ) const {
unsigned int nLastUsedByte = 0 ;
for ( unsigned int b = 0 ; 2 + b * 8 < vout . size ( ) ; b + + ) {
bool fZero = true ;
for ( unsigned int i = 0 ; i < 8 & & 2 + b * 8 + i < vout . size ( ) ; i + + ) {
if ( ! vout [ 2 + b * 8 + i ] . IsNull ( ) ) {
fZero = false ;
continue ;
}
}
if ( ! fZero ) {
nLastUsedByte = b + 1 ;
nNonzeroBytes + + ;
}
}
nBytes + = nLastUsedByte ;
}
bool IsCoinBase ( ) const {
return fCoinBase ;
}
unsigned int GetSerializeSize ( int nType , int nVersion ) const {
unsigned int nSize = 0 ;
unsigned int nMaskSize = 0 , nMaskCode = 0 ;
CalcMaskSize ( nMaskSize , nMaskCode ) ;
bool fFirst = vout . size ( ) > 0 & & ! vout [ 0 ] . IsNull ( ) ;
bool fSecond = vout . size ( ) > 1 & & ! vout [ 1 ] . IsNull ( ) ;
assert ( fFirst | | fSecond | | nMaskCode ) ;
unsigned int nCode = 8 * ( nMaskCode - ( fFirst | | fSecond ? 0 : 1 ) ) + ( fCoinBase ? 1 : 0 ) + ( fFirst ? 2 : 0 ) + ( fSecond ? 4 : 0 ) ;
// version
nSize + = : : GetSerializeSize ( VARINT ( this - > nVersion ) , nType , nVersion ) ;
// size of header code
nSize + = : : GetSerializeSize ( VARINT ( nCode ) , nType , nVersion ) ;
// spentness bitmask
nSize + = nMaskSize ;
// txouts themself
for ( unsigned int i = 0 ; i < vout . size ( ) ; i + + )
if ( ! vout [ i ] . IsNull ( ) )
nSize + = : : GetSerializeSize ( CTxOutCompressor ( REF ( vout [ i ] ) ) , nType , nVersion ) ;
// height
nSize + = : : GetSerializeSize ( VARINT ( nHeight ) , nType , nVersion ) ;
return nSize ;
}
template < typename Stream >
void Serialize ( Stream & s , int nType , int nVersion ) const {
unsigned int nMaskSize = 0 , nMaskCode = 0 ;
CalcMaskSize ( nMaskSize , nMaskCode ) ;
bool fFirst = vout . size ( ) > 0 & & ! vout [ 0 ] . IsNull ( ) ;
bool fSecond = vout . size ( ) > 1 & & ! vout [ 1 ] . IsNull ( ) ;
assert ( fFirst | | fSecond | | nMaskCode ) ;
unsigned int nCode = 8 * ( nMaskCode - ( fFirst | | fSecond ? 0 : 1 ) ) + ( fCoinBase ? 1 : 0 ) + ( fFirst ? 2 : 0 ) + ( fSecond ? 4 : 0 ) ;
// version
: : Serialize ( s , VARINT ( this - > nVersion ) , nType , nVersion ) ;
// header code
: : Serialize ( s , VARINT ( nCode ) , nType , nVersion ) ;
// spentness bitmask
for ( unsigned int b = 0 ; b < nMaskSize ; b + + ) {
unsigned char chAvail = 0 ;
for ( unsigned int i = 0 ; i < 8 & & 2 + b * 8 + i < vout . size ( ) ; i + + )
if ( ! vout [ 2 + b * 8 + i ] . IsNull ( ) )
chAvail | = ( 1 < < i ) ;
: : Serialize ( s , chAvail , nType , nVersion ) ;
}
// txouts themself
for ( unsigned int i = 0 ; i < vout . size ( ) ; i + + ) {
if ( ! vout [ i ] . IsNull ( ) )
: : Serialize ( s , CTxOutCompressor ( REF ( vout [ i ] ) ) , nType , nVersion ) ;
}
// coinbase height
: : Serialize ( s , VARINT ( nHeight ) , nType , nVersion ) ;
}
template < typename Stream >
void Unserialize ( Stream & s , int nType , int nVersion ) {
unsigned int nCode = 0 ;
// version
: : Unserialize ( s , VARINT ( this - > nVersion ) , nType , nVersion ) ;
// header code
: : Unserialize ( s , VARINT ( nCode ) , nType , nVersion ) ;
fCoinBase = nCode & 1 ;
std : : vector < bool > vAvail ( 2 , false ) ;
vAvail [ 0 ] = nCode & 2 ;
vAvail [ 1 ] = nCode & 4 ;
unsigned int nMaskCode = ( nCode / 8 ) + ( ( nCode & 6 ) ! = 0 ? 0 : 1 ) ;
// spentness bitmask
while ( nMaskCode > 0 ) {
unsigned char chAvail = 0 ;
: : Unserialize ( s , chAvail , nType , nVersion ) ;
for ( unsigned int p = 0 ; p < 8 ; p + + ) {
bool f = ( chAvail & ( 1 < < p ) ) ! = 0 ;
vAvail . push_back ( f ) ;
}
if ( chAvail ! = 0 )
nMaskCode - - ;
}
// txouts themself
vout . assign ( vAvail . size ( ) , CTxOut ( ) ) ;
for ( unsigned int i = 0 ; i < vAvail . size ( ) ; i + + ) {
if ( vAvail [ i ] )
: : Unserialize ( s , REF ( CTxOutCompressor ( vout [ i ] ) ) , nType , nVersion ) ;
}
// coinbase height
: : Unserialize ( s , VARINT ( nHeight ) , nType , nVersion ) ;
Cleanup ( ) ;
}
// mark an outpoint spent
bool Spend ( const COutPoint & out ) {
if ( out . n > = vout . size ( ) )
return false ;
if ( vout [ out . n ] . IsNull ( ) )
return false ;
vout [ out . n ] . SetNull ( ) ;
Cleanup ( ) ;
return true ;
}
// mark a vout spent
bool Spend ( int nPos ) {
COutPoint out ( 0 , nPos ) ;
return Spend ( out ) ;
}
// check whether a particular output is still available
bool IsAvailable ( unsigned int nPos ) const {
return ( nPos < vout . size ( ) & & ! vout [ nPos ] . IsNull ( ) ) ;
}
// check whether the entire CCoins is spent
// note that only !IsPruned() CCoins can be serialized
bool IsPruned ( ) const {
BOOST_FOREACH ( const CTxOut & out , vout )
if ( ! out . IsNull ( ) )
return false ;
return true ;
}
} ;