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(operation_sequence)?;
103 if journal.authority() != &authority {
104 return Err(IcSnapshotTransferReadError::AuthorityMismatch);
105 }
106 payload.validate_binding(&authority)?;
107 let reservation = MutationReservation::new(authority, journal)?;
108 Ok(Self {
109 plan,
110 payload,
111 reservation,
112 })
113 }
114 #[must_use]
116 pub const fn plan(&self) -> &'request OperationPlanRecord {
117 self.plan
118 }
119 #[must_use]
121 pub const fn payload(&self) -> IcSnapshotTransferReadPayload<'request, 'metadata> {
122 self.payload
123 }
124 #[must_use]
126 pub const fn authority(&self) -> &AttemptAuthorityRecord {
127 &self.reservation.authority
128 }
129 #[must_use]
131 pub const fn mutation_attempt(&self) -> u32 {
132 self.reservation.mutation_attempt
133 }
134 pub fn validate_journal(
138 &self,
139 journal: &AttemptJournalRecord,
140 ) -> Result<(), IcSnapshotTransferReadError> {
141 self.reservation.validate(journal).map_err(Into::into)
142 }
143}
144
145#[derive(Clone)]
147pub struct IcSnapshotTransferReadResponse {
148 input: IcUpdateResponseInput,
149}
150
151impl IcSnapshotTransferReadResponse {
152 pub fn new(mut input: IcUpdateResponseInput) -> Result<Self, IcSnapshotTransferReadError> {
156 input.admit(MAX_IC_SNAPSHOT_DATA_REPLY_BYTES)?;
157 Ok(Self { input })
158 }
159 #[must_use]
161 pub const fn input(&self) -> &IcUpdateResponseInput {
162 &self.input
163 }
164}
165
166impl fmt::Debug for IcSnapshotTransferReadResponse {
167 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
168 self.input
169 .fmt_redacted(formatter, "IcSnapshotTransferReadResponse")
170 }
171}
172
173#[derive(Debug, Error)]
175pub enum IcSnapshotTransferReadError {
176 #[error("snapshot transfer read authority differs")]
178 AuthorityMismatch,
179 #[error("snapshot transfer read payload differs")]
181 PayloadMismatch,
182 #[error("snapshot transfer read requires a pending original update")]
184 NoPendingMutation,
185 #[error("snapshot transfer read original attempt differs")]
187 MutationMismatch,
188 #[error("snapshot transfer read recovery observation is pending")]
190 ObservationPending,
191 #[error("invalid snapshot transfer read attempt")]
193 InvalidAttempt,
194 #[error("snapshot transfer read reply too large")]
196 ReplyTooLarge,
197 #[error("invalid snapshot transfer read target")]
199 InvalidTarget,
200 #[error(transparent)]
202 Plan(#[from] OperationPlanError),
203}
204
205impl From<crate::model::attempt_journal::MutationReservationError> for IcSnapshotTransferReadError {
206 fn from(error: crate::model::attempt_journal::MutationReservationError) -> Self {
207 match error {
208 Reservation::NoPendingMutation => Self::NoPendingMutation,
209 Reservation::AuthorityMismatch => Self::AuthorityMismatch,
210 Reservation::MutationMismatch => Self::MutationMismatch,
211 Reservation::ObservationPending => Self::ObservationPending,
212 }
213 }
214}
215
216impl From<crate::model::ic_update_response::UpdateResponseAdmissionError>
217 for IcSnapshotTransferReadError
218{
219 fn from(error: crate::model::ic_update_response::UpdateResponseAdmissionError) -> Self {
220 match error {
221 crate::model::ic_update_response::UpdateResponseAdmissionError::InvalidAttempt => {
222 Self::InvalidAttempt
223 }
224 crate::model::ic_update_response::UpdateResponseAdmissionError::ReplyTooLarge => {
225 Self::ReplyTooLarge
226 }
227 crate::model::ic_update_response::UpdateResponseAdmissionError::InvalidTarget => {
228 Self::InvalidTarget
229 }
230 }
231 }
232}