First step in implementing #4386 (#4437)

* First step in implementing https://github.com/paritytech/polkadot/issues/4386

This PR:

- Reduces MAX_UNSHARED_UPLOAD_TIME to 150ms
- Increases timeout on collation fetching to 1200ms
- Reduces limit on needed backing votes in the runtime

This PR does not yet reduce the number of needed backing votes on the
node as this can only be meaningfully enacted once the changed limit in
the runtime is live.

* Fix tests.

* Guide updates.

* Review remarks.

* Bump minimum required backing votes to 2 in runtime.

* Make sure node side code won't make runtime vomit.

* cargo +nightly fmt
This commit is contained in:
Robert Klotzner
2021-12-23 17:41:34 +01:00
committed by GitHub
parent 4689ccffce
commit 846828f61c
6 changed files with 44 additions and 19 deletions
+11 -3
View File
@@ -190,8 +190,16 @@ struct AttestingData {
backing: Vec<ValidatorIndex>,
}
const fn group_quorum(n_validators: usize) -> usize {
(n_validators / 2) + 1
/// How many votes we need to consider a candidate backed.
fn minimum_votes(n_validators: usize) -> usize {
// Runtime change going live, see: https://github.com/paritytech/polkadot/pull/4437
let old_runtime_value = n_validators / 2 + 1;
let new_runtime_value = std::cmp::min(2, n_validators);
// Until new runtime is live everywhere and we don't yet have
// https://github.com/paritytech/polkadot/issues/4576, we want to err on the higher value for
// secured block production:
std::cmp::max(old_runtime_value, new_runtime_value)
}
#[derive(Default)]
@@ -223,7 +231,7 @@ impl TableContextTrait for TableContext {
}
fn requisite_votes(&self, group: &ParaId) -> usize {
self.groups.get(group).map_or(usize::MAX, |g| group_quorum(g.len()))
self.groups.get(group).map_or(usize::MAX, |g| minimum_votes(g.len()))
}
}
@@ -66,12 +66,8 @@ const COST_APPARENT_FLOOD: Rep =
///
/// This is to protect from a single slow validator preventing collations from happening.
///
/// With a collation size of 5MB and bandwidth of 500Mbit/s (requirement for Kusama validators),
/// the transfer should be possible within 0.1 seconds. 400 milliseconds should therefore be
/// plenty and should be low enough for later validators to still be able to finish on time.
///
/// There is debug logging output, so we can adjust this value based on production results.
const MAX_UNSHARED_UPLOAD_TIME: Duration = Duration::from_millis(400);
/// For considerations on this value, see: https://github.com/paritytech/polkadot/issues/4386
const MAX_UNSHARED_UPLOAD_TIME: Duration = Duration::from_millis(150);
#[derive(Clone, Default)]
pub struct Metrics(Option<MetricsInner>);
@@ -95,7 +95,7 @@ pub const CHUNK_REQUEST_TIMEOUT: Duration = DEFAULT_REQUEST_TIMEOUT_CONNECTED;
/// This timeout is based on what seems sensible from a time budget perspective, considering 6
/// second block time. This is going to be tough, if we have multiple forks and large PoVs, but we
/// only have so much time.
const POV_REQUEST_TIMEOUT_CONNECTED: Duration = Duration::from_millis(1000);
const POV_REQUEST_TIMEOUT_CONNECTED: Duration = Duration::from_millis(1200);
/// We want timeout statement requests fast, so we don't waste time on slow nodes. Responders will
/// try their best to either serve within that timeout or return an error immediately. (We need to
@@ -1,6 +1,6 @@
# Candidate Backing
The Candidate Backing subsystem ensures every parablock considered for relay block inclusion has been seconded by at least one validator, and approved by a quorum. Parablocks for which no validator will assert correctness are discarded. If the block later proves invalid, the initial backers are slashable; this gives polkadot a rational threat model during subsequent stages.
The Candidate Backing subsystem ensures every parablock considered for relay block inclusion has been seconded by at least one validator, and approved by a quorum. Parablocks for which not enough validators will assert correctness are discarded. If the block later proves invalid, the initial backers are slashable; this gives polkadot a rational threat model during subsequent stages.
Its role is to produce backable candidates for inclusion in new relay-chain blocks. It does so by issuing signed [`Statement`s][Statement] and tracking received statements signed by other validators. Once enough statements are received, they can be combined into backing for specific candidates.
@@ -91,7 +91,7 @@ match msg {
}
```
Add `Seconded` statements and `Valid` statements to a quorum. If quorum reaches validator-group majority, send a [`ProvisionerMessage`][PM]`::ProvisionableData(ProvisionableData::BackedCandidate(CandidateReceipt))` message.
Add `Seconded` statements and `Valid` statements to a quorum. If the quorum reaches a pre-defined threshold, send a [`ProvisionerMessage`][PM]`::ProvisionableData(ProvisionableData::BackedCandidate(CandidateReceipt))` message.
`Invalid` statements that conflict with already witnessed `Seconded` and `Valid` statements for the given candidate, statements that are double-votes, self-contradictions and so on, should result in issuing a [`ProvisionerMessage`][PM]`::MisbehaviorReport` message for each newly detected case of this kind.
On each incoming statement, [`DisputeCoordinatorMessage::ImportStatement`][DCM] should be issued.
@@ -169,6 +169,15 @@ impl<H> Default for ProcessedCandidates<H> {
}
}
/// Number of backing votes we need for a valid backing.
pub fn minimum_backing_votes(n_validators: usize) -> usize {
// For considerations on this value see:
// https://github.com/paritytech/polkadot/pull/1656#issuecomment-999734650
// and
// https://github.com/paritytech/polkadot/issues/4386
sp_std::cmp::min(n_validators, 2)
}
#[frame_support::pallet]
pub mod pallet {
use super::*;
@@ -578,7 +587,7 @@ impl<T: Config> Pallet<T> {
match maybe_amount_validated {
Ok(amount_validated) => ensure!(
amount_validated * 2 > group_vals.len(),
amount_validated >= minimum_backing_votes(group_vals.len()),
Error::<T>::InsufficientBacking,
),
Err(()) => {
@@ -113,7 +113,7 @@ pub(crate) async fn back_candidate(
kind: BackingKind,
) -> BackedCandidate {
let mut validator_indices = bitvec::bitvec![BitOrderLsb0, u8; 0; group.len()];
let threshold = (group.len() / 2) + 1;
let threshold = minimum_backing_votes(group.len());
let signing = match kind {
BackingKind::Unanimous => group.len(),
@@ -151,8 +151,8 @@ pub(crate) async fn back_candidate(
Some(validators[group[i].0 as usize].public().into())
})
.ok()
.unwrap_or(0) *
2 > group.len();
.unwrap_or(0) >=
threshold;
match kind {
BackingKind::Unanimous | BackingKind::Threshold => assert!(successfully_backed),
@@ -1651,6 +1651,10 @@ fn backing_works() {
assure_candidate_sorting(candidate_receipt_with_backing_validator_indices)
);
let backers = {
let num_backers = minimum_backing_votes(group_validators(GroupIndex(0)).unwrap().len());
backing_bitfield(&(0..num_backers).collect::<Vec<_>>())
};
assert_eq!(
<PendingAvailability<Test>>::get(&chain_a),
Some(CandidatePendingAvailability {
@@ -1660,7 +1664,7 @@ fn backing_works() {
availability_votes: default_availability_votes(),
relay_parent_number: System::block_number() - 1,
backed_in_number: System::block_number(),
backers: backing_bitfield(&[0, 1]),
backers,
backing_group: GroupIndex::from(0),
})
);
@@ -1669,6 +1673,10 @@ fn backing_works() {
Some(candidate_a.commitments),
);
let backers = {
let num_backers = minimum_backing_votes(group_validators(GroupIndex(0)).unwrap().len());
backing_bitfield(&(0..num_backers).map(|v| v + 2).collect::<Vec<_>>())
};
assert_eq!(
<PendingAvailability<Test>>::get(&chain_b),
Some(CandidatePendingAvailability {
@@ -1678,7 +1686,7 @@ fn backing_works() {
availability_votes: default_availability_votes(),
relay_parent_number: System::block_number() - 1,
backed_in_number: System::block_number(),
backers: backing_bitfield(&[2, 3]),
backers,
backing_group: GroupIndex::from(1),
})
);
@@ -1790,6 +1798,10 @@ fn can_include_candidate_with_ok_code_upgrade() {
assert_eq!(occupied_cores, vec![CoreIndex::from(0)]);
let backers = {
let num_backers = minimum_backing_votes(group_validators(GroupIndex(0)).unwrap().len());
backing_bitfield(&(0..num_backers).collect::<Vec<_>>())
};
assert_eq!(
<PendingAvailability<Test>>::get(&chain_a),
Some(CandidatePendingAvailability {
@@ -1799,7 +1811,7 @@ fn can_include_candidate_with_ok_code_upgrade() {
availability_votes: default_availability_votes(),
relay_parent_number: System::block_number() - 1,
backed_in_number: System::block_number(),
backers: backing_bitfield(&[0, 1, 2]),
backers,
backing_group: GroupIndex::from(0),
})
);