ic_backup/policy/ic_mutation/
mod.rs1use super::response_identity::{ResponseIdentity, ResponseIdentityMismatch};
4use crate::model::{
5 attempt_journal::AttemptJournalRecord,
6 ic_lifecycle_reply::{IcLifecycleReply, IcLifecycleReplyError},
7 ic_mutation::{IcMutationAcknowledgement, IcMutationRequest, IcMutationRequestError},
8 ic_request::IcManagementMethodRecord,
9 ic_snapshot_reply::{IcSnapshotReply, IcSnapshotReplyError},
10};
11use thiserror::Error;
12
13#[derive(Debug)]
15pub enum IcMutationReplyView<'a> {
16 Capture(IcSnapshotReply<'a>),
18 Lifecycle(IcLifecycleReply<'a>),
20}
21
22#[derive(Debug)]
27pub struct IcMutationAcknowledgementView<'a> {
28 acknowledgement: &'a IcMutationAcknowledgement,
29 reply: IcMutationReplyView<'a>,
30}
31impl<'a> IcMutationAcknowledgementView<'a> {
32 #[must_use]
34 pub const fn acknowledgement(&self) -> &'a IcMutationAcknowledgement {
35 self.acknowledgement
36 }
37 #[must_use]
39 pub const fn reply(&self) -> &IcMutationReplyView<'a> {
40 &self.reply
41 }
42}
43
44pub fn validate_acknowledgement<'a>(
52 request: &IcMutationRequest<'a>,
53 journal: &AttemptJournalRecord,
54 acknowledgement: &'a IcMutationAcknowledgement,
55) -> Result<IcMutationAcknowledgementView<'a>, IcMutationAssociationError> {
56 request.validate_journal(journal)?;
57 let input = acknowledgement.input();
58 ResponseIdentity {
59 authority: &input.authority,
60 mutation_attempt: input.mutation_attempt,
61 context: &input.context,
62 target: &input.target,
63 }
64 .compare(&ResponseIdentity {
65 authority: &request.authority().digest(),
66 mutation_attempt: request.mutation_attempt(),
67 context: request.plan().context(),
68 target: request.payload().target(),
69 })
70 .map_err(|mismatch| match mismatch {
71 ResponseIdentityMismatch::Authority => IcMutationAssociationError::AuthorityMismatch,
72 ResponseIdentityMismatch::Attempt => IcMutationAssociationError::AttemptMismatch,
73 ResponseIdentityMismatch::Context => IcMutationAssociationError::ContextMismatch,
74 ResponseIdentityMismatch::Target => IcMutationAssociationError::TargetMismatch,
75 })?;
76 let reply = match request.payload().method() {
77 IcManagementMethodRecord::TakeCanisterSnapshot => {
78 IcMutationReplyView::Capture(IcSnapshotReply::decode(request.payload(), &input.reply)?)
79 }
80 _ => IcMutationReplyView::Lifecycle(IcLifecycleReply::decode(
83 request.payload(),
84 &input.reply,
85 )?),
86 };
87 Ok(IcMutationAcknowledgementView {
88 acknowledgement,
89 reply,
90 })
91}
92
93#[derive(Debug, Error)]
95pub enum IcMutationAssociationError {
96 #[error(transparent)]
98 Reservation(#[from] IcMutationRequestError),
99 #[error("IC mutation acknowledgement authority mismatch")]
101 AuthorityMismatch,
102 #[error("IC mutation acknowledgement attempt mismatch")]
104 AttemptMismatch,
105 #[error("IC mutation acknowledgement context mismatch")]
107 ContextMismatch,
108 #[error("IC mutation acknowledgement target mismatch")]
110 TargetMismatch,
111 #[error(transparent)]
113 Snapshot(#[from] IcSnapshotReplyError),
114 #[error(transparent)]
116 Lifecycle(#[from] IcLifecycleReplyError),
117}
118
119#[cfg(test)]
120mod tests;