polkadot_subsystem_bench/approval/
test_message.rs1use crate::{
18 approval::{ApprovalsOptions, BlockTestData, CandidateTestData},
19 configuration::TestAuthorities,
20};
21use codec::{Decode, Encode};
22use itertools::Itertools;
23use polkadot_node_network_protocol::v3 as protocol_v3;
24use polkadot_primitives::{CandidateIndex, Hash, ValidatorIndex};
25use sc_network_types::PeerId;
26use std::collections::{HashMap, HashSet};
27
28#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
29pub struct TestMessageInfo {
30 pub msg: protocol_v3::ApprovalDistributionMessage,
32 pub sent_by: Vec<ValidatorIndex>,
36 pub tranche: u32,
38 pub block_hash: Hash,
40}
41
42impl std::hash::Hash for TestMessageInfo {
43 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
44 match &self.msg {
45 protocol_v3::ApprovalDistributionMessage::Assignments(assignments) => {
46 for (assignment, candidates) in assignments {
47 (assignment.block_hash, assignment.validator).hash(state);
48 candidates.hash(state);
49 }
50 },
51 protocol_v3::ApprovalDistributionMessage::Approvals(approvals) => {
52 for approval in approvals {
53 (approval.block_hash, approval.validator).hash(state);
54 approval.candidate_indices.hash(state);
55 }
56 },
57 };
58 }
59}
60
61#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
62pub struct MessagesBundle {
65 pub assignments: Vec<TestMessageInfo>,
66 pub approvals: Vec<TestMessageInfo>,
67}
68
69impl MessagesBundle {
70 pub fn tranche_to_send(&self) -> u32 {
73 self.assignments
74 .iter()
75 .chain(self.approvals.iter())
76 .max_by(|a, b| a.tranche.cmp(&b.tranche))
77 .unwrap()
78 .tranche
79 }
80
81 pub fn min_tranche(&self) -> u32 {
83 self.assignments
84 .iter()
85 .chain(self.approvals.iter())
86 .min_by(|a, b| a.tranche.cmp(&b.tranche))
87 .unwrap()
88 .tranche
89 }
90
91 pub fn should_send(
95 &self,
96 candidates_test_data: &HashMap<(Hash, CandidateIndex), CandidateTestData>,
97 options: &ApprovalsOptions,
98 ) -> bool {
99 self.needed_for_approval(candidates_test_data) ||
100 (!options.stop_when_approved &&
101 self.min_tranche() <= options.last_considered_tranche)
102 }
103
104 pub fn needed_for_approval(
106 &self,
107 candidates_test_data: &HashMap<(Hash, CandidateIndex), CandidateTestData>,
108 ) -> bool {
109 self.assignments
110 .iter()
111 .any(|message| message.needed_for_approval(candidates_test_data))
112 }
113
114 pub fn record_sent_assignment(
116 &self,
117 candidates_test_data: &mut HashMap<(Hash, CandidateIndex), CandidateTestData>,
118 ) {
119 self.assignments
120 .iter()
121 .for_each(|assignment| assignment.record_sent_assignment(candidates_test_data));
122 }
123}
124
125impl TestMessageInfo {
126 fn is_approval(&self) -> bool {
128 match self.msg {
129 protocol_v3::ApprovalDistributionMessage::Assignments(_) => false,
130 protocol_v3::ApprovalDistributionMessage::Approvals(_) => true,
131 }
132 }
133
134 pub fn record_vote(&self, state: &BlockTestData) {
138 if self.is_approval() {
139 match &self.msg {
140 protocol_v3::ApprovalDistributionMessage::Assignments(_) => todo!(),
141 protocol_v3::ApprovalDistributionMessage::Approvals(approvals) =>
142 for approval in approvals {
143 for candidate_index in approval.candidate_indices.iter_ones() {
144 state
145 .votes
146 .get(approval.validator.0 as usize)
147 .unwrap()
148 .get(candidate_index)
149 .unwrap()
150 .store(true, std::sync::atomic::Ordering::SeqCst);
151 }
152 },
153 }
154 }
155 }
156
157 pub fn record_sent_assignment(
159 &self,
160 candidates_test_data: &mut HashMap<(Hash, CandidateIndex), CandidateTestData>,
161 ) {
162 match &self.msg {
163 protocol_v3::ApprovalDistributionMessage::Assignments(assignments) => {
164 for (assignment, candidate_indices) in assignments {
165 for candidate_index in candidate_indices.iter_ones() {
166 let candidate_test_data = candidates_test_data
167 .get_mut(&(assignment.block_hash, candidate_index as CandidateIndex))
168 .unwrap();
169 candidate_test_data.mark_sent_assignment(self.tranche)
170 }
171 }
172 },
173 protocol_v3::ApprovalDistributionMessage::Approvals(_approvals) => todo!(),
174 }
175 }
176
177 pub fn candidate_indices(&self) -> HashSet<usize> {
179 let mut unique_candidate_indices = HashSet::new();
180 match &self.msg {
181 protocol_v3::ApprovalDistributionMessage::Assignments(assignments) =>
182 for (_assignment, candidate_indices) in assignments {
183 for candidate_index in candidate_indices.iter_ones() {
184 unique_candidate_indices.insert(candidate_index);
185 }
186 },
187 protocol_v3::ApprovalDistributionMessage::Approvals(approvals) =>
188 for approval in approvals {
189 for candidate_index in approval.candidate_indices.iter_ones() {
190 unique_candidate_indices.insert(candidate_index);
191 }
192 },
193 }
194 unique_candidate_indices
195 }
196
197 pub fn no_show_if_required(
201 &self,
202 assignments: &[TestMessageInfo],
203 candidates_test_data: &mut HashMap<(Hash, CandidateIndex), CandidateTestData>,
204 ) -> bool {
205 let mut should_no_show = false;
206 if self.is_approval() {
207 let covered_candidates = assignments
208 .iter()
209 .map(|assignment| (assignment, assignment.candidate_indices()))
210 .collect_vec();
211
212 match &self.msg {
213 protocol_v3::ApprovalDistributionMessage::Assignments(_) => todo!(),
214 protocol_v3::ApprovalDistributionMessage::Approvals(approvals) => {
215 assert_eq!(approvals.len(), 1);
216
217 for approval in approvals {
218 should_no_show = should_no_show ||
219 approval.candidate_indices.iter_ones().all(|candidate_index| {
220 let candidate_test_data = candidates_test_data
221 .get_mut(&(
222 approval.block_hash,
223 candidate_index as CandidateIndex,
224 ))
225 .unwrap();
226 let assignment = covered_candidates
227 .iter()
228 .find(|(_assignment, candidates)| {
229 candidates.contains(&candidate_index)
230 })
231 .unwrap();
232 candidate_test_data.should_no_show(assignment.0.tranche)
233 });
234
235 if should_no_show {
236 for candidate_index in approval.candidate_indices.iter_ones() {
237 let candidate_test_data = candidates_test_data
238 .get_mut(&(
239 approval.block_hash,
240 candidate_index as CandidateIndex,
241 ))
242 .unwrap();
243 let assignment = covered_candidates
244 .iter()
245 .find(|(_assignment, candidates)| {
246 candidates.contains(&candidate_index)
247 })
248 .unwrap();
249 candidate_test_data.record_no_show(assignment.0.tranche)
250 }
251 }
252 }
253 },
254 }
255 }
256 should_no_show
257 }
258
259 pub fn needed_for_approval(
261 &self,
262 candidates_test_data: &HashMap<(Hash, CandidateIndex), CandidateTestData>,
263 ) -> bool {
264 match &self.msg {
265 protocol_v3::ApprovalDistributionMessage::Assignments(assignments) =>
266 assignments.iter().any(|(assignment, candidate_indices)| {
267 candidate_indices.iter_ones().any(|candidate_index| {
268 candidates_test_data
269 .get(&(assignment.block_hash, candidate_index as CandidateIndex))
270 .map(|data| data.should_send_tranche(self.tranche))
271 .unwrap_or_default()
272 })
273 }),
274 protocol_v3::ApprovalDistributionMessage::Approvals(approvals) =>
275 approvals.iter().any(|approval| {
276 approval.candidate_indices.iter_ones().any(|candidate_index| {
277 candidates_test_data
278 .get(&(approval.block_hash, candidate_index as CandidateIndex))
279 .map(|data| data.should_send_tranche(self.tranche))
280 .unwrap_or_default()
281 })
282 }),
283 }
284 }
285
286 pub fn split_by_peer_id(
289 self,
290 authorities: &TestAuthorities,
291 ) -> HashMap<(ValidatorIndex, PeerId), Vec<TestMessageInfo>> {
292 let mut result: HashMap<(ValidatorIndex, PeerId), Vec<TestMessageInfo>> = HashMap::new();
293
294 for validator_index in &self.sent_by {
295 let peer = authorities.peer_ids.get(validator_index.0 as usize).unwrap();
296 result.entry((*validator_index, *peer)).or_default().push(TestMessageInfo {
297 msg: self.msg.clone(),
298 sent_by: Default::default(),
299 tranche: self.tranche,
300 block_hash: self.block_hash,
301 });
302 }
303 result
304 }
305}