diff --git a/bitcoin.cpp b/bitcoin.cpp index 967e905..4602d25 100644 --- a/bitcoin.cpp +++ b/bitcoin.cpp @@ -81,7 +81,7 @@ class CNode { } void GotVersion() { - // printf("%s: version %i\n", ToString(you).c_str(), nVersion); + // printf("\n%s: version %i\n", ToString(you).c_str(), nVersion); BeginMessage("getaddr"); EndMessage(); doneAfter = time(NULL) + 10; @@ -256,9 +256,13 @@ public: int GetClientVersion() { return nVersion; } + + std::string GetClientSubVersion() { + return strSubVer; + } }; -bool TestNode(const CIPPort &cip, int &ban, int &clientV, vector& vAddr) { +bool TestNode(const CIPPort &cip, int &ban, int &clientV, std::string &clientSV, vector& vAddr) { try { CNode node(cip, vAddr); bool ret = node.Run(); @@ -268,6 +272,7 @@ bool TestNode(const CIPPort &cip, int &ban, int &clientV, vector& vAdd ban = 0; } clientV = node.GetClientVersion(); + clientSV = node.GetClientSubVersion(); // printf("%s: %s!!!\n", cip.ToString().c_str(), ret ? "GOOD" : "BAD"); return ret; } catch(std::ios_base::failure& e) { diff --git a/bitcoin.h b/bitcoin.h index 04f3c07..1258b80 100644 --- a/bitcoin.h +++ b/bitcoin.h @@ -3,6 +3,6 @@ #include "protocol.h" -bool TestNode(const CIPPort &cip, int &ban, int &client, std::vector& vAddr); +bool TestNode(const CIPPort &cip, int &ban, int &client, std::string &clientSV, std::vector& vAddr); #endif diff --git a/db.cpp b/db.cpp index a3dfb5b..3284035 100644 --- a/db.cpp +++ b/db.cpp @@ -16,6 +16,7 @@ void CAddrInfo::Update(bool good) { stat8H.Update(good, age, 3600*8); stat1D.Update(good, age, 3600*24); stat1W.Update(good, age, 3600*24*7); + stat1M.Update(good, age, 3600*24*30); int ign = GetIgnoreTime(); if (ign && (ignoreTill==0 || ignoreTill < ign+now)) ignoreTill = ign+now; // printf("%s: got %s result: success=%i/%i; 2H:%.2f%%-%.2f%%(%.2f) 8H:%.2f%%-%.2f%%(%.2f) 1D:%.2f%%-%.2f%%(%.2f) 1W:%.2f%%-%.2f%%(%.2f) \n", ToString(ip).c_str(), good ? "good" : "bad", success, total, @@ -83,13 +84,14 @@ int CAddrDb::Lookup_(const CIPPort &ip) { return -1; } -void CAddrDb::Good_(const CIPPort &addr, int clientV) { +void CAddrDb::Good_(const CIPPort &addr, int clientV, std::string clientSV) { int id = Lookup_(addr); if (id == -1) return; unkId.erase(id); banned.erase(addr); CAddrInfo &info = idToInfo[id]; info.clientVersion = clientV; + info.clientSubVersion = clientSV; info.Update(true); if (info.IsGood() && goodId.count(id)==0) { goodId.insert(id); diff --git a/db.h b/db.h index c379f9e..73e664c 100644 --- a/db.h +++ b/db.h @@ -46,6 +46,8 @@ class CAddrReport { public: CIPPort ip; int clientVersion; + double uptime[5]; + std::string clientSubVersion; }; @@ -60,9 +62,11 @@ private: CAddrStat stat8H; CAddrStat stat1D; CAddrStat stat1W; + CAddrStat stat1M; int clientVersion; int total; int success; + std::string clientSubVersion; public: CAddrInfo() : services(0), lastTry(0), ourLastTry(0), ignoreTill(0), clientVersion(0), total(0), success(0) {} @@ -70,6 +74,12 @@ public: CAddrReport ret; ret.ip = ip; ret.clientVersion = clientVersion; + ret.clientSubVersion = clientSubVersion; + ret.uptime[0] = stat2H.reliability; + ret.uptime[1] = stat8H.reliability; + ret.uptime[2] = stat1D.reliability; + ret.uptime[3] = stat1W.reliability; + ret.uptime[4] = stat1M.reliability; return ret; } @@ -109,7 +119,7 @@ public: friend class CAddrDb; IMPLEMENT_SERIALIZE ( - unsigned char version = 0; + unsigned char version = 2; READWRITE(version); READWRITE(ip); READWRITE(services); @@ -123,9 +133,16 @@ public: READWRITE(stat8H); READWRITE(stat1D); READWRITE(stat1W); + if (version >= 1) + READWRITE(stat1M); + else + if (!fWrite) + *((CAddrStat*)(&stat1M)) = stat1W; READWRITE(total); READWRITE(success); READWRITE(clientVersion); + if (version >= 2) + READWRITE(clientSubVersion); } ) }; @@ -157,20 +174,20 @@ private: std::deque ourId; // sequence of tried nodes, in order we have tried connecting to them (c,d) std::set unkId; // set of nodes not yet tried (b) std::set goodId; // set of good nodes (d, good e) - std::map banned; // nodes that are banned, with their unban time (a) int nDirty; protected: // internal routines that assume proper locks are acquired void Add_(const CAddress &addr, bool force); // add an address bool Get_(CIPPort &ip, int& wait); // get an IP to test (must call Good_, Bad_, or Skipped_ on result afterwards) - void Good_(const CIPPort &ip, int clientV); // mark an IP as good (must have been returned by Get_) + void Good_(const CIPPort &ip, int clientV, std::string clientSV); // mark an IP as good (must have been returned by Get_) void Bad_(const CIPPort &ip, int ban); // mark an IP as bad (and optionally ban it) (must have been returned by Get_) void Skipped_(const CIPPort &ip); // mark an IP as skipped (must have been returned by Get_) int Lookup_(const CIPPort &ip); // look up id of an IP void GetIPs_(std::set& ips, int max, bool fOnlyIPv4); // get a random set of IPs (shared lock only) public: + std::map banned; // nodes that are banned, with their unban time (a) void GetStats(CAddrDbStats &stats) { SHARED_CRITICAL_BLOCK(cs) { @@ -255,9 +272,9 @@ public: for (int i=0; i + #include #include #include @@ -105,10 +107,11 @@ extern "C" void* ThreadCrawler(void* data) { int ban = 0; vector addr; int clientV = 0; - bool ret = TestNode(ip,ban,clientV,addr); + std::string clientSV; + bool ret = TestNode(ip,ban,clientV,clientSV,addr); db.Add(addr); if (ret) { - db.Good(ip, clientV); + db.Good(ip, clientV, clientSV); } else { db.Bad(ip, ban); } @@ -150,6 +153,18 @@ extern "C" void* ThreadDNS(void* arg) { dnsserver(&dns_opt); } +int StatCompare(const CAddrReport& a, const CAddrReport& b) { + if (a.uptime[4] == b.uptime[4]) { + if (a.uptime[3] == b.uptime[3]) { + return a.clientVersion > b.clientVersion; + } else { + return a.uptime[3] > b.uptime[3]; + } + } else { + return a.uptime[4] > b.uptime[4]; + } +} + extern "C" void* ThreadDumper(void*) { do { Sleep(100000); @@ -159,16 +174,28 @@ extern "C" void* ThreadDumper(void*) { CAutoFile cf(f); cf << db; } + FILE *d = fopen("dnsseed.dump", "w"); + vector v = db.GetAll(); + sort(v.begin(), v.end(), StatCompare); + for (vector::const_iterator it = v.begin(); it < v.end(); it++) { + CAddrReport rep = *it; + fprintf(d, "%s\t%.2f%%\t%.2f%%\t%.2f%%\t%.2f%%\t%.2f%%\t%i \"%s\"\n", rep.ip.ToString().c_str(), 100.0*rep.uptime[0], 100.0*rep.uptime[1], 100.0*rep.uptime[2], 100.0*rep.uptime[3], 100.0*rep.uptime[4], rep.clientVersion, rep.clientSubVersion.c_str()); + } + fclose(d); } } while(1); } extern "C" void* ThreadStats(void*) { do { + char c[256]; + time_t tim = time(NULL); + struct tm *tmp = localtime(&tim); + strftime(c, 256, "[%y-%m-%d %H:%M:%S]", tmp); CAddrDbStats stats; db.GetStats(stats); printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); - printf("*** %i/%i available (%i tried in %is, %i new, %i active), %i banned; %llu DNS requests", stats.nGood, stats.nAvail, stats.nTracked, stats.nAge, stats.nNew, stats.nAvail - stats.nTracked - stats.nNew, stats.nBanned, (unsigned long long)dns_opt.nRequests); + printf("%s %i/%i available (%i tried in %is, %i new, %i active), %i banned; %llu DNS requests", c, stats.nGood, stats.nAvail, stats.nTracked, stats.nAge, stats.nNew, stats.nAvail - stats.nTracked - stats.nNew, stats.nBanned, (unsigned long long)dns_opt.nRequests); Sleep(1000); } while(1); } @@ -205,13 +232,7 @@ int main(int argc, char **argv) { printf("Loading dnsseed.dat..."); CAutoFile cf(f); cf >> db; -// FILE *d = fopen("dnsseed.dump", "w"); -// vector v = db.GetAll(); -// for (vector::const_iterator it = v.begin(); it < v.end(); it++) { -// CAddrReport rep = *it; -// fprintf(d, "%s %i\n", rep.ip.ToString().c_str(), rep.clientVersion); -// } -// fclose(d); +// db.banned.clear(); printf("done\n"); } pthread_t threadDns, threadSeed, threadDump, threadStats;