Skip to content

Commit 6b854ac

Browse files
authored
[3 / 5] Move crypto checks in the approval-distribution (#4928)
# Prerequisite This is part of the work to further optimize the approval subsystems, if you want to understand the full context start with reading #4849 (comment), # Description This PR contain changes, so that the crypto checks are performed by the approval-distribution subsystem instead of the approval-voting one. The benefit for these, is twofold: 1. Approval-distribution won't have to wait every single time for the approval-voting to finish its job, so the work gets to be pipelined between approval-distribution and approval-voting. 2. By running in parallel multiple instances of approval-distribution as described here #4849 (comment), this significant body of work gets to run in parallel. ## Changes: 1. When approval-voting send `ApprovalDistributionMessage::NewBlocks` it needs to pass the core_index and candidate_hash of the candidates. 2. ApprovalDistribution needs to use `RuntimeInfo` to be able to fetch the SessionInfo from the runtime. 3. Move `approval-voting` logic that checks VRF assignment into `approval-distribution` 4. Move `approval-voting` logic that checks vote is correctly signed into `approval-distribution` 5. Plumb `approval-distribution` and `approval-voting` tests to support the new logic. ## Benefits Even without parallelisation the gains are significant, for example on my machine if we run approval subsystem bench for 500 validators and 100 cores and trigger all 89 tranches of assignments and approvals, the system won't fall behind anymore because of late processing of messages. ``` Before change Chain selection approved after 11500 ms hash=0x0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a After change Chain selection approved after 5500 ms hash=0x0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a ``` ## TODO: - [x] Run on versi. - [x] Update parachain host documentation. --------- Signed-off-by: Alexandru Gheorghe <[email protected]>
1 parent f0b2add commit 6b854ac

File tree

27 files changed

+4648
-3535
lines changed

27 files changed

+4648
-3535
lines changed

Cargo.lock

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

polkadot/node/core/approval-voting/benches/approval-voting-regression-bench.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ fn main() -> Result<(), String> {
8282
("Sent to peers", 63995.2200, 0.01),
8383
]));
8484
messages.extend(average_usage.check_cpu_usage(&[
85-
("approval-distribution", 6.3912, 0.1),
86-
("approval-voting", 10.0578, 0.1),
85+
("approval-distribution", 12.2736, 0.1),
86+
("approval-voting", 2.7174, 0.1),
8787
]));
8888

8989
if messages.is_empty() {

polkadot/node/core/approval-voting/src/approval_checking.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ use polkadot_primitives::ValidatorIndex;
2222

2323
use crate::{
2424
persisted_entries::{ApprovalEntry, CandidateEntry, TrancheEntry},
25-
time::Tick,
2625
MAX_RECORDED_NO_SHOW_VALIDATORS_PER_CANDIDATE,
2726
};
27+
use polkadot_node_primitives::approval::time::Tick;
2828

2929
/// Result of counting the necessary tranches needed for approving a block.
3030
#[derive(Debug, PartialEq, Clone)]
@@ -1195,9 +1195,9 @@ mod tests {
11951195
struct NoShowTest {
11961196
assignments: Vec<(ValidatorIndex, Tick)>,
11971197
approvals: Vec<usize>,
1198-
clock_drift: crate::time::Tick,
1199-
no_show_duration: crate::time::Tick,
1200-
drifted_tick_now: crate::time::Tick,
1198+
clock_drift: Tick,
1199+
no_show_duration: Tick,
1200+
drifted_tick_now: Tick,
12011201
exp_no_shows: usize,
12021202
exp_next_no_show: Option<u64>,
12031203
}

polkadot/node/core/approval-voting/src/criteria.rs

Lines changed: 29 additions & 145 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,21 @@
1616

1717
//! Assignment criteria VRF generation and checking.
1818
19-
use codec::{Decode, Encode};
19+
use codec::Encode;
2020
use itertools::Itertools;
21+
pub use polkadot_node_primitives::approval::criteria::{
22+
AssignmentCriteria, Config, InvalidAssignment, InvalidAssignmentReason, OurAssignment,
23+
};
2124
use polkadot_node_primitives::approval::{
2225
self as approval_types,
2326
v1::{AssignmentCert, AssignmentCertKind, DelayTranche, RelayVRFStory},
2427
v2::{
2528
AssignmentCertKindV2, AssignmentCertV2, CoreBitfield, VrfPreOutput, VrfProof, VrfSignature,
2629
},
2730
};
31+
2832
use polkadot_primitives::{
29-
AssignmentId, AssignmentPair, CandidateHash, CoreIndex, GroupIndex, IndexedVec, SessionInfo,
30-
ValidatorIndex,
33+
AssignmentPair, CandidateHash, CoreIndex, GroupIndex, IndexedVec, ValidatorIndex,
3134
};
3235
use rand::{seq::SliceRandom, SeedableRng};
3336
use rand_chacha::ChaCha20Rng;
@@ -44,56 +47,19 @@ use std::{
4447

4548
use super::LOG_TARGET;
4649

47-
/// Details pertaining to our assignment on a block.
48-
#[derive(Debug, Clone, Encode, Decode, PartialEq)]
49-
pub struct OurAssignment {
50-
cert: AssignmentCertV2,
51-
tranche: DelayTranche,
52-
validator_index: ValidatorIndex,
53-
// Whether the assignment has been triggered already.
54-
triggered: bool,
55-
}
56-
57-
impl OurAssignment {
58-
pub fn cert(&self) -> &AssignmentCertV2 {
59-
&self.cert
60-
}
61-
62-
pub fn tranche(&self) -> DelayTranche {
63-
self.tranche
64-
}
65-
66-
pub(crate) fn validator_index(&self) -> ValidatorIndex {
67-
self.validator_index
68-
}
69-
70-
pub(crate) fn triggered(&self) -> bool {
71-
self.triggered
72-
}
73-
74-
pub(crate) fn mark_triggered(&mut self) {
75-
self.triggered = true;
76-
}
77-
}
78-
7950
impl From<crate::approval_db::v2::OurAssignment> for OurAssignment {
8051
fn from(entry: crate::approval_db::v2::OurAssignment) -> Self {
81-
OurAssignment {
82-
cert: entry.cert,
83-
tranche: entry.tranche,
84-
validator_index: entry.validator_index,
85-
triggered: entry.triggered,
86-
}
52+
OurAssignment::new(entry.cert, entry.tranche, entry.validator_index, entry.triggered)
8753
}
8854
}
8955

9056
impl From<OurAssignment> for crate::approval_db::v2::OurAssignment {
9157
fn from(entry: OurAssignment) -> Self {
9258
Self {
93-
cert: entry.cert,
94-
tranche: entry.tranche,
95-
validator_index: entry.validator_index,
96-
triggered: entry.triggered,
59+
tranche: entry.tranche(),
60+
validator_index: entry.validator_index(),
61+
triggered: entry.triggered(),
62+
cert: entry.into_cert(),
9763
}
9864
}
9965
}
@@ -223,60 +189,7 @@ fn assigned_core_transcript(core_index: CoreIndex) -> Transcript {
223189
t
224190
}
225191

226-
/// Information about the world assignments are being produced in.
227-
#[derive(Clone, Debug)]
228-
pub struct Config {
229-
/// The assignment public keys for validators.
230-
assignment_keys: Vec<AssignmentId>,
231-
/// The groups of validators assigned to each core.
232-
validator_groups: IndexedVec<GroupIndex, Vec<ValidatorIndex>>,
233-
/// The number of availability cores used by the protocol during this session.
234-
n_cores: u32,
235-
/// The zeroth delay tranche width.
236-
zeroth_delay_tranche_width: u32,
237-
/// The number of samples we do of `relay_vrf_modulo`.
238-
relay_vrf_modulo_samples: u32,
239-
/// The number of delay tranches in total.
240-
n_delay_tranches: u32,
241-
}
242-
243-
impl<'a> From<&'a SessionInfo> for Config {
244-
fn from(s: &'a SessionInfo) -> Self {
245-
Config {
246-
assignment_keys: s.assignment_keys.clone(),
247-
validator_groups: s.validator_groups.clone(),
248-
n_cores: s.n_cores,
249-
zeroth_delay_tranche_width: s.zeroth_delay_tranche_width,
250-
relay_vrf_modulo_samples: s.relay_vrf_modulo_samples,
251-
n_delay_tranches: s.n_delay_tranches,
252-
}
253-
}
254-
}
255-
256-
/// A trait for producing and checking assignments. Used to mock.
257-
pub(crate) trait AssignmentCriteria {
258-
fn compute_assignments(
259-
&self,
260-
keystore: &LocalKeystore,
261-
relay_vrf_story: RelayVRFStory,
262-
config: &Config,
263-
leaving_cores: Vec<(CandidateHash, CoreIndex, GroupIndex)>,
264-
enable_v2_assignments: bool,
265-
) -> HashMap<CoreIndex, OurAssignment>;
266-
267-
fn check_assignment_cert(
268-
&self,
269-
claimed_core_bitfield: CoreBitfield,
270-
validator_index: ValidatorIndex,
271-
config: &Config,
272-
relay_vrf_story: RelayVRFStory,
273-
assignment: &AssignmentCertV2,
274-
// Backing groups for each "leaving core".
275-
backing_groups: Vec<GroupIndex>,
276-
) -> Result<DelayTranche, InvalidAssignment>;
277-
}
278-
279-
pub(crate) struct RealAssignmentCriteria;
192+
pub struct RealAssignmentCriteria;
280193

281194
impl AssignmentCriteria for RealAssignmentCriteria {
282195
fn compute_assignments(
@@ -469,12 +382,12 @@ fn compute_relay_vrf_modulo_assignments_v1(
469382
};
470383

471384
// All assignments of type RelayVRFModulo have tranche 0.
472-
assignments.entry(core).or_insert(OurAssignment {
473-
cert: cert.into(),
474-
tranche: 0,
385+
assignments.entry(core).or_insert(OurAssignment::new(
386+
cert.into(),
387+
0,
475388
validator_index,
476-
triggered: false,
477-
});
389+
false,
390+
));
478391
}
479392
}
480393
}
@@ -549,7 +462,7 @@ fn compute_relay_vrf_modulo_assignments_v2(
549462
};
550463

551464
// All assignments of type RelayVRFModulo have tranche 0.
552-
OurAssignment { cert, tranche: 0, validator_index, triggered: false }
465+
OurAssignment::new(cert, 0, validator_index, false)
553466
}) {
554467
for core_index in assigned_cores {
555468
assignments.insert(core_index, assignment.clone());
@@ -583,15 +496,15 @@ fn compute_relay_vrf_delay_assignments(
583496
},
584497
};
585498

586-
let our_assignment = OurAssignment { cert, tranche, validator_index, triggered: false };
499+
let our_assignment = OurAssignment::new(cert, tranche, validator_index, false);
587500

588501
let used = match assignments.entry(core) {
589502
Entry::Vacant(e) => {
590503
let _ = e.insert(our_assignment);
591504
true
592505
},
593506
Entry::Occupied(mut e) =>
594-
if e.get().tranche > our_assignment.tranche {
507+
if e.get().tranche() > our_assignment.tranche() {
595508
e.insert(our_assignment);
596509
true
597510
} else {
@@ -612,35 +525,6 @@ fn compute_relay_vrf_delay_assignments(
612525
}
613526
}
614527

615-
/// Assignment invalid.
616-
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
617-
pub struct InvalidAssignment(pub(crate) InvalidAssignmentReason);
618-
619-
impl std::fmt::Display for InvalidAssignment {
620-
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
621-
write!(f, "Invalid Assignment: {:?}", self.0)
622-
}
623-
}
624-
625-
impl std::error::Error for InvalidAssignment {}
626-
627-
/// Failure conditions when checking an assignment cert.
628-
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
629-
pub(crate) enum InvalidAssignmentReason {
630-
ValidatorIndexOutOfBounds,
631-
SampleOutOfBounds,
632-
CoreIndexOutOfBounds,
633-
InvalidAssignmentKey,
634-
IsInBackingGroup,
635-
VRFModuloCoreIndexMismatch,
636-
VRFModuloOutputMismatch,
637-
VRFDelayCoreIndexMismatch,
638-
VRFDelayOutputMismatch,
639-
InvalidArguments,
640-
/// Assignment vrf check resulted in 0 assigned cores.
641-
NullAssignment,
642-
}
643-
644528
/// Checks the crypto of an assignment cert. Failure conditions:
645529
/// * Validator index out of bounds
646530
/// * VRF signature check fails
@@ -820,21 +704,21 @@ fn is_in_backing_group(
820704
/// Migration helpers.
821705
impl From<crate::approval_db::v1::OurAssignment> for OurAssignment {
822706
fn from(value: crate::approval_db::v1::OurAssignment) -> Self {
823-
Self {
824-
cert: value.cert.into(),
825-
tranche: value.tranche,
826-
validator_index: value.validator_index,
707+
Self::new(
708+
value.cert.into(),
709+
value.tranche,
710+
value.validator_index,
827711
// Whether the assignment has been triggered already.
828-
triggered: value.triggered,
829-
}
712+
value.triggered,
713+
)
830714
}
831715
}
832716

833717
#[cfg(test)]
834718
mod tests {
835719
use super::*;
836720
use crate::import::tests::garbage_vrf_signature;
837-
use polkadot_primitives::{Hash, ASSIGNMENT_KEY_TYPE_ID};
721+
use polkadot_primitives::{AssignmentId, Hash, ASSIGNMENT_KEY_TYPE_ID};
838722
use sp_application_crypto::sr25519;
839723
use sp_core::crypto::Pair as PairT;
840724
use sp_keyring::sr25519::Keyring as Sr25519Keyring;
@@ -1053,7 +937,7 @@ mod tests {
1053937

1054938
let mut counted = 0;
1055939
for (core, assignment) in assignments {
1056-
let cores = match assignment.cert.kind.clone() {
940+
let cores = match assignment.cert().kind.clone() {
1057941
AssignmentCertKindV2::RelayVRFModuloCompact { core_bitfield } => core_bitfield,
1058942
AssignmentCertKindV2::RelayVRFModulo { sample: _ } => core.into(),
1059943
AssignmentCertKindV2::RelayVRFDelay { core_index } => core_index.into(),
@@ -1062,7 +946,7 @@ mod tests {
1062946
let mut mutated = MutatedAssignment {
1063947
cores: cores.clone(),
1064948
groups: cores.iter_ones().map(|core| group_for_core(core)).collect(),
1065-
cert: assignment.cert,
949+
cert: assignment.into_cert(),
1066950
own_group: GroupIndex(0),
1067951
val_index: ValidatorIndex(0),
1068952
config: config.clone(),

polkadot/node/core/approval-voting/src/import.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,10 @@ use crate::{
6262
criteria::{AssignmentCriteria, OurAssignment},
6363
get_extended_session_info, get_session_info,
6464
persisted_entries::CandidateEntry,
65-
time::{slot_number_to_tick, Tick},
6665
};
6766

67+
use polkadot_node_primitives::approval::time::{slot_number_to_tick, Tick};
68+
6869
use super::{State, LOG_TARGET};
6970

7071
#[derive(Debug)]
@@ -574,9 +575,13 @@ pub(crate) async fn handle_new_head<Context, B: Backend>(
574575
hash: block_hash,
575576
number: block_header.number,
576577
parent_hash: block_header.parent_hash,
577-
candidates: included_candidates.iter().map(|(hash, _, _, _)| *hash).collect(),
578+
candidates: included_candidates
579+
.iter()
580+
.map(|(hash, _, core_index, group_index)| (*hash, *core_index, *group_index))
581+
.collect(),
578582
slot,
579583
session: session_index,
584+
vrf_story: relay_vrf_story,
580585
});
581586

582587
imported_candidates.push(BlockImportedCandidates {
@@ -609,6 +614,7 @@ pub(crate) mod tests {
609614
approval_db::common::{load_block_entry, DbBackend},
610615
RuntimeInfo, RuntimeInfoConfig, MAX_BLOCKS_WITH_ASSIGNMENT_TIMESTAMPS,
611616
};
617+
use approval_types::time::Clock;
612618
use assert_matches::assert_matches;
613619
use polkadot_node_primitives::{
614620
approval::v1::{VrfSignature, VrfTranscript},
@@ -642,7 +648,7 @@ pub(crate) mod tests {
642648
#[derive(Default)]
643649
struct MockClock;
644650

645-
impl crate::time::Clock for MockClock {
651+
impl Clock for MockClock {
646652
fn tick_now(&self) -> Tick {
647653
42 // chosen by fair dice roll
648654
}

0 commit comments

Comments
 (0)