polkadot_node_subsystem_util/
reputation.rs1use polkadot_node_network_protocol::{PeerId, UnifiedReputationChange};
20use polkadot_node_subsystem::{
21 messages::{NetworkBridgeTxMessage, ReportPeerMessage},
22 overseer,
23};
24use std::{collections::HashMap, time::Duration};
25
26pub const REPUTATION_CHANGE_INTERVAL: Duration = Duration::from_secs(30);
28const LOG_TARGET: &'static str = "parachain::reputation-aggregator";
29
30type BatchReputationChange = HashMap<PeerId, i32>;
31
32#[derive(Debug, Clone)]
34pub struct ReputationAggregator {
35 send_immediately_if: fn(UnifiedReputationChange) -> bool,
36 by_peer: Option<BatchReputationChange>,
37}
38
39impl Default for ReputationAggregator {
40 fn default() -> Self {
41 Self::new(|rep| matches!(rep, UnifiedReputationChange::Malicious(_)))
42 }
43}
44
45impl ReputationAggregator {
46 pub fn new(send_immediately_if: fn(UnifiedReputationChange) -> bool) -> Self {
55 Self { by_peer: Default::default(), send_immediately_if }
56 }
57
58 pub async fn send(
61 &mut self,
62 sender: &mut impl overseer::SubsystemSender<NetworkBridgeTxMessage>,
63 ) {
64 if let Some(by_peer) = self.by_peer.take() {
65 sender
66 .send_message(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Batch(by_peer)))
67 .await;
68 }
69 }
70
71 pub async fn modify(
74 &mut self,
75 sender: &mut impl overseer::SubsystemSender<NetworkBridgeTxMessage>,
76 peer_id: PeerId,
77 rep: UnifiedReputationChange,
78 ) {
79 if rep.cost_or_benefit() < 0 {
80 gum::debug!(target: LOG_TARGET, peer = ?peer_id, ?rep, "Reduce reputation");
81 }
82
83 if (self.send_immediately_if)(rep) {
84 self.single_send(sender, peer_id, rep).await;
85 } else {
86 self.add(peer_id, rep);
87 }
88 }
89
90 async fn single_send(
91 &self,
92 sender: &mut impl overseer::SubsystemSender<NetworkBridgeTxMessage>,
93 peer_id: PeerId,
94 rep: UnifiedReputationChange,
95 ) {
96 sender
97 .send_message(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(
98 peer_id,
99 rep.into(),
100 )))
101 .await;
102 }
103
104 fn add(&mut self, peer_id: PeerId, rep: UnifiedReputationChange) {
105 let by_peer = self.by_peer.get_or_insert(HashMap::new());
106 add_reputation(by_peer, peer_id, rep)
107 }
108}
109
110pub fn add_reputation(
112 acc: &mut BatchReputationChange,
113 peer_id: PeerId,
114 rep: UnifiedReputationChange,
115) {
116 let cost = rep.cost_or_benefit();
117 acc.entry(peer_id).and_modify(|v| *v = v.saturating_add(cost)).or_insert(cost);
118}