@ -14,6 +14,7 @@
@@ -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
@@ -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
@@ -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) {
@@ -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) {
@@ -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) {
@@ -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
@@ -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
@@ -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)
@@ -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 ( ) ;
}