ic_backup/model/ic_snapshot_transfer_read/
mod.rs1use crate::model::ic_update_response::IcUpdateResponseInput;
4use crate::model::{
5 artifacts::ArtifactChecksumRecord,
6 attempt_journal::{AttemptAuthorityRecord, AttemptJournalRecord},
7 ic_snapshot_data::{IcSnapshotDataRequest, MAX_IC_SNAPSHOT_DATA_REPLY_BYTES},
8 ic_snapshot_metadata::IcSnapshotMetadataRequest,
9 operation_plan::{OperationPlanError, OperationPlanRecord},
10};
11use std::fmt;
12use thiserror::Error;
13
14#[derive(Clone, Copy, Debug)]
16pub enum IcSnapshotTransferReadPayload<'request, 'metadata> {
17 Metadata(&'request IcSnapshotMetadataRequest),
19 Data(&'request IcSnapshotDataRequest<'metadata>),
21}
22
23impl IcSnapshotTransferReadPayload<'_, '_> {
24 pub(crate) fn validate_binding(
25 &self,
26 authority: &AttemptAuthorityRecord,
27 ) -> Result<(), IcSnapshotTransferReadError> {
28 if self.target() != authority.binding().target()
29 || self.digest().hash() != authority.binding().request()
30 {
31 return Err(IcSnapshotTransferReadError::PayloadMismatch);
32 }
33 Ok(())
34 }
35 #[must_use]
37 pub fn target(&self) -> &str {
38 match self {
39 Self::Metadata(payload) => payload.target(),
40 Self::Data(payload) => payload.target(),
41 }
42 }
43 #[must_use]
45 pub const fn receiver(&self) -> &'static str {
46 match self {
47 Self::Metadata(payload) => payload.receiver(),
48 Self::Data(payload) => payload.receiver(),
49 }
50 }
51 #[must_use]
53 pub const fn method(&self) -> &'static str {
54 match self {
55 Self::Metadata(payload) => payload.method(),
56 Self::Data(payload) => payload.method(),
57 }
58 }
59 #[must_use]
61 pub fn arguments(&self) -> &[u8] {
62 match self {
63 Self::Metadata(payload) => payload.arguments(),
64 Self::Data(payload) => payload.arguments(),
65 }
66 }
67 #[must_use]
69 pub fn digest(&self) -> ArtifactChecksumRecord {
70 match self {
71 Self::Metadata(payload) => payload.digest(),
72 Self::Data(payload) => payload.digest(),
73 }
74 }
75}
76
77#[derive(Debug)]
83pub struct IcSnapshotTransferReadRequest<'request, 'metadata> {
84 plan: &'request OperationPlanRecord,
85 payload: IcSnapshotTransferReadPayload<'request, 'metadata>,
86 authority: AttemptAuthorityRecord,
87 mutation_attempt: u32,
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 mutation_attempt = journal
107 .pending_mutation()
108 .ok_or(IcSnapshotTransferReadError::NoPendingMutation)?;
109 let request = Self {
110 plan,
111 payload,
112 authority,
113 mutation_attempt,
114 };
115 request.validate_journal(journal)?;
116 Ok(request)
117 }
118 #[must_use]
120 pub const fn plan(&self) -> &'request OperationPlanRecord {
121 self.plan
122 }
123 #[must_use]
125 pub const fn payload(&self) -> IcSnapshotTransferReadPayload<'request, 'metadata> {
126 self.payload
127 }
128 #[must_use]
130 pub const fn authority(&self) -> &AttemptAuthorityRecord {
131 &self.authority
132 }
133 #[must_use]
135 pub const fn mutation_attempt(&self) -> u32 {
136 self.mutation_attempt
137 }
138 pub fn validate_journal(
142 &self,
143 journal: &AttemptJournalRecord,
144 ) -> Result<(), IcSnapshotTransferReadError> {
145 journal.validate_pending_mutation(
146 &self.authority,
147 self.mutation_attempt,
148 IcSnapshotTransferReadError::AuthorityMismatch,
149 IcSnapshotTransferReadError::MutationMismatch,
150 IcSnapshotTransferReadError::ObservationPending,
151 )
152 }
153}
154
155#[derive(Clone)]
157pub struct IcSnapshotTransferReadResponse {
158 input: IcUpdateResponseInput,
159}
160
161impl IcSnapshotTransferReadResponse {
162 pub fn new(mut input: IcUpdateResponseInput) -> Result<Self, IcSnapshotTransferReadError> {
166 input.admit(
167 MAX_IC_SNAPSHOT_DATA_REPLY_BYTES,
168 IcSnapshotTransferReadError::InvalidAttempt,
169 IcSnapshotTransferReadError::ReplyTooLarge,
170 IcSnapshotTransferReadError::InvalidTarget,
171 )?;
172 Ok(Self { input })
173 }
174 #[must_use]
176 pub const fn input(&self) -> &IcUpdateResponseInput {
177 &self.input
178 }
179}
180
181impl fmt::Debug for IcSnapshotTransferReadResponse {
182 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
183 self.input
184 .fmt_redacted(formatter, "IcSnapshotTransferReadResponse")
185 }
186}
187
188#[derive(Debug, Error)]
190pub enum IcSnapshotTransferReadError {
191 #[error("snapshot transfer read authority differs")]
193 AuthorityMismatch,
194 #[error("snapshot transfer read payload differs")]
196 PayloadMismatch,
197 #[error("snapshot transfer read requires a pending original update")]
199 NoPendingMutation,
200 #[error("snapshot transfer read original attempt differs")]
202 MutationMismatch,
203 #[error("snapshot transfer read recovery observation is pending")]
205 ObservationPending,
206 #[error("invalid snapshot transfer read attempt")]
208 InvalidAttempt,
209 #[error("snapshot transfer read reply too large")]
211 ReplyTooLarge,
212 #[error("invalid snapshot transfer read target")]
214 InvalidTarget,
215 #[error(transparent)]
217 Plan(#[from] OperationPlanError),
218}