ic_backup/model/ic_snapshot_transfer_read/
mod.rs1use crate::model::{
4 artifacts::ArtifactChecksumRecord,
5 attempt_journal::{AttemptAuthorityRecord, AttemptJournalRecord, MAX_OPERATION_ATTEMPTS},
6 ic_snapshot_data::{IcSnapshotDataRequest, MAX_IC_SNAPSHOT_DATA_REPLY_BYTES},
7 ic_snapshot_metadata::IcSnapshotMetadataRequest,
8 operation_plan::{OperationPlanError, OperationPlanRecord, PlanContextRecord},
9};
10use std::fmt;
11use thiserror::Error;
12
13#[derive(Clone, Copy, Debug)]
15pub enum IcSnapshotTransferReadPayload<'request, 'metadata> {
16 Metadata(&'request IcSnapshotMetadataRequest),
18 Data(&'request IcSnapshotDataRequest<'metadata>),
20}
21
22impl IcSnapshotTransferReadPayload<'_, '_> {
23 #[must_use]
25 pub fn target(&self) -> &str {
26 match self {
27 Self::Metadata(payload) => payload.target(),
28 Self::Data(payload) => payload.target(),
29 }
30 }
31 #[must_use]
33 pub const fn receiver(&self) -> &'static str {
34 match self {
35 Self::Metadata(payload) => payload.receiver(),
36 Self::Data(payload) => payload.receiver(),
37 }
38 }
39 #[must_use]
41 pub const fn method(&self) -> &'static str {
42 match self {
43 Self::Metadata(payload) => payload.method(),
44 Self::Data(payload) => payload.method(),
45 }
46 }
47 #[must_use]
49 pub fn arguments(&self) -> &[u8] {
50 match self {
51 Self::Metadata(payload) => payload.arguments(),
52 Self::Data(payload) => payload.arguments(),
53 }
54 }
55 #[must_use]
57 pub fn digest(&self) -> ArtifactChecksumRecord {
58 match self {
59 Self::Metadata(payload) => payload.digest(),
60 Self::Data(payload) => payload.digest(),
61 }
62 }
63}
64
65#[derive(Debug)]
71pub struct IcSnapshotTransferReadRequest<'request, 'metadata> {
72 plan: &'request OperationPlanRecord,
73 payload: IcSnapshotTransferReadPayload<'request, 'metadata>,
74 authority: AttemptAuthorityRecord,
75 mutation_attempt: u32,
76}
77
78impl<'request, 'metadata> IcSnapshotTransferReadRequest<'request, 'metadata> {
79 pub fn new(
84 plan: &'request OperationPlanRecord,
85 operation_sequence: u64,
86 journal: &AttemptJournalRecord,
87 payload: IcSnapshotTransferReadPayload<'request, 'metadata>,
88 ) -> Result<Self, IcSnapshotTransferReadError> {
89 let authority = plan.attempt_authority(operation_sequence)?;
90 if journal.authority() != &authority {
91 return Err(IcSnapshotTransferReadError::AuthorityMismatch);
92 }
93 if payload.target() != authority.binding().target()
94 || payload.digest().hash() != authority.binding().request()
95 {
96 return Err(IcSnapshotTransferReadError::PayloadMismatch);
97 }
98 let mutation_attempt = journal
99 .view()
100 .pending_mutation
101 .ok_or(IcSnapshotTransferReadError::NoPendingMutation)?;
102 let request = Self {
103 plan,
104 payload,
105 authority,
106 mutation_attempt,
107 };
108 request.validate_journal(journal)?;
109 Ok(request)
110 }
111 #[must_use]
113 pub const fn plan(&self) -> &'request OperationPlanRecord {
114 self.plan
115 }
116 #[must_use]
118 pub const fn payload(&self) -> IcSnapshotTransferReadPayload<'request, 'metadata> {
119 self.payload
120 }
121 #[must_use]
123 pub const fn authority(&self) -> &AttemptAuthorityRecord {
124 &self.authority
125 }
126 #[must_use]
128 pub const fn mutation_attempt(&self) -> u32 {
129 self.mutation_attempt
130 }
131 pub fn validate_journal(
135 &self,
136 journal: &AttemptJournalRecord,
137 ) -> Result<(), IcSnapshotTransferReadError> {
138 if journal.authority() != &self.authority {
139 return Err(IcSnapshotTransferReadError::AuthorityMismatch);
140 }
141 let view = journal.view();
142 if view.pending_mutation != Some(self.mutation_attempt) {
143 return Err(IcSnapshotTransferReadError::MutationMismatch);
144 }
145 if view.pending_observation.is_some() {
146 return Err(IcSnapshotTransferReadError::ObservationPending);
147 }
148 Ok(())
149 }
150}
151
152#[derive(Clone)]
154pub struct IcSnapshotTransferReadResponseInput {
155 pub authority: ArtifactChecksumRecord,
157 pub mutation_attempt: u32,
159 pub context: PlanContextRecord,
161 pub target: String,
163 pub reply: Vec<u8>,
165 pub evidence: ArtifactChecksumRecord,
167}
168
169#[derive(Clone)]
171pub struct IcSnapshotTransferReadResponse {
172 input: IcSnapshotTransferReadResponseInput,
173}
174
175impl IcSnapshotTransferReadResponse {
176 pub fn new(
180 mut input: IcSnapshotTransferReadResponseInput,
181 ) -> Result<Self, IcSnapshotTransferReadError> {
182 if input.mutation_attempt == 0 || input.mutation_attempt > MAX_OPERATION_ATTEMPTS {
183 return Err(IcSnapshotTransferReadError::InvalidAttempt);
184 }
185 if input.reply.len() > MAX_IC_SNAPSHOT_DATA_REPLY_BYTES {
186 return Err(IcSnapshotTransferReadError::ReplyTooLarge);
187 }
188 input.target = crate::model::principal::canonical_text(&input.target)
189 .ok_or(IcSnapshotTransferReadError::InvalidTarget)?;
190 Ok(Self { input })
191 }
192 #[must_use]
194 pub const fn input(&self) -> &IcSnapshotTransferReadResponseInput {
195 &self.input
196 }
197}
198
199impl fmt::Debug for IcSnapshotTransferReadResponse {
200 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201 f.debug_struct("IcSnapshotTransferReadResponse")
202 .field("authority", &self.input.authority)
203 .field("mutation_attempt", &self.input.mutation_attempt)
204 .field("target", &self.input.target)
205 .field("reply_bytes", &self.input.reply.len())
206 .finish_non_exhaustive()
207 }
208}
209
210#[derive(Debug, Error)]
212pub enum IcSnapshotTransferReadError {
213 #[error("snapshot transfer read authority differs")]
215 AuthorityMismatch,
216 #[error("snapshot transfer read payload differs")]
218 PayloadMismatch,
219 #[error("snapshot transfer read requires a pending original update")]
221 NoPendingMutation,
222 #[error("snapshot transfer read original attempt differs")]
224 MutationMismatch,
225 #[error("snapshot transfer read recovery observation is pending")]
227 ObservationPending,
228 #[error("invalid snapshot transfer read attempt")]
230 InvalidAttempt,
231 #[error("snapshot transfer read reply too large")]
233 ReplyTooLarge,
234 #[error("invalid snapshot transfer read target")]
236 InvalidTarget,
237 #[error(transparent)]
239 Plan(#[from] OperationPlanError),
240}