diff --git a/substrate/client/finality-grandpa/src/communication/gossip.rs b/substrate/client/finality-grandpa/src/communication/gossip.rs index 9795121882..af08e76157 100644 --- a/substrate/client/finality-grandpa/src/communication/gossip.rs +++ b/substrate/client/finality-grandpa/src/communication/gossip.rs @@ -84,7 +84,7 @@ use sp_runtime::traits::{NumberFor, Block as BlockT, Zero}; use network::consensus_gossip::{self as network_gossip, MessageIntent, ValidatorContext}; -use network::{config::Roles, PeerId}; +use network::{config::Roles, PeerId, ReputationChange}; use codec::{Encode, Decode}; use fg_primitives::AuthorityId; @@ -114,7 +114,7 @@ const ROUND_DURATION: u32 = 4; // measured in gossip durations const MIN_LUCKY: usize = 5; -type Report = (PeerId, i32); +type Report = (PeerId, ReputationChange); /// An outcome of examining a message. #[derive(Debug, PartialEq, Clone, Copy)] @@ -384,14 +384,19 @@ pub(super) enum Misbehavior { } impl Misbehavior { - pub(super) fn cost(&self) -> i32 { + pub(super) fn cost(&self) -> ReputationChange { use Misbehavior::*; match *self { InvalidViewChange => cost::INVALID_VIEW_CHANGE, - UndecodablePacket(bytes) => bytes.saturating_mul(cost::PER_UNDECODABLE_BYTE), - BadCatchUpMessage { signatures_checked } => + UndecodablePacket(bytes) => ReputationChange::new( + bytes.saturating_mul(cost::PER_UNDECODABLE_BYTE), + "Grandpa: Bad packet", + ), + BadCatchUpMessage { signatures_checked } => ReputationChange::new( cost::PER_SIGNATURE_CHECKED.saturating_mul(signatures_checked), + "Grandpa: Bad cath-up message", + ), BadCommitMessage { signatures_checked, blocks_loaded, equivocations_caught } => { let cost = cost::PER_SIGNATURE_CHECKED .saturating_mul(signatures_checked) @@ -399,7 +404,7 @@ impl Misbehavior { let benefit = equivocations_caught.saturating_mul(benefit::PER_EQUIVOCATION); - (benefit as i32).saturating_add(cost as i32) + ReputationChange::new((benefit as i32).saturating_add(cost as i32), "Grandpa: Bad commit") }, FutureMessage => cost::FUTURE_MESSAGE, OutOfScopeMessage => cost::OUT_OF_SCOPE_MESSAGE, @@ -551,11 +556,11 @@ impl Peers { #[derive(Debug, PartialEq)] pub(super) enum Action { // repropagate under given topic, to the given peers, applying cost/benefit to originator. - Keep(H, i32), + Keep(H, ReputationChange), // discard and process. - ProcessAndDiscard(H, i32), + ProcessAndDiscard(H, ReputationChange), // discard, applying cost/benefit to originator. - Discard(i32), + Discard(ReputationChange), } /// State of catch up request handling. @@ -731,7 +736,7 @@ impl Inner { .unwrap_or(Consider::RejectOutOfScope) } - fn cost_past_rejection(&self, _who: &PeerId, _round: Round, _set_id: SetId) -> i32 { + fn cost_past_rejection(&self, _who: &PeerId, _round: Round, _set_id: SetId) -> ReputationChange { // hardcoded for now. cost::PAST_REJECTION } @@ -783,7 +788,6 @@ impl Inner { return Action::Discard(self.cost_past_rejection(who, full.round, full.set_id)), Consider::RejectOutOfScope => return Action::Discard(Misbehavior::OutOfScopeMessage.cost()), Consider::Accept => {}, - } if full.message.precommits.len() != full.message.auth_data.len() || full.message.precommits.is_empty() { @@ -1221,7 +1225,7 @@ impl GossipValidator { self.inner.write().note_catch_up_message_processed(); } - fn report(&self, who: PeerId, cost_benefit: i32) { + fn report(&self, who: PeerId, cost_benefit: ReputationChange) { let _ = self.report_sender.unbounded_send(PeerReport { who, cost_benefit }); } @@ -1443,7 +1447,7 @@ impl network_gossip::Validator for GossipValidator struct PeerReport { who: PeerId, - cost_benefit: i32, + cost_benefit: ReputationChange, } // wrapper around a stream of reports. diff --git a/substrate/client/finality-grandpa/src/communication/mod.rs b/substrate/client/finality-grandpa/src/communication/mod.rs index 8354d41bb0..f705812271 100644 --- a/substrate/client/finality-grandpa/src/communication/mod.rs +++ b/substrate/client/finality-grandpa/src/communication/mod.rs @@ -35,7 +35,7 @@ use futures03::stream::{StreamExt, TryStreamExt}; use grandpa::Message::{Prevote, Precommit, PrimaryPropose}; use grandpa::{voter, voter_set::VoterSet}; use log::{debug, trace}; -use network::{consensus_gossip as network_gossip, NetworkService}; +use network::{consensus_gossip as network_gossip, NetworkService, ReputationChange}; use network_gossip::ConsensusMessage; use codec::{Encode, Decode}; use primitives::Pair; @@ -65,33 +65,35 @@ pub use fg_primitives::GRANDPA_ENGINE_ID; // cost scalars for reporting peers. mod cost { - pub(super) const PAST_REJECTION: i32 = -50; - pub(super) const BAD_SIGNATURE: i32 = -100; - pub(super) const MALFORMED_CATCH_UP: i32 = -1000; - pub(super) const MALFORMED_COMMIT: i32 = -1000; - pub(super) const FUTURE_MESSAGE: i32 = -500; - pub(super) const UNKNOWN_VOTER: i32 = -150; + use network::ReputationChange as Rep; + pub(super) const PAST_REJECTION: Rep = Rep::new(-50, "Grandpa: Past message"); + pub(super) const BAD_SIGNATURE: Rep = Rep::new(-100, "Grandpa: Bad signature"); + pub(super) const MALFORMED_CATCH_UP: Rep = Rep::new(-1000, "Grandpa: Malformed cath-up"); + pub(super) const MALFORMED_COMMIT: Rep = Rep::new(-1000, "Grandpa: Malformed commit"); + pub(super) const FUTURE_MESSAGE: Rep = Rep::new(-500, "Grandpa: Future message"); + pub(super) const UNKNOWN_VOTER: Rep = Rep::new(-150, "Grandpa: Uknown voter"); - pub(super) const INVALID_VIEW_CHANGE: i32 = -500; + pub(super) const INVALID_VIEW_CHANGE: Rep = Rep::new(-500, "Grandpa: Invalid view change"); pub(super) const PER_UNDECODABLE_BYTE: i32 = -5; pub(super) const PER_SIGNATURE_CHECKED: i32 = -25; pub(super) const PER_BLOCK_LOADED: i32 = -10; - pub(super) const INVALID_CATCH_UP: i32 = -5000; - pub(super) const INVALID_COMMIT: i32 = -5000; - pub(super) const OUT_OF_SCOPE_MESSAGE: i32 = -500; - pub(super) const CATCH_UP_REQUEST_TIMEOUT: i32 = -200; + pub(super) const INVALID_CATCH_UP: Rep = Rep::new(-5000, "Grandpa: Invalid catch-up"); + pub(super) const INVALID_COMMIT: Rep = Rep::new(-5000, "Grandpa: Invalid commit"); + pub(super) const OUT_OF_SCOPE_MESSAGE: Rep = Rep::new(-500, "Grandpa: Out-of-scope message"); + pub(super) const CATCH_UP_REQUEST_TIMEOUT: Rep = Rep::new(-200, "Grandpa: Catch-up reqeust timeout"); // cost of answering a catch up request - pub(super) const CATCH_UP_REPLY: i32 = -200; - pub(super) const HONEST_OUT_OF_SCOPE_CATCH_UP: i32 = -200; + pub(super) const CATCH_UP_REPLY: Rep = Rep::new(-200, "Grandpa: Catch-up reply"); + pub(super) const HONEST_OUT_OF_SCOPE_CATCH_UP: Rep = Rep::new(-200, "Grandpa: Out-of-scope catch-up"); } // benefit scalars for reporting peers. mod benefit { - pub(super) const NEIGHBOR_MESSAGE: i32 = 100; - pub(super) const ROUND_MESSAGE: i32 = 100; - pub(super) const BASIC_VALIDATED_CATCH_UP: i32 = 200; - pub(super) const BASIC_VALIDATED_COMMIT: i32 = 100; + use network::ReputationChange as Rep; + pub(super) const NEIGHBOR_MESSAGE: Rep = Rep::new(100, "Grandpa: Neighbor message"); + pub(super) const ROUND_MESSAGE: Rep = Rep::new(100, "Grandpa: Round message"); + pub(super) const BASIC_VALIDATED_CATCH_UP: Rep = Rep::new(200, "Grandpa: Catch-up message"); + pub(super) const BASIC_VALIDATED_COMMIT: Rep = Rep::new(100, "Grandpa: Commit"); pub(super) const PER_EQUIVOCATION: i32 = 10; } @@ -125,7 +127,7 @@ pub trait Network: Clone + Send + 'static { fn send_message(&self, who: Vec, data: Vec); /// Report a peer's cost or benefit after some action. - fn report(&self, who: network::PeerId, cost_benefit: i32); + fn report(&self, who: network::PeerId, cost_benefit: ReputationChange); /// Inform peers that a block with given hash should be downloaded. fn announce(&self, block: Block::Hash, associated_data: Vec); @@ -217,7 +219,7 @@ impl Network for Arc> where }) } - fn report(&self, who: network::PeerId, cost_benefit: i32) { + fn report(&self, who: network::PeerId, cost_benefit: ReputationChange) { self.report_peer(who, cost_benefit) } @@ -803,7 +805,7 @@ fn check_compact_commit( voters: &VoterSet, round: Round, set_id: SetId, -) -> Result<(), i32> { +) -> Result<(), ReputationChange> { // 4f + 1 = equivocations from f voters. let f = voters.total_weight() - voters.threshold(); let full_threshold = voters.total_weight() + f; @@ -862,7 +864,7 @@ fn check_catch_up( msg: &CatchUp, voters: &VoterSet, set_id: SetId, -) -> Result<(), i32> { +) -> Result<(), ReputationChange> { // 4f + 1 = equivocations from f voters. let f = voters.total_weight() - voters.threshold(); let full_threshold = voters.total_weight() + f; @@ -872,7 +874,7 @@ fn check_catch_up( voters: &'a VoterSet, votes: impl Iterator, full_threshold: u64, - ) -> Result<(), i32> { + ) -> Result<(), ReputationChange> { let mut total_weight = 0; for id in votes { @@ -911,7 +913,7 @@ fn check_catch_up( round: RoundNumber, set_id: SetIdNumber, mut signatures_checked: usize, - ) -> Result where + ) -> Result where B: BlockT, I: Iterator, &'a AuthorityId, &'a AuthoritySignature)>, { diff --git a/substrate/client/finality-grandpa/src/communication/tests.rs b/substrate/client/finality-grandpa/src/communication/tests.rs index 2d08ecbde7..b36f8ad3e6 100644 --- a/substrate/client/finality-grandpa/src/communication/tests.rs +++ b/substrate/client/finality-grandpa/src/communication/tests.rs @@ -37,7 +37,7 @@ enum Event { RegisterValidator(Arc>), GossipMessage(Hash, Vec, bool), SendMessage(Vec, Vec), - Report(network::PeerId, i32), + Report(network::PeerId, network::ReputationChange), Announce(Hash), } @@ -85,7 +85,7 @@ impl super::Network for TestNetwork { } /// Report a peer's cost or benefit after some action. - fn report(&self, who: network::PeerId, cost_benefit: i32) { + fn report(&self, who: network::PeerId, cost_benefit: network::ReputationChange) { let _ = self.sender.unbounded_send(Event::Report(who, cost_benefit)); } diff --git a/substrate/client/network/src/legacy_proto/behaviour.rs b/substrate/client/network/src/legacy_proto/behaviour.rs index d1d378174a..f890219158 100644 --- a/substrate/client/network/src/legacy_proto/behaviour.rs +++ b/substrate/client/network/src/legacy_proto/behaviour.rs @@ -940,7 +940,10 @@ where // a different chain, or a node that doesn't speak the same protocol(s). We // decrease the node's reputation, hence lowering the chances we try this node // again in the short term. - self.peerset.report_peer(source.clone(), i32::min_value()); + self.peerset.report_peer( + source.clone(), + peerset::ReputationChange::new(i32::min_value(), "Protocol error") + ); self.disconnect_peer_inner(&source, Some(Duration::from_secs(5))); } } diff --git a/substrate/client/network/src/lib.rs b/substrate/client/network/src/lib.rs index 9b25992dd9..1816a21f97 100644 --- a/substrate/client/network/src/lib.rs +++ b/substrate/client/network/src/lib.rs @@ -199,6 +199,7 @@ pub use libp2p::multiaddr; pub use message::{generic as generic_message, RequestId, Status as StatusMessage}; pub use on_demand_layer::{OnDemand, RemoteResponse}; +pub use peerset::ReputationChange; // Used by the `construct_simple_protocol!` macro. #[doc(hidden)] diff --git a/substrate/client/network/src/protocol.rs b/substrate/client/network/src/protocol.rs index 6b9c0755c0..c8a4fadbff 100644 --- a/substrate/client/network/src/protocol.rs +++ b/substrate/client/network/src/protocol.rs @@ -88,23 +88,38 @@ const MAX_CONSENSUS_MESSAGES: usize = 256; /// and disconnect to free connection slot. const LIGHT_MAXIMAL_BLOCKS_DIFFERENCE: u64 = 8192; -/// Reputation change when a peer is "clogged", meaning that it's not fast enough to process our -/// messages. -const CLOGGED_PEER_REPUTATION_CHANGE: i32 = -(1 << 12); -/// Reputation change when a peer doesn't respond in time to our messages. -const TIMEOUT_REPUTATION_CHANGE: i32 = -(1 << 10); -/// Reputation change when a peer sends us a status message while we already received one. -const UNEXPECTED_STATUS_REPUTATION_CHANGE: i32 = -(1 << 20); -/// Reputation change when we are a light client and a peer is behind us. -const PEER_BEHIND_US_LIGHT_REPUTATION_CHANGE: i32 = -(1 << 8); -/// Reputation change when a peer sends us an extrinsic that we didn't know about. -const GOOD_EXTRINSIC_REPUTATION_CHANGE: i32 = 1 << 7; -/// Reputation change when a peer sends us a bad extrinsic. -const BAD_EXTRINSIC_REPUTATION_CHANGE: i32 = -(1 << 12); -/// We sent an RPC query to the given node, but it failed. -const RPC_FAILED_REPUTATION_CHANGE: i32 = -(1 << 12); -/// We received a message that failed to decode. -const BAD_MESSAGE_REPUTATION_CHANGE: i32 = -(1 << 12); +mod rep { + use peerset::ReputationChange as Rep; + /// Reputation change when a peer is "clogged", meaning that it's not fast enough to process our + /// messages. + pub const CLOGGED_PEER: Rep = Rep::new(-(1 << 12), "Clogged message queue"); + /// Reputation change when a peer doesn't respond in time to our messages. + pub const TIMEOUT: Rep = Rep::new(-(1 << 10), "Request timeout"); + /// Reputation change when a peer sends us a status message while we already received one. + pub const UNEXPECTED_STATUS: Rep = Rep::new(-(1 << 20), "Unexpected status message"); + /// Reputation change when we are a light client and a peer is behind us. + pub const PEER_BEHIND_US_LIGHT: Rep = Rep::new(-(1 << 8), "Useless for a light peer"); + /// Reputation change when a peer sends us an extrinsic that we didn't know about. + pub const GOOD_EXTRINSIC: Rep = Rep::new(1 << 7, "Good extrinsic"); + /// Reputation change when a peer sends us a bad extrinsic. + pub const BAD_EXTRINSIC: Rep = Rep::new(-(1 << 12), "Bad extrinsic"); + /// We sent an RPC query to the given node, but it failed. + pub const RPC_FAILED: Rep = Rep::new(-(1 << 12), "Remote call failed"); + /// We received a message that failed to decode. + pub const BAD_MESSAGE: Rep = Rep::new(-(1 << 12), "Bad message"); + /// We received an unexpected response. + pub const UNEXPECTED_RESPONSE: Rep = Rep::new_fatal("Unexpected response packet"); + /// We received an unexpected extrinsic packet. + pub const UNEXPECTED_EXTRINSICS: Rep = Rep::new_fatal("Unexpected extrinsics packet"); + /// We received an unexpected light node request. + pub const UNEXPECTED_REQUEST: Rep = Rep::new_fatal("Unexpected block request packet"); + /// Peer has different genesis. + pub const GENESIS_MISMATCH: Rep = Rep::new_fatal("Genesis mismatch"); + /// Peer is on unsupported protocol version. + pub const BAD_PROTOCOL: Rep = Rep::new_fatal("Unsupported protocol"); + /// Peer role does not match (e.g. light peer connecting to another light peer). + pub const BAD_ROLE: Rep = Rep::new_fatal("Unsupported role"); +} // Lock must always be taken in order declared here. pub struct Protocol, H: ExHashT> { @@ -183,7 +198,7 @@ struct LightDispatchIn<'a> { } impl<'a, B: BlockT> LightDispatchNetwork for LightDispatchIn<'a> { - fn report_peer(&mut self, who: &PeerId, reputation: i32) { + fn report_peer(&mut self, who: &PeerId, reputation: peerset::ReputationChange) { self.peerset.report_peer(who.clone(), reputation) } @@ -303,7 +318,7 @@ impl<'a, B: BlockT> LightDispatchNetwork for LightDispatchIn<'a> { pub trait Context { /// Adjusts the reputation of the peer. Use this to point out that a peer has been malign or /// irresponsible or appeared lazy. - fn report_peer(&mut self, who: PeerId, reputation: i32); + fn report_peer(&mut self, who: PeerId, reputation: peerset::ReputationChange); /// Force disconnecting from a peer. Use this when a peer misbehaved. fn disconnect_peer(&mut self, who: PeerId); @@ -333,7 +348,7 @@ impl<'a, B: BlockT + 'a, H: 'a + ExHashT> ProtocolContext<'a, B, H> { } impl<'a, B: BlockT + 'a, H: ExHashT + 'a> Context for ProtocolContext<'a, B, H> { - fn report_peer(&mut self, who: PeerId, reputation: i32) { + fn report_peer(&mut self, who: PeerId, reputation: peerset::ReputationChange) { self.peerset_handle.report_peer(who, reputation) } @@ -557,7 +572,7 @@ impl, H: ExHashT> Protocol { return request.map(|(_, r)| r) } trace!(target: "sync", "Unexpected response packet from {} ({})", who, response.id); - self.peerset_handle.report_peer(who.clone(), i32::min_value()); + self.peerset_handle.report_peer(who.clone(), rep::UNEXPECTED_RESPONSE); self.behaviour.disconnect_peer(&who); } None @@ -587,7 +602,7 @@ impl, H: ExHashT> Protocol { Ok(message) => message, Err(err) => { debug!(target: "sync", "Couldn't decode packet sent by {}: {:?}: {}", who, data, err.what()); - self.peerset_handle.report_peer(who.clone(), BAD_MESSAGE_REPUTATION_CHANGE); + self.peerset_handle.report_peer(who.clone(), rep::BAD_MESSAGE); return CustomMessageOutcome::None; } }; @@ -755,7 +770,7 @@ impl, H: ExHashT> Protocol { /// Called as a back-pressure mechanism if the networking detects that the peer cannot process /// our messaging rate fast enough. pub fn on_clogged_peer(&self, who: PeerId, _msg: Option>) { - self.peerset_handle.report_peer(who.clone(), CLOGGED_PEER_REPUTATION_CHANGE); + self.peerset_handle.report_peer(who.clone(), rep::CLOGGED_PEER); // Print some diagnostics. if let Some(peer) = self.context_data.peers.get(&who) { @@ -784,7 +799,7 @@ impl, H: ExHashT> Protocol { if !self.config.roles.is_full() { trace!(target: "sync", "Peer {} is trying to sync from the light node", peer); self.behaviour.disconnect_peer(&peer); - self.peerset_handle.report_peer(peer, i32::min_value()); + self.peerset_handle.report_peer(peer, rep::UNEXPECTED_REQUEST); return; } @@ -846,7 +861,7 @@ impl, H: ExHashT> Protocol { } /// Adjusts the reputation of a node. - pub fn report_peer(&self, who: PeerId, reputation: i32) { + pub fn report_peer(&self, who: PeerId, reputation: peerset::ReputationChange) { self.peerset_handle.report_peer(who, reputation) } @@ -953,7 +968,7 @@ impl, H: ExHashT> Protocol { ); for p in aborting { self.behaviour.disconnect_peer(&p); - self.peerset_handle.report_peer(p, TIMEOUT_REPUTATION_CHANGE); + self.peerset_handle.report_peer(p, rep::TIMEOUT); } } @@ -967,7 +982,7 @@ impl, H: ExHashT> Protocol { if self.important_peers.contains(&who) { Level::Warn } else { Level::Debug }, "Unexpected status packet from {}", who ); - self.peerset_handle.report_peer(who, UNEXPECTED_STATUS_REPUTATION_CHANGE); + self.peerset_handle.report_peer(who, rep::UNEXPECTED_STATUS); return; } if status.genesis_hash != self.genesis_hash { @@ -977,7 +992,7 @@ impl, H: ExHashT> Protocol { "Peer is on different chain (our genesis: {} theirs: {})", self.genesis_hash, status.genesis_hash ); - self.peerset_handle.report_peer(who.clone(), i32::min_value()); + self.peerset_handle.report_peer(who.clone(), rep::GENESIS_MISMATCH); self.behaviour.disconnect_peer(&who); return; } @@ -987,7 +1002,7 @@ impl, H: ExHashT> Protocol { if self.important_peers.contains(&who) { Level::Warn } else { Level::Trace }, "Peer {:?} using unsupported protocol version {}", who, status.version ); - self.peerset_handle.report_peer(who.clone(), i32::min_value()); + self.peerset_handle.report_peer(who.clone(), rep::BAD_PROTOCOL); self.behaviour.disconnect_peer(&who); return; } @@ -996,7 +1011,7 @@ impl, H: ExHashT> Protocol { // we're not interested in light peers if status.roles.is_light() { debug!(target: "sync", "Peer {} is unable to serve light requests", who); - self.peerset_handle.report_peer(who.clone(), i32::min_value()); + self.peerset_handle.report_peer(who.clone(), rep::BAD_ROLE); self.behaviour.disconnect_peer(&who); return; } @@ -1013,7 +1028,7 @@ impl, H: ExHashT> Protocol { .saturated_into::(); if blocks_difference > LIGHT_MAXIMAL_BLOCKS_DIFFERENCE { debug!(target: "sync", "Peer {} is far behind us and will unable to serve light requests", who); - self.peerset_handle.report_peer(who.clone(), PEER_BEHIND_US_LIGHT_REPUTATION_CHANGE); + self.peerset_handle.report_peer(who.clone(), rep::PEER_BEHIND_US_LIGHT); self.behaviour.disconnect_peer(&who); return; } @@ -1082,7 +1097,7 @@ impl, H: ExHashT> Protocol { if !self.config.roles.is_full() { trace!(target: "sync", "Peer {} is trying to send extrinsic to the light node", who); self.behaviour.disconnect_peer(&who); - self.peerset_handle.report_peer(who, i32::min_value()); + self.peerset_handle.report_peer(who, rep::UNEXPECTED_EXTRINSICS); return; } @@ -1100,8 +1115,8 @@ impl, H: ExHashT> Protocol { self.transaction_pool.import( self.peerset_handle.clone().into(), who.clone(), - GOOD_EXTRINSIC_REPUTATION_CHANGE, - BAD_EXTRINSIC_REPUTATION_CHANGE, + rep::GOOD_EXTRINSIC, + rep::BAD_EXTRINSIC, t, ); } @@ -1351,7 +1366,7 @@ impl, H: ExHashT> Protocol { request.block, error ); - self.peerset_handle.report_peer(who.clone(), RPC_FAILED_REPUTATION_CHANGE); + self.peerset_handle.report_peer(who.clone(), rep::RPC_FAILED); StorageProof::empty() } }; @@ -1679,7 +1694,7 @@ impl, H: ExHashT> Protocol { None }, }; - self.send_message( + self.send_message( &who, GenericMessage::FinalityProofResponse(message::FinalityProofResponse { id: 0, diff --git a/substrate/client/network/src/protocol/consensus_gossip.rs b/substrate/client/network/src/protocol/consensus_gossip.rs index 3062047952..24561debef 100644 --- a/substrate/client/network/src/protocol/consensus_gossip.rs +++ b/substrate/client/network/src/protocol/consensus_gossip.rs @@ -61,15 +61,19 @@ use crate::config::Roles; const KNOWN_MESSAGES_CACHE_SIZE: usize = 4096; const REBROADCAST_INTERVAL: time::Duration = time::Duration::from_secs(30); -/// Reputation change when a peer sends us a gossip message that we didn't know about. -const GOSSIP_SUCCESS_REPUTATION_CHANGE: i32 = 1 << 4; -/// Reputation change when a peer sends us a gossip message that we already knew about. -const DUPLICATE_GOSSIP_REPUTATION_CHANGE: i32 = -(1 << 2); -/// Reputation change when a peer sends us a gossip message for an unknown engine, whatever that -/// means. -const UNKNOWN_GOSSIP_REPUTATION_CHANGE: i32 = -(1 << 6); -/// Reputation change when a peer sends a message from a topic it isn't registered on. -const UNREGISTERED_TOPIC_REPUTATION_CHANGE: i32 = -(1 << 10); + +mod rep { + use peerset::ReputationChange as Rep; + /// Reputation change when a peer sends us a gossip message that we didn't know about. + pub const GOSSIP_SUCCESS: Rep = Rep::new(1 << 4, "Successfull gossip"); + /// Reputation change when a peer sends us a gossip message that we already knew about. + pub const DUPLICATE_GOSSIP: Rep = Rep::new(-(1 << 2), "Duplicate gossip"); + /// Reputation change when a peer sends us a gossip message for an unknown engine, whatever that + /// means. + pub const UNKNOWN_GOSSIP: Rep = Rep::new(-(1 << 6), "Unknown gossup message engine id"); + /// Reputation change when a peer sends a message from a topic it isn't registered on. + pub const UNREGISTERED_TOPIC: Rep = Rep::new(-(1 << 10), "Unregistered gossip message topic"); +} struct PeerConsensus { known_messages: HashSet, @@ -470,7 +474,7 @@ impl ConsensusGossip { if self.known_messages.contains(&message_hash) { trace!(target:"gossip", "Ignored already known message from {}", who); - protocol.report_peer(who.clone(), DUPLICATE_GOSSIP_REPUTATION_CHANGE); + protocol.report_peer(who.clone(), rep::DUPLICATE_GOSSIP); continue; } @@ -489,14 +493,14 @@ impl ConsensusGossip { Some(ValidationResult::Discard) => None, None => { trace!(target:"gossip", "Unknown message engine id {:?} from {}", engine_id, who); - protocol.report_peer(who.clone(), UNKNOWN_GOSSIP_REPUTATION_CHANGE); + protocol.report_peer(who.clone(), rep::UNKNOWN_GOSSIP); protocol.disconnect_peer(who.clone()); continue; } }; if let Some((topic, keep)) = validation_result { - protocol.report_peer(who.clone(), GOSSIP_SUCCESS_REPUTATION_CHANGE); + protocol.report_peer(who.clone(), rep::GOSSIP_SUCCESS); if let Some(ref mut peer) = self.peers.get_mut(&who) { peer.known_messages.insert(message_hash); if let Entry::Occupied(mut entry) = self.live_message_sinks.entry((engine_id, topic)) { @@ -519,7 +523,7 @@ impl ConsensusGossip { } } else { trace!(target:"gossip", "Ignored statement from unregistered peer {}", who); - protocol.report_peer(who.clone(), UNREGISTERED_TOPIC_REPUTATION_CHANGE); + protocol.report_peer(who.clone(), rep::UNREGISTERED_TOPIC); } } else { trace!(target:"gossip", "Handled valid one hop message from peer {}", who); diff --git a/substrate/client/network/src/protocol/light_dispatch.rs b/substrate/client/network/src/protocol/light_dispatch.rs index 7d37b49b6c..ef240cbf06 100644 --- a/substrate/client/network/src/protocol/light_dispatch.rs +++ b/substrate/client/network/src/protocol/light_dispatch.rs @@ -33,6 +33,7 @@ use crate::message::{self, BlockAttributes, Direction, FromBlock, RequestId}; use libp2p::PeerId; use crate::config::Roles; use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; +use peerset::ReputationChange; /// Remote request timeout. const REQUEST_TIMEOUT: Duration = Duration::from_secs(15); @@ -44,7 +45,7 @@ const TIMEOUT_REPUTATION_CHANGE: i32 = -(1 << 8); /// Trait used by the `LightDispatch` service to communicate messages back to the network. pub trait LightDispatchNetwork { /// Adjusts the reputation of the given peer. - fn report_peer(&mut self, who: &PeerId, reputation_change: i32); + fn report_peer(&mut self, who: &PeerId, reputation_change: ReputationChange); /// Disconnect from the given peer. Used in case of misbehaviour. fn disconnect_peer(&mut self, who: &PeerId); @@ -267,7 +268,7 @@ impl LightDispatch where Some(request) => request, None => { info!("Invalid remote {} response from peer {}", rtype, peer); - network.report_peer(&peer, i32::min_value()); + network.report_peer(&peer, ReputationChange::new_fatal("Invalid remote response")); network.disconnect_peer(&peer); self.remove_peer(peer); return; @@ -279,7 +280,7 @@ impl LightDispatch where Accept::Ok => (retry_count, None), Accept::CheckFailed(error, retry_request_data) => { info!("Failed to check remote {} response from peer {}: {}", rtype, peer, error); - network.report_peer(&peer, i32::min_value()); + network.report_peer(&peer, ReputationChange::new_fatal("Failed remote response check")); network.disconnect_peer(&peer); self.remove_peer(peer); @@ -293,7 +294,7 @@ impl LightDispatch where }, Accept::Unexpected(retry_request_data) => { info!("Unexpected response to remote {} from peer", rtype); - network.report_peer(&peer, i32::min_value()); + network.report_peer(&peer, ReputationChange::new_fatal("Unexpected remote response")); network.disconnect_peer(&peer); self.remove_peer(peer); @@ -350,7 +351,7 @@ impl LightDispatch where let (bad_peer, request) = self.active_peers.pop_front().expect("front() is Some as checked above"); self.pending_requests.push_front(request); - network.report_peer(&bad_peer, TIMEOUT_REPUTATION_CHANGE); + network.report_peer(&bad_peer, ReputationChange::new(TIMEOUT_REPUTATION_CHANGE, "Light request timeout")); network.disconnect_peer(&bad_peer); } @@ -800,7 +801,7 @@ pub mod tests { } impl<'a, B: BlockT> LightDispatchNetwork for &'a mut DummyNetwork { - fn report_peer(&mut self, _: &PeerId, _: i32) {} + fn report_peer(&mut self, _: &PeerId, _: crate::ReputationChange) {} fn disconnect_peer(&mut self, who: &PeerId) { self.disconnected_peers.insert(who.clone()); } diff --git a/substrate/client/network/src/protocol/sync.rs b/substrate/client/network/src/protocol/sync.rs index 01f36bd4da..ca332d46f1 100644 --- a/substrate/client/network/src/protocol/sync.rs +++ b/substrate/client/network/src/protocol/sync.rs @@ -72,29 +72,34 @@ const MAJOR_SYNC_BLOCKS: u8 = 5; /// Number of recently announced blocks to track for each peer. const ANNOUNCE_HISTORY_SIZE: usize = 64; -/// Reputation change when a peer sent us a status message that led to a -/// database read error. -const BLOCKCHAIN_STATUS_READ_ERROR_REPUTATION_CHANGE: i32 = -(1 << 16); +mod rep { + use peerset::ReputationChange as Rep; + /// Reputation change when a peer sent us a message that led to a + /// database read error. + pub const BLOCKCHAIN_READ_ERROR: Rep = Rep::new(-(1 << 16), "DB Error"); -/// Reputation change when a peer failed to answer our legitimate ancestry -/// block search. -const ANCESTRY_BLOCK_ERROR_REPUTATION_CHANGE: i32 = -(1 << 9); + /// Reputation change when a peer sent us a status message with a different + /// genesis than us. + pub const GENESIS_MISMATCH: Rep = Rep::new(i32::min_value(), "Genesis mismatch"); -/// Reputation change when a peer sent us a status message with a different -/// genesis than us. -const GENESIS_MISMATCH_REPUTATION_CHANGE: i32 = i32::min_value() + 1; + /// Reputation change for peers which send us a block with an incomplete header. + pub const INCOMPLETE_HEADER: Rep = Rep::new(-(1 << 20), "Incomplete header"); -/// Reputation change for peers which send us a block with an incomplete header. -const INCOMPLETE_HEADER_REPUTATION_CHANGE: i32 = -(1 << 20); + /// Reputation change for peers which send us a block which we fail to verify. + pub const VERIFICATION_FAIL: Rep = Rep::new(-(1 << 20), "Block verification failed"); -/// Reputation change for peers which send us a block which we fail to verify. -const VERIFICATION_FAIL_REPUTATION_CHANGE: i32 = -(1 << 20); + /// Reputation change for peers which send us a known bad block. + pub const BAD_BLOCK: Rep = Rep::new(-(1 << 29), "Bad block"); -/// Reputation change for peers which send us a bad block. -const BAD_BLOCK_REPUTATION_CHANGE: i32 = -(1 << 29); + /// Reputation change for peers which send us a block with bad justifications. + pub const BAD_JUSTIFICATION: Rep = Rep::new(-(1 << 16), "Bad justification"); -/// Reputation change for peers which send us a block with bad justifications. -const BAD_JUSTIFICATION_REPUTATION_CHANGE: i32 = -(1 << 16); + /// Reputation change for peers which send us a block with bad finality proof. + pub const BAD_FINALITY_PROOF: Rep = Rep::new(-(1 << 16), "Bad finality proof"); + + /// Reputation change when a peer sent us invlid ancestry result. + pub const UNKNOWN_ANCESTOR:Rep = Rep::new(-(1 << 16), "DB Error"); +} /// The main data structure which contains all the state for a chains /// active syncing strategy. @@ -225,11 +230,11 @@ pub struct Status { /// A peer did not behave as expected and should be reported. #[derive(Debug, Clone, PartialEq, Eq)] -pub struct BadPeer(pub PeerId, pub i32); +pub struct BadPeer(pub PeerId, pub peerset::ReputationChange); impl fmt::Display for BadPeer { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "bad peer {}; reputation change: {}", self.0, self.1) + write!(f, "Bad peer {}; Reputation change: {:?}", self.0, self.1) } } @@ -358,16 +363,16 @@ impl ChainSync { match self.block_status(&best_hash) { Err(e) => { debug!(target:"sync", "Error reading blockchain: {:?}", e); - Err(BadPeer(who, BLOCKCHAIN_STATUS_READ_ERROR_REPUTATION_CHANGE)) + Err(BadPeer(who, rep::BLOCKCHAIN_READ_ERROR)) } Ok(BlockStatus::KnownBad) => { info!("New peer with known bad best block {} ({}).", best_hash, best_number); - Err(BadPeer(who, i32::min_value())) + Err(BadPeer(who, rep::BAD_BLOCK)) } Ok(BlockStatus::Unknown) => { if best_number.is_zero() { info!("New peer with unknown genesis hash {} ({}).", best_hash, best_number); - return Err(BadPeer(who, i32::min_value())) + return Err(BadPeer(who, rep::GENESIS_MISMATCH)); } // If there are more than `MAJOR_SYNC_BLOCKS` in the import queue then we have // enough to do in the import queue that it's not worth kicking off @@ -688,11 +693,11 @@ impl ChainSync { }, (None, _) => { debug!(target: "sync", "Invalid response when searching for ancestor from {}", who); - return Err(BadPeer(who, i32::min_value())) + return Err(BadPeer(who, rep::UNKNOWN_ANCESTOR)) }, (_, Err(e)) => { info!("Error answering legitimate blockchain query: {:?}", e); - return Err(BadPeer(who, ANCESTRY_BLOCK_ERROR_REPUTATION_CHANGE)) + return Err(BadPeer(who, rep::BLOCKCHAIN_READ_ERROR)) } }; if matching_hash.is_some() && peer.common_number < *num { @@ -700,7 +705,7 @@ impl ChainSync { } if matching_hash.is_none() && num.is_zero() { trace!(target:"sync", "Ancestry search: genesis mismatch for peer {}", who); - return Err(BadPeer(who, GENESIS_MISMATCH_REPUTATION_CHANGE)) + return Err(BadPeer(who, rep::GENESIS_MISMATCH)) } if let Some((next_state, next_num)) = handle_ancestor_search_state(state, *num, matching_hash.is_some()) { peer.state = PeerSyncState::AncestorSearch(next_num, next_state); @@ -790,9 +795,10 @@ impl ChainSync { if let Some(block) = response.blocks.into_iter().next() { if hash != block.hash { info!( + target: "sync", "Invalid block justification provided by {}: requested: {:?} got: {:?}", who, hash, block.hash ); - return Err(BadPeer(who, i32::min_value())) + return Err(BadPeer(who, rep::BAD_JUSTIFICATION)); } if let Some((peer, hash, number, j)) = self.extra_justifications.on_response(who, block.justification) { return Ok(OnBlockJustification::Import { peer, hash, number, justification: j }) @@ -825,8 +831,13 @@ impl ChainSync { // We only request one finality proof at a time. if hash != resp.block { - info!("Invalid block finality proof provided: requested: {:?} got: {:?}", hash, resp.block); - return Err(BadPeer(who, i32::min_value())) + info!( + target: "sync", + "Invalid block finality proof provided: requested: {:?} got: {:?}", + hash, + resp.block + ); + return Err(BadPeer(who, rep::BAD_FINALITY_PROOF)); } if let Some((peer, hash, number, p)) = self.extra_finality_proofs.on_response(who, resp.proof) { @@ -887,7 +898,7 @@ impl ChainSync { if aux.bad_justification { if let Some(peer) = who { info!("Sent block with bad justification to import"); - output.push(Err(BadPeer(peer, BAD_JUSTIFICATION_REPUTATION_CHANGE))); + output.push(Err(BadPeer(peer, rep::BAD_JUSTIFICATION))); } } @@ -903,21 +914,21 @@ impl ChainSync { Err(BlockImportError::IncompleteHeader(who)) => { if let Some(peer) = who { info!("Peer sent block with incomplete header to import"); - output.push(Err(BadPeer(peer, INCOMPLETE_HEADER_REPUTATION_CHANGE))); + output.push(Err(BadPeer(peer, rep::INCOMPLETE_HEADER))); output.extend(self.restart()); } }, Err(BlockImportError::VerificationFailed(who, e)) => { if let Some(peer) = who { info!("Verification failed from peer: {}", e); - output.push(Err(BadPeer(peer, VERIFICATION_FAIL_REPUTATION_CHANGE))); + output.push(Err(BadPeer(peer, rep::VERIFICATION_FAIL))); output.extend(self.restart()); } }, Err(BlockImportError::BadBlock(who)) => { if let Some(peer) = who { info!("Bad block"); - output.push(Err(BadPeer(peer, BAD_BLOCK_REPUTATION_CHANGE))); + output.push(Err(BadPeer(peer, rep::BAD_BLOCK))); output.extend(self.restart()); } }, diff --git a/substrate/client/network/src/service.rs b/substrate/client/network/src/service.rs index 4a60c3def7..85fd1c3ff5 100644 --- a/substrate/client/network/src/service.rs +++ b/substrate/client/network/src/service.rs @@ -42,7 +42,7 @@ use sp_runtime::{traits::{Block as BlockT, NumberFor}, ConsensusEngineId}; use crate::{behaviour::{Behaviour, BehaviourOut}, config::{parse_str_addr, parse_addr}}; use crate::{NetworkState, NetworkStateNotConnectedPeer, NetworkStatePeer}; -use crate::{transport, config::NonReservedPeerMode}; +use crate::{transport, config::NonReservedPeerMode, ReputationChange}; use crate::config::{Params, TransportConfig}; use crate::error::Error; use crate::protocol::{self, Protocol, Context, CustomMessageOutcome, PeerInfo}; @@ -71,8 +71,8 @@ pub trait TransactionPool: Send + Sync { &self, report_handle: ReportHandle, who: PeerId, - reputation_change_good: i32, - reputation_change_bad: i32, + reputation_change_good: ReputationChange, + reputation_change_bad: ReputationChange, transaction: B::Extrinsic, ); /// Notify the pool about transactions broadcast. @@ -94,7 +94,7 @@ impl From for ReportHandle { impl ReportHandle { /// Report a given peer as either beneficial (+) or costly (-) according to the /// given scalar. - pub fn report_peer(&self, who: PeerId, cost_benefit: i32) { + pub fn report_peer(&self, who: PeerId, cost_benefit: ReputationChange) { self.inner.report_peer(who, cost_benefit); } } @@ -449,7 +449,7 @@ impl, H: ExHashT> NetworkServic /// Report a given peer as either beneficial (+) or costly (-) according to the /// given scalar. - pub fn report_peer(&self, who: PeerId, cost_benefit: i32) { + pub fn report_peer(&self, who: PeerId, cost_benefit: ReputationChange) { self.peerset.report_peer(who, cost_benefit); } @@ -786,7 +786,7 @@ impl<'a, B: BlockT, S: NetworkSpecialization, H: ExHashT> Link for Network if !success { info!("Invalid justification provided by {} for #{}", who, hash); self.protocol.user_protocol_mut().disconnect_peer(&who); - self.protocol.user_protocol_mut().report_peer(who, i32::min_value()); + self.protocol.user_protocol_mut().report_peer(who, ReputationChange::new_fatal("Invalid justification")); } } fn request_justification(&mut self, hash: &B::Hash, number: NumberFor) { @@ -806,7 +806,7 @@ impl<'a, B: BlockT, S: NetworkSpecialization, H: ExHashT> Link for Network if !success { info!("Invalid finality proof provided by {} for #{}", who, request_block.0); self.protocol.user_protocol_mut().disconnect_peer(&who); - self.protocol.user_protocol_mut().report_peer(who, i32::min_value()); + self.protocol.user_protocol_mut().report_peer(who, ReputationChange::new_fatal("Invalid finality proof")); } } } diff --git a/substrate/client/network/src/test/mod.rs b/substrate/client/network/src/test/mod.rs index d0cac918e7..f016ef99d8 100644 --- a/substrate/client/network/src/test/mod.rs +++ b/substrate/client/network/src/test/mod.rs @@ -401,8 +401,8 @@ impl TransactionPool for EmptyTransactionPool { &self, _report_handle: ReportHandle, _who: PeerId, - _rep_change_good: i32, - _rep_change_bad: i32, + _rep_change_good: crate::ReputationChange, + _rep_change_bad: crate::ReputationChange, _transaction: Extrinsic ) {} diff --git a/substrate/client/peerset/src/lib.rs b/substrate/client/peerset/src/lib.rs index a243fd00bd..ab7942f60d 100644 --- a/substrate/client/peerset/src/lib.rs +++ b/substrate/client/peerset/src/lib.rs @@ -38,12 +38,33 @@ enum Action { AddReservedPeer(PeerId), RemoveReservedPeer(PeerId), SetReservedOnly(bool), - ReportPeer(PeerId, i32), + ReportPeer(PeerId, ReputationChange), SetPriorityGroup(String, HashSet), AddToPriorityGroup(String, PeerId), RemoveFromPriorityGroup(String, PeerId), } +/// Shared handle to the peer set manager (PSM). Distributed around the code. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ReputationChange { + /// Reputation delta. + pub value: i32, + /// Reason for reputation change. + pub reason: &'static str, +} + +impl ReputationChange { + /// New reputation change with given delta and reason. + pub const fn new(value: i32, reason: &'static str) -> ReputationChange { + ReputationChange { value, reason } + } + + /// New reputation change that forces minimum possible reputation. + pub const fn new_fatal(reason: &'static str) -> ReputationChange { + ReputationChange { value: i32::min_value(), reason } + } +} + /// Shared handle to the peer set manager (PSM). Distributed around the code. #[derive(Debug, Clone)] pub struct PeersetHandle { @@ -75,7 +96,7 @@ impl PeersetHandle { } /// Reports an adjustment to the reputation of the given peer. - pub fn report_peer(&self, peer_id: PeerId, score_diff: i32) { + pub fn report_peer(&self, peer_id: PeerId, score_diff: ReputationChange) { let _ = self.tx.unbounded_send(Action::ReportPeer(peer_id, score_diff)); } @@ -258,20 +279,27 @@ impl Peerset { self.alloc_slots(); } - fn on_report_peer(&mut self, peer_id: PeerId, score_diff: i32) { + fn on_report_peer(&mut self, peer_id: PeerId, change: ReputationChange) { // We want reputations to be up-to-date before adjusting them. self.update_time(); match self.data.peer(&peer_id) { peersstate::Peer::Connected(mut peer) => { - peer.add_reputation(score_diff); + peer.add_reputation(change.value); if peer.reputation() < BANNED_THRESHOLD { + debug!(target: "peerset", "Report {}: {:+} to {}. Reason: {}, Disconnecting", + peer_id, change.value, peer.reputation(), change.reason + ); peer.disconnect(); self.message_queue.push_back(Message::Drop(peer_id)); + } else { + trace!(target: "peerset", "Report {}: {:+} to {}. Reason: {}", + peer_id, change.value, peer.reputation(), change.reason + ); } }, - peersstate::Peer::NotConnected(mut peer) => peer.add_reputation(score_diff), - peersstate::Peer::Unknown(peer) => peer.discover().add_reputation(score_diff), + peersstate::Peer::NotConnected(mut peer) => peer.add_reputation(change.value), + peersstate::Peer::Unknown(peer) => peer.discover().add_reputation(change.value), } } @@ -293,7 +321,7 @@ impl Peerset { // takes `ln(0.5) / ln(k)` seconds to reduce the reputation by half. Use this formula to // empirically determine a value of `k` that looks correct. for _ in 0..secs_diff { - for peer in self.data.peers().cloned().collect::>() { + for peer_id in self.data.peers().cloned().collect::>() { // We use `k = 0.98`, so we divide by `50`. With that value, it takes 34.3 seconds // to reduce the reputation by half. fn reput_tick(reput: i32) -> i32 { @@ -305,13 +333,21 @@ impl Peerset { } reput.saturating_sub(diff) } - match self.data.peer(&peer) { - peersstate::Peer::Connected(mut peer) => - peer.set_reputation(reput_tick(peer.reputation())), - peersstate::Peer::NotConnected(mut peer) => - peer.set_reputation(reput_tick(peer.reputation())), + match self.data.peer(&peer_id) { + peersstate::Peer::Connected(mut peer) => { + let before = peer.reputation(); + let after = reput_tick(before); + trace!(target: "peerset", "Fleeting {}: {} -> {}", peer_id, before, after); + peer.set_reputation(after) + } + peersstate::Peer::NotConnected(mut peer) => { + let before = peer.reputation(); + let after = reput_tick(before); + trace!(target: "peerset", "Fleeting {}: {} -> {}", peer_id, before, after); + peer.set_reputation(after) + } peersstate::Peer::Unknown(_) => unreachable!("We iterate over known peers; qed") - } + }; } } } @@ -432,7 +468,7 @@ impl Peerset { } /// Reports an adjustment to the reputation of the given peer. - pub fn report_peer(&mut self, peer_id: PeerId, score_diff: i32) { + pub fn report_peer(&mut self, peer_id: PeerId, score_diff: ReputationChange) { // We don't immediately perform the adjustments in order to have state consistency. We // don't want the reporting here to take priority over messages sent using the // `PeersetHandle`. @@ -510,7 +546,7 @@ impl Stream for Peerset { mod tests { use libp2p::PeerId; use futures::prelude::*; - use super::{PeersetConfig, Peerset, Message, IncomingIndex, BANNED_THRESHOLD}; + use super::{PeersetConfig, Peerset, Message, IncomingIndex, ReputationChange, BANNED_THRESHOLD}; use std::{pin::Pin, task::Poll, thread, time::Duration}; fn assert_messages(mut peerset: Peerset, messages: Vec) -> Peerset { @@ -620,7 +656,7 @@ mod tests { // We ban a node by setting its reputation under the threshold. let peer_id = PeerId::random(); - handle.report_peer(peer_id.clone(), BANNED_THRESHOLD - 1); + handle.report_peer(peer_id.clone(), ReputationChange::new(BANNED_THRESHOLD - 1, "")); let fut = futures::future::poll_fn(move |cx| { // We need one polling for the message to be processed. diff --git a/substrate/client/peerset/tests/fuzz.rs b/substrate/client/peerset/tests/fuzz.rs index 604bbcc831..55d8fabbad 100644 --- a/substrate/client/peerset/tests/fuzz.rs +++ b/substrate/client/peerset/tests/fuzz.rs @@ -19,7 +19,7 @@ use libp2p::PeerId; use rand::distributions::{Distribution, Uniform, WeightedIndex}; use rand::seq::IteratorRandom; use std::{collections::HashMap, collections::HashSet, iter, pin::Pin, task::Poll}; -use sc_peerset::{IncomingIndex, Message, PeersetConfig, Peerset}; +use sc_peerset::{IncomingIndex, Message, PeersetConfig, Peerset, ReputationChange}; #[test] fn run() { @@ -97,7 +97,7 @@ fn test_once() { // If we generate 2, adjust a random reputation. 2 => if let Some(id) = known_nodes.iter().choose(&mut rng) { let val = Uniform::new_inclusive(i32::min_value(), i32::max_value()).sample(&mut rng); - peerset_handle.report_peer(id.clone(), val); + peerset_handle.report_peer(id.clone(), ReputationChange::new(val, "")); } // If we generate 3, disconnect from a random node. diff --git a/substrate/client/service/src/lib.rs b/substrate/client/service/src/lib.rs index 1a86e05b88..8e2be43965 100644 --- a/substrate/client/service/src/lib.rs +++ b/substrate/client/service/src/lib.rs @@ -629,8 +629,8 @@ where &self, report_handle: ReportHandle, who: PeerId, - reputation_change_good: i32, - reputation_change_bad: i32, + reputation_change_good: network::ReputationChange, + reputation_change_bad: network::ReputationChange, transaction: B::Extrinsic ) { if !self.imports_external_transactions {