Browse Source

Merge pull request #5131

24f5c94 Update comments in addrman to be doxygen compatible (Michael Ford)
c772f4c Add doc/doxygen to .gitignore (Michael Ford)
0.10
Wladimir J. van der Laan 10 years ago
parent
commit
b847e0139e
No known key found for this signature in database
GPG Key ID: 74810B012346C9A6
  1. 2
      .gitignore
  2. 8
      src/addrman.cpp
  3. 239
      src/addrman.h

2
.gitignore vendored

@ -102,3 +102,5 @@ qa/pull-tester/run-bitcoind-for-test.sh
qa/pull-tester/build-tests.sh qa/pull-tester/build-tests.sh
!src/leveldb*/Makefile !src/leveldb*/Makefile
/doc/doxygen/

8
src/addrman.cpp

@ -1,5 +1,5 @@
// Copyright (c) 2012 Pieter Wuille // Copyright (c) 2012 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying // Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "addrman.h" #include "addrman.h"
@ -39,7 +39,7 @@ int CAddrInfo::GetNewBucket(const std::vector<unsigned char>& nKey, const CNetAd
bool CAddrInfo::IsTerrible(int64_t nNow) const bool CAddrInfo::IsTerrible(int64_t nNow) const
{ {
if (nLastTry && nLastTry >= nNow - 60) // never remove things tried the last minute if (nLastTry && nLastTry >= nNow - 60) // never remove things tried in the last minute
return false; return false;
if (nTime > nNow + 10 * 60) // came in a flying DeLorean if (nTime > nNow + 10 * 60) // came in a flying DeLorean
@ -131,7 +131,7 @@ int CAddrMan::SelectTried(int nKBucket)
{ {
std::vector<int>& vTried = vvTried[nKBucket]; std::vector<int>& vTried = vvTried[nKBucket];
// random shuffle the first few elements (using the entire list) // randomly shuffle the first few elements (using the entire list)
// find the least recently tried among them // find the least recently tried among them
int64_t nOldest = -1; int64_t nOldest = -1;
int nOldestPos = -1; int nOldestPos = -1;
@ -211,7 +211,7 @@ void CAddrMan::MakeTried(CAddrInfo& info, int nId, int nOrigin)
assert(info.nRefCount == 0); assert(info.nRefCount == 0);
// what tried bucket to move the entry to // which tried bucket to move the entry to
int nKBucket = info.GetTriedBucket(nKey); int nKBucket = info.GetTriedBucket(nKey);
std::vector<int>& vTried = vvTried[nKBucket]; std::vector<int>& vTried = vvTried[nKBucket];

239
src/addrman.h

@ -1,5 +1,5 @@
// Copyright (c) 2012 Pieter Wuille // Copyright (c) 2012 Pieter Wuille
// Distributed under the MIT/X11 software license, see the accompanying // Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef _BITCOIN_ADDRMAN #ifndef _BITCOIN_ADDRMAN
@ -17,29 +17,31 @@
#include <stdint.h> #include <stdint.h>
#include <vector> #include <vector>
/** Extended statistics about a CAddress */ /**
* Extended statistics about a CAddress
*/
class CAddrInfo : public CAddress class CAddrInfo : public CAddress
{ {
private: private:
// where knowledge about this address first came from //! where knowledge about this address first came from
CNetAddr source; CNetAddr source;
// last successful connection by us //! last successful connection by us
int64_t nLastSuccess; int64_t nLastSuccess;
// last try whatsoever by us: //! last try whatsoever by us:
// int64_t CAddress::nLastTry // int64_t CAddress::nLastTry
// connection attempts since last successful attempt //! connection attempts since last successful attempt
int nAttempts; int nAttempts;
// reference count in new sets (memory only) //! reference count in new sets (memory only)
int nRefCount; int nRefCount;
// in tried set? (memory only) //! in tried set? (memory only)
bool fInTried; bool fInTried;
// position in vRandom //! position in vRandom
int nRandomPos; int nRandomPos;
friend class CAddrMan; friend class CAddrMan;
@ -76,200 +78,205 @@ public:
Init(); Init();
} }
// Calculate in which "tried" bucket this entry belongs //! Calculate in which "tried" bucket this entry belongs
int GetTriedBucket(const std::vector<unsigned char> &nKey) const; int GetTriedBucket(const std::vector<unsigned char> &nKey) const;
// Calculate in which "new" bucket this entry belongs, given a certain source //! Calculate in which "new" bucket this entry belongs, given a certain source
int GetNewBucket(const std::vector<unsigned char> &nKey, const CNetAddr& src) const; int GetNewBucket(const std::vector<unsigned char> &nKey, const CNetAddr& src) const;
// Calculate in which "new" bucket this entry belongs, using its default source //! Calculate in which "new" bucket this entry belongs, using its default source
int GetNewBucket(const std::vector<unsigned char> &nKey) const int GetNewBucket(const std::vector<unsigned char> &nKey) const
{ {
return GetNewBucket(nKey, source); return GetNewBucket(nKey, source);
} }
// Determine whether the statistics about this entry are bad enough so that it can just be deleted //! Determine whether the statistics about this entry are bad enough so that it can just be deleted
bool IsTerrible(int64_t nNow = GetAdjustedTime()) const; bool IsTerrible(int64_t nNow = GetAdjustedTime()) const;
// Calculate the relative chance this entry should be given when selecting nodes to connect to //! Calculate the relative chance this entry should be given when selecting nodes to connect to
double GetChance(int64_t nNow = GetAdjustedTime()) const; double GetChance(int64_t nNow = GetAdjustedTime()) const;
}; };
// Stochastic address manager /** Stochastic address manager
// *
// Design goals: * Design goals:
// * Only keep a limited number of addresses around, so that addr.dat and memory requirements do not grow without bound. * * Keep the address tables in-memory, and asynchronously dump the entire to able in peers.dat.
// * Keep the address tables in-memory, and asynchronously dump the entire to able in addr.dat. * * Make sure no (localized) attacker can fill the entire table with his nodes/addresses.
// * Make sure no (localized) attacker can fill the entire table with his nodes/addresses. *
// * To that end:
// To that end: * * Addresses are organized into buckets.
// * Addresses are organized into buckets. * * Address that have not yet been tried go into 256 "new" buckets.
// * Address that have not yet been tried go into 256 "new" buckets. * * Based on the address range (/16 for IPv4) of source of the information, 32 buckets are selected at random
// * Based on the address range (/16 for IPv4) of source of the information, 32 buckets are selected at random * * The actual bucket is chosen from one of these, based on the range the address itself is located.
// * The actual bucket is chosen from one of these, based on the range the address itself is located. * * One single address can occur in up to 4 different buckets, to increase selection chances for addresses that
// * One single address can occur in up to 4 different buckets, to increase selection chances for addresses that * are seen frequently. The chance for increasing this multiplicity decreases exponentially.
// are seen frequently. The chance for increasing this multiplicity decreases exponentially. * * When adding a new address to a full bucket, a randomly chosen entry (with a bias favoring less recently seen
// * When adding a new address to a full bucket, a randomly chosen entry (with a bias favoring less recently seen * ones) is removed from it first.
// ones) is removed from it first. * * Addresses of nodes that are known to be accessible go into 64 "tried" buckets.
// * Addresses of nodes that are known to be accessible go into 64 "tried" buckets. * * Each address range selects at random 4 of these buckets.
// * Each address range selects at random 4 of these buckets. * * The actual bucket is chosen from one of these, based on the full address.
// * The actual bucket is chosen from one of these, based on the full address. * * When adding a new good address to a full bucket, a randomly chosen entry (with a bias favoring less recently
// * When adding a new good address to a full bucket, a randomly chosen entry (with a bias favoring less recently * tried ones) is evicted from it, back to the "new" buckets.
// tried ones) is evicted from it, back to the "new" buckets. * * Bucket selection is based on cryptographic hashing, using a randomly-generated 256-bit key, which should not
// * Bucket selection is based on cryptographic hashing, using a randomly-generated 256-bit key, which should not * be observable by adversaries.
// be observable by adversaries. * * Several indexes are kept for high performance. Defining DEBUG_ADDRMAN will introduce frequent (and expensive)
// * Several indexes are kept for high performance. Defining DEBUG_ADDRMAN will introduce frequent (and expensive) * consistency checks for the entire data structure.
// consistency checks for the entire data structure. */
// total number of buckets for tried addresses //! total number of buckets for tried addresses
#define ADDRMAN_TRIED_BUCKET_COUNT 64 #define ADDRMAN_TRIED_BUCKET_COUNT 64
// maximum allowed number of entries in buckets for tried addresses //! maximum allowed number of entries in buckets for tried addresses
#define ADDRMAN_TRIED_BUCKET_SIZE 64 #define ADDRMAN_TRIED_BUCKET_SIZE 64
// total number of buckets for new addresses //! total number of buckets for new addresses
#define ADDRMAN_NEW_BUCKET_COUNT 256 #define ADDRMAN_NEW_BUCKET_COUNT 256
// maximum allowed number of entries in buckets for new addresses //! maximum allowed number of entries in buckets for new addresses
#define ADDRMAN_NEW_BUCKET_SIZE 64 #define ADDRMAN_NEW_BUCKET_SIZE 64
// over how many buckets entries with tried addresses from a single group (/16 for IPv4) are spread //! over how many buckets entries with tried addresses from a single group (/16 for IPv4) are spread
#define ADDRMAN_TRIED_BUCKETS_PER_GROUP 4 #define ADDRMAN_TRIED_BUCKETS_PER_GROUP 4
// over how many buckets entries with new addresses originating from a single group are spread //! over how many buckets entries with new addresses originating from a single group are spread
#define ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP 32 #define ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP 32
// in how many buckets for entries with new addresses a single address may occur //! in how many buckets for entries with new addresses a single address may occur
#define ADDRMAN_NEW_BUCKETS_PER_ADDRESS 4 #define ADDRMAN_NEW_BUCKETS_PER_ADDRESS 4
// how many entries in a bucket with tried addresses are inspected, when selecting one to replace //! how many entries in a bucket with tried addresses are inspected, when selecting one to replace
#define ADDRMAN_TRIED_ENTRIES_INSPECT_ON_EVICT 4 #define ADDRMAN_TRIED_ENTRIES_INSPECT_ON_EVICT 4
// how old addresses can maximally be //! how old addresses can maximally be
#define ADDRMAN_HORIZON_DAYS 30 #define ADDRMAN_HORIZON_DAYS 30
// after how many failed attempts we give up on a new node //! after how many failed attempts we give up on a new node
#define ADDRMAN_RETRIES 3 #define ADDRMAN_RETRIES 3
// how many successive failures are allowed ... //! how many successive failures are allowed ...
#define ADDRMAN_MAX_FAILURES 10 #define ADDRMAN_MAX_FAILURES 10
// ... in at least this many days //! ... in at least this many days
#define ADDRMAN_MIN_FAIL_DAYS 7 #define ADDRMAN_MIN_FAIL_DAYS 7
// the maximum percentage of nodes to return in a getaddr call //! the maximum percentage of nodes to return in a getaddr call
#define ADDRMAN_GETADDR_MAX_PCT 23 #define ADDRMAN_GETADDR_MAX_PCT 23
// the maximum number of nodes to return in a getaddr call //! the maximum number of nodes to return in a getaddr call
#define ADDRMAN_GETADDR_MAX 2500 #define ADDRMAN_GETADDR_MAX 2500
/** Stochastical (IP) address manager */ /**
* Stochastical (IP) address manager
*/
class CAddrMan class CAddrMan
{ {
private: private:
// critical section to protect the inner data structures //! critical section to protect the inner data structures
mutable CCriticalSection cs; mutable CCriticalSection cs;
// secret key to randomize bucket select with //! secret key to randomize bucket select with
std::vector<unsigned char> nKey; std::vector<unsigned char> nKey;
// last used nId //! last used nId
int nIdCount; int nIdCount;
// table with information about all nIds //! table with information about all nIds
std::map<int, CAddrInfo> mapInfo; std::map<int, CAddrInfo> mapInfo;
// find an nId based on its network address //! find an nId based on its network address
std::map<CNetAddr, int> mapAddr; std::map<CNetAddr, int> mapAddr;
// randomly-ordered vector of all nIds //! randomly-ordered vector of all nIds
std::vector<int> vRandom; std::vector<int> vRandom;
// number of "tried" entries // number of "tried" entries
int nTried; int nTried;
// list of "tried" buckets //! list of "tried" buckets
std::vector<std::vector<int> > vvTried; std::vector<std::vector<int> > vvTried;
// number of (unique) "new" entries //! number of (unique) "new" entries
int nNew; int nNew;
// list of "new" buckets //! list of "new" buckets
std::vector<std::set<int> > vvNew; std::vector<std::set<int> > vvNew;
protected: protected:
// Find an entry. //! Find an entry.
CAddrInfo* Find(const CNetAddr& addr, int *pnId = NULL); CAddrInfo* Find(const CNetAddr& addr, int *pnId = NULL);
// find an entry, creating it if necessary. //! find an entry, creating it if necessary.
// nTime and nServices of found node is updated, if necessary. //! nTime and nServices of the found node are updated, if necessary.
CAddrInfo* Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId = NULL); CAddrInfo* Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId = NULL);
// Swap two elements in vRandom. //! Swap two elements in vRandom.
void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2); void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2);
// Return position in given bucket to replace. //! Return position in given bucket to replace.
int SelectTried(int nKBucket); int SelectTried(int nKBucket);
// Remove an element from a "new" bucket. //! Remove an element from a "new" bucket.
// This is the only place where actual deletes occur. //! This is the only place where actual deletions occur.
// They are never deleted while in the "tried" table, only possibly evicted back to the "new" table. //! Elements are never deleted while in the "tried" table, only possibly evicted back to the "new" table.
int ShrinkNew(int nUBucket); int ShrinkNew(int nUBucket);
// Move an entry from the "new" table(s) to the "tried" table //! Move an entry from the "new" table(s) to the "tried" table
// @pre vvUnkown[nOrigin].count(nId) != 0 //! @pre vvUnkown[nOrigin].count(nId) != 0
void MakeTried(CAddrInfo& info, int nId, int nOrigin); void MakeTried(CAddrInfo& info, int nId, int nOrigin);
// Mark an entry "good", possibly moving it from "new" to "tried". //! Mark an entry "good", possibly moving it from "new" to "tried".
void Good_(const CService &addr, int64_t nTime); void Good_(const CService &addr, int64_t nTime);
// Add an entry to the "new" table. //! Add an entry to the "new" table.
bool Add_(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty); bool Add_(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty);
// Mark an entry as attempted to connect. //! Mark an entry as attempted to connect.
void Attempt_(const CService &addr, int64_t nTime); void Attempt_(const CService &addr, int64_t nTime);
// Select an address to connect to. //! Select an address to connect to.
// nUnkBias determines how much to favor new addresses over tried ones (min=0, max=100) //! nUnkBias determines how much to favor new addresses over tried ones (min=0, max=100)
CAddress Select_(int nUnkBias); CAddress Select_(int nUnkBias);
#ifdef DEBUG_ADDRMAN #ifdef DEBUG_ADDRMAN
// Perform consistency check. Returns an error code or zero. //! Perform consistency check. Returns an error code or zero.
int Check_(); int Check_();
#endif #endif
// Select several addresses at once. //! Select several addresses at once.
void GetAddr_(std::vector<CAddress> &vAddr); void GetAddr_(std::vector<CAddress> &vAddr);
// Mark an entry as currently-connected-to. //! Mark an entry as currently-connected-to.
void Connected_(const CService &addr, int64_t nTime); void Connected_(const CService &addr, int64_t nTime);
public: public:
// serialized format: /**
// * version byte (currently 0) * serialized format:
// * nKey * * version byte (currently 0)
// * nNew * * nKey
// * nTried * * nNew
// * number of "new" buckets * * nTried
// * all nNew addrinfos in vvNew * * number of "new" buckets
// * all nTried addrinfos in vvTried * * all nNew addrinfos in vvNew
// * for each bucket: * * all nTried addrinfos in vvTried
// * number of elements * * for each bucket:
// * for each element: index * * number of elements
// * * for each element: index
// Notice that vvTried, mapAddr and vVector are never encoded explicitly; *
// they are instead reconstructed from the other information. * Notice that vvTried, mapAddr and vVector are never encoded explicitly;
// * they are instead reconstructed from the other information.
// vvNew is serialized, but only used if ADDRMAN_UNKOWN_BUCKET_COUNT didn't change, *
// otherwise it is reconstructed as well. * vvNew is serialized, but only used if ADDRMAN_UNKOWN_BUCKET_COUNT didn't change,
// * otherwise it is reconstructed as well.
// 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. * 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 ADD_SERIALIZE_METHODS since the serialization and deserialization code has *
// very little in common. * We don't use ADD_SERIALIZE_METHODS since the serialization and deserialization code has
* very little in common.
*
*/
template<typename Stream> template<typename Stream>
void Serialize(Stream &s, int nType, int nVersionDummy) const void Serialize(Stream &s, int nType, int nVersionDummy) const
{ {
@ -394,13 +401,13 @@ public:
nNew = 0; nNew = 0;
} }
// Return the number of (unique) addresses in all tables. //! Return the number of (unique) addresses in all tables.
int size() int size()
{ {
return vRandom.size(); return vRandom.size();
} }
// Consistency check //! Consistency check
void Check() void Check()
{ {
#ifdef DEBUG_ADDRMAN #ifdef DEBUG_ADDRMAN
@ -413,7 +420,7 @@ public:
#endif #endif
} }
// Add a single address. //! Add a single address.
bool Add(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty = 0) bool Add(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty = 0)
{ {
bool fRet = false; bool fRet = false;
@ -428,7 +435,7 @@ public:
return fRet; return fRet;
} }
// Add multiple addresses. //! Add multiple addresses.
bool Add(const std::vector<CAddress> &vAddr, const CNetAddr& source, int64_t nTimePenalty = 0) bool Add(const std::vector<CAddress> &vAddr, const CNetAddr& source, int64_t nTimePenalty = 0)
{ {
int nAdd = 0; int nAdd = 0;
@ -444,7 +451,7 @@ public:
return nAdd > 0; return nAdd > 0;
} }
// Mark an entry as accessible. //! Mark an entry as accessible.
void Good(const CService &addr, int64_t nTime = GetAdjustedTime()) void Good(const CService &addr, int64_t nTime = GetAdjustedTime())
{ {
{ {
@ -455,7 +462,7 @@ public:
} }
} }
// Mark an entry as connection attempted to. //! Mark an entry as connection attempted to.
void Attempt(const CService &addr, int64_t nTime = GetAdjustedTime()) void Attempt(const CService &addr, int64_t nTime = GetAdjustedTime())
{ {
{ {
@ -466,8 +473,10 @@ public:
} }
} }
// Choose an address to connect to. /**
// nUnkBias determines how much "new" entries are favored over "tried" ones (0-100). * Choose an address to connect to.
* nUnkBias determines how much "new" entries are favored over "tried" ones (0-100).
*/
CAddress Select(int nUnkBias = 50) CAddress Select(int nUnkBias = 50)
{ {
CAddress addrRet; CAddress addrRet;
@ -480,7 +489,7 @@ public:
return addrRet; return addrRet;
} }
// Return a bunch of addresses, selected at random. //! Return a bunch of addresses, selected at random.
std::vector<CAddress> GetAddr() std::vector<CAddress> GetAddr()
{ {
Check(); Check();
@ -493,7 +502,7 @@ public:
return vAddr; return vAddr;
} }
// Mark an entry as currently-connected-to. //! Mark an entry as currently-connected-to.
void Connected(const CService &addr, int64_t nTime = GetAdjustedTime()) void Connected(const CService &addr, int64_t nTime = GetAdjustedTime())
{ {
{ {

Loading…
Cancel
Save