ic_backup/ops/persistence/execution_settlement/
mod.rs1use super::json::check_json_size;
4use super::{
5 AttemptJournalError, BackupLayoutGuard, JournalLock, JournalLockError,
6 OperationPlanPersistenceError, PersistenceError, create_json_durable, read_json,
7 read_operation_plan,
8};
9use crate::{
10 model::{
11 artifacts::ArtifactChecksumRecord,
12 execution_settlement::{ExecutionSettlementRecord, MAX_EXECUTION_SETTLEMENT_BYTES},
13 },
14 policy::execution_settlement::{ExecutionSettlementPolicyError, validate},
15};
16use std::path::Path;
17use thiserror::Error;
18
19pub fn create_execution_settlement(
29 layout: &BackupLayoutGuard,
30 record: &ExecutionSettlementRecord,
31) -> Result<(), ExecutionSettlementPersistenceError> {
32 create_with(layout, record, create_json_durable)
33}
34fn create_with(
35 layout: &BackupLayoutGuard,
36 record: &ExecutionSettlementRecord,
37 writer: impl FnOnce(&Path, &ExecutionSettlementRecord) -> Result<(), PersistenceError>,
38) -> Result<(), ExecutionSettlementPersistenceError> {
39 layout.check_root()?;
40 let path = layout.root().join("execution-settlement.json");
41 let _lock = JournalLock::acquire(&path)?;
42 check_json_size(record, MAX_EXECUTION_SETTLEMENT_BYTES)?;
43 validate_retained(layout, record)?;
44 writer(&path, record)?;
45 Ok(())
46}
47pub fn read_execution_settlement(
55 layout: &BackupLayoutGuard,
56 expected_plan: &ArtifactChecksumRecord,
57 expected: &ArtifactChecksumRecord,
58) -> Result<ExecutionSettlementRecord, ExecutionSettlementPersistenceError> {
59 layout.check_root()?;
60 let path = layout.root().join("execution-settlement.json");
61 let _lock = JournalLock::acquire(&path)?;
62 let record: ExecutionSettlementRecord = read_json(&path, MAX_EXECUTION_SETTLEMENT_BYTES)?;
63 check_json_size(&record, MAX_EXECUTION_SETTLEMENT_BYTES)?;
64 if record.plan_intent() != expected_plan || &record.digest() != expected {
65 return Err(ExecutionSettlementPersistenceError::DigestMismatch);
66 }
67 validate_retained(layout, &record)?;
68 Ok(record)
69}
70fn validate_retained(
71 layout: &BackupLayoutGuard,
72 record: &ExecutionSettlementRecord,
73) -> Result<(), ExecutionSettlementPersistenceError> {
74 let plan = read_operation_plan(layout, record.plan_intent())?;
75 let authorities = plan.attempt_authorities()?;
76 let journals = super::attempt_journal::read_original_journals(layout, &authorities, None)?;
77 let references: Vec<_> = journals.iter().collect();
78 validate(&plan, &references, record)?;
79 layout.check_root()?;
80 Ok(())
81}
82#[derive(Debug, Error)]
84pub enum ExecutionSettlementPersistenceError {
85 #[error("execution settlement digest mismatch")]
87 DigestMismatch,
88 #[error(transparent)]
90 Plan(#[from] OperationPlanPersistenceError),
91 #[error(transparent)]
93 Authority(#[from] crate::model::operation_plan::OperationPlanError),
94 #[error(transparent)]
96 Journal(#[from] AttemptJournalError),
97 #[error(transparent)]
99 Policy(#[from] ExecutionSettlementPolicyError),
100 #[error(transparent)]
102 Lock(#[from] JournalLockError),
103 #[error(transparent)]
105 Persistence(#[from] PersistenceError),
106}
107#[cfg(all(test, unix))]
108mod tests;