1use itertools::Itertools;
24use polkadot_node_primitives::approval::{
25 v1::{DelayTranche, RelayVRFStory},
26 v2::{AssignmentCertV2, CandidateBitfield},
27};
28use polkadot_primitives::{
29 BlockNumber, CandidateHash, CandidateIndex, CandidateReceiptV2 as CandidateReceipt, CoreIndex,
30 GroupIndex, Hash, SessionIndex, ValidatorIndex, ValidatorSignature,
31};
32use sp_consensus_slots::Slot;
33
34use bitvec::{order::Lsb0 as BitOrderLsb0, slice::BitSlice};
35use std::collections::BTreeMap;
36
37use crate::approval_db::v2::Bitfield;
38
39use super::criteria::OurAssignment;
40
41use polkadot_node_primitives::approval::time::Tick;
42
43#[derive(Debug, Clone, PartialEq)]
45pub struct TrancheEntry {
46 tranche: DelayTranche,
47 assignments: Vec<(ValidatorIndex, Tick)>,
50}
51
52impl TrancheEntry {
53 pub fn tranche(&self) -> DelayTranche {
55 self.tranche
56 }
57
58 pub fn assignments(&self) -> &[(ValidatorIndex, Tick)] {
60 &self.assignments
61 }
62}
63
64impl From<crate::approval_db::v2::TrancheEntry> for TrancheEntry {
65 fn from(entry: crate::approval_db::v2::TrancheEntry) -> Self {
66 TrancheEntry {
67 tranche: entry.tranche,
68 assignments: entry.assignments.into_iter().map(|(v, t)| (v, t.into())).collect(),
69 }
70 }
71}
72
73impl From<TrancheEntry> for crate::approval_db::v2::TrancheEntry {
74 fn from(entry: TrancheEntry) -> Self {
75 Self {
76 tranche: entry.tranche,
77 assignments: entry.assignments.into_iter().map(|(v, t)| (v, t.into())).collect(),
78 }
79 }
80}
81
82impl From<crate::approval_db::v3::OurApproval> for OurApproval {
83 fn from(approval: crate::approval_db::v3::OurApproval) -> Self {
84 Self {
85 signature: approval.signature,
86 signed_candidates_indices: approval.signed_candidates_indices,
87 }
88 }
89}
90impl From<OurApproval> for crate::approval_db::v3::OurApproval {
91 fn from(approval: OurApproval) -> Self {
92 Self {
93 signature: approval.signature,
94 signed_candidates_indices: approval.signed_candidates_indices,
95 }
96 }
97}
98
99#[derive(Debug, Clone, PartialEq)]
101pub struct OurApproval {
102 pub signature: ValidatorSignature,
104 pub signed_candidates_indices: CandidateBitfield,
106}
107
108impl OurApproval {
109 pub fn from_v1(value: ValidatorSignature, candidate_index: CandidateIndex) -> Self {
112 Self { signature: value, signed_candidates_indices: candidate_index.into() }
113 }
114
115 pub fn from_v2(value: ValidatorSignature, candidate_index: CandidateIndex) -> Self {
118 Self::from_v1(value, candidate_index)
119 }
120}
121#[derive(Debug, Clone, PartialEq)]
124pub struct ApprovalEntry {
125 tranches: Vec<TrancheEntry>,
126 backing_group: GroupIndex,
127 our_assignment: Option<OurAssignment>,
128 our_approval_sig: Option<OurApproval>,
129 assigned_validators: Bitfield,
131 approved: bool,
132}
133
134impl ApprovalEntry {
135 pub fn new(
137 tranches: Vec<TrancheEntry>,
138 backing_group: GroupIndex,
139 our_assignment: Option<OurAssignment>,
140 our_approval_sig: Option<OurApproval>,
141 assigned_validators: Bitfield,
143 approved: bool,
144 ) -> Self {
145 Self {
146 tranches,
147 backing_group,
148 our_assignment,
149 our_approval_sig,
150 assigned_validators,
151 approved,
152 }
153 }
154
155 pub fn our_assignment(&self) -> Option<&OurAssignment> {
157 self.our_assignment.as_ref()
158 }
159
160 pub fn trigger_our_assignment(
162 &mut self,
163 tick_now: Tick,
164 ) -> Option<(AssignmentCertV2, ValidatorIndex, DelayTranche)> {
165 let our = self.our_assignment.as_mut().and_then(|a| {
166 if a.triggered() {
167 return None
168 }
169 a.mark_triggered();
170
171 Some(a.clone())
172 });
173
174 our.map(|a| {
175 self.import_assignment(a.tranche(), a.validator_index(), tick_now, false);
176
177 (a.cert().clone(), a.validator_index(), a.tranche())
178 })
179 }
180
181 pub fn import_approval_sig(&mut self, approval_sig: OurApproval) {
183 self.our_approval_sig = Some(approval_sig);
184 }
185
186 pub fn is_assigned(&self, validator_index: ValidatorIndex) -> bool {
188 self.assigned_validators
189 .get(validator_index.0 as usize)
190 .map(|b| *b)
191 .unwrap_or(false)
192 }
193
194 pub fn import_assignment(
196 &mut self,
197 tranche: DelayTranche,
198 validator_index: ValidatorIndex,
199 tick_now: Tick,
200 is_duplicate: bool,
201 ) {
202 let idx = match self.tranches.iter().position(|t| t.tranche >= tranche) {
204 Some(pos) => {
205 if self.tranches[pos].tranche > tranche {
206 self.tranches.insert(pos, TrancheEntry { tranche, assignments: Vec::new() });
207 }
208
209 pos
210 },
211 None => {
212 self.tranches.push(TrancheEntry { tranche, assignments: Vec::new() });
213
214 self.tranches.len() - 1
215 },
216 };
217 if !is_duplicate {
224 self.tranches[idx].assignments.push((validator_index, tick_now));
225 }
226 self.assigned_validators.set(validator_index.0 as _, true);
227 }
228
229 pub fn assignments_up_to(&self, tranche: DelayTranche) -> Bitfield {
232 self.tranches.iter().take_while(|e| e.tranche <= tranche).fold(
233 bitvec::bitvec![u8, BitOrderLsb0; 0; self.assigned_validators.len()],
234 |mut a, e| {
235 for &(v, _) in &e.assignments {
236 a.set(v.0 as _, true);
237 }
238
239 a
240 },
241 )
242 }
243
244 pub fn is_approved(&self) -> bool {
246 self.approved
247 }
248
249 pub fn mark_approved(&mut self) {
251 self.approved = true;
252 }
253
254 pub fn tranches(&self) -> &[TrancheEntry] {
256 &self.tranches
257 }
258
259 pub fn n_validators(&self) -> usize {
261 self.assigned_validators.len()
262 }
263
264 pub fn n_assignments(&self) -> usize {
266 self.assigned_validators.count_ones()
267 }
268
269 pub fn backing_group(&self) -> GroupIndex {
271 self.backing_group
272 }
273
274 pub fn local_statements(&self) -> (Option<OurAssignment>, Option<OurApproval>) {
278 let approval_sig = self.our_approval_sig.clone();
279 if let Some(our_assignment) = self.our_assignment.as_ref().filter(|a| a.triggered()) {
280 (Some(our_assignment.clone()), approval_sig)
281 } else {
282 (None, None)
283 }
284 }
285
286 pub fn from_v1(
288 value: crate::approval_db::v1::ApprovalEntry,
289 candidate_index: CandidateIndex,
290 ) -> Self {
291 ApprovalEntry {
292 tranches: value.tranches.into_iter().map(|tranche| tranche.into()).collect(),
293 backing_group: value.backing_group,
294 our_assignment: value.our_assignment.map(|assignment| assignment.into()),
295 our_approval_sig: value
296 .our_approval_sig
297 .map(|sig| OurApproval::from_v1(sig, candidate_index)),
298 assigned_validators: value.assignments,
299 approved: value.approved,
300 }
301 }
302
303 pub fn from_v2(
305 value: crate::approval_db::v2::ApprovalEntry,
306 candidate_index: CandidateIndex,
307 ) -> Self {
308 ApprovalEntry {
309 tranches: value.tranches.into_iter().map(|tranche| tranche.into()).collect(),
310 backing_group: value.backing_group,
311 our_assignment: value.our_assignment.map(|assignment| assignment.into()),
312 our_approval_sig: value
313 .our_approval_sig
314 .map(|sig| OurApproval::from_v2(sig, candidate_index)),
315 assigned_validators: value.assigned_validators,
316 approved: value.approved,
317 }
318 }
319}
320
321impl From<crate::approval_db::v3::ApprovalEntry> for ApprovalEntry {
322 fn from(entry: crate::approval_db::v3::ApprovalEntry) -> Self {
323 ApprovalEntry {
324 tranches: entry.tranches.into_iter().map(Into::into).collect(),
325 backing_group: entry.backing_group,
326 our_assignment: entry.our_assignment.map(Into::into),
327 our_approval_sig: entry.our_approval_sig.map(Into::into),
328 assigned_validators: entry.assigned_validators,
329 approved: entry.approved,
330 }
331 }
332}
333
334impl From<ApprovalEntry> for crate::approval_db::v3::ApprovalEntry {
335 fn from(entry: ApprovalEntry) -> Self {
336 Self {
337 tranches: entry.tranches.into_iter().map(Into::into).collect(),
338 backing_group: entry.backing_group,
339 our_assignment: entry.our_assignment.map(Into::into),
340 our_approval_sig: entry.our_approval_sig.map(Into::into),
341 assigned_validators: entry.assigned_validators,
342 approved: entry.approved,
343 }
344 }
345}
346
347#[derive(Debug, Clone, PartialEq)]
349pub struct CandidateEntry {
350 pub candidate: CandidateReceipt,
351 pub session: SessionIndex,
352 pub block_assignments: BTreeMap<Hash, ApprovalEntry>,
355 pub approvals: Bitfield,
356}
357
358impl CandidateEntry {
359 pub fn approvals(&self) -> &BitSlice<u8, BitOrderLsb0> {
361 &self.approvals
362 }
363
364 pub fn mark_approval(&mut self, validator: ValidatorIndex) -> bool {
366 let prev = self.has_approved(validator);
367 self.approvals.set(validator.0 as usize, true);
368 prev
369 }
370
371 pub fn has_approved(&self, validator: ValidatorIndex) -> bool {
373 self.approvals.get(validator.0 as usize).map(|b| *b).unwrap_or(false)
374 }
375
376 pub fn candidate_receipt(&self) -> &CandidateReceipt {
378 &self.candidate
379 }
380
381 pub fn approval_entry_mut(&mut self, block_hash: &Hash) -> Option<&mut ApprovalEntry> {
383 self.block_assignments.get_mut(block_hash)
384 }
385
386 pub fn approval_entry(&self, block_hash: &Hash) -> Option<&ApprovalEntry> {
388 self.block_assignments.get(block_hash)
389 }
390
391 pub fn from_v1(
393 value: crate::approval_db::v1::CandidateEntry,
394 candidate_index: CandidateIndex,
395 ) -> Self {
396 Self {
397 approvals: value.approvals,
398 block_assignments: value
399 .block_assignments
400 .into_iter()
401 .map(|(h, ae)| (h, ApprovalEntry::from_v1(ae, candidate_index)))
402 .collect(),
403 candidate: value.candidate,
404 session: value.session,
405 }
406 }
407
408 pub fn from_v2(
410 value: crate::approval_db::v2::CandidateEntry,
411 candidate_index: CandidateIndex,
412 ) -> Self {
413 Self {
414 approvals: value.approvals,
415 block_assignments: value
416 .block_assignments
417 .into_iter()
418 .map(|(h, ae)| (h, ApprovalEntry::from_v2(ae, candidate_index)))
419 .collect(),
420 candidate: value.candidate,
421 session: value.session,
422 }
423 }
424}
425
426impl From<crate::approval_db::v3::CandidateEntry> for CandidateEntry {
427 fn from(entry: crate::approval_db::v3::CandidateEntry) -> Self {
428 CandidateEntry {
429 candidate: entry.candidate,
430 session: entry.session,
431 block_assignments: entry
432 .block_assignments
433 .into_iter()
434 .map(|(h, ae)| (h, ae.into()))
435 .collect(),
436 approvals: entry.approvals,
437 }
438 }
439}
440
441impl From<CandidateEntry> for crate::approval_db::v3::CandidateEntry {
442 fn from(entry: CandidateEntry) -> Self {
443 Self {
444 candidate: entry.candidate,
445 session: entry.session,
446 block_assignments: entry
447 .block_assignments
448 .into_iter()
449 .map(|(h, ae)| (h, ae.into()))
450 .collect(),
451 approvals: entry.approvals,
452 }
453 }
454}
455
456#[derive(Debug, Clone, PartialEq)]
459pub struct BlockEntry {
460 block_hash: Hash,
461 parent_hash: Hash,
462 block_number: BlockNumber,
463 session: SessionIndex,
464 slot: Slot,
465 relay_vrf_story: RelayVRFStory,
466 candidates: Vec<(CoreIndex, CandidateHash)>,
469 pub approved_bitfield: Bitfield,
473 pub children: Vec<Hash>,
474 candidates_pending_signature: BTreeMap<CandidateIndex, CandidateSigningContext>,
477 distributed_assignments: Bitfield,
481}
482
483#[derive(Debug, Clone, PartialEq)]
484pub struct CandidateSigningContext {
485 pub candidate_hash: CandidateHash,
486 pub sign_no_later_than_tick: Tick,
487}
488
489impl BlockEntry {
490 pub fn mark_approved_by_hash(&mut self, candidate_hash: &CandidateHash) {
492 if let Some(p) = self.candidates.iter().position(|(_, h)| h == candidate_hash) {
493 self.approved_bitfield.set(p, true);
494 }
495 }
496
497 pub fn is_candidate_approved(&self, candidate_hash: &CandidateHash) -> bool {
499 self.candidates
500 .iter()
501 .position(|(_, h)| h == candidate_hash)
502 .and_then(|p| self.approved_bitfield.get(p).map(|b| *b))
503 .unwrap_or(false)
504 }
505
506 pub fn is_fully_approved(&self) -> bool {
508 self.approved_bitfield.all()
509 }
510
511 pub fn unapproved_candidates(&self) -> impl Iterator<Item = CandidateHash> + '_ {
513 self.approved_bitfield.iter().enumerate().filter_map(move |(i, a)| {
514 if !*a {
515 Some(self.candidates[i].1)
516 } else {
517 None
518 }
519 })
520 }
521
522 pub fn slot(&self) -> Slot {
524 self.slot
525 }
526
527 pub fn relay_vrf_story(&self) -> RelayVRFStory {
529 self.relay_vrf_story.clone()
530 }
531
532 pub fn session(&self) -> SessionIndex {
534 self.session
535 }
536
537 pub fn candidate(&self, i: usize) -> Option<&(CoreIndex, CandidateHash)> {
539 self.candidates.get(i)
540 }
541
542 pub fn candidates(&self) -> &[(CoreIndex, CandidateHash)] {
544 &self.candidates
545 }
546
547 pub fn block_number(&self) -> BlockNumber {
549 self.block_number
550 }
551
552 pub fn block_hash(&self) -> Hash {
554 self.block_hash
555 }
556
557 pub fn parent_hash(&self) -> Hash {
559 self.parent_hash
560 }
561
562 pub fn mark_assignment_distributed(&mut self, candidates: CandidateBitfield) -> bool {
565 let bitfield = candidates.into_inner();
566 let total_one_bits = self.distributed_assignments.count_ones();
567
568 let new_len = std::cmp::max(self.distributed_assignments.len(), bitfield.len());
569 self.distributed_assignments.resize(new_len, false);
570 self.distributed_assignments |= bitfield;
571
572 let distributed = total_one_bits == self.distributed_assignments.count_ones();
574
575 distributed
576 }
577
578 pub fn defer_candidate_signature(
580 &mut self,
581 candidate_index: CandidateIndex,
582 candidate_hash: CandidateHash,
583 sign_no_later_than_tick: Tick,
584 ) -> Option<CandidateSigningContext> {
585 self.candidates_pending_signature.insert(
586 candidate_index,
587 CandidateSigningContext { candidate_hash, sign_no_later_than_tick },
588 )
589 }
590
591 pub fn num_candidates_pending_signature(&self) -> usize {
593 self.candidates_pending_signature.len()
594 }
595
596 pub fn has_candidates_pending_signature(&self) -> bool {
598 !self.candidates_pending_signature.is_empty()
599 }
600
601 pub fn candidate_is_pending_signature(&self, candidate_hash: CandidateHash) -> bool {
603 self.candidates_pending_signature
604 .values()
605 .any(|context| context.candidate_hash == candidate_hash)
606 }
607
608 fn candidate_hashes_pending_signature(&self) -> Vec<CandidateHash> {
610 self.candidates_pending_signature
611 .values()
612 .map(|unsigned_approval| unsigned_approval.candidate_hash)
613 .collect()
614 }
615
616 fn candidate_indices_pending_signature(&self) -> Option<CandidateBitfield> {
618 self.candidates_pending_signature
619 .keys()
620 .map(|val| *val)
621 .collect_vec()
622 .try_into()
623 .ok()
624 }
625
626 pub fn get_candidates_that_need_signature(
634 &self,
635 tick_now: Tick,
636 max_approval_coalesce_count: u32,
637 ) -> (Option<(Vec<CandidateHash>, CandidateBitfield)>, Option<Tick>) {
638 let sign_no_later_than_tick = self
639 .candidates_pending_signature
640 .values()
641 .min_by(|a, b| a.sign_no_later_than_tick.cmp(&b.sign_no_later_than_tick))
642 .map(|val| val.sign_no_later_than_tick);
643
644 if let Some(sign_no_later_than_tick) = sign_no_later_than_tick {
645 if sign_no_later_than_tick <= tick_now ||
646 self.num_candidates_pending_signature() >= max_approval_coalesce_count as usize
647 {
648 (
649 self.candidate_indices_pending_signature().and_then(|candidate_indices| {
650 Some((self.candidate_hashes_pending_signature(), candidate_indices))
651 }),
652 Some(sign_no_later_than_tick),
653 )
654 } else {
655 (Default::default(), Some(sign_no_later_than_tick))
658 }
659 } else {
660 (Default::default(), sign_no_later_than_tick)
664 }
665 }
666
667 pub fn issued_approval(&mut self) {
669 self.candidates_pending_signature.clear();
670 }
671}
672
673impl From<crate::approval_db::v3::BlockEntry> for BlockEntry {
674 fn from(entry: crate::approval_db::v3::BlockEntry) -> Self {
675 BlockEntry {
676 block_hash: entry.block_hash,
677 parent_hash: entry.parent_hash,
678 block_number: entry.block_number,
679 session: entry.session,
680 slot: entry.slot,
681 relay_vrf_story: RelayVRFStory(entry.relay_vrf_story),
682 candidates: entry.candidates,
683 approved_bitfield: entry.approved_bitfield,
684 children: entry.children,
685 candidates_pending_signature: entry
686 .candidates_pending_signature
687 .into_iter()
688 .map(|(candidate_index, signing_context)| (candidate_index, signing_context.into()))
689 .collect(),
690 distributed_assignments: entry.distributed_assignments,
691 }
692 }
693}
694
695impl From<crate::approval_db::v1::BlockEntry> for BlockEntry {
696 fn from(entry: crate::approval_db::v1::BlockEntry) -> Self {
697 BlockEntry {
698 block_hash: entry.block_hash,
699 parent_hash: entry.parent_hash,
700 block_number: entry.block_number,
701 session: entry.session,
702 slot: entry.slot,
703 relay_vrf_story: RelayVRFStory(entry.relay_vrf_story),
704 candidates: entry.candidates,
705 approved_bitfield: entry.approved_bitfield,
706 children: entry.children,
707 distributed_assignments: Default::default(),
708 candidates_pending_signature: Default::default(),
709 }
710 }
711}
712
713impl From<crate::approval_db::v2::BlockEntry> for BlockEntry {
714 fn from(entry: crate::approval_db::v2::BlockEntry) -> Self {
715 BlockEntry {
716 block_hash: entry.block_hash,
717 parent_hash: entry.parent_hash,
718 block_number: entry.block_number,
719 session: entry.session,
720 slot: entry.slot,
721 relay_vrf_story: RelayVRFStory(entry.relay_vrf_story),
722 candidates: entry.candidates,
723 approved_bitfield: entry.approved_bitfield,
724 children: entry.children,
725 distributed_assignments: entry.distributed_assignments,
726 candidates_pending_signature: Default::default(),
727 }
728 }
729}
730
731impl From<BlockEntry> for crate::approval_db::v3::BlockEntry {
732 fn from(entry: BlockEntry) -> Self {
733 Self {
734 block_hash: entry.block_hash,
735 parent_hash: entry.parent_hash,
736 block_number: entry.block_number,
737 session: entry.session,
738 slot: entry.slot,
739 relay_vrf_story: entry.relay_vrf_story.0,
740 candidates: entry.candidates,
741 approved_bitfield: entry.approved_bitfield,
742 children: entry.children,
743 candidates_pending_signature: entry
744 .candidates_pending_signature
745 .into_iter()
746 .map(|(candidate_index, signing_context)| (candidate_index, signing_context.into()))
747 .collect(),
748 distributed_assignments: entry.distributed_assignments,
749 }
750 }
751}
752
753impl From<crate::approval_db::v3::CandidateSigningContext> for CandidateSigningContext {
754 fn from(signing_context: crate::approval_db::v3::CandidateSigningContext) -> Self {
755 Self {
756 candidate_hash: signing_context.candidate_hash,
757 sign_no_later_than_tick: signing_context.sign_no_later_than_tick.into(),
758 }
759 }
760}
761
762impl From<CandidateSigningContext> for crate::approval_db::v3::CandidateSigningContext {
763 fn from(signing_context: CandidateSigningContext) -> Self {
764 Self {
765 candidate_hash: signing_context.candidate_hash,
766 sign_no_later_than_tick: signing_context.sign_no_later_than_tick.into(),
767 }
768 }
769}