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(
157 MAX_IC_SNAPSHOT_DATA_REPLY_BYTES,
158 IcSnapshotTransferReadError::InvalidAttempt,
159 IcSnapshotTransferReadError::ReplyTooLarge,
160 IcSnapshotTransferReadError::InvalidTarget,
161 )?;
162 Ok(Self { input })
163 }
164 #[must_use]
166 pub const fn input(&self) -> &IcUpdateResponseInput {
167 &self.input
168 }
169}
170
171impl fmt::Debug for IcSnapshotTransferReadResponse {
172 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
173 self.input
174 .fmt_redacted(formatter, "IcSnapshotTransferReadResponse")
175 }
176}
177
178#[derive(Debug, Error)]
180pub enum IcSnapshotTransferReadError {
181 #[error("snapshot transfer read authority differs")]
183 AuthorityMismatch,
184 #[error("snapshot transfer read payload differs")]
186 PayloadMismatch,
187 #[error("snapshot transfer read requires a pending original update")]
189 NoPendingMutation,
190 #[error("snapshot transfer read original attempt differs")]
192 MutationMismatch,
193 #[error("snapshot transfer read recovery observation is pending")]
195 ObservationPending,
196 #[error("invalid snapshot transfer read attempt")]
198 InvalidAttempt,
199 #[error("snapshot transfer read reply too large")]
201 ReplyTooLarge,
202 #[error("invalid snapshot transfer read target")]
204 InvalidTarget,
205 #[error(transparent)]
207 Plan(#[from] OperationPlanError),
208}
209
210impl From<crate::model::attempt_journal::MutationReservationError> for IcSnapshotTransferReadError {
211 fn from(error: crate::model::attempt_journal::MutationReservationError) -> Self {
212 match error {
213 Reservation::NoPendingMutation => Self::NoPendingMutation,
214 Reservation::AuthorityMismatch => Self::AuthorityMismatch,
215 Reservation::MutationMismatch => Self::MutationMismatch,
216 Reservation::ObservationPending => Self::ObservationPending,
217 }
218 }
219}