From c31b24f745a84669f2af729052da7fd7ed2da868 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 25 May 2016 15:38:32 +0200 Subject: [PATCH] Use 64-bit SipHash of netgroups in eviction --- src/net.cpp | 39 ++++++++++++++++++++++++++------------- src/net.h | 22 +++------------------- 2 files changed, 29 insertions(+), 32 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index eb62ee8a0..0bc501601 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -839,7 +839,7 @@ struct NodeEvictionCandidate int64_t nTimeConnected; int64_t nMinPingUsecTime; CAddress addr; - std::vector vchKeyedNetGroup; + uint64_t nKeyedNetGroup; }; static bool ReverseCompareNodeMinPingTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b) @@ -853,7 +853,7 @@ static bool ReverseCompareNodeTimeConnected(const NodeEvictionCandidate &a, cons } static bool CompareNetGroupKeyed(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b) { - return a.vchKeyedNetGroup < b.vchKeyedNetGroup; + return a.nKeyedNetGroup < b.nKeyedNetGroup; }; /** Try to find a connection to evict when the node is full. @@ -876,7 +876,7 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { continue; if (node->fDisconnect) continue; - NodeEvictionCandidate candidate = {node->id, node->nTimeConnected, node->nMinPingUsecTime, node->addr, node->vchKeyedNetGroup}; + NodeEvictionCandidate candidate = {node->id, node->nTimeConnected, node->nMinPingUsecTime, node->addr, node->nKeyedNetGroup}; vEvictionCandidates.push_back(candidate); } } @@ -908,24 +908,24 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { // Identify the network group with the most connections and youngest member. // (vEvictionCandidates is already sorted by reverse connect time) - std::vector naMostConnections; + uint64_t naMostConnections; unsigned int nMostConnections = 0; int64_t nMostConnectionsTime = 0; - std::map, std::vector > mapAddrCounts; + std::map > mapAddrCounts; BOOST_FOREACH(const NodeEvictionCandidate &node, vEvictionCandidates) { - mapAddrCounts[node.addr.GetGroup()].push_back(node); - int64_t grouptime = mapAddrCounts[node.addr.GetGroup()][0].nTimeConnected; - size_t groupsize = mapAddrCounts[node.addr.GetGroup()].size(); + mapAddrCounts[node.nKeyedNetGroup].push_back(node); + int64_t grouptime = mapAddrCounts[node.nKeyedNetGroup][0].nTimeConnected; + size_t groupsize = mapAddrCounts[node.nKeyedNetGroup].size(); if (groupsize > nMostConnections || (groupsize == nMostConnections && grouptime > nMostConnectionsTime)) { nMostConnections = groupsize; nMostConnectionsTime = grouptime; - naMostConnections = node.addr.GetGroup(); + naMostConnections = node.nKeyedNetGroup; } } // Reduce to the network group with the most connections - vEvictionCandidates = mapAddrCounts[naMostConnections]; + vEvictionCandidates = std::move(mapAddrCounts[naMostConnections]); // Do not disconnect peers if there is only one unprotected connection from their network group. // This step excessively favors netgroup diversity, and should be removed once more protective criteria are established. @@ -2318,6 +2318,8 @@ unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", DEFAULT_MAX CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), + addr(addrIn), + nKeyedNetGroup(CalculateKeyedNetGroup(addrIn)), addrKnown(5000, 0.001), filterInventoryKnown(50000, 0.000001) { @@ -2330,7 +2332,6 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa nRecvBytes = 0; nTimeConnected = GetTime(); nTimeOffset = 0; - addr = addrIn; addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn; nVersion = 0; strSubVer = ""; @@ -2365,8 +2366,6 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa lastSentFeeFilter = 0; nextSendTimeFeeFilter = 0; - CalculateKeyedNetGroup(); - BOOST_FOREACH(const std::string &msg, getAllNetMessageTypes()) mapRecvBytesPerMsgCmd[msg] = 0; mapRecvBytesPerMsgCmd[NET_MESSAGE_COMMAND_OTHER] = 0; @@ -2599,3 +2598,17 @@ bool CBanDB::Read(banmap_t& banSet) int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) { return nNow + (int64_t)(log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */) * average_interval_seconds * -1000000.0 + 0.5); } + +/* static */ uint64_t CNode::CalculateKeyedNetGroup(const CAddress& ad) +{ + static uint64_t k0 = 0, k1 = 0; + while (k0 == 0 && k1 == 0) { + // Make sure this only runs on the first invocation. + GetRandBytes((unsigned char*)&k0, sizeof(k0)); + GetRandBytes((unsigned char*)&k1, sizeof(k1)); + } + + std::vector vchNetGroup(ad.GetGroup()); + + return CSipHasher(k0, k1).Write(&vchNetGroup[0], vchNetGroup.size()).Finalize(); +} diff --git a/src/net.h b/src/net.h index 019a3f7ee..8df3cb421 100644 --- a/src/net.h +++ b/src/net.h @@ -9,8 +9,6 @@ #include "amount.h" #include "bloom.h" #include "compat.h" -#include "crypto/common.h" -#include "crypto/sha256.h" #include "limitedmap.h" #include "netbase.h" #include "protocol.h" @@ -337,7 +335,7 @@ public: int64_t nLastRecv; int64_t nTimeConnected; int64_t nTimeOffset; - CAddress addr; + const CAddress addr; std::string addrName; CService addrLocal; int nVersion; @@ -365,7 +363,7 @@ public: int nRefCount; NodeId id; - std::vector vchKeyedNetGroup; + const uint64_t nKeyedNetGroup; protected: // Denial-of-service detection/prevention @@ -454,22 +452,8 @@ private: CNode(const CNode&); void operator=(const CNode&); - void CalculateKeyedNetGroup() { - static std::vector vchSecretKey; - if (vchSecretKey.empty()) { - vchSecretKey.resize(32, 0); - GetRandBytes(vchSecretKey.data(), vchSecretKey.size()); - } - - std::vector vchNetGroup(this->addr.GetGroup()); + static uint64_t CalculateKeyedNetGroup(const CAddress& ad); - CSHA256 hash; - hash.Write(begin_ptr(vchNetGroup), vchNetGroup.size()); - hash.Write(begin_ptr(vchSecretKey), vchSecretKey.size()); - - vchKeyedNetGroup.resize(32, 0); - hash.Finalize(begin_ptr(vchKeyedNetGroup)); - } public: NodeId GetId() const {