Reputation changes requires reason (#4277)

This commit is contained in:
Arkadiy Paronyan
2019-12-03 11:33:33 +01:00
committed by Gavin Wood
parent 5edc4350b4
commit 5ec0923285
14 changed files with 233 additions and 156 deletions
@@ -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<N: Ord> Peers<N> {
#[derive(Debug, PartialEq)]
pub(super) enum Action<H> {
// 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<Block: BlockT> Inner<Block> {
.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<Block: BlockT> Inner<Block> {
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<Block: BlockT> GossipValidator<Block> {
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<Block: BlockT> network_gossip::Validator<Block> for GossipValidator<Block>
struct PeerReport {
who: PeerId,
cost_benefit: i32,
cost_benefit: ReputationChange,
}
// wrapper around a stream of reports.
@@ -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<Block: BlockT>: Clone + Send + 'static {
fn send_message(&self, who: Vec<network::PeerId>, data: Vec<u8>);
/// 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<u8>);
@@ -217,7 +219,7 @@ impl<B, S, H> Network<B> for Arc<NetworkService<B, S, H>> 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<Block: BlockT>(
voters: &VoterSet<AuthorityId>,
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<Block: BlockT>(
msg: &CatchUp<Block>,
voters: &VoterSet<AuthorityId>,
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<Block: BlockT>(
voters: &'a VoterSet<AuthorityId>,
votes: impl Iterator<Item=&'a AuthorityId>,
full_threshold: u64,
) -> Result<(), i32> {
) -> Result<(), ReputationChange> {
let mut total_weight = 0;
for id in votes {
@@ -911,7 +913,7 @@ fn check_catch_up<Block: BlockT>(
round: RoundNumber,
set_id: SetIdNumber,
mut signatures_checked: usize,
) -> Result<usize, i32> where
) -> Result<usize, ReputationChange> where
B: BlockT,
I: Iterator<Item=(Message<B>, &'a AuthorityId, &'a AuthoritySignature)>,
{
@@ -37,7 +37,7 @@ enum Event {
RegisterValidator(Arc<dyn network_gossip::Validator<Block>>),
GossipMessage(Hash, Vec<u8>, bool),
SendMessage(Vec<network::PeerId>, Vec<u8>),
Report(network::PeerId, i32),
Report(network::PeerId, network::ReputationChange),
Announce(Hash),
}
@@ -85,7 +85,7 @@ impl super::Network<Block> 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));
}
@@ -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)));
}
}
+1
View File
@@ -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)]
+51 -36
View File
@@ -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<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> {
@@ -183,7 +198,7 @@ struct LightDispatchIn<'a> {
}
impl<'a, B: BlockT> LightDispatchNetwork<B> 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<B> for LightDispatchIn<'a> {
pub trait Context<B: BlockT> {
/// 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<B> 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<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
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<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
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<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
/// 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<Message<B>>) {
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<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
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<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
}
/// 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<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
);
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<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
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<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
"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<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
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<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
// 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<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
.saturated_into::<u64>();
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<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
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<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
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<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
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<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
None
},
};
self.send_message(
self.send_message(
&who,
GenericMessage::FinalityProofResponse(message::FinalityProofResponse {
id: 0,
@@ -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<H> {
known_messages: HashSet<H>,
@@ -470,7 +474,7 @@ impl<B: BlockT> ConsensusGossip<B> {
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<B: BlockT> ConsensusGossip<B> {
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<B: BlockT> ConsensusGossip<B> {
}
} 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);
@@ -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<B: BlockT> {
/// 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<B: BlockT> LightDispatch<B> 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<B: BlockT> LightDispatch<B> 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<B: BlockT> LightDispatch<B> 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<B: BlockT> LightDispatch<B> 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<B> 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());
}
+43 -32
View File
@@ -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<B: BlockT> {
/// 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<B: BlockT> ChainSync<B> {
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<B: BlockT> ChainSync<B> {
},
(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<B: BlockT> ChainSync<B> {
}
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<B: BlockT> ChainSync<B> {
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<B: BlockT> ChainSync<B> {
// 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<B: BlockT> ChainSync<B> {
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<B: BlockT> ChainSync<B> {
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());
}
},
+7 -7
View File
@@ -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<H: ExHashT, B: BlockT>: 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<PeersetHandle> 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<B: BlockT + 'static, S: NetworkSpecialization<B>, 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<B>, H: ExHashT> Link<B> 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<B>) {
@@ -806,7 +806,7 @@ impl<'a, B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Link<B> 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"));
}
}
}
+2 -2
View File
@@ -401,8 +401,8 @@ impl TransactionPool<Hash, Block> 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
) {}
+52 -16
View File
@@ -38,12 +38,33 @@ enum Action {
AddReservedPeer(PeerId),
RemoveReservedPeer(PeerId),
SetReservedOnly(bool),
ReportPeer(PeerId, i32),
ReportPeer(PeerId, ReputationChange),
SetPriorityGroup(String, HashSet<PeerId>),
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::<Vec<_>>() {
for peer_id in self.data.peers().cloned().collect::<Vec<_>>() {
// 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<Message>) -> 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.
+2 -2
View File
@@ -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.
+2 -2
View File
@@ -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 {