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, ExecutionProgressError, ExecutionProgressRequest, ExecutionProgressView,
10 OperationProgressState,
11 },
12};
13use std::collections::BTreeMap;
14use thiserror::Error;
15
16pub fn validate(
28 plan: &OperationPlanRecord,
29 journals: &[&AttemptJournalRecord],
30 settlement: &ExecutionSettlementRecord,
31) -> Result<ExecutionProgressView, ExecutionSettlementPolicyError> {
32 if &plan.digest() != settlement.plan_intent() {
33 return Err(ExecutionSettlementPolicyError::IntentMismatch);
34 }
35 let view = execution_progress::progress(&ExecutionProgressRequest { plan, journals })?;
36 if let Some(operation) = view
37 .operations
38 .iter()
39 .find(|operation| operation.state != OperationProgressState::Applied)
40 {
41 return Err(ExecutionSettlementPolicyError::UnsettledOperation(
42 operation.operation_sequence,
43 ));
44 }
45 if settlement.journals().len() != plan.operations().len() {
46 return Err(ExecutionSettlementPolicyError::JournalSetMismatch);
47 }
48 let actual: BTreeMap<_, _> = journals
49 .iter()
50 .map(|journal| (journal.authority().binding().operation_sequence(), *journal))
51 .collect();
52 for (row, operation) in settlement.journals().iter().zip(plan.operations()) {
53 if row.operation_sequence() != operation.operation_sequence() {
54 return Err(ExecutionSettlementPolicyError::JournalSetMismatch);
55 }
56 let journal = actual
57 .get(&row.operation_sequence())
58 .ok_or(ExecutionSettlementPolicyError::JournalSetMismatch)?;
59 if &journal.digest() != row.history() {
60 return Err(ExecutionSettlementPolicyError::HistoryMismatch(
61 row.operation_sequence(),
62 ));
63 }
64 }
65 Ok(view)
66}
67#[derive(Debug, Eq, Error, PartialEq)]
69pub enum ExecutionSettlementPolicyError {
70 #[error("execution settlement original plan mismatch")]
72 IntentMismatch,
73 #[error(transparent)]
75 Progress(#[from] ExecutionProgressError),
76 #[error("execution settlement operation {0} is not applied")]
78 UnsettledOperation(u64),
79 #[error("execution settlement journal set mismatch")]
81 JournalSetMismatch,
82 #[error("execution settlement journal {0} history mismatch")]
84 HistoryMismatch(u64),
85}
86#[cfg(test)]
87mod tests;