@ -59,8 +59,8 @@ CMedianFilter<int> cPeerBlockCounts(8, 0); // Amount of blocks that other nodes
map < uint256 , CBlock * > mapOrphanBlocks ;
map < uint256 , CBlock * > mapOrphanBlocks ;
multimap < uint256 , CBlock * > mapOrphanBlocksByPrev ;
multimap < uint256 , CBlock * > mapOrphanBlocksByPrev ;
map < uint256 , CDataStream * > mapOrphanTransactions ;
map < uint256 , CTransaction > mapOrphanTransactions ;
map < uint256 , map < uint256 , CDataStream * > > mapOrphanTransactionsByPrev ;
map < uint256 , set < uint256 > > mapOrphanTransactionsByPrev ;
// Constant stuff for coinbase transactions we create:
// Constant stuff for coinbase transactions we create:
CScript COINBASE_FLAGS ;
CScript COINBASE_FLAGS ;
@ -399,16 +399,12 @@ CBlockTreeDB *pblocktree = NULL;
// mapOrphanTransactions
// mapOrphanTransactions
//
//
bool AddOrphanTx ( const CDataStream & vMsg )
bool AddOrphanTx ( const CTransaction & tx )
{
{
CTransaction tx ;
CDataStream ( vMsg ) > > tx ;
uint256 hash = tx . GetHash ( ) ;
uint256 hash = tx . GetHash ( ) ;
if ( mapOrphanTransactions . count ( hash ) )
if ( mapOrphanTransactions . count ( hash ) )
return false ;
return false ;
CDataStream * pvMsg = new CDataStream ( vMsg ) ;
// Ignore big transactions, to avoid a
// Ignore big transactions, to avoid a
// send-big-orphans memory exhaustion attack. If a peer has a legitimate
// send-big-orphans memory exhaustion attack. If a peer has a legitimate
// large transaction with a missing parent then we assume
// large transaction with a missing parent then we assume
@ -416,16 +412,16 @@ bool AddOrphanTx(const CDataStream& vMsg)
// have been mined or received.
// have been mined or received.
// 10,000 orphans, each of which is at most 5,000 bytes big is
// 10,000 orphans, each of which is at most 5,000 bytes big is
// at most 500 megabytes of orphans:
// at most 500 megabytes of orphans:
if ( pvMsg - > size ( ) > 5000 )
unsigned int sz = tx . GetSerializeSize ( SER_NETWORK , CTransaction : : CURRENT_VERSION ) ;
if ( sz > 5000 )
{
{
printf ( " ignoring large orphan tx (size: % " PRIszu " , hash: %s) \n " , pvMsg - > size ( ) , hash . ToString ( ) . c_str ( ) ) ;
printf ( " ignoring large orphan tx (size: %u, hash: %s) \n " , sz , hash . ToString ( ) . c_str ( ) ) ;
delete pvMsg ;
return false ;
return false ;
}
}
mapOrphanTransactions [ hash ] = pvMsg ;
mapOrphanTransactions [ hash ] = tx ;
BOOST_FOREACH ( const CTxIn & txin , tx . vin )
BOOST_FOREACH ( const CTxIn & txin , tx . vin )
mapOrphanTransactionsByPrev [ txin . prevout . hash ] . insert ( make_pair ( hash , pvMsg ) ) ;
mapOrphanTransactionsByPrev [ txin . prevout . hash ] . insert ( hash ) ;
printf ( " stored orphan tx %s (mapsz % " PRIszu " ) \n " , hash . ToString ( ) . c_str ( ) ,
printf ( " stored orphan tx %s (mapsz % " PRIszu " ) \n " , hash . ToString ( ) . c_str ( ) ,
mapOrphanTransactions . size ( ) ) ;
mapOrphanTransactions . size ( ) ) ;
@ -436,16 +432,13 @@ void static EraseOrphanTx(uint256 hash)
{
{
if ( ! mapOrphanTransactions . count ( hash ) )
if ( ! mapOrphanTransactions . count ( hash ) )
return ;
return ;
const CDataStream * pvMsg = mapOrphanTransactions [ hash ] ;
const CTransaction & tx = mapOrphanTransactions [ hash ] ;
CTransaction tx ;
CDataStream ( * pvMsg ) > > tx ;
BOOST_FOREACH ( const CTxIn & txin , tx . vin )
BOOST_FOREACH ( const CTxIn & txin , tx . vin )
{
{
mapOrphanTransactionsByPrev [ txin . prevout . hash ] . erase ( hash ) ;
mapOrphanTransactionsByPrev [ txin . prevout . hash ] . erase ( hash ) ;
if ( mapOrphanTransactionsByPrev [ txin . prevout . hash ] . empty ( ) )
if ( mapOrphanTransactionsByPrev [ txin . prevout . hash ] . empty ( ) )
mapOrphanTransactionsByPrev . erase ( txin . prevout . hash ) ;
mapOrphanTransactionsByPrev . erase ( txin . prevout . hash ) ;
}
}
delete pvMsg ;
mapOrphanTransactions . erase ( hash ) ;
mapOrphanTransactions . erase ( hash ) ;
}
}
@ -456,7 +449,7 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
{
{
// Evict a random orphan:
// Evict a random orphan:
uint256 randomhash = GetRandHash ( ) ;
uint256 randomhash = GetRandHash ( ) ;
map < uint256 , CDataStream * > : : iterator it = mapOrphanTransactions . lower_bound ( randomhash ) ;
map < uint256 , CTransaction > : : iterator it = mapOrphanTransactions . lower_bound ( randomhash ) ;
if ( it = = mapOrphanTransactions . end ( ) )
if ( it = = mapOrphanTransactions . end ( ) )
it = mapOrphanTransactions . begin ( ) ;
it = mapOrphanTransactions . begin ( ) ;
EraseOrphanTx ( it - > first ) ;
EraseOrphanTx ( it - > first ) ;
@ -793,7 +786,7 @@ void CTxMemPool::pruneSpent(const uint256 &hashTx, CCoins &coins)
}
}
}
}
bool CTxMemPool : : accept ( CValidationState & state , CTransaction & tx , bool fLimitFree ,
bool CTxMemPool : : accept ( CValidationState & state , const CTransaction & tx , bool fLimitFree ,
bool * pfMissingInputs )
bool * pfMissingInputs )
{
{
if ( pfMissingInputs )
if ( pfMissingInputs )
@ -960,7 +953,7 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fLimitFr
}
}
bool CTxMemPool : : addUnchecked ( const uint256 & hash , CTransaction & tx )
bool CTxMemPool : : addUnchecked ( const uint256 & hash , const CTransaction & tx )
{
{
// Add to memory pool without checking anything. Don't call this directly,
// Add to memory pool without checking anything. Don't call this directly,
// call CTxMemPool::accept to properly check the transaction first.
// call CTxMemPool::accept to properly check the transaction first.
@ -3598,21 +3591,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
CInv inv ( MSG_TX , tx . GetHash ( ) ) ;
CInv inv ( MSG_TX , tx . GetHash ( ) ) ;
pfrom - > AddInventoryKnown ( inv ) ;
pfrom - > AddInventoryKnown ( inv ) ;
// Truncate messages to the size of the tx in them
unsigned int nSize = : : GetSerializeSize ( tx , SER_NETWORK , PROTOCOL_VERSION ) ;
unsigned int oldSize = vMsg . size ( ) ;
if ( nSize < oldSize ) {
vMsg . resize ( nSize ) ;
printf ( " truncating oversized TX %s (%u -> %u) \n " ,
tx . GetHash ( ) . ToString ( ) . c_str ( ) ,
oldSize , nSize ) ;
}
bool fMissingInputs = false ;
bool fMissingInputs = false ;
CValidationState state ;
CValidationState state ;
if ( mempool . accept ( state , tx , true , & fMissingInputs ) )
if ( mempool . accept ( state , tx , true , & fMissingInputs ) )
{
{
RelayTransaction ( tx , inv . hash , vMsg ) ;
RelayTransaction ( tx , inv . hash ) ;
mapAlreadyAskedFor . erase ( inv ) ;
mapAlreadyAskedFor . erase ( inv ) ;
vWorkQueue . push_back ( inv . hash ) ;
vWorkQueue . push_back ( inv . hash ) ;
vEraseQueue . push_back ( inv . hash ) ;
vEraseQueue . push_back ( inv . hash ) ;
@ -3621,31 +3604,31 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
for ( unsigned int i = 0 ; i < vWorkQueue . size ( ) ; i + + )
for ( unsigned int i = 0 ; i < vWorkQueue . size ( ) ; i + + )
{
{
uint256 hashPrev = vWorkQueue [ i ] ;
uint256 hashPrev = vWorkQueue [ i ] ;
for ( map < uint256 , CDataStream * > : : iterator mi = mapOrphanTransactionsByPrev [ hashPrev ] . begin ( ) ;
for ( set < uint256 > : : iterator mi = mapOrphanTransactionsByPrev [ hashPrev ] . begin ( ) ;
mi ! = mapOrphanTransactionsByPrev [ hashPrev ] . end ( ) ;
mi ! = mapOrphanTransactionsByPrev [ hashPrev ] . end ( ) ;
+ + mi )
+ + mi )
{
{
const CDataStream & vMsg = * ( ( * mi ) . second ) ;
const uint256 & orphanHash = * mi ;
CTransaction tx ;
const CTransaction & orphanTx = mapOrphanTransactions [ orphanHash ] ;
CDataStream ( vMsg ) > > tx ;
CInv inv ( MSG_TX , tx . GetHash ( ) ) ;
bool fMissingInputs2 = false ;
bool fMissingInputs2 = false ;
// Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan resolution (that is, feeding people an invalid transaction based on LegitTxX in order to get anyone relaying LegitTxX banned)
// Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan
// resolution (that is, feeding people an invalid transaction based on LegitTxX in order to get
// anyone relaying LegitTxX banned)
CValidationState stateDummy ;
CValidationState stateDummy ;
if ( mempool . accept ( stateDummy , t x, true , & fMissingInputs2 ) )
if ( mempool . accept ( stateDummy , orphanT x, true , & fMissingInputs2 ) )
{
{
printf ( " accepted orphan tx %s \n " , inv . h ash. ToString ( ) . c_str ( ) ) ;
printf ( " accepted orphan tx %s \n " , orphanH ash. ToString ( ) . c_str ( ) ) ;
RelayTransaction ( tx , inv . hash , vMsg ) ;
RelayTransaction ( orphanTx , orphanHash ) ;
mapAlreadyAskedFor . erase ( inv ) ;
mapAlreadyAskedFor . erase ( CInv ( MSG_TX , orphanHash ) ) ;
vWorkQueue . push_back ( inv . h ash) ;
vWorkQueue . push_back ( orphanH ash) ;
vEraseQueue . push_back ( inv . h ash) ;
vEraseQueue . push_back ( orphanH ash) ;
}
}
else if ( ! fMissingInputs2 )
else if ( ! fMissingInputs2 )
{
{
// invalid or too-little-fee orphan
// invalid or too-little-fee orphan
vEraseQueue . push_back ( inv . h ash) ;
vEraseQueue . push_back ( orphanH ash) ;
printf ( " removed orphan tx %s \n " , inv . h ash. ToString ( ) . c_str ( ) ) ;
printf ( " removed orphan tx %s \n " , orphanH ash. ToString ( ) . c_str ( ) ) ;
}
}
}
}
}
}
@ -3655,7 +3638,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
}
}
else if ( fMissingInputs )
else if ( fMissingInputs )
{
{
AddOrphanTx ( vMsg ) ;
AddOrphanTx ( tx ) ;
// DoS prevention: do not allow mapOrphanTransactions to grow unbounded
// DoS prevention: do not allow mapOrphanTransactions to grow unbounded
unsigned int nEvicted = LimitOrphanTxSize ( MAX_ORPHAN_TRANSACTIONS ) ;
unsigned int nEvicted = LimitOrphanTxSize ( MAX_ORPHAN_TRANSACTIONS ) ;
@ -4142,9 +4125,6 @@ public:
mapOrphanBlocks . clear ( ) ;
mapOrphanBlocks . clear ( ) ;
// orphan transactions
// orphan transactions
std : : map < uint256 , CDataStream * > : : iterator it3 = mapOrphanTransactions . begin ( ) ;
for ( ; it3 ! = mapOrphanTransactions . end ( ) ; it3 + + )
delete ( * it3 ) . second ;
mapOrphanTransactions . clear ( ) ;
mapOrphanTransactions . clear ( ) ;
}
}
} instance_of_cmaincleanup ;
} instance_of_cmaincleanup ;