aboutsummaryrefslogtreecommitdiff
path: root/src/net.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/net.cpp')
-rw-r--r--src/net.cpp301
1 files changed, 186 insertions, 115 deletions
diff --git a/src/net.cpp b/src/net.cpp
index c09e3aedb..4eca3d75c 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"
@@ -70,12 +71,15 @@ namespace {
const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*";
+/** Services this node implementation cares about */
+static const ServiceFlags nRelevantServices = NODE_NETWORK;
+
//
// Global state variables
//
bool fDiscover = true;
bool fListen = true;
-uint64_t nLocalServices = NODE_NETWORK;
+ServiceFlags nLocalServices = NODE_NETWORK;
bool fRelayTxes = true;
CCriticalSection cs_mapLocalHost;
std::map<CNetAddr, LocalServiceInfo> mapLocalHost;
@@ -158,7 +162,7 @@ static std::vector<CAddress> convertSeed6(const std::vector<SeedSpec6> &vSeedsIn
{
struct in6_addr ip;
memcpy(&ip, i->addr, sizeof(ip));
- CAddress addr(CService(ip, i->port));
+ CAddress addr(CService(ip, i->port), NODE_NETWORK);
addr.nTime = GetTime() - GetRand(nOneWeek) - nOneWeek;
vSeedsOut.push_back(addr);
}
@@ -171,13 +175,12 @@ static std::vector<CAddress> convertSeed6(const std::vector<SeedSpec6> &vSeedsIn
// one by discovery.
CAddress GetLocalAddress(const CNetAddr *paddrPeer)
{
- CAddress ret(CService("0.0.0.0",GetListenPort()),0);
+ CAddress ret(CService("0.0.0.0",GetListenPort()), NODE_NONE);
CService addr;
if (GetLocal(addr, paddrPeer))
{
- ret = CAddress(addr);
+ ret = CAddress(addr, nLocalServices);
}
- ret.nServices = nLocalServices;
ret.nTime = GetAdjustedTime();
return ret;
}
@@ -365,7 +368,7 @@ CNode* FindNode(const CService& addr)
return NULL;
}
-CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
+CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure)
{
if (pszDest == NULL) {
if (IsLocal(addrConnect))
@@ -397,7 +400,27 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
return NULL;
}
- addrman.Attempt(addrConnect);
+ if (pszDest && addrConnect.IsValid()) {
+ // It is possible that we already have a connection to the IP/port pszDest resolved to.
+ // In that case, drop the connection that was just created, and return the existing CNode instead.
+ // Also store the name we used to connect in that CNode, so that future FindNode() calls to that
+ // name catch this early.
+ CNode* pnode = FindNode((CService)addrConnect);
+ if (pnode)
+ {
+ pnode->AddRef();
+ {
+ LOCK(cs_vNodes);
+ if (pnode->addrName.empty()) {
+ pnode->addrName = std::string(pszDest);
+ }
+ }
+ CloseSocket(hSocket);
+ return pnode;
+ }
+ }
+
+ addrman.Attempt(addrConnect, fCountFailure);
// Add node
CNode* pnode = new CNode(hSocket, addrConnect, pszDest ? pszDest : "", false);
@@ -408,13 +431,14 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
vNodes.push_back(pnode);
}
+ pnode->nServicesExpected = ServiceFlags(addrConnect.nServices & nRelevantServices);
pnode->nTimeConnected = GetTime();
return pnode;
} else if (!proxyConnectionFailed) {
// If connecting to the node failed, and failure is not caused by a problem connecting to
// the proxy, mark this as an attempt.
- addrman.Attempt(addrConnect);
+ addrman.Attempt(addrConnect, fCountFailure);
}
return NULL;
@@ -460,14 +484,14 @@ void CNode::PushVersion()
int nBestHeight = GetNodeSignals().GetHeight().get_value_or(0);
int64_t nTime = (fInbound ? GetAdjustedTime() : GetTime());
- CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0",0)));
+ CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0", 0), addr.nServices));
CAddress addrMe = GetLocalAddress(&addr);
GetRandBytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
if (fLogIPs)
LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), addrYou.ToString(), id);
else
LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), id);
- PushMessage(NetMsgType::VERSION, PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe,
+ PushMessage(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalServices, nTime, addrYou, addrMe,
nLocalHostNonce, strSubVersion, nBestHeight, ::fRelayTxes);
}
@@ -837,7 +861,13 @@ struct NodeEvictionCandidate
NodeId id;
int64_t nTimeConnected;
int64_t nMinPingUsecTime;
+ int64_t nLastBlockTime;
+ int64_t nLastTXTime;
+ bool fNetworkNode;
+ bool fRelayTxes;
+ bool fBloomFilter;
CAddress addr;
+ uint64_t nKeyedNetGroup;
};
static bool ReverseCompareNodeMinPingTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
@@ -850,37 +880,26 @@ 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());
+static bool CompareNetGroupKeyed(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b) {
+ return a.nKeyedNetGroup < b.nKeyedNetGroup;
+}
- hashA.Finalize(begin_ptr(vchA));
- hashB.Finalize(begin_ptr(vchB));
+static bool CompareNodeBlockTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
+{
+ // There is a fall-through here because it is common for a node to have many peers which have not yet relayed a block.
+ if (a.nLastBlockTime != b.nLastBlockTime) return a.nLastBlockTime < b.nLastBlockTime;
+ if (a.fNetworkNode != b.fNetworkNode) return b.fNetworkNode;
+ return a.nTimeConnected > b.nTimeConnected;
+}
- return vchA < vchB;
- }
-};
+static bool CompareNodeTXTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
+{
+ // There is a fall-through here because it is common for a node to have more than a few peers that have not yet relayed txn.
+ if (a.nLastTXTime != b.nLastTXTime) return a.nLastTXTime < b.nLastTXTime;
+ if (a.fRelayTxes != b.fRelayTxes) return b.fRelayTxes;
+ if (a.fBloomFilter != b.fBloomFilter) return a.fBloomFilter;
+ return a.nTimeConnected > b.nTimeConnected;
+}
/** Try to find a connection to evict when the node is full.
* Extreme care must be taken to avoid opening the node to attacker
@@ -890,7 +909,7 @@ public:
* to forge. In order to partition a node the attacker must be
* simultaneously better at all of them than honest peers.
*/
-static bool AttemptToEvictConnection(bool fPreferNewConnection) {
+static bool AttemptToEvictConnection() {
std::vector<NodeEvictionCandidate> vEvictionCandidates;
{
LOCK(cs_vNodes);
@@ -902,7 +921,9 @@ 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->nLastBlockTime, node->nLastTXTime, node->fNetworkNode,
+ node->fRelayTxes, node->pfilter != NULL, node->addr, node->nKeyedNetGroup};
vEvictionCandidates.push_back(candidate);
}
}
@@ -912,9 +933,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;
@@ -926,6 +946,20 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) {
if (vEvictionCandidates.empty()) return false;
+ // Protect 4 nodes that most recently sent us transactions.
+ // An attacker cannot manipulate this metric without performing useful work.
+ std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), CompareNodeTXTime);
+ vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(4, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());
+
+ if (vEvictionCandidates.empty()) return false;
+
+ // Protect 4 nodes that most recently sent us blocks.
+ // An attacker cannot manipulate this metric without performing useful work.
+ std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), CompareNodeBlockTime);
+ vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(4, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());
+
+ if (vEvictionCandidates.empty()) return false;
+
// Protect the half of the remaining nodes which have been connected the longest.
// This replicates the non-eviction implicit behavior, and precludes attacks that start later.
std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeTimeConnected);
@@ -935,31 +969,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];
-
- // 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.
- if (vEvictionCandidates.size() <= 1)
- // unless we prefer the new connection (for whitelisted peers)
- if (!fPreferNewConnection)
- return false;
+ vEvictionCandidates = std::move(mapAddrCounts[naMostConnections]);
// Disconnect from the network group with the most connections
NodeId evicted = vEvictionCandidates.front().id;
@@ -1026,7 +1053,7 @@ static void AcceptConnection(const ListenSocket& hListenSocket) {
if (nInbound >= nMaxInbound)
{
- if (!AttemptToEvictConnection(whitelisted)) {
+ if (!AttemptToEvictConnection()) {
// No connection to evict, disconnect the new connection
LogPrint("net", "failed to find an eviction candidate - connection dropped (full)\n");
CloseSocket(hSocket);
@@ -1439,6 +1466,18 @@ void MapPort(bool)
+static std::string GetDNSHost(const CDNSSeedData& data, ServiceFlags* requiredServiceBits)
+{
+ //use default host for non-filter-capable seeds or if we use the default service bits (NODE_NETWORK)
+ if (!data.supportsServiceBitsFiltering || *requiredServiceBits == NODE_NETWORK) {
+ *requiredServiceBits = NODE_NETWORK;
+ return data.host;
+ }
+
+ return strprintf("x%x.%s", *requiredServiceBits, data.host);
+}
+
+
void ThreadDNSAddressSeed()
{
// goal: only query DNS seeds if address need is acute
@@ -1464,12 +1503,13 @@ void ThreadDNSAddressSeed()
} else {
std::vector<CNetAddr> vIPs;
std::vector<CAddress> vAdd;
- if (LookupHost(seed.host.c_str(), vIPs, 0, true))
+ ServiceFlags requiredServiceBits = nRelevantServices;
+ if (LookupHost(GetDNSHost(seed, &requiredServiceBits).c_str(), vIPs, 0, true))
{
BOOST_FOREACH(const CNetAddr& ip, vIPs)
{
int nOneDay = 24*3600;
- CAddress addr = CAddress(CService(ip, Params().GetDefaultPort()));
+ CAddress addr = CAddress(CService(ip, Params().GetDefaultPort()), requiredServiceBits);
addr.nTime = GetTime() - 3*nOneDay - GetRand(4*nOneDay); // use a random age between 3 and 7 days old
vAdd.push_back(addr);
found++;
@@ -1531,7 +1571,7 @@ void static ProcessOneShot()
CAddress addr;
CSemaphoreGrant grant(*semOutbound, true);
if (grant) {
- if (!OpenNetworkConnection(addr, &grant, strDest.c_str(), true))
+ if (!OpenNetworkConnection(addr, false, &grant, strDest.c_str(), true))
AddOneShot(strDest);
}
}
@@ -1546,8 +1586,8 @@ void ThreadOpenConnections()
ProcessOneShot();
BOOST_FOREACH(const std::string& strAddr, mapMultiArgs["-connect"])
{
- CAddress addr;
- OpenNetworkConnection(addr, NULL, strAddr.c_str());
+ CAddress addr(CService(), NODE_NONE);
+ OpenNetworkConnection(addr, false, NULL, strAddr.c_str());
for (int i = 0; i < 10 && i < nLoop; i++)
{
MilliSleep(500);
@@ -1618,6 +1658,10 @@ void ThreadOpenConnections()
if (IsLimited(addr))
continue;
+ // only connect to full nodes
+ if ((addr.nServices & REQUIRED_SERVICES) != REQUIRED_SERVICES)
+ continue;
+
// only consider very recently tried nodes after 30 failed attempts
if (nANow - addr.nLastTry < 600 && nTries < 30)
continue;
@@ -1631,76 +1675,89 @@ void ThreadOpenConnections()
}
if (addrConnect.IsValid())
- OpenNetworkConnection(addrConnect, &grant);
+ OpenNetworkConnection(addrConnect, (int)setConnected.size() >= std::min(nMaxConnections - 1, 2), &grant);
}
}
-void ThreadOpenAddedConnections()
+std::vector<AddedNodeInfo> GetAddedNodeInfo()
{
+ std::vector<AddedNodeInfo> ret;
+
+ std::list<std::string> lAddresses(0);
{
LOCK(cs_vAddedNodes);
- vAddedNodes = mapMultiArgs["-addnode"];
+ ret.reserve(vAddedNodes.size());
+ BOOST_FOREACH(const std::string& strAddNode, vAddedNodes)
+ lAddresses.push_back(strAddNode);
}
- if (HaveNameProxy()) {
- while(true) {
- std::list<std::string> lAddresses(0);
- {
- LOCK(cs_vAddedNodes);
- BOOST_FOREACH(const std::string& strAddNode, vAddedNodes)
- lAddresses.push_back(strAddNode);
+
+ // Build a map of all already connected addresses (by IP:port and by name) to inbound/outbound and resolved CService
+ std::map<CService, bool> mapConnected;
+ std::map<std::string, std::pair<bool, CService>> mapConnectedByName;
+ {
+ LOCK(cs_vNodes);
+ for (const CNode* pnode : vNodes) {
+ if (pnode->addr.IsValid()) {
+ mapConnected[pnode->addr] = pnode->fInbound;
}
- BOOST_FOREACH(const std::string& strAddNode, lAddresses) {
- CAddress addr;
- CSemaphoreGrant grant(*semOutbound);
- OpenNetworkConnection(addr, &grant, strAddNode.c_str());
- MilliSleep(500);
+ if (!pnode->addrName.empty()) {
+ mapConnectedByName[pnode->addrName] = std::make_pair(pnode->fInbound, static_cast<const CService&>(pnode->addr));
}
- MilliSleep(120000); // Retry every 2 minutes
}
}
+ BOOST_FOREACH(const std::string& strAddNode, lAddresses) {
+ CService service(strAddNode, Params().GetDefaultPort());
+ if (service.IsValid()) {
+ // strAddNode is an IP:port
+ auto it = mapConnected.find(service);
+ if (it != mapConnected.end()) {
+ ret.push_back(AddedNodeInfo{strAddNode, service, true, it->second});
+ } else {
+ ret.push_back(AddedNodeInfo{strAddNode, CService(), false, false});
+ }
+ } else {
+ // strAddNode is a name
+ auto it = mapConnectedByName.find(strAddNode);
+ if (it != mapConnectedByName.end()) {
+ ret.push_back(AddedNodeInfo{strAddNode, it->second.second, true, it->second.first});
+ } else {
+ ret.push_back(AddedNodeInfo{strAddNode, CService(), false, false});
+ }
+ }
+ }
+
+ return ret;
+}
+
+void ThreadOpenAddedConnections()
+{
+ {
+ LOCK(cs_vAddedNodes);
+ vAddedNodes = mapMultiArgs["-addnode"];
+ }
+
for (unsigned int i = 0; true; i++)
{
- std::list<std::string> lAddresses(0);
- {
- LOCK(cs_vAddedNodes);
- BOOST_FOREACH(const std::string& strAddNode, vAddedNodes)
- lAddresses.push_back(strAddNode);
+ std::vector<AddedNodeInfo> vInfo = GetAddedNodeInfo();
+ for (const AddedNodeInfo& info : vInfo) {
+ if (!info.fConnected) {
+ CSemaphoreGrant grant(*semOutbound);
+ // If strAddedNode is an IP/port, decode it immediately, so
+ // OpenNetworkConnection can detect existing connections to that IP/port.
+ CService service(info.strAddedNode, Params().GetDefaultPort());
+ OpenNetworkConnection(CAddress(service, NODE_NONE), false, &grant, info.strAddedNode.c_str(), false);
+ MilliSleep(500);
+ }
}
- std::list<std::vector<CService> > lservAddressesToAdd(0);
- BOOST_FOREACH(const std::string& strAddNode, lAddresses) {
- std::vector<CService> vservNode(0);
- if(Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0))
- lservAddressesToAdd.push_back(vservNode);
- }
- // Attempt to connect to each IP for each addnode entry until at least one is successful per addnode entry
- // (keeping in mind that addnode entries can have many IPs if fNameLookup)
- {
- LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodes)
- for (std::list<std::vector<CService> >::iterator it = lservAddressesToAdd.begin(); it != lservAddressesToAdd.end(); it++)
- BOOST_FOREACH(const CService& addrNode, *(it))
- if (pnode->addr == addrNode)
- {
- it = lservAddressesToAdd.erase(it);
- it--;
- break;
- }
- }
- BOOST_FOREACH(std::vector<CService>& vserv, lservAddressesToAdd)
- {
- CSemaphoreGrant grant(*semOutbound);
- OpenNetworkConnection(CAddress(vserv[i % vserv.size()]), &grant);
- MilliSleep(500);
- }
MilliSleep(120000); // Retry every 2 minutes
}
}
// if successful, this moves the passed grant to the constructed node
-bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot)
+bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot)
{
//
// Initiate outbound network connection
@@ -1714,7 +1771,7 @@ bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOu
} else if (FindNode(std::string(pszDest)))
return false;
- CNode* pnode = ConnectNode(addrConnect, pszDest);
+ CNode* pnode = ConnectNode(addrConnect, pszDest, fCountFailure);
boost::this_thread::interruption_point();
if (!pnode)
@@ -2345,10 +2402,13 @@ 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)
{
- nServices = 0;
+ nServices = NODE_NONE;
+ nServicesExpected = NODE_NONE;
hSocket = hSocketIn;
nRecvVersion = INIT_PROTO_VERSION;
nLastSend = 0;
@@ -2357,7 +2417,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 = "";
@@ -2383,6 +2442,8 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa
fSentAddr = false;
pfilter = new CBloomFilter();
timeLastMempoolReq = 0;
+ nLastBlockTime = 0;
+ nLastTXTime = 0;
nPingNonceSent = 0;
nPingUsecStart = 0;
nPingUsecTime = 0;
@@ -2624,3 +2685,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();
+}