@ -63,8 +63,13 @@ struct COrphanBlock {
map < uint256 , COrphanBlock * > mapOrphanBlocks ;
map < uint256 , COrphanBlock * > mapOrphanBlocks ;
multimap < uint256 , COrphanBlock * > mapOrphanBlocksByPrev ;
multimap < uint256 , COrphanBlock * > mapOrphanBlocksByPrev ;
map < uint256 , CTransaction > mapOrphanTransactions ;
struct COrphanTx {
CTransaction tx ;
NodeId fromPeer ;
} ;
map < uint256 , COrphanTx > mapOrphanTransactions ;
map < uint256 , set < uint256 > > mapOrphanTransactionsByPrev ;
map < uint256 , set < uint256 > > mapOrphanTransactionsByPrev ;
void EraseOrphansFor ( NodeId peer ) ;
// Constant stuff for coinbase transactions we create:
// Constant stuff for coinbase transactions we create:
CScript COINBASE_FLAGS ;
CScript COINBASE_FLAGS ;
@ -264,6 +269,7 @@ void FinalizeNode(NodeId nodeid) {
mapBlocksInFlight . erase ( entry . hash ) ;
mapBlocksInFlight . erase ( entry . hash ) ;
BOOST_FOREACH ( const uint256 & hash , state - > vBlocksToDownload )
BOOST_FOREACH ( const uint256 & hash , state - > vBlocksToDownload )
mapBlocksToDownload . erase ( hash ) ;
mapBlocksToDownload . erase ( hash ) ;
EraseOrphansFor ( nodeid ) ;
mapNodeState . erase ( nodeid ) ;
mapNodeState . erase ( nodeid ) ;
}
}
@ -461,7 +467,7 @@ CBlockTreeDB *pblocktree = NULL;
// mapOrphanTransactions
// mapOrphanTransactions
//
//
bool AddOrphanTx ( const CTransaction & tx )
bool AddOrphanTx ( const CTransaction & tx , NodeId peer )
{
{
uint256 hash = tx . GetHash ( ) ;
uint256 hash = tx . GetHash ( ) ;
if ( mapOrphanTransactions . count ( hash ) )
if ( mapOrphanTransactions . count ( hash ) )
@ -481,21 +487,22 @@ bool AddOrphanTx(const CTransaction& tx)
return false ;
return false ;
}
}
mapOrphanTransactions [ hash ] = tx ;
mapOrphanTransactions [ hash ] . tx = tx ;
mapOrphanTransactions [ hash ] . fromPeer = peer ;
BOOST_FOREACH ( const CTxIn & txin , tx . vin )
BOOST_FOREACH ( const CTxIn & txin , tx . vin )
mapOrphanTransactionsByPrev [ txin . prevout . hash ] . insert ( hash ) ;
mapOrphanTransactionsByPrev [ txin . prevout . hash ] . insert ( hash ) ;
LogPrint ( " mempool " , " stored orphan tx %s (mapsz %u) \n " , hash . ToString ( ) ,
LogPrint ( " mempool " , " stored orphan tx %s (mapsz %u prevsz %u ) \n " , hash . ToString ( ) ,
mapOrphanTransactions . size ( ) ) ;
mapOrphanTransactions . size ( ) , mapOrphanTransactionsByPrev . size ( ) ) ;
return true ;
return true ;
}
}
void static EraseOrphanTx ( uint256 hash )
void static EraseOrphanTx ( uint256 hash )
{
{
map < uint256 , CTransaction > : : iterator it = mapOrphanTransactions . find ( hash ) ;
map < uint256 , COrphanTx > : : iterator it = mapOrphanTransactions . find ( hash ) ;
if ( it = = mapOrphanTransactions . end ( ) )
if ( it = = mapOrphanTransactions . end ( ) )
return ;
return ;
BOOST_FOREACH ( const CTxIn & txin , it - > second . vin )
BOOST_FOREACH ( const CTxIn & txin , it - > second . tx . vin )
{
{
map < uint256 , set < uint256 > > : : iterator itPrev = mapOrphanTransactionsByPrev . find ( txin . prevout . hash ) ;
map < uint256 , set < uint256 > > : : iterator itPrev = mapOrphanTransactionsByPrev . find ( txin . prevout . hash ) ;
if ( itPrev = = mapOrphanTransactionsByPrev . end ( ) )
if ( itPrev = = mapOrphanTransactionsByPrev . end ( ) )
@ -507,6 +514,23 @@ void static EraseOrphanTx(uint256 hash)
mapOrphanTransactions . erase ( it ) ;
mapOrphanTransactions . erase ( it ) ;
}
}
void EraseOrphansFor ( NodeId peer )
{
int nErased = 0 ;
map < uint256 , COrphanTx > : : iterator iter = mapOrphanTransactions . begin ( ) ;
while ( iter ! = mapOrphanTransactions . end ( ) )
{
map < uint256 , COrphanTx > : : iterator maybeErase = iter + + ; // increment to avoid iterator becoming invalid
if ( maybeErase - > second . fromPeer = = peer )
{
EraseOrphanTx ( maybeErase - > second . tx . GetHash ( ) ) ;
+ + nErased ;
}
}
if ( nErased > 0 ) LogPrint ( " mempool " , " Erased %d orphan tx from peer %d \n " , nErased , peer ) ;
}
unsigned int LimitOrphanTxSize ( unsigned int nMaxOrphans )
unsigned int LimitOrphanTxSize ( unsigned int nMaxOrphans )
{
{
unsigned int nEvicted = 0 ;
unsigned int nEvicted = 0 ;
@ -514,7 +538,7 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
{
{
// Evict a random orphan:
// Evict a random orphan:
uint256 randomhash = GetRandHash ( ) ;
uint256 randomhash = GetRandHash ( ) ;
map < uint256 , CTransaction > : : iterator it = mapOrphanTransactions . lower_bound ( randomhash ) ;
map < uint256 , COrphanTx > : : 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 ) ;
@ -3777,6 +3801,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
mempool . mapTx . size ( ) ) ;
mempool . mapTx . size ( ) ) ;
// Recursively process any orphan transactions that depended on this one
// Recursively process any orphan transactions that depended on this one
set < NodeId > setMisbehaving ;
for ( unsigned int i = 0 ; i < vWorkQueue . size ( ) ; i + + )
for ( unsigned int i = 0 ; i < vWorkQueue . size ( ) ; i + + )
{
{
map < uint256 , set < uint256 > > : : iterator itByPrev = mapOrphanTransactionsByPrev . find ( vWorkQueue [ i ] ) ;
map < uint256 , set < uint256 > > : : iterator itByPrev = mapOrphanTransactionsByPrev . find ( vWorkQueue [ i ] ) ;
@ -3787,25 +3812,36 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
+ + mi )
+ + mi )
{
{
const uint256 & orphanHash = * mi ;
const uint256 & orphanHash = * mi ;
const CTransaction & orphanTx = mapOrphanTransactions [ orphanHash ] ;
const CTransaction & orphanTx = mapOrphanTransactions [ orphanHash ] . tx ;
NodeId fromPeer = mapOrphanTransactions [ orphanHash ] . fromPeer ;
bool fMissingInputs2 = false ;
bool fMissingInputs2 = false ;
// Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan
// 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
// resolution (that is, feeding people an invalid transaction based on LegitTxX in order to get
// anyone relaying LegitTxX banned)
// anyone relaying LegitTxX banned)
CValidationState stateDummy ;
CValidationState stateDummy ;
vEraseQueue . push_back ( orphanHash ) ;
if ( setMisbehaving . count ( fromPeer ) )
continue ;
if ( AcceptToMemoryPool ( mempool , stateDummy , orphanTx , true , & fMissingInputs2 ) )
if ( AcceptToMemoryPool ( mempool , stateDummy , orphanTx , true , & fMissingInputs2 ) )
{
{
LogPrint ( " mempool " , " accepted orphan tx %s \n " , orphanHash . ToString ( ) ) ;
LogPrint ( " mempool " , " accepted orphan tx %s \n " , orphanHash . ToString ( ) ) ;
RelayTransaction ( orphanTx ) ;
RelayTransaction ( orphanTx ) ;
mapAlreadyAskedFor . erase ( CInv ( MSG_TX , orphanHash ) ) ;
mapAlreadyAskedFor . erase ( CInv ( MSG_TX , orphanHash ) ) ;
vWorkQueue . push_back ( orphanHash ) ;
vWorkQueue . push_back ( orphanHash ) ;
vEraseQueue . push_back ( orphanHash ) ;
}
}
else if ( ! fMissingInputs2 )
else if ( ! fMissingInputs2 )
{
{
// invalid or too-little-fee orphan
int nDos = 0 ;
vEraseQueue . push_back ( orphanHash ) ;
if ( stateDummy . IsInvalid ( nDos ) & & nDos > 0 )
{
// Punish peer that gave us an invalid orphan tx
Misbehaving ( fromPeer , nDos ) ;
setMisbehaving . insert ( fromPeer ) ;
LogPrint ( " mempool " , " invalid orphan tx %s \n " , orphanHash . ToString ( ) ) ;
}
// too-little-fee orphan
LogPrint ( " mempool " , " removed orphan tx %s \n " , orphanHash . ToString ( ) ) ;
LogPrint ( " mempool " , " removed orphan tx %s \n " , orphanHash . ToString ( ) ) ;
}
}
mempool . check ( pcoinsTip ) ;
mempool . check ( pcoinsTip ) ;
@ -3817,10 +3853,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
}
else if ( fMissingInputs )
else if ( fMissingInputs )
{
{
AddOrphanTx ( tx ) ;
AddOrphanTx ( tx , pfrom - > GetId ( ) ) ;
// 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 nMaxOrphanTx = ( unsigned int ) std : : max ( ( int64_t ) 0 , GetArg ( " -maxorphantx " , DEFAULT_MAX_ORPHAN_TRANSACTIONS ) ) ;
unsigned int nEvicted = LimitOrphanTxSize ( nMaxOrphanTx ) ;
if ( nEvicted > 0 )
if ( nEvicted > 0 )
LogPrint ( " mempool " , " mapOrphan overflow, removed %u tx \n " , nEvicted ) ;
LogPrint ( " mempool " , " mapOrphan overflow, removed %u tx \n " , nEvicted ) ;
} else if ( pfrom - > fWhitelisted ) {
} else if ( pfrom - > fWhitelisted ) {
@ -4324,7 +4361,9 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
if ( pto - > addr . IsLocal ( ) )
if ( pto - > addr . IsLocal ( ) )
LogPrintf ( " Warning: not banning local peer %s! \n " , pto - > addr . ToString ( ) ) ;
LogPrintf ( " Warning: not banning local peer %s! \n " , pto - > addr . ToString ( ) ) ;
else
else
{
CNode : : Ban ( pto - > addr ) ;
CNode : : Ban ( pto - > addr ) ;
}
}
}
state . fShouldBan = false ;
state . fShouldBan = false ;
}
}
@ -4538,5 +4577,6 @@ public:
// orphan transactions
// orphan transactions
mapOrphanTransactions . clear ( ) ;
mapOrphanTransactions . clear ( ) ;
mapOrphanTransactionsByPrev . clear ( ) ;
}
}
} instance_of_cmaincleanup ;
} instance_of_cmaincleanup ;