2012-01-04 19:39:45 -03:00
// Copyright (c) 2012 Pieter Wuille
2020-04-16 13:14:08 -04:00
// Copyright (c) 2012-2020 The Bitcoin Core developers
2014-10-24 01:04:27 -03:00
// Distributed under the MIT software license, see the accompanying
2012-05-18 10:02:28 -04:00
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2012-01-04 19:39:45 -03:00
2017-11-09 21:57:53 -03:00
# include <addrman.h>
2021-09-01 14:21:29 -04:00
# include <addrman_impl.h>
2013-04-13 02:13:08 -03:00
2021-09-07 05:48:45 -03:00
# include <clientversion.h>
2017-11-09 21:57:53 -03:00
# include <hash.h>
2020-01-10 15:08:15 -03:00
# include <logging.h>
2021-05-02 12:44:17 -04:00
# include <netaddress.h>
2019-12-29 14:54:33 -03:00
# include <serialize.h>
2021-09-07 05:48:45 -03:00
# include <streams.h>
2021-09-09 16:41:51 -03:00
# include <util/check.h>
2012-01-04 19:39:45 -03:00
2021-01-27 04:04:34 -03:00
# include <cmath>
2021-05-02 12:44:17 -04:00
# include <optional>
2020-04-20 11:11:08 -04:00
# include <unordered_map>
# include <unordered_set>
2021-01-27 04:04:34 -03:00
2021-08-18 04:45:54 -04:00
/** Over how many buckets entries with tried addresses from a single group (/16 for IPv4) are spread */
2021-08-17 16:55:11 -04:00
static constexpr uint32_t ADDRMAN_TRIED_BUCKETS_PER_GROUP { 8 } ;
2021-08-18 04:45:54 -04:00
/** Over how many buckets entries with new addresses originating from a single group are spread */
2021-08-17 16:55:11 -04:00
static constexpr uint32_t ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP { 64 } ;
2021-08-18 04:45:54 -04:00
/** Maximum number of times an address can be added to the new table */
2021-08-17 16:55:11 -04:00
static constexpr int32_t ADDRMAN_NEW_BUCKETS_PER_ADDRESS { 8 } ;
2021-08-18 04:45:54 -04:00
/** How old addresses can maximally be */
2021-08-17 16:55:11 -04:00
static constexpr int64_t ADDRMAN_HORIZON_DAYS { 30 } ;
2021-08-18 04:45:54 -04:00
/** After how many failed attempts we give up on a new node */
2021-08-17 16:55:11 -04:00
static constexpr int32_t ADDRMAN_RETRIES { 3 } ;
2021-08-18 04:45:54 -04:00
/** How many successive failures are allowed ... */
2021-08-17 16:55:11 -04:00
static constexpr int32_t ADDRMAN_MAX_FAILURES { 10 } ;
2021-08-18 04:45:54 -04:00
/** ... in at least this many days */
2021-08-17 16:55:11 -04:00
static constexpr int64_t ADDRMAN_MIN_FAIL_DAYS { 7 } ;
2021-08-18 04:45:54 -04:00
/** How recent a successful connection should be before we allow an address to be evicted from tried */
2021-08-17 16:55:11 -04:00
static constexpr int64_t ADDRMAN_REPLACEMENT_HOURS { 4 } ;
2021-08-18 04:45:54 -04:00
/** The maximum number of tried addr collisions to store */
2021-08-17 16:55:11 -04:00
static constexpr size_t ADDRMAN_SET_TRIED_COLLISION_SIZE { 10 } ;
2021-08-18 04:45:54 -04:00
/** The maximum time we'll spend trying to resolve a tried table collision, in seconds */
2021-08-17 16:55:11 -04:00
static constexpr int64_t ADDRMAN_TEST_WINDOW { 40 * 60 } ; // 40 minutes
2019-12-24 15:18:44 -03:00
int CAddrInfo : : GetTriedBucket ( const uint256 & nKey , const std : : vector < bool > & asmap ) const
2012-01-04 19:39:45 -03:00
{
2018-05-17 01:50:15 -04:00
uint64_t hash1 = ( CHashWriter ( SER_GETHASH , 0 ) < < nKey < < GetKey ( ) ) . GetCheapHash ( ) ;
2019-12-24 15:18:44 -03:00
uint64_t hash2 = ( CHashWriter ( SER_GETHASH , 0 ) < < nKey < < GetGroup ( asmap ) < < ( hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP ) ) . GetCheapHash ( ) ;
2020-01-10 15:08:15 -03:00
int tried_bucket = hash2 % ADDRMAN_TRIED_BUCKET_COUNT ;
uint32_t mapped_as = GetMappedAS ( asmap ) ;
2019-12-29 14:54:33 -03:00
LogPrint ( BCLog : : NET , " IP %s mapped to AS%i belongs to tried bucket %i \n " , ToStringIP ( ) , mapped_as , tried_bucket ) ;
2020-01-10 15:08:15 -03:00
return tried_bucket ;
2012-01-04 19:39:45 -03:00
}
2019-12-24 15:18:44 -03:00
int CAddrInfo : : GetNewBucket ( const uint256 & nKey , const CNetAddr & src , const std : : vector < bool > & asmap ) const
2012-01-04 19:39:45 -03:00
{
2019-12-24 15:18:44 -03:00
std : : vector < unsigned char > vchSourceGroupKey = src . GetGroup ( asmap ) ;
uint64_t hash1 = ( CHashWriter ( SER_GETHASH , 0 ) < < nKey < < GetGroup ( asmap ) < < vchSourceGroupKey ) . GetCheapHash ( ) ;
2018-05-17 01:50:15 -04:00
uint64_t hash2 = ( CHashWriter ( SER_GETHASH , 0 ) < < nKey < < vchSourceGroupKey < < ( hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP ) ) . GetCheapHash ( ) ;
2020-01-10 15:08:15 -03:00
int new_bucket = hash2 % ADDRMAN_NEW_BUCKET_COUNT ;
uint32_t mapped_as = GetMappedAS ( asmap ) ;
2019-12-29 14:54:33 -03:00
LogPrint ( BCLog : : NET , " IP %s mapped to AS%i belongs to new bucket %i \n " , ToStringIP ( ) , mapped_as , new_bucket ) ;
2020-01-10 15:08:15 -03:00
return new_bucket ;
2012-01-04 19:39:45 -03:00
}
2015-03-18 13:31:49 -03:00
int CAddrInfo : : GetBucketPosition ( const uint256 & nKey , bool fNew , int nBucket ) const
{
2021-05-31 08:57:32 -04:00
uint64_t hash1 = ( CHashWriter ( SER_GETHASH , 0 ) < < nKey < < ( fNew ? uint8_t { ' N ' } : uint8_t { ' K ' } ) < < nBucket < < GetKey ( ) ) . GetCheapHash ( ) ;
2015-03-18 13:31:49 -03:00
return hash1 % ADDRMAN_BUCKET_SIZE ;
}
2013-04-13 02:13:08 -03:00
bool CAddrInfo : : IsTerrible ( int64_t nNow ) const
2012-01-04 19:39:45 -03:00
{
2014-10-24 01:04:27 -03:00
if ( nLastTry & & nLastTry > = nNow - 60 ) // never remove things tried in the last minute
2012-01-04 19:39:45 -03:00
return false ;
2014-09-19 14:21:46 -03:00
if ( nTime > nNow + 10 * 60 ) // came in a flying DeLorean
2012-01-04 19:39:45 -03:00
return true ;
2014-09-19 14:21:46 -03:00
if ( nTime = = 0 | | nNow - nTime > ADDRMAN_HORIZON_DAYS * 24 * 60 * 60 ) // not seen in recent history
2012-01-04 19:39:45 -03:00
return true ;
2014-09-19 14:21:46 -03:00
if ( nLastSuccess = = 0 & & nAttempts > = ADDRMAN_RETRIES ) // tried N times and never a success
2012-01-04 19:39:45 -03:00
return true ;
2014-09-19 14:21:46 -03: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 19:39:45 -03:00
return true ;
return false ;
}
2013-04-13 02:13:08 -03:00
double CAddrInfo : : GetChance ( int64_t nNow ) const
2012-01-04 19:39:45 -03:00
{
double fChance = 1.0 ;
2017-02-03 05:20:54 -03:00
int64_t nSinceLastTry = std : : max < int64_t > ( nNow - nLastTry , 0 ) ;
2012-01-04 19:39:45 -03:00
// deprioritize very recent attempts away
2014-09-19 14:21:46 -03:00
if ( nSinceLastTry < 60 * 10 )
2012-01-04 19:39:45 -03:00
fChance * = 0.01 ;
2015-04-19 15:47:56 -03: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 09:45:19 -03:00
fChance * = pow ( 0.66 , std : : min ( nAttempts , 8 ) ) ;
2012-01-04 19:39:45 -03:00
return fChance ;
}
2021-09-01 14:21:29 -04:00
AddrManImpl : : AddrManImpl ( std : : vector < bool > & & asmap , bool deterministic , int32_t consistency_check_ratio )
2021-08-05 09:10:02 -04:00
: insecure_rand { deterministic }
2021-08-05 09:14:21 -04:00
, nKey { deterministic ? uint256 { 1 } : insecure_rand . rand256 ( ) }
2021-08-05 09:10:02 -04:00
, m_consistency_check_ratio { consistency_check_ratio }
2021-08-24 06:47:17 -04:00
, m_asmap { std : : move ( asmap ) }
2021-08-05 09:10:02 -04:00
{
2021-08-05 09:14:21 -04:00
for ( auto & bucket : vvNew ) {
for ( auto & entry : bucket ) {
entry = - 1 ;
2021-08-05 09:10:02 -04:00
}
}
2021-08-05 09:14:21 -04:00
for ( auto & bucket : vvTried ) {
for ( auto & entry : bucket ) {
entry = - 1 ;
2021-08-05 09:10:02 -04:00
}
}
}
2021-09-01 14:21:29 -04:00
AddrManImpl : : ~ AddrManImpl ( )
2021-09-24 17:14:39 -03:00
{
nKey . SetNull ( ) ;
}
2021-08-17 12:31:23 -04:00
template < typename Stream >
2021-09-01 14:21:29 -04:00
void AddrManImpl : : Serialize ( Stream & s_ ) const
2021-08-17 12:31:23 -04:00
{
LOCK ( cs ) ;
/**
* Serialized format .
* * format version byte ( @ see ` Format ` )
* * lowest compatible format version byte . This is used to help old software decide
* whether to parse the file . For example :
* * Bitcoin Core version N knows how to parse up to format = 3. If a new format = 4 is
* introduced in version N + 1 that is compatible with format = 3 and it is known that
* version N will be able to parse it , then version N + 1 will write
* ( format = 4 , lowest_compatible = 3 ) in the first two bytes of the file , and so
* version N will still try to parse it .
* * Bitcoin Core version N + 2 introduces a new incompatible format = 5. It will write
* ( format = 5 , lowest_compatible = 5 ) and so any versions that do not know how to parse
* format = 5 will not try to read the file .
* * nKey
* * nNew
* * nTried
* * number of " new " buckets XOR 2 * * 30
* * all new addresses ( total count : nNew )
* * all tried addresses ( total count : nTried )
* * for each new bucket :
* * number of elements
* * for each element : index in the serialized " all new addresses "
* * asmap checksum
*
* 2 * * 30 is xorred with the number of buckets to make addrman deserializer v0 detect it
* as incompatible . This is necessary because it did not check the version number on
* deserialization .
*
* vvNew , vvTried , mapInfo , mapAddr and vRandom are never encoded explicitly ;
* they are instead reconstructed from the other information .
*
* This format is more complex , but significantly smaller ( at most 1.5 MiB ) , and supports
* changes to the ADDRMAN_ parameters without breaking the on - disk structure .
*
* We don ' t use SERIALIZE_METHODS since the serialization and deserialization code has
* very little in common .
*/
// Always serialize in the latest version (FILE_FORMAT).
OverrideStream < Stream > s ( & s_ , s_ . GetType ( ) , s_ . GetVersion ( ) | ADDRV2_FORMAT ) ;
s < < static_cast < uint8_t > ( FILE_FORMAT ) ;
// Increment `lowest_compatible` iff a newly introduced format is incompatible with
// the previous one.
static constexpr uint8_t lowest_compatible = Format : : V3_BIP155 ;
s < < static_cast < uint8_t > ( INCOMPATIBILITY_BASE + lowest_compatible ) ;
s < < nKey ;
s < < nNew ;
s < < nTried ;
int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ ( 1 < < 30 ) ;
s < < nUBuckets ;
std : : unordered_map < int , int > mapUnkIds ;
int nIds = 0 ;
for ( const auto & entry : mapInfo ) {
mapUnkIds [ entry . first ] = nIds ;
const CAddrInfo & info = entry . second ;
if ( info . nRefCount ) {
assert ( nIds ! = nNew ) ; // this means nNew was wrong, oh ow
s < < info ;
nIds + + ;
}
}
nIds = 0 ;
for ( const auto & entry : mapInfo ) {
const CAddrInfo & info = entry . second ;
if ( info . fInTried ) {
assert ( nIds ! = nTried ) ; // this means nTried was wrong, oh ow
s < < info ;
nIds + + ;
}
}
for ( int bucket = 0 ; bucket < ADDRMAN_NEW_BUCKET_COUNT ; bucket + + ) {
int nSize = 0 ;
for ( int i = 0 ; i < ADDRMAN_BUCKET_SIZE ; i + + ) {
if ( vvNew [ bucket ] [ i ] ! = - 1 )
nSize + + ;
}
s < < nSize ;
for ( int i = 0 ; i < ADDRMAN_BUCKET_SIZE ; i + + ) {
if ( vvNew [ bucket ] [ i ] ! = - 1 ) {
int nIndex = mapUnkIds [ vvNew [ bucket ] [ i ] ] ;
s < < nIndex ;
}
}
}
// Store asmap checksum after bucket entries so that it
// can be ignored by older clients for backward compatibility.
uint256 asmap_checksum ;
if ( m_asmap . size ( ) ! = 0 ) {
asmap_checksum = SerializeHash ( m_asmap ) ;
}
s < < asmap_checksum ;
}
2021-08-17 12:31:23 -04:00
template < typename Stream >
2021-09-01 14:21:29 -04:00
void AddrManImpl : : Unserialize ( Stream & s_ )
2021-08-17 12:31:23 -04:00
{
LOCK ( cs ) ;
assert ( vRandom . empty ( ) ) ;
Format format ;
s_ > > Using < CustomUintFormatter < 1 > > ( format ) ;
int stream_version = s_ . GetVersion ( ) ;
if ( format > = Format : : V3_BIP155 ) {
// Add ADDRV2_FORMAT to the version so that the CNetAddr and CAddress
// unserialize methods know that an address in addrv2 format is coming.
stream_version | = ADDRV2_FORMAT ;
}
OverrideStream < Stream > s ( & s_ , s_ . GetType ( ) , stream_version ) ;
uint8_t compat ;
s > > compat ;
const uint8_t lowest_compatible = compat - INCOMPATIBILITY_BASE ;
if ( lowest_compatible > FILE_FORMAT ) {
throw std : : ios_base : : failure ( strprintf (
2021-09-03 10:44:58 -04:00
" Unsupported format of addrman database: %u. It is compatible with formats >=%u, "
" but the maximum supported by this version of %s is %u. " ,
uint8_t { format } , uint8_t { lowest_compatible } , PACKAGE_NAME , uint8_t { FILE_FORMAT } ) ) ;
2021-08-17 12:31:23 -04:00
}
s > > nKey ;
s > > nNew ;
s > > nTried ;
int nUBuckets = 0 ;
s > > nUBuckets ;
if ( format > = Format : : V1_DETERMINISTIC ) {
nUBuckets ^ = ( 1 < < 30 ) ;
}
if ( nNew > ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE | | nNew < 0 ) {
throw std : : ios_base : : failure (
2021-08-17 12:31:23 -04:00
strprintf ( " Corrupt CAddrMan serialization: nNew=%d, should be in [0, %d] " ,
2021-08-17 12:31:23 -04:00
nNew ,
ADDRMAN_NEW_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE ) ) ;
}
if ( nTried > ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE | | nTried < 0 ) {
throw std : : ios_base : : failure (
2021-08-17 12:31:23 -04:00
strprintf ( " Corrupt CAddrMan serialization: nTried=%d, should be in [0, %d] " ,
2021-08-17 12:31:23 -04:00
nTried ,
ADDRMAN_TRIED_BUCKET_COUNT * ADDRMAN_BUCKET_SIZE ) ) ;
}
// Deserialize entries from the new table.
for ( int n = 0 ; n < nNew ; n + + ) {
CAddrInfo & info = mapInfo [ n ] ;
s > > info ;
mapAddr [ info ] = n ;
info . nRandomPos = vRandom . size ( ) ;
vRandom . push_back ( n ) ;
}
nIdCount = nNew ;
// Deserialize entries from the tried table.
int nLost = 0 ;
for ( int n = 0 ; n < nTried ; n + + ) {
CAddrInfo info ;
s > > info ;
int nKBucket = info . GetTriedBucket ( nKey , m_asmap ) ;
int nKBucketPos = info . GetBucketPosition ( nKey , false , nKBucket ) ;
if ( info . IsValid ( )
& & vvTried [ nKBucket ] [ nKBucketPos ] = = - 1 ) {
info . nRandomPos = vRandom . size ( ) ;
info . fInTried = true ;
vRandom . push_back ( nIdCount ) ;
mapInfo [ nIdCount ] = info ;
mapAddr [ info ] = nIdCount ;
vvTried [ nKBucket ] [ nKBucketPos ] = nIdCount ;
nIdCount + + ;
} else {
nLost + + ;
}
}
nTried - = nLost ;
// Store positions in the new table buckets to apply later (if possible).
// An entry may appear in up to ADDRMAN_NEW_BUCKETS_PER_ADDRESS buckets,
// so we store all bucket-entry_index pairs to iterate through later.
std : : vector < std : : pair < int , int > > bucket_entries ;
for ( int bucket = 0 ; bucket < nUBuckets ; + + bucket ) {
int num_entries { 0 } ;
s > > num_entries ;
for ( int n = 0 ; n < num_entries ; + + n ) {
int entry_index { 0 } ;
s > > entry_index ;
if ( entry_index > = 0 & & entry_index < nNew ) {
bucket_entries . emplace_back ( bucket , entry_index ) ;
}
}
}
// If the bucket count and asmap checksum haven't changed, then attempt
// to restore the entries to the buckets/positions they were in before
// serialization.
uint256 supplied_asmap_checksum ;
if ( m_asmap . size ( ) ! = 0 ) {
supplied_asmap_checksum = SerializeHash ( m_asmap ) ;
}
uint256 serialized_asmap_checksum ;
if ( format > = Format : : V2_ASMAP ) {
s > > serialized_asmap_checksum ;
}
const bool restore_bucketing { nUBuckets = = ADDRMAN_NEW_BUCKET_COUNT & &
serialized_asmap_checksum = = supplied_asmap_checksum } ;
if ( ! restore_bucketing ) {
LogPrint ( BCLog : : ADDRMAN , " Bucketing method was updated, re-bucketing addrman entries from disk \n " ) ;
}
for ( auto bucket_entry : bucket_entries ) {
int bucket { bucket_entry . first } ;
const int entry_index { bucket_entry . second } ;
CAddrInfo & info = mapInfo [ entry_index ] ;
// Don't store the entry in the new bucket if it's not a valid address for our addrman
if ( ! info . IsValid ( ) ) continue ;
// The entry shouldn't appear in more than
// ADDRMAN_NEW_BUCKETS_PER_ADDRESS. If it has already, just skip
// this bucket_entry.
if ( info . nRefCount > = ADDRMAN_NEW_BUCKETS_PER_ADDRESS ) continue ;
int bucket_position = info . GetBucketPosition ( nKey , true , bucket ) ;
if ( restore_bucketing & & vvNew [ bucket ] [ bucket_position ] = = - 1 ) {
// Bucketing has not changed, using existing bucket positions for the new table
vvNew [ bucket ] [ bucket_position ] = entry_index ;
+ + info . nRefCount ;
} else {
// In case the new table data cannot be used (bucket count wrong or new asmap),
// try to give them a reference based on their primary source address.
bucket = info . GetNewBucket ( nKey , m_asmap ) ;
bucket_position = info . GetBucketPosition ( nKey , true , bucket ) ;
if ( vvNew [ bucket ] [ bucket_position ] = = - 1 ) {
vvNew [ bucket ] [ bucket_position ] = entry_index ;
+ + info . nRefCount ;
}
}
}
// Prune new entries with refcount 0 (as a result of collisions or invalid address).
int nLostUnk = 0 ;
for ( auto it = mapInfo . cbegin ( ) ; it ! = mapInfo . cend ( ) ; ) {
if ( it - > second . fInTried = = false & & it - > second . nRefCount = = 0 ) {
const auto itCopy = it + + ;
Delete ( itCopy - > first ) ;
+ + nLostUnk ;
} else {
+ + it ;
}
}
if ( nLost + nLostUnk > 0 ) {
LogPrint ( BCLog : : ADDRMAN , " addrman lost %i new and %i tried addresses due to collisions or invalid addresses \n " , nLostUnk , nLost ) ;
}
2021-08-18 03:57:56 -04:00
const int check_code { ForceCheckAddrman ( ) } ;
if ( check_code ! = 0 ) {
throw std : : ios_base : : failure ( strprintf (
" Corrupt data. Consistency check failed with code %s " ,
check_code ) ) ;
}
2021-08-17 12:31:23 -04:00
}
2021-09-01 14:21:29 -04:00
CAddrInfo * AddrManImpl : : Find ( const CNetAddr & addr , int * pnId )
2012-01-04 19:39:45 -03:00
{
2021-05-23 14:06:10 -04:00
AssertLockHeld ( cs ) ;
2020-04-20 11:11:08 -04:00
const auto it = mapAddr . find ( addr ) ;
2012-01-04 19:39:45 -03:00
if ( it = = mapAddr . end ( ) )
2017-08-07 01:36:37 -04:00
return nullptr ;
2012-01-04 19:39:45 -03:00
if ( pnId )
* pnId = ( * it ) . second ;
2020-04-20 11:11:08 -04:00
const auto it2 = mapInfo . find ( ( * it ) . second ) ;
2012-01-04 19:39:45 -03:00
if ( it2 ! = mapInfo . end ( ) )
return & ( * it2 ) . second ;
2017-08-07 01:36:37 -04:00
return nullptr ;
2012-01-04 19:39:45 -03:00
}
2021-09-01 14:21:29 -04:00
CAddrInfo * AddrManImpl : : Create ( const CAddress & addr , const CNetAddr & addrSource , int * pnId )
2012-01-04 19:39:45 -03:00
{
2021-05-23 14:06:10 -04:00
AssertLockHeld ( cs ) ;
2012-01-04 19:39:45 -03: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 ] ;
}
2021-09-01 14:21:29 -04:00
void AddrManImpl : : SwapRandom ( unsigned int nRndPos1 , unsigned int nRndPos2 ) const
2012-01-04 19:39:45 -03:00
{
2021-05-23 14:06:10 -04:00
AssertLockHeld ( cs ) ;
2012-01-04 19:39:45 -03:00
if ( nRndPos1 = = nRndPos2 )
return ;
2012-05-05 15:30:38 -04:00
assert ( nRndPos1 < vRandom . size ( ) & & nRndPos2 < vRandom . size ( ) ) ;
2012-01-04 19:39:45 -03:00
int nId1 = vRandom [ nRndPos1 ] ;
int nId2 = vRandom [ nRndPos2 ] ;
2021-05-13 07:43:36 -04:00
const auto it_1 { mapInfo . find ( nId1 ) } ;
const auto it_2 { mapInfo . find ( nId2 ) } ;
assert ( it_1 ! = mapInfo . end ( ) ) ;
assert ( it_2 ! = mapInfo . end ( ) ) ;
2012-05-05 15:30:38 -04:00
2021-05-13 07:43:36 -04:00
it_1 - > second . nRandomPos = nRndPos2 ;
it_2 - > second . nRandomPos = nRndPos1 ;
2012-01-04 19:39:45 -03:00
vRandom [ nRndPos1 ] = nId2 ;
vRandom [ nRndPos2 ] = nId1 ;
}
2021-09-01 14:21:29 -04:00
void AddrManImpl : : Delete ( int nId )
2012-01-04 19:39:45 -03:00
{
2021-05-23 14:06:10 -04:00
AssertLockHeld ( cs ) ;
2015-03-18 13:31:49 -03:00
assert ( mapInfo . count ( nId ) ! = 0 ) ;
CAddrInfo & info = mapInfo [ nId ] ;
assert ( ! info . fInTried ) ;
assert ( info . nRefCount = = 0 ) ;
2012-01-04 19:39:45 -03:00
2015-03-18 13:31:49 -03:00
SwapRandom ( info . nRandomPos , vRandom . size ( ) - 1 ) ;
vRandom . pop_back ( ) ;
mapAddr . erase ( info ) ;
mapInfo . erase ( nId ) ;
nNew - - ;
2012-01-04 19:39:45 -03:00
}
2021-09-01 14:21:29 -04:00
void AddrManImpl : : ClearNew ( int nUBucket , int nUBucketPos )
2012-01-04 19:39:45 -03:00
{
2021-05-23 14:06:10 -04:00
AssertLockHeld ( cs ) ;
2015-03-18 13:31:49 -03: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 19:39:45 -03:00
}
}
}
2021-09-01 14:21:29 -04:00
void AddrManImpl : : MakeTried ( CAddrInfo & info , int nId )
2012-01-04 19:39:45 -03:00
{
2021-05-23 14:06:10 -04:00
AssertLockHeld ( cs ) ;
2012-01-04 19:39:45 -03:00
// remove the entry from all new buckets
2021-09-09 16:41:51 -03:00
const int start_bucket { info . GetNewBucket ( nKey , m_asmap ) } ;
for ( int n = 0 ; n < ADDRMAN_NEW_BUCKET_COUNT ; + + n ) {
const int bucket { ( start_bucket + n ) % ADDRMAN_NEW_BUCKET_COUNT } ;
const int pos { info . GetBucketPosition ( nKey , true , bucket ) } ;
2015-03-18 13:31:49 -03:00
if ( vvNew [ bucket ] [ pos ] = = nId ) {
vvNew [ bucket ] [ pos ] = - 1 ;
2012-01-04 19:39:45 -03:00
info . nRefCount - - ;
2021-09-09 16:41:51 -03:00
if ( info . nRefCount = = 0 ) break ;
2015-03-18 13:31:49 -03:00
}
2012-01-04 19:39:45 -03:00
}
nNew - - ;
2012-05-05 15:30:38 -04:00
assert ( info . nRefCount = = 0 ) ;
2014-10-24 01:04:27 -03:00
// which tried bucket to move the entry to
2019-12-24 15:18:44 -03:00
int nKBucket = info . GetTriedBucket ( nKey , m_asmap ) ;
2015-03-18 13:31:49 -03: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
2019-12-24 15:18:44 -03:00
int nUBucket = infoOld . GetNewBucket ( nKey , m_asmap ) ;
2015-03-18 13:31:49 -03:00
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 19:39:45 -03:00
}
2015-03-18 13:31:49 -03:00
assert ( vvTried [ nKBucket ] [ nKBucketPos ] = = - 1 ) ;
2012-01-04 19:39:45 -03:00
2015-03-18 13:31:49 -03:00
vvTried [ nKBucket ] [ nKBucketPos ] = nId ;
nTried + + ;
2012-01-04 19:39:45 -03:00
info . fInTried = true ;
}
2021-09-01 14:21:29 -04:00
void AddrManImpl : : Good_ ( const CService & addr , bool test_before_evict , int64_t nTime )
2012-01-04 19:39:45 -03:00
{
2021-05-23 14:06:10 -04:00
AssertLockHeld ( cs ) ;
2012-01-04 19:39:45 -03:00
int nId ;
2015-04-19 17:39:38 -03:00
nLastGood = nTime ;
2014-09-19 14:21:46 -03:00
CAddrInfo * pinfo = Find ( addr , & nId ) ;
2012-01-04 19:39:45 -03:00
// if not found, bail out
if ( ! pinfo )
return ;
2014-09-19 14:21:46 -03:00
CAddrInfo & info = * pinfo ;
2012-01-04 19:39:45 -03: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 09:01:22 -03:00
// nTime is not updated here, to avoid leaking information about
// currently-connected peers.
2012-01-04 19:39:45 -03:00
// if it is already in the tried set, don't do anything else
if ( info . fInTried )
return ;
2021-09-09 16:41:51 -03:00
// if it is not in new, something bad happened
if ( ! Assume ( info . nRefCount > 0 ) ) {
2014-09-19 14:21:46 -03:00
return ;
2021-09-09 16:41:51 -03:00
}
2012-01-04 19:39:45 -03:00
2016-10-27 14:55:39 -03:00
// which tried bucket to move the entry to
2019-12-24 15:18:44 -03:00
int tried_bucket = info . GetTriedBucket ( nKey , m_asmap ) ;
2016-10-27 14:55:39 -03:00
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 16:59:30 -03: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 14:55:39 -03: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 19:39:45 -03:00
2016-10-27 14:55:39 -03:00
// move nId to the tried tables
MakeTried ( info , nId ) ;
}
2012-01-04 19:39:45 -03:00
}
2021-09-01 14:21:29 -04:00
bool AddrManImpl : : Add_ ( const CAddress & addr , const CNetAddr & source , int64_t nTimePenalty )
2012-01-04 19:39:45 -03:00
{
2021-05-23 14:06:10 -04:00
AssertLockHeld ( cs ) ;
2012-01-04 19:39:45 -03:00
if ( ! addr . IsRoutable ( ) )
return false ;
bool fNew = false ;
int nId ;
2014-09-19 14:21:46 -03:00
CAddrInfo * pinfo = Find ( addr , & nId ) ;
2012-01-04 19:39:45 -03:00
2017-01-18 12:15:37 -03:00
// Do not set a penalty for a source's self-announcement
2016-09-03 07:24:37 -03:00
if ( addr = = source ) {
nTimePenalty = 0 ;
}
2014-09-19 14:21:46 -03:00
if ( pinfo ) {
2012-01-04 19:39:45 -03:00
// periodically update nTime
bool fCurrentlyOnline = ( GetAdjustedTime ( ) - addr . nTime < 24 * 60 * 60 ) ;
2013-04-13 02:13:08 -03:00
int64_t nUpdateInterval = ( fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60 ) ;
2012-01-04 19:39:45 -03:00
if ( addr . nTime & & ( ! pinfo - > nTime | | pinfo - > nTime < addr . nTime - nUpdateInterval - nTimePenalty ) )
2015-06-15 09:45:19 -03:00
pinfo - > nTime = std : : max ( ( int64_t ) 0 , addr . nTime - nTimePenalty ) ;
2012-01-04 19:39:45 -03:00
// add services
2016-06-08 13:12:22 -04:00
pinfo - > nServices = ServiceFlags ( pinfo - > nServices | addr . nServices ) ;
2012-01-04 19:39:45 -03:00
// do not update if no new information is present
2012-04-15 08:03:28 -03:00
if ( ! addr . nTime | | ( pinfo - > nTime & & addr . nTime < = pinfo - > nTime ) )
2012-01-04 19:39:45 -03: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 14:21:46 -03:00
for ( int n = 0 ; n < pinfo - > nRefCount ; n + + )
2012-01-04 19:39:45 -03:00
nFactor * = 2 ;
2018-10-31 17:56:19 -03:00
if ( nFactor > 1 & & ( insecure_rand . randrange ( nFactor ) ! = 0 ) )
2012-01-04 19:39:45 -03:00
return false ;
} else {
pinfo = Create ( addr , source , & nId ) ;
2015-06-15 09:45:19 -03:00
pinfo - > nTime = std : : max ( ( int64_t ) 0 , ( int64_t ) pinfo - > nTime - nTimePenalty ) ;
2012-01-04 19:39:45 -03:00
nNew + + ;
fNew = true ;
}
2019-12-24 15:18:44 -03:00
int nUBucket = pinfo - > GetNewBucket ( nKey , source , m_asmap ) ;
2015-03-18 13:31:49 -03: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 19:39:45 -03:00
}
return fNew ;
}
2021-09-01 14:21:29 -04:00
void AddrManImpl : : Attempt_ ( const CService & addr , bool fCountFailure , int64_t nTime )
2012-01-04 19:39:45 -03:00
{
2021-05-23 14:06:10 -04:00
AssertLockHeld ( cs ) ;
2014-09-19 14:21:46 -03:00
CAddrInfo * pinfo = Find ( addr ) ;
2012-01-04 19:39:45 -03:00
// if not found, bail out
if ( ! pinfo )
return ;
2014-09-19 14:21:46 -03:00
CAddrInfo & info = * pinfo ;
2012-01-04 19:39:45 -03: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 17:39:38 -03:00
if ( fCountFailure & & info . nLastCountAttempt < nLastGood ) {
info . nLastCountAttempt = nTime ;
info . nAttempts + + ;
}
2012-01-04 19:39:45 -03:00
}
2021-08-25 18:40:59 -04:00
std : : pair < CAddress , int64_t > AddrManImpl : : Select_ ( bool newOnly ) const
2012-01-04 19:39:45 -03:00
{
2021-05-23 14:06:10 -04:00
AssertLockHeld ( cs ) ;
2021-08-25 18:40:59 -04:00
if ( vRandom . empty ( ) ) return { } ;
2012-01-04 19:39:45 -03:00
2021-08-25 18:40:59 -04:00
if ( newOnly & & nNew = = 0 ) return { } ;
2015-09-22 16:24:16 -03:00
2015-03-19 13:51:59 -03:00
// Use a 50% chance for choosing between tried and new table entries.
2015-09-22 16:24:16 -03:00
if ( ! newOnly & &
2018-10-31 17:56:19 -03:00
( nTried > 0 & & ( nNew = = 0 | | insecure_rand . randbool ( ) = = 0 ) ) ) {
2012-01-04 19:39:45 -03:00
// use a tried node
double fChanceFactor = 1.0 ;
2014-09-19 14:21:46 -03:00
while ( 1 ) {
2018-10-31 17:56:19 -03:00
int nKBucket = insecure_rand . randrange ( ADDRMAN_TRIED_BUCKET_COUNT ) ;
int nKBucketPos = insecure_rand . randrange ( ADDRMAN_BUCKET_SIZE ) ;
2015-08-06 14:49:19 -03:00
while ( vvTried [ nKBucket ] [ nKBucketPos ] = = - 1 ) {
2017-02-15 22:45:22 -03: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 14:49:19 -03:00
}
2015-03-18 13:31:49 -03:00
int nId = vvTried [ nKBucket ] [ nKBucketPos ] ;
2021-05-13 06:13:27 -04:00
const auto it_found { mapInfo . find ( nId ) } ;
assert ( it_found ! = mapInfo . end ( ) ) ;
const CAddrInfo & info { it_found - > second } ;
2021-08-25 18:40:59 -04:00
if ( insecure_rand . randbits ( 30 ) < fChanceFactor * info . GetChance ( ) * ( 1 < < 30 ) ) {
return { info , info . nLastTry } ;
}
2012-01-04 19:39:45 -03:00
fChanceFactor * = 1.2 ;
}
} else {
2012-08-18 10:45:24 -04:00
// use a new node
2012-01-04 19:39:45 -03:00
double fChanceFactor = 1.0 ;
2014-09-19 14:21:46 -03:00
while ( 1 ) {
2018-10-31 17:56:19 -03:00
int nUBucket = insecure_rand . randrange ( ADDRMAN_NEW_BUCKET_COUNT ) ;
int nUBucketPos = insecure_rand . randrange ( ADDRMAN_BUCKET_SIZE ) ;
2015-08-06 14:49:19 -03:00
while ( vvNew [ nUBucket ] [ nUBucketPos ] = = - 1 ) {
2017-02-15 22:45:22 -03: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 14:49:19 -03:00
}
2015-03-18 13:31:49 -03:00
int nId = vvNew [ nUBucket ] [ nUBucketPos ] ;
2021-05-13 06:13:27 -04:00
const auto it_found { mapInfo . find ( nId ) } ;
assert ( it_found ! = mapInfo . end ( ) ) ;
const CAddrInfo & info { it_found - > second } ;
2021-08-25 18:40:59 -04:00
if ( insecure_rand . randbits ( 30 ) < fChanceFactor * info . GetChance ( ) * ( 1 < < 30 ) ) {
return { info , info . nLastTry } ;
}
2012-01-04 19:39:45 -03:00
fChanceFactor * = 1.2 ;
}
}
}
2021-09-22 18:47:49 -03:00
std : : vector < CAddress > AddrManImpl : : GetAddr_ ( size_t max_addresses , size_t max_pct , std : : optional < Network > network ) const
2012-01-04 19:39:45 -03:00
{
2021-05-23 14:06:10 -04:00
AssertLockHeld ( cs ) ;
2020-07-23 10:34:40 -04:00
size_t nNodes = vRandom . size ( ) ;
if ( max_pct ! = 0 ) {
nNodes = max_pct * nNodes / 100 ;
}
if ( max_addresses ! = 0 ) {
nNodes = std : : min ( nNodes , max_addresses ) ;
}
2012-01-04 19:39:45 -03:00
2014-08-18 16:50:39 -04:00
// gather a list of random nodes, skipping those of low quality
2021-05-12 10:53:25 -04:00
const int64_t now { GetAdjustedTime ( ) } ;
2021-09-22 18:47:49 -03:00
std : : vector < CAddress > addresses ;
2014-09-19 14:21:46 -03:00
for ( unsigned int n = 0 ; n < vRandom . size ( ) ; n + + ) {
2021-09-22 18:47:49 -03:00
if ( addresses . size ( ) > = nNodes )
2014-08-18 16:50:39 -04:00
break ;
2018-10-31 17:56:19 -03:00
int nRndPos = insecure_rand . randrange ( vRandom . size ( ) - n ) + n ;
2012-01-04 19:39:45 -03:00
SwapRandom ( n , nRndPos ) ;
2021-05-13 07:43:36 -04:00
const auto it { mapInfo . find ( vRandom [ n ] ) } ;
assert ( it ! = mapInfo . end ( ) ) ;
2014-08-18 16:50:39 -04:00
2021-05-13 07:43:36 -04:00
const CAddrInfo & ai { it - > second } ;
2021-05-02 12:44:17 -04:00
// Filter by network (optional)
if ( network ! = std : : nullopt & & ai . GetNetClass ( ) ! = network ) continue ;
// Filter for quality
2021-05-12 10:53:25 -04:00
if ( ai . IsTerrible ( now ) ) continue ;
2021-05-02 12:44:17 -04:00
2021-09-22 18:47:49 -03:00
addresses . push_back ( ai ) ;
2012-01-04 19:39:45 -03:00
}
2021-09-22 18:47:49 -03:00
return addresses ;
2012-01-04 19:39:45 -03:00
}
2021-09-01 14:21:29 -04:00
void AddrManImpl : : Connected_ ( const CService & addr , int64_t nTime )
2012-01-04 19:39:45 -03:00
{
2021-05-23 14:06:10 -04:00
AssertLockHeld ( cs ) ;
2014-09-19 14:21:46 -03:00
CAddrInfo * pinfo = Find ( addr ) ;
2012-01-04 19:39:45 -03:00
// if not found, bail out
if ( ! pinfo )
return ;
2014-09-19 14:21:46 -03:00
CAddrInfo & info = * pinfo ;
2012-01-04 19:39:45 -03:00
// check whether we are talking about the exact same CService (including same port)
if ( info ! = addr )
return ;
// update info
2013-04-13 02:13:08 -03:00
int64_t nUpdateInterval = 20 * 60 ;
2012-01-04 19:39:45 -03:00
if ( nTime - info . nTime > nUpdateInterval )
info . nTime = nTime ;
}
2015-12-13 00:34:08 -03:00
2021-09-01 14:21:29 -04:00
void AddrManImpl : : SetServices_ ( const CService & addr , ServiceFlags nServices )
2016-03-26 14:58:00 -03:00
{
2021-05-23 14:06:10 -04:00
AssertLockHeld ( cs ) ;
2016-03-26 14:58:00 -03: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 ;
}
2021-09-01 14:21:29 -04:00
void AddrManImpl : : ResolveCollisions_ ( )
2016-10-27 14:55:39 -03:00
{
2021-05-23 14:06:10 -04:00
AssertLockHeld ( cs ) ;
2016-10-27 14:55:39 -03:00
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.
2019-12-24 15:18:44 -03:00
int tried_bucket = info_new . GetTriedBucket ( nKey , m_asmap ) ;
2016-10-27 14:55:39 -03:00
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 18:15:50 -03:00
LogPrint ( BCLog : : ADDRMAN , " Replacing %s with %s in tried table \n " , info_old . ToString ( ) , info_new . ToString ( ) ) ;
2016-10-27 14:55:39 -03: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 18:34:26 -03: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 18:15:50 -03: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 18:34:26 -03:00
Good_ ( info_new , false , GetAdjustedTime ( ) ) ;
erase_collision = true ;
2016-10-27 14:55:39 -03: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 + + ;
}
}
}
2021-08-25 18:40:59 -04:00
std : : pair < CAddress , int64_t > AddrManImpl : : SelectTriedCollision_ ( )
2016-10-27 14:55:39 -03:00
{
2021-05-23 14:06:10 -04:00
AssertLockHeld ( cs ) ;
2021-08-25 18:40:59 -04:00
if ( m_tried_collisions . size ( ) = = 0 ) return { } ;
2016-10-27 14:55:39 -03:00
std : : set < int > : : iterator it = m_tried_collisions . begin ( ) ;
// Selects a random element from m_tried_collisions
2018-10-31 17:56:19 -03:00
std : : advance ( it , insecure_rand . randrange ( m_tried_collisions . size ( ) ) ) ;
2016-10-27 14:55:39 -03: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 ) ;
2021-08-25 18:40:59 -04:00
return { } ;
2016-10-27 14:55:39 -03:00
}
2020-12-06 13:11:39 -03:00
const CAddrInfo & newInfo = mapInfo [ id_new ] ;
2016-10-27 14:55:39 -03:00
// which tried bucket to move the entry to
2019-12-24 15:18:44 -03:00
int tried_bucket = newInfo . GetTriedBucket ( nKey , m_asmap ) ;
2016-10-27 14:55:39 -03:00
int tried_bucket_pos = newInfo . GetBucketPosition ( nKey , false , tried_bucket ) ;
2021-08-25 18:40:59 -04:00
const CAddrInfo & info_old = mapInfo [ vvTried [ tried_bucket ] [ tried_bucket_pos ] ] ;
return { info_old , info_old . nLastTry } ;
2016-10-27 14:55:39 -03:00
}
2021-09-24 17:14:39 -03:00
2021-09-01 14:21:29 -04:00
void AddrManImpl : : Check ( ) const
2021-09-28 16:46:43 -03:00
{
AssertLockHeld ( cs ) ;
// Run consistency checks 1 in m_consistency_check_ratio times if enabled
if ( m_consistency_check_ratio = = 0 ) return ;
if ( insecure_rand . randrange ( m_consistency_check_ratio ) > = 1 ) return ;
const int err { ForceCheckAddrman ( ) } ;
if ( err ) {
LogPrintf ( " ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i \n " , err ) ;
assert ( false ) ;
}
}
2021-09-01 14:21:29 -04:00
int AddrManImpl : : ForceCheckAddrman ( ) const
2021-09-28 16:46:43 -03:00
{
AssertLockHeld ( cs ) ;
LogPrint ( BCLog : : ADDRMAN , " Addrman checks started: new %i, tried %i, total %u \n " , nNew , nTried , vRandom . size ( ) ) ;
std : : unordered_set < int > setTried ;
std : : unordered_map < int , int > mapNew ;
if ( vRandom . size ( ) ! = ( size_t ) ( nTried + nNew ) )
return - 7 ;
for ( const auto & entry : mapInfo ) {
int n = entry . first ;
const CAddrInfo & info = entry . second ;
if ( info . fInTried ) {
if ( ! info . nLastSuccess )
return - 1 ;
if ( info . nRefCount )
return - 2 ;
setTried . insert ( n ) ;
} else {
if ( info . nRefCount < 0 | | info . nRefCount > ADDRMAN_NEW_BUCKETS_PER_ADDRESS )
return - 3 ;
if ( ! info . nRefCount )
return - 4 ;
mapNew [ n ] = info . nRefCount ;
}
const auto it { mapAddr . find ( info ) } ;
if ( it = = mapAddr . end ( ) | | it - > second ! = n ) {
return - 5 ;
}
if ( info . nRandomPos < 0 | | ( size_t ) info . nRandomPos > = vRandom . size ( ) | | vRandom [ info . nRandomPos ] ! = n )
return - 14 ;
if ( info . nLastTry < 0 )
return - 6 ;
if ( info . nLastSuccess < 0 )
return - 8 ;
}
if ( setTried . size ( ) ! = ( size_t ) nTried )
return - 9 ;
if ( mapNew . size ( ) ! = ( size_t ) nNew )
return - 10 ;
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 ;
const auto it { mapInfo . find ( vvTried [ n ] [ i ] ) } ;
if ( it = = mapInfo . end ( ) | | it - > second . GetTriedBucket ( nKey , m_asmap ) ! = n ) {
return - 17 ;
}
if ( it - > second . GetBucketPosition ( nKey , false , n ) ! = i ) {
return - 18 ;
}
setTried . erase ( vvTried [ n ] [ i ] ) ;
}
}
}
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 ;
const auto it { mapInfo . find ( vvNew [ n ] [ i ] ) } ;
if ( it = = mapInfo . end ( ) | | it - > second . GetBucketPosition ( nKey , true , n ) ! = i ) {
return - 19 ;
}
if ( - - mapNew [ vvNew [ n ] [ i ] ] = = 0 )
mapNew . erase ( vvNew [ n ] [ i ] ) ;
}
}
}
if ( setTried . size ( ) )
return - 13 ;
if ( mapNew . size ( ) )
return - 15 ;
if ( nKey . IsNull ( ) )
return - 16 ;
LogPrint ( BCLog : : ADDRMAN , " Addrman checks completed successfully \n " ) ;
return 0 ;
}
2021-09-01 14:21:29 -04:00
size_t AddrManImpl : : size ( ) const
2021-09-24 17:14:39 -03:00
{
LOCK ( cs ) ; // TODO: Cache this in an atomic to avoid this overhead
return vRandom . size ( ) ;
}
2021-09-01 14:21:29 -04:00
bool AddrManImpl : : Add ( const std : : vector < CAddress > & vAddr , const CNetAddr & source , int64_t nTimePenalty )
2021-09-24 17:14:39 -03:00
{
LOCK ( cs ) ;
int nAdd = 0 ;
Check ( ) ;
for ( std : : vector < CAddress > : : const_iterator it = vAddr . begin ( ) ; it ! = vAddr . end ( ) ; it + + )
nAdd + = Add_ ( * it , source , nTimePenalty ) ? 1 : 0 ;
Check ( ) ;
if ( nAdd ) {
LogPrint ( BCLog : : ADDRMAN , " Added %i addresses from %s: %i tried, %i new \n " , nAdd , source . ToString ( ) , nTried , nNew ) ;
}
return nAdd > 0 ;
}
2021-09-01 14:21:29 -04:00
void AddrManImpl : : Good ( const CService & addr , int64_t nTime )
2021-09-24 17:14:39 -03:00
{
LOCK ( cs ) ;
Check ( ) ;
Good_ ( addr , /* test_before_evict */ true , nTime ) ;
Check ( ) ;
}
2021-09-01 14:21:29 -04:00
void AddrManImpl : : Attempt ( const CService & addr , bool fCountFailure , int64_t nTime )
2021-09-24 17:14:39 -03:00
{
LOCK ( cs ) ;
Check ( ) ;
Attempt_ ( addr , fCountFailure , nTime ) ;
Check ( ) ;
}
2021-09-01 14:21:29 -04:00
void AddrManImpl : : ResolveCollisions ( )
2021-09-24 17:14:39 -03:00
{
LOCK ( cs ) ;
Check ( ) ;
ResolveCollisions_ ( ) ;
Check ( ) ;
}
2021-08-25 18:40:59 -04:00
std : : pair < CAddress , int64_t > AddrManImpl : : SelectTriedCollision ( )
2021-09-24 17:14:39 -03:00
{
LOCK ( cs ) ;
Check ( ) ;
2021-08-25 18:40:59 -04:00
const auto ret = SelectTriedCollision_ ( ) ;
2021-09-24 17:14:39 -03:00
Check ( ) ;
return ret ;
}
2021-08-25 18:40:59 -04:00
std : : pair < CAddress , int64_t > AddrManImpl : : Select ( bool newOnly ) const
2021-09-24 17:14:39 -03:00
{
LOCK ( cs ) ;
Check ( ) ;
2021-08-25 18:40:59 -04:00
const auto addrRet = Select_ ( newOnly ) ;
2021-09-24 17:14:39 -03:00
Check ( ) ;
return addrRet ;
}
2021-09-01 14:21:29 -04:00
std : : vector < CAddress > AddrManImpl : : GetAddr ( size_t max_addresses , size_t max_pct , std : : optional < Network > network ) const
2021-09-24 17:14:39 -03:00
{
LOCK ( cs ) ;
Check ( ) ;
2021-09-22 18:47:49 -03:00
const auto addresses = GetAddr_ ( max_addresses , max_pct , network ) ;
2021-09-24 17:14:39 -03:00
Check ( ) ;
2021-09-22 18:47:49 -03:00
return addresses ;
2021-09-24 17:14:39 -03:00
}
2021-09-01 14:21:29 -04:00
void AddrManImpl : : Connected ( const CService & addr , int64_t nTime )
2021-09-24 17:14:39 -03:00
{
LOCK ( cs ) ;
Check ( ) ;
Connected_ ( addr , nTime ) ;
Check ( ) ;
}
2021-09-01 14:21:29 -04:00
void AddrManImpl : : SetServices ( const CService & addr , ServiceFlags nServices )
2021-09-24 17:14:39 -03:00
{
LOCK ( cs ) ;
Check ( ) ;
SetServices_ ( addr , nServices ) ;
Check ( ) ;
}
2021-09-01 14:21:29 -04:00
const std : : vector < bool > & AddrManImpl : : GetAsmap ( ) const
2021-09-24 17:14:39 -03:00
{
return m_asmap ;
}
2021-09-01 14:21:29 -04:00
CAddrMan : : CAddrMan ( std : : vector < bool > asmap , bool deterministic , int32_t consistency_check_ratio )
: m_impl ( std : : make_unique < AddrManImpl > ( std : : move ( asmap ) , deterministic , consistency_check_ratio ) ) { }
CAddrMan : : ~ CAddrMan ( ) = default ;
template < typename Stream >
void CAddrMan : : Serialize ( Stream & s_ ) const
{
m_impl - > Serialize < Stream > ( s_ ) ;
}
template < typename Stream >
void CAddrMan : : Unserialize ( Stream & s_ )
{
m_impl - > Unserialize < Stream > ( s_ ) ;
}
// explicit instantiation
template void CAddrMan : : Serialize ( CHashWriter & s ) const ;
template void CAddrMan : : Serialize ( CAutoFile & s ) const ;
template void CAddrMan : : Serialize ( CDataStream & s ) const ;
template void CAddrMan : : Unserialize ( CAutoFile & s ) ;
template void CAddrMan : : Unserialize ( CHashVerifier < CAutoFile > & s ) ;
template void CAddrMan : : Unserialize ( CDataStream & s ) ;
template void CAddrMan : : Unserialize ( CHashVerifier < CDataStream > & s ) ;
size_t CAddrMan : : size ( ) const
{
return m_impl - > size ( ) ;
}
bool CAddrMan : : Add ( const std : : vector < CAddress > & vAddr , const CNetAddr & source , int64_t nTimePenalty )
{
return m_impl - > Add ( vAddr , source , nTimePenalty ) ;
}
void CAddrMan : : Good ( const CService & addr , int64_t nTime )
{
m_impl - > Good ( addr , nTime ) ;
}
void CAddrMan : : Attempt ( const CService & addr , bool fCountFailure , int64_t nTime )
{
m_impl - > Attempt ( addr , fCountFailure , nTime ) ;
}
void CAddrMan : : ResolveCollisions ( )
{
m_impl - > ResolveCollisions ( ) ;
}
2021-08-25 18:40:59 -04:00
std : : pair < CAddress , int64_t > CAddrMan : : SelectTriedCollision ( )
2021-09-01 14:21:29 -04:00
{
return m_impl - > SelectTriedCollision ( ) ;
}
2021-08-25 18:40:59 -04:00
std : : pair < CAddress , int64_t > CAddrMan : : Select ( bool newOnly ) const
2021-09-01 14:21:29 -04:00
{
return m_impl - > Select ( newOnly ) ;
}
std : : vector < CAddress > CAddrMan : : GetAddr ( size_t max_addresses , size_t max_pct , std : : optional < Network > network ) const
{
return m_impl - > GetAddr ( max_addresses , max_pct , network ) ;
}
void CAddrMan : : Connected ( const CService & addr , int64_t nTime )
{
m_impl - > Connected ( addr , nTime ) ;
}
void CAddrMan : : SetServices ( const CService & addr , ServiceFlags nServices )
{
m_impl - > SetServices ( addr , nServices ) ;
}
const std : : vector < bool > & CAddrMan : : GetAsmap ( ) const
{
return m_impl - > GetAsmap ( ) ;
}