1use crate::{
2 evaluation::{response::EvaluatorError, runner::types::EvaluateInfo},
3 governance::data::GovernanceData,
4 model::common::viewpoints::validate_fact_viewpoints,
5};
6use ave_common::{
7 Namespace, SchemaType, ValueWrapper,
8 identity::{DigestIdentifier, PublicKey, Signed},
9 request::EventRequest,
10};
11
12use borsh::{BorshDeserialize, BorshSerialize};
13use serde::{Deserialize, Serialize};
14use std::collections::{BTreeMap, BTreeSet};
15
16#[derive(Debug, Clone, Default)]
17pub enum EvalWorkerContext {
18 #[default]
19 Empty,
20 Governance {
21 issuers: BTreeSet<PublicKey>,
22 issuer_any: bool,
23 },
24 TrackerFact {
25 issuers: BTreeSet<PublicKey>,
26 issuer_any: bool,
27 schema_viewpoints: BTreeSet<String>,
28 },
29 TrackerTransfer {
30 members: BTreeSet<PublicKey>,
31 creators: BTreeMap<PublicKey, BTreeSet<Namespace>>,
32 },
33}
34
35impl EvalWorkerContext {
36 pub const fn issuers(&self) -> Option<(&BTreeSet<PublicKey>, bool)> {
37 match self {
38 Self::Governance {
39 issuers,
40 issuer_any,
41 }
42 | Self::TrackerFact {
43 issuers,
44 issuer_any,
45 ..
46 } => Some((issuers, *issuer_any)),
47 Self::Empty | Self::TrackerTransfer { .. } => None,
48 }
49 }
50}
51
52#[derive(
54 Debug, Clone, Serialize, Deserialize, BorshSerialize, BorshDeserialize,
55)]
56pub struct EvaluationReq {
57 pub event_request: Signed<EventRequest>,
59
60 pub governance_id: DigestIdentifier,
61
62 pub data: EvaluateData,
63
64 pub sn: u64,
65
66 pub gov_version: u64,
67
68 pub namespace: Namespace,
69
70 pub schema_id: SchemaType,
71
72 pub signer: PublicKey,
73
74 pub signer_is_owner: bool,
75}
76
77impl EvaluationReq {
78 fn validate_fact_viewpoints(
79 fact_viewpoints: &BTreeSet<String>,
80 schema_id: &SchemaType,
81 schema_viewpoints: Option<&BTreeSet<String>>,
82 ) -> Result<(), EvaluatorError> {
83 validate_fact_viewpoints(fact_viewpoints, schema_id, schema_viewpoints)
84 .map_err(EvaluatorError::InvalidEventRequest)
85 }
86
87 pub fn build_evaluate_info(
88 &self,
89 init_state: &Option<ValueWrapper>,
90 worker_context: &EvalWorkerContext,
91 ) -> Result<EvaluateInfo, EvaluatorError> {
92 match (self.event_request.content(), &self.data) {
93 (
94 EventRequest::Fact(fact_request),
95 EvaluateData::GovFact { state },
96 ) => {
97 Self::validate_fact_viewpoints(
98 &fact_request.viewpoints,
99 &self.schema_id,
100 None,
101 )?;
102
103 Ok(EvaluateInfo::GovFact {
104 payload: fact_request.payload.clone(),
105 state: state.clone(),
106 })
107 }
108 (
109 EventRequest::Fact(fact_request),
110 EvaluateData::TrackerSchemasFact { state },
111 ) => init_state.as_ref().map_or_else(
112 || {
113 Err(EvaluatorError::InternalError(
114 "Init state must be some".to_owned(),
115 ))
116 },
117 |init_state| {
118 let EvalWorkerContext::TrackerFact {
119 schema_viewpoints,
120 ..
121 } = worker_context
122 else {
123 return Err(EvaluatorError::InternalError(
124 "Tracker fact evaluation context is missing"
125 .to_owned(),
126 ));
127 };
128
129 Self::validate_fact_viewpoints(
130 &fact_request.viewpoints,
131 &self.schema_id,
132 Some(schema_viewpoints),
133 )?;
134
135 Ok(EvaluateInfo::TrackerSchemasFact {
136 contract: format!(
137 "{}_{}",
138 self.governance_id, self.schema_id
139 ),
140 init_state: init_state.clone(),
141 state: state.clone(),
142 payload: fact_request.payload.clone(),
143 })
144 },
145 ),
146 (
147 EventRequest::Transfer(transfer_request),
148 EvaluateData::GovTransfer { state },
149 ) => Ok(EvaluateInfo::GovTransfer {
150 new_owner: transfer_request.new_owner.clone(),
151 state: state.clone(),
152 }),
153 (
154 EventRequest::Transfer(transfer_request),
155 EvaluateData::TrackerSchemasTransfer { .. },
156 ) => {
157 let EvalWorkerContext::TrackerTransfer { members, creators } =
158 worker_context
159 else {
160 return Err(EvaluatorError::InternalError(
161 "Tracker transfer evaluation context is missing"
162 .to_owned(),
163 ));
164 };
165
166 Ok(EvaluateInfo::TrackerSchemasTransfer {
167 new_owner: transfer_request.new_owner.clone(),
168 old_owner: self.event_request.signature().signer.clone(),
169 namespace: self.namespace.clone(),
170 schema_id: self.schema_id.clone(),
171 members: members.clone(),
172 creators: creators.clone(),
173 })
174 }
175 (
176 EventRequest::Confirm(confirm_request),
177 EvaluateData::GovConfirm { state },
178 ) => Ok(EvaluateInfo::GovConfirm {
179 new_owner: self.event_request.signature().signer.clone(),
180 old_owner_name: confirm_request.name_old_owner.clone(),
181 state: state.clone(),
182 }),
183 _ => Err(EvaluatorError::InvalidEventRequest(
184 "Evaluate data does not correspond to the type of request"
185 .to_string(),
186 )),
187 }
188 }
189}
190
191#[derive(
192 Debug, Clone, Serialize, Deserialize, BorshSerialize, BorshDeserialize,
193)]
194pub enum EvaluateData {
195 GovFact { state: GovernanceData },
196 GovTransfer { state: GovernanceData },
197 GovConfirm { state: GovernanceData },
198 TrackerSchemasFact { state: ValueWrapper },
199 TrackerSchemasTransfer { state: ValueWrapper },
200}
201
202impl EvaluateData {
203 pub const fn is_gov_event(&self) -> bool {
204 match self {
205 Self::GovFact { .. }
206 | Self::GovTransfer { .. }
207 | Self::GovConfirm { .. } => true,
208 Self::TrackerSchemasFact { .. }
209 | Self::TrackerSchemasTransfer { .. } => false,
210 }
211 }
212}
213
214#[derive(
216 Debug,
217 Clone,
218 Serialize,
219 Deserialize,
220 Eq,
221 PartialEq,
222 BorshSerialize,
223 BorshDeserialize,
224)]
225pub struct SubjectContext {
226 pub subject_id: DigestIdentifier,
227 pub governance_id: DigestIdentifier,
228 pub schema_id: SchemaType,
229 pub is_owner: bool,
230 pub namespace: Namespace,
231}
232
233#[cfg(test)]
234mod tests {
235 use super::*;
236 use ave_common::identity::{
237 Signed,
238 keys::{Ed25519Signer, KeyPair},
239 };
240 use serde_json::json;
241
242 #[test]
243 fn test_build_evaluate_info_rejects_governance_fact_viewpoints() {
244 let signer = Ed25519Signer::generate().unwrap();
245 let public_key = KeyPair::Ed25519(signer.clone()).public_key();
246 let request = EventRequest::Fact(ave_common::request::FactRequest {
247 subject_id: DigestIdentifier::default(),
248 payload: ValueWrapper(json!({ "members": { "add": [] } })),
249 viewpoints: BTreeSet::from(["agua".to_owned()]),
250 });
251
252 let event_request = Signed::new(request, &signer).unwrap();
253
254 let req = EvaluationReq {
255 event_request,
256 governance_id: DigestIdentifier::default(),
257 data: EvaluateData::GovFact {
258 state: GovernanceData::new(public_key.clone()),
259 },
260 sn: 1,
261 gov_version: 0,
262 namespace: Namespace::default(),
263 schema_id: SchemaType::Governance,
264 signer: public_key,
265 signer_is_owner: true,
266 };
267
268 let error = req
269 .build_evaluate_info(&None, &EvalWorkerContext::default())
270 .unwrap_err();
271 assert!(matches!(error, EvaluatorError::InvalidEventRequest(_)));
272 }
273
274 #[test]
275 fn test_build_evaluate_info_rejects_unknown_tracker_fact_viewpoint() {
276 let signer = Ed25519Signer::generate().unwrap();
277 let public_key = KeyPair::Ed25519(signer.clone()).public_key();
278 let request = EventRequest::Fact(ave_common::request::FactRequest {
279 subject_id: DigestIdentifier::default(),
280 payload: ValueWrapper(json!({ "ModOne": { "data": 1 } })),
281 viewpoints: BTreeSet::from(["vidrio".to_owned()]),
282 });
283
284 let event_request = Signed::new(request, &signer).unwrap();
285
286 let req = EvaluationReq {
287 event_request,
288 governance_id: DigestIdentifier::default(),
289 data: EvaluateData::TrackerSchemasFact {
290 state: ValueWrapper(json!({ "one": 0, "two": 0, "three": 0 })),
291 },
292 sn: 1,
293 gov_version: 0,
294 namespace: Namespace::default(),
295 schema_id: SchemaType::Type("Example".to_owned()),
296 signer: public_key,
297 signer_is_owner: true,
298 };
299
300 let error = req
301 .build_evaluate_info(
302 &Some(ValueWrapper(json!({}))),
303 &EvalWorkerContext::TrackerFact {
304 issuers: BTreeSet::new(),
305 issuer_any: false,
306 schema_viewpoints: BTreeSet::from([
307 "agua".to_owned(),
308 "basura".to_owned(),
309 ]),
310 },
311 )
312 .unwrap_err();
313 assert!(matches!(error, EvaluatorError::InvalidEventRequest(_)));
314 }
315
316 #[test]
317 fn test_build_evaluate_info_rejects_all_viewpoints_in_tracker_fact() {
318 let signer = Ed25519Signer::generate().unwrap();
319 let public_key = KeyPair::Ed25519(signer.clone()).public_key();
320 let request = EventRequest::Fact(ave_common::request::FactRequest {
321 subject_id: DigestIdentifier::default(),
322 payload: ValueWrapper(json!({ "ModOne": { "data": 1 } })),
323 viewpoints: BTreeSet::from(["AllViewpoints".to_owned()]),
324 });
325
326 let event_request = Signed::new(request, &signer).unwrap();
327
328 let req = EvaluationReq {
329 event_request,
330 governance_id: DigestIdentifier::default(),
331 data: EvaluateData::TrackerSchemasFact {
332 state: ValueWrapper(json!({ "one": 0, "two": 0, "three": 0 })),
333 },
334 sn: 1,
335 gov_version: 0,
336 namespace: Namespace::default(),
337 schema_id: SchemaType::Type("Example".to_owned()),
338 signer: public_key,
339 signer_is_owner: true,
340 };
341
342 let error = req
343 .build_evaluate_info(
344 &Some(ValueWrapper(json!({}))),
345 &EvalWorkerContext::TrackerFact {
346 issuers: BTreeSet::new(),
347 issuer_any: false,
348 schema_viewpoints: BTreeSet::from([
349 "agua".to_owned(),
350 "basura".to_owned(),
351 ]),
352 },
353 )
354 .unwrap_err();
355 assert!(matches!(error, EvaluatorError::InvalidEventRequest(_)));
356 }
357
358 #[test]
359 fn test_build_evaluate_info_rejects_unknown_no_viewpoints_viewpoint() {
360 let signer = Ed25519Signer::generate().unwrap();
361 let public_key = KeyPair::Ed25519(signer.clone()).public_key();
362 let request = EventRequest::Fact(ave_common::request::FactRequest {
363 subject_id: DigestIdentifier::default(),
364 payload: ValueWrapper(json!({ "ModOne": { "data": 1 } })),
365 viewpoints: BTreeSet::from(["NoViewpoints".to_owned()]),
366 });
367
368 let event_request = Signed::new(request, &signer).unwrap();
369
370 let req = EvaluationReq {
371 event_request,
372 governance_id: DigestIdentifier::default(),
373 data: EvaluateData::TrackerSchemasFact {
374 state: ValueWrapper(json!({ "one": 0, "two": 0, "three": 0 })),
375 },
376 sn: 1,
377 gov_version: 0,
378 namespace: Namespace::default(),
379 schema_id: SchemaType::Type("Example".to_owned()),
380 signer: public_key,
381 signer_is_owner: true,
382 };
383
384 let error = req
385 .build_evaluate_info(
386 &Some(ValueWrapper(json!({}))),
387 &EvalWorkerContext::TrackerFact {
388 issuers: BTreeSet::new(),
389 issuer_any: false,
390 schema_viewpoints: BTreeSet::from([
391 "agua".to_owned(),
392 "basura".to_owned(),
393 ]),
394 },
395 )
396 .unwrap_err();
397 assert!(matches!(error, EvaluatorError::InvalidEventRequest(_)));
398 }
399}