diff --git a/src/avalanche/peermanager.h b/src/avalanche/peermanager.h --- a/src/avalanche/peermanager.h +++ b/src/avalanche/peermanager.h @@ -93,6 +93,8 @@ std::chrono::seconds registration_time; std::chrono::seconds nextPossibleConflictTime; + double availabilityScore = 0.0; + /** * Consider dropping the peer if no node is attached after this timeout * expired. @@ -378,6 +380,24 @@ uint32_t getTotalPeersScore() const { return totalPeersScore; } uint32_t getConnectedPeersScore() const { return connectedPeersScore; } + template + void updateAvailabilityScores(const double decayFactor, + Callable &&getNodeAvailabilityScore) { + forEachPeer([&](const avalanche::Peer &peer) { + // Calculate average of current node scores + double peerScore = 0.0; + forEachNode(peer, [&](const avalanche::Node &node) { + peerScore += getNodeAvailabilityScore(node.nodeid); + }); + peerScore /= peer.node_count; + + // Calculate exponential moving average of averaged node scores + peer.availabilityScore = + decayFactor * peerScore + + (1. - decayFactor) * peer.availabilityScore; + }); + } + /**************************************************** * Functions which are public for testing purposes. * ****************************************************/ diff --git a/src/net_processing.cpp b/src/net_processing.cpp --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -1705,6 +1705,32 @@ m_connman.ForEachNode([](CNode *pnode) { pnode->updateAvailabilityScore(AVALANCHE_STATISTICS_DECAY_FACTOR); }); + + if (!g_avalanche) { + // Not enabled or not ready yet + return; + } + + // Generate a peer availability score by computing an exponentially + // weighted moving average of the average of node availability scores. + // This ensures the peer score is bound to the lifetime of its proof which + // incentivizes stable network activity. + g_avalanche->withPeerManager([&](const avalanche::PeerManager &pm) { + pm.forEachPeer([&](const avalanche::Peer &peer) { + double peerScore = 0.0; + pm.forEachNode(peer, [&](const avalanche::Node &node) { + m_connman.ForNode(node.nodeid, [&](CNode *pavanode) { + peerScore += pavanode->getAvailabilityScore(); + }); + }); + // TODO move this into a testable module on its own + peerScore /= peer.node_count; + peer.availabilityScore = + AVALANCHE_STATISTICS_DECAY_FACTOR * peerScore + + (1. - AVALANCHE_STATISTICS_DECAY_FACTOR) * + peer.availabilityScore; + }); + }); } void PeerManagerImpl::AvalanchePeriodicNetworking(CScheduler &scheduler) const {