polkadot_node_core_pvf_checker/
interest_view.rs1use polkadot_primitives::{Hash, ValidationCodeHash};
18use std::collections::{
19 btree_map::{self, BTreeMap},
20 HashSet,
21};
22
23#[derive(Copy, Clone, Debug)]
25pub enum Judgement {
26 Valid,
27 Invalid,
28}
29
30impl Judgement {
31 pub fn is_valid(&self) -> bool {
33 match self {
34 Judgement::Valid => true,
35 Judgement::Invalid => false,
36 }
37 }
38}
39
40#[derive(Default, Debug)]
42struct PvfData {
43 judgement: Option<Judgement>,
46
47 seen_in: HashSet<Hash>,
49}
50
51impl PvfData {
52 fn pending(origin: Hash) -> Self {
54 let mut seen_in = HashSet::with_capacity(5);
57 seen_in.insert(origin);
58 Self { judgement: None, seen_in }
59 }
60
61 pub fn seen_in(&mut self, relay_hash: Hash) {
63 self.seen_in.insert(relay_hash);
64 }
65
66 pub fn remove_origin(&mut self, relay_hash: &Hash) -> bool {
68 self.seen_in.remove(relay_hash);
69 self.seen_in.is_empty()
70 }
71}
72
73pub struct OnLeavesUpdateOutcome {
75 pub newcomers: Vec<ValidationCodeHash>,
77 pub left_num: usize,
79}
80
81#[derive(Debug)]
84pub struct InterestView {
85 active_leaves: BTreeMap<Hash, HashSet<ValidationCodeHash>>,
86 pvfs: BTreeMap<ValidationCodeHash, PvfData>,
87}
88
89impl InterestView {
90 pub fn new() -> Self {
91 Self { active_leaves: BTreeMap::new(), pvfs: BTreeMap::new() }
92 }
93
94 pub fn on_leaves_update(
95 &mut self,
96 activated: Option<(Hash, Vec<ValidationCodeHash>)>,
97 deactivated: &[Hash],
98 ) -> OnLeavesUpdateOutcome {
99 let mut newcomers = Vec::new();
100
101 if let Some((leaf, pending_pvfs)) = activated {
102 for pvf in &pending_pvfs {
103 match self.pvfs.entry(*pvf) {
104 btree_map::Entry::Vacant(v) => {
105 v.insert(PvfData::pending(leaf));
106 newcomers.push(*pvf);
107 },
108 btree_map::Entry::Occupied(mut o) => {
109 o.get_mut().seen_in(leaf);
110 },
111 }
112 }
113 self.active_leaves.entry(leaf).or_default().extend(pending_pvfs);
114 }
115
116 let mut left_num = 0;
117 for leaf in deactivated {
118 let pvfs = self.active_leaves.remove(leaf);
119 for pvf in pvfs.into_iter().flatten() {
120 if let btree_map::Entry::Occupied(mut o) = self.pvfs.entry(pvf) {
121 let now_empty = o.get_mut().remove_origin(leaf);
122 if now_empty {
123 left_num += 1;
124 o.remove();
125 }
126 }
127 }
128 }
129
130 OnLeavesUpdateOutcome { newcomers, left_num }
131 }
132
133 pub fn on_judgement(
137 &mut self,
138 subject: ValidationCodeHash,
139 judgement: Judgement,
140 ) -> Result<(), ()> {
141 match self.pvfs.get_mut(&subject) {
142 Some(data) => {
143 data.judgement = Some(judgement);
144 Ok(())
145 },
146 None => Err(()),
147 }
148 }
149
150 pub fn judgements(&self) -> impl Iterator<Item = (ValidationCodeHash, Judgement)> + '_ {
152 self.pvfs
153 .iter()
154 .filter_map(|(code_hash, data)| data.judgement.map(|judgement| (*code_hash, judgement)))
155 }
156}