Skip to main content

ave_core/governance/
role_register.rs

1use std::collections::{HashMap, HashSet};
2
3use crate::{
4    governance::model::Quorum,
5    model::common::{
6        CeilingMap, Interval, IntervalSet, emit_fail, purge_storage,
7    },
8};
9use async_trait::async_trait;
10use ave_actors::{
11    Actor, ActorContext, ActorError, ActorPath, Event, Handler,
12    LightPersistence, Message, PersistentActor, Response,
13};
14
15use ave_common::{Namespace, SchemaType, identity::PublicKey};
16use borsh::{BorshDeserialize, BorshSerialize};
17use serde::{Deserialize, Serialize};
18use tracing::{Span, debug, error, info_span};
19
20use crate::db::Storable;
21
22#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]
23pub struct SearchRole {
24    pub schema_id: SchemaType,
25    pub namespace: Namespace,
26}
27
28#[derive(
29    Debug,
30    Clone,
31    Serialize,
32    Deserialize,
33    Hash,
34    Eq,
35    PartialEq,
36    Ord,
37    PartialOrd,
38    BorshDeserialize,
39    BorshSerialize,
40)]
41pub struct RoleData {
42    pub key: PublicKey,
43    pub namespace: Namespace,
44}
45
46#[derive(
47    Debug,
48    Clone,
49    Serialize,
50    Deserialize,
51    BorshDeserialize,
52    BorshSerialize,
53    Default,
54)]
55pub struct RoleRegister {
56    version: u64,
57
58    appr_quorum: Quorum,
59    approvers: HashSet<PublicKey>,
60
61    eval_quorum: HashMap<SchemaType, Quorum>,
62    evaluators: HashMap<SchemaType, HashSet<(PublicKey, Namespace)>>,
63
64    vali_quorum: HashMap<SchemaType, CeilingMap<Quorum>>,
65    validators:
66        HashMap<SchemaType, HashMap<(PublicKey, Namespace), IntervalData>>,
67}
68
69type IntervalData = (IntervalSet, Option<u64>);
70
71impl RoleRegister {
72    pub fn new() -> Self {
73        Self {
74            version: 0,
75            appr_quorum: Quorum::Majority,
76            eval_quorum: HashMap::new(),
77            vali_quorum: HashMap::new(),
78            evaluators: HashMap::new(),
79            validators: HashMap::new(),
80            approvers: HashSet::new(),
81        }
82    }
83}
84
85#[derive(
86    Debug, Clone, Deserialize, Serialize, BorshDeserialize, BorshSerialize,
87)]
88pub struct UpdateRole {
89    pub schema_id: SchemaType,
90    pub role: HashSet<RoleData>,
91}
92
93#[derive(
94    Debug, Clone, Deserialize, Serialize, BorshDeserialize, BorshSerialize,
95)]
96pub struct UpdateQuorum {
97    pub schema_id: SchemaType,
98    pub quorum: Quorum,
99}
100
101#[derive(
102    Debug, Clone, Serialize, Deserialize, BorshDeserialize, BorshSerialize,
103)]
104pub struct RoleDataRegister {
105    pub workers: HashSet<PublicKey>,
106    pub quorum: Quorum,
107}
108
109#[derive(Debug, Clone)]
110pub struct CurrentSchemaRoles {
111    pub evaluation: HashSet<RoleData>,
112    pub evaluation_quorum: Quorum,
113    pub validation: HashSet<RoleData>,
114    pub validation_quorum: Quorum,
115}
116
117#[derive(Debug, Clone)]
118pub struct CurrentValidationRoles {
119    pub approval: RoleDataRegister,
120    pub schema: CurrentSchemaRoles,
121}
122
123#[derive(Debug, Clone)]
124pub enum RoleRegisterMessage {
125    PurgeStorage,
126    GetCurrentValidationRoles {
127        schema_id: SchemaType,
128    },
129    SearchActualRoles {
130        version: u64,
131        evaluation: SearchRole,
132        approval: bool,
133    },
134    SearchValidators {
135        search: SearchRole,
136        version: u64,
137    },
138    UpdateVersion {
139        version: u64,
140    },
141    UpdateFact {
142        version: u64,
143
144        appr_quorum: Option<Quorum>,
145        eval_quorum: HashMap<SchemaType, Quorum>,
146        vali_quorum: HashMap<SchemaType, Quorum>,
147
148        new_approvers: Vec<PublicKey>,
149        remove_approvers: Vec<PublicKey>,
150
151        new_evaluators: HashMap<(SchemaType, PublicKey), Vec<Namespace>>,
152        remove_evaluators: HashMap<(SchemaType, PublicKey), Vec<Namespace>>,
153
154        new_validators: HashMap<(SchemaType, PublicKey), Vec<Namespace>>,
155        remove_validators: HashMap<(SchemaType, PublicKey), Vec<Namespace>>,
156    },
157    UpdateConfirm {
158        version: u64,
159
160        new_approver: Option<PublicKey>,
161        remove_approver: PublicKey,
162
163        new_evaluator: Option<PublicKey>,
164        remove_evaluators: HashMap<(SchemaType, PublicKey), Vec<Namespace>>,
165
166        new_validator: Option<PublicKey>,
167        remove_validators: HashMap<(SchemaType, PublicKey), Vec<Namespace>>,
168    },
169}
170impl Message for RoleRegisterMessage {
171    fn is_critical(&self) -> bool {
172        matches!(
173            self,
174            Self::PurgeStorage
175                | Self::UpdateVersion { .. }
176                | Self::UpdateFact { .. }
177                | Self::UpdateConfirm { .. }
178        )
179    }
180}
181
182#[derive(Debug, Clone)]
183pub enum RoleRegisterResponse {
184    CurrentValidationRoles(CurrentValidationRoles),
185    ActualRoles {
186        evaluation: RoleDataRegister,
187        approval: Option<RoleDataRegister>,
188    },
189    Validation(RoleDataRegister),
190    MissingData,
191    OutOfVersion,
192    Ok,
193}
194
195impl Response for RoleRegisterResponse {}
196
197#[derive(
198    Debug, Clone, Deserialize, Serialize, BorshDeserialize, BorshSerialize,
199)]
200pub enum RoleRegisterEvent {
201    UpdateVersion {
202        version: u64,
203    },
204    UpdateFact {
205        version: u64,
206
207        appr_quorum: Option<Quorum>,
208        eval_quorum: HashMap<SchemaType, Quorum>,
209        vali_quorum: HashMap<SchemaType, Quorum>,
210
211        new_approvers: Vec<PublicKey>,
212        remove_approvers: Vec<PublicKey>,
213
214        new_evaluators: HashMap<(SchemaType, PublicKey), Vec<Namespace>>,
215        remove_evaluators: HashMap<(SchemaType, PublicKey), Vec<Namespace>>,
216
217        new_validators: HashMap<(SchemaType, PublicKey), Vec<Namespace>>,
218        remove_validators: HashMap<(SchemaType, PublicKey), Vec<Namespace>>,
219    },
220    UpdateConfirm {
221        version: u64,
222
223        new_approver: Option<PublicKey>,
224        remove_approver: PublicKey,
225
226        new_evaluator: Option<PublicKey>,
227        remove_evaluators: HashMap<(SchemaType, PublicKey), Vec<Namespace>>,
228
229        new_validator: Option<PublicKey>,
230        remove_validators: HashMap<(SchemaType, PublicKey), Vec<Namespace>>,
231    },
232}
233
234impl Event for RoleRegisterEvent {}
235
236#[async_trait]
237impl Actor for RoleRegister {
238    type Event = RoleRegisterEvent;
239    type Message = RoleRegisterMessage;
240    type Response = RoleRegisterResponse;
241
242    fn get_span(_id: &str, parent_span: Option<Span>) -> tracing::Span {
243        parent_span.map_or_else(
244            || info_span!("RoleRegister"),
245            |parent_span| info_span!(parent: parent_span, "RoleRegister"),
246        )
247    }
248
249    async fn pre_start(
250        &mut self,
251        ctx: &mut ActorContext<Self>,
252    ) -> Result<(), ActorError> {
253        let prefix = ctx.path().parent().key();
254        if let Err(e) = self
255            .init_store("role_register", Some(prefix), true, ctx)
256            .await
257        {
258            error!(
259                error = %e,
260                "Failed to initialize role_register store"
261            );
262            return Err(e);
263        }
264        Ok(())
265    }
266}
267
268#[async_trait]
269impl Handler<Self> for RoleRegister {
270    async fn handle_message(
271        &mut self,
272        _sender: ActorPath,
273        msg: RoleRegisterMessage,
274        ctx: &mut ActorContext<Self>,
275    ) -> Result<RoleRegisterResponse, ActorError> {
276        match msg {
277            RoleRegisterMessage::PurgeStorage => {
278                purge_storage(ctx).await?;
279
280                debug!(
281                    msg_type = "PurgeStorage",
282                    "Role register storage purged"
283                );
284
285                Ok(RoleRegisterResponse::Ok)
286            }
287            RoleRegisterMessage::GetCurrentValidationRoles { schema_id } => {
288                let approval = RoleDataRegister {
289                    workers: self.approvers.clone(),
290                    quorum: self.appr_quorum.clone(),
291                };
292
293                let Some(evaluation_quorum) =
294                    self.eval_quorum.get(&schema_id).cloned()
295                else {
296                    return Ok(RoleRegisterResponse::MissingData);
297                };
298
299                let Some(validation_quorum) = self
300                    .vali_quorum
301                    .get(&schema_id)
302                    .and_then(|quorum| quorum.get_prev_or_equal(self.version))
303                else {
304                    return Ok(RoleRegisterResponse::MissingData);
305                };
306
307                let mut evaluation = HashSet::new();
308                if !schema_id.is_gov()
309                    && let Some(evaluators) =
310                        self.evaluators.get(&SchemaType::TrackerSchemas)
311                {
312                    for (key, namespace) in evaluators {
313                        evaluation.insert(RoleData {
314                            key: key.clone(),
315                            namespace: namespace.clone(),
316                        });
317                    }
318                }
319
320                if let Some(evaluators) = self.evaluators.get(&schema_id) {
321                    for (key, namespace) in evaluators {
322                        evaluation.insert(RoleData {
323                            key: key.clone(),
324                            namespace: namespace.clone(),
325                        });
326                    }
327                }
328
329                let mut validation = HashSet::new();
330                if !schema_id.is_gov()
331                    && let Some(validators) =
332                        self.validators.get(&SchemaType::TrackerSchemas)
333                {
334                    for ((key, namespace), (_, last)) in validators {
335                        if let Some(last) = last
336                            && *last <= self.version
337                        {
338                            validation.insert(RoleData {
339                                key: key.clone(),
340                                namespace: namespace.clone(),
341                            });
342                        }
343                    }
344                }
345
346                if let Some(validators) = self.validators.get(&schema_id) {
347                    for ((key, namespace), (_, last)) in validators {
348                        if let Some(last) = last
349                            && *last <= self.version
350                        {
351                            validation.insert(RoleData {
352                                key: key.clone(),
353                                namespace: namespace.clone(),
354                            });
355                        }
356                    }
357                }
358
359                Ok(RoleRegisterResponse::CurrentValidationRoles(
360                    CurrentValidationRoles {
361                        approval,
362                        schema: CurrentSchemaRoles {
363                            evaluation,
364                            evaluation_quorum,
365                            validation,
366                            validation_quorum,
367                        },
368                    },
369                ))
370            }
371            RoleRegisterMessage::SearchActualRoles {
372                version,
373                evaluation,
374                approval,
375            } => {
376                if version != self.version {
377                    debug!(
378                        msg_type = "SearchActualRoles",
379                        version = version,
380                        current_version = self.version,
381                        schema_id = %evaluation.schema_id,
382                        namespace = %evaluation.namespace,
383                        "Request version exceeds current version"
384                    );
385                    return Ok(RoleRegisterResponse::OutOfVersion);
386                }
387
388                'data: {
389                    let approvers = if approval {
390                        if self.approvers.is_empty() {
391                            break 'data;
392                        } else {
393                            Some(RoleDataRegister {
394                                workers: self.approvers.clone(),
395                                quorum: self.appr_quorum.clone(),
396                            })
397                        }
398                    } else {
399                        None
400                    };
401
402                    let mut all_eval = if !evaluation.schema_id.is_gov()
403                        && let Some(evaluators) =
404                            self.evaluators.get(&SchemaType::TrackerSchemas)
405                    {
406                        let mut schema_eval = vec![];
407                        for (key, namespace) in evaluators {
408                            if namespace
409                                .is_ancestor_or_equal_of(&evaluation.namespace)
410                            {
411                                schema_eval.push(key.clone());
412                            }
413                        }
414
415                        schema_eval
416                    } else {
417                        vec![]
418                    };
419
420                    let mut schema_eval = if let Some(evaluators) =
421                        self.evaluators.get(&evaluation.schema_id)
422                    {
423                        let mut schema_eval = vec![];
424                        for (key, namespace) in evaluators {
425                            if namespace
426                                .is_ancestor_or_equal_of(&evaluation.namespace)
427                            {
428                                schema_eval.push(key.clone());
429                            }
430                        }
431
432                        schema_eval
433                    } else {
434                        vec![]
435                    };
436
437                    let quorum = if let Some(quorum_schema) =
438                        self.eval_quorum.get(&evaluation.schema_id)
439                    {
440                        quorum_schema.clone()
441                    } else {
442                        break 'data;
443                    };
444
445                    if schema_eval.is_empty() && all_eval.is_empty() {
446                        break 'data;
447                    }
448
449                    let mut evaluators = vec![];
450                    evaluators.append(&mut schema_eval);
451                    evaluators.append(&mut all_eval);
452
453                    debug!(
454                        msg_type = "SearchActualRoles",
455                        version = version,
456                        schema_id = %evaluation.schema_id,
457                        namespace = %evaluation.namespace,
458                        evaluators_count = evaluators.len(),
459                        has_approvers = approvers.is_some(),
460                        "Found actual roles successfully"
461                    );
462
463                    return Ok(RoleRegisterResponse::ActualRoles {
464                        evaluation: RoleDataRegister {
465                            workers: evaluators.iter().cloned().collect(),
466                            quorum,
467                        },
468                        approval: approvers,
469                    });
470                }
471
472                debug!(
473                    msg_type = "SearchActualRoles",
474                    version = version,
475                    schema_id = %evaluation.schema_id,
476                    namespace = %evaluation.namespace,
477                    "Missing role data for version"
478                );
479                Ok(RoleRegisterResponse::MissingData)
480            }
481            RoleRegisterMessage::SearchValidators { search, version } => {
482                if version > self.version {
483                    debug!(
484                        msg_type = "SearchValidators",
485                        version = version,
486                        current_version = self.version,
487                        schema_id = %search.schema_id,
488                        namespace = %search.namespace,
489                        "Request version exceeds current version"
490                    );
491                    return Ok(RoleRegisterResponse::OutOfVersion);
492                }
493
494                let mut all_val = if !search.schema_id.is_gov()
495                    && let Some(validators) =
496                        self.validators.get(&SchemaType::TrackerSchemas)
497                {
498                    // PublicKey, Namespace), (IntervalSet, Option<u64>
499                    let mut schema_val = vec![];
500                    for ((key, namespace), (interval, last)) in validators {
501                        if namespace.is_ancestor_or_equal_of(&search.namespace)
502                        {
503                            if let Some(last) = last
504                                && last <= &version
505                            {
506                                schema_val.push(key.clone());
507                            } else if interval.contains(version) {
508                                schema_val.push(key.clone());
509                            }
510                        }
511                    }
512
513                    schema_val
514                } else {
515                    vec![]
516                };
517
518                let mut schema_val = if let Some(validators) =
519                    self.validators.get(&search.schema_id)
520                {
521                    let mut schema_val = vec![];
522                    for ((key, namespace), (interval, last)) in validators {
523                        if namespace.is_ancestor_or_equal_of(&search.namespace)
524                        {
525                            if let Some(last) = last
526                                && last <= &version
527                            {
528                                schema_val.push(key.clone());
529                            } else if interval.contains(version) {
530                                schema_val.push(key.clone());
531                            }
532                        }
533                    }
534
535                    schema_val
536                } else {
537                    vec![]
538                };
539
540                'data: {
541                    let quorum = if let Some(quorum_schema) =
542                        self.vali_quorum.get(&search.schema_id)
543                    {
544                        let Some(quorum) =
545                            quorum_schema.get_prev_or_equal(version)
546                        else {
547                            break 'data;
548                        };
549
550                        quorum
551                    } else {
552                        break 'data;
553                    };
554
555                    if schema_val.is_empty() && all_val.is_empty() {
556                        break 'data;
557                    }
558
559                    let mut validators = vec![];
560                    validators.append(&mut schema_val);
561                    validators.append(&mut all_val);
562
563                    debug!(
564                        msg_type = "SearchValidators",
565                        version = version,
566                        schema_id = %search.schema_id,
567                        namespace = %search.namespace,
568                        validators_count = validators.len(),
569                        "Found validators successfully"
570                    );
571
572                    return Ok(RoleRegisterResponse::Validation(
573                        RoleDataRegister {
574                            workers: validators.iter().cloned().collect(),
575                            quorum,
576                        },
577                    ));
578                }
579
580                debug!(
581                    msg_type = "SearchValidators",
582                    version = version,
583                    schema_id = %search.schema_id,
584                    namespace = %search.namespace,
585                    "Missing validator data for version"
586                );
587                Ok(RoleRegisterResponse::MissingData)
588            }
589            RoleRegisterMessage::UpdateVersion { version } => {
590                if version > self.version || self.version == 0 {
591                    self.on_event(
592                        RoleRegisterEvent::UpdateVersion { version },
593                        ctx,
594                    )
595                    .await;
596
597                    debug!(
598                        msg_type = "UpdateVersion",
599                        version = version,
600                        "Roles register updated successfully"
601                    );
602                } else {
603                    debug!(
604                        msg_type = "UpdateVersion",
605                        version = version,
606                        current_version = self.version,
607                        "Update skipped, version not greater than current"
608                    );
609                }
610
611                Ok(RoleRegisterResponse::Ok)
612            }
613            RoleRegisterMessage::UpdateConfirm {
614                version,
615                new_approver,
616                remove_approver,
617                new_evaluator,
618                remove_evaluators,
619                new_validator,
620                remove_validators,
621            } => {
622                if version > self.version || self.version == 0 {
623                    self.on_event(
624                        RoleRegisterEvent::UpdateConfirm {
625                            version,
626                            new_approver,
627                            remove_approver,
628                            new_evaluator,
629                            remove_evaluators,
630                            new_validator,
631                            remove_validators,
632                        },
633                        ctx,
634                    )
635                    .await;
636
637                    debug!(
638                        msg_type = "UpdateConfirm",
639                        version = version,
640                        "Roles register updated successfully"
641                    );
642                } else {
643                    debug!(
644                        msg_type = "UpdateConfirm",
645                        version = version,
646                        current_version = self.version,
647                        "Update skipped, version not greater than current"
648                    );
649                }
650
651                Ok(RoleRegisterResponse::Ok)
652            }
653            RoleRegisterMessage::UpdateFact {
654                version,
655                appr_quorum,
656                eval_quorum,
657                vali_quorum,
658                new_approvers,
659                remove_approvers,
660                new_evaluators,
661                remove_evaluators,
662                new_validators,
663                remove_validators,
664            } => {
665                if version > self.version || self.version == 0 {
666                    self.on_event(
667                        RoleRegisterEvent::UpdateFact {
668                            version,
669                            appr_quorum,
670                            eval_quorum,
671                            vali_quorum,
672                            new_approvers,
673                            remove_approvers,
674                            new_evaluators,
675                            remove_evaluators,
676                            new_validators,
677                            remove_validators,
678                        },
679                        ctx,
680                    )
681                    .await;
682
683                    debug!(
684                        msg_type = "UpdateFact",
685                        version = version,
686                        "Roles register updated successfully"
687                    );
688                } else {
689                    debug!(
690                        msg_type = "UpdateFact",
691                        version = version,
692                        current_version = self.version,
693                        "Update skipped, version not greater than current"
694                    );
695                }
696
697                Ok(RoleRegisterResponse::Ok)
698            }
699        }
700    }
701
702    async fn on_event(
703        &mut self,
704        event: RoleRegisterEvent,
705        ctx: &mut ActorContext<Self>,
706    ) {
707        if let Err(e) = self.persist(&event, ctx).await {
708            let version = match &event {
709                RoleRegisterEvent::UpdateFact { version, .. } => *version,
710                RoleRegisterEvent::UpdateVersion { version } => *version,
711                RoleRegisterEvent::UpdateConfirm { version, .. } => *version,
712            };
713            error!(
714                version = version,
715                error = %e,
716                "Failed to persist role register event"
717            );
718            emit_fail(ctx, e).await;
719        }
720    }
721}
722
723#[async_trait]
724impl PersistentActor for RoleRegister {
725    type Persistence = LightPersistence;
726    type InitParams = ();
727
728    fn create_initial(_params: Self::InitParams) -> Self {
729        Self::default()
730    }
731
732    fn apply(&mut self, event: &Self::Event) -> Result<(), ActorError> {
733        match event {
734            RoleRegisterEvent::UpdateVersion { version } => {
735                self.version = *version;
736            }
737            RoleRegisterEvent::UpdateConfirm {
738                version,
739                new_approver,
740                remove_approver,
741                new_evaluator,
742                remove_evaluators,
743                new_validator,
744                remove_validators,
745            } => {
746                self.version = *version;
747                if let Some(approver) = new_approver {
748                    self.approvers.insert(approver.clone());
749                }
750
751                if let Some(evaluator) = new_evaluator {
752                    self.evaluators
753                        .entry(SchemaType::Governance)
754                        .or_default()
755                        .insert((evaluator.clone(), Namespace::new()));
756                }
757
758                if let Some(validator) = new_validator {
759                    self.validators
760                        .entry(SchemaType::Governance)
761                        .or_default()
762                        .entry((validator.clone(), Namespace::new()))
763                        .or_default()
764                        .1 = Some(*version);
765                }
766
767                self.approvers.remove(remove_approver);
768
769                for ((schema_id, evaluator), namespaces) in
770                    remove_evaluators.iter()
771                {
772                    for ns in namespaces.iter() {
773                        self.evaluators
774                            .entry(schema_id.clone())
775                            .or_default()
776                            .remove(&(evaluator.clone(), ns.clone()));
777                    }
778                }
779
780                for ((schema_id, validator), namespaces) in
781                    remove_validators.iter()
782                {
783                    for ns in namespaces.iter() {
784                        let (interval, last) = self
785                            .validators
786                            .entry(schema_id.clone())
787                            .or_default()
788                            .entry((validator.clone(), ns.clone()))
789                            .or_default();
790                        if let Some(last) = last.take() {
791                            interval.insert(Interval {
792                                lo: last,
793                                hi: *version - 1,
794                            });
795                        }
796                    }
797                }
798
799                debug!(
800                    event_type = "UpdateFact",
801                    version = version,
802                    new_approver = new_approver.is_some(),
803                    remove_approvers_count = 1,
804                    new_evaluator = new_evaluator.is_some(),
805                    remove_evaluators_count = remove_evaluators.len(),
806                    new_validator = new_validator.is_some(),
807                    remove_validators_count = remove_validators.len(),
808                    "Role register state updated"
809                );
810            }
811            RoleRegisterEvent::UpdateFact {
812                version,
813                appr_quorum,
814                eval_quorum,
815                vali_quorum,
816                new_approvers,
817                remove_approvers,
818                new_evaluators,
819                remove_evaluators,
820                new_validators,
821                remove_validators,
822            } => {
823                self.version = *version;
824
825                if let Some(appr_quorum) = appr_quorum {
826                    self.appr_quorum = appr_quorum.clone();
827                }
828
829                for (schema_id, quorum) in vali_quorum.iter() {
830                    self.vali_quorum
831                        .entry(schema_id.clone())
832                        .or_default()
833                        .insert(*version, quorum.clone());
834                }
835
836                for (schema_id, quorum) in eval_quorum.iter() {
837                    self.eval_quorum.insert(schema_id.clone(), quorum.clone());
838                }
839
840                for approver in new_approvers.iter() {
841                    self.approvers.insert(approver.clone());
842                }
843
844                for approver in remove_approvers.iter() {
845                    self.approvers.remove(approver);
846                }
847
848                for ((schema_id, evaluator), namespaces) in
849                    new_evaluators.iter()
850                {
851                    for ns in namespaces.iter() {
852                        self.evaluators
853                            .entry(schema_id.clone())
854                            .or_default()
855                            .insert((evaluator.clone(), ns.clone()));
856                    }
857                }
858
859                for ((schema_id, evaluator), namespaces) in
860                    remove_evaluators.iter()
861                {
862                    for ns in namespaces.iter() {
863                        self.evaluators
864                            .entry(schema_id.clone())
865                            .or_default()
866                            .remove(&(evaluator.clone(), ns.clone()));
867                    }
868                }
869
870                for ((schema_id, validator), namespaces) in
871                    new_validators.iter()
872                {
873                    for ns in namespaces.iter() {
874                        self.validators
875                            .entry(schema_id.clone())
876                            .or_default()
877                            .entry((validator.clone(), ns.clone()))
878                            .or_default()
879                            .1 = Some(*version);
880                    }
881                }
882
883                for ((schema_id, validator), namespaces) in
884                    remove_validators.iter()
885                {
886                    for ns in namespaces.iter() {
887                        let (interval, last) = self
888                            .validators
889                            .entry(schema_id.clone())
890                            .or_default()
891                            .entry((validator.clone(), ns.clone()))
892                            .or_default();
893                        if let Some(last) = last.take() {
894                            interval.insert(Interval {
895                                lo: last,
896                                hi: *version - 1,
897                            });
898                        }
899                    }
900                }
901
902                debug!(
903                    event_type = "UpdateFact",
904                    version = version,
905                    new_approvers_count = new_approvers.len(),
906                    remove_approvers_count = remove_approvers.len(),
907                    new_evaluators_count = new_evaluators.len(),
908                    remove_evaluators_count = remove_evaluators.len(),
909                    new_validators_count = new_validators.len(),
910                    remove_validators_count = remove_validators.len(),
911                    "Role register state updated"
912                );
913            }
914        }
915        Ok(())
916    }
917}
918
919impl Storable for RoleRegister {}