1use crate::{
2 algos::et::convergence_check,
3 merkle::{self, fixed::DenseMerkleTree, hash_leaf, Hash},
4 tx::trust::{ScoreEntry, TrustEntry},
5 Domain, DomainHash,
6};
7use getset::Getters;
8use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
9use sha3::Keccak256;
10use std::collections::{BTreeMap, HashMap};
11use tracing::info;
12
13use super::{BaseRunner, Error as BaseError};
14
15#[derive(Getters)]
16#[getset(get = "pub")]
17pub struct VerificationRunner {
19 base: BaseRunner,
20 compute_scores: HashMap<DomainHash, HashMap<Hash, Vec<ScoreEntry>>>,
21 compute_tree: HashMap<DomainHash, HashMap<Hash, DenseMerkleTree<Keccak256>>>,
22 commitments: HashMap<Hash, Hash>,
23}
24
25impl VerificationRunner {
26 pub fn new(domains: &[Domain]) -> Self {
27 let base = BaseRunner::new(domains);
28 let mut compute_scores = HashMap::new();
29 let mut compute_tree = HashMap::new();
30 for domain in domains {
31 let domain_hash = domain.to_hash();
32 compute_scores.insert(domain_hash, HashMap::new());
33 compute_tree.insert(domain_hash, HashMap::new());
34 }
35 Self {
36 base,
37 compute_scores,
38 compute_tree,
39 commitments: HashMap::new(),
40 }
41 }
42
43 pub fn update_trust(
45 &mut self,
46 domain: Domain,
47 trust_entries: Vec<TrustEntry>,
48 ) -> Result<(), Error> {
49 self.base
50 .update_trust(domain, trust_entries)
51 .map_err(Error::Base)
52 }
53
54 pub fn update_trust_map(
55 &mut self,
56 domain: Domain,
57 trust_entries: Vec<TrustEntry>,
58 ) -> Result<(), Error> {
59 self.base
60 .update_trust_map(domain, trust_entries)
61 .map_err(Error::Base)
62 }
63
64 pub fn update_seed(
66 &mut self,
67 domain: Domain,
68 seed_entries: Vec<ScoreEntry>,
69 ) -> Result<(), Error> {
70 self.base
71 .update_seed(domain, seed_entries)
72 .map_err(Error::Base)
73 }
74
75 pub fn update_seed_map(
76 &mut self,
77 domain: Domain,
78 seed_entries: Vec<ScoreEntry>,
79 ) -> Result<(), Error> {
80 self.base
81 .update_seed_map(domain, seed_entries)
82 .map_err(Error::Base)
83 }
84
85 pub fn update_commitment(&mut self, compute_id: Hash, commitment: Hash) {
87 self.commitments.insert(compute_id, commitment);
88 }
89
90 pub fn update_scores(
92 &mut self,
93 domain: Domain,
94 compute_id: Hash,
95 compute_scores: Vec<ScoreEntry>,
96 ) -> Result<(), Error> {
97 let score_values = self
98 .compute_scores
99 .get_mut(&domain.clone().to_hash())
100 .ok_or(Error::ComputeScoresNotFoundWithDomain(domain.to_hash()))?;
101 score_values.insert(compute_id, compute_scores);
102 Ok(())
103 }
104
105 pub fn verify_job(&mut self, domain: Domain, compute_id: Hash) -> Result<bool, Error> {
107 info!("COMPLETED_ASSIGNMENT_SEARCH: {}", domain.to_hash());
108 let commitment = self.commitments.get(&compute_id.clone()).unwrap();
109 let cp_root = commitment.clone();
110
111 self.create_compute_tree(domain.clone(), compute_id.clone())?;
112 let (res_lt_root, res_compute_root) =
113 self.get_root_hashes(domain.clone(), compute_id.clone())?;
114 info!(
115 "LT_ROOT: {}, COMPUTE_ROOT: {}",
116 res_lt_root, res_compute_root
117 );
118 let is_root_equal = cp_root == res_compute_root;
119 let is_converged = self.compute_verification(domain.clone(), compute_id.clone())?;
120 info!(
121 "COMPLETED_ASSIGNMENT, DOMAIN: {}, is_root_equal: {}, is_converged: {}",
122 domain.to_hash(),
123 is_root_equal,
124 is_converged,
125 );
126
127 return Ok(is_root_equal && is_converged);
128 }
129
130 pub fn verify_scores(&mut self, domain: Domain, compute_id: Hash) -> Result<bool, Error> {
132 info!("COMPLETED_ASSIGNMENT_SEARCH: {}", domain.to_hash());
133
134 self.create_compute_tree(domain.clone(), compute_id.clone())?;
135 let (res_lt_root, res_compute_root) =
136 self.get_root_hashes(domain.clone(), compute_id.clone())?;
137 info!(
138 "LT_ROOT: {}, COMPUTE_ROOT: {}",
139 res_lt_root, res_compute_root
140 );
141 let is_converged = self.compute_verification(domain.clone(), compute_id.clone())?;
142 info!(
143 "COMPLETED_ASSIGNMENT, DOMAIN: {}, is_converged: {}",
144 domain.to_hash(),
145 is_converged,
146 );
147
148 return Ok(is_converged);
149 }
150
151 fn create_compute_tree(&mut self, domain: Domain, compute_id: Hash) -> Result<(), Error> {
153 info!("CREATE_COMPUTE_TREE: {}", domain.to_hash());
154 let compute_tree_map = self
155 .compute_tree
156 .get_mut(&domain.to_hash())
157 .ok_or(Error::ComputeTreeNotFoundWithDomain(domain.to_hash()))?;
158 let compute_scores = self
159 .compute_scores
160 .get(&domain.to_hash())
161 .ok_or(Error::ComputeScoresNotFoundWithDomain(domain.to_hash()))?;
162 let scores = compute_scores.get(&compute_id).unwrap();
163 let score_entries: Vec<f32> = scores.iter().map(|x| *x.value()).collect();
164 let score_hashes: Vec<Hash> = score_entries
165 .par_iter()
166 .map(|&x| hash_leaf::<Keccak256>(x.to_be_bytes().to_vec()))
167 .collect();
168 let compute_tree =
169 DenseMerkleTree::<Keccak256>::new(score_hashes).map_err(Error::Merkle)?;
170 info!(
171 "COMPUTE_TREE_ROOT_HASH: {}",
172 compute_tree.root().map_err(Error::Merkle)?
173 );
174 compute_tree_map.insert(compute_id, compute_tree);
175
176 Ok(())
177 }
178
179 fn compute_verification(&mut self, domain: Domain, compute_id: Hash) -> Result<bool, Error> {
181 let compute_scores = self
182 .compute_scores
183 .get(&domain.to_hash())
184 .ok_or(Error::ComputeScoresNotFoundWithDomain(domain.to_hash()))?;
185 let domain_indices = self
186 .base
187 .indices
188 .get(&domain.to_hash())
189 .ok_or::<Error>(BaseError::IndicesNotFound(domain.to_hash()).into())?;
190 let lt = self
191 .base
192 .local_trust
193 .get(&domain.trust_namespace())
194 .ok_or::<Error>(BaseError::LocalTrustNotFound(domain.trust_namespace()).into())?;
195 let count = self
196 .base
197 .count
198 .get(&domain.to_hash())
199 .ok_or::<Error>(BaseError::CountNotFound(domain.to_hash()).into())?;
200 let seed = self
201 .base
202 .seed_trust
203 .get(&domain.seed_namespace())
204 .ok_or::<Error>(BaseError::SeedTrustNotFound(domain.seed_namespace()).into())?;
205 let scores = compute_scores.get(&compute_id).unwrap();
206 let score_entries: BTreeMap<u64, f32> = {
207 let mut score_entries_map: BTreeMap<u64, f32> = BTreeMap::new();
208 for entry in scores {
209 let i = domain_indices
210 .get(entry.id())
211 .ok_or(Error::DomainIndexNotFound(entry.id().clone()))?;
212 score_entries_map.insert(*i, *entry.value());
213 }
214 score_entries_map
215 };
216 Ok(convergence_check(
217 lt.clone(),
218 seed.clone(),
219 &score_entries,
220 *count,
221 ))
222 }
223
224 pub fn get_root_hashes(
226 &self,
227 domain: Domain,
228 assignment_id: Hash,
229 ) -> Result<(Hash, Hash), Error> {
230 let tree_roots = self.base.get_base_root_hashes(&domain)?;
231
232 let compute_tree_map = self
233 .compute_tree
234 .get(&domain.to_hash())
235 .ok_or(Error::ComputeTreeNotFoundWithDomain(domain.to_hash()))?;
236 let compute_tree = compute_tree_map.get(&assignment_id).unwrap();
237 let ct_tree_root = compute_tree.root().map_err(Error::Merkle)?;
238
239 Ok((tree_roots, ct_tree_root))
240 }
241}
242
243#[derive(thiserror::Error, Debug)]
244pub enum Error {
245 #[error("{0}")]
246 Base(BaseError),
247 #[error("compute_tree not found for domain: {0}")]
248 ComputeTreeNotFoundWithDomain(DomainHash),
249 #[error("compute_scores not found for domain: {0}")]
250 ComputeScoresNotFoundWithDomain(DomainHash),
251 #[error("active_assignments not found for domain: {0}")]
252 ActiveAssignmentsNotFound(DomainHash),
253 #[error("domain_indice not found for address: {0}")]
254 DomainIndexNotFound(String),
255 #[error("{0}")]
256 Merkle(merkle::Error),
257}
258
259impl From<BaseError> for Error {
260 fn from(err: BaseError) -> Self {
261 Self::Base(err)
262 }
263}