ic_backup/model/ic_snapshot_transfer_read/
mod.rs1use crate::model::attempt_journal::MutationReservation;
4use crate::model::ic_update_response::IcUpdateResponseInput;
5use crate::model::{
6 artifacts::ArtifactChecksumRecord,
7 attempt_journal::{AttemptAuthorityRecord, AttemptJournalRecord},
8 ic_snapshot_data::{IcSnapshotDataRequest, MAX_IC_SNAPSHOT_DATA_REPLY_BYTES},
9 ic_snapshot_metadata::IcSnapshotMetadataRequest,
10 operation_plan::{OperationPlanError, OperationPlanRecord},
11};
12use std::fmt;
13use thiserror::Error;
14
15#[derive(Clone, Copy, Debug)]
17pub enum IcSnapshotTransferReadPayload<'request, 'metadata> {
18 Metadata(&'request IcSnapshotMetadataRequest),
20 Data(&'request IcSnapshotDataRequest<'metadata>),
22}
23
24impl<'request> IcSnapshotTransferReadPayload<'request, '_> {
25 pub(crate) fn validate_binding(
26 &self,
27 authority: &AttemptAuthorityRecord,
28 ) -> Result<(), IcSnapshotTransferReadError> {
29 if self.target() != authority.binding().target()
30 || self.digest().hash() != authority.binding().request()
31 {
32 return Err(IcSnapshotTransferReadError::PayloadMismatch);
33 }
34 Ok(())
35 }
36 #[must_use]
38 pub fn target(&self) -> &'request str {
39 match self {
40 Self::Metadata(payload) => payload.target(),
41 Self::Data(payload) => payload.target(),
42 }
43 }
44 #[must_use]
46 pub const fn receiver(&self) -> &'static str {
47 match self {
48 Self::Metadata(payload) => payload.receiver(),
49 Self::Data(payload) => payload.receiver(),
50 }
51 }
52 #[must_use]
54 pub const fn method(&self) -> &'static str {
55 match self {
56 Self::Metadata(payload) => payload.method(),
57 Self::Data(payload) => payload.method(),
58 }
59 }
60 #[must_use]
62 pub fn arguments(&self) -> &'request [u8] {
63 match self {
64 Self::Metadata(payload) => payload.arguments(),
65 Self::Data(payload) => payload.arguments(),
66 }
67 }
68 #[must_use]
70 pub fn digest(&self) -> ArtifactChecksumRecord {
71 match self {
72 Self::Metadata(payload) => payload.digest(),
73 Self::Data(payload) => payload.digest(),
74 }
75 }
76}
77
78#[derive(Debug)]
84pub struct IcSnapshotTransferReadRequest<'request, 'metadata> {
85 plan: &'request OperationPlanRecord,
86 payload: IcSnapshotTransferReadPayload<'request, 'metadata>,
87 reservation: MutationReservation,
88}
89
90impl<'request, 'metadata> IcSnapshotTransferReadRequest<'request, 'metadata> {
91 pub fn new(
96 plan: &'request OperationPlanRecord,
97 operation_sequence: u64,
98 journal: &AttemptJournalRecord,
99 payload: IcSnapshotTransferReadPayload<'request, 'metadata>,
100 ) -> Result<Self, IcSnapshotTransferReadError> {
101 let authority = plan.attempt_authority(operation_sequence)?;
102 if journal.authority() != &authority {
103 return Err(IcSnapshotTransferReadError::AuthorityMismatch);
104 }
105 payload.validate_binding(&authority)?;
106 let reservation = MutationReservation::new(
107 authority,
108 journal,
109 IcSnapshotTransferReadError::NoPendingMutation,
110 IcSnapshotTransferReadError::AuthorityMismatch,
111 IcSnapshotTransferReadError::MutationMismatch,
112 IcSnapshotTransferReadError::ObservationPending,
113 )?;
114 Ok(Self {
115 plan,
116 payload,
117 reservation,
118 })
119 }
120 #[must_use]
122 pub const fn plan(&self) -> &'request OperationPlanRecord {
123 self.plan
124 }
125 #[must_use]
127 pub const fn payload(&self) -> IcSnapshotTransferReadPayload<'request, 'metadata> {
128 self.payload
129 }
130 #[must_use]
132 pub const fn authority(&self) -> &AttemptAuthorityRecord {
133 &self.reservation.authority
134 }
135 #[must_use]
137 pub const fn mutation_attempt(&self) -> u32 {
138 self.reservation.mutation_attempt
139 }
140 pub fn validate_journal(
144 &self,
145 journal: &AttemptJournalRecord,
146 ) -> Result<(), IcSnapshotTransferReadError> {
147 self.reservation.validate(
148 journal,
149 IcSnapshotTransferReadError::AuthorityMismatch,
150 IcSnapshotTransferReadError::MutationMismatch,
151 IcSnapshotTransferReadError::ObservationPending,
152 )
153 }
154}
155
156#[derive(Clone)]
158pub struct IcSnapshotTransferReadResponse {
159 input: IcUpdateResponseInput,
160}
161
162impl IcSnapshotTransferReadResponse {
163 pub fn new(mut input: IcUpdateResponseInput) -> Result<Self, IcSnapshotTransferReadError> {
167 input.admit(
168 MAX_IC_SNAPSHOT_DATA_REPLY_BYTES,
169 IcSnapshotTransferReadError::InvalidAttempt,
170 IcSnapshotTransferReadError::ReplyTooLarge,
171 IcSnapshotTransferReadError::InvalidTarget,
172 )?;
173 Ok(Self { input })
174 }
175 #[must_use]
177 pub const fn input(&self) -> &IcUpdateResponseInput {
178 &self.input
179 }
180}
181
182impl fmt::Debug for IcSnapshotTransferReadResponse {
183 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
184 self.input
185 .fmt_redacted(formatter, "IcSnapshotTransferReadResponse")
186 }
187}
188
189#[derive(Debug, Error)]
191pub enum IcSnapshotTransferReadError {
192 #[error("snapshot transfer read authority differs")]
194 AuthorityMismatch,
195 #[error("snapshot transfer read payload differs")]
197 PayloadMismatch,
198 #[error("snapshot transfer read requires a pending original update")]
200 NoPendingMutation,
201 #[error("snapshot transfer read original attempt differs")]
203 MutationMismatch,
204 #[error("snapshot transfer read recovery observation is pending")]
206 ObservationPending,
207 #[error("invalid snapshot transfer read attempt")]
209 InvalidAttempt,
210 #[error("snapshot transfer read reply too large")]
212 ReplyTooLarge,
213 #[error("invalid snapshot transfer read target")]
215 InvalidTarget,
216 #[error(transparent)]
218 Plan(#[from] OperationPlanError),
219}