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_for_journal(
51 operation_sequence,
52 journal,
53 IcMutationRequestError::AuthorityMismatch,
54 )?;
55 payload.validate_mutation_binding(authority.binding())?;
56 let reservation = MutationReservation::new(authority, journal)?;
57 Ok(Self {
58 plan,
59 payload,
60 reservation,
61 })
62 }
63
64 #[must_use]
66 pub const fn plan(&self) -> &OperationPlanRecord {
67 self.plan
68 }
69 #[must_use]
71 pub const fn payload(&self) -> &'a IcManagementRequestRecord {
72 self.payload
73 }
74 #[must_use]
76 pub const fn authority(&self) -> &AttemptAuthorityRecord {
77 &self.reservation.authority
78 }
79 #[must_use]
81 pub const fn mutation_attempt(&self) -> u32 {
82 self.reservation.mutation_attempt
83 }
84 pub fn validate_journal(
88 &self,
89 journal: &AttemptJournalRecord,
90 ) -> Result<(), IcMutationRequestError> {
91 self.reservation.validate(journal).map_err(Into::into)
92 }
93}
94
95#[derive(Clone)]
101pub struct IcMutationAcknowledgement {
102 input: IcUpdateResponseInput,
103}
104
105impl IcMutationAcknowledgement {
106 pub fn new(mut input: IcUpdateResponseInput) -> Result<Self, IcMutationAcknowledgementError> {
110 input.admit(MAX_IC_MUTATION_REPLY_BYTES)?;
111 Ok(Self { input })
112 }
113 #[must_use]
115 pub const fn input(&self) -> &IcUpdateResponseInput {
116 &self.input
117 }
118}
119
120impl fmt::Debug for IcMutationAcknowledgement {
121 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
122 self.input
123 .fmt_redacted(formatter, "IcMutationAcknowledgement")
124 }
125}
126
127#[derive(Debug, Error)]
129pub enum IcMutationRequestError {
130 #[error("IC mutation original authority mismatch")]
132 AuthorityMismatch,
133 #[error("IC mutation requires a pending original mutation")]
135 NoPendingMutation,
136 #[error("IC mutation original attempt mismatch")]
138 MutationMismatch,
139 #[error("IC mutation has a pending recovery observation")]
141 ObservationPending,
142 #[error(transparent)]
144 Payload(#[from] IcRequestError),
145 #[error(transparent)]
147 Plan(#[from] OperationPlanError),
148}
149
150#[derive(Clone, Copy, Debug, Eq, Error, PartialEq)]
152pub enum IcMutationAcknowledgementError {
153 #[error("invalid IC mutation acknowledgement attempt")]
155 InvalidAttempt,
156 #[error("IC mutation acknowledgement reply too large")]
158 ReplyTooLarge,
159 #[error("invalid IC mutation acknowledgement target")]
161 InvalidTarget,
162}
163
164#[cfg(test)]
165mod tests;
166
167impl From<crate::model::attempt_journal::MutationReservationError> for IcMutationRequestError {
168 fn from(error: crate::model::attempt_journal::MutationReservationError) -> Self {
169 match error {
170 Reservation::NoPendingMutation => Self::NoPendingMutation,
171 Reservation::AuthorityMismatch => Self::AuthorityMismatch,
172 Reservation::MutationMismatch => Self::MutationMismatch,
173 Reservation::ObservationPending => Self::ObservationPending,
174 }
175 }
176}
177
178impl From<crate::model::ic_update_response::UpdateResponseAdmissionError>
179 for IcMutationAcknowledgementError
180{
181 fn from(error: crate::model::ic_update_response::UpdateResponseAdmissionError) -> Self {
182 match error {
183 crate::model::ic_update_response::UpdateResponseAdmissionError::InvalidAttempt => {
184 Self::InvalidAttempt
185 }
186 crate::model::ic_update_response::UpdateResponseAdmissionError::ReplyTooLarge => {
187 Self::ReplyTooLarge
188 }
189 crate::model::ic_update_response::UpdateResponseAdmissionError::InvalidTarget => {
190 Self::InvalidTarget
191 }
192 }
193 }
194}