aboutsummaryrefslogtreecommitdiff
path: root/src/net.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/net.cpp')
-rw-r--r--src/net.cpp137
1 files changed, 59 insertions, 78 deletions
diff --git a/src/net.cpp b/src/net.cpp
index a0c670e595..a390eca776 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;
@@ -90,9 +94,6 @@ std::string strSubVersion;
std::vector<CNode*> vNodes;
CCriticalSection cs_vNodes;
-std::map<uint256, CTransaction> mapRelay;
-std::deque<std::pair<int64_t, uint256> > vRelayExpiration;
-CCriticalSection cs_mapRelay;
limitedmap<uint256, int64_t> mapAlreadyAskedFor(MAX_INV_SZ);
static std::deque<std::string> vOneShots;
@@ -161,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);
}
@@ -174,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;
}
@@ -368,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))
@@ -400,7 +400,7 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
return NULL;
}
- addrman.Attempt(addrConnect);
+ addrman.Attempt(addrConnect, fCountFailure);
// Add node
CNode* pnode = new CNode(hSocket, addrConnect, pszDest ? pszDest : "", false);
@@ -411,13 +411,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;
@@ -463,14 +464,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);
}
@@ -841,6 +842,7 @@ struct NodeEvictionCandidate
int64_t nTimeConnected;
int64_t nMinPingUsecTime;
CAddress addr;
+ uint64_t nKeyedNetGroup;
};
static bool ReverseCompareNodeMinPingTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
@@ -853,36 +855,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.
@@ -905,7 +879,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);
}
}
@@ -915,9 +889,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;
@@ -938,24 +911,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.
@@ -1467,12 +1440,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(seed.getHost(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++;
@@ -1534,7 +1508,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);
}
}
@@ -1549,8 +1523,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);
@@ -1621,6 +1595,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;
@@ -1634,7 +1612,7 @@ void ThreadOpenConnections()
}
if (addrConnect.IsValid())
- OpenNetworkConnection(addrConnect, &grant);
+ OpenNetworkConnection(addrConnect, (int)setConnected.size() >= std::min(nMaxConnections - 1, 2), &grant);
}
}
@@ -1656,7 +1634,7 @@ void ThreadOpenAddedConnections()
BOOST_FOREACH(const std::string& strAddNode, lAddresses) {
CAddress addr;
CSemaphoreGrant grant(*semOutbound);
- OpenNetworkConnection(addr, &grant, strAddNode.c_str());
+ OpenNetworkConnection(addr, false, &grant, strAddNode.c_str());
MilliSleep(500);
}
MilliSleep(120000); // Retry every 2 minutes
@@ -1695,7 +1673,9 @@ void ThreadOpenAddedConnections()
BOOST_FOREACH(std::vector<CService>& vserv, lservAddressesToAdd)
{
CSemaphoreGrant grant(*semOutbound);
- OpenNetworkConnection(CAddress(vserv[i % vserv.size()]), &grant);
+ /* We want -addnode to work even for nodes that don't provide all
+ * wanted services, so pass in nServices=NODE_NONE to CAddress. */
+ OpenNetworkConnection(CAddress(vserv[i % vserv.size()], NODE_NONE), false, &grant);
MilliSleep(500);
}
MilliSleep(120000); // Retry every 2 minutes
@@ -1703,7 +1683,7 @@ void ThreadOpenAddedConnections()
}
// 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
@@ -1717,7 +1697,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)
@@ -2081,18 +2061,6 @@ instance_of_cnetcleanup;
void RelayTransaction(const CTransaction& tx)
{
CInv inv(MSG_TX, tx.GetHash());
- {
- LOCK(cs_mapRelay);
- // Expire old relay messages
- while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime())
- {
- mapRelay.erase(vRelayExpiration.front().second);
- vRelayExpiration.pop_front();
- }
-
- mapRelay.insert(std::make_pair(inv.hash, tx));
- vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv.hash));
- }
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
{
@@ -2360,10 +2328,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;
@@ -2372,7 +2343,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 = "";
@@ -2397,6 +2367,7 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa
fRelayTxes = false;
fSentAddr = false;
pfilter = new CBloomFilter();
+ timeLastMempoolReq = 0;
nPingNonceSent = 0;
nPingUsecStart = 0;
nPingUsecTime = 0;
@@ -2638,3 +2609,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();
+}