Merge pull request #5131

24f5c94 Update comments in addrman to be doxygen compatible (Michael Ford)
c772f4c Add doc/doxygen to .gitignore (Michael Ford)
This commit is contained in:
Wladimir J. van der Laan 2014-10-25 09:10:12 +02:00
commit b847e0139e
No known key found for this signature in database
GPG key ID: 74810B012346C9A6
3 changed files with 129 additions and 118 deletions

2
.gitignore vendored
View file

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

View file

@ -1,5 +1,5 @@
// 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.
#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
{
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;
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];
// 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
int64_t nOldest = -1;
int nOldestPos = -1;
@ -211,7 +211,7 @@ void CAddrMan::MakeTried(CAddrInfo& info, int nId, int nOrigin)
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);
std::vector<int>& vTried = vvTried[nKBucket];

View file

@ -1,5 +1,5 @@
// 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.
#ifndef _BITCOIN_ADDRMAN
@ -17,29 +17,31 @@
#include <stdint.h>
#include <vector>
/** Extended statistics about a CAddress */
/**
* Extended statistics about a CAddress
*/
class CAddrInfo : public CAddress
{
private:
// where knowledge about this address first came from
//! where knowledge about this address first came from
CNetAddr source;
// last successful connection by us
//! last successful connection by us
int64_t nLastSuccess;
// last try whatsoever by us:
//! last try whatsoever by us:
// int64_t CAddress::nLastTry
// connection attempts since last successful attempt
//! connection attempts since last successful attempt
int nAttempts;
// reference count in new sets (memory only)
//! reference count in new sets (memory only)
int nRefCount;
// in tried set? (memory only)
//! in tried set? (memory only)
bool fInTried;
// position in vRandom
//! position in vRandom
int nRandomPos;
friend class CAddrMan;
@ -76,200 +78,205 @@ public:
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;
// 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;
// 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
{
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;
// 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;
};
// Stochastic address manager
//
// 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 addr.dat.
// * Make sure no (localized) attacker can fill the entire table with his nodes/addresses.
//
// To that end:
// * Addresses are organized into 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
// * 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
// 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
// ones) is removed from it first.
// * Addresses of nodes that are known to be accessible go into 64 "tried" 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.
// * 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.
// * Bucket selection is based on cryptographic hashing, using a randomly-generated 256-bit key, which should not
// be observable by adversaries.
// * Several indexes are kept for high performance. Defining DEBUG_ADDRMAN will introduce frequent (and expensive)
// consistency checks for the entire data structure.
/** Stochastic address manager
*
* Design goals:
* * Keep the address tables in-memory, and asynchronously dump the entire to able in peers.dat.
* * Make sure no (localized) attacker can fill the entire table with his nodes/addresses.
*
* To that end:
* * Addresses are organized into 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
* * 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
* 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
* ones) is removed from it first.
* * Addresses of nodes that are known to be accessible go into 64 "tried" 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.
* * 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.
* * Bucket selection is based on cryptographic hashing, using a randomly-generated 256-bit key, which should not
* be observable by adversaries.
* * Several indexes are kept for high performance. Defining DEBUG_ADDRMAN will introduce frequent (and expensive)
* 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
// 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
// total number of buckets for new addresses
//! total number of buckets for new addresses
#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
// 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
// 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
// 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
// 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
// how old addresses can maximally be
//! how old addresses can maximally be
#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
// how many successive failures are allowed ...
//! how many successive failures are allowed ...
#define ADDRMAN_MAX_FAILURES 10
// ... in at least this many days
//! ... in at least this many days
#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
// 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
/** Stochastical (IP) address manager */
/**
* Stochastical (IP) address manager
*/
class CAddrMan
{
private:
// critical section to protect the inner data structures
//! critical section to protect the inner data structures
mutable CCriticalSection cs;
// secret key to randomize bucket select with
//! secret key to randomize bucket select with
std::vector<unsigned char> nKey;
// last used nId
//! last used nId
int nIdCount;
// table with information about all nIds
//! table with information about all nIds
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;
// randomly-ordered vector of all nIds
//! randomly-ordered vector of all nIds
std::vector<int> vRandom;
// number of "tried" entries
int nTried;
// list of "tried" buckets
//! list of "tried" buckets
std::vector<std::vector<int> > vvTried;
// number of (unique) "new" entries
//! number of (unique) "new" entries
int nNew;
// list of "new" buckets
//! list of "new" buckets
std::vector<std::set<int> > vvNew;
protected:
// Find an entry.
//! Find an entry.
CAddrInfo* Find(const CNetAddr& addr, int *pnId = NULL);
// find an entry, creating it if necessary.
// nTime and nServices of found node is updated, if necessary.
//! find an entry, creating it if necessary.
//! nTime and nServices of the found node are updated, if necessary.
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);
// Return position in given bucket to replace.
//! Return position in given bucket to replace.
int SelectTried(int nKBucket);
// Remove an element from a "new" bucket.
// This is the only place where actual deletes occur.
// They are never deleted while in the "tried" table, only possibly evicted back to the "new" table.
//! Remove an element from a "new" bucket.
//! This is the only place where actual deletions occur.
//! Elements are never deleted while in the "tried" table, only possibly evicted back to the "new" table.
int ShrinkNew(int nUBucket);
// Move an entry from the "new" table(s) to the "tried" table
// @pre vvUnkown[nOrigin].count(nId) != 0
//! Move an entry from the "new" table(s) to the "tried" table
//! @pre vvUnkown[nOrigin].count(nId) != 0
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);
// 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);
// Mark an entry as attempted to connect.
//! Mark an entry as attempted to connect.
void Attempt_(const CService &addr, int64_t nTime);
// Select an address to connect to.
// nUnkBias determines how much to favor new addresses over tried ones (min=0, max=100)
//! Select an address to connect to.
//! nUnkBias determines how much to favor new addresses over tried ones (min=0, max=100)
CAddress Select_(int nUnkBias);
#ifdef DEBUG_ADDRMAN
// Perform consistency check. Returns an error code or zero.
//! Perform consistency check. Returns an error code or zero.
int Check_();
#endif
// Select several addresses at once.
//! Select several addresses at once.
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);
public:
// serialized format:
// * version byte (currently 0)
// * nKey
// * nNew
// * nTried
// * number of "new" buckets
// * all nNew addrinfos in vvNew
// * all nTried addrinfos in vvTried
// * for each bucket:
// * 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.
//
// 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.
//
// We don't use ADD_SERIALIZE_METHODS since the serialization and deserialization code has
// very little in common.
/**
* serialized format:
* * version byte (currently 0)
* * nKey
* * nNew
* * nTried
* * number of "new" buckets
* * all nNew addrinfos in vvNew
* * all nTried addrinfos in vvTried
* * for each bucket:
* * 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.
*
* 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.
*
* We don't use ADD_SERIALIZE_METHODS since the serialization and deserialization code has
* very little in common.
*
*/
template<typename Stream>
void Serialize(Stream &s, int nType, int nVersionDummy) const
{
@ -394,13 +401,13 @@ public:
nNew = 0;
}
// Return the number of (unique) addresses in all tables.
//! Return the number of (unique) addresses in all tables.
int size()
{
return vRandom.size();
}
// Consistency check
//! Consistency check
void Check()
{
#ifdef DEBUG_ADDRMAN
@ -413,7 +420,7 @@ public:
#endif
}
// Add a single address.
//! Add a single address.
bool Add(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty = 0)
{
bool fRet = false;
@ -428,7 +435,7 @@ public:
return fRet;
}
// Add multiple addresses.
//! Add multiple addresses.
bool Add(const std::vector<CAddress> &vAddr, const CNetAddr& source, int64_t nTimePenalty = 0)
{
int nAdd = 0;
@ -444,7 +451,7 @@ public:
return nAdd > 0;
}
// Mark an entry as accessible.
//! Mark an entry as accessible.
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())
{
{
@ -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 addrRet;
@ -480,7 +489,7 @@ public:
return addrRet;
}
// Return a bunch of addresses, selected at random.
//! Return a bunch of addresses, selected at random.
std::vector<CAddress> GetAddr()
{
Check();
@ -493,7 +502,7 @@ public:
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())
{
{