mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-05 14:06:27 -05:00
Merge #19910: net processing: Move peer_map to PeerManager
3025ca9e77
[net processing] Add RemovePeer() (John Newbery)a20ab22786
[net processing] Make GetPeerRef const (John Newbery)ed7e469cee
[net_processing] Move peer_map to PeerManager (John Newbery)a529fd3e3f
[net processing] Move GetNodeStateStats into PeerManager (John Newbery) Pull request description: This moves `g_peer_map` from a global in net_processing.cpp's unnamed namespace to being a member `m_peer_map` of `PeerManager`. ACKs for top commit: theuni: Re-ACK3025ca9e77
. dongcarl: Re-ACK3025ca9
hebasto: re-ACK3025ca9e77
, since my [previous](https://github.com/bitcoin/bitcoin/pull/19910#pullrequestreview-545574237) review only reverted the change that introduced NRVO in `PeerManager::GetPeerRef`, and comments are fixed in the proper commits. Tree-SHA512: 6369eb3c688ac5b84f89f7674115f78ff02edbed76063ac2ebb1759894c9e973883e10821a35dab92bd3d738280acc095bd5368f552a060b83cd309330387d47
This commit is contained in:
commit
795afe6e63
4 changed files with 94 additions and 74 deletions
|
@ -422,58 +422,6 @@ static CNodeState *State(NodeId pnode) EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
|
||||||
return &it->second;
|
return &it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Data structure for an individual peer. This struct is not protected by
|
|
||||||
* cs_main since it does not contain validation-critical data.
|
|
||||||
*
|
|
||||||
* Memory is owned by shared pointers and this object is destructed when
|
|
||||||
* the refcount drops to zero.
|
|
||||||
*
|
|
||||||
* TODO: move most members from CNodeState to this structure.
|
|
||||||
* TODO: move remaining application-layer data members from CNode to this structure.
|
|
||||||
*/
|
|
||||||
struct Peer {
|
|
||||||
/** Same id as the CNode object for this peer */
|
|
||||||
const NodeId m_id{0};
|
|
||||||
|
|
||||||
/** Protects misbehavior data members */
|
|
||||||
Mutex m_misbehavior_mutex;
|
|
||||||
/** Accumulated misbehavior score for this peer */
|
|
||||||
int m_misbehavior_score GUARDED_BY(m_misbehavior_mutex){0};
|
|
||||||
/** Whether this peer should be disconnected and marked as discouraged (unless it has the noban permission). */
|
|
||||||
bool m_should_discourage GUARDED_BY(m_misbehavior_mutex){false};
|
|
||||||
|
|
||||||
/** Set of txids to reconsider once their parent transactions have been accepted **/
|
|
||||||
std::set<uint256> m_orphan_work_set GUARDED_BY(g_cs_orphans);
|
|
||||||
|
|
||||||
/** Protects m_getdata_requests **/
|
|
||||||
Mutex m_getdata_requests_mutex;
|
|
||||||
/** Work queue of items requested by this peer **/
|
|
||||||
std::deque<CInv> m_getdata_requests GUARDED_BY(m_getdata_requests_mutex);
|
|
||||||
|
|
||||||
explicit Peer(NodeId id) : m_id(id) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
using PeerRef = std::shared_ptr<Peer>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Map of all Peer objects, keyed by peer id. This map is protected
|
|
||||||
* by the global g_peer_mutex. Once a shared pointer reference is
|
|
||||||
* taken, the lock may be released. Individual fields are protected by
|
|
||||||
* their own locks.
|
|
||||||
*/
|
|
||||||
Mutex g_peer_mutex;
|
|
||||||
static std::map<NodeId, PeerRef> g_peer_map GUARDED_BY(g_peer_mutex);
|
|
||||||
|
|
||||||
/** Get a shared pointer to the Peer object.
|
|
||||||
* May return nullptr if the Peer object can't be found. */
|
|
||||||
static PeerRef GetPeerRef(NodeId id)
|
|
||||||
{
|
|
||||||
LOCK(g_peer_mutex);
|
|
||||||
auto it = g_peer_map.find(id);
|
|
||||||
return it != g_peer_map.end() ? it->second : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void UpdatePreferredDownload(const CNode& node, CNodeState* state) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
static void UpdatePreferredDownload(const CNode& node, CNodeState* state) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
||||||
{
|
{
|
||||||
nPreferredDownload -= state->fPreferredDownload;
|
nPreferredDownload -= state->fPreferredDownload;
|
||||||
|
@ -807,8 +755,8 @@ void PeerManager::InitializeNode(CNode *pnode) {
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
PeerRef peer = std::make_shared<Peer>(nodeid);
|
PeerRef peer = std::make_shared<Peer>(nodeid);
|
||||||
LOCK(g_peer_mutex);
|
LOCK(m_peer_mutex);
|
||||||
g_peer_map.emplace_hint(g_peer_map.end(), nodeid, std::move(peer));
|
m_peer_map.emplace_hint(m_peer_map.end(), nodeid, std::move(peer));
|
||||||
}
|
}
|
||||||
if (!pnode->IsInboundConn()) {
|
if (!pnode->IsInboundConn()) {
|
||||||
PushNodeVersion(*pnode, m_connman, GetTime());
|
PushNodeVersion(*pnode, m_connman, GetTime());
|
||||||
|
@ -842,11 +790,9 @@ void PeerManager::FinalizeNode(const CNode& node, bool& fUpdateConnectionTime) {
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
int misbehavior{0};
|
int misbehavior{0};
|
||||||
{
|
{
|
||||||
PeerRef peer = GetPeerRef(nodeid);
|
PeerRef peer = RemovePeer(nodeid);
|
||||||
assert(peer != nullptr);
|
assert(peer != nullptr);
|
||||||
misbehavior = WITH_LOCK(peer->m_misbehavior_mutex, return peer->m_misbehavior_score);
|
misbehavior = WITH_LOCK(peer->m_misbehavior_mutex, return peer->m_misbehavior_score);
|
||||||
LOCK(g_peer_mutex);
|
|
||||||
g_peer_map.erase(nodeid);
|
|
||||||
}
|
}
|
||||||
CNodeState *state = State(nodeid);
|
CNodeState *state = State(nodeid);
|
||||||
assert(state != nullptr);
|
assert(state != nullptr);
|
||||||
|
@ -887,7 +833,26 @@ void PeerManager::FinalizeNode(const CNode& node, bool& fUpdateConnectionTime) {
|
||||||
LogPrint(BCLog::NET, "Cleared nodestate for peer=%d\n", nodeid);
|
LogPrint(BCLog::NET, "Cleared nodestate for peer=%d\n", nodeid);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) {
|
PeerRef PeerManager::GetPeerRef(NodeId id) const
|
||||||
|
{
|
||||||
|
LOCK(m_peer_mutex);
|
||||||
|
auto it = m_peer_map.find(id);
|
||||||
|
return it != m_peer_map.end() ? it->second : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
PeerRef PeerManager::RemovePeer(NodeId id)
|
||||||
|
{
|
||||||
|
PeerRef ret;
|
||||||
|
LOCK(m_peer_mutex);
|
||||||
|
auto it = m_peer_map.find(id);
|
||||||
|
if (it != m_peer_map.end()) {
|
||||||
|
ret = std::move(it->second);
|
||||||
|
m_peer_map.erase(it);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PeerManager::GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) {
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
CNodeState* state = State(nodeid);
|
CNodeState* state = State(nodeid);
|
||||||
|
|
|
@ -32,6 +32,47 @@ static const bool DEFAULT_PEERBLOCKFILTERS = false;
|
||||||
/** Threshold for marking a node to be discouraged, e.g. disconnected and added to the discouragement filter. */
|
/** Threshold for marking a node to be discouraged, e.g. disconnected and added to the discouragement filter. */
|
||||||
static const int DISCOURAGEMENT_THRESHOLD{100};
|
static const int DISCOURAGEMENT_THRESHOLD{100};
|
||||||
|
|
||||||
|
struct CNodeStateStats {
|
||||||
|
int m_misbehavior_score = 0;
|
||||||
|
int nSyncHeight = -1;
|
||||||
|
int nCommonHeight = -1;
|
||||||
|
std::vector<int> vHeightInFlight;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data structure for an individual peer. This struct is not protected by
|
||||||
|
* cs_main since it does not contain validation-critical data.
|
||||||
|
*
|
||||||
|
* Memory is owned by shared pointers and this object is destructed when
|
||||||
|
* the refcount drops to zero.
|
||||||
|
*
|
||||||
|
* TODO: move most members from CNodeState to this structure.
|
||||||
|
* TODO: move remaining application-layer data members from CNode to this structure.
|
||||||
|
*/
|
||||||
|
struct Peer {
|
||||||
|
/** Same id as the CNode object for this peer */
|
||||||
|
const NodeId m_id{0};
|
||||||
|
|
||||||
|
/** Protects misbehavior data members */
|
||||||
|
Mutex m_misbehavior_mutex;
|
||||||
|
/** Accumulated misbehavior score for this peer */
|
||||||
|
int m_misbehavior_score GUARDED_BY(m_misbehavior_mutex){0};
|
||||||
|
/** Whether this peer should be disconnected and marked as discouraged (unless it has the noban permission). */
|
||||||
|
bool m_should_discourage GUARDED_BY(m_misbehavior_mutex){false};
|
||||||
|
|
||||||
|
/** Set of txids to reconsider once their parent transactions have been accepted **/
|
||||||
|
std::set<uint256> m_orphan_work_set GUARDED_BY(g_cs_orphans);
|
||||||
|
|
||||||
|
/** Protects m_getdata_requests **/
|
||||||
|
Mutex m_getdata_requests_mutex;
|
||||||
|
/** Work queue of items requested by this peer **/
|
||||||
|
std::deque<CInv> m_getdata_requests GUARDED_BY(m_getdata_requests_mutex);
|
||||||
|
|
||||||
|
explicit Peer(NodeId id) : m_id(id) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
using PeerRef = std::shared_ptr<Peer>;
|
||||||
|
|
||||||
class PeerManager final : public CValidationInterface, public NetEventsInterface {
|
class PeerManager final : public CValidationInterface, public NetEventsInterface {
|
||||||
public:
|
public:
|
||||||
PeerManager(const CChainParams& chainparams, CConnman& connman, BanMan* banman,
|
PeerManager(const CChainParams& chainparams, CConnman& connman, BanMan* banman,
|
||||||
|
@ -94,7 +135,18 @@ public:
|
||||||
*/
|
*/
|
||||||
void Misbehaving(const NodeId pnode, const int howmuch, const std::string& message);
|
void Misbehaving(const NodeId pnode, const int howmuch, const std::string& message);
|
||||||
|
|
||||||
|
/** Get statistics from node state */
|
||||||
|
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/** Get a shared pointer to the Peer object.
|
||||||
|
* May return an empty shared_ptr if the Peer object can't be found. */
|
||||||
|
PeerRef GetPeerRef(NodeId id) const;
|
||||||
|
|
||||||
|
/** Get a shared pointer to the Peer object and remove it from m_peer_map.
|
||||||
|
* May return an empty shared_ptr if the Peer object can't be found. */
|
||||||
|
PeerRef RemovePeer(NodeId id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Potentially mark a node discouraged based on the contents of a BlockValidationState object
|
* Potentially mark a node discouraged based on the contents of a BlockValidationState object
|
||||||
*
|
*
|
||||||
|
@ -143,18 +195,18 @@ private:
|
||||||
TxRequestTracker m_txrequest GUARDED_BY(::cs_main);
|
TxRequestTracker m_txrequest GUARDED_BY(::cs_main);
|
||||||
|
|
||||||
int64_t m_stale_tip_check_time; //!< Next time to check for stale tip
|
int64_t m_stale_tip_check_time; //!< Next time to check for stale tip
|
||||||
};
|
|
||||||
|
|
||||||
struct CNodeStateStats {
|
/** Protects m_peer_map */
|
||||||
int m_misbehavior_score = 0;
|
mutable Mutex m_peer_mutex;
|
||||||
int nSyncHeight = -1;
|
/**
|
||||||
int nCommonHeight = -1;
|
* Map of all Peer objects, keyed by peer id. This map is protected
|
||||||
std::vector<int> vHeightInFlight;
|
* by the m_peer_mutex. Once a shared pointer reference is
|
||||||
|
* taken, the lock may be released. Individual fields are protected by
|
||||||
|
* their own locks.
|
||||||
|
*/
|
||||||
|
std::map<NodeId, PeerRef> m_peer_map GUARDED_BY(m_peer_mutex);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Get statistics from node state */
|
|
||||||
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats);
|
|
||||||
|
|
||||||
/** Relay transaction to every node */
|
/** Relay transaction to every node */
|
||||||
void RelayTransaction(const uint256& txid, const uint256& wtxid, const CConnman& connman) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
void RelayTransaction(const uint256& txid, const uint256& wtxid, const CConnman& connman) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
||||||
|
|
|
@ -121,11 +121,13 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to retrieve the CNodeStateStats for each node.
|
// Try to retrieve the CNodeStateStats for each node.
|
||||||
TRY_LOCK(::cs_main, lockMain);
|
if (m_context->peerman) {
|
||||||
if (lockMain) {
|
TRY_LOCK(::cs_main, lockMain);
|
||||||
for (auto& node_stats : stats) {
|
if (lockMain) {
|
||||||
std::get<1>(node_stats) =
|
for (auto& node_stats : stats) {
|
||||||
GetNodeStateStats(std::get<0>(node_stats).nodeid, std::get<2>(node_stats));
|
std::get<1>(node_stats) =
|
||||||
|
m_context->peerman->GetNodeStateStats(std::get<0>(node_stats).nodeid, std::get<2>(node_stats));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -165,8 +165,9 @@ static RPCHelpMan getpeerinfo()
|
||||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||||
{
|
{
|
||||||
NodeContext& node = EnsureNodeContext(request.context);
|
NodeContext& node = EnsureNodeContext(request.context);
|
||||||
if(!node.connman)
|
if(!node.connman || !node.peerman) {
|
||||||
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
|
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<CNodeStats> vstats;
|
std::vector<CNodeStats> vstats;
|
||||||
node.connman->GetNodeStats(vstats);
|
node.connman->GetNodeStats(vstats);
|
||||||
|
@ -176,7 +177,7 @@ static RPCHelpMan getpeerinfo()
|
||||||
for (const CNodeStats& stats : vstats) {
|
for (const CNodeStats& stats : vstats) {
|
||||||
UniValue obj(UniValue::VOBJ);
|
UniValue obj(UniValue::VOBJ);
|
||||||
CNodeStateStats statestats;
|
CNodeStateStats statestats;
|
||||||
bool fStateStats = GetNodeStateStats(stats.nodeid, statestats);
|
bool fStateStats = node.peerman->GetNodeStateStats(stats.nodeid, statestats);
|
||||||
obj.pushKV("id", stats.nodeid);
|
obj.pushKV("id", stats.nodeid);
|
||||||
obj.pushKV("addr", stats.addrName);
|
obj.pushKV("addr", stats.addrName);
|
||||||
if (stats.addrBind.IsValid()) {
|
if (stats.addrBind.IsValid()) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue