mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-11-11 14:38:29 +01:00
Merge #8173: Use SipHash for node eviction (cont'd)
eebc232test: Add more test vectors for siphash (Wladimir J. van der Laan)8884830Use C++11 thread-safe static initializers (Pieter Wuille)c31b24fUse 64-bit SipHash of netgroups in eviction (Pieter Wuille)9bf156bSupport SipHash with arbitrary byte writes (Pieter Wuille)053930fAvoid recalculating vchKeyedNetGroup in eviction logic. (Patrick Strateman)
This commit is contained in:
68
src/net.cpp
68
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;
|
||||
uint64_t nKeyedNetGroup;
|
||||
};
|
||||
|
||||
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<unsigned char> vchSecretKey;
|
||||
public:
|
||||
CompareNetGroupKeyed()
|
||||
{
|
||||
vchSecretKey.resize(32, 0);
|
||||
GetRandBytes(vchSecretKey.data(), vchSecretKey.size());
|
||||
}
|
||||
|
||||
bool operator()(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
|
||||
{
|
||||
std::vector<unsigned char> vchGroupA, vchGroupB;
|
||||
CSHA256 hashA, hashB;
|
||||
std::vector<unsigned char> 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.nKeyedNetGroup < b.nKeyedNetGroup;
|
||||
};
|
||||
|
||||
/** 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->nKeyedNetGroup};
|
||||
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<int>(vEvictionCandidates.size())), vEvictionCandidates.end());
|
||||
|
||||
if (vEvictionCandidates.empty()) return false;
|
||||
@@ -935,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<unsigned char> naMostConnections;
|
||||
uint64_t naMostConnections;
|
||||
unsigned int nMostConnections = 0;
|
||||
int64_t nMostConnectionsTime = 0;
|
||||
std::map<std::vector<unsigned char>, std::vector<NodeEvictionCandidate> > mapAddrCounts;
|
||||
std::map<uint64_t, std::vector<NodeEvictionCandidate> > 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.
|
||||
@@ -2346,6 +2319,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)
|
||||
{
|
||||
@@ -2358,7 +2333,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 = "";
|
||||
@@ -2625,3 +2599,13 @@ 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 const uint64_t k0 = GetRand(std::numeric_limits<uint64_t>::max());
|
||||
static const uint64_t k1 = GetRand(std::numeric_limits<uint64_t>::max());
|
||||
|
||||
std::vector<unsigned char> vchNetGroup(ad.GetGroup());
|
||||
|
||||
return CSipHasher(k0, k1).Write(&vchNetGroup[0], vchNetGroup.size()).Finalize();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user