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