diff --git a/src/seeder/bitcoin.cpp b/src/seeder/bitcoin.cpp index f9f2238f6c..de99ba67d3 100644 --- a/src/seeder/bitcoin.cpp +++ b/src/seeder/bitcoin.cpp @@ -1,321 +1,321 @@ #include "bitcoin.h" #include "db.h" #include "netbase.h" #include "serialize.h" #include "uint256.h" #include #define BITCOIN_SEED_NONCE 0x0539a019ca550825ULL class CNode { SOCKET sock; CDataStream vSend; CDataStream vRecv; unsigned int nHeaderStart; unsigned int nMessageStart; int nVersion; std::string strSubVer; int nStartingHeight; std::vector *vAddr; int ban; - int64 doneAfter; + int64_t doneAfter; CAddress you; int GetTimeout() { return you.IsTor() ? 120 : 30; } void BeginMessage(const char *pszCommand) { if (nHeaderStart != -1) AbortMessage(); nHeaderStart = vSend.size(); vSend << CMessageHeader(pszCommand, 0); nMessageStart = vSend.size(); // printf("%s: SEND %s\n", ToString(you).c_str(), pszCommand); } void AbortMessage() { if (nHeaderStart == -1) return; vSend.resize(nHeaderStart); nHeaderStart = -1; nMessageStart = -1; } void EndMessage() { if (nHeaderStart == -1) return; unsigned int nSize = vSend.size() - nMessageStart; memcpy((char *)&vSend[nHeaderStart] + offsetof(CMessageHeader, nMessageSize), &nSize, sizeof(nSize)); if (vSend.GetVersion() >= 209) { uint256 hash = Hash(vSend.begin() + nMessageStart, vSend.end()); unsigned int nChecksum = 0; memcpy(&nChecksum, &hash, sizeof(nChecksum)); assert(nMessageStart - nHeaderStart >= offsetof(CMessageHeader, nChecksum) + sizeof(nChecksum)); memcpy((char *)&vSend[nHeaderStart] + offsetof(CMessageHeader, nChecksum), &nChecksum, sizeof(nChecksum)); } nHeaderStart = -1; nMessageStart = -1; } void Send() { if (sock == INVALID_SOCKET) return; if (vSend.empty()) return; int nBytes = send(sock, &vSend[0], vSend.size(), 0); if (nBytes > 0) { vSend.erase(vSend.begin(), vSend.begin() + nBytes); } else { close(sock); sock = INVALID_SOCKET; } } void PushVersion() { - int64 nTime = time(nullptr); - uint64 nLocalNonce = BITCOIN_SEED_NONCE; - int64 nLocalServices = 0; + int64_t nTime = time(nullptr); + uint64_t nLocalNonce = BITCOIN_SEED_NONCE; + int64_t nLocalServices = 0; CAddress me(CService("0.0.0.0")); BeginMessage("version"); int nBestHeight = GetRequireHeight(); std::string ver = "/bitcoin-seeder:0.01/"; vSend << PROTOCOL_VERSION << nLocalServices << nTime << you << me << nLocalNonce << ver << nBestHeight; EndMessage(); } void GotVersion() { // printf("\n%s: version %i\n", ToString(you).c_str(), nVersion); if (vAddr) { BeginMessage("getaddr"); EndMessage(); doneAfter = time(nullptr) + GetTimeout(); } else { doneAfter = time(nullptr) + 1; } } bool ProcessMessage(std::string strCommand, CDataStream &vRecv) { // printf("%s: RECV %s\n", ToString(you).c_str(), // strCommand.c_str()); if (strCommand == "version") { - int64 nTime; + int64_t nTime; CAddress addrMe; CAddress addrFrom; - uint64 nNonce = 1; + uint64_t nNonce = 1; vRecv >> nVersion >> you.nServices >> nTime >> addrMe; if (nVersion == 10300) nVersion = 300; if (nVersion >= 106 && !vRecv.empty()) vRecv >> addrFrom >> nNonce; if (nVersion >= 106 && !vRecv.empty()) vRecv >> strSubVer; if (nVersion >= 209 && !vRecv.empty()) vRecv >> nStartingHeight; if (nVersion >= 209) { BeginMessage("verack"); EndMessage(); } vSend.SetVersion(std::min(nVersion, PROTOCOL_VERSION)); if (nVersion < 209) { this->vRecv.SetVersion(std::min(nVersion, PROTOCOL_VERSION)); GotVersion(); } return false; } if (strCommand == "verack") { this->vRecv.SetVersion(std::min(nVersion, PROTOCOL_VERSION)); GotVersion(); return false; } if (strCommand == "addr" && vAddr) { std::vector vAddrNew; vRecv >> vAddrNew; // printf("%s: got %i addresses\n", ToString(you).c_str(), // (int)vAddrNew.size()); - int64 now = time(nullptr); + int64_t now = time(nullptr); std::vector::iterator it = vAddrNew.begin(); if (vAddrNew.size() > 1) { if (doneAfter == 0 || doneAfter > now + 1) doneAfter = now + 1; } while (it != vAddrNew.end()) { CAddress &addr = *it; // printf("%s: got address %s\n", ToString(you).c_str(), // addr.ToString().c_str(), (int)(vAddr->size())); it++; if (addr.nTime <= 100000000 || addr.nTime > now + 600) addr.nTime = now - 5 * 86400; if (addr.nTime > now - 604800) vAddr->push_back(addr); // printf("%s: added address %s (#%i)\n", // ToString(you).c_str(), addr.ToString().c_str(), // (int)(vAddr->size())); if (vAddr->size() > 1000) { doneAfter = 1; return true; } } return false; } return false; } bool ProcessMessages() { if (vRecv.empty()) return false; do { CDataStream::iterator pstart = search(vRecv.begin(), vRecv.end(), BEGIN(pchMessageStart), END(pchMessageStart)); int nHeaderSize = vRecv.GetSerializeSize(CMessageHeader()); if (vRecv.end() - pstart < nHeaderSize) { if (vRecv.size() > nHeaderSize) { vRecv.erase(vRecv.begin(), vRecv.end() - nHeaderSize); } break; } vRecv.erase(vRecv.begin(), pstart); std::vector vHeaderSave(vRecv.begin(), vRecv.begin() + nHeaderSize); CMessageHeader hdr; vRecv >> hdr; if (!hdr.IsValid()) { // printf("%s: BAD (invalid header)\n", ToString(you).c_str()); ban = 100000; return true; } std::string strCommand = hdr.GetCommand(); unsigned int nMessageSize = hdr.nMessageSize; if (nMessageSize > MAX_SIZE) { // printf("%s: BAD (message too large)\n", // ToString(you).c_str()); ban = 100000; return true; } if (nMessageSize > vRecv.size()) { vRecv.insert(vRecv.begin(), vHeaderSave.begin(), vHeaderSave.end()); break; } if (vRecv.GetVersion() >= 209) { uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize); unsigned int nChecksum = 0; memcpy(&nChecksum, &hash, sizeof(nChecksum)); if (nChecksum != hdr.nChecksum) continue; } CDataStream vMsg(vRecv.begin(), vRecv.begin() + nMessageSize, vRecv.nType, vRecv.nVersion); vRecv.ignore(nMessageSize); if (ProcessMessage(strCommand, vMsg)) return true; // printf("%s: done processing %s\n", ToString(you).c_str(), // strCommand.c_str()); } while (1); return false; } public: CNode(const CService &ip, std::vector *vAddrIn) : you(ip), nHeaderStart(-1), nMessageStart(-1), vAddr(vAddrIn), ban(0), doneAfter(0), nVersion(0) { vSend.SetType(SER_NETWORK); vSend.SetVersion(0); vRecv.SetType(SER_NETWORK); vRecv.SetVersion(0); if (time(nullptr) > 1329696000) { vSend.SetVersion(209); vRecv.SetVersion(209); } } bool Run() { bool res = true; if (!ConnectSocket(you, sock)) return false; PushVersion(); Send(); - int64 now; + int64_t now; while (now = time(nullptr), ban == 0 && (doneAfter == 0 || doneAfter > now) && sock != INVALID_SOCKET) { char pchBuf[0x10000]; fd_set set; FD_ZERO(&set); FD_SET(sock, &set); struct timeval wa; if (doneAfter) { wa.tv_sec = doneAfter - now; wa.tv_usec = 0; } else { wa.tv_sec = GetTimeout(); wa.tv_usec = 0; } int ret = select(sock + 1, &set, nullptr, &set, &wa); if (ret != 1) { if (!doneAfter) res = false; break; } int nBytes = recv(sock, pchBuf, sizeof(pchBuf), 0); int nPos = vRecv.size(); if (nBytes > 0) { vRecv.resize(nPos + nBytes); memcpy(&vRecv[nPos], pchBuf, nBytes); } else if (nBytes == 0) { // printf("%s: BAD (connection closed prematurely)\n", // ToString(you).c_str()); res = false; break; } else { // printf("%s: BAD (connection error)\n", // ToString(you).c_str()); res = false; break; } ProcessMessages(); Send(); } if (sock == INVALID_SOCKET) res = false; close(sock); sock = INVALID_SOCKET; return (ban == 0) && res; } int GetBan() { return ban; } int GetClientVersion() { return nVersion; } std::string GetClientSubVersion() { return strSubVer; } int GetStartingHeight() { return nStartingHeight; } }; bool TestNode(const CService &cip, int &ban, int &clientV, std::string &clientSV, int &blocks, std::vector *vAddr) { try { CNode node(cip, vAddr); bool ret = node.Run(); if (!ret) { ban = node.GetBan(); } else { ban = 0; } clientV = node.GetClientVersion(); clientSV = node.GetClientSubVersion(); blocks = node.GetStartingHeight(); // printf("%s: %s!!!\n", cip.ToString().c_str(), ret ? "GOOD" : "BAD"); return ret; } catch (std::ios_base::failure &e) { ban = 0; return false; } } /* int main(void) { CService ip("bitcoin.sipa.be", 8333, true); std::vector vAddr; vAddr.clear(); int ban = 0; bool ret = TestNode(ip, ban, vAddr); printf("ret=%s ban=%i vAddr.size()=%i\n", ret ? "good" : "bad", ban, (int)vAddr.size()); } */ diff --git a/src/seeder/db.cpp b/src/seeder/db.cpp index 90ad7de2c4..ebd522b2b4 100644 --- a/src/seeder/db.cpp +++ b/src/seeder/db.cpp @@ -1,209 +1,209 @@ #include "db.h" #include void CAddrInfo::Update(bool good) { uint32_t now = time(nullptr); if (ourLastTry == 0) ourLastTry = now - MIN_RETRY; int age = now - ourLastTry; lastTry = now; ourLastTry = now; total++; if (good) { success++; ourLastSuccess = now; } stat2H.Update(good, age, 3600 * 2); 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, // 100.0 * stat2H.reliability, 100.0 * (stat2H.reliability + 1.0 - // stat2H.weight), stat2H.count, // 100.0 * stat8H.reliability, 100.0 * (stat8H.reliability + 1.0 - // stat8H.weight), stat8H.count, // 100.0 * stat1D.reliability, 100.0 * (stat1D.reliability + 1.0 - // stat1D.weight), stat1D.count, // 100.0 * stat1W.reliability, 100.0 * (stat1W.reliability + 1.0 - // stat1W.weight), stat1W.count); } bool CAddrDb::Get_(CServiceResult &ip, int &wait) { - int64 now = time(nullptr); + int64_t now = time(nullptr); int cont = 0; int tot = unkId.size() + ourId.size(); if (tot == 0) { wait = 5; return false; } do { int rnd = rand() % tot; int ret; if (rnd < unkId.size()) { std::set::iterator it = unkId.end(); it--; ret = *it; unkId.erase(it); } else { ret = ourId.front(); if (time(nullptr) - idToInfo[ret].ourLastTry < MIN_RETRY) return false; ourId.pop_front(); } if (idToInfo[ret].ignoreTill && idToInfo[ret].ignoreTill < now) { ourId.push_back(ret); idToInfo[ret].ourLastTry = now; } else { ip.service = idToInfo[ret].ip; ip.ourLastSuccess = idToInfo[ret].ourLastSuccess; break; } } while (1); nDirty++; return true; } int CAddrDb::Lookup_(const CService &ip) { if (ipToId.count(ip)) return ipToId[ip]; return -1; } void CAddrDb::Good_(const CService &addr, int clientV, std::string clientSV, int blocks) { 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.blocks = blocks; info.Update(true); if (info.IsGood() && goodId.count(id) == 0) { goodId.insert(id); // printf("%s: good; %i good nodes now\n", ToString(addr).c_str(), // (int)goodId.size()); } nDirty++; ourId.push_back(id); } void CAddrDb::Bad_(const CService &addr, int ban) { int id = Lookup_(addr); if (id == -1) return; unkId.erase(id); CAddrInfo &info = idToInfo[id]; info.Update(false); uint32_t now = time(nullptr); int ter = info.GetBanTime(); if (ter) { // printf("%s: terrible\n", ToString(addr).c_str()); if (ban < ter) ban = ter; } if (ban > 0) { // printf("%s: ban for %i seconds\n", ToString(addr).c_str(), ban); banned[info.ip] = ban + now; ipToId.erase(info.ip); goodId.erase(id); idToInfo.erase(id); } else { if (/*!info.IsGood() && */ goodId.count(id) == 1) { goodId.erase(id); // printf("%s: not good; %i good nodes left\n", // ToString(addr).c_str(), (int)goodId.size()); } ourId.push_back(id); } nDirty++; } void CAddrDb::Skipped_(const CService &addr) { int id = Lookup_(addr); if (id == -1) return; unkId.erase(id); ourId.push_back(id); // printf("%s: skipped\n", ToString(addr).c_str()); nDirty++; } void CAddrDb::Add_(const CAddress &addr, bool force) { if (!force && !addr.IsRoutable()) return; CService ipp(addr); if (banned.count(ipp)) { time_t bantime = banned[ipp]; if (force || (bantime < time(nullptr) && addr.nTime > bantime)) banned.erase(ipp); else return; } if (ipToId.count(ipp)) { CAddrInfo &ai = idToInfo[ipToId[ipp]]; if (addr.nTime > ai.lastTry || ai.services != addr.nServices) { ai.lastTry = addr.nTime; ai.services |= addr.nServices; // printf("%s: updated\n", ToString(addr).c_str()); } if (force) { ai.ignoreTill = 0; } return; } CAddrInfo ai; ai.ip = ipp; ai.services = addr.nServices; ai.lastTry = addr.nTime; ai.ourLastTry = 0; ai.total = 0; ai.success = 0; int id = nId++; idToInfo[id] = ai; ipToId[ipp] = id; // printf("%s: added\n", ToString(ipp).c_str(), ipToId[ipp]); unkId.insert(id); nDirty++; } void CAddrDb::GetIPs_(std::set &ips, uint64_t requestedFlags, int max, const bool *nets) { if (goodId.size() == 0) { int id = -1; if (ourId.size() == 0) { if (unkId.size() == 0) return; id = *unkId.begin(); } else { id = *ourId.begin(); } if (id >= 0 && (idToInfo[id].services & requestedFlags) == requestedFlags) { ips.insert(idToInfo[id].ip); } return; } std::vector goodIdFiltered; for (std::set::const_iterator it = goodId.begin(); it != goodId.end(); it++) { if ((idToInfo[*it].services & requestedFlags) == requestedFlags) goodIdFiltered.push_back(*it); } if (!goodIdFiltered.size()) return; if (max > goodIdFiltered.size() / 2) max = goodIdFiltered.size() / 2; if (max < 1) max = 1; std::set ids; while (ids.size() < max) { ids.insert(goodIdFiltered[rand() % goodIdFiltered.size()]); } for (std::set::const_iterator it = ids.begin(); it != ids.end(); it++) { CService &ip = idToInfo[*it].ip; if (nets[ip.GetNetwork()]) ips.insert(ip); } } diff --git a/src/seeder/db.h b/src/seeder/db.h index 0a6a10c515..a170b74bc3 100644 --- a/src/seeder/db.h +++ b/src/seeder/db.h @@ -1,407 +1,407 @@ #ifndef BITCOIN_SEEDER_DB_H #define BITCOIN_SEEDER_DB_H #include "netbase.h" #include "protocol.h" #include "util.h" #include #include #include #include #include #include #define MIN_RETRY 1000 #define REQUIRE_VERSION 70001 static inline int GetRequireHeight(const bool testnet = fTestNet) { return testnet ? 500000 : 350000; } static inline std::string ToString(const CService &ip) { std::string str = ip.ToString(); while (str.size() < 22) str += ' '; return str; } class CAddrStat { private: float weight; float count; float reliability; public: CAddrStat() : weight(0), count(0), reliability(0) {} - void Update(bool good, int64 age, double tau) { + void Update(bool good, int64_t age, double tau) { double f = exp(-age / tau); reliability = reliability * f + (good ? (1.0 - f) : 0); count = count * f + 1; weight = weight * f + (1.0 - f); } IMPLEMENT_SERIALIZE(READWRITE(weight); READWRITE(count); READWRITE(reliability);) friend class CAddrInfo; }; class CAddrReport { public: CService ip; int clientVersion; int blocks; double uptime[5]; std::string clientSubVersion; int64_t lastSuccess; bool fGood; uint64_t services; }; class CAddrInfo { private: CService ip; uint64_t services; - int64 lastTry; - int64 ourLastTry; - int64 ourLastSuccess; - int64 ignoreTill; + int64_t lastTry; + int64_t ourLastTry; + int64_t ourLastSuccess; + int64_t ignoreTill; CAddrStat stat2H; CAddrStat stat8H; CAddrStat stat1D; CAddrStat stat1W; CAddrStat stat1M; int clientVersion; int blocks; int total; int success; std::string clientSubVersion; public: CAddrInfo() : services(0), lastTry(0), ourLastTry(0), ourLastSuccess(0), ignoreTill(0), clientVersion(0), blocks(0), total(0), success(0) {} CAddrReport GetReport() const { CAddrReport ret; ret.ip = ip; ret.clientVersion = clientVersion; ret.clientSubVersion = clientSubVersion; ret.blocks = blocks; 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; ret.lastSuccess = ourLastSuccess; ret.fGood = IsGood(); ret.services = services; return ret; } bool IsGood() const { if (ip.GetPort() != GetDefaultPort()) return false; if (!(services & NODE_NETWORK)) return false; if (!(services & NODE_BITCOIN_CASH)) return false; if (!ip.IsRoutable()) return false; if (clientVersion && clientVersion < REQUIRE_VERSION) return false; if (blocks && blocks < GetRequireHeight()) return false; if (total <= 3 && success * 2 >= total) return true; if (stat2H.reliability > 0.85 && stat2H.count > 2) return true; if (stat8H.reliability > 0.70 && stat8H.count > 4) return true; if (stat1D.reliability > 0.55 && stat1D.count > 8) return true; if (stat1W.reliability > 0.45 && stat1W.count > 16) return true; if (stat1M.reliability > 0.35 && stat1M.count > 32) return true; return false; } int GetBanTime() const { if (IsGood()) return 0; if (clientVersion && clientVersion < 31900) { return 604800; } if (stat1M.reliability - stat1M.weight + 1.0 < 0.15 && stat1M.count > 32) { return 30 * 86400; } if (stat1W.reliability - stat1W.weight + 1.0 < 0.10 && stat1W.count > 16) { return 7 * 86400; } if (stat1D.reliability - stat1D.weight + 1.0 < 0.05 && stat1D.count > 8) { return 1 * 86400; } return 0; } int GetIgnoreTime() const { if (IsGood()) return 0; if (stat1M.reliability - stat1M.weight + 1.0 < 0.20 && stat1M.count > 2) { return 10 * 86400; } if (stat1W.reliability - stat1W.weight + 1.0 < 0.16 && stat1W.count > 2) { return 3 * 86400; } if (stat1D.reliability - stat1D.weight + 1.0 < 0.12 && stat1D.count > 2) { return 8 * 3600; } if (stat8H.reliability - stat8H.weight + 1.0 < 0.08 && stat8H.count > 2) { return 2 * 3600; } return 0; } void Update(bool good); friend class CAddrDb; IMPLEMENT_SERIALIZE(uint8_t version = 4; READWRITE(version); READWRITE(ip); READWRITE(services); READWRITE(lastTry); uint8_t tried = ourLastTry != 0; READWRITE(tried); if (tried) { READWRITE(ourLastTry); READWRITE(ignoreTill); READWRITE(stat2H); 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); if (version >= 3) READWRITE(blocks); if (version >= 4) READWRITE(ourLastSuccess); }) }; class CAddrDbStats { public: int nBanned; int nAvail; int nTracked; int nNew; int nGood; int nAge; }; struct CServiceResult { CService service; bool fGood; int nBanTime; int nHeight; int nClientV; std::string strClientV; - int64 ourLastSuccess; + int64_t ourLastSuccess; }; // seen nodes // / \ // (a) banned nodes available nodes-------------- // / | \ // tracked nodes (b) unknown nodes (e) active nodes // / \ // (d) good nodes (c) non-good nodes class CAddrDb { private: mutable CCriticalSection cs; // number of address id's int nId; // map address id to address info (b,c,d,e) std::map idToInfo; // map ip to id (b,c,d,e) std::map ipToId; // sequence of tried nodes, in order we have tried connecting to them (c,d) std::deque ourId; // set of nodes not yet tried (b) std::set unkId; // set of good nodes (d, good e) std::set goodId; int nDirty; protected: // internal routines that assume proper locks are acquired // add an address void Add_(const CAddress &addr, bool force); // get an IP to test (must call Good_, Bad_, or Skipped_ on result // afterwards) bool Get_(CServiceResult &ip, int &wait); bool GetMany_(std::vector &ips, int max, int &wait); // mark an IP as good (must have been returned by Get_) void Good_(const CService &ip, int clientV, std::string clientSV, int blocks); // mark an IP as bad (and optionally ban it) (must have been returned by // Get_) void Bad_(const CService &ip, int ban); // mark an IP as skipped (must have been returned by Get_) void Skipped_(const CService &ip); // look up id of an IP int Lookup_(const CService &ip); // get a random set of IPs (shared lock only) void GetIPs_(std::set &ips, uint64_t requestedFlags, int max, const bool *nets); public: // nodes that are banned, with their unban time (a) std::map banned; void GetStats(CAddrDbStats &stats) { SHARED_CRITICAL_BLOCK(cs) { stats.nBanned = banned.size(); stats.nAvail = idToInfo.size(); stats.nTracked = ourId.size(); stats.nGood = goodId.size(); stats.nNew = unkId.size(); stats.nAge = time(nullptr) - idToInfo[ourId[0]].ourLastTry; } } void ResetIgnores() { for (std::map::iterator it = idToInfo.begin(); it != idToInfo.end(); it++) { (*it).second.ignoreTill = 0; } } std::vector GetAll() { std::vector ret; SHARED_CRITICAL_BLOCK(cs) { for (std::deque::const_iterator it = ourId.begin(); it != ourId.end(); it++) { const CAddrInfo &info = idToInfo[*it]; if (info.success > 0) { ret.push_back(info.GetReport()); } } } return ret; } // serialization code // format: // nVersion (0 for now) // n (number of ips in (b,c,d)) // CAddrInfo[n] // banned // acquires a shared lock (this does not suffice for read mode, but we // assume that only happens at startup, single-threaded) // this way, dumping does not interfere with GetIPs_, which is called from // the DNS thread IMPLEMENT_SERIALIZE(({ int nVersion = 0; READWRITE(nVersion); SHARED_CRITICAL_BLOCK(cs) { if (fWrite) { CAddrDb *db = const_cast(this); int n = ourId.size() + unkId.size(); READWRITE(n); for (std::deque::const_iterator it = ourId.begin(); it != ourId.end(); it++) { std::map::iterator ci = db->idToInfo.find(*it); READWRITE((*ci).second); } for (std::set::const_iterator it = unkId.begin(); it != unkId.end(); it++) { std::map::iterator ci = db->idToInfo.find(*it); READWRITE((*ci).second); } } else { CAddrDb *db = const_cast(this); db->nId = 0; int n; READWRITE(n); for (int i = 0; i < n; i++) { CAddrInfo info; READWRITE(info); if (!info.GetBanTime()) { int id = db->nId++; db->idToInfo[id] = info; db->ipToId[info.ip] = id; if (info.ourLastTry) { db->ourId.push_back(id); if (info.IsGood()) db->goodId.insert(id); } else { db->unkId.insert(id); } } } db->nDirty++; } READWRITE(banned); } });) void Add(const CAddress &addr, bool fForce = false) { CRITICAL_BLOCK(cs) Add_(addr, fForce); } void Add(const std::vector &vAddr, bool fForce = false) { CRITICAL_BLOCK(cs) for (int i = 0; i < vAddr.size(); i++) Add_(vAddr[i], fForce); } void Good(const CService &addr, int clientVersion, std::string clientSubVersion, int blocks) { CRITICAL_BLOCK(cs) Good_(addr, clientVersion, clientSubVersion, blocks); } void Skipped(const CService &addr) { CRITICAL_BLOCK(cs) Skipped_(addr); } void Bad(const CService &addr, int ban = 0) { CRITICAL_BLOCK(cs) Bad_(addr, ban); } bool Get(CServiceResult &ip, int &wait) { CRITICAL_BLOCK(cs) return Get_(ip, wait); } void GetMany(std::vector &ips, int max, int &wait) { CRITICAL_BLOCK(cs) { while (max > 0) { CServiceResult ip = {}; if (!Get_(ip, wait)) return; ips.push_back(ip); max--; } } } void ResultMany(const std::vector &ips) { CRITICAL_BLOCK(cs) { for (int i = 0; i < ips.size(); i++) { if (ips[i].fGood) { Good_(ips[i].service, ips[i].nClientV, ips[i].strClientV, ips[i].nHeight); } else { Bad_(ips[i].service, ips[i].nBanTime); } } } } void GetIPs(std::set &ips, uint64_t requestedFlags, int max, const bool *nets) { SHARED_CRITICAL_BLOCK(cs) GetIPs_(ips, requestedFlags, max, nets); } }; #endif diff --git a/src/seeder/main.cpp b/src/seeder/main.cpp index 9904cbd775..a399908d2c 100644 --- a/src/seeder/main.cpp +++ b/src/seeder/main.cpp @@ -1,561 +1,561 @@ #include "bitcoin.h" #include "db.h" #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS #include bool fTestNet = false; class CDnsSeedOpts { public: int nThreads; int nPort; int nDnsThreads; int fUseTestNet; int fWipeBan; int fWipeIgnore; const char *mbox; const char *ns; const char *host; const char *tor; const char *ipv4_proxy; const char *ipv6_proxy; std::set filter_whitelist; CDnsSeedOpts() : nThreads(96), nDnsThreads(4), nPort(53), mbox(nullptr), ns(nullptr), host(nullptr), tor(nullptr), fUseTestNet(false), fWipeBan(false), fWipeIgnore(false), ipv4_proxy(nullptr), ipv6_proxy(nullptr) {} void ParseCommandLine(int argc, char **argv) { static const char *help = "Bitcoin-seeder\n" "Usage: %s -h -n [-m ] [-t ] [-p " "]\n" "\n" "Options:\n" "-h Hostname of the DNS seed\n" "-n Hostname of the nameserver\n" "-m E-Mail address reported in SOA records\n" "-t Number of crawlers to run in parallel (default " "96)\n" "-d Number of DNS server threads (default 4)\n" "-p UDP port to listen on (default 53)\n" "-o Tor proxy IP/Port\n" "-i IPV4 SOCKS5 proxy IP/Port\n" "-k IPV6 SOCKS5 proxy IP/Port\n" "-w f1,f2,... Allow these flag combinations as filters\n" "--testnet Use testnet\n" "--wipeban Wipe list of banned nodes\n" "--wipeignore Wipe list of ignored nodes\n" "-?, --help Show this text\n" "\n"; bool showHelp = false; while (1) { static struct option long_options[] = { {"host", required_argument, 0, 'h'}, {"ns", required_argument, 0, 'n'}, {"mbox", required_argument, 0, 'm'}, {"threads", required_argument, 0, 't'}, {"dnsthreads", required_argument, 0, 'd'}, {"port", required_argument, 0, 'p'}, {"onion", required_argument, 0, 'o'}, {"proxyipv4", required_argument, 0, 'i'}, {"proxyipv6", required_argument, 0, 'k'}, {"filter", required_argument, 0, 'w'}, {"testnet", no_argument, &fUseTestNet, 1}, {"wipeban", no_argument, &fWipeBan, 1}, {"wipeignore", no_argument, &fWipeBan, 1}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}}; int option_index = 0; int c = getopt_long(argc, argv, "h:n:m:t:p:d:o:i:k:w:", long_options, &option_index); if (c == -1) break; switch (c) { case 'h': { host = optarg; break; } case 'm': { mbox = optarg; break; } case 'n': { ns = optarg; break; } case 't': { int n = strtol(optarg, nullptr, 10); if (n > 0 && n < 1000) nThreads = n; break; } case 'd': { int n = strtol(optarg, nullptr, 10); if (n > 0 && n < 1000) nDnsThreads = n; break; } case 'p': { int p = strtol(optarg, nullptr, 10); if (p > 0 && p < 65536) nPort = p; break; } case 'o': { tor = optarg; break; } case 'i': { ipv4_proxy = optarg; break; } case 'k': { ipv6_proxy = optarg; break; } case 'w': { char *ptr = optarg; while (*ptr != 0) { unsigned long l = strtoul(ptr, &ptr, 0); if (*ptr == ',') { ptr++; } else if (*ptr != 0) { break; } filter_whitelist.insert(l); } break; } case '?': { showHelp = true; break; } } } if (filter_whitelist.empty()) { filter_whitelist.insert(NODE_NETWORK | NODE_BITCOIN_CASH); filter_whitelist.insert(NODE_NETWORK | NODE_BITCOIN_CASH | NODE_BLOOM); filter_whitelist.insert(NODE_NETWORK | NODE_BITCOIN_CASH | NODE_XTHIN); filter_whitelist.insert(NODE_NETWORK | NODE_BITCOIN_CASH | NODE_BLOOM | NODE_XTHIN); } if (host != nullptr && ns == nullptr) showHelp = true; if (showHelp) fprintf(stderr, help, argv[0]); } }; extern "C" { #include "dns.h" } CAddrDb db; extern "C" void *ThreadCrawler(void *data) { int *nThreads = (int *)data; do { std::vector ips; int wait = 5; db.GetMany(ips, 16, wait); - int64 now = time(nullptr); + int64_t now = time(nullptr); if (ips.empty()) { wait *= 1000; wait += rand() % (500 * *nThreads); Sleep(wait); continue; } std::vector addr; for (int i = 0; i < ips.size(); i++) { CServiceResult &res = ips[i]; res.nBanTime = 0; res.nClientV = 0; res.nHeight = 0; res.strClientV = ""; bool getaddr = res.ourLastSuccess + 86400 < now; res.fGood = TestNode(res.service, res.nBanTime, res.nClientV, res.strClientV, res.nHeight, getaddr ? &addr : nullptr); } db.ResultMany(ips); db.Add(addr); } while (1); return nullptr; } extern "C" int GetIPList(void *thread, char *requestedHostname, addr_t *addr, int max, int ipv4, int ipv6); class CDnsThread { public: struct FlagSpecificData { int nIPv4, nIPv6; std::vector cache; time_t cacheTime; unsigned int cacheHits; FlagSpecificData() : nIPv4(0), nIPv6(0), cacheTime(0), cacheHits(0) {} }; dns_opt_t dns_opt; // must be first const int id; std::map perflag; std::atomic dbQueries; std::set filterWhitelist; void cacheHit(uint64_t requestedFlags, bool force = false) { static bool nets[NET_MAX] = {}; if (!nets[NET_IPV4]) { nets[NET_IPV4] = true; nets[NET_IPV6] = true; } time_t now = time(nullptr); FlagSpecificData &thisflag = perflag[requestedFlags]; thisflag.cacheHits++; if (force || thisflag.cacheHits * 400 > (thisflag.cache.size() * thisflag.cache.size()) || (thisflag.cacheHits * thisflag.cacheHits * 20 > thisflag.cache.size() && (now - thisflag.cacheTime > 5))) { std::set ips; db.GetIPs(ips, requestedFlags, 1000, nets); dbQueries++; thisflag.cache.clear(); thisflag.nIPv4 = 0; thisflag.nIPv6 = 0; thisflag.cache.reserve(ips.size()); for (auto &ip : ips) { struct in_addr addr; struct in6_addr addr6; if (ip.GetInAddr(&addr)) { addr_t a; a.v = 4; memcpy(&a.data.v4, &addr, 4); thisflag.cache.push_back(a); thisflag.nIPv4++; } else if (ip.GetIn6Addr(&addr6)) { addr_t a; a.v = 6; memcpy(&a.data.v6, &addr6, 16); thisflag.cache.push_back(a); thisflag.nIPv6++; } } thisflag.cacheHits = 0; thisflag.cacheTime = now; } } CDnsThread(CDnsSeedOpts *opts, int idIn) : id(idIn) { dns_opt.host = opts->host; dns_opt.ns = opts->ns; dns_opt.mbox = opts->mbox; dns_opt.datattl = 3600; dns_opt.nsttl = 40000; dns_opt.cb = GetIPList; dns_opt.port = opts->nPort; dns_opt.nRequests = 0; dbQueries = 0; perflag.clear(); filterWhitelist = opts->filter_whitelist; } void run() { dnsserver(&dns_opt); } }; extern "C" int GetIPList(void *data, char *requestedHostname, addr_t *addr, int max, int ipv4, int ipv6) { CDnsThread *thread = (CDnsThread *)data; uint64_t requestedFlags = 0; int hostlen = strlen(requestedHostname); if (hostlen > 1 && requestedHostname[0] == 'x' && requestedHostname[1] != '0') { char *pEnd; uint64_t flags = (uint64_t)strtoull(requestedHostname + 1, &pEnd, 16); if (*pEnd == '.' && pEnd <= requestedHostname + 17 && std::find(thread->filterWhitelist.begin(), thread->filterWhitelist.end(), flags) != thread->filterWhitelist.end()) requestedFlags = flags; else return 0; } else if (strcasecmp(requestedHostname, thread->dns_opt.host)) return 0; thread->cacheHit(requestedFlags); auto &thisflag = thread->perflag[requestedFlags]; unsigned int size = thisflag.cache.size(); unsigned int maxmax = (ipv4 ? thisflag.nIPv4 : 0) + (ipv6 ? thisflag.nIPv6 : 0); if (max > size) max = size; if (max > maxmax) max = maxmax; int i = 0; while (i < max) { int j = i + (rand() % (size - i)); do { bool ok = (ipv4 && thisflag.cache[j].v == 4) || (ipv6 && thisflag.cache[j].v == 6); if (ok) break; j++; if (j == size) j = i; } while (1); addr[i] = thisflag.cache[j]; thisflag.cache[j] = thisflag.cache[i]; thisflag.cache[i] = addr[i]; i++; } return max; } std::vector dnsThread; extern "C" void *ThreadDNS(void *arg) { CDnsThread *thread = (CDnsThread *)arg; thread->run(); return nullptr; } 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 *) { int count = 0; do { // First 100s, than 200s, 400s, 800s, 1600s, and then 3200s forever Sleep(100000 << count); if (count < 5) { count++; } { std::vector v = db.GetAll(); sort(v.begin(), v.end(), StatCompare); FILE *f = fopen("dnsseed.dat.new", "w+"); if (f) { { CAutoFile cf(f); cf << db; } rename("dnsseed.dat.new", "dnsseed.dat"); } FILE *d = fopen("dnsseed.dump", "w"); fprintf(d, "# address good " "lastSuccess %%(2h) %%(8h) %%(1d) %%(7d) " "%%(30d) blocks svcs version\n"); double stat[5] = {0, 0, 0, 0, 0}; for (CAddrReport rep : v) { fprintf( d, "%-47s %4d %11" PRId64 " %6.2f%% %6.2f%% %6.2f%% %6.2f%% %6.2f%% %6i %08" PRIx64 " %5i \"%s\"\n", rep.ip.ToString().c_str(), (int)rep.fGood, rep.lastSuccess, 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.blocks, rep.services, rep.clientVersion, rep.clientSubVersion.c_str()); stat[0] += rep.uptime[0]; stat[1] += rep.uptime[1]; stat[2] += rep.uptime[2]; stat[3] += rep.uptime[3]; stat[4] += rep.uptime[4]; } fclose(d); FILE *ff = fopen("dnsstats.log", "a"); fprintf(ff, "%llu %g %g %g %g %g\n", (unsigned long long)(time(nullptr)), stat[0], stat[1], stat[2], stat[3], stat[4]); fclose(ff); } } while (1); return nullptr; } extern "C" void *ThreadStats(void *) { bool first = true; do { char c[256]; time_t tim = time(nullptr); struct tm *tmp = localtime(&tim); strftime(c, 256, "[%y-%m-%d %H:%M:%S]", tmp); CAddrDbStats stats; db.GetStats(stats); if (first) { first = false; printf("\n\n\n\x1b[3A"); } else printf("\x1b[2K\x1b[u"); printf("\x1b[s"); uint64_t requests = 0; uint64_t queries = 0; for (unsigned int i = 0; i < dnsThread.size(); i++) { requests += dnsThread[i]->dns_opt.nRequests; queries += dnsThread[i]->dbQueries; } printf("%s %i/%i available (%i tried in %is, %i new, %i active), %i " "banned; %llu DNS requests, %llu db queries", c, stats.nGood, stats.nAvail, stats.nTracked, stats.nAge, stats.nNew, stats.nAvail - stats.nTracked - stats.nNew, stats.nBanned, (unsigned long long)requests, (unsigned long long)queries); Sleep(1000); } while (1); return nullptr; } static const std::string mainnet_seeds[] = { "seed.bitcoinabc.org", "seed-abc.bitcoinforks.org", "seed.bitprim.org", "seed.deadalnix.me", "seeder.criptolayer.net", ""}; static const std::string testnet_seeds[] = { "testnet-seed.bitcoinabc.org", "testnet-seed-abc.bitcoinforks.org", "testnet-seed.bitprim.org", "testnet-seed.deadalnix.me", "testnet-seeder.criptolayer.net", ""}; static const std::string *seeds = mainnet_seeds; extern "C" void *ThreadSeeder(void *) { if (!fTestNet) { db.Add(CService("kjy2eqzk4zwi5zd3.onion", 8333), true); } do { for (int i = 0; seeds[i] != ""; i++) { std::vector ips; LookupHost(seeds[i].c_str(), ips); for (auto &ip : ips) { db.Add(CService(ip, GetDefaultPort()), true); } } Sleep(1800000); } while (1); return nullptr; } int main(int argc, char **argv) { signal(SIGPIPE, SIG_IGN); setbuf(stdout, nullptr); CDnsSeedOpts opts; opts.ParseCommandLine(argc, argv); printf("Supporting whitelisted filters: "); for (std::set::const_iterator it = opts.filter_whitelist.begin(); it != opts.filter_whitelist.end(); it++) { if (it != opts.filter_whitelist.begin()) { printf(","); } printf("0x%lx", (unsigned long)*it); } printf("\n"); if (opts.tor) { CService service(opts.tor, 9050); if (service.IsValid()) { printf("Using Tor proxy at %s\n", service.ToStringIPPort().c_str()); SetProxy(NET_TOR, service); } } if (opts.ipv4_proxy) { CService service(opts.ipv4_proxy, 9050); if (service.IsValid()) { printf("Using IPv4 proxy at %s\n", service.ToStringIPPort().c_str()); SetProxy(NET_IPV4, service); } } if (opts.ipv6_proxy) { CService service(opts.ipv6_proxy, 9050); if (service.IsValid()) { printf("Using IPv6 proxy at %s\n", service.ToStringIPPort().c_str()); SetProxy(NET_IPV6, service); } } bool fDNS = true; if (opts.fUseTestNet) { printf("Using testnet.\n"); pchMessageStart[0] = 0xf4; pchMessageStart[1] = 0xe5; pchMessageStart[2] = 0xf3; pchMessageStart[3] = 0xf4; seeds = testnet_seeds; fTestNet = true; } if (!opts.ns) { printf("No nameserver set. Not starting DNS server.\n"); fDNS = false; } if (fDNS && !opts.host) { fprintf(stderr, "No hostname set. Please use -h.\n"); exit(1); } if (fDNS && !opts.mbox) { fprintf(stderr, "No e-mail address set. Please use -m.\n"); exit(1); } FILE *f = fopen("dnsseed.dat", "r"); if (f) { printf("Loading dnsseed.dat..."); CAutoFile cf(f); cf >> db; if (opts.fWipeBan) db.banned.clear(); if (opts.fWipeIgnore) db.ResetIgnores(); printf("done\n"); } pthread_t threadDns, threadSeed, threadDump, threadStats; if (fDNS) { printf("Starting %i DNS threads for %s on %s (port %i)...", opts.nDnsThreads, opts.host, opts.ns, opts.nPort); dnsThread.clear(); for (int i = 0; i < opts.nDnsThreads; i++) { dnsThread.push_back(new CDnsThread(&opts, i)); pthread_create(&threadDns, nullptr, ThreadDNS, dnsThread[i]); printf("."); Sleep(20); } printf("done\n"); } printf("Starting seeder..."); pthread_create(&threadSeed, nullptr, ThreadSeeder, nullptr); printf("done\n"); printf("Starting %i crawler threads...", opts.nThreads); pthread_attr_t attr_crawler; pthread_attr_init(&attr_crawler); pthread_attr_setstacksize(&attr_crawler, 0x20000); for (int i = 0; i < opts.nThreads; i++) { pthread_t thread; pthread_create(&thread, &attr_crawler, ThreadCrawler, &opts.nThreads); } pthread_attr_destroy(&attr_crawler); printf("done\n"); pthread_create(&threadStats, nullptr, ThreadStats, nullptr); pthread_create(&threadDump, nullptr, ThreadDumper, nullptr); void *res; pthread_join(threadDump, &res); return 0; } diff --git a/src/seeder/netbase.cpp b/src/seeder/netbase.cpp index 617272851f..dc20da759d 100644 --- a/src/seeder/netbase.cpp +++ b/src/seeder/netbase.cpp @@ -1,1066 +1,1066 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "netbase.h" #include "strlcpy.h" #include "util.h" #ifndef WIN32 #include #endif #include // for to_lower() #define printf my_printf // Settings typedef std::pair proxyType; static proxyType proxyInfo[NET_MAX]; static proxyType nameproxyInfo; int nConnectTimeout = 5000; bool fNameLookup = false; static const uint8_t pchIPv4[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}; enum Network ParseNetwork(std::string net) { boost::to_lower(net); if (net == "ipv4") return NET_IPV4; if (net == "ipv6") return NET_IPV6; if (net == "tor") return NET_TOR; if (net == "i2p") return NET_I2P; return NET_UNROUTABLE; } void SplitHostPort(std::string in, int &portOut, std::string &hostOut) { size_t colon = in.find_last_of(':'); // if a : is found, and it either follows a [...], or no other : is in the // string, treat it as port separator bool fHaveColon = colon != in.npos; // if there is a colon, and in[0]=='[', colon is not 0, so in[colon-1] is // safe bool fBracketed = fHaveColon && (in[0] == '[' && in[colon - 1] == ']'); bool fMultiColon = fHaveColon && (in.find_last_of(':', colon - 1) != in.npos); if (fHaveColon && (colon == 0 || fBracketed || !fMultiColon)) { char *endp = nullptr; int n = strtol(in.c_str() + colon + 1, &endp, 10); if (endp && *endp == 0 && n >= 0) { in = in.substr(0, colon); if (n > 0 && n < 0x10000) portOut = n; } } if (in.size() > 0 && in[0] == '[' && in[in.size() - 1] == ']') hostOut = in.substr(1, in.size() - 2); else hostOut = in; } static bool LookupIntern(const char *pszName, std::vector &vIP, unsigned int nMaxSolutions, bool fAllowLookup) { vIP.clear(); { CNetAddr addr; if (addr.SetSpecial(std::string(pszName))) { vIP.push_back(addr); return true; } } struct addrinfo aiHint; memset(&aiHint, 0, sizeof(struct addrinfo)); aiHint.ai_socktype = SOCK_STREAM; aiHint.ai_protocol = IPPROTO_TCP; #ifdef WIN32 aiHint.ai_family = AF_UNSPEC; aiHint.ai_flags = fAllowLookup ? 0 : AI_NUMERICHOST; #else aiHint.ai_family = AF_UNSPEC; aiHint.ai_flags = fAllowLookup ? AI_ADDRCONFIG : AI_NUMERICHOST; #endif struct addrinfo *aiRes = nullptr; int nErr = getaddrinfo(pszName, nullptr, &aiHint, &aiRes); if (nErr) return false; struct addrinfo *aiTrav = aiRes; while (aiTrav != nullptr && (nMaxSolutions == 0 || vIP.size() < nMaxSolutions)) { if (aiTrav->ai_family == AF_INET) { assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in)); vIP.push_back( CNetAddr(((struct sockaddr_in *)(aiTrav->ai_addr))->sin_addr)); } if (aiTrav->ai_family == AF_INET6) { assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in6)); vIP.push_back(CNetAddr( ((struct sockaddr_in6 *)(aiTrav->ai_addr))->sin6_addr)); } aiTrav = aiTrav->ai_next; } freeaddrinfo(aiRes); return (vIP.size() > 0); } bool LookupHost(const char *pszName, std::vector &vIP, unsigned int nMaxSolutions, bool fAllowLookup) { if (pszName[0] == 0) return false; char psz[256]; char *pszHost = psz; strlcpy(psz, pszName, sizeof(psz)); if (psz[0] == '[' && psz[strlen(psz) - 1] == ']') { pszHost = psz + 1; psz[strlen(psz) - 1] = 0; } return LookupIntern(pszHost, vIP, nMaxSolutions, fAllowLookup); } bool LookupHostNumeric(const char *pszName, std::vector &vIP, unsigned int nMaxSolutions) { return LookupHost(pszName, vIP, nMaxSolutions, false); } bool Lookup(const char *pszName, std::vector &vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions) { if (pszName[0] == 0) return false; int port = portDefault; std::string hostname = ""; SplitHostPort(std::string(pszName), port, hostname); std::vector vIP; bool fRet = LookupIntern(hostname.c_str(), vIP, nMaxSolutions, fAllowLookup); if (!fRet) return false; vAddr.resize(vIP.size()); for (unsigned int i = 0; i < vIP.size(); i++) vAddr[i] = CService(vIP[i], port); return true; } bool Lookup(const char *pszName, CService &addr, int portDefault, bool fAllowLookup) { std::vector vService; bool fRet = Lookup(pszName, vService, portDefault, fAllowLookup, 1); if (!fRet) return false; addr = vService[0]; return true; } bool LookupNumeric(const char *pszName, CService &addr, int portDefault) { return Lookup(pszName, addr, portDefault, false); } static bool Socks4(const CService &addrDest, SOCKET &hSocket) { printf("SOCKS4 connecting %s\n", addrDest.ToString().c_str()); if (!addrDest.IsIPv4()) { closesocket(hSocket); return error("Proxy destination is not IPv4"); } char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user"; struct sockaddr_in addr; socklen_t len = sizeof(addr); if (!addrDest.GetSockAddr((struct sockaddr *)&addr, &len) || addr.sin_family != AF_INET) { closesocket(hSocket); return error("Cannot get proxy destination address"); } memcpy(pszSocks4IP + 2, &addr.sin_port, 2); memcpy(pszSocks4IP + 4, &addr.sin_addr, 4); char *pszSocks4 = pszSocks4IP; int nSize = sizeof(pszSocks4IP); int ret = send(hSocket, pszSocks4, nSize, MSG_NOSIGNAL); if (ret != nSize) { closesocket(hSocket); return error("Error sending to proxy"); } char pchRet[8]; if (recv(hSocket, pchRet, 8, 0) != 8) { closesocket(hSocket); return error("Error reading proxy response"); } if (pchRet[1] != 0x5a) { closesocket(hSocket); if (pchRet[1] != 0x5b) printf("ERROR: Proxy returned error %d\n", pchRet[1]); return false; } printf("SOCKS4 connected %s\n", addrDest.ToString().c_str()); return true; } static bool Socks5(std::string strDest, int port, SOCKET &hSocket) { printf("SOCKS5 connecting %s\n", strDest.c_str()); if (strDest.size() > 255) { closesocket(hSocket); return error("Hostname too long"); } char pszSocks5Init[] = "\5\1\0"; char *pszSocks5 = pszSocks5Init; ssize_t nSize = sizeof(pszSocks5Init) - 1; ssize_t ret = send(hSocket, pszSocks5, nSize, MSG_NOSIGNAL); if (ret != nSize) { closesocket(hSocket); return error("Error sending to proxy"); } char pchRet1[2]; if (recv(hSocket, pchRet1, 2, 0) != 2) { closesocket(hSocket); return error("Error reading proxy response"); } if (pchRet1[0] != 0x05 || pchRet1[1] != 0x00) { closesocket(hSocket); return error("Proxy failed to initialize"); } std::string strSocks5("\5\1"); strSocks5 += '\000'; strSocks5 += '\003'; strSocks5 += static_cast(std::min((int)strDest.size(), 255)); strSocks5 += strDest; strSocks5 += static_cast((port >> 8) & 0xFF); strSocks5 += static_cast((port >> 0) & 0xFF); ret = send(hSocket, strSocks5.c_str(), strSocks5.size(), MSG_NOSIGNAL); if (ret != (ssize_t)strSocks5.size()) { closesocket(hSocket); return error("Error sending to proxy"); } char pchRet2[4]; if (recv(hSocket, pchRet2, 4, 0) != 4) { closesocket(hSocket); return error("Error reading proxy response"); } if (pchRet2[0] != 0x05) { closesocket(hSocket); return error("Proxy failed to accept request"); } if (pchRet2[1] != 0x00) { closesocket(hSocket); switch (pchRet2[1]) { case 0x01: return error("Proxy error: general failure"); case 0x02: return error("Proxy error: connection not allowed"); case 0x03: return error("Proxy error: network unreachable"); case 0x04: return error("Proxy error: host unreachable"); case 0x05: return error("Proxy error: connection refused"); case 0x06: return error("Proxy error: TTL expired"); case 0x07: return error("Proxy error: protocol error"); case 0x08: return error("Proxy error: address type not supported"); default: return error("Proxy error: unknown"); } } if (pchRet2[2] != 0x00) { closesocket(hSocket); return error("Error: malformed proxy response"); } char pchRet3[256]; switch (pchRet2[3]) { case 0x01: ret = recv(hSocket, pchRet3, 4, 0) != 4; break; case 0x04: ret = recv(hSocket, pchRet3, 16, 0) != 16; break; case 0x03: { ret = recv(hSocket, pchRet3, 1, 0) != 1; if (ret) return error("Error reading from proxy"); int nRecv = pchRet3[0]; ret = recv(hSocket, pchRet3, nRecv, 0) != nRecv; break; } default: closesocket(hSocket); return error("Error: malformed proxy response"); } if (ret) { closesocket(hSocket); return error("Error reading from proxy"); } if (recv(hSocket, pchRet3, 2, 0) != 2) { closesocket(hSocket); return error("Error reading from proxy"); } printf("SOCKS5 connected %s\n", strDest.c_str()); return true; } static bool ConnectSocketDirectly(const CService &addrConnect, SOCKET &hSocketRet, int nTimeout) { hSocketRet = INVALID_SOCKET; struct sockaddr_storage sockaddr; socklen_t len = sizeof(sockaddr); if (!addrConnect.GetSockAddr((struct sockaddr *)&sockaddr, &len)) { printf("Cannot connect to %s: unsupported network\n", addrConnect.ToString().c_str()); return false; } SOCKET hSocket = socket(((struct sockaddr *)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP); if (hSocket == INVALID_SOCKET) return false; #ifdef SO_NOSIGPIPE int set = 1; setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int)); #endif #ifdef WIN32 u_long fNonblock = 1; if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR) #else int fFlags = fcntl(hSocket, F_GETFL, 0); if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) == -1) #endif { closesocket(hSocket); return false; } if (connect(hSocket, (struct sockaddr *)&sockaddr, len) == SOCKET_ERROR) { // WSAEINVAL is here because some legacy version of winsock uses it if (WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == WSAEINVAL) { struct timeval timeout; timeout.tv_sec = nTimeout / 1000; timeout.tv_usec = (nTimeout % 1000) * 1000; fd_set fdset; FD_ZERO(&fdset); FD_SET(hSocket, &fdset); int nRet = select(hSocket + 1, nullptr, &fdset, nullptr, &timeout); if (nRet == 0) { printf("connection timeout\n"); closesocket(hSocket); return false; } if (nRet == SOCKET_ERROR) { printf("select() for connection failed: %i\n", WSAGetLastError()); closesocket(hSocket); return false; } socklen_t nRetSize = sizeof(nRet); #ifdef WIN32 if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (char *)(&nRet), &nRetSize) == SOCKET_ERROR) #else if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR) #endif { printf("getsockopt() for connection failed: %i\n", WSAGetLastError()); closesocket(hSocket); return false; } if (nRet != 0) { printf("connect() failed after select(): %s\n", strerror(nRet)); closesocket(hSocket); return false; } } #ifdef WIN32 else if (WSAGetLastError() != WSAEISCONN) #else else #endif { printf("connect() failed: %i\n", WSAGetLastError()); closesocket(hSocket); return false; } } // this isn't even strictly necessary // CNode::ConnectNode immediately turns the socket back to non-blocking // but we'll turn it back to blocking just in case #ifdef WIN32 fNonblock = 0; if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR) #else fFlags = fcntl(hSocket, F_GETFL, 0); if (fcntl(hSocket, F_SETFL, fFlags & !O_NONBLOCK) == SOCKET_ERROR) #endif { closesocket(hSocket); return false; } hSocketRet = hSocket; return true; } bool SetProxy(enum Network net, CService addrProxy, int nSocksVersion) { assert(net >= 0 && net < NET_MAX); if (nSocksVersion != 0 && nSocksVersion != 4 && nSocksVersion != 5) return false; if (nSocksVersion != 0 && !addrProxy.IsValid()) return false; proxyInfo[net] = std::make_pair(addrProxy, nSocksVersion); return true; } bool GetProxy(enum Network net, CService &addrProxy) { assert(net >= 0 && net < NET_MAX); if (!proxyInfo[net].second) return false; addrProxy = proxyInfo[net].first; return true; } bool SetNameProxy(CService addrProxy, int nSocksVersion) { if (nSocksVersion != 0 && nSocksVersion != 5) return false; if (nSocksVersion != 0 && !addrProxy.IsValid()) return false; nameproxyInfo = std::make_pair(addrProxy, nSocksVersion); return true; } bool GetNameProxy() { return nameproxyInfo.second != 0; } bool IsProxy(const CNetAddr &addr) { for (int i = 0; i < NET_MAX; i++) { if (proxyInfo[i].second && (addr == (CNetAddr)proxyInfo[i].first)) return true; } return false; } bool ConnectSocket(const CService &addrDest, SOCKET &hSocketRet, int nTimeout) { const proxyType &proxy = proxyInfo[addrDest.GetNetwork()]; // no proxy needed if (!proxy.second) return ConnectSocketDirectly(addrDest, hSocketRet, nTimeout); SOCKET hSocket = INVALID_SOCKET; // first connect to proxy server if (!ConnectSocketDirectly(proxy.first, hSocket, nTimeout)) return false; // do socks negotiation switch (proxy.second) { case 4: if (!Socks4(addrDest, hSocket)) return false; break; case 5: if (!Socks5(addrDest.ToStringIP(), addrDest.GetPort(), hSocket)) return false; break; default: return false; } hSocketRet = hSocket; return true; } bool ConnectSocketByName(CService &addr, SOCKET &hSocketRet, const char *pszDest, int portDefault, int nTimeout) { std::string strDest; int port = portDefault; SplitHostPort(std::string(pszDest), port, strDest); SOCKET hSocket = INVALID_SOCKET; CService addrResolved( CNetAddr(strDest, fNameLookup && !nameproxyInfo.second), port); if (addrResolved.IsValid()) { addr = addrResolved; return ConnectSocket(addr, hSocketRet, nTimeout); } addr = CService("0.0.0.0:0"); if (!nameproxyInfo.second) return false; if (!ConnectSocketDirectly(nameproxyInfo.first, hSocket, nTimeout)) return false; switch (nameproxyInfo.second) { default: case 4: return false; case 5: if (!Socks5(strDest, port, hSocket)) return false; break; } hSocketRet = hSocket; return true; } void CNetAddr::Init() { memset(ip, 0, 16); } void CNetAddr::SetIP(const CNetAddr &ipIn) { memcpy(ip, ipIn.ip, sizeof(ip)); } static const uint8_t pchOnionCat[] = {0xFD, 0x87, 0xD8, 0x7E, 0xEB, 0x43}; static const uint8_t pchGarliCat[] = {0xFD, 0x60, 0xDB, 0x4D, 0xDD, 0xB5}; bool CNetAddr::SetSpecial(const std::string &strName) { if (strName.size() > 6 && strName.substr(strName.size() - 6, 6) == ".onion") { std::vector vchAddr = DecodeBase32(strName.substr(0, strName.size() - 6).c_str()); if (vchAddr.size() != 16 - sizeof(pchOnionCat)) return false; memcpy(ip, pchOnionCat, sizeof(pchOnionCat)); for (unsigned int i = 0; i < 16 - sizeof(pchOnionCat); i++) ip[i + sizeof(pchOnionCat)] = vchAddr[i]; return true; } if (strName.size() > 11 && strName.substr(strName.size() - 11, 11) == ".oc.b32.i2p") { std::vector vchAddr = DecodeBase32(strName.substr(0, strName.size() - 11).c_str()); if (vchAddr.size() != 16 - sizeof(pchGarliCat)) return false; memcpy(ip, pchOnionCat, sizeof(pchGarliCat)); for (unsigned int i = 0; i < 16 - sizeof(pchGarliCat); i++) ip[i + sizeof(pchGarliCat)] = vchAddr[i]; return true; } return false; } CNetAddr::CNetAddr() { Init(); } CNetAddr::CNetAddr(const struct in_addr &ipv4Addr) { memcpy(ip, pchIPv4, 12); memcpy(ip + 12, &ipv4Addr, 4); } CNetAddr::CNetAddr(const struct in6_addr &ipv6Addr) { memcpy(ip, &ipv6Addr, 16); } CNetAddr::CNetAddr(const char *pszIp, bool fAllowLookup) { Init(); std::vector vIP; if (LookupHost(pszIp, vIP, 1, fAllowLookup)) *this = vIP[0]; } CNetAddr::CNetAddr(const std::string &strIp, bool fAllowLookup) { Init(); std::vector vIP; if (LookupHost(strIp.c_str(), vIP, 1, fAllowLookup)) *this = vIP[0]; } unsigned int CNetAddr::GetByte(int n) const { return ip[15 - n]; } bool CNetAddr::IsIPv4() const { return (memcmp(ip, pchIPv4, sizeof(pchIPv4)) == 0); } bool CNetAddr::IsIPv6() const { return (!IsIPv4() && !IsTor() && !IsI2P()); } bool CNetAddr::IsRFC1918() const { return IsIPv4() && (GetByte(3) == 10 || (GetByte(3) == 192 && GetByte(2) == 168) || (GetByte(3) == 172 && (GetByte(2) >= 16 && GetByte(2) <= 31))); } bool CNetAddr::IsReserved() const { return IsIPv4() && (GetByte(3) >= 240); } bool CNetAddr::IsRFC3927() const { return IsIPv4() && (GetByte(3) == 169 && GetByte(2) == 254); } bool CNetAddr::IsRFC3849() const { return GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x0D && GetByte(12) == 0xB8; } bool CNetAddr::IsRFC3964() const { return (GetByte(15) == 0x20 && GetByte(14) == 0x02); } bool CNetAddr::IsRFC6052() const { static const uint8_t pchRFC6052[] = {0, 0x64, 0xFF, 0x9B, 0, 0, 0, 0, 0, 0, 0, 0}; return (memcmp(ip, pchRFC6052, sizeof(pchRFC6052)) == 0); } bool CNetAddr::IsRFC4380() const { return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0 && GetByte(12) == 0); } bool CNetAddr::IsRFC4862() const { static const uint8_t pchRFC4862[] = {0xFE, 0x80, 0, 0, 0, 0, 0, 0}; return (memcmp(ip, pchRFC4862, sizeof(pchRFC4862)) == 0); } bool CNetAddr::IsRFC4193() const { return ((GetByte(15) & 0xFE) == 0xFC); } bool CNetAddr::IsRFC6145() const { static const uint8_t pchRFC6145[] = {0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0}; return (memcmp(ip, pchRFC6145, sizeof(pchRFC6145)) == 0); } bool CNetAddr::IsRFC4843() const { return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x00 && (GetByte(12) & 0xF0) == 0x10); } bool CNetAddr::IsTor() const { return (memcmp(ip, pchOnionCat, sizeof(pchOnionCat)) == 0); } bool CNetAddr::IsI2P() const { return (memcmp(ip, pchGarliCat, sizeof(pchGarliCat)) == 0); } bool CNetAddr::IsLocal() const { // IPv4 loopback if (IsIPv4() && (GetByte(3) == 127 || GetByte(3) == 0)) return true; // IPv6 loopback (::1/128) static const uint8_t pchLocal[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; if (memcmp(ip, pchLocal, 16) == 0) return true; return false; } bool CNetAddr::IsMulticast() const { return (IsIPv4() && (GetByte(3) & 0xF0) == 0xE0) || (GetByte(15) == 0xFF); } bool CNetAddr::IsValid() const { // Cleanup 3-byte shifted addresses caused by garbage in size field // of addr messages from versions before 0.2.9 checksum. // Two consecutive addr messages look like this: // header20 vectorlen3 addr26 addr26 addr26 header20 vectorlen3 addr26 // addr26 addr26... // so if the first length field is garbled, it reads the second batch // of addr misaligned by 3 bytes. if (memcmp(ip, pchIPv4 + 3, sizeof(pchIPv4) - 3) == 0) return false; // unspecified IPv6 address (::/128) uint8_t ipNone[16] = {}; if (memcmp(ip, ipNone, 16) == 0) return false; // documentation IPv6 address if (IsRFC3849()) return false; if (IsIPv4()) { // INADDR_NONE uint32_t ipNone = INADDR_NONE; if (memcmp(ip + 12, &ipNone, 4) == 0) return false; // 0 ipNone = 0; if (memcmp(ip + 12, &ipNone, 4) == 0) return false; } return true; } bool CNetAddr::IsRoutable() const { return IsValid() && !(IsReserved() || IsRFC1918() || IsRFC3927() || IsRFC4862() || (IsRFC4193() && !IsTor() && !IsI2P()) || IsRFC4843() || IsLocal()); } enum Network CNetAddr::GetNetwork() const { if (!IsRoutable()) return NET_UNROUTABLE; if (IsIPv4()) return NET_IPV4; if (IsTor()) return NET_TOR; if (IsI2P()) return NET_I2P; return NET_IPV6; } std::string CNetAddr::ToStringIP() const { if (IsTor()) return EncodeBase32(&ip[6], 10) + ".onion"; if (IsI2P()) return EncodeBase32(&ip[6], 10) + ".oc.b32.i2p"; CService serv(*this, 0); struct sockaddr_storage sockaddr; socklen_t socklen = sizeof(sockaddr); if (serv.GetSockAddr((struct sockaddr *)&sockaddr, &socklen)) { char name[1025] = ""; if (!getnameinfo((const struct sockaddr *)&sockaddr, socklen, name, sizeof(name), nullptr, 0, NI_NUMERICHOST)) return std::string(name); } if (IsIPv4()) { return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0)); } return strprintf("%x:%x:%x:%x:%x:%x:%x:%x", GetByte(15) << 8 | GetByte(14), GetByte(13) << 8 | GetByte(12), GetByte(11) << 8 | GetByte(10), GetByte(9) << 8 | GetByte(8), GetByte(7) << 8 | GetByte(6), GetByte(5) << 8 | GetByte(4), GetByte(3) << 8 | GetByte(2), GetByte(1) << 8 | GetByte(0)); } std::string CNetAddr::ToString() const { return ToStringIP(); } bool operator==(const CNetAddr &a, const CNetAddr &b) { return (memcmp(a.ip, b.ip, 16) == 0); } bool operator!=(const CNetAddr &a, const CNetAddr &b) { return (memcmp(a.ip, b.ip, 16) != 0); } bool operator<(const CNetAddr &a, const CNetAddr &b) { return (memcmp(a.ip, b.ip, 16) < 0); } bool CNetAddr::GetInAddr(struct in_addr *pipv4Addr) const { if (!IsIPv4()) return false; memcpy(pipv4Addr, ip + 12, 4); return true; } bool CNetAddr::GetIn6Addr(struct in6_addr *pipv6Addr) const { memcpy(pipv6Addr, ip, 16); return true; } // get canonical identifier of an address' group // no two connections will be attempted to addresses with the same group std::vector CNetAddr::GetGroup() const { std::vector vchRet; int nClass = NET_IPV6; int nStartByte = 0; int nBits = 16; // all local addresses belong to the same group if (IsLocal()) { nClass = 255; nBits = 0; } // all unroutable addresses belong to the same group if (!IsRoutable()) { nClass = NET_UNROUTABLE; nBits = 0; } // for IPv4 addresses, '1' + the 16 higher-order bits of the IP // includes mapped IPv4, SIIT translated IPv4, and the well-known prefix else if (IsIPv4() || IsRFC6145() || IsRFC6052()) { nClass = NET_IPV4; nStartByte = 12; } // for 6to4 tunnelled addresses, use the encapsulated IPv4 address else if (IsRFC3964()) { nClass = NET_IPV4; nStartByte = 2; } // for Teredo-tunnelled IPv6 addresses, use the encapsulated IPv4 address else if (IsRFC4380()) { vchRet.push_back(NET_IPV4); vchRet.push_back(GetByte(3) ^ 0xFF); vchRet.push_back(GetByte(2) ^ 0xFF); return vchRet; } else if (IsTor()) { nClass = NET_TOR; nStartByte = 6; nBits = 4; } else if (IsI2P()) { nClass = NET_I2P; nStartByte = 6; nBits = 4; } else if (GetByte(15) == 0x20 && GetByte(14) == 0x11 && GetByte(13) == 0x04 && GetByte(12) == 0x70) { // for he.net, use /36 groups nBits = 36; } else { // for the rest of the IPv6 network, use /32 groups nBits = 32; } vchRet.push_back(nClass); while (nBits >= 8) { vchRet.push_back(GetByte(15 - nStartByte)); nStartByte++; nBits -= 8; } if (nBits > 0) vchRet.push_back(GetByte(15 - nStartByte) | ((1 << nBits) - 1)); return vchRet; } -uint64 CNetAddr::GetHash() const { +uint64_t CNetAddr::GetHash() const { uint256 hash = Hash(&ip[0], &ip[16]); - uint64 nRet; + uint64_t nRet; memcpy(&nRet, &hash, sizeof(nRet)); return nRet; } void CNetAddr::print() const { printf("CNetAddr(%s)\n", ToString().c_str()); } // private extensions to enum Network, only returned by GetExtNetwork, // and only used in GetReachabilityFrom static const int NET_UNKNOWN = NET_MAX + 0; static const int NET_TEREDO = NET_MAX + 1; static int GetExtNetwork(const CNetAddr *addr) { if (addr == nullptr) return NET_UNKNOWN; if (addr->IsRFC4380()) return NET_TEREDO; return addr->GetNetwork(); } /** Calculates a metric for how reachable (*this) is from a given partner */ int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const { enum Reachability { REACH_UNREACHABLE, REACH_DEFAULT, REACH_TEREDO, REACH_IPV6_WEAK, REACH_IPV4, REACH_IPV6_STRONG, REACH_PRIVATE }; if (!IsRoutable()) return REACH_UNREACHABLE; int ourNet = GetExtNetwork(this); int theirNet = GetExtNetwork(paddrPartner); bool fTunnel = IsRFC3964() || IsRFC6052() || IsRFC6145(); switch (theirNet) { case NET_IPV4: switch (ourNet) { default: return REACH_DEFAULT; case NET_IPV4: return REACH_IPV4; } case NET_IPV6: switch (ourNet) { default: return REACH_DEFAULT; case NET_TEREDO: return REACH_TEREDO; case NET_IPV4: return REACH_IPV4; case NET_IPV6: // only prefer giving our IPv6 address if it's not tunnelled return fTunnel ? REACH_IPV6_WEAK : REACH_IPV6_STRONG; } case NET_TOR: switch (ourNet) { default: return REACH_DEFAULT; case NET_IPV4: // Tor users can connect to IPv4 as well return REACH_IPV4; case NET_TOR: return REACH_PRIVATE; } case NET_I2P: switch (ourNet) { default: return REACH_DEFAULT; case NET_I2P: return REACH_PRIVATE; } case NET_TEREDO: switch (ourNet) { default: return REACH_DEFAULT; case NET_TEREDO: return REACH_TEREDO; case NET_IPV6: return REACH_IPV6_WEAK; case NET_IPV4: return REACH_IPV4; } case NET_UNKNOWN: case NET_UNROUTABLE: default: switch (ourNet) { default: return REACH_DEFAULT; case NET_TEREDO: return REACH_TEREDO; case NET_IPV6: return REACH_IPV6_WEAK; case NET_IPV4: return REACH_IPV4; case NET_I2P: // assume connections from unroutable addresses are return REACH_PRIVATE; case NET_TOR: // either from Tor/I2P, or don't care about our address return REACH_PRIVATE; } } } void CService::Init() { port = 0; } CService::CService() { Init(); } CService::CService(const CNetAddr &cip, unsigned short portIn) : CNetAddr(cip), port(portIn) {} CService::CService(const struct in_addr &ipv4Addr, unsigned short portIn) : CNetAddr(ipv4Addr), port(portIn) {} CService::CService(const struct in6_addr &ipv6Addr, unsigned short portIn) : CNetAddr(ipv6Addr), port(portIn) {} CService::CService(const struct sockaddr_in &addr) : CNetAddr(addr.sin_addr), port(ntohs(addr.sin_port)) { assert(addr.sin_family == AF_INET); } CService::CService(const struct sockaddr_in6 &addr) : CNetAddr(addr.sin6_addr), port(ntohs(addr.sin6_port)) { assert(addr.sin6_family == AF_INET6); } bool CService::SetSockAddr(const struct sockaddr *paddr) { switch (paddr->sa_family) { case AF_INET: *this = CService(*(const struct sockaddr_in *)paddr); return true; case AF_INET6: *this = CService(*(const struct sockaddr_in6 *)paddr); return true; default: return false; } } CService::CService(const char *pszIpPort, bool fAllowLookup) { Init(); CService ip; if (Lookup(pszIpPort, ip, 0, fAllowLookup)) *this = ip; } CService::CService(const char *pszIpPort, int portDefault, bool fAllowLookup) { Init(); CService ip; if (Lookup(pszIpPort, ip, portDefault, fAllowLookup)) *this = ip; } CService::CService(const std::string &strIpPort, bool fAllowLookup) { Init(); CService ip; if (Lookup(strIpPort.c_str(), ip, 0, fAllowLookup)) *this = ip; } CService::CService(const std::string &strIpPort, int portDefault, bool fAllowLookup) { Init(); CService ip; if (Lookup(strIpPort.c_str(), ip, portDefault, fAllowLookup)) *this = ip; } unsigned short CService::GetPort() const { return port; } bool operator==(const CService &a, const CService &b) { return (CNetAddr)a == (CNetAddr)b && a.port == b.port; } bool operator!=(const CService &a, const CService &b) { return (CNetAddr)a != (CNetAddr)b || a.port != b.port; } bool operator<(const CService &a, const CService &b) { return (CNetAddr)a < (CNetAddr)b || ((CNetAddr)a == (CNetAddr)b && a.port < b.port); } bool CService::GetSockAddr(struct sockaddr *paddr, socklen_t *addrlen) const { if (IsIPv4()) { if (*addrlen < (socklen_t)sizeof(struct sockaddr_in)) return false; *addrlen = sizeof(struct sockaddr_in); struct sockaddr_in *paddrin = (struct sockaddr_in *)paddr; memset(paddrin, 0, *addrlen); if (!GetInAddr(&paddrin->sin_addr)) return false; paddrin->sin_family = AF_INET; paddrin->sin_port = htons(port); return true; } if (IsIPv6()) { if (*addrlen < (socklen_t)sizeof(struct sockaddr_in6)) return false; *addrlen = sizeof(struct sockaddr_in6); struct sockaddr_in6 *paddrin6 = (struct sockaddr_in6 *)paddr; memset(paddrin6, 0, *addrlen); if (!GetIn6Addr(&paddrin6->sin6_addr)) return false; paddrin6->sin6_family = AF_INET6; paddrin6->sin6_port = htons(port); return true; } return false; } std::vector CService::GetKey() const { std::vector vKey; vKey.resize(18); memcpy(&vKey[0], ip, 16); vKey[16] = port / 0x100; vKey[17] = port & 0x0FF; return vKey; } std::string CService::ToStringPort() const { return strprintf("%u", port); } std::string CService::ToStringIPPort() const { if (IsIPv4() || IsTor() || IsI2P()) { return ToStringIP() + ":" + ToStringPort(); } else { return "[" + ToStringIP() + "]:" + ToStringPort(); } } std::string CService::ToString() const { return ToStringIPPort(); } void CService::print() const { printf("CService(%s)\n", ToString().c_str()); } void CService::SetPort(unsigned short portIn) { port = portIn; } diff --git a/src/seeder/netbase.h b/src/seeder/netbase.h index 6eb1cf50b7..20b4259de0 100644 --- a/src/seeder/netbase.h +++ b/src/seeder/netbase.h @@ -1,149 +1,149 @@ // Copyright (c) 2009-2012 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_SEEDER_NETBASE_H #define BITCOIN_SEEDER_NETBASE_H #include "compat.h" #include "serialize.h" #include #include extern int nConnectTimeout; #ifdef WIN32 // In MSVC, this is defined as a macro, undefine it to prevent a compile and // link error #undef SetPort #endif enum Network { NET_UNROUTABLE, NET_IPV4, NET_IPV6, NET_TOR, NET_I2P, NET_MAX, }; extern int nConnectTimeout; extern bool fNameLookup; /** IP address (IPv6, or IPv4 using mapped IPv6 range (::FFFF:0:0/96)) */ class CNetAddr { protected: uint8_t ip[16]; // in network byte order public: CNetAddr(); CNetAddr(const struct in_addr &ipv4Addr); explicit CNetAddr(const char *pszIp, bool fAllowLookup = false); explicit CNetAddr(const std::string &strIp, bool fAllowLookup = false); void Init(); void SetIP(const CNetAddr &ip); bool SetSpecial(const std::string &strName); // for Tor and I2P addresses bool IsIPv4() const; // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0) bool IsIPv6() const; // IPv6 address (not mapped IPv4, not Tor/I2P) bool IsReserved() const; // Against Hetzners Abusal/Netscan Bot bool IsRFC1918() const; // IPv4 private networks (10.0.0.0/8, // 192.168.0.0/16, 172.16.0.0/12) bool IsRFC3849() const; // IPv6 documentation address (2001:0DB8::/32) bool IsRFC3927() const; // IPv4 autoconfig (169.254.0.0/16) bool IsRFC3964() const; // IPv6 6to4 tunnelling (2002::/16) bool IsRFC4193() const; // IPv6 unique local (FC00::/15) bool IsRFC4380() const; // IPv6 Teredo tunnelling (2001::/32) bool IsRFC4843() const; // IPv6 ORCHID (2001:10::/28) bool IsRFC4862() const; // IPv6 autoconfig (FE80::/64) bool IsRFC6052() const; // IPv6 well-known prefix (64:FF9B::/96) bool IsRFC6145() const; // IPv6 IPv4-translated address (::FFFF:0:0:0/96) bool IsTor() const; bool IsI2P() const; bool IsLocal() const; bool IsRoutable() const; bool IsValid() const; bool IsMulticast() const; enum Network GetNetwork() const; std::string ToString() const; std::string ToStringIP() const; unsigned int GetByte(int n) const; - uint64 GetHash() const; + uint64_t GetHash() const; bool GetInAddr(struct in_addr *pipv4Addr) const; std::vector GetGroup() const; int GetReachabilityFrom(const CNetAddr *paddrPartner = nullptr) const; void print() const; CNetAddr(const struct in6_addr &pipv6Addr); bool GetIn6Addr(struct in6_addr *pipv6Addr) const; friend bool operator==(const CNetAddr &a, const CNetAddr &b); friend bool operator!=(const CNetAddr &a, const CNetAddr &b); friend bool operator<(const CNetAddr &a, const CNetAddr &b); IMPLEMENT_SERIALIZE(READWRITE(FLATDATA(ip));) }; /** A combination of a network address (CNetAddr) and a (TCP) port */ class CService : public CNetAddr { protected: unsigned short port; // host order public: CService(); CService(const CNetAddr &ip, unsigned short port); CService(const struct in_addr &ipv4Addr, unsigned short port); CService(const struct sockaddr_in &addr); explicit CService(const char *pszIpPort, int portDefault, bool fAllowLookup = false); explicit CService(const char *pszIpPort, bool fAllowLookup = false); explicit CService(const std::string &strIpPort, int portDefault, bool fAllowLookup = false); explicit CService(const std::string &strIpPort, bool fAllowLookup = false); void Init(); void SetPort(unsigned short portIn); unsigned short GetPort() const; bool GetSockAddr(struct sockaddr *paddr, socklen_t *addrlen) const; bool SetSockAddr(const struct sockaddr *paddr); friend bool operator==(const CService &a, const CService &b); friend bool operator!=(const CService &a, const CService &b); friend bool operator<(const CService &a, const CService &b); std::vector GetKey() const; std::string ToString() const; std::string ToStringPort() const; std::string ToStringIPPort() const; void print() const; CService(const struct in6_addr &ipv6Addr, unsigned short port); CService(const struct sockaddr_in6 &addr); IMPLEMENT_SERIALIZE(CService *pthis = const_cast(this); READWRITE(FLATDATA(ip)); unsigned short portN = htons(port); READWRITE(portN); if (fRead) pthis->port = ntohs(portN);) }; enum Network ParseNetwork(std::string net); void SplitHostPort(std::string in, int &portOut, std::string &hostOut); bool SetProxy(enum Network net, CService addrProxy, int nSocksVersion = 5); bool GetProxy(enum Network net, CService &addrProxy); bool IsProxy(const CNetAddr &addr); bool SetNameProxy(CService addrProxy, int nSocksVersion = 5); bool GetNameProxy(); bool LookupHost(const char *pszName, std::vector &vIP, unsigned int nMaxSolutions = 0, bool fAllowLookup = true); bool LookupHostNumeric(const char *pszName, std::vector &vIP, unsigned int nMaxSolutions = 0); bool Lookup(const char *pszName, CService &addr, int portDefault = 0, bool fAllowLookup = true); bool Lookup(const char *pszName, std::vector &vAddr, int portDefault = 0, bool fAllowLookup = true, unsigned int nMaxSolutions = 0); bool LookupNumeric(const char *pszName, CService &addr, int portDefault = 0); bool ConnectSocket(const CService &addr, SOCKET &hSocketRet, int nTimeout = nConnectTimeout); bool ConnectSocketByName(CService &addr, SOCKET &hSocketRet, const char *pszDest, int portDefault = 0, int nTimeout = nConnectTimeout); #endif diff --git a/src/seeder/protocol.h b/src/seeder/protocol.h index 6670a696e3..361c270fef 100644 --- a/src/seeder/protocol.h +++ b/src/seeder/protocol.h @@ -1,111 +1,111 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2011 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. #ifndef __cplusplus #error This header can only be compiled as C++. #endif #ifndef BITCOIN_SEEDER_PROTOCOL_H #define BITCOIN_SEEDER_PROTOCOL_H #include "netbase.h" #include "serialize.h" #include "uint256.h" #include #include extern bool fTestNet; static inline unsigned short GetDefaultPort(const bool testnet = fTestNet) { return testnet ? 18333 : 8333; } // // Message header // (4) message start // (12) command // (4) size // (4) checksum extern uint8_t pchMessageStart[4]; class CMessageHeader { public: CMessageHeader(); CMessageHeader(const char *pszCommand, unsigned int nMessageSizeIn); std::string GetCommand() const; bool IsValid() const; IMPLEMENT_SERIALIZE(READWRITE(FLATDATA(pchMessageStart)); READWRITE(FLATDATA(pchCommand)); READWRITE(nMessageSize); if (nVersion >= 209) READWRITE(nChecksum);) // TODO: make private (improves encapsulation) public: enum { COMMAND_SIZE = 12 }; char pchMessageStart[sizeof(::pchMessageStart)]; char pchCommand[COMMAND_SIZE]; unsigned int nMessageSize; unsigned int nChecksum; }; enum ServiceFlags : uint64_t { NODE_NETWORK = (1 << 0), NODE_BLOOM = (1 << 2), NODE_XTHIN = (1 << 4), NODE_BITCOIN_CASH = (1 << 5), }; class CAddress : public CService { public: CAddress(); CAddress(CService ipIn, uint64_t nServicesIn = NODE_NETWORK | NODE_BITCOIN_CASH); void Init(); IMPLEMENT_SERIALIZE(CAddress *pthis = const_cast(this); CService *pip = (CService *)pthis; if (fRead) pthis->Init(); if (nType & SER_DISK) READWRITE(nVersion); if ((nType & SER_DISK) || (nVersion >= 31402 && !(nType & SER_GETHASH))) READWRITE(nTime); READWRITE(nServices); READWRITE(*pip);) void print() const; // TODO: make private (improves encapsulation) public: - uint64 nServices; + uint64_t nServices; // disk and network only unsigned int nTime; }; class CInv { public: CInv(); CInv(int typeIn, const uint256 &hashIn); CInv(const std::string &strType, const uint256 &hashIn); IMPLEMENT_SERIALIZE(READWRITE(type); READWRITE(hash);) friend bool operator<(const CInv &a, const CInv &b); bool IsKnownType() const; const char *GetCommand() const; std::string ToString() const; void print() const; // TODO: make private (improves encapsulation) public: int type; uint256 hash; }; #endif // __INCLUDED_PROTOCOL_H__ diff --git a/src/seeder/serialize.h b/src/seeder/serialize.h index bc37268eb1..278bb9888d 100644 --- a/src/seeder/serialize.h +++ b/src/seeder/serialize.h @@ -1,1358 +1,1320 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2011 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_SEEDER_SERIALIZE_H #define BITCOIN_SEEDER_SERIALIZE_H #include #include +#include #include #include #include #include #include #include #include #include #include #include -#if defined(_MSC_VER) || defined(__BORLANDC__) -typedef __int64 int64; -typedef unsigned __int64 uint64; -#else -typedef long long int64; -typedef unsigned long long uint64; -#endif #if defined(_MSC_VER) && _MSC_VER < 1300 #define for if (false); else for #endif #ifdef WIN32 #include // This is used to attempt to keep keying material out of swap // Note that VirtualLock does not provide this as a guarantee on Windows, // but, in practice, memory that has been VirtualLock'd almost never gets // written to // the pagefile except in rare circumstances where memory is extremely low. #include #define mlock(p, n) VirtualLock((p), (n)); #define munlock(p, n) VirtualUnlock((p), (n)); #else #include #include /* This comes from limits.h if it's not defined there set a sane default */ #ifndef PAGESIZE #include #define PAGESIZE sysconf(_SC_PAGESIZE) #endif #define mlock(a, b) \ mlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))), \ (((((size_t)(a)) + (b)-1) | ((PAGESIZE)-1)) + 1) - \ (((size_t)(a)) & (~((PAGESIZE)-1)))) #define munlock(a, b) \ munlock(((void *)(((size_t)(a)) & (~((PAGESIZE)-1)))), \ (((((size_t)(a)) + (b)-1) | ((PAGESIZE)-1)) + 1) - \ (((size_t)(a)) & (~((PAGESIZE)-1)))) #endif class CScript; class CDataStream; class CAutoFile; static const unsigned int MAX_SIZE = 0x02000000; static const int PROTOCOL_VERSION = 60000; // Used to bypass the rule against non-const reference to temporary // where it makes sense with wrappers such as CFlatData or CTxDB template inline T &REF(const T &val) { return const_cast(val); } ///////////////////////////////////////////////////////////////// // // Templates for serializing to anything that looks like a stream, // i.e. anything that supports .read(char*, int) and .write(char*, int) // enum { // primary actions SER_NETWORK = (1 << 0), SER_DISK = (1 << 1), SER_GETHASH = (1 << 2), // modifiers SER_SKIPSIG = (1 << 16), SER_BLOCKHEADERONLY = (1 << 17), }; #define IMPLEMENT_SERIALIZE(statements) \ unsigned int GetSerializeSize(int nType = 0, \ int nVersion = PROTOCOL_VERSION) const { \ CSerActionGetSerializeSize ser_action; \ const bool fGetSize = true; \ const bool fWrite = false; \ const bool fRead = false; \ unsigned int nSerSize = 0; \ ser_streamplaceholder s; \ s.nType = nType; \ s.nVersion = nVersion; \ { statements } \ return nSerSize; \ } \ template \ void Serialize(Stream &s, int nType = 0, int nVersion = PROTOCOL_VERSION) \ const { \ CSerActionSerialize ser_action; \ const bool fGetSize = false; \ const bool fWrite = true; \ const bool fRead = false; \ unsigned int nSerSize = 0; \ { statements } \ } \ template \ void Unserialize(Stream &s, int nType = 0, \ int nVersion = PROTOCOL_VERSION) { \ CSerActionUnserialize ser_action; \ const bool fGetSize = false; \ const bool fWrite = false; \ const bool fRead = true; \ unsigned int nSerSize = 0; \ { statements } \ } #define READWRITE(obj) \ (nSerSize += ::SerReadWrite(s, (obj), nType, nVersion, ser_action)) // // Basic types // #define WRITEDATA(s, obj) s.write((char *)&(obj), sizeof(obj)) #define READDATA(s, obj) s.read((char *)&(obj), sizeof(obj)) -inline unsigned int GetSerializeSize(char a, int, int = 0) { - return sizeof(a); -} -inline unsigned int GetSerializeSize(signed char a, int, int = 0) { +inline unsigned int GetSerializeSize(int8_t a, int, int = 0) { return sizeof(a); } inline unsigned int GetSerializeSize(uint8_t a, int, int = 0) { return sizeof(a); } -inline unsigned int GetSerializeSize(signed short a, int, int = 0) { - return sizeof(a); -} -inline unsigned int GetSerializeSize(unsigned short a, int, int = 0) { - return sizeof(a); -} -inline unsigned int GetSerializeSize(signed int a, int, int = 0) { +inline unsigned int GetSerializeSize(int16_t a, int, int = 0) { return sizeof(a); } -inline unsigned int GetSerializeSize(unsigned int a, int, int = 0) { +inline unsigned int GetSerializeSize(uint16_t a, int, int = 0) { return sizeof(a); } -inline unsigned int GetSerializeSize(signed long a, int, int = 0) { +inline unsigned int GetSerializeSize(int32_t a, int, int = 0) { return sizeof(a); } -inline unsigned int GetSerializeSize(unsigned long a, int, int = 0) { +inline unsigned int GetSerializeSize(uint32_t a, int, int = 0) { return sizeof(a); } -inline unsigned int GetSerializeSize(int64 a, int, int = 0) { +inline unsigned int GetSerializeSize(int64_t a, int, int = 0) { return sizeof(a); } -inline unsigned int GetSerializeSize(uint64 a, int, int = 0) { +inline unsigned int GetSerializeSize(uint64_t a, int, int = 0) { return sizeof(a); } inline unsigned int GetSerializeSize(float a, int, int = 0) { return sizeof(a); } inline unsigned int GetSerializeSize(double a, int, int = 0) { return sizeof(a); } template -inline void Serialize(Stream &s, char a, int, int = 0) { - WRITEDATA(s, a); -} -template -inline void Serialize(Stream &s, signed char a, int, int = 0) { +inline void Serialize(Stream &s, int8_t a, int, int = 0) { WRITEDATA(s, a); } template inline void Serialize(Stream &s, uint8_t a, int, int = 0) { WRITEDATA(s, a); } template -inline void Serialize(Stream &s, signed short a, int, int = 0) { - WRITEDATA(s, a); -} -template -inline void Serialize(Stream &s, unsigned short a, int, int = 0) { +inline void Serialize(Stream &s, int16_t a, int, int = 0) { WRITEDATA(s, a); } template -inline void Serialize(Stream &s, signed int a, int, int = 0) { +inline void Serialize(Stream &s, uint16_t a, int, int = 0) { WRITEDATA(s, a); } template -inline void Serialize(Stream &s, unsigned int a, int, int = 0) { +inline void Serialize(Stream &s, int32_t a, int, int = 0) { WRITEDATA(s, a); } template -inline void Serialize(Stream &s, signed long a, int, int = 0) { +inline void Serialize(Stream &s, uint32_t a, int, int = 0) { WRITEDATA(s, a); } template -inline void Serialize(Stream &s, unsigned long a, int, int = 0) { +inline void Serialize(Stream &s, int64_t a, int, int = 0) { WRITEDATA(s, a); } template -inline void Serialize(Stream &s, int64 a, int, int = 0) { - WRITEDATA(s, a); -} -template -inline void Serialize(Stream &s, uint64 a, int, int = 0) { +inline void Serialize(Stream &s, uint64_t a, int, int = 0) { WRITEDATA(s, a); } template inline void Serialize(Stream &s, float a, int, int = 0) { WRITEDATA(s, a); } template inline void Serialize(Stream &s, double a, int, int = 0) { WRITEDATA(s, a); } template -inline void Unserialize(Stream &s, char &a, int, int = 0) { - READDATA(s, a); -} -template -inline void Unserialize(Stream &s, signed char &a, int, int = 0) { +inline void Unserialize(Stream &s, int8_t &a, int, int = 0) { READDATA(s, a); } template inline void Unserialize(Stream &s, uint8_t &a, int, int = 0) { READDATA(s, a); } template -inline void Unserialize(Stream &s, signed short &a, int, int = 0) { +inline void Unserialize(Stream &s, int16_t &a, int, int = 0) { READDATA(s, a); } template -inline void Unserialize(Stream &s, unsigned short &a, int, int = 0) { +inline void Unserialize(Stream &s, uint16_t &a, int, int = 0) { READDATA(s, a); } template -inline void Unserialize(Stream &s, signed int &a, int, int = 0) { +inline void Unserialize(Stream &s, int32_t &a, int, int = 0) { READDATA(s, a); } template -inline void Unserialize(Stream &s, unsigned int &a, int, int = 0) { +inline void Unserialize(Stream &s, uint32_t &a, int, int = 0) { READDATA(s, a); } template -inline void Unserialize(Stream &s, signed long &a, int, int = 0) { +inline void Unserialize(Stream &s, int64_t &a, int, int = 0) { READDATA(s, a); } template -inline void Unserialize(Stream &s, unsigned long &a, int, int = 0) { - READDATA(s, a); -} -template -inline void Unserialize(Stream &s, int64 &a, int, int = 0) { - READDATA(s, a); -} -template -inline void Unserialize(Stream &s, uint64 &a, int, int = 0) { +inline void Unserialize(Stream &s, uint64_t &a, int, int = 0) { READDATA(s, a); } template inline void Unserialize(Stream &s, float &a, int, int = 0) { READDATA(s, a); } template inline void Unserialize(Stream &s, double &a, int, int = 0) { READDATA(s, a); } inline unsigned int GetSerializeSize(bool a, int, int = 0) { return sizeof(char); } template inline void Serialize(Stream &s, bool a, int, int = 0) { char f = a; WRITEDATA(s, f); } template inline void Unserialize(Stream &s, bool &a, int, int = 0) { char f; READDATA(s, f); a = f; } // // Compact size // size < 253 -- 1 byte // size <= USHRT_MAX -- 3 bytes (253 + 2 bytes) // size <= UINT_MAX -- 5 bytes (254 + 4 bytes) // size > UINT_MAX -- 9 bytes (255 + 8 bytes) // -inline unsigned int GetSizeOfCompactSize(uint64 nSize) { +inline unsigned int GetSizeOfCompactSize(uint64_t nSize) { if (nSize < 253) return sizeof(uint8_t); else if (nSize <= USHRT_MAX) - return sizeof(uint8_t) + sizeof(unsigned short); + return sizeof(uint8_t) + sizeof(uint16_t); else if (nSize <= UINT_MAX) - return sizeof(uint8_t) + sizeof(unsigned int); + return sizeof(uint8_t) + sizeof(uint32_t); else - return sizeof(uint8_t) + sizeof(uint64); + return sizeof(uint8_t) + sizeof(uint64_t); } -template void WriteCompactSize(Stream &os, uint64 nSize) { +template void WriteCompactSize(Stream &os, uint64_t nSize) { if (nSize < 253) { uint8_t chSize = nSize; WRITEDATA(os, chSize); } else if (nSize <= USHRT_MAX) { uint8_t chSize = 253; - unsigned short xSize = nSize; + uint16_t xSize = nSize; WRITEDATA(os, chSize); WRITEDATA(os, xSize); } else if (nSize <= UINT_MAX) { uint8_t chSize = 254; - unsigned int xSize = nSize; + uint32_t xSize = nSize; WRITEDATA(os, chSize); WRITEDATA(os, xSize); } else { uint8_t chSize = 255; - uint64 xSize = nSize; + uint64_t xSize = nSize; WRITEDATA(os, chSize); WRITEDATA(os, xSize); } return; } -template uint64 ReadCompactSize(Stream &is) { +template uint64_t ReadCompactSize(Stream &is) { uint8_t chSize; READDATA(is, chSize); - uint64 nSizeRet = 0; + uint64_t nSizeRet = 0; if (chSize < 253) { nSizeRet = chSize; } else if (chSize == 253) { - unsigned short xSize; + uint16_t xSize; READDATA(is, xSize); nSizeRet = xSize; } else if (chSize == 254) { - unsigned int xSize; + uint32_t xSize; READDATA(is, xSize); nSizeRet = xSize; } else { - uint64 xSize; + uint64_t xSize; READDATA(is, xSize); nSizeRet = xSize; } - if (nSizeRet > (uint64)MAX_SIZE) + if (nSizeRet > uint64_t(MAX_SIZE)) { throw std::ios_base::failure("ReadCompactSize() : size too large"); + } return nSizeRet; } // // Wrapper for serializing arrays and POD // There's a clever template way to make arrays serialize normally, but MSVC6 // doesn't support it // #define FLATDATA(obj) \ REF(CFlatData((char *)&(obj), (char *)&(obj) + sizeof(obj))) class CFlatData { protected: char *pbegin; char *pend; public: CFlatData(void *pbeginIn, void *pendIn) : pbegin((char *)pbeginIn), pend((char *)pendIn) {} char *begin() { return pbegin; } const char *begin() const { return pbegin; } char *end() { return pend; } const char *end() const { return pend; } unsigned int GetSerializeSize(int, int = 0) const { return pend - pbegin; } template void Serialize(Stream &s, int, int = 0) const { s.write(pbegin, pend - pbegin); } template void Unserialize(Stream &s, int, int = 0) { s.read(pbegin, pend - pbegin); } }; // // string stored as a fixed length field // template class CFixedFieldString { protected: const std::string *pcstr; std::string *pstr; public: explicit CFixedFieldString(const std::string &str) : pcstr(&str), pstr(nullptr) {} explicit CFixedFieldString(std::string &str) : pcstr(&str), pstr(&str) {} unsigned int GetSerializeSize(int, int = 0) const { return LEN; } template void Serialize(Stream &s, int, int = 0) const { char pszBuf[LEN]; strncpy(pszBuf, pcstr->c_str(), LEN); s.write(pszBuf, LEN); } template void Unserialize(Stream &s, int, int = 0) { if (pstr == nullptr) throw std::ios_base::failure("CFixedFieldString::Unserialize : " "trying to unserialize to const " "string"); char pszBuf[LEN + 1]; s.read(pszBuf, LEN); pszBuf[LEN] = '\0'; *pstr = pszBuf; } }; // // Forward declarations // // string template unsigned int GetSerializeSize(const std::basic_string &str, int, int = 0); template void Serialize(Stream &os, const std::basic_string &str, int, int = 0); template void Unserialize(Stream &is, std::basic_string &str, int, int = 0); // vector template unsigned int GetSerializeSize_impl(const std::vector &v, int nType, int nVersion, const boost::true_type &); template unsigned int GetSerializeSize_impl(const std::vector &v, int nType, int nVersion, const boost::false_type &); template inline unsigned int GetSerializeSize(const std::vector &v, int nType, int nVersion = PROTOCOL_VERSION); template void Serialize_impl(Stream &os, const std::vector &v, int nType, int nVersion, const boost::true_type &); template void Serialize_impl(Stream &os, const std::vector &v, int nType, int nVersion, const boost::false_type &); template inline void Serialize(Stream &os, const std::vector &v, int nType, int nVersion = PROTOCOL_VERSION); template void Unserialize_impl(Stream &is, std::vector &v, int nType, int nVersion, const boost::true_type &); template void Unserialize_impl(Stream &is, std::vector &v, int nType, int nVersion, const boost::false_type &); template inline void Unserialize(Stream &is, std::vector &v, int nType, int nVersion = PROTOCOL_VERSION); // others derived from vector extern inline unsigned int GetSerializeSize(const CScript &v, int nType, int nVersion = PROTOCOL_VERSION); template void Serialize(Stream &os, const CScript &v, int nType, int nVersion = PROTOCOL_VERSION); template void Unserialize(Stream &is, CScript &v, int nType, int nVersion = PROTOCOL_VERSION); // pair template unsigned int GetSerializeSize(const std::pair &item, int nType, int nVersion = PROTOCOL_VERSION); template void Serialize(Stream &os, const std::pair &item, int nType, int nVersion = PROTOCOL_VERSION); template void Unserialize(Stream &is, std::pair &item, int nType, int nVersion = PROTOCOL_VERSION); // 3 tuple template unsigned int GetSerializeSize(const boost::tuple &item, int nType, int nVersion = PROTOCOL_VERSION); template void Serialize(Stream &os, const boost::tuple &item, int nType, int nVersion = PROTOCOL_VERSION); template void Unserialize(Stream &is, boost::tuple &item, int nType, int nVersion = PROTOCOL_VERSION); // 4 tuple template unsigned int GetSerializeSize(const boost::tuple &item, int nType, int nVersion = PROTOCOL_VERSION); template void Serialize(Stream &os, const boost::tuple &item, int nType, int nVersion = PROTOCOL_VERSION); template void Unserialize(Stream &is, boost::tuple &item, int nType, int nVersion = PROTOCOL_VERSION); // map template unsigned int GetSerializeSize(const std::map &m, int nType, int nVersion = PROTOCOL_VERSION); template void Serialize(Stream &os, const std::map &m, int nType, int nVersion = PROTOCOL_VERSION); template void Unserialize(Stream &is, std::map &m, int nType, int nVersion = PROTOCOL_VERSION); // set template unsigned int GetSerializeSize(const std::set &m, int nType, int nVersion = PROTOCOL_VERSION); template void Serialize(Stream &os, const std::set &m, int nType, int nVersion = PROTOCOL_VERSION); template void Unserialize(Stream &is, std::set &m, int nType, int nVersion = PROTOCOL_VERSION); // // If none of the specialized versions above matched, default to calling member // function. // "int nType" is changed to "long nType" to keep from getting an ambiguous // overload error. // The compiler will only cast int to long if none of the other templates // matched. // Thanks to Boost serialization for this idea. // template inline unsigned int GetSerializeSize(const T &a, long nType, int nVersion = PROTOCOL_VERSION) { return a.GetSerializeSize((int)nType, nVersion); } template inline void Serialize(Stream &os, const T &a, long nType, int nVersion = PROTOCOL_VERSION) { a.Serialize(os, (int)nType, nVersion); } template inline void Unserialize(Stream &is, T &a, long nType, int nVersion = PROTOCOL_VERSION) { a.Unserialize(is, (int)nType, nVersion); } // // string // template unsigned int GetSerializeSize(const std::basic_string &str, int, int) { return GetSizeOfCompactSize(str.size()) + str.size() * sizeof(str[0]); } template void Serialize(Stream &os, const std::basic_string &str, int, int) { WriteCompactSize(os, str.size()); if (!str.empty()) os.write((char *)&str[0], str.size() * sizeof(str[0])); } template void Unserialize(Stream &is, std::basic_string &str, int, int) { unsigned int nSize = ReadCompactSize(is); str.resize(nSize); if (nSize != 0) is.read((char *)&str[0], nSize * sizeof(str[0])); } // // vector // template unsigned int GetSerializeSize_impl(const std::vector &v, int nType, int nVersion, const boost::true_type &) { return (GetSizeOfCompactSize(v.size()) + v.size() * sizeof(T)); } template unsigned int GetSerializeSize_impl(const std::vector &v, int nType, int nVersion, const boost::false_type &) { unsigned int nSize = GetSizeOfCompactSize(v.size()); for (typename std::vector::const_iterator vi = v.begin(); vi != v.end(); ++vi) nSize += GetSerializeSize((*vi), nType, nVersion); return nSize; } template inline unsigned int GetSerializeSize(const std::vector &v, int nType, int nVersion) { return GetSerializeSize_impl(v, nType, nVersion, boost::is_fundamental()); } template void Serialize_impl(Stream &os, const std::vector &v, int nType, int nVersion, const boost::true_type &) { WriteCompactSize(os, v.size()); if (!v.empty()) os.write((char *)&v[0], v.size() * sizeof(T)); } template void Serialize_impl(Stream &os, const std::vector &v, int nType, int nVersion, const boost::false_type &) { WriteCompactSize(os, v.size()); for (typename std::vector::const_iterator vi = v.begin(); vi != v.end(); ++vi) ::Serialize(os, (*vi), nType, nVersion); } template inline void Serialize(Stream &os, const std::vector &v, int nType, int nVersion) { Serialize_impl(os, v, nType, nVersion, boost::is_fundamental()); } template void Unserialize_impl(Stream &is, std::vector &v, int nType, int nVersion, const boost::true_type &) { // unsigned int nSize = ReadCompactSize(is); // v.resize(nSize); // is.read((char*)&v[0], nSize * sizeof(T)); // Limit size per read so bogus size value won't cause out of memory v.clear(); unsigned int nSize = ReadCompactSize(is); unsigned int i = 0; while (i < nSize) { unsigned int blk = std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(T))); v.resize(i + blk); is.read((char *)&v[i], blk * sizeof(T)); i += blk; } } template void Unserialize_impl(Stream &is, std::vector &v, int nType, int nVersion, const boost::false_type &) { // unsigned int nSize = ReadCompactSize(is); // v.resize(nSize); // for (std::vector::iterator vi = v.begin(); vi != v.end(); ++vi) // Unserialize(is, (*vi), nType, nVersion); v.clear(); unsigned int nSize = ReadCompactSize(is); unsigned int i = 0; unsigned int nMid = 0; while (nMid < nSize) { nMid += 5000000 / sizeof(T); if (nMid > nSize) nMid = nSize; v.resize(nMid); for (; i < nMid; i++) Unserialize(is, v[i], nType, nVersion); } } template inline void Unserialize(Stream &is, std::vector &v, int nType, int nVersion) { Unserialize_impl(is, v, nType, nVersion, boost::is_fundamental()); } // // others derived from vector // inline unsigned int GetSerializeSize(const CScript &v, int nType, int nVersion) { return GetSerializeSize((const std::vector &)v, nType, nVersion); } template void Serialize(Stream &os, const CScript &v, int nType, int nVersion) { Serialize(os, (const std::vector &)v, nType, nVersion); } template void Unserialize(Stream &is, CScript &v, int nType, int nVersion) { Unserialize(is, (std::vector &)v, nType, nVersion); } // // pair // template unsigned int GetSerializeSize(const std::pair &item, int nType, int nVersion) { return GetSerializeSize(item.first, nType, nVersion) + GetSerializeSize(item.second, nType, nVersion); } template void Serialize(Stream &os, const std::pair &item, int nType, int nVersion) { Serialize(os, item.first, nType, nVersion); Serialize(os, item.second, nType, nVersion); } template void Unserialize(Stream &is, std::pair &item, int nType, int nVersion) { Unserialize(is, item.first, nType, nVersion); Unserialize(is, item.second, nType, nVersion); } // // 3 tuple // template unsigned int GetSerializeSize(const boost::tuple &item, int nType, int nVersion) { unsigned int nSize = 0; nSize += GetSerializeSize(boost::get<0>(item), nType, nVersion); nSize += GetSerializeSize(boost::get<1>(item), nType, nVersion); nSize += GetSerializeSize(boost::get<2>(item), nType, nVersion); return nSize; } template void Serialize(Stream &os, const boost::tuple &item, int nType, int nVersion) { Serialize(os, boost::get<0>(item), nType, nVersion); Serialize(os, boost::get<1>(item), nType, nVersion); Serialize(os, boost::get<2>(item), nType, nVersion); } template void Unserialize(Stream &is, boost::tuple &item, int nType, int nVersion) { Unserialize(is, boost::get<0>(item), nType, nVersion); Unserialize(is, boost::get<1>(item), nType, nVersion); Unserialize(is, boost::get<2>(item), nType, nVersion); } // // 4 tuple // template unsigned int GetSerializeSize(const boost::tuple &item, int nType, int nVersion) { unsigned int nSize = 0; nSize += GetSerializeSize(boost::get<0>(item), nType, nVersion); nSize += GetSerializeSize(boost::get<1>(item), nType, nVersion); nSize += GetSerializeSize(boost::get<2>(item), nType, nVersion); nSize += GetSerializeSize(boost::get<3>(item), nType, nVersion); return nSize; } template void Serialize(Stream &os, const boost::tuple &item, int nType, int nVersion) { Serialize(os, boost::get<0>(item), nType, nVersion); Serialize(os, boost::get<1>(item), nType, nVersion); Serialize(os, boost::get<2>(item), nType, nVersion); Serialize(os, boost::get<3>(item), nType, nVersion); } template void Unserialize(Stream &is, boost::tuple &item, int nType, int nVersion) { Unserialize(is, boost::get<0>(item), nType, nVersion); Unserialize(is, boost::get<1>(item), nType, nVersion); Unserialize(is, boost::get<2>(item), nType, nVersion); Unserialize(is, boost::get<3>(item), nType, nVersion); } // // map // template unsigned int GetSerializeSize(const std::map &m, int nType, int nVersion) { unsigned int nSize = GetSizeOfCompactSize(m.size()); for (typename std::map::const_iterator mi = m.begin(); mi != m.end(); ++mi) nSize += GetSerializeSize((*mi), nType, nVersion); return nSize; } template void Serialize(Stream &os, const std::map &m, int nType, int nVersion) { WriteCompactSize(os, m.size()); for (typename std::map::const_iterator mi = m.begin(); mi != m.end(); ++mi) Serialize(os, (*mi), nType, nVersion); } template void Unserialize(Stream &is, std::map &m, int nType, int nVersion) { m.clear(); unsigned int nSize = ReadCompactSize(is); typename std::map::iterator mi = m.begin(); for (unsigned int i = 0; i < nSize; i++) { std::pair item; Unserialize(is, item, nType, nVersion); mi = m.insert(mi, item); } } // // set // template unsigned int GetSerializeSize(const std::set &m, int nType, int nVersion) { unsigned int nSize = GetSizeOfCompactSize(m.size()); for (typename std::set::const_iterator it = m.begin(); it != m.end(); ++it) nSize += GetSerializeSize((*it), nType, nVersion); return nSize; } template void Serialize(Stream &os, const std::set &m, int nType, int nVersion) { WriteCompactSize(os, m.size()); for (typename std::set::const_iterator it = m.begin(); it != m.end(); ++it) Serialize(os, (*it), nType, nVersion); } template void Unserialize(Stream &is, std::set &m, int nType, int nVersion) { m.clear(); unsigned int nSize = ReadCompactSize(is); typename std::set::iterator it = m.begin(); for (unsigned int i = 0; i < nSize; i++) { K key; Unserialize(is, key, nType, nVersion); it = m.insert(it, key); } } // // Support for IMPLEMENT_SERIALIZE and READWRITE macro // class CSerActionGetSerializeSize {}; class CSerActionSerialize {}; class CSerActionUnserialize {}; template inline unsigned int SerReadWrite(Stream &s, const T &obj, int nType, int nVersion, CSerActionGetSerializeSize ser_action) { return ::GetSerializeSize(obj, nType, nVersion); } template inline unsigned int SerReadWrite(Stream &s, const T &obj, int nType, int nVersion, CSerActionSerialize ser_action) { ::Serialize(s, obj, nType, nVersion); return 0; } template inline unsigned int SerReadWrite(Stream &s, T &obj, int nType, int nVersion, CSerActionUnserialize ser_action) { ::Unserialize(s, obj, nType, nVersion); return 0; } struct ser_streamplaceholder { int nType; int nVersion; }; // // Allocator that locks its contents from being paged // out of memory and clears its contents before deletion. // template struct secure_allocator : public std::allocator { // MSVC8 default copy constructor is broken typedef std::allocator base; typedef typename base::size_type size_type; typedef typename base::difference_type difference_type; typedef typename base::pointer pointer; typedef typename base::const_pointer const_pointer; typedef typename base::reference reference; typedef typename base::const_reference const_reference; typedef typename base::value_type value_type; secure_allocator() throw() {} secure_allocator(const secure_allocator &a) throw() : base(a) {} template secure_allocator(const secure_allocator &a) throw() : base(a) {} ~secure_allocator() throw() {} template struct rebind { typedef secure_allocator<_Other> other; }; T *allocate(std::size_t n, const void *hint = 0) { T *p; p = std::allocator::allocate(n, hint); if (p != nullptr) mlock(p, sizeof(T) * n); return p; } void deallocate(T *p, std::size_t n) { if (p != nullptr) { memset(p, 0, sizeof(T) * n); munlock(p, sizeof(T) * n); } std::allocator::deallocate(p, n); } }; // // Double ended buffer combining vector and stream-like interfaces. // >> and << read and write unformatted data using the above serialization // templates. // Fills with data in linear time; some stringstream implementations take N^2 // time. // class CDataStream { protected: typedef std::vector> vector_type; vector_type vch; unsigned int nReadPos; short state; short exceptmask; public: int nType; int nVersion; typedef vector_type::allocator_type allocator_type; typedef vector_type::size_type size_type; typedef vector_type::difference_type difference_type; typedef vector_type::reference reference; typedef vector_type::const_reference const_reference; typedef vector_type::value_type value_type; typedef vector_type::iterator iterator; typedef vector_type::const_iterator const_iterator; typedef vector_type::reverse_iterator reverse_iterator; explicit CDataStream(int nTypeIn = SER_NETWORK, int nVersionIn = PROTOCOL_VERSION) { Init(nTypeIn, nVersionIn); } CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn = SER_NETWORK, int nVersionIn = PROTOCOL_VERSION) : vch(pbegin, pend) { Init(nTypeIn, nVersionIn); } #if !defined(_MSC_VER) || _MSC_VER >= 1300 CDataStream(const char *pbegin, const char *pend, int nTypeIn = SER_NETWORK, int nVersionIn = PROTOCOL_VERSION) : vch(pbegin, pend) { Init(nTypeIn, nVersionIn); } #endif CDataStream(const vector_type &vchIn, int nTypeIn = SER_NETWORK, int nVersionIn = PROTOCOL_VERSION) : vch(vchIn.begin(), vchIn.end()) { Init(nTypeIn, nVersionIn); } CDataStream(const std::vector &vchIn, int nTypeIn = SER_NETWORK, int nVersionIn = PROTOCOL_VERSION) : vch(vchIn.begin(), vchIn.end()) { Init(nTypeIn, nVersionIn); } CDataStream(const std::vector &vchIn, int nTypeIn = SER_NETWORK, int nVersionIn = PROTOCOL_VERSION) : vch((char *)&vchIn.begin()[0], (char *)&vchIn.end()[0]) { Init(nTypeIn, nVersionIn); } void Init(int nTypeIn = SER_NETWORK, int nVersionIn = PROTOCOL_VERSION) { nReadPos = 0; nType = nTypeIn; nVersion = nVersionIn; state = 0; exceptmask = std::ios::badbit | std::ios::failbit; } CDataStream &operator+=(const CDataStream &b) { vch.insert(vch.end(), b.begin(), b.end()); return *this; } friend CDataStream operator+(const CDataStream &a, const CDataStream &b) { CDataStream ret = a; ret += b; return (ret); } std::string str() const { return (std::string(begin(), end())); } // // Vector subset // const_iterator begin() const { return vch.begin() + nReadPos; } iterator begin() { return vch.begin() + nReadPos; } const_iterator end() const { return vch.end(); } iterator end() { return vch.end(); } size_type size() const { return vch.size() - nReadPos; } bool empty() const { return vch.size() == nReadPos; } void resize(size_type n, value_type c = 0) { vch.resize(n + nReadPos, c); } void reserve(size_type n) { vch.reserve(n + nReadPos); } const_reference operator[](size_type pos) const { return vch[pos + nReadPos]; } reference operator[](size_type pos) { return vch[pos + nReadPos]; } void clear() { vch.clear(); nReadPos = 0; } iterator insert(iterator it, const char &x = char()) { return vch.insert(it, x); } void insert(iterator it, size_type n, const char &x) { vch.insert(it, n, x); } void insert(iterator it, std::vector::const_iterator first, std::vector::const_iterator last) { if (it == vch.begin() + nReadPos && last - first <= nReadPos) { // special case for inserting at the front when there's room nReadPos -= (last - first); memcpy(&vch[nReadPos], &first[0], last - first); } else vch.insert(it, first, last); } #if !defined(_MSC_VER) || _MSC_VER >= 1300 void insert(iterator it, const char *first, const char *last) { if (it == vch.begin() + nReadPos && last - first <= nReadPos) { // special case for inserting at the front when there's room nReadPos -= (last - first); memcpy(&vch[nReadPos], &first[0], last - first); } else vch.insert(it, first, last); } #endif iterator erase(iterator it) { if (it == vch.begin() + nReadPos) { // special case for erasing from the front if (++nReadPos >= vch.size()) { // whenever we reach the end, we take the opportunity to clear // the buffer nReadPos = 0; return vch.erase(vch.begin(), vch.end()); } return vch.begin() + nReadPos; } else return vch.erase(it); } iterator erase(iterator first, iterator last) { if (first == vch.begin() + nReadPos) { // special case for erasing from the front if (last == vch.end()) { nReadPos = 0; return vch.erase(vch.begin(), vch.end()); } else { nReadPos = (last - vch.begin()); return last; } } else return vch.erase(first, last); } inline void Compact() { vch.erase(vch.begin(), vch.begin() + nReadPos); nReadPos = 0; } bool Rewind(size_type n) { // Rewind by n characters if the buffer hasn't been compacted yet if (n > nReadPos) return false; nReadPos -= n; return true; } // // Stream subset // void setstate(short bits, const char *psz) { state |= bits; if (state & exceptmask) throw std::ios_base::failure(psz); } bool eof() const { return size() == 0; } bool fail() const { return state & (std::ios::badbit | std::ios::failbit); } bool good() const { return !eof() && (state == 0); } void clear(short n) { state = n; } // name conflict with vector clear() short exceptions() { return exceptmask; } short exceptions(short mask) { short prev = exceptmask; exceptmask = mask; setstate(0, "CDataStream"); return prev; } CDataStream *rdbuf() { return this; } int in_avail() { return size(); } void SetType(int n) { nType = n; } int GetType() { return nType; } void SetVersion(int n) { nVersion = n; } int GetVersion() { return nVersion; } void ReadVersion() { *this >> nVersion; } void WriteVersion() { *this << nVersion; } CDataStream &read(char *pch, int nSize) { // Read from the beginning of the buffer assert(nSize >= 0); unsigned int nReadPosNext = nReadPos + nSize; if (nReadPosNext >= vch.size()) { if (nReadPosNext > vch.size()) { setstate(std::ios::failbit, "CDataStream::read() : end of data"); memset(pch, 0, nSize); nSize = vch.size() - nReadPos; } memcpy(pch, &vch[nReadPos], nSize); nReadPos = 0; vch.clear(); return (*this); } memcpy(pch, &vch[nReadPos], nSize); nReadPos = nReadPosNext; return (*this); } CDataStream &ignore(int nSize) { // Ignore from the beginning of the buffer assert(nSize >= 0); unsigned int nReadPosNext = nReadPos + nSize; if (nReadPosNext >= vch.size()) { if (nReadPosNext > vch.size()) { setstate(std::ios::failbit, "CDataStream::ignore() : end of data"); nSize = vch.size() - nReadPos; } nReadPos = 0; vch.clear(); return (*this); } nReadPos = nReadPosNext; return (*this); } CDataStream &write(const char *pch, int nSize) { // Write to the end of the buffer assert(nSize >= 0); vch.insert(vch.end(), pch, pch + nSize); return (*this); } template void Serialize(Stream &s, int nType = 0, int nVersion = PROTOCOL_VERSION) const { // Special case: stream << stream concatenates like stream += stream if (!vch.empty()) s.write((char *)&vch[0], vch.size() * sizeof(vch[0])); } template unsigned int GetSerializeSize(const T &obj) { // Tells the size of the object if serialized to this stream return ::GetSerializeSize(obj, nType, nVersion); } template CDataStream &operator<<(const T &obj) { // Serialize to this stream ::Serialize(*this, obj, nType, nVersion); return (*this); } template CDataStream &operator>>(T &obj) { // Unserialize from this stream ::Unserialize(*this, obj, nType, nVersion); return (*this); } }; #ifdef TESTCDATASTREAM // VC6sp6 // CDataStream: // n=1000 0 seconds // n=2000 0 seconds // n=4000 0 seconds // n=8000 0 seconds // n=16000 0 seconds // n=32000 0 seconds // n=64000 1 seconds // n=128000 1 seconds // n=256000 2 seconds // n=512000 4 seconds // n=1024000 8 seconds // n=2048000 16 seconds // n=4096000 32 seconds // stringstream: // n=1000 1 seconds // n=2000 1 seconds // n=4000 13 seconds // n=8000 87 seconds // n=16000 400 seconds // n=32000 1660 seconds // n=64000 6749 seconds // n=128000 27241 seconds // n=256000 109804 seconds #include int main(int argc, char *argv[]) { vector vch(0xcc, 250); printf("CDataStream:\n"); for (int n = 1000; n <= 4500000; n *= 2) { CDataStream ss; time_t nStart = time(nullptr); for (int i = 0; i < n; i++) ss.write((char *)&vch[0], vch.size()); printf("n=%-10d %d seconds\n", n, time(nullptr) - nStart); } printf("stringstream:\n"); for (int n = 1000; n <= 4500000; n *= 2) { stringstream ss; time_t nStart = time(nullptr); for (int i = 0; i < n; i++) ss.write((char *)&vch[0], vch.size()); printf("n=%-10d %d seconds\n", n, time(nullptr) - nStart); } } #endif // // Automatic closing wrapper for FILE* // - Will automatically close the file when it goes out of scope if not null. // - If you're returning the file pointer, return file.release(). // - If you need to close the file early, use file.fclose() instead of // fclose(file). // class CAutoFile { protected: FILE *file; short state; short exceptmask; public: int nType; int nVersion; typedef FILE element_type; CAutoFile(FILE *filenew = nullptr, int nTypeIn = SER_DISK, int nVersionIn = PROTOCOL_VERSION) { file = filenew; nType = nTypeIn; nVersion = nVersionIn; state = 0; exceptmask = std::ios::badbit | std::ios::failbit; } ~CAutoFile() { fclose(); } void fclose() { if (file != nullptr && file != stdin && file != stdout && file != stderr) ::fclose(file); file = nullptr; } FILE *release() { FILE *ret = file; file = nullptr; return ret; } operator FILE *() { return file; } FILE *operator->() { return file; } FILE &operator*() { return *file; } FILE **operator&() { return &file; } FILE *operator=(FILE *pnew) { return file = pnew; } bool operator!() { return (file == nullptr); } // // Stream subset // void setstate(short bits, const char *psz) { state |= bits; if (state & exceptmask) throw std::ios_base::failure(psz); } bool fail() const { return state & (std::ios::badbit | std::ios::failbit); } bool good() const { return state == 0; } void clear(short n = 0) { state = n; } short exceptions() { return exceptmask; } short exceptions(short mask) { short prev = exceptmask; exceptmask = mask; setstate(0, "CAutoFile"); return prev; } void SetType(int n) { nType = n; } int GetType() { return nType; } void SetVersion(int n) { nVersion = n; } int GetVersion() { return nVersion; } void ReadVersion() { *this >> nVersion; } void WriteVersion() { *this << nVersion; } CAutoFile &read(char *pch, int nSize) { if (!file) throw std::ios_base::failure( "CAutoFile::read : file handle is nullptr"); if (fread(pch, 1, nSize, file) != nSize) setstate(std::ios::failbit, feof(file) ? "CAutoFile::read : end of file" : "CAutoFile::read : fread failed"); return (*this); } CAutoFile &write(const char *pch, int nSize) { if (!file) throw std::ios_base::failure( "CAutoFile::write : file handle is nullptr"); if (fwrite(pch, 1, nSize, file) != nSize) setstate(std::ios::failbit, "CAutoFile::write : write failed"); return (*this); } template unsigned int GetSerializeSize(const T &obj) { // Tells the size of the object if serialized to this stream return ::GetSerializeSize(obj, nType, nVersion); } template CAutoFile &operator<<(const T &obj) { // Serialize to this stream if (!file) throw std::ios_base::failure( "CAutoFile::operator<< : file handle is nullptr"); ::Serialize(*this, obj, nType, nVersion); return (*this); } template CAutoFile &operator>>(T &obj) { // Unserialize from this stream if (!file) throw std::ios_base::failure( "CAutoFile::operator>> : file handle is nullptr"); ::Unserialize(*this, obj, nType, nVersion); return (*this); } }; #endif diff --git a/src/seeder/uint256.h b/src/seeder/uint256.h index 0e7a002c0e..6b5c61e6f5 100644 --- a/src/seeder/uint256.h +++ b/src/seeder/uint256.h @@ -1,831 +1,825 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2011 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_SEEDER_UINT256_H #define BITCOIN_SEEDER_UINT256_H #include "serialize.h" #include +#include #include #include -#if defined(_MSC_VER) || defined(__BORLANDC__) -typedef __int64 int64; -typedef unsigned __int64 uint64; -#else -typedef long long int64; -typedef unsigned long long uint64; -#endif #if defined(_MSC_VER) && _MSC_VER < 1300 #define for if (false); else for #endif inline int Testuint256AdHoc(std::vector vArg); // We have to keep a separate base class without constructors // so the compiler will let us use it in a union template class base_uint { protected: enum { WIDTH = BITS / 32 }; unsigned int pn[WIDTH]; public: bool operator!() const { for (int i = 0; i < WIDTH; i++) if (pn[i] != 0) return false; return true; } const base_uint operator~() const { base_uint ret; for (int i = 0; i < WIDTH; i++) ret.pn[i] = ~pn[i]; return ret; } const base_uint operator-() const { base_uint ret; for (int i = 0; i < WIDTH; i++) ret.pn[i] = ~pn[i]; ret++; return ret; } - base_uint &operator=(uint64 b) { + base_uint &operator=(uint64_t b) { pn[0] = (unsigned int)b; pn[1] = (unsigned int)(b >> 32); for (int i = 2; i < WIDTH; i++) pn[i] = 0; return *this; } base_uint &operator^=(const base_uint &b) { for (int i = 0; i < WIDTH; i++) pn[i] ^= b.pn[i]; return *this; } base_uint &operator&=(const base_uint &b) { for (int i = 0; i < WIDTH; i++) pn[i] &= b.pn[i]; return *this; } base_uint &operator|=(const base_uint &b) { for (int i = 0; i < WIDTH; i++) pn[i] |= b.pn[i]; return *this; } - base_uint &operator^=(uint64 b) { + base_uint &operator^=(uint64_t b) { pn[0] ^= (unsigned int)b; pn[1] ^= (unsigned int)(b >> 32); return *this; } - base_uint &operator&=(uint64 b) { + base_uint &operator&=(uint64_t b) { pn[0] &= (unsigned int)b; pn[1] &= (unsigned int)(b >> 32); return *this; } - base_uint &operator|=(uint64 b) { + base_uint &operator|=(uint64_t b) { pn[0] |= (unsigned int)b; pn[1] |= (unsigned int)(b >> 32); return *this; } base_uint &operator<<=(unsigned int shift) { base_uint a(*this); for (int i = 0; i < WIDTH; i++) pn[i] = 0; int k = shift / 32; shift = shift % 32; for (int i = 0; i < WIDTH; i++) { if (i + k + 1 < WIDTH && shift != 0) pn[i + k + 1] |= (a.pn[i] >> (32 - shift)); if (i + k < WIDTH) pn[i + k] |= (a.pn[i] << shift); } return *this; } base_uint &operator>>=(unsigned int shift) { base_uint a(*this); for (int i = 0; i < WIDTH; i++) pn[i] = 0; int k = shift / 32; shift = shift % 32; for (int i = 0; i < WIDTH; i++) { if (i - k - 1 >= 0 && shift != 0) pn[i - k - 1] |= (a.pn[i] << (32 - shift)); if (i - k >= 0) pn[i - k] |= (a.pn[i] >> shift); } return *this; } base_uint &operator+=(const base_uint &b) { - uint64 carry = 0; + uint64_t carry = 0; for (int i = 0; i < WIDTH; i++) { - uint64 n = carry + pn[i] + b.pn[i]; + uint64_t n = carry + pn[i] + b.pn[i]; pn[i] = n & 0xffffffff; carry = n >> 32; } return *this; } base_uint &operator-=(const base_uint &b) { *this += -b; return *this; } - base_uint &operator+=(uint64 b64) { + base_uint &operator+=(uint64_t b64) { base_uint b; b = b64; *this += b; return *this; } - base_uint &operator-=(uint64 b64) { + base_uint &operator-=(uint64_t b64) { base_uint b; b = b64; *this += -b; return *this; } base_uint &operator++() { // prefix operator int i = 0; while (++pn[i] == 0 && i < WIDTH - 1) i++; return *this; } const base_uint operator++(int) { // postfix operator const base_uint ret = *this; ++(*this); return ret; } base_uint &operator--() { // prefix operator int i = 0; while (--pn[i] == -1 && i < WIDTH - 1) i++; return *this; } const base_uint operator--(int) { // postfix operator const base_uint ret = *this; --(*this); return ret; } friend inline bool operator<(const base_uint &a, const base_uint &b) { for (int i = base_uint::WIDTH - 1; i >= 0; i--) { if (a.pn[i] < b.pn[i]) return true; else if (a.pn[i] > b.pn[i]) return false; } return false; } friend inline bool operator<=(const base_uint &a, const base_uint &b) { for (int i = base_uint::WIDTH - 1; i >= 0; i--) { if (a.pn[i] < b.pn[i]) return true; else if (a.pn[i] > b.pn[i]) return false; } return true; } friend inline bool operator>(const base_uint &a, const base_uint &b) { for (int i = base_uint::WIDTH - 1; i >= 0; i--) { if (a.pn[i] > b.pn[i]) return true; else if (a.pn[i] < b.pn[i]) return false; } return false; } friend inline bool operator>=(const base_uint &a, const base_uint &b) { for (int i = base_uint::WIDTH - 1; i >= 0; i--) { if (a.pn[i] > b.pn[i]) return true; else if (a.pn[i] < b.pn[i]) return false; } return true; } friend inline bool operator==(const base_uint &a, const base_uint &b) { for (int i = 0; i < base_uint::WIDTH; i++) if (a.pn[i] != b.pn[i]) return false; return true; } - friend inline bool operator==(const base_uint &a, uint64 b) { + friend inline bool operator==(const base_uint &a, uint64_t b) { if (a.pn[0] != (unsigned int)b) return false; if (a.pn[1] != (unsigned int)(b >> 32)) return false; for (int i = 2; i < base_uint::WIDTH; i++) if (a.pn[i] != 0) return false; return true; } friend inline bool operator!=(const base_uint &a, const base_uint &b) { return (!(a == b)); } - friend inline bool operator!=(const base_uint &a, uint64 b) { + friend inline bool operator!=(const base_uint &a, uint64_t b) { return (!(a == b)); } std::string GetHex() const { char psz[sizeof(pn) * 2 + 1]; for (int i = 0; i < sizeof(pn); i++) sprintf(psz + i * 2, "%02x", ((uint8_t *)pn)[sizeof(pn) - i - 1]); return std::string(psz, psz + sizeof(pn) * 2); } void SetHex(const char *psz) { for (int i = 0; i < WIDTH; i++) pn[i] = 0; // skip leading spaces while (isspace(*psz)) psz++; // skip 0x if (psz[0] == '0' && tolower(psz[1]) == 'x') psz += 2; // hex string to uint static char phexdigit[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 0, 0, 0, 0, 0, 0, 0, 0}; const char *pbegin = psz; while (phexdigit[(uint8_t)*psz] || *psz == '0') psz++; psz--; uint8_t *p1 = (uint8_t *)pn; uint8_t *pend = p1 + WIDTH * 4; while (psz >= pbegin && p1 < pend) { *p1 = phexdigit[(uint8_t)*psz--]; if (psz >= pbegin) { *p1 |= (phexdigit[(uint8_t)*psz--] << 4); p1++; } } } void SetHex(const std::string &str) { SetHex(str.c_str()); } std::string ToString() const { return (GetHex()); } uint8_t *begin() { return (uint8_t *)&pn[0]; } uint8_t *end() { return (uint8_t *)&pn[WIDTH]; } unsigned int size() { return sizeof(pn); } unsigned int GetSerializeSize(int nType = 0, int nVersion = PROTOCOL_VERSION) const { return sizeof(pn); } template void Serialize(Stream &s, int nType = 0, int nVersion = PROTOCOL_VERSION) const { s.write((char *)pn, sizeof(pn)); } template void Unserialize(Stream &s, int nType = 0, int nVersion = PROTOCOL_VERSION) { s.read((char *)pn, sizeof(pn)); } friend class uint160; friend class uint256; friend inline int Testuint256AdHoc(std::vector vArg); }; typedef base_uint<160> base_uint160; typedef base_uint<256> base_uint256; // // uint160 and uint256 could be implemented as templates, but to keep // compile errors and debugging cleaner, they're copy and pasted. // ////////////////////////////////////////////////////////////////////////////// // // uint160 // class uint160 : public base_uint160 { public: typedef base_uint160 basetype; uint160() { for (int i = 0; i < WIDTH; i++) pn[i] = 0; } uint160(const basetype &b) { for (int i = 0; i < WIDTH; i++) pn[i] = b.pn[i]; } uint160 &operator=(const basetype &b) { for (int i = 0; i < WIDTH; i++) pn[i] = b.pn[i]; return *this; } - uint160(uint64 b) { + uint160(uint64_t b) { pn[0] = (unsigned int)b; pn[1] = (unsigned int)(b >> 32); for (int i = 2; i < WIDTH; i++) pn[i] = 0; } - uint160 &operator=(uint64 b) { + uint160 &operator=(uint64_t b) { pn[0] = (unsigned int)b; pn[1] = (unsigned int)(b >> 32); for (int i = 2; i < WIDTH; i++) pn[i] = 0; return *this; } explicit uint160(const std::string &str) { SetHex(str); } explicit uint160(const std::vector &vch) { if (vch.size() == sizeof(pn)) memcpy(pn, &vch[0], sizeof(pn)); else *this = 0; } }; -inline bool operator==(const uint160 &a, uint64 b) { +inline bool operator==(const uint160 &a, uint64_t b) { return (base_uint160)a == b; } -inline bool operator!=(const uint160 &a, uint64 b) { +inline bool operator!=(const uint160 &a, uint64_t b) { return (base_uint160)a != b; } inline const uint160 operator<<(const base_uint160 &a, unsigned int shift) { return uint160(a) <<= shift; } inline const uint160 operator>>(const base_uint160 &a, unsigned int shift) { return uint160(a) >>= shift; } inline const uint160 operator<<(const uint160 &a, unsigned int shift) { return uint160(a) <<= shift; } inline const uint160 operator>>(const uint160 &a, unsigned int shift) { return uint160(a) >>= shift; } inline const uint160 operator^(const base_uint160 &a, const base_uint160 &b) { return uint160(a) ^= b; } inline const uint160 operator&(const base_uint160 &a, const base_uint160 &b) { return uint160(a) &= b; } inline const uint160 operator|(const base_uint160 &a, const base_uint160 &b) { return uint160(a) |= b; } inline const uint160 operator+(const base_uint160 &a, const base_uint160 &b) { return uint160(a) += b; } inline const uint160 operator-(const base_uint160 &a, const base_uint160 &b) { return uint160(a) -= b; } inline bool operator<(const base_uint160 &a, const uint160 &b) { return (base_uint160)a < (base_uint160)b; } inline bool operator<=(const base_uint160 &a, const uint160 &b) { return (base_uint160)a <= (base_uint160)b; } inline bool operator>(const base_uint160 &a, const uint160 &b) { return (base_uint160)a > (base_uint160)b; } inline bool operator>=(const base_uint160 &a, const uint160 &b) { return (base_uint160)a >= (base_uint160)b; } inline bool operator==(const base_uint160 &a, const uint160 &b) { return (base_uint160)a == (base_uint160)b; } inline bool operator!=(const base_uint160 &a, const uint160 &b) { return (base_uint160)a != (base_uint160)b; } inline const uint160 operator^(const base_uint160 &a, const uint160 &b) { return (base_uint160)a ^ (base_uint160)b; } inline const uint160 operator&(const base_uint160 &a, const uint160 &b) { return (base_uint160)a & (base_uint160)b; } inline const uint160 operator|(const base_uint160 &a, const uint160 &b) { return (base_uint160)a | (base_uint160)b; } inline const uint160 operator+(const base_uint160 &a, const uint160 &b) { return (base_uint160)a + (base_uint160)b; } inline const uint160 operator-(const base_uint160 &a, const uint160 &b) { return (base_uint160)a - (base_uint160)b; } inline bool operator<(const uint160 &a, const base_uint160 &b) { return (base_uint160)a < (base_uint160)b; } inline bool operator<=(const uint160 &a, const base_uint160 &b) { return (base_uint160)a <= (base_uint160)b; } inline bool operator>(const uint160 &a, const base_uint160 &b) { return (base_uint160)a > (base_uint160)b; } inline bool operator>=(const uint160 &a, const base_uint160 &b) { return (base_uint160)a >= (base_uint160)b; } inline bool operator==(const uint160 &a, const base_uint160 &b) { return (base_uint160)a == (base_uint160)b; } inline bool operator!=(const uint160 &a, const base_uint160 &b) { return (base_uint160)a != (base_uint160)b; } inline const uint160 operator^(const uint160 &a, const base_uint160 &b) { return (base_uint160)a ^ (base_uint160)b; } inline const uint160 operator&(const uint160 &a, const base_uint160 &b) { return (base_uint160)a & (base_uint160)b; } inline const uint160 operator|(const uint160 &a, const base_uint160 &b) { return (base_uint160)a | (base_uint160)b; } inline const uint160 operator+(const uint160 &a, const base_uint160 &b) { return (base_uint160)a + (base_uint160)b; } inline const uint160 operator-(const uint160 &a, const base_uint160 &b) { return (base_uint160)a - (base_uint160)b; } inline bool operator<(const uint160 &a, const uint160 &b) { return (base_uint160)a < (base_uint160)b; } inline bool operator<=(const uint160 &a, const uint160 &b) { return (base_uint160)a <= (base_uint160)b; } inline bool operator>(const uint160 &a, const uint160 &b) { return (base_uint160)a > (base_uint160)b; } inline bool operator>=(const uint160 &a, const uint160 &b) { return (base_uint160)a >= (base_uint160)b; } inline bool operator==(const uint160 &a, const uint160 &b) { return (base_uint160)a == (base_uint160)b; } inline bool operator!=(const uint160 &a, const uint160 &b) { return (base_uint160)a != (base_uint160)b; } inline const uint160 operator^(const uint160 &a, const uint160 &b) { return (base_uint160)a ^ (base_uint160)b; } inline const uint160 operator&(const uint160 &a, const uint160 &b) { return (base_uint160)a & (base_uint160)b; } inline const uint160 operator|(const uint160 &a, const uint160 &b) { return (base_uint160)a | (base_uint160)b; } inline const uint160 operator+(const uint160 &a, const uint160 &b) { return (base_uint160)a + (base_uint160)b; } inline const uint160 operator-(const uint160 &a, const uint160 &b) { return (base_uint160)a - (base_uint160)b; } ////////////////////////////////////////////////////////////////////////////// // // uint256 // class uint256 : public base_uint256 { public: typedef base_uint256 basetype; uint256() { for (int i = 0; i < WIDTH; i++) pn[i] = 0; } uint256(const basetype &b) { for (int i = 0; i < WIDTH; i++) pn[i] = b.pn[i]; } uint256 &operator=(const basetype &b) { for (int i = 0; i < WIDTH; i++) pn[i] = b.pn[i]; return *this; } - uint256(uint64 b) { + uint256(uint64_t b) { pn[0] = (unsigned int)b; pn[1] = (unsigned int)(b >> 32); for (int i = 2; i < WIDTH; i++) pn[i] = 0; } - uint256 &operator=(uint64 b) { + uint256 &operator=(uint64_t b) { pn[0] = (unsigned int)b; pn[1] = (unsigned int)(b >> 32); for (int i = 2; i < WIDTH; i++) pn[i] = 0; return *this; } explicit uint256(const std::string &str) { SetHex(str); } explicit uint256(const std::vector &vch) { if (vch.size() == sizeof(pn)) memcpy(pn, &vch[0], sizeof(pn)); else *this = 0; } }; -inline bool operator==(const uint256 &a, uint64 b) { +inline bool operator==(const uint256 &a, uint64_t b) { return (base_uint256)a == b; } -inline bool operator!=(const uint256 &a, uint64 b) { +inline bool operator!=(const uint256 &a, uint64_t b) { return (base_uint256)a != b; } inline const uint256 operator<<(const base_uint256 &a, unsigned int shift) { return uint256(a) <<= shift; } inline const uint256 operator>>(const base_uint256 &a, unsigned int shift) { return uint256(a) >>= shift; } inline const uint256 operator<<(const uint256 &a, unsigned int shift) { return uint256(a) <<= shift; } inline const uint256 operator>>(const uint256 &a, unsigned int shift) { return uint256(a) >>= shift; } inline const uint256 operator^(const base_uint256 &a, const base_uint256 &b) { return uint256(a) ^= b; } inline const uint256 operator&(const base_uint256 &a, const base_uint256 &b) { return uint256(a) &= b; } inline const uint256 operator|(const base_uint256 &a, const base_uint256 &b) { return uint256(a) |= b; } inline const uint256 operator+(const base_uint256 &a, const base_uint256 &b) { return uint256(a) += b; } inline const uint256 operator-(const base_uint256 &a, const base_uint256 &b) { return uint256(a) -= b; } inline bool operator<(const base_uint256 &a, const uint256 &b) { return (base_uint256)a < (base_uint256)b; } inline bool operator<=(const base_uint256 &a, const uint256 &b) { return (base_uint256)a <= (base_uint256)b; } inline bool operator>(const base_uint256 &a, const uint256 &b) { return (base_uint256)a > (base_uint256)b; } inline bool operator>=(const base_uint256 &a, const uint256 &b) { return (base_uint256)a >= (base_uint256)b; } inline bool operator==(const base_uint256 &a, const uint256 &b) { return (base_uint256)a == (base_uint256)b; } inline bool operator!=(const base_uint256 &a, const uint256 &b) { return (base_uint256)a != (base_uint256)b; } inline const uint256 operator^(const base_uint256 &a, const uint256 &b) { return (base_uint256)a ^ (base_uint256)b; } inline const uint256 operator&(const base_uint256 &a, const uint256 &b) { return (base_uint256)a & (base_uint256)b; } inline const uint256 operator|(const base_uint256 &a, const uint256 &b) { return (base_uint256)a | (base_uint256)b; } inline const uint256 operator+(const base_uint256 &a, const uint256 &b) { return (base_uint256)a + (base_uint256)b; } inline const uint256 operator-(const base_uint256 &a, const uint256 &b) { return (base_uint256)a - (base_uint256)b; } inline bool operator<(const uint256 &a, const base_uint256 &b) { return (base_uint256)a < (base_uint256)b; } inline bool operator<=(const uint256 &a, const base_uint256 &b) { return (base_uint256)a <= (base_uint256)b; } inline bool operator>(const uint256 &a, const base_uint256 &b) { return (base_uint256)a > (base_uint256)b; } inline bool operator>=(const uint256 &a, const base_uint256 &b) { return (base_uint256)a >= (base_uint256)b; } inline bool operator==(const uint256 &a, const base_uint256 &b) { return (base_uint256)a == (base_uint256)b; } inline bool operator!=(const uint256 &a, const base_uint256 &b) { return (base_uint256)a != (base_uint256)b; } inline const uint256 operator^(const uint256 &a, const base_uint256 &b) { return (base_uint256)a ^ (base_uint256)b; } inline const uint256 operator&(const uint256 &a, const base_uint256 &b) { return (base_uint256)a & (base_uint256)b; } inline const uint256 operator|(const uint256 &a, const base_uint256 &b) { return (base_uint256)a | (base_uint256)b; } inline const uint256 operator+(const uint256 &a, const base_uint256 &b) { return (base_uint256)a + (base_uint256)b; } inline const uint256 operator-(const uint256 &a, const base_uint256 &b) { return (base_uint256)a - (base_uint256)b; } inline bool operator<(const uint256 &a, const uint256 &b) { return (base_uint256)a < (base_uint256)b; } inline bool operator<=(const uint256 &a, const uint256 &b) { return (base_uint256)a <= (base_uint256)b; } inline bool operator>(const uint256 &a, const uint256 &b) { return (base_uint256)a > (base_uint256)b; } inline bool operator>=(const uint256 &a, const uint256 &b) { return (base_uint256)a >= (base_uint256)b; } inline bool operator==(const uint256 &a, const uint256 &b) { return (base_uint256)a == (base_uint256)b; } inline bool operator!=(const uint256 &a, const uint256 &b) { return (base_uint256)a != (base_uint256)b; } inline const uint256 operator^(const uint256 &a, const uint256 &b) { return (base_uint256)a ^ (base_uint256)b; } inline const uint256 operator&(const uint256 &a, const uint256 &b) { return (base_uint256)a & (base_uint256)b; } inline const uint256 operator|(const uint256 &a, const uint256 &b) { return (base_uint256)a | (base_uint256)b; } inline const uint256 operator+(const uint256 &a, const uint256 &b) { return (base_uint256)a + (base_uint256)b; } inline const uint256 operator-(const uint256 &a, const uint256 &b) { return (base_uint256)a - (base_uint256)b; } inline int Testuint256AdHoc(std::vector vArg) { uint256 g(0); printf("%s\n", g.ToString().c_str()); g--; printf("g--\n"); printf("%s\n", g.ToString().c_str()); g--; printf("g--\n"); printf("%s\n", g.ToString().c_str()); g++; printf("g++\n"); printf("%s\n", g.ToString().c_str()); g++; printf("g++\n"); printf("%s\n", g.ToString().c_str()); g++; printf("g++\n"); printf("%s\n", g.ToString().c_str()); g++; printf("g++\n"); printf("%s\n", g.ToString().c_str()); uint256 a(7); printf("a=7\n"); printf("%s\n", a.ToString().c_str()); uint256 b; printf("b undefined\n"); printf("%s\n", b.ToString().c_str()); int c = 3; a = c; a.pn[3] = 15; printf("%s\n", a.ToString().c_str()); uint256 k(c); a = 5; a.pn[3] = 15; printf("%s\n", a.ToString().c_str()); b = 1; b <<= 52; a |= b; a ^= 0x500; printf("a %s\n", a.ToString().c_str()); a = a | b | (uint256)0x1000; printf("a %s\n", a.ToString().c_str()); printf("b %s\n", b.ToString().c_str()); a = 0xfffffffe; a.pn[4] = 9; printf("%s\n", a.ToString().c_str()); a++; printf("%s\n", a.ToString().c_str()); a++; printf("%s\n", a.ToString().c_str()); a++; printf("%s\n", a.ToString().c_str()); a++; printf("%s\n", a.ToString().c_str()); a--; printf("%s\n", a.ToString().c_str()); a--; printf("%s\n", a.ToString().c_str()); a--; printf("%s\n", a.ToString().c_str()); uint256 d = a--; printf("%s\n", d.ToString().c_str()); printf("%s\n", a.ToString().c_str()); a--; printf("%s\n", a.ToString().c_str()); a--; printf("%s\n", a.ToString().c_str()); d = a; printf("%s\n", d.ToString().c_str()); for (int i = uint256::WIDTH - 1; i >= 0; i--) printf("%08x", d.pn[i]); printf("\n"); uint256 neg = d; neg = ~neg; printf("%s\n", neg.ToString().c_str()); uint256 e = uint256("0xABCDEF123abcdef12345678909832180000011111111"); printf("\n"); printf("%s\n", e.ToString().c_str()); printf("\n"); uint256 x1 = uint256("0xABCDEF123abcdef12345678909832180000011111111"); uint256 x2; printf("%s\n", x1.ToString().c_str()); for (int i = 0; i < 270; i += 4) { x2 = x1 << i; printf("%s\n", x2.ToString().c_str()); } printf("\n"); printf("%s\n", x1.ToString().c_str()); for (int i = 0; i < 270; i += 4) { x2 = x1; x2 >>= i; printf("%s\n", x2.ToString().c_str()); } for (int i = 0; i < 100; i++) { uint256 k = (~uint256(0) >> i); printf("%s\n", k.ToString().c_str()); } for (int i = 0; i < 100; i++) { uint256 k = (~uint256(0) << i); printf("%s\n", k.ToString().c_str()); } return (0); } #endif