From 053930ffc41ba33fe7ce26bde7097951fe0b8462 Mon Sep 17 00:00:00 2001 From: Patrick Strateman Date: Mon, 23 May 2016 00:21:05 -0700 Subject: Avoid recalculating vchKeyedNetGroup in eviction logic. Lazy calculate vchKeyedNetGroup in CNode::GetKeyedNetGroup. --- src/net.cpp | 43 +++++++++---------------------------------- 1 file changed, 9 insertions(+), 34 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index c09e3aedb..eb62ee8a0 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -14,6 +14,7 @@ #include "clientversion.h" #include "consensus/consensus.h" #include "crypto/common.h" +#include "crypto/sha256.h" #include "hash.h" #include "primitives/transaction.h" #include "scheduler.h" @@ -838,6 +839,7 @@ struct NodeEvictionCandidate int64_t nTimeConnected; int64_t nMinPingUsecTime; CAddress addr; + std::vector vchKeyedNetGroup; }; static bool ReverseCompareNodeMinPingTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b) @@ -850,36 +852,8 @@ static bool ReverseCompareNodeTimeConnected(const NodeEvictionCandidate &a, cons return a.nTimeConnected > b.nTimeConnected; } -class CompareNetGroupKeyed -{ - std::vector vchSecretKey; -public: - CompareNetGroupKeyed() - { - vchSecretKey.resize(32, 0); - GetRandBytes(vchSecretKey.data(), vchSecretKey.size()); - } - - bool operator()(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b) - { - std::vector vchGroupA, vchGroupB; - CSHA256 hashA, hashB; - std::vector vchA(32), vchB(32); - - vchGroupA = a.addr.GetGroup(); - vchGroupB = b.addr.GetGroup(); - - hashA.Write(begin_ptr(vchGroupA), vchGroupA.size()); - hashB.Write(begin_ptr(vchGroupB), vchGroupB.size()); - - hashA.Write(begin_ptr(vchSecretKey), vchSecretKey.size()); - hashB.Write(begin_ptr(vchSecretKey), vchSecretKey.size()); - - hashA.Finalize(begin_ptr(vchA)); - hashB.Finalize(begin_ptr(vchB)); - - return vchA < vchB; - } +static bool CompareNetGroupKeyed(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b) { + return a.vchKeyedNetGroup < b.vchKeyedNetGroup; }; /** Try to find a connection to evict when the node is full. @@ -902,7 +876,7 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { continue; if (node->fDisconnect) continue; - NodeEvictionCandidate candidate = {node->id, node->nTimeConnected, node->nMinPingUsecTime, node->addr}; + NodeEvictionCandidate candidate = {node->id, node->nTimeConnected, node->nMinPingUsecTime, node->addr, node->vchKeyedNetGroup}; vEvictionCandidates.push_back(candidate); } } @@ -912,9 +886,8 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { // Protect connections with certain characteristics // Deterministically select 4 peers to protect by netgroup. - // An attacker cannot predict which netgroups will be protected. - static CompareNetGroupKeyed comparerNetGroupKeyed; - std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), comparerNetGroupKeyed); + // An attacker cannot predict which netgroups will be protected + std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), CompareNetGroupKeyed); vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(4, static_cast(vEvictionCandidates.size())), vEvictionCandidates.end()); if (vEvictionCandidates.empty()) return false; @@ -2392,6 +2365,8 @@ 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; -- cgit v1.2.3 From c31b24f745a84669f2af729052da7fd7ed2da868 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 25 May 2016 15:38:32 +0200 Subject: Use 64-bit SipHash of netgroups in eviction --- src/net.cpp | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) (limited to 'src/net.cpp') 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(); +} -- cgit v1.2.3 From 888483098e60f2a944f1d246bbfec4d14a2975f8 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 7 Jun 2016 16:29:03 +0200 Subject: Use C++11 thread-safe static initializers --- src/net.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'src/net.cpp') diff --git a/src/net.cpp b/src/net.cpp index 0bc501601..e29053cf5 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2601,12 +2601,8 @@ int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) { /* 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)); - } + static const uint64_t k0 = GetRand(std::numeric_limits::max()); + static const uint64_t k1 = GetRand(std::numeric_limits::max()); std::vector vchNetGroup(ad.GetGroup()); -- cgit v1.2.3