mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-11-11 22:50:59 +01:00
Add recently accepted blocks and txn to AttemptToEvictConnection.
This protects any not-already-protected peers who were the most recent four to relay transactions and most recent four to send blocks to us.
This commit is contained in:
48
src/net.cpp
48
src/net.cpp
@@ -838,6 +838,11 @@ 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;
|
||||
};
|
||||
@@ -854,7 +859,24 @@ static bool ReverseCompareNodeTimeConnected(const NodeEvictionCandidate &a, cons
|
||||
|
||||
static bool CompareNetGroupKeyed(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b) {
|
||||
return a.nKeyedNetGroup < b.nKeyedNetGroup;
|
||||
};
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
@@ -864,7 +886,7 @@ static bool CompareNetGroupKeyed(const NodeEvictionCandidate &a, const NodeEvict
|
||||
* 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);
|
||||
@@ -876,7 +898,9 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) {
|
||||
continue;
|
||||
if (node->fDisconnect)
|
||||
continue;
|
||||
NodeEvictionCandidate candidate = {node->id, node->nTimeConnected, node->nMinPingUsecTime, node->addr, node->nKeyedNetGroup};
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -899,6 +923,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);
|
||||
@@ -999,7 +1037,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);
|
||||
@@ -2358,6 +2396,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;
|
||||
|
||||
Reference in New Issue
Block a user