ic_backup/model/ic_update_response/
mod.rs1use crate::model::{
4 artifacts::ArtifactChecksumRecord, attempt_journal::MAX_OPERATION_ATTEMPTS,
5 operation_plan::PlanContextRecord,
6};
7use std::fmt;
8use thiserror::Error;
9
10#[derive(Clone)]
12pub struct IcUpdateResponseInput {
13 pub authority: ArtifactChecksumRecord,
15 pub mutation_attempt: u32,
17 pub context: PlanContextRecord,
19 pub target: String,
21 pub reply: Vec<u8>,
23 pub evidence: ArtifactChecksumRecord,
25}
26
27#[derive(Clone, Copy, Debug, Eq, Error, PartialEq)]
29pub enum IcUpdateResponseError {
30 #[error("invalid IC update response attempt")]
32 InvalidAttempt,
33 #[error("IC update response reply too large")]
35 ReplyTooLarge,
36 #[error("invalid IC update response target")]
38 InvalidTarget,
39}
40
41impl IcUpdateResponseInput {
42 pub(crate) fn admit(&mut self, max_reply_bytes: usize) -> Result<(), IcUpdateResponseError> {
43 if self.mutation_attempt == 0 || self.mutation_attempt > MAX_OPERATION_ATTEMPTS {
44 return Err(IcUpdateResponseError::InvalidAttempt);
45 }
46 if self.reply.len() > max_reply_bytes {
47 return Err(IcUpdateResponseError::ReplyTooLarge);
48 }
49 self.target = crate::model::principal::canonical_text(&self.target)
50 .ok_or(IcUpdateResponseError::InvalidTarget)?;
51 Ok(())
52 }
53
54 pub(crate) fn fmt_redacted(
55 &self,
56 formatter: &mut fmt::Formatter<'_>,
57 name: &str,
58 ) -> fmt::Result {
59 formatter
60 .debug_struct(name)
61 .field("authority", &self.authority)
62 .field("mutation_attempt", &self.mutation_attempt)
63 .field("target", &self.target)
64 .field("reply_bytes", &self.reply.len())
65 .finish_non_exhaustive()
66 }
67}
68
69#[cfg(test)]
70mod tests;