message: [net processing] Add Peer
  Peer is a struct for holding per-peer data. This structure is not
  protected by cs_main since it does not contain validation-critical data.
diff: @@ -481,6 +481,43 @@ static CNodeState *State(NodeId pnode) EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
  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};
  +
  + 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)
  {
  nPreferredDownload -= state->fPreferredDownload;
  @@ -848,6 +885,11 @@ void PeerLogicValidation::InitializeNode(CNode *pnode) {
  LOCK(cs_main);
  mapNodeState.emplace_hint(mapNodeState.end(), std::piecewise_construct, std::forward_as_tuple(nodeid), std::forward_as_tuple(addr, pnode->IsInboundConn(), pnode->IsManualConn()));
  }
  + {
  + PeerRef peer = std::make_shared<Peer>(nodeid);
  + LOCK(g_peer_mutex);
  + g_peer_map.emplace_hint(g_peer_map.end(), nodeid, std::move(peer));
  + }
  if(!pnode->IsInboundConn())
  PushNodeVersion(*pnode, m_connman, GetTime());
  }
  @@ -875,6 +917,10 @@ void PeerLogicValidation::ReattemptInitialBroadcast(CScheduler& scheduler) const
  void PeerLogicValidation::FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) {
  fUpdateConnectionTime = false;
  LOCK(cs_main);
  + {
  + LOCK(g_peer_mutex);
  + g_peer_map.erase(nodeid);
  + }
  CNodeState *state = State(nodeid);
  assert(state != nullptr);
  