use crate::{
model::{
attempt_journal::AttemptJournalRecord, execution_settlement::ExecutionSettlementRecord,
operation_plan::OperationPlanRecord,
},
policy::execution_progress::{
self, ExecutionProgressError, ExecutionProgressRequest, ExecutionProgressView,
OperationProgressState,
},
};
use std::collections::BTreeMap;
use thiserror::Error;
pub fn validate(
plan: &OperationPlanRecord,
journals: &[&AttemptJournalRecord],
settlement: &ExecutionSettlementRecord,
) -> Result<ExecutionProgressView, ExecutionSettlementPolicyError> {
if &plan.digest() != settlement.plan_intent() {
return Err(ExecutionSettlementPolicyError::IntentMismatch);
}
let view = execution_progress::progress(&ExecutionProgressRequest { plan, journals })?;
if let Some(operation) = view
.operations
.iter()
.find(|operation| operation.state != OperationProgressState::Applied)
{
return Err(ExecutionSettlementPolicyError::UnsettledOperation(
operation.operation_sequence,
));
}
if settlement.journals().len() != plan.operations().len() {
return Err(ExecutionSettlementPolicyError::JournalSetMismatch);
}
let actual: BTreeMap<_, _> = journals
.iter()
.map(|journal| (journal.authority().binding().operation_sequence(), *journal))
.collect();
for (row, operation) in settlement.journals().iter().zip(plan.operations()) {
if row.operation_sequence() != operation.operation_sequence() {
return Err(ExecutionSettlementPolicyError::JournalSetMismatch);
}
let journal = actual
.get(&row.operation_sequence())
.ok_or(ExecutionSettlementPolicyError::JournalSetMismatch)?;
if &journal.digest() != row.history() {
return Err(ExecutionSettlementPolicyError::HistoryMismatch(
row.operation_sequence(),
));
}
}
Ok(view)
}
#[derive(Debug, Eq, Error, PartialEq)]
pub enum ExecutionSettlementPolicyError {
#[error("execution settlement original plan mismatch")]
IntentMismatch,
#[error(transparent)]
Progress(#[from] ExecutionProgressError),
#[error("execution settlement operation {0} is not applied")]
UnsettledOperation(u64),
#[error("execution settlement journal set mismatch")]
JournalSetMismatch,
#[error("execution settlement journal {0} history mismatch")]
HistoryMismatch(u64),
}
#[cfg(test)]
mod tests;