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_for_journal(
50 operation_sequence,
51 journal,
52 IcMutationRequestError::Reservation(
53 crate::model::attempt_journal::MutationReservationError::AuthorityMismatch,
54 ),
55 )?;
56 payload.validate_mutation_binding(authority.binding())?;
57 let reservation = MutationReservation::new(authority, journal)?;
58 Ok(Self {
59 plan,
60 payload,
61 reservation,
62 })
63 }
64
65 #[must_use]
67 pub const fn plan(&self) -> &OperationPlanRecord {
68 self.plan
69 }
70 #[must_use]
72 pub const fn payload(&self) -> &'a IcManagementRequestRecord {
73 self.payload
74 }
75 #[must_use]
77 pub const fn authority(&self) -> &AttemptAuthorityRecord {
78 &self.reservation.authority
79 }
80 #[must_use]
82 pub const fn mutation_attempt(&self) -> u32 {
83 self.reservation.mutation_attempt
84 }
85 pub fn validate_journal(
89 &self,
90 journal: &AttemptJournalRecord,
91 ) -> Result<(), IcMutationRequestError> {
92 self.reservation.validate(journal).map_err(Into::into)
93 }
94}
95
96#[derive(Clone)]
102pub struct IcMutationAcknowledgement {
103 input: IcUpdateResponseInput,
104}
105
106impl IcMutationAcknowledgement {
107 pub fn new(mut input: IcUpdateResponseInput) -> Result<Self, IcMutationAcknowledgementError> {
111 input.admit(MAX_IC_MUTATION_REPLY_BYTES)?;
112 Ok(Self { input })
113 }
114 #[must_use]
116 pub const fn input(&self) -> &IcUpdateResponseInput {
117 &self.input
118 }
119}
120
121impl fmt::Debug for IcMutationAcknowledgement {
122 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
123 self.input
124 .fmt_redacted(formatter, "IcMutationAcknowledgement")
125 }
126}
127
128#[derive(Debug, Error)]
130pub enum IcMutationRequestError {
131 #[error("original mutation reservation rejected: {0}")]
133 Reservation(#[from] crate::model::attempt_journal::MutationReservationError),
134 #[error(transparent)]
136 Payload(#[from] IcRequestError),
137 #[error(transparent)]
139 Plan(#[from] OperationPlanError),
140}
141
142#[derive(Clone, Copy, Debug, Eq, Error, PartialEq)]
144pub enum IcMutationAcknowledgementError {
145 #[error("invalid IC mutation acknowledgement attempt")]
147 InvalidAttempt,
148 #[error("IC mutation acknowledgement reply too large")]
150 ReplyTooLarge,
151 #[error("invalid IC mutation acknowledgement target")]
153 InvalidTarget,
154}
155
156#[cfg(test)]
157mod tests;
158
159impl From<crate::model::ic_update_response::UpdateResponseAdmissionError>
160 for IcMutationAcknowledgementError
161{
162 fn from(error: crate::model::ic_update_response::UpdateResponseAdmissionError) -> Self {
163 match error {
164 crate::model::ic_update_response::UpdateResponseAdmissionError::InvalidAttempt => {
165 Self::InvalidAttempt
166 }
167 crate::model::ic_update_response::UpdateResponseAdmissionError::ReplyTooLarge => {
168 Self::ReplyTooLarge
169 }
170 crate::model::ic_update_response::UpdateResponseAdmissionError::InvalidTarget => {
171 Self::InvalidTarget
172 }
173 }
174 }
175}