ic_backup/policy/execution_settlement/
mod.rs1use crate::{
4 model::{
5 attempt_journal::AttemptJournalRecord, execution_settlement::ExecutionSettlementRecord,
6 operation_plan::OperationPlanRecord,
7 },
8 policy::execution_progress::{
9 self, AdmittedProgress, ExecutionProgressError, ExecutionProgressView,
10 OperationProgressState,
11 },
12};
13use thiserror::Error;
14
15pub fn validate(
27 plan: &OperationPlanRecord,
28 journals: &[&AttemptJournalRecord],
29 settlement: &ExecutionSettlementRecord,
30) -> Result<ExecutionProgressView, ExecutionSettlementPolicyError> {
31 validate_journals(plan, journals.iter().copied(), settlement)
32}
33
34pub(crate) fn validate_journals<'a>(
35 plan: &OperationPlanRecord,
36 journals: impl ExactSizeIterator<Item = &'a AttemptJournalRecord>,
37 settlement: &ExecutionSettlementRecord,
38) -> Result<ExecutionProgressView, ExecutionSettlementPolicyError> {
39 if &plan.digest() != settlement.plan_intent() {
40 return Err(ExecutionSettlementPolicyError::IntentMismatch);
41 }
42 let AdmittedProgress {
43 view,
44 journals: actual,
45 } = execution_progress::progress_with_journals(plan, journals)?;
46 if let Some(operation) = view
47 .operations
48 .iter()
49 .find(|operation| operation.state != OperationProgressState::Applied)
50 {
51 return Err(ExecutionSettlementPolicyError::UnsettledOperation(
52 operation.operation_sequence,
53 ));
54 }
55 if settlement.journals().len() != plan.operations().len() {
56 return Err(ExecutionSettlementPolicyError::JournalSetMismatch);
57 }
58 for (row, operation) in settlement.journals().iter().zip(plan.operations()) {
59 if row.operation_sequence() != operation.operation_sequence() {
60 return Err(ExecutionSettlementPolicyError::JournalSetMismatch);
61 }
62 let journal = actual
63 .get(&row.operation_sequence())
64 .ok_or(ExecutionSettlementPolicyError::JournalSetMismatch)?;
65 if &journal.digest() != row.history() {
66 return Err(ExecutionSettlementPolicyError::HistoryMismatch(
67 row.operation_sequence(),
68 ));
69 }
70 }
71 Ok(view)
72}
73#[derive(Debug, Eq, Error, PartialEq)]
75pub enum ExecutionSettlementPolicyError {
76 #[error("execution settlement original plan mismatch")]
78 IntentMismatch,
79 #[error(transparent)]
81 Progress(#[from] ExecutionProgressError),
82 #[error("execution settlement operation {0} is not applied")]
84 UnsettledOperation(u64),
85 #[error("execution settlement journal set mismatch")]
87 JournalSetMismatch,
88 #[error("execution settlement journal {0} history mismatch")]
90 HistoryMismatch(u64),
91}
92#[cfg(test)]
93mod tests;