2012-01-04 23:39:45 +01:00
// Copyright (c) 2012 Pieter Wuille
2018-07-27 00:36:45 +02:00
// Copyright (c) 2012-2018 The Bitcoin Core developers
2014-10-24 06:04:27 +02:00
// Distributed under the MIT software license, see the accompanying
2012-05-18 16:02:28 +02:00
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2012-01-04 23:39:45 +01:00
2017-11-10 01:57:53 +01:00
# include <addrman.h>
2013-04-13 07:13:08 +02:00
2017-11-10 01:57:53 +01:00
# include <hash.h>
# include <serialize.h>
2012-01-04 23:39:45 +01:00
2015-03-08 14:30:05 +01:00
int CAddrInfo : : GetTriedBucket ( const uint256 & nKey ) const
2012-01-04 23:39:45 +01:00
{
2018-05-17 07:50:15 +02:00
uint64_t hash1 = ( CHashWriter ( SER_GETHASH , 0 ) < < nKey < < GetKey ( ) ) . GetCheapHash ( ) ;
uint64_t hash2 = ( CHashWriter ( SER_GETHASH , 0 ) < < nKey < < GetGroup ( ) < < ( hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP ) ) . GetCheapHash ( ) ;
2012-01-04 23:39:45 +01:00
return hash2 % ADDRMAN_TRIED_BUCKET_COUNT ;
}
2015-03-08 14:30:05 +01:00
int CAddrInfo : : GetNewBucket ( const uint256 & nKey , const CNetAddr & src ) const
2012-01-04 23:39:45 +01:00
{
std : : vector < unsigned char > vchSourceGroupKey = src . GetGroup ( ) ;
2018-05-17 07:50:15 +02:00
uint64_t hash1 = ( CHashWriter ( SER_GETHASH , 0 ) < < nKey < < GetGroup ( ) < < vchSourceGroupKey ) . GetCheapHash ( ) ;
uint64_t hash2 = ( CHashWriter ( SER_GETHASH , 0 ) < < nKey < < vchSourceGroupKey < < ( hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP ) ) . GetCheapHash ( ) ;
2012-01-04 23:39:45 +01:00
return hash2 % ADDRMAN_NEW_BUCKET_COUNT ;
}
2015-03-18 17:31:49 +01:00
int CAddrInfo : : GetBucketPosition ( const uint256 & nKey , bool fNew , int nBucket ) const
{
2018-05-17 07:50:15 +02:00
uint64_t hash1 = ( CHashWriter ( SER_GETHASH , 0 ) < < nKey < < ( fNew ? ' N ' : ' K ' ) < < nBucket < < GetKey ( ) ) . GetCheapHash ( ) ;
2015-03-18 17:31:49 +01:00
return hash1 % ADDRMAN_BUCKET_SIZE ;
}
2013-04-13 07:13:08 +02:00
bool CAddrInfo : : IsTerrible ( int64_t nNow ) const
2012-01-04 23:39:45 +01:00
{
2014-10-24 06:04:27 +02:00
if ( nLastTry & & nLastTry > = nNow - 60 ) // never remove things tried in the last minute
2012-01-04 23:39:45 +01:00
return false ;
2014-09-19 19:21:46 +02:00
if ( nTime > nNow + 10 * 60 ) // came in a flying DeLorean
2012-01-04 23:39:45 +01:00
return true ;
2014-09-19 19:21:46 +02:00
if ( nTime = = 0 | | nNow - nTime > ADDRMAN_HORIZON_DAYS * 24 * 60 * 60 ) // not seen in recent history
2012-01-04 23:39:45 +01:00
return true ;
2014-09-19 19:21:46 +02:00
if ( nLastSuccess = = 0 & & nAttempts > = ADDRMAN_RETRIES ) // tried N times and never a success
2012-01-04 23:39:45 +01:00
return true ;
2014-09-19 19:21:46 +02:00
if ( nNow - nLastSuccess > ADDRMAN_MIN_FAIL_DAYS * 24 * 60 * 60 & & nAttempts > = ADDRMAN_MAX_FAILURES ) // N successive failures in the last week
2012-01-04 23:39:45 +01:00
return true ;
return false ;
}
2013-04-13 07:13:08 +02:00
double CAddrInfo : : GetChance ( int64_t nNow ) const
2012-01-04 23:39:45 +01:00
{
double fChance = 1.0 ;
2017-02-03 09:20:54 +01:00
int64_t nSinceLastTry = std : : max < int64_t > ( nNow - nLastTry , 0 ) ;
2012-01-04 23:39:45 +01:00
// deprioritize very recent attempts away
2014-09-19 19:21:46 +02:00
if ( nSinceLastTry < 60 * 10 )
2012-01-04 23:39:45 +01:00
fChance * = 0.01 ;
2015-04-19 20:47:56 +02:00
// deprioritize 66% after each failed attempt, but at most 1/28th to avoid the search taking forever or overly penalizing outages.
2015-06-15 14:45:19 +02:00
fChance * = pow ( 0.66 , std : : min ( nAttempts , 8 ) ) ;
2012-01-04 23:39:45 +01:00
return fChance ;
}
2014-09-19 19:21:46 +02:00
CAddrInfo * CAddrMan : : Find ( const CNetAddr & addr , int * pnId )
2012-01-04 23:39:45 +01:00
{
std : : map < CNetAddr , int > : : iterator it = mapAddr . find ( addr ) ;
if ( it = = mapAddr . end ( ) )
2017-08-07 07:36:37 +02:00
return nullptr ;
2012-01-04 23:39:45 +01:00
if ( pnId )
* pnId = ( * it ) . second ;
std : : map < int , CAddrInfo > : : iterator it2 = mapInfo . find ( ( * it ) . second ) ;
if ( it2 ! = mapInfo . end ( ) )
return & ( * it2 ) . second ;
2017-08-07 07:36:37 +02:00
return nullptr ;
2012-01-04 23:39:45 +01:00
}
2014-09-19 19:21:46 +02:00
CAddrInfo * CAddrMan : : Create ( const CAddress & addr , const CNetAddr & addrSource , int * pnId )
2012-01-04 23:39:45 +01:00
{
int nId = nIdCount + + ;
mapInfo [ nId ] = CAddrInfo ( addr , addrSource ) ;
mapAddr [ addr ] = nId ;
mapInfo [ nId ] . nRandomPos = vRandom . size ( ) ;
vRandom . push_back ( nId ) ;
if ( pnId )
* pnId = nId ;
return & mapInfo [ nId ] ;
}
2012-05-09 03:48:14 +02:00
void CAddrMan : : SwapRandom ( unsigned int nRndPos1 , unsigned int nRndPos2 )
2012-01-04 23:39:45 +01:00
{
if ( nRndPos1 = = nRndPos2 )
return ;
2012-05-05 21:30:38 +02:00
assert ( nRndPos1 < vRandom . size ( ) & & nRndPos2 < vRandom . size ( ) ) ;
2012-01-04 23:39:45 +01:00
int nId1 = vRandom [ nRndPos1 ] ;
int nId2 = vRandom [ nRndPos2 ] ;
2012-05-05 21:30:38 +02:00
assert ( mapInfo . count ( nId1 ) = = 1 ) ;
assert ( mapInfo . count ( nId2 ) = = 1 ) ;
2012-01-04 23:39:45 +01:00
mapInfo [ nId1 ] . nRandomPos = nRndPos2 ;
mapInfo [ nId2 ] . nRandomPos = nRndPos1 ;
vRandom [ nRndPos1 ] = nId2 ;
vRandom [ nRndPos2 ] = nId1 ;
}
2015-03-18 17:31:49 +01:00
void CAddrMan : : Delete ( int nId )
2012-01-04 23:39:45 +01:00
{
2015-03-18 17:31:49 +01:00
assert ( mapInfo . count ( nId ) ! = 0 ) ;
CAddrInfo & info = mapInfo [ nId ] ;
assert ( ! info . fInTried ) ;
assert ( info . nRefCount = = 0 ) ;
2012-01-04 23:39:45 +01:00
2015-03-18 17:31:49 +01:00
SwapRandom ( info . nRandomPos , vRandom . size ( ) - 1 ) ;
vRandom . pop_back ( ) ;
mapAddr . erase ( info ) ;
mapInfo . erase ( nId ) ;
nNew - - ;
2012-01-04 23:39:45 +01:00
}
2015-03-18 17:31:49 +01:00
void CAddrMan : : ClearNew ( int nUBucket , int nUBucketPos )
2012-01-04 23:39:45 +01:00
{
2015-03-18 17:31:49 +01:00
// if there is an entry in the specified bucket, delete it.
if ( vvNew [ nUBucket ] [ nUBucketPos ] ! = - 1 ) {
int nIdDelete = vvNew [ nUBucket ] [ nUBucketPos ] ;
CAddrInfo & infoDelete = mapInfo [ nIdDelete ] ;
assert ( infoDelete . nRefCount > 0 ) ;
infoDelete . nRefCount - - ;
vvNew [ nUBucket ] [ nUBucketPos ] = - 1 ;
if ( infoDelete . nRefCount = = 0 ) {
Delete ( nIdDelete ) ;
2012-01-04 23:39:45 +01:00
}
}
}
2015-03-18 17:31:49 +01:00
void CAddrMan : : MakeTried ( CAddrInfo & info , int nId )
2012-01-04 23:39:45 +01:00
{
// remove the entry from all new buckets
2015-03-18 17:31:49 +01:00
for ( int bucket = 0 ; bucket < ADDRMAN_NEW_BUCKET_COUNT ; bucket + + ) {
int pos = info . GetBucketPosition ( nKey , true , bucket ) ;
if ( vvNew [ bucket ] [ pos ] = = nId ) {
vvNew [ bucket ] [ pos ] = - 1 ;
2012-01-04 23:39:45 +01:00
info . nRefCount - - ;
2015-03-18 17:31:49 +01:00
}
2012-01-04 23:39:45 +01:00
}
nNew - - ;
2012-05-05 21:30:38 +02:00
assert ( info . nRefCount = = 0 ) ;
2014-10-24 06:04:27 +02:00
// which tried bucket to move the entry to
2012-01-04 23:39:45 +01:00
int nKBucket = info . GetTriedBucket ( nKey ) ;
2015-03-18 17:31:49 +01:00
int nKBucketPos = info . GetBucketPosition ( nKey , false , nKBucket ) ;
// first make space to add it (the existing tried entry there is moved to new, deleting whatever is there).
if ( vvTried [ nKBucket ] [ nKBucketPos ] ! = - 1 ) {
// find an item to evict
int nIdEvict = vvTried [ nKBucket ] [ nKBucketPos ] ;
assert ( mapInfo . count ( nIdEvict ) = = 1 ) ;
CAddrInfo & infoOld = mapInfo [ nIdEvict ] ;
// Remove the to-be-evicted item from the tried set.
infoOld . fInTried = false ;
vvTried [ nKBucket ] [ nKBucketPos ] = - 1 ;
nTried - - ;
// find which new bucket it belongs to
int nUBucket = infoOld . GetNewBucket ( nKey ) ;
int nUBucketPos = infoOld . GetBucketPosition ( nKey , true , nUBucket ) ;
ClearNew ( nUBucket , nUBucketPos ) ;
assert ( vvNew [ nUBucket ] [ nUBucketPos ] = = - 1 ) ;
// Enter it into the new set again.
infoOld . nRefCount = 1 ;
vvNew [ nUBucket ] [ nUBucketPos ] = nIdEvict ;
nNew + + ;
2012-01-04 23:39:45 +01:00
}
2015-03-18 17:31:49 +01:00
assert ( vvTried [ nKBucket ] [ nKBucketPos ] = = - 1 ) ;
2012-01-04 23:39:45 +01:00
2015-03-18 17:31:49 +01:00
vvTried [ nKBucket ] [ nKBucketPos ] = nId ;
nTried + + ;
2012-01-04 23:39:45 +01:00
info . fInTried = true ;
}
2016-10-27 19:55:39 +02:00
void CAddrMan : : Good_ ( const CService & addr , bool test_before_evict , int64_t nTime )
2012-01-04 23:39:45 +01:00
{
int nId ;
2015-04-19 22:39:38 +02:00
nLastGood = nTime ;
2014-09-19 19:21:46 +02:00
CAddrInfo * pinfo = Find ( addr , & nId ) ;
2012-01-04 23:39:45 +01:00
// if not found, bail out
if ( ! pinfo )
return ;
2014-09-19 19:21:46 +02:00
CAddrInfo & info = * pinfo ;
2012-01-04 23:39:45 +01:00
// check whether we are talking about the exact same CService (including same port)
if ( info ! = addr )
return ;
// update info
info . nLastSuccess = nTime ;
info . nLastTry = nTime ;
info . nAttempts = 0 ;
2015-03-05 13:01:22 +01:00
// nTime is not updated here, to avoid leaking information about
// currently-connected peers.
2012-01-04 23:39:45 +01:00
// if it is already in the tried set, don't do anything else
if ( info . fInTried )
return ;
// find a bucket it is in now
2018-10-31 21:56:19 +01:00
int nRnd = insecure_rand . randrange ( ADDRMAN_NEW_BUCKET_COUNT ) ;
2012-01-04 23:39:45 +01:00
int nUBucket = - 1 ;
2015-03-18 17:31:49 +01:00
for ( unsigned int n = 0 ; n < ADDRMAN_NEW_BUCKET_COUNT ; n + + ) {
int nB = ( n + nRnd ) % ADDRMAN_NEW_BUCKET_COUNT ;
int nBpos = info . GetBucketPosition ( nKey , true , nB ) ;
if ( vvNew [ nB ] [ nBpos ] = = nId ) {
2012-01-04 23:39:45 +01:00
nUBucket = nB ;
break ;
}
}
// if no bucket is found, something bad happened;
// TODO: maybe re-add the node, but for now, just bail out
2014-09-19 19:21:46 +02:00
if ( nUBucket = = - 1 )
return ;
2012-01-04 23:39:45 +01:00
2016-10-27 19:55:39 +02:00
// which tried bucket to move the entry to
int tried_bucket = info . GetTriedBucket ( nKey ) ;
int tried_bucket_pos = info . GetBucketPosition ( nKey , false , tried_bucket ) ;
// Will moving this address into tried evict another entry?
if ( test_before_evict & & ( vvTried [ tried_bucket ] [ tried_bucket_pos ] ! = - 1 ) ) {
2019-02-26 20:59:30 +01:00
// Output the entry we'd be colliding with, for debugging purposes
auto colliding_entry = mapInfo . find ( vvTried [ tried_bucket ] [ tried_bucket_pos ] ) ;
LogPrint ( BCLog : : ADDRMAN , " Collision inserting element into tried table (%s), moving %s to m_tried_collisions=%d \n " , colliding_entry ! = mapInfo . end ( ) ? colliding_entry - > second . ToString ( ) : " " , addr . ToString ( ) , m_tried_collisions . size ( ) ) ;
2016-10-27 19:55:39 +02:00
if ( m_tried_collisions . size ( ) < ADDRMAN_SET_TRIED_COLLISION_SIZE ) {
m_tried_collisions . insert ( nId ) ;
}
} else {
LogPrint ( BCLog : : ADDRMAN , " Moving %s to tried \n " , addr . ToString ( ) ) ;
2012-01-04 23:39:45 +01:00
2016-10-27 19:55:39 +02:00
// move nId to the tried tables
MakeTried ( info , nId ) ;
}
2012-01-04 23:39:45 +01:00
}
2014-09-19 19:21:46 +02:00
bool CAddrMan : : Add_ ( const CAddress & addr , const CNetAddr & source , int64_t nTimePenalty )
2012-01-04 23:39:45 +01:00
{
if ( ! addr . IsRoutable ( ) )
return false ;
bool fNew = false ;
int nId ;
2014-09-19 19:21:46 +02:00
CAddrInfo * pinfo = Find ( addr , & nId ) ;
2012-01-04 23:39:45 +01:00
2017-01-18 16:15:37 +01:00
// Do not set a penalty for a source's self-announcement
2016-09-03 12:24:37 +02:00
if ( addr = = source ) {
nTimePenalty = 0 ;
}
2014-09-19 19:21:46 +02:00
if ( pinfo ) {
2012-01-04 23:39:45 +01:00
// periodically update nTime
bool fCurrentlyOnline = ( GetAdjustedTime ( ) - addr . nTime < 24 * 60 * 60 ) ;
2013-04-13 07:13:08 +02:00
int64_t nUpdateInterval = ( fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60 ) ;
2012-01-04 23:39:45 +01:00
if ( addr . nTime & & ( ! pinfo - > nTime | | pinfo - > nTime < addr . nTime - nUpdateInterval - nTimePenalty ) )
2015-06-15 14:45:19 +02:00
pinfo - > nTime = std : : max ( ( int64_t ) 0 , addr . nTime - nTimePenalty ) ;
2012-01-04 23:39:45 +01:00
// add services
2016-06-08 19:12:22 +02:00
pinfo - > nServices = ServiceFlags ( pinfo - > nServices | addr . nServices ) ;
2012-01-04 23:39:45 +01:00
// do not update if no new information is present
2012-04-15 13:03:28 +02:00
if ( ! addr . nTime | | ( pinfo - > nTime & & addr . nTime < = pinfo - > nTime ) )
2012-01-04 23:39:45 +01:00
return false ;
// do not update if the entry was already in the "tried" table
if ( pinfo - > fInTried )
return false ;
// do not update if the max reference count is reached
if ( pinfo - > nRefCount = = ADDRMAN_NEW_BUCKETS_PER_ADDRESS )
return false ;
// stochastic test: previous nRefCount == N: 2^N times harder to increase it
int nFactor = 1 ;
2014-09-19 19:21:46 +02:00
for ( int n = 0 ; n < pinfo - > nRefCount ; n + + )
2012-01-04 23:39:45 +01:00
nFactor * = 2 ;
2018-10-31 21:56:19 +01:00
if ( nFactor > 1 & & ( insecure_rand . randrange ( nFactor ) ! = 0 ) )
2012-01-04 23:39:45 +01:00
return false ;
} else {
pinfo = Create ( addr , source , & nId ) ;
2015-06-15 14:45:19 +02:00
pinfo - > nTime = std : : max ( ( int64_t ) 0 , ( int64_t ) pinfo - > nTime - nTimePenalty ) ;
2012-01-04 23:39:45 +01:00
nNew + + ;
fNew = true ;
}
int nUBucket = pinfo - > GetNewBucket ( nKey , source ) ;
2015-03-18 17:31:49 +01:00
int nUBucketPos = pinfo - > GetBucketPosition ( nKey , true , nUBucket ) ;
if ( vvNew [ nUBucket ] [ nUBucketPos ] ! = nId ) {
bool fInsert = vvNew [ nUBucket ] [ nUBucketPos ] = = - 1 ;
if ( ! fInsert ) {
CAddrInfo & infoExisting = mapInfo [ vvNew [ nUBucket ] [ nUBucketPos ] ] ;
if ( infoExisting . IsTerrible ( ) | | ( infoExisting . nRefCount > 1 & & pinfo - > nRefCount = = 0 ) ) {
// Overwrite the existing new table entry.
fInsert = true ;
}
}
if ( fInsert ) {
ClearNew ( nUBucket , nUBucketPos ) ;
pinfo - > nRefCount + + ;
vvNew [ nUBucket ] [ nUBucketPos ] = nId ;
} else {
if ( pinfo - > nRefCount = = 0 ) {
Delete ( nId ) ;
}
}
2012-01-04 23:39:45 +01:00
}
return fNew ;
}
2015-04-19 21:34:43 +02:00
void CAddrMan : : Attempt_ ( const CService & addr , bool fCountFailure , int64_t nTime )
2012-01-04 23:39:45 +01:00
{
2014-09-19 19:21:46 +02:00
CAddrInfo * pinfo = Find ( addr ) ;
2012-01-04 23:39:45 +01:00
// if not found, bail out
if ( ! pinfo )
return ;
2014-09-19 19:21:46 +02:00
CAddrInfo & info = * pinfo ;
2012-01-04 23:39:45 +01:00
// check whether we are talking about the exact same CService (including same port)
if ( info ! = addr )
return ;
// update info
info . nLastTry = nTime ;
2015-04-19 22:39:38 +02:00
if ( fCountFailure & & info . nLastCountAttempt < nLastGood ) {
info . nLastCountAttempt = nTime ;
info . nAttempts + + ;
}
2012-01-04 23:39:45 +01:00
}
2015-09-22 21:24:16 +02:00
CAddrInfo CAddrMan : : Select_ ( bool newOnly )
2012-01-04 23:39:45 +01:00
{
if ( size ( ) = = 0 )
2015-04-19 20:10:13 +02:00
return CAddrInfo ( ) ;
2012-01-04 23:39:45 +01:00
2015-09-22 21:24:16 +02:00
if ( newOnly & & nNew = = 0 )
return CAddrInfo ( ) ;
2015-03-19 17:51:59 +01:00
// Use a 50% chance for choosing between tried and new table entries.
2015-09-22 21:24:16 +02:00
if ( ! newOnly & &
2018-10-31 21:56:19 +01:00
( nTried > 0 & & ( nNew = = 0 | | insecure_rand . randbool ( ) = = 0 ) ) ) {
2012-01-04 23:39:45 +01:00
// use a tried node
double fChanceFactor = 1.0 ;
2014-09-19 19:21:46 +02:00
while ( 1 ) {
2018-10-31 21:56:19 +01:00
int nKBucket = insecure_rand . randrange ( ADDRMAN_TRIED_BUCKET_COUNT ) ;
int nKBucketPos = insecure_rand . randrange ( ADDRMAN_BUCKET_SIZE ) ;
2015-08-06 19:49:19 +02:00
while ( vvTried [ nKBucket ] [ nKBucketPos ] = = - 1 ) {
2017-02-16 02:45:22 +01:00
nKBucket = ( nKBucket + insecure_rand . randbits ( ADDRMAN_TRIED_BUCKET_COUNT_LOG2 ) ) % ADDRMAN_TRIED_BUCKET_COUNT ;
nKBucketPos = ( nKBucketPos + insecure_rand . randbits ( ADDRMAN_BUCKET_SIZE_LOG2 ) ) % ADDRMAN_BUCKET_SIZE ;
2015-08-06 19:49:19 +02:00
}
2015-03-18 17:31:49 +01:00
int nId = vvTried [ nKBucket ] [ nKBucketPos ] ;
assert ( mapInfo . count ( nId ) = = 1 ) ;
CAddrInfo & info = mapInfo [ nId ] ;
2018-10-31 21:56:19 +01:00
if ( insecure_rand . randbits ( 30 ) < fChanceFactor * info . GetChance ( ) * ( 1 < < 30 ) )
2012-01-04 23:39:45 +01:00
return info ;
fChanceFactor * = 1.2 ;
}
} else {
2012-08-18 16:45:24 +02:00
// use a new node
2012-01-04 23:39:45 +01:00
double fChanceFactor = 1.0 ;
2014-09-19 19:21:46 +02:00
while ( 1 ) {
2018-10-31 21:56:19 +01:00
int nUBucket = insecure_rand . randrange ( ADDRMAN_NEW_BUCKET_COUNT ) ;
int nUBucketPos = insecure_rand . randrange ( ADDRMAN_BUCKET_SIZE ) ;
2015-08-06 19:49:19 +02:00
while ( vvNew [ nUBucket ] [ nUBucketPos ] = = - 1 ) {
2017-02-16 02:45:22 +01:00
nUBucket = ( nUBucket + insecure_rand . randbits ( ADDRMAN_NEW_BUCKET_COUNT_LOG2 ) ) % ADDRMAN_NEW_BUCKET_COUNT ;
nUBucketPos = ( nUBucketPos + insecure_rand . randbits ( ADDRMAN_BUCKET_SIZE_LOG2 ) ) % ADDRMAN_BUCKET_SIZE ;
2015-08-06 19:49:19 +02:00
}
2015-03-18 17:31:49 +01:00
int nId = vvNew [ nUBucket ] [ nUBucketPos ] ;
assert ( mapInfo . count ( nId ) = = 1 ) ;
CAddrInfo & info = mapInfo [ nId ] ;
2018-10-31 21:56:19 +01:00
if ( insecure_rand . randbits ( 30 ) < fChanceFactor * info . GetChance ( ) * ( 1 < < 30 ) )
2012-01-04 23:39:45 +01:00
return info ;
fChanceFactor * = 1.2 ;
}
}
}
# ifdef DEBUG_ADDRMAN
int CAddrMan : : Check_ ( )
{
std : : set < int > setTried ;
std : : map < int , int > mapNew ;
2017-10-30 10:29:27 +01:00
if ( vRandom . size ( ) ! = ( size_t ) ( nTried + nNew ) )
2014-09-19 19:21:46 +02:00
return - 7 ;
2012-01-04 23:39:45 +01:00
2017-06-04 22:02:43 +02:00
for ( const auto & entry : mapInfo ) {
int n = entry . first ;
const CAddrInfo & info = entry . second ;
2014-09-19 19:21:46 +02:00
if ( info . fInTried ) {
if ( ! info . nLastSuccess )
return - 1 ;
if ( info . nRefCount )
return - 2 ;
2012-01-04 23:39:45 +01:00
setTried . insert ( n ) ;
} else {
2014-09-19 19:21:46 +02:00
if ( info . nRefCount < 0 | | info . nRefCount > ADDRMAN_NEW_BUCKETS_PER_ADDRESS )
return - 3 ;
if ( ! info . nRefCount )
return - 4 ;
2012-01-04 23:39:45 +01:00
mapNew [ n ] = info . nRefCount ;
}
2014-09-19 19:21:46 +02:00
if ( mapAddr [ info ] ! = n )
return - 5 ;
2017-10-30 10:29:27 +01:00
if ( info . nRandomPos < 0 | | ( size_t ) info . nRandomPos > = vRandom . size ( ) | | vRandom [ info . nRandomPos ] ! = n )
2014-09-19 19:21:46 +02:00
return - 14 ;
if ( info . nLastTry < 0 )
return - 6 ;
if ( info . nLastSuccess < 0 )
return - 8 ;
2012-01-04 23:39:45 +01:00
}
2017-10-30 10:29:27 +01:00
if ( setTried . size ( ) ! = ( size_t ) nTried )
2014-09-19 19:21:46 +02:00
return - 9 ;
2017-10-30 10:29:27 +01:00
if ( mapNew . size ( ) ! = ( size_t ) nNew )
2014-09-19 19:21:46 +02:00
return - 10 ;
2012-01-04 23:39:45 +01:00
2015-03-18 17:31:49 +01:00
for ( int n = 0 ; n < ADDRMAN_TRIED_BUCKET_COUNT ; n + + ) {
for ( int i = 0 ; i < ADDRMAN_BUCKET_SIZE ; i + + ) {
if ( vvTried [ n ] [ i ] ! = - 1 ) {
if ( ! setTried . count ( vvTried [ n ] [ i ] ) )
return - 11 ;
if ( mapInfo [ vvTried [ n ] [ i ] ] . GetTriedBucket ( nKey ) ! = n )
return - 17 ;
if ( mapInfo [ vvTried [ n ] [ i ] ] . GetBucketPosition ( nKey , false , n ) ! = i )
return - 18 ;
setTried . erase ( vvTried [ n ] [ i ] ) ;
}
2012-01-04 23:39:45 +01:00
}
}
2015-03-18 17:31:49 +01:00
for ( int n = 0 ; n < ADDRMAN_NEW_BUCKET_COUNT ; n + + ) {
for ( int i = 0 ; i < ADDRMAN_BUCKET_SIZE ; i + + ) {
if ( vvNew [ n ] [ i ] ! = - 1 ) {
if ( ! mapNew . count ( vvNew [ n ] [ i ] ) )
return - 12 ;
if ( mapInfo [ vvNew [ n ] [ i ] ] . GetBucketPosition ( nKey , true , n ) ! = i )
return - 19 ;
if ( - - mapNew [ vvNew [ n ] [ i ] ] = = 0 )
mapNew . erase ( vvNew [ n ] [ i ] ) ;
}
2012-01-04 23:39:45 +01:00
}
}
2014-09-19 19:21:46 +02:00
if ( setTried . size ( ) )
return - 13 ;
if ( mapNew . size ( ) )
return - 15 ;
2015-03-08 14:30:05 +01:00
if ( nKey . IsNull ( ) )
return - 16 ;
2012-01-04 23:39:45 +01:00
return 0 ;
}
# endif
2014-09-19 19:21:46 +02:00
void CAddrMan : : GetAddr_ ( std : : vector < CAddress > & vAddr )
2012-01-04 23:39:45 +01:00
{
2014-08-18 22:50:39 +02:00
unsigned int nNodes = ADDRMAN_GETADDR_MAX_PCT * vRandom . size ( ) / 100 ;
2012-01-04 23:39:45 +01:00
if ( nNodes > ADDRMAN_GETADDR_MAX )
nNodes = ADDRMAN_GETADDR_MAX ;
2014-08-18 22:50:39 +02:00
// gather a list of random nodes, skipping those of low quality
2014-09-19 19:21:46 +02:00
for ( unsigned int n = 0 ; n < vRandom . size ( ) ; n + + ) {
2014-08-18 22:50:39 +02:00
if ( vAddr . size ( ) > = nNodes )
break ;
2018-10-31 21:56:19 +01:00
int nRndPos = insecure_rand . randrange ( vRandom . size ( ) - n ) + n ;
2012-01-04 23:39:45 +01:00
SwapRandom ( n , nRndPos ) ;
2012-05-05 21:30:38 +02:00
assert ( mapInfo . count ( vRandom [ n ] ) = = 1 ) ;
2014-08-18 22:50:39 +02:00
const CAddrInfo & ai = mapInfo [ vRandom [ n ] ] ;
if ( ! ai . IsTerrible ( ) )
vAddr . push_back ( ai ) ;
2012-01-04 23:39:45 +01:00
}
}
2014-09-19 19:21:46 +02:00
void CAddrMan : : Connected_ ( const CService & addr , int64_t nTime )
2012-01-04 23:39:45 +01:00
{
2014-09-19 19:21:46 +02:00
CAddrInfo * pinfo = Find ( addr ) ;
2012-01-04 23:39:45 +01:00
// if not found, bail out
if ( ! pinfo )
return ;
2014-09-19 19:21:46 +02:00
CAddrInfo & info = * pinfo ;
2012-01-04 23:39:45 +01:00
// check whether we are talking about the exact same CService (including same port)
if ( info ! = addr )
return ;
// update info
2013-04-13 07:13:08 +02:00
int64_t nUpdateInterval = 20 * 60 ;
2012-01-04 23:39:45 +01:00
if ( nTime - info . nTime > nUpdateInterval )
info . nTime = nTime ;
}
2015-12-13 04:34:08 +01:00
2016-06-08 19:12:22 +02:00
void CAddrMan : : SetServices_ ( const CService & addr , ServiceFlags nServices )
2016-03-26 18:58:00 +01:00
{
CAddrInfo * pinfo = Find ( addr ) ;
// if not found, bail out
if ( ! pinfo )
return ;
CAddrInfo & info = * pinfo ;
// check whether we are talking about the exact same CService (including same port)
if ( info ! = addr )
return ;
// update info
info . nServices = nServices ;
}
2016-10-27 19:55:39 +02:00
void CAddrMan : : ResolveCollisions_ ( )
{
for ( std : : set < int > : : iterator it = m_tried_collisions . begin ( ) ; it ! = m_tried_collisions . end ( ) ; ) {
int id_new = * it ;
bool erase_collision = false ;
// If id_new not found in mapInfo remove it from m_tried_collisions
if ( mapInfo . count ( id_new ) ! = 1 ) {
erase_collision = true ;
} else {
CAddrInfo & info_new = mapInfo [ id_new ] ;
// Which tried bucket to move the entry to.
int tried_bucket = info_new . GetTriedBucket ( nKey ) ;
int tried_bucket_pos = info_new . GetBucketPosition ( nKey , false , tried_bucket ) ;
if ( ! info_new . IsValid ( ) ) { // id_new may no longer map to a valid address
erase_collision = true ;
} else if ( vvTried [ tried_bucket ] [ tried_bucket_pos ] ! = - 1 ) { // The position in the tried bucket is not empty
// Get the to-be-evicted address that is being tested
int id_old = vvTried [ tried_bucket ] [ tried_bucket_pos ] ;
CAddrInfo & info_old = mapInfo [ id_old ] ;
// Has successfully connected in last X hours
if ( GetAdjustedTime ( ) - info_old . nLastSuccess < ADDRMAN_REPLACEMENT_HOURS * ( 60 * 60 ) ) {
erase_collision = true ;
} else if ( GetAdjustedTime ( ) - info_old . nLastTry < ADDRMAN_REPLACEMENT_HOURS * ( 60 * 60 ) ) { // attempted to connect and failed in last X hours
// Give address at least 60 seconds to successfully connect
if ( GetAdjustedTime ( ) - info_old . nLastTry > 60 ) {
2019-03-01 22:15:50 +01:00
LogPrint ( BCLog : : ADDRMAN , " Replacing %s with %s in tried table \n " , info_old . ToString ( ) , info_new . ToString ( ) ) ;
2016-10-27 19:55:39 +02:00
// Replaces an existing address already in the tried table with the new address
Good_ ( info_new , false , GetAdjustedTime ( ) ) ;
erase_collision = true ;
}
2019-02-26 22:34:26 +01:00
} else if ( GetAdjustedTime ( ) - info_new . nLastSuccess > ADDRMAN_TEST_WINDOW ) {
// If the collision hasn't resolved in some reasonable amount of time,
// just evict the old entry -- we must not be able to
// connect to it for some reason.
2019-03-01 22:15:50 +01:00
LogPrint ( BCLog : : ADDRMAN , " Unable to test; replacing %s with %s in tried table anyway \n " , info_old . ToString ( ) , info_new . ToString ( ) ) ;
2019-02-26 22:34:26 +01:00
Good_ ( info_new , false , GetAdjustedTime ( ) ) ;
erase_collision = true ;
2016-10-27 19:55:39 +02:00
}
} else { // Collision is not actually a collision anymore
Good_ ( info_new , false , GetAdjustedTime ( ) ) ;
erase_collision = true ;
}
}
if ( erase_collision ) {
m_tried_collisions . erase ( it + + ) ;
} else {
it + + ;
}
}
}
CAddrInfo CAddrMan : : SelectTriedCollision_ ( )
{
if ( m_tried_collisions . size ( ) = = 0 ) return CAddrInfo ( ) ;
std : : set < int > : : iterator it = m_tried_collisions . begin ( ) ;
// Selects a random element from m_tried_collisions
2018-10-31 21:56:19 +01:00
std : : advance ( it , insecure_rand . randrange ( m_tried_collisions . size ( ) ) ) ;
2016-10-27 19:55:39 +02:00
int id_new = * it ;
// If id_new not found in mapInfo remove it from m_tried_collisions
if ( mapInfo . count ( id_new ) ! = 1 ) {
m_tried_collisions . erase ( it ) ;
return CAddrInfo ( ) ;
}
CAddrInfo & newInfo = mapInfo [ id_new ] ;
// which tried bucket to move the entry to
int tried_bucket = newInfo . GetTriedBucket ( nKey ) ;
int tried_bucket_pos = newInfo . GetBucketPosition ( nKey , false , tried_bucket ) ;
int id_old = vvTried [ tried_bucket ] [ tried_bucket_pos ] ;
return mapInfo [ id_old ] ;
}