Skip to main content

ic_backup/model/ic_update_response/
mod.rs

1//! Shared passive IC update-response fields, bounded admission and redacted formatting.
2
3use crate::model::{
4    artifacts::ArtifactChecksumRecord, attempt_journal::MAX_OPERATION_ATTEMPTS,
5    operation_plan::PlanContextRecord,
6};
7use std::fmt;
8
9/// Passive provider fields; actual authentication and association are integration-owned.
10#[derive(Clone)]
11pub struct IcUpdateResponseInput {
12    /// Full original authority digest, including plan/context/operation/limits.
13    pub authority: ArtifactChecksumRecord,
14    /// Original already reserved mutation attempt, never a new call number.
15    pub mutation_attempt: u32,
16    /// Actual authenticated network/caller/release claimed by the provider.
17    pub context: PlanContextRecord,
18    /// Actual response routing target claimed by the provider; canonicalized on admission.
19    pub target: String,
20    /// Exact raw Candid reply, retained under the existing codec byte ceilings.
21    pub reply: Vec<u8>,
22    /// Opaque provider evidence binding original request/attempt and all actual fields.
23    pub evidence: ArtifactChecksumRecord,
24}
25
26impl IcUpdateResponseInput {
27    pub(crate) fn admit<E>(
28        &mut self,
29        max_reply_bytes: usize,
30        invalid_attempt: E,
31        reply_too_large: E,
32        invalid_target: E,
33    ) -> Result<(), E> {
34        if self.mutation_attempt == 0 || self.mutation_attempt > MAX_OPERATION_ATTEMPTS {
35            return Err(invalid_attempt);
36        }
37        if self.reply.len() > max_reply_bytes {
38            return Err(reply_too_large);
39        }
40        self.target =
41            crate::model::principal::canonical_text(&self.target).ok_or(invalid_target)?;
42        Ok(())
43    }
44
45    pub(crate) fn fmt_redacted(
46        &self,
47        formatter: &mut fmt::Formatter<'_>,
48        name: &str,
49    ) -> fmt::Result {
50        formatter
51            .debug_struct(name)
52            .field("authority", &self.authority)
53            .field("mutation_attempt", &self.mutation_attempt)
54            .field("target", &self.target)
55            .field("reply_bytes", &self.reply.len())
56            .finish_non_exhaustive()
57    }
58}
59
60#[cfg(test)]
61mod tests;