13 #define MIN_RETRY 1000
15 std::string static inline ToString(const CService &ip) {
16 std::string str = ip.ToString();
17 while (str.size() < 22) str += ' ';
27 CAddrStat() : weight(0), count(0), reliability(0) {}
29 void Update(bool good, int64 age, double tau) {
30 double f = exp(-age/tau);
31 reliability = reliability * f + (good ? (1.0-f) : 0);
32 count = count * f + 1;
33 weight = weight * f + (1.0-f);
39 READWRITE(reliability);
42 friend class CAddrInfo;
51 std::string clientSubVersion;
71 std::string clientSubVersion;
73 CAddrInfo() : services(0), lastTry(0), ourLastTry(0), ignoreTill(0), clientVersion(0), blocks(0), total(0), success(0) {}
75 CAddrReport GetReport() const {
78 ret.clientVersion = clientVersion;
79 ret.clientSubVersion = clientSubVersion;
81 ret.uptime[0] = stat2H.reliability;
82 ret.uptime[1] = stat8H.reliability;
83 ret.uptime[2] = stat1D.reliability;
84 ret.uptime[3] = stat1W.reliability;
85 ret.uptime[4] = stat1M.reliability;
90 if (ip.GetPort() != ::nP2Port) return false;
91 if (!(services & NODE_NETWORK)) return false;
92 if (!ip.IsRoutable()) return false;
93 if (clientVersion && clientVersion < 32400) return false;
95 if (total <= 3 && success * 2 >= total) return true;
97 if (stat2H.reliability > 0.85 && stat2H.count > 2) return true;
98 if (stat8H.reliability > 0.70 && stat8H.count > 4) return true;
99 if (stat1D.reliability > 0.55 && stat1D.count > 8) return true;
100 if (stat1W.reliability > 0.45 && stat1W.count > 16) return true;
101 if (stat1M.reliability > 0.35 && stat1M.count > 32) return true;
105 int GetBanTime() const {
106 if (IsGood()) return 0;
107 if (clientVersion && clientVersion < 31900) { return 604800; }
110 int GetIgnoreTime() const {
111 if (IsGood()) return 0;
112 if (stat1M.reliability - stat1M.weight + 1.0 < 0.08 && stat1D.count > 48) { return 8*3600; }
113 if (stat1W.reliability - stat1W.weight + 1.0 < 0.12 && stat8H.count > 24) { return 4*3600; }
114 if (stat1D.reliability - stat1D.weight + 1.0 < 0.16 && stat1D.count > 12) { return 2*3600; }
115 if (stat8H.reliability - stat8H.weight + 1.0 < 0.20 && stat8H.count > 6) { return 1*3600; }
119 void Update(bool good);
121 friend class CAddrDb;
123 IMPLEMENT_SERIALIZE (
124 unsigned char version = 3;
129 unsigned char tried = ourLastTry != 0;
132 READWRITE(ourLastTry);
133 READWRITE(ignoreTill);
142 *((CAddrStat*)(&stat1M)) = stat1W;
145 READWRITE(clientVersion);
147 READWRITE(clientSubVersion);
166 // (a) banned nodes available nodes--------------
168 // tracked nodes (b) unknown nodes (e) active nodes
170 // (d) good nodes (c) non-good nodes
174 mutable CCriticalSection cs;
175 int nId; // number of address id's
176 std::map<int, CAddrInfo> idToInfo; // map address id to address info (b,c,d,e)
177 std::map<CService, int> ipToId; // map ip to id (b,c,d,e)
178 std::deque<int> ourId; // sequence of tried nodes, in order we have tried connecting to them (c,d)
179 std::set<int> unkId; // set of nodes not yet tried (b)
180 std::set<int> goodId; // set of good nodes (d, good e)
184 // internal routines that assume proper locks are acquired
185 void Add_(const CAddress &addr, bool force); // add an address
186 bool Get_(CService &ip, int& wait); // get an IP to test (must call Good_, Bad_, or Skipped_ on result afterwards)
187 void Good_(const CService &ip, int clientV, std::string clientSV, int blocks); // mark an IP as good (must have been returned by Get_)
188 void Bad_(const CService &ip, int ban); // mark an IP as bad (and optionally ban it) (must have been returned by Get_)
189 void Skipped_(const CService &ip); // mark an IP as skipped (must have been returned by Get_)
190 int Lookup_(const CService &ip); // look up id of an IP
191 void GetIPs_(std::set<CNetAddr>& ips, int max, const bool *nets); // get a random set of IPs (shared lock only)
194 std::map<CService, time_t> banned; // nodes that are banned, with their unban time (a)
196 void GetStats(CAddrDbStats &stats) {
197 SHARED_CRITICAL_BLOCK(cs) {
198 stats.nBanned = banned.size();
199 stats.nAvail = idToInfo.size();
200 stats.nTracked = ourId.size();
201 stats.nGood = goodId.size();
202 stats.nNew = unkId.size();
203 stats.nAge = time(NULL) - idToInfo[ourId[0]].ourLastTry;
207 void ResetIgnores() {
208 for (std::map<int, CAddrInfo>::iterator it = idToInfo.begin(); it != idToInfo.end(); it++) {
209 (*it).second.ignoreTill = 0;
213 std::vector<CAddrReport> GetAll() {
214 std::vector<CAddrReport> ret;
215 SHARED_CRITICAL_BLOCK(cs) {
216 for (std::deque<int>::const_iterator it = ourId.begin(); it != ourId.end(); it++) {
217 const CAddrInfo &info = idToInfo[*it];
218 if (info.success > 0) {
219 ret.push_back(info.GetReport());
226 // serialization code
228 // nVersion (0 for now)
229 // n (number of ips in (b,c,d))
232 // acquires a shared lock (this does not suffice for read mode, but we assume that only happens at startup, single-threaded)
233 // this way, dumping does not interfere with GetIPs_, which is called from the DNS thread
234 IMPLEMENT_SERIALIZE (({
237 SHARED_CRITICAL_BLOCK(cs) {
239 CAddrDb *db = const_cast<CAddrDb*>(this);
240 int n = ourId.size() + unkId.size();
242 for (std::deque<int>::const_iterator it = ourId.begin(); it != ourId.end(); it++) {
243 std::map<int, CAddrInfo>::iterator ci = db->idToInfo.find(*it);
244 READWRITE((*ci).second);
246 for (std::set<int>::const_iterator it = unkId.begin(); it != unkId.end(); it++) {
247 std::map<int, CAddrInfo>::iterator ci = db->idToInfo.find(*it);
248 READWRITE((*ci).second);
251 CAddrDb *db = const_cast<CAddrDb*>(this);
255 for (int i=0; i<n; i++) {
258 if (!info.GetBanTime()) {
260 db->idToInfo[id] = info;
261 db->ipToId[info.ip] = id;
262 if (info.ourLastTry) {
263 db->ourId.push_back(id);
264 if (info.IsGood()) db->goodId.insert(id);
266 db->unkId.insert(id);
276 void Add(const CAddress &addr, bool fForce = false) {
280 void Add(const std::vector<CAddress> &vAddr, bool fForce = false) {
282 for (int i=0; i<vAddr.size(); i++)
283 Add_(vAddr[i], fForce);
285 void Good(const CService &addr, int clientVersion, std::string clientSubVersion, int blocks) {
287 Good_(addr, clientVersion, clientSubVersion, blocks);
289 void Skipped(const CService &addr) {
293 void Bad(const CService &addr, int ban = 0) {
297 bool Get(CService &ip, int& wait) {
299 return Get_(ip, wait);
301 void GetIPs(std::set<CNetAddr>& ips, int max, const bool *nets) {
302 SHARED_CRITICAL_BLOCK(cs)
303 GetIPs_(ips, max, nets);