ic_backup/model/ic_snapshot_upload_observation/
mod.rs1use crate::model::{
4 attempt_journal::{AttemptAuthorityRecord, AttemptJournalRecord},
5 ic_observation::{IcObservationRequestError, ObservationReservation, pending_attempts},
6 ic_request::{IcManagementMethodRecord, IcManagementRequestRecord},
7 ic_snapshot_upload::{
8 IcSnapshotUploadAttemptError, IcSnapshotUploadKind, IcSnapshotUploadRequest,
9 original_authority,
10 },
11 operation_plan::OperationPlanRecord,
12};
13use thiserror::Error;
14
15mod settlement;
16pub use settlement::{IcSnapshotUploadAttribution, IcSnapshotUploadSettlement};
17
18#[derive(Debug)]
25pub struct IcSnapshotUploadObservationRequest<'request, 'source> {
26 plan: &'request OperationPlanRecord,
27 mutation: &'request IcSnapshotUploadRequest<'source>,
28 payload: &'request IcManagementRequestRecord,
29 authority: AttemptAuthorityRecord,
30 mutation_attempt: u32,
31 observation_attempt: u32,
32}
33
34impl<'request, 'source> IcSnapshotUploadObservationRequest<'request, 'source> {
35 pub fn new(
42 plan: &'request OperationPlanRecord,
43 operation_sequence: u64,
44 journal: &AttemptJournalRecord,
45 mutation: &'request IcSnapshotUploadRequest<'source>,
46 payload: &'request IcManagementRequestRecord,
47 ) -> Result<Self, IcSnapshotUploadObservationError> {
48 if !matches!(mutation.kind(), IcSnapshotUploadKind::Metadata) {
49 return Err(IcSnapshotUploadObservationError::UnsupportedUpload);
50 }
51 if payload.method() != IcManagementMethodRecord::ListCanisterSnapshots {
52 return Err(IcSnapshotUploadObservationError::UnsupportedObservation);
53 }
54 let authority = original_authority(plan, operation_sequence, journal, mutation)?;
55 payload
56 .validate_observation_binding(authority.binding(), &payload.digest())
57 .map_err(IcObservationRequestError::from)?;
58 let (mutation_attempt, observation_attempt) = pending_attempts(journal)?;
59 let request = Self {
60 plan,
61 mutation,
62 payload,
63 authority,
64 mutation_attempt,
65 observation_attempt,
66 };
67 request.validate_journal(journal)?;
68 Ok(request)
69 }
70
71 #[must_use]
73 pub const fn plan(&self) -> &OperationPlanRecord {
74 self.plan
75 }
76 #[must_use]
78 pub const fn mutation(&self) -> &'request IcSnapshotUploadRequest<'source> {
79 self.mutation
80 }
81 #[must_use]
83 pub const fn payload(&self) -> &'request IcManagementRequestRecord {
84 self.payload
85 }
86 #[must_use]
88 pub const fn authority(&self) -> &AttemptAuthorityRecord {
89 &self.authority
90 }
91 #[must_use]
93 pub const fn mutation_attempt(&self) -> u32 {
94 self.mutation_attempt
95 }
96 #[must_use]
98 pub const fn observation_attempt(&self) -> u32 {
99 self.observation_attempt
100 }
101 pub fn validate_journal(
105 &self,
106 journal: &AttemptJournalRecord,
107 ) -> Result<(), IcObservationRequestError> {
108 ObservationReservation {
109 authority: &self.authority,
110 mutation_attempt: self.mutation_attempt,
111 observation_attempt: self.observation_attempt,
112 request: self.payload.digest(),
113 }
114 .validate(journal)
115 }
116}
117
118#[derive(Debug, Error)]
120pub enum IcSnapshotUploadObservationError {
121 #[error("snapshot upload observation requires metadata intent")]
123 UnsupportedUpload,
124 #[error("snapshot upload observation requires snapshot list")]
126 UnsupportedObservation,
127 #[error(transparent)]
129 Upload(#[from] IcSnapshotUploadAttemptError),
130 #[error(transparent)]
132 Observation(#[from] IcObservationRequestError),
133}
134
135#[cfg(test)]
136mod tests;