backing: move the min votes threshold to the runtime (#1200)

* move min backing votes const to runtime

also cache it per-session in the backing subsystem

Signed-off-by: alindima <alin@parity.io>

* add runtime migration

* introduce api versioning for min_backing votes

also enable it for rococo/versi for testing

* also add min_backing_votes runtime calls to statement-distribution

this dependency has been recently introduced by async backing

* remove explicit version runtime API call

this is not needed, as the RuntimeAPISubsystem already takes care
of versioning and will return NotSupported if the version is not
right.

* address review comments

- parametrise backing votes runtime API with session index
- remove RuntimeInfo usage in backing subsystem, as runtime API
caches the min backing votes by session index anyway.
- move the logic for adjusting the configured needed backing votes with the size of the backing group
to a primitives helper.
- move the legacy min backing votes value to a primitives helper.
- mark JoinMultiple error as fatal, since the Canceled (non-multiple) counterpart is also fatal.
- make backing subsystem handle fatal errors for new leaves update.
- add HostConfiguration consistency check for zeroed backing votes threshold
- add cumulus accompanying change

* fix cumulus test compilation

* fix tests

* more small fixes

* fix merge

* bump runtime api version for westend and rollback version for rococo

---------

Signed-off-by: alindima <alin@parity.io>
Co-authored-by: Javier Viola <javier@parity.io>
This commit is contained in:
Alin Dima
2023-08-31 14:01:36 +03:00
committed by GitHub
parent f1845f725d
commit d6af073aa5
37 changed files with 920 additions and 255 deletions
@@ -1074,7 +1074,7 @@ mod tests {
fn dummy_groups(group_size: usize) -> Groups {
let groups = vec![(0..(group_size as u32)).map(ValidatorIndex).collect()].into();
Groups::new(groups)
Groups::new(groups, 2)
}
#[test]
@@ -16,8 +16,10 @@
//! A utility for tracking groups and their members within a session.
use polkadot_node_primitives::minimum_votes;
use polkadot_primitives::vstaging::{GroupIndex, IndexedVec, ValidatorIndex};
use polkadot_primitives::{
effective_minimum_backing_votes,
vstaging::{GroupIndex, IndexedVec, ValidatorIndex},
};
use std::collections::HashMap;
@@ -27,12 +29,16 @@ use std::collections::HashMap;
pub struct Groups {
groups: IndexedVec<GroupIndex, Vec<ValidatorIndex>>,
by_validator_index: HashMap<ValidatorIndex, GroupIndex>,
backing_threshold: u32,
}
impl Groups {
/// Create a new [`Groups`] tracker with the groups and discovery keys
/// from the session.
pub fn new(groups: IndexedVec<GroupIndex, Vec<ValidatorIndex>>) -> Self {
pub fn new(
groups: IndexedVec<GroupIndex, Vec<ValidatorIndex>>,
backing_threshold: u32,
) -> Self {
let mut by_validator_index = HashMap::new();
for (i, group) in groups.iter().enumerate() {
@@ -42,7 +48,7 @@ impl Groups {
}
}
Groups { groups, by_validator_index }
Groups { groups, by_validator_index, backing_threshold }
}
/// Access all the underlying groups.
@@ -60,7 +66,8 @@ impl Groups {
&self,
group_index: GroupIndex,
) -> Option<(usize, usize)> {
self.get(group_index).map(|g| (g.len(), minimum_votes(g.len())))
self.get(group_index)
.map(|g| (g.len(), effective_minimum_backing_votes(g.len(), self.backing_threshold)))
}
/// Get the group index for a validator by index.
@@ -41,8 +41,9 @@ use polkadot_node_subsystem::{
overseer, ActivatedLeaf,
};
use polkadot_node_subsystem_util::{
backing_implicit_view::View as ImplicitView, reputation::ReputationAggregator,
runtime::ProspectiveParachainsMode,
backing_implicit_view::View as ImplicitView,
reputation::ReputationAggregator,
runtime::{request_min_backing_votes, ProspectiveParachainsMode},
};
use polkadot_primitives::vstaging::{
AuthorityDiscoveryId, CandidateHash, CompactStatement, CoreIndex, CoreState, GroupIndex,
@@ -163,8 +164,8 @@ struct PerSessionState {
}
impl PerSessionState {
fn new(session_info: SessionInfo, keystore: &KeystorePtr) -> Self {
let groups = Groups::new(session_info.validator_groups.clone());
fn new(session_info: SessionInfo, keystore: &KeystorePtr, backing_threshold: u32) -> Self {
let groups = Groups::new(session_info.validator_groups.clone(), backing_threshold);
let mut authority_lookup = HashMap::new();
for (i, ad) in session_info.discovery_keys.iter().cloned().enumerate() {
authority_lookup.insert(ad, ValidatorIndex(i as _));
@@ -504,9 +505,13 @@ pub(crate) async fn handle_active_leaves_update<Context>(
Some(s) => s,
};
state
.per_session
.insert(session_index, PerSessionState::new(session_info, &state.keystore));
let minimum_backing_votes =
request_min_backing_votes(new_relay_parent, session_index, ctx.sender()).await?;
state.per_session.insert(
session_index,
PerSessionState::new(session_info, &state.keystore, minimum_backing_votes),
);
}
let per_session = state
@@ -2502,7 +2507,7 @@ pub(crate) async fn dispatch_requests<Context>(ctx: &mut Context, state: &mut St
Some(RequestProperties {
unwanted_mask,
backing_threshold: if require_backing {
Some(polkadot_node_primitives::minimum_votes(group.len()))
Some(per_session.groups.get_size_and_backing_threshold(group_index)?.1)
} else {
None
},
@@ -356,7 +356,7 @@ async fn activate_leaf(
virtual_overseer: &mut VirtualOverseer,
leaf: &TestLeaf,
test_state: &TestState,
expect_session_info_request: bool,
is_new_session: bool,
) {
let activated = ActivatedLeaf {
hash: leaf.hash,
@@ -371,14 +371,14 @@ async fn activate_leaf(
))))
.await;
handle_leaf_activation(virtual_overseer, leaf, test_state, expect_session_info_request).await;
handle_leaf_activation(virtual_overseer, leaf, test_state, is_new_session).await;
}
async fn handle_leaf_activation(
virtual_overseer: &mut VirtualOverseer,
leaf: &TestLeaf,
test_state: &TestState,
expect_session_info_request: bool,
is_new_session: bool,
) {
let TestLeaf { number, hash, parent_hash, para_data, session, availability_cores } = leaf;
@@ -447,7 +447,7 @@ async fn handle_leaf_activation(
}
);
if expect_session_info_request {
if is_new_session {
assert_matches!(
virtual_overseer.recv().await,
AllMessages::RuntimeApi(
@@ -455,6 +455,16 @@ async fn handle_leaf_activation(
tx.send(Ok(Some(test_state.session_info.clone()))).unwrap();
}
);
assert_matches!(
virtual_overseer.recv().await,
AllMessages::RuntimeApi(RuntimeApiMessage::Request(
parent,
RuntimeApiRequest::MinimumBackingVotes(session_index, tx),
)) if parent == *hash && session_index == *session => {
tx.send(Ok(2)).unwrap();
}
);
}
}