Skip to content

Commit

Permalink
use the accumulated disabled state per session
Browse files Browse the repository at this point in the history
  • Loading branch information
ordian committed Oct 18, 2023
1 parent 681883b commit 2427dd8
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 65 deletions.
76 changes: 44 additions & 32 deletions polkadot/node/network/statement-distribution/src/v2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
//! Implementation of the v2 statement distribution protocol,
//! designed for asynchronous backing.

use bitvec::prelude::{BitVec, Lsb0};
use polkadot_node_network_protocol::{
self as net_protocol,
grid_topology::SessionGridTopology,
Expand Down Expand Up @@ -63,7 +64,7 @@ use futures::{
use std::{
collections::{
hash_map::{Entry, HashMap},
HashSet,
BTreeSet, HashSet,
},
time::{Duration, Instant},
};
Expand Down Expand Up @@ -162,6 +163,9 @@ struct PerSessionState {
// getting the topology from the gossip-support subsystem
grid_view: Option<grid::SessionTopologyView>,
local_validator: Option<ValidatorIndex>,
// We assume that the validators are never re-enabled per session
// and store the latest state here.
disabled_validators: BTreeSet<ValidatorIndex>,
}

impl PerSessionState {
Expand All @@ -183,6 +187,7 @@ impl PerSessionState {
authority_lookup,
grid_view: None,
local_validator: local_validator.map(|(_key, index)| index),
disabled_validators: BTreeSet::new(),
}
}

Expand All @@ -195,6 +200,34 @@ impl PerSessionState {

self.grid_view = Some(grid_view);
}

/// A convenience function to generate a disabled bitmask for the given backing group.
/// The output bits are set to `true` for validators that are disabled.
/// Returns `None` if the group index is out of bounds.
pub fn disabled_bitmask(&self, group: GroupIndex) -> Option<BitVec<u8, Lsb0>> {
let group = self.groups.get(group)?;
let group_size = group.len();
let mut mask = BitVec::repeat(false, group_size);
for (i, v) in group.iter().enumerate() {
if self.is_disabled(v) {
mask.set(i, true);
}
}
Some(mask)
}

/// Returns `true` if the given validator is disabled in the current session.
pub fn is_disabled(&self, validator_index: &ValidatorIndex) -> bool {
self.disabled_validators.contains(validator_index)
}

/// Extend the set of disabled validators for the current session.
pub fn extend_disabled_validators(
&mut self,
disabled: impl IntoIterator<Item = ValidatorIndex>,
) {
self.disabled_validators.extend(disabled);
}
}

pub(crate) struct State {
Expand Down Expand Up @@ -483,9 +516,6 @@ pub(crate) async fn handle_active_leaves_update<Context>(
.map_err(JfyiError::RuntimeApiUnavailable)?
.map_err(JfyiError::FetchDisabledValidators)?;

// deduplicate and order
let disabled_validators = disabled_validators.into_iter().collect();

let group_rotation_info =
polkadot_node_subsystem_util::request_validator_groups(new_relay_parent, ctx.sender())
.await
Expand Down Expand Up @@ -529,9 +559,11 @@ pub(crate) async fn handle_active_leaves_update<Context>(

let per_session = state
.per_session
.get(&session_index)
.get_mut(&session_index)
.expect("either existed or just inserted; qed");

per_session.extend_disabled_validators(disabled_validators);

let local_validator = per_session.local_validator.and_then(|v| {
find_local_validator_state(
v,
Expand All @@ -546,7 +578,7 @@ pub(crate) async fn handle_active_leaves_update<Context>(
new_relay_parent,
PerRelayParentState {
local_validator,
statement_store: StatementStore::new(&per_session.groups, &disabled_validators),
statement_store: StatementStore::new(&per_session.groups),
availability_cores,
group_rotation_info,
seconding_limit,
Expand Down Expand Up @@ -1313,10 +1345,7 @@ async fn handle_incoming_statement<Context>(
},
};

if per_relay_parent
.statement_store
.is_disabled(&statement.unchecked_validator_index())
{
if per_session.is_disabled(&statement.unchecked_validator_index()) {
gum::debug!(
target: LOG_TARGET,
?relay_parent,
Expand Down Expand Up @@ -1450,17 +1479,6 @@ async fn handle_incoming_statement<Context>(

return
},
Err(statement_store::Error::ValidatorDisabled) => {
// sanity: should never happen, checked above.
gum::warn!(
target: LOG_TARGET,
?relay_parent,
validator_index = ?originator_index,
"Error - accepted message from disabled validator."
);

return
},
Ok(known) => known,
};

Expand Down Expand Up @@ -2024,11 +2042,7 @@ async fn handle_incoming_manifest_common<'a, Context>(
let claimed_parent_hash = manifest_summary.claimed_parent_hash;

// Ignore votes from disabled validators when counting towards the threshold.
let disabled_mask = per_session
.groups
.get(group_index)
.map(|group| relay_parent_state.statement_store.disabled_bitmask(group))
.unwrap_or_default();
let disabled_mask = per_session.disabled_bitmask(group_index).unwrap_or_default();
manifest_summary.statement_knowledge.mask_seconded(&disabled_mask);
manifest_summary.statement_knowledge.mask_valid(&disabled_mask);

Expand Down Expand Up @@ -2622,7 +2636,9 @@ pub(crate) async fn handle_response<Context>(
Some(g) => g,
};

let disabled_mask = relay_parent_state.statement_store.disabled_bitmask(group);
let disabled_mask = per_session
.disabled_bitmask(group_index)
.expect("group_index checked above; qed");

let res = response.validate_response(
&mut state.request_manager,
Expand Down Expand Up @@ -2800,11 +2816,7 @@ pub(crate) fn answer_request(state: &mut State, message: ResponderMessage) {
};

// Ignore disabled validators when sending the response.
let disabled_mask = per_session
.groups
.get(confirmed.group_index())
.map(|group| relay_parent_state.statement_store.disabled_bitmask(group))
.unwrap_or_default();
let disabled_mask = per_session.disabled_bitmask(confirmed.group_index()).unwrap_or_default();
and_mask.mask_seconded(&disabled_mask);
and_mask.mask_valid(&disabled_mask);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,7 @@ use polkadot_node_network_protocol::v2::StatementFilter;
use polkadot_primitives::{
CandidateHash, CompactStatement, GroupIndex, SignedStatement, ValidatorIndex,
};
use std::collections::{
hash_map::{Entry as HEntry, HashMap},
BTreeSet,
};
use std::collections::hash_map::{Entry as HEntry, HashMap};

use super::groups::Groups;

Expand Down Expand Up @@ -71,7 +68,7 @@ pub struct StatementStore {

impl StatementStore {
/// Create a new [`StatementStore`]
pub fn new(groups: &Groups, disabled: &BTreeSet<ValidatorIndex>) -> Self {
pub fn new(groups: &Groups) -> Self {
let mut validator_meta = HashMap::new();
for (g, group) in groups.all().iter().enumerate() {
for (i, v) in group.iter().enumerate() {
Expand All @@ -81,7 +78,6 @@ impl StatementStore {
seconded_count: 0,
within_group_index: i,
group: GroupIndex(g as _),
is_disabled: disabled.contains(v),
},
);
}
Expand All @@ -95,7 +91,7 @@ impl StatementStore {
}

/// Insert a statement. Returns `true` if was not known already, `false` if it was.
/// Ignores statements by unknown and disabled validators and returns an error.
/// Ignores statements by unknown validators and returns an error.
pub fn insert(
&mut self,
groups: &Groups,
Expand All @@ -107,9 +103,6 @@ impl StatementStore {
None => return Err(Error::ValidatorUnknown),
Some(m) => m,
};
if validator_meta.is_disabled {
return Err(Error::ValidatorDisabled)
}

let compact = statement.payload().clone();
let fingerprint = (validator_index, compact.clone());
Expand Down Expand Up @@ -161,25 +154,6 @@ impl StatementStore {
Ok(true)
}

/// Returns true if the validator is disabled as of current relay parent.
pub fn is_disabled(&self, index: &ValidatorIndex) -> bool {
self.validator_meta.get(&index).map(|m| m.is_disabled).unwrap_or(false)
}

/// A convenience funtion to generate a disabled bitmask for the given backing group.
/// The output bits are set to `true` for validators that are disabled.
/// The group size should match the size of the backing group.
pub fn disabled_bitmask(&self, group: &[ValidatorIndex]) -> BitVec<u8, BitOrderLsb0> {
let group_size = group.len();
let mut mask = BitVec::repeat(false, group_size);
for (i, v) in group.iter().enumerate() {
if self.is_disabled(v) {
mask.set(i, true);
}
}
mask
}

/// Fill a `StatementFilter` to be used in the grid topology with all statements
/// we are already aware of.
pub fn fill_statement_filter(
Expand Down Expand Up @@ -275,12 +249,10 @@ impl StatementStore {
}
}

/// Error indicating that the validator was unknown or disabled.
/// Error when inserting a statement into the statement store.
pub enum Error {
/// The validator was unknown.
ValidatorUnknown,
/// A statement from a disabled validator should be rejected.
ValidatorDisabled,
}

type Fingerprint = (ValidatorIndex, CompactStatement);
Expand All @@ -289,7 +261,6 @@ struct ValidatorMeta {
group: GroupIndex,
within_group_index: usize,
seconded_count: usize,
is_disabled: bool,
}

struct GroupStatements {
Expand Down

0 comments on commit 2427dd8

Please sign in to comment.