ic_backup/model/ic_snapshot_transfer_read/
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 artifacts::ArtifactChecksumRecord,
8 attempt_journal::{AttemptAuthorityRecord, AttemptJournalRecord},
9 ic_snapshot_data::{IcSnapshotDataRequest, MAX_IC_SNAPSHOT_DATA_REPLY_BYTES},
10 ic_snapshot_metadata::IcSnapshotMetadataRequest,
11 operation_plan::{OperationPlanError, OperationPlanRecord},
12};
13use std::fmt;
14use thiserror::Error;
15
16#[derive(Clone, Copy, Debug)]
18pub enum IcSnapshotTransferReadPayload<'request, 'metadata> {
19 Metadata(&'request IcSnapshotMetadataRequest),
21 Data(&'request IcSnapshotDataRequest<'metadata>),
23}
24
25impl<'request> IcSnapshotTransferReadPayload<'request, '_> {
26 pub(crate) fn validate_binding(
27 &self,
28 authority: &AttemptAuthorityRecord,
29 ) -> Result<(), IcSnapshotTransferReadError> {
30 if self.target() != authority.binding().target()
31 || self.digest().hash() != authority.binding().request()
32 {
33 return Err(IcSnapshotTransferReadError::PayloadMismatch);
34 }
35 Ok(())
36 }
37 #[must_use]
39 pub fn target(&self) -> &'request str {
40 match self {
41 Self::Metadata(payload) => payload.target(),
42 Self::Data(payload) => payload.target(),
43 }
44 }
45 #[must_use]
47 pub const fn receiver(&self) -> &'static str {
48 match self {
49 Self::Metadata(payload) => payload.receiver(),
50 Self::Data(payload) => payload.receiver(),
51 }
52 }
53 #[must_use]
55 pub const fn method(&self) -> &'static str {
56 match self {
57 Self::Metadata(payload) => payload.method(),
58 Self::Data(payload) => payload.method(),
59 }
60 }
61 #[must_use]
63 pub fn arguments(&self) -> &'request [u8] {
64 match self {
65 Self::Metadata(payload) => payload.arguments(),
66 Self::Data(payload) => payload.arguments(),
67 }
68 }
69 #[must_use]
71 pub fn digest(&self) -> ArtifactChecksumRecord {
72 match self {
73 Self::Metadata(payload) => payload.digest(),
74 Self::Data(payload) => payload.digest(),
75 }
76 }
77}
78
79#[derive(Debug)]
85pub struct IcSnapshotTransferReadRequest<'request, 'metadata> {
86 plan: &'request OperationPlanRecord,
87 payload: IcSnapshotTransferReadPayload<'request, 'metadata>,
88 reservation: MutationReservation,
89}
90
91impl<'request, 'metadata> IcSnapshotTransferReadRequest<'request, 'metadata> {
92 pub fn new(
97 plan: &'request OperationPlanRecord,
98 operation_sequence: u64,
99 journal: &AttemptJournalRecord,
100 payload: IcSnapshotTransferReadPayload<'request, 'metadata>,
101 ) -> Result<Self, IcSnapshotTransferReadError> {
102 let authority = plan.attempt_authority_for_journal(
103 operation_sequence,
104 journal,
105 IcSnapshotTransferReadError::AuthorityMismatch,
106 )?;
107 payload.validate_binding(&authority)?;
108 let reservation = MutationReservation::new(authority, journal)?;
109 Ok(Self {
110 plan,
111 payload,
112 reservation,
113 })
114 }
115 #[must_use]
117 pub const fn plan(&self) -> &'request OperationPlanRecord {
118 self.plan
119 }
120 #[must_use]
122 pub const fn payload(&self) -> IcSnapshotTransferReadPayload<'request, 'metadata> {
123 self.payload
124 }
125 #[must_use]
127 pub const fn authority(&self) -> &AttemptAuthorityRecord {
128 &self.reservation.authority
129 }
130 #[must_use]
132 pub const fn mutation_attempt(&self) -> u32 {
133 self.reservation.mutation_attempt
134 }
135 pub fn validate_journal(
139 &self,
140 journal: &AttemptJournalRecord,
141 ) -> Result<(), IcSnapshotTransferReadError> {
142 self.reservation.validate(journal).map_err(Into::into)
143 }
144}
145
146#[derive(Clone)]
148pub struct IcSnapshotTransferReadResponse {
149 input: IcUpdateResponseInput,
150}
151
152impl IcSnapshotTransferReadResponse {
153 pub fn new(mut input: IcUpdateResponseInput) -> Result<Self, IcSnapshotTransferReadError> {
157 input.admit(MAX_IC_SNAPSHOT_DATA_REPLY_BYTES)?;
158 Ok(Self { input })
159 }
160 #[must_use]
162 pub const fn input(&self) -> &IcUpdateResponseInput {
163 &self.input
164 }
165}
166
167impl fmt::Debug for IcSnapshotTransferReadResponse {
168 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
169 self.input
170 .fmt_redacted(formatter, "IcSnapshotTransferReadResponse")
171 }
172}
173
174#[derive(Debug, Error)]
176pub enum IcSnapshotTransferReadError {
177 #[error("snapshot transfer read authority differs")]
179 AuthorityMismatch,
180 #[error("snapshot transfer read payload differs")]
182 PayloadMismatch,
183 #[error("snapshot transfer read requires a pending original update")]
185 NoPendingMutation,
186 #[error("snapshot transfer read original attempt differs")]
188 MutationMismatch,
189 #[error("snapshot transfer read recovery observation is pending")]
191 ObservationPending,
192 #[error("invalid snapshot transfer read attempt")]
194 InvalidAttempt,
195 #[error("snapshot transfer read reply too large")]
197 ReplyTooLarge,
198 #[error("invalid snapshot transfer read target")]
200 InvalidTarget,
201 #[error(transparent)]
203 Plan(#[from] OperationPlanError),
204}
205
206impl From<crate::model::attempt_journal::MutationReservationError> for IcSnapshotTransferReadError {
207 fn from(error: crate::model::attempt_journal::MutationReservationError) -> Self {
208 match error {
209 Reservation::NoPendingMutation => Self::NoPendingMutation,
210 Reservation::AuthorityMismatch => Self::AuthorityMismatch,
211 Reservation::MutationMismatch => Self::MutationMismatch,
212 Reservation::ObservationPending => Self::ObservationPending,
213 }
214 }
215}
216
217impl From<crate::model::ic_update_response::UpdateResponseAdmissionError>
218 for IcSnapshotTransferReadError
219{
220 fn from(error: crate::model::ic_update_response::UpdateResponseAdmissionError) -> Self {
221 match error {
222 crate::model::ic_update_response::UpdateResponseAdmissionError::InvalidAttempt => {
223 Self::InvalidAttempt
224 }
225 crate::model::ic_update_response::UpdateResponseAdmissionError::ReplyTooLarge => {
226 Self::ReplyTooLarge
227 }
228 crate::model::ic_update_response::UpdateResponseAdmissionError::InvalidTarget => {
229 Self::InvalidTarget
230 }
231 }
232 }
233}