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_for_journal(
102 operation_sequence,
103 journal,
104 IcSnapshotTransferReadError::Reservation(
105 crate::model::attempt_journal::MutationReservationError::AuthorityMismatch,
106 ),
107 )?;
108 payload.validate_binding(&authority)?;
109 let reservation = MutationReservation::new(authority, journal)?;
110 Ok(Self {
111 plan,
112 payload,
113 reservation,
114 })
115 }
116 #[must_use]
118 pub const fn plan(&self) -> &'request OperationPlanRecord {
119 self.plan
120 }
121 #[must_use]
123 pub const fn payload(&self) -> IcSnapshotTransferReadPayload<'request, 'metadata> {
124 self.payload
125 }
126 #[must_use]
128 pub const fn authority(&self) -> &AttemptAuthorityRecord {
129 &self.reservation.authority
130 }
131 #[must_use]
133 pub const fn mutation_attempt(&self) -> u32 {
134 self.reservation.mutation_attempt
135 }
136 pub fn validate_journal(
140 &self,
141 journal: &AttemptJournalRecord,
142 ) -> Result<(), IcSnapshotTransferReadError> {
143 self.reservation.validate(journal).map_err(Into::into)
144 }
145}
146
147#[derive(Clone)]
149pub struct IcSnapshotTransferReadResponse {
150 input: IcUpdateResponseInput,
151}
152
153impl IcSnapshotTransferReadResponse {
154 pub fn new(mut input: IcUpdateResponseInput) -> Result<Self, IcSnapshotTransferReadError> {
158 input.admit(MAX_IC_SNAPSHOT_DATA_REPLY_BYTES)?;
159 Ok(Self { input })
160 }
161 #[must_use]
163 pub const fn input(&self) -> &IcUpdateResponseInput {
164 &self.input
165 }
166}
167
168impl fmt::Debug for IcSnapshotTransferReadResponse {
169 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
170 self.input
171 .fmt_redacted(formatter, "IcSnapshotTransferReadResponse")
172 }
173}
174
175#[derive(Debug, Error)]
177pub enum IcSnapshotTransferReadError {
178 #[error("original mutation reservation rejected: {0}")]
180 Reservation(#[from] crate::model::attempt_journal::MutationReservationError),
181 #[error("snapshot transfer read payload differs")]
183 PayloadMismatch,
184 #[error("invalid snapshot transfer read attempt")]
186 InvalidAttempt,
187 #[error("snapshot transfer read reply too large")]
189 ReplyTooLarge,
190 #[error("invalid snapshot transfer read target")]
192 InvalidTarget,
193 #[error(transparent)]
195 Plan(#[from] OperationPlanError),
196}
197
198impl From<crate::model::ic_update_response::UpdateResponseAdmissionError>
199 for IcSnapshotTransferReadError
200{
201 fn from(error: crate::model::ic_update_response::UpdateResponseAdmissionError) -> Self {
202 match error {
203 crate::model::ic_update_response::UpdateResponseAdmissionError::InvalidAttempt => {
204 Self::InvalidAttempt
205 }
206 crate::model::ic_update_response::UpdateResponseAdmissionError::ReplyTooLarge => {
207 Self::ReplyTooLarge
208 }
209 crate::model::ic_update_response::UpdateResponseAdmissionError::InvalidTarget => {
210 Self::InvalidTarget
211 }
212 }
213 }
214}