ic_backup/model/control_authority/
mod.rs1use crate::model::attempt_journal::OperationBindingRecord;
4use thiserror::Error;
5
6pub const MAX_CONTROLLERS: usize = 10;
8
9#[derive(Clone, Debug, Eq, PartialEq)]
14pub struct ControllerSet {
15 principals: Vec<String>,
16}
17impl ControllerSet {
18 pub fn new(mut principals: Vec<String>) -> Result<Self, ControlObservationError> {
22 if principals.len() > MAX_CONTROLLERS {
23 return Err(ControlObservationError::TooManyControllers);
24 }
25 for principal in &mut principals {
26 *principal = super::principal::canonical_text(principal)
27 .ok_or(ControlObservationError::InvalidPrincipal)?;
28 }
29 principals.sort();
30 if principals.windows(2).any(|pair| pair[0] == pair[1]) {
31 return Err(ControlObservationError::DuplicateController);
32 }
33 Ok(Self { principals })
34 }
35 #[must_use]
37 pub fn principals(&self) -> &[String] {
38 &self.principals
39 }
40 #[must_use]
42 pub fn contains_caller(&self, binding: &OperationBindingRecord) -> bool {
43 self.principals
44 .binary_search_by(|principal| principal.as_str().cmp(binding.caller()))
45 .is_ok()
46 }
47}
48
49#[derive(Debug, Eq, Error, PartialEq)]
51pub enum ControlObservationError {
52 #[error("invalid control observation principal")]
54 InvalidPrincipal,
55 #[error("controller set exceeds {MAX_CONTROLLERS}")]
57 TooManyControllers,
58 #[error("duplicate controller principal")]
60 DuplicateController,
61}
62
63#[cfg(test)]
64mod tests;