@ -162,6 +162,29 @@ namespace {
*/
*/
map < uint256 , NodeId > mapBlockSource ;
map < uint256 , NodeId > mapBlockSource ;
/**
* Filter for transactions that were recently rejected by
* AcceptToMemoryPool . These are not rerequested until the chain tip
* changes , at which point the entire filter is reset . Protected by
* cs_main .
*
* Without this filter we ' d be re - requesting txs from each of our peers ,
* increasing bandwidth consumption considerably . For instance , with 100
* peers , half of which relay a tx we don ' t accept , that might be a 50 x
* bandwidth increase . A flooding attacker attempting to roll - over the
* filter using minimum - sized , 60 byte , transactions might manage to send
* 1000 / sec if we have fast peers , so we pick 120 , 000 to give our peers a
* two minute window to send invs to us .
*
* Decreasing the false positive rate is fairly cheap , so we pick one in a
* million to make it highly unlikely for users to have issues with this
* filter .
*
* Memory used : 1.7 MB
*/
boost : : scoped_ptr < CRollingBloomFilter > recentRejects ;
uint256 hashRecentRejectsChainTip ;
/** Blocks that are in flight, and that are in the queue to be downloaded. Protected by cs_main. */
/** Blocks that are in flight, and that are in the queue to be downloaded. Protected by cs_main. */
struct QueuedBlock {
struct QueuedBlock {
uint256 hash ;
uint256 hash ;
@ -3248,6 +3271,7 @@ void UnloadBlockIndex()
setDirtyBlockIndex . clear ( ) ;
setDirtyBlockIndex . clear ( ) ;
setDirtyFileInfo . clear ( ) ;
setDirtyFileInfo . clear ( ) ;
mapNodeState . clear ( ) ;
mapNodeState . clear ( ) ;
recentRejects . reset ( NULL ) ;
BOOST_FOREACH ( BlockMap : : value_type & entry , mapBlockIndex ) {
BOOST_FOREACH ( BlockMap : : value_type & entry , mapBlockIndex ) {
delete entry . second ;
delete entry . second ;
@ -3268,6 +3292,10 @@ bool LoadBlockIndex()
bool InitBlockIndex ( ) {
bool InitBlockIndex ( ) {
const CChainParams & chainparams = Params ( ) ;
const CChainParams & chainparams = Params ( ) ;
LOCK ( cs_main ) ;
LOCK ( cs_main ) ;
// Initialize global variables that cannot be constructed at startup.
recentRejects . reset ( new CRollingBloomFilter ( 120000 , 0.000001 ) ) ;
// Check whether we're already initialized
// Check whether we're already initialized
if ( chainActive . Genesis ( ) ! = NULL )
if ( chainActive . Genesis ( ) ! = NULL )
return true ;
return true ;
@ -3670,9 +3698,20 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
{
case MSG_TX :
case MSG_TX :
{
{
bool txInMap = false ;
assert ( recentRejects ) ;
txInMap = mempool . exists ( inv . hash ) ;
if ( chainActive . Tip ( ) - > GetBlockHash ( ) ! = hashRecentRejectsChainTip )
return txInMap | | mapOrphanTransactions . count ( inv . hash ) | |
{
// If the chain tip has changed previously rejected transactions
// might be now valid, e.g. due to a nLockTime'd tx becoming valid,
// or a double-spend. Reset the rejects filter and give those
// txs a second chance.
hashRecentRejectsChainTip = chainActive . Tip ( ) - > GetBlockHash ( ) ;
recentRejects - > reset ( ) ;
}
return recentRejects - > contains ( inv . hash ) | |
mempool . exists ( inv . hash ) | |
mapOrphanTransactions . count ( inv . hash ) | |
pcoinsTip - > HaveCoins ( inv . hash ) ;
pcoinsTip - > HaveCoins ( inv . hash ) ;
}
}
case MSG_BLOCK :
case MSG_BLOCK :
@ -4273,6 +4312,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Probably non-standard or insufficient fee/priority
// Probably non-standard or insufficient fee/priority
LogPrint ( " mempool " , " removed orphan tx %s \n " , orphanHash . ToString ( ) ) ;
LogPrint ( " mempool " , " removed orphan tx %s \n " , orphanHash . ToString ( ) ) ;
vEraseQueue . push_back ( orphanHash ) ;
vEraseQueue . push_back ( orphanHash ) ;
assert ( recentRejects ) ;
recentRejects - > insert ( orphanHash ) ;
}
}
mempool . check ( pcoinsTip ) ;
mempool . check ( pcoinsTip ) ;
}
}
@ -4290,12 +4331,25 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
unsigned int nEvicted = LimitOrphanTxSize ( nMaxOrphanTx ) ;
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 {
// AcceptToMemoryPool() returned false, possibly because the tx is
// already in the mempool; if the tx isn't in the mempool that
// means it was rejected and we shouldn't ask for it again.
if ( ! mempool . exists ( tx . GetHash ( ) ) ) {
assert ( recentRejects ) ;
recentRejects - > insert ( tx . GetHash ( ) ) ;
}
if ( pfrom - > fWhitelisted ) {
// Always relay transactions received from whitelisted peers, even
// Always relay transactions received from whitelisted peers, even
// if they are already in the mempool (allowing the node to function
// if they were rejected from the mempool, allowing the node to
// as a gateway for nodes hidden behind it).
// function as a gateway for nodes hidden behind it.
//
// FIXME: This includes invalid transactions, which means a
// whitelisted peer could get us banned! We may want to change
// that.
RelayTransaction ( tx ) ;
RelayTransaction ( tx ) ;
}
}
}
int nDoS = 0 ;
int nDoS = 0 ;
if ( state . IsInvalid ( nDoS ) )
if ( state . IsInvalid ( nDoS ) )
{
{
@ -4797,7 +4851,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
{
{
// Periodically clear addrKnown to allow refresh broadcasts
// Periodically clear addrKnown to allow refresh broadcasts
if ( nLastRebroadcast )
if ( nLastRebroadcast )
pnode - > addrKnown . clea r( ) ;
pnode - > addrKnown . reset ( ) ;
// Rebroadcast our address
// Rebroadcast our address
AdvertizeLocal ( pnode ) ;
AdvertizeLocal ( pnode ) ;