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