ic_backup/model/ic_mutation/
mod.rs1use crate::model::attempt_journal::MutationReservation;
4use crate::model::attempt_journal::MutationReservationError as Reservation;
5use crate::model::ic_update_response::IcUpdateResponseInput;
6use crate::model::{
7 attempt_journal::{AttemptAuthorityRecord, AttemptJournalRecord},
8 ic_lifecycle_reply::MAX_IC_LIFECYCLE_REPLY_BYTES,
9 ic_request::{IcManagementRequestRecord, IcRequestError},
10 ic_snapshot_reply::MAX_IC_SNAPSHOT_REPLY_BYTES,
11 operation_plan::{OperationPlanError, OperationPlanRecord},
12};
13use std::fmt;
14use thiserror::Error;
15
16pub const MAX_IC_MUTATION_REPLY_BYTES: usize =
18 if MAX_IC_SNAPSHOT_REPLY_BYTES < MAX_IC_LIFECYCLE_REPLY_BYTES {
19 MAX_IC_SNAPSHOT_REPLY_BYTES
20 } else {
21 MAX_IC_LIFECYCLE_REPLY_BYTES
22 };
23
24#[derive(Debug)]
30pub struct IcMutationRequest<'a> {
31 plan: &'a OperationPlanRecord,
32 payload: &'a IcManagementRequestRecord,
33 reservation: MutationReservation,
34}
35
36impl<'a> IcMutationRequest<'a> {
37 pub fn new(
45 plan: &'a OperationPlanRecord,
46 operation_sequence: u64,
47 journal: &AttemptJournalRecord,
48 payload: &'a IcManagementRequestRecord,
49 ) -> Result<Self, IcMutationRequestError> {
50 let authority = plan.attempt_authority(operation_sequence)?;
51 if journal.authority() != &authority {
52 return Err(IcMutationRequestError::AuthorityMismatch);
53 }
54 payload.validate_mutation_binding(authority.binding())?;
55 let reservation = MutationReservation::new(authority, journal)?;
56 Ok(Self {
57 plan,
58 payload,
59 reservation,
60 })
61 }
62
63 #[must_use]
65 pub const fn plan(&self) -> &OperationPlanRecord {
66 self.plan
67 }
68 #[must_use]
70 pub const fn payload(&self) -> &'a IcManagementRequestRecord {
71 self.payload
72 }
73 #[must_use]
75 pub const fn authority(&self) -> &AttemptAuthorityRecord {
76 &self.reservation.authority
77 }
78 #[must_use]
80 pub const fn mutation_attempt(&self) -> u32 {
81 self.reservation.mutation_attempt
82 }
83 pub fn validate_journal(
87 &self,
88 journal: &AttemptJournalRecord,
89 ) -> Result<(), IcMutationRequestError> {
90 self.reservation.validate(journal).map_err(Into::into)
91 }
92}
93
94#[derive(Clone)]
100pub struct IcMutationAcknowledgement {
101 input: IcUpdateResponseInput,
102}
103
104impl IcMutationAcknowledgement {
105 pub fn new(mut input: IcUpdateResponseInput) -> Result<Self, IcMutationAcknowledgementError> {
109 input.admit(
110 MAX_IC_MUTATION_REPLY_BYTES,
111 IcMutationAcknowledgementError::InvalidAttempt,
112 IcMutationAcknowledgementError::ReplyTooLarge,
113 IcMutationAcknowledgementError::InvalidTarget,
114 )?;
115 Ok(Self { input })
116 }
117 #[must_use]
119 pub const fn input(&self) -> &IcUpdateResponseInput {
120 &self.input
121 }
122}
123
124impl fmt::Debug for IcMutationAcknowledgement {
125 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
126 self.input
127 .fmt_redacted(formatter, "IcMutationAcknowledgement")
128 }
129}
130
131#[derive(Debug, Error)]
133pub enum IcMutationRequestError {
134 #[error("IC mutation original authority mismatch")]
136 AuthorityMismatch,
137 #[error("IC mutation requires a pending original mutation")]
139 NoPendingMutation,
140 #[error("IC mutation original attempt mismatch")]
142 MutationMismatch,
143 #[error("IC mutation has a pending recovery observation")]
145 ObservationPending,
146 #[error(transparent)]
148 Payload(#[from] IcRequestError),
149 #[error(transparent)]
151 Plan(#[from] OperationPlanError),
152}
153
154#[derive(Clone, Copy, Debug, Eq, Error, PartialEq)]
156pub enum IcMutationAcknowledgementError {
157 #[error("invalid IC mutation acknowledgement attempt")]
159 InvalidAttempt,
160 #[error("IC mutation acknowledgement reply too large")]
162 ReplyTooLarge,
163 #[error("invalid IC mutation acknowledgement target")]
165 InvalidTarget,
166}
167
168#[cfg(test)]
169mod tests;
170
171impl From<crate::model::attempt_journal::MutationReservationError> for IcMutationRequestError {
172 fn from(error: crate::model::attempt_journal::MutationReservationError) -> Self {
173 match error {
174 Reservation::NoPendingMutation => Self::NoPendingMutation,
175 Reservation::AuthorityMismatch => Self::AuthorityMismatch,
176 Reservation::MutationMismatch => Self::MutationMismatch,
177 Reservation::ObservationPending => Self::ObservationPending,
178 }
179 }
180}