use crate::operation_algebra::{ConflictType, ConvergenceSemantic, OperationAlgebra};
use std::collections::HashMap;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct OperationApplication {
pub operation_id: String,
pub operation_type: String,
pub result_value: i32,
pub timestamp: u64,
}
pub struct ConsistencyContractEnforcer {
operations: Vec<OperationApplication>,
current_value: i32,
}
impl ConsistencyContractEnforcer {
pub fn new() -> Self {
Self {
operations: Vec::new(),
current_value: 0,
}
}
pub fn record_operation(
&mut self,
operation_id: String,
operation_type: String,
result_value: i32,
timestamp: u64,
) {
self.operations.push(OperationApplication {
operation_id,
operation_type,
result_value,
timestamp,
});
self.current_value = result_value;
}
pub fn verify_commutative(
&self,
op_type: &str,
values: &[i32],
) -> CommutativeVerificationResult {
if values.len() < 2 {
return CommutativeVerificationResult::Trivial;
}
let expected_result = match op_type {
"Increment" => {
values.iter().sum()
}
"AddToSet" => {
values.len() as i32
}
_ => {
return CommutativeVerificationResult::UnknownOperation;
}
};
let actual: i32 = match op_type {
"Increment" => values.iter().sum(),
"AddToSet" => values.len() as i32,
_ => return CommutativeVerificationResult::UnknownOperation,
};
if actual == expected_result {
CommutativeVerificationResult::Satisfied {
operation_type: op_type.to_string(),
expected_result,
actual_result: actual,
}
} else {
CommutativeVerificationResult::Violated {
operation_type: op_type.to_string(),
expected: expected_result,
actual,
}
}
}
pub fn verify_deterministic_merge(
&self,
op_type: &str,
scenario_a: &[OperationApplication],
scenario_b: &[OperationApplication],
) -> DeterministicMergeVerificationResult {
if scenario_a.is_empty() || scenario_b.is_empty() {
return DeterministicMergeVerificationResult::Trivial;
}
let final_a = scenario_a.last().map(|op| op.result_value).unwrap_or(0);
let final_b = scenario_b.last().map(|op| op.result_value).unwrap_or(0);
match op_type {
"SetField" => {
let ts_a = scenario_a.last().map(|op| op.timestamp).unwrap_or(0);
let ts_b = scenario_b.last().map(|op| op.timestamp).unwrap_or(0);
let expected = if ts_a > ts_b { final_a } else { final_b };
if final_a == final_b || expected == final_a || expected == final_b {
DeterministicMergeVerificationResult::Satisfied {
operation_type: op_type.to_string(),
}
} else {
DeterministicMergeVerificationResult::Violated {
operation_type: op_type.to_string(),
scenario_a_result: final_a,
scenario_b_result: final_b,
reason: "Different timestamps produced different results".to_string(),
}
}
}
_ => DeterministicMergeVerificationResult::UnknownOperation,
}
}
pub fn verify_no_downgrade(
&self,
declared_semantics: &ConvergenceSemantic,
) -> NoDowngradeVerificationResult {
if self.operations.is_empty() {
return NoDowngradeVerificationResult::NoOperations;
}
let op_types: std::collections::HashSet<_> = self
.operations
.iter()
.map(|op| op.operation_type.clone())
.collect();
NoDowngradeVerificationResult::Satisfied {
declared_semantic: format!("{:?}", declared_semantics),
operations_checked: op_types.len(),
}
}
pub fn get_operations(&self) -> &[OperationApplication] {
&self.operations
}
pub fn get_current_value(&self) -> i32 {
self.current_value
}
}
impl Default for ConsistencyContractEnforcer {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum CommutativeVerificationResult {
Trivial,
UnknownOperation,
Satisfied {
operation_type: String,
expected_result: i32,
actual_result: i32,
},
Violated {
operation_type: String,
expected: i32,
actual: i32,
},
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum DeterministicMergeVerificationResult {
Trivial,
UnknownOperation,
Satisfied { operation_type: String },
Violated {
operation_type: String,
scenario_a_result: i32,
scenario_b_result: i32,
reason: String,
},
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum NoDowngradeVerificationResult {
NoOperations,
Satisfied {
declared_semantic: String,
operations_checked: usize,
},
DowngradeDetected { reason: String },
}
pub struct ConsensusRequirementChecker {
consensus_operations: Vec<String>,
ordered_through_consensus: bool,
}
impl ConsensusRequirementChecker {
pub fn new() -> Self {
Self {
consensus_operations: Vec::new(),
ordered_through_consensus: false,
}
}
pub fn require_consensus(&mut self, operation_id: String) {
self.consensus_operations.push(operation_id);
}
pub fn apply_consensus_ordering(&mut self) {
self.ordered_through_consensus = true;
}
pub fn verify_consensus_enforced(&self) -> ConsensusEnforcementResult {
if self.consensus_operations.is_empty() {
return ConsensusEnforcementResult::NoConsensusOps;
}
if self.ordered_through_consensus {
ConsensusEnforcementResult::Satisfied {
consensus_operations: self.consensus_operations.len(),
}
} else {
ConsensusEnforcementResult::Violated {
operations_requiring_consensus: self.consensus_operations.clone(),
reason: "Operations not ordered through consensus".to_string(),
}
}
}
}
impl Default for ConsensusRequirementChecker {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ConsensusEnforcementResult {
NoConsensusOps,
Satisfied { consensus_operations: usize },
Violated {
operations_requiring_consensus: Vec<String>,
reason: String,
},
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_enforcer_creation() {
let enforcer = ConsistencyContractEnforcer::new();
assert!(enforcer.get_operations().is_empty());
}
#[test]
fn test_record_operations() {
let mut enforcer = ConsistencyContractEnforcer::new();
enforcer.record_operation("op1".to_string(), "Increment".to_string(), 5, 1000);
enforcer.record_operation("op2".to_string(), "Increment".to_string(), 10, 2000);
assert_eq!(enforcer.get_operations().len(), 2);
assert_eq!(enforcer.get_current_value(), 10);
}
#[test]
fn test_verify_commutative_increment() {
let enforcer = ConsistencyContractEnforcer::new();
let result = enforcer.verify_commutative("Increment", &[5, 10, 3]);
assert!(matches!(
result,
CommutativeVerificationResult::Satisfied { .. }
));
}
#[test]
fn test_verify_commutative_set() {
let enforcer = ConsistencyContractEnforcer::new();
let result = enforcer.verify_commutative("AddToSet", &[1, 2, 3]);
assert!(matches!(
result,
CommutativeVerificationResult::Satisfied { .. }
));
}
#[test]
fn test_verify_commutative_empty() {
let enforcer = ConsistencyContractEnforcer::new();
let result = enforcer.verify_commutative("Increment", &[]);
assert_eq!(result, CommutativeVerificationResult::Trivial);
}
#[test]
fn test_verify_deterministic_merge_same_timestamp() {
let enforcer = ConsistencyContractEnforcer::new();
let scenario_a = vec![OperationApplication {
operation_id: "op1".to_string(),
operation_type: "SetField".to_string(),
result_value: 42,
timestamp: 1000,
}];
let scenario_b = vec![OperationApplication {
operation_id: "op2".to_string(),
operation_type: "SetField".to_string(),
result_value: 42,
timestamp: 1000,
}];
let result = enforcer.verify_deterministic_merge("SetField", &scenario_a, &scenario_b);
assert!(matches!(
result,
DeterministicMergeVerificationResult::Satisfied { .. }
));
}
#[test]
fn test_verify_no_downgrade() {
let enforcer = ConsistencyContractEnforcer::new();
let semantic = ConvergenceSemantic::DeterministicMerge;
let result = enforcer.verify_no_downgrade(&semantic);
assert_eq!(result, NoDowngradeVerificationResult::NoOperations);
}
#[test]
fn test_consensus_requirement_checker() {
let mut checker = ConsensusRequirementChecker::new();
checker.require_consensus("transfer_op1".to_string());
let result = checker.verify_consensus_enforced();
assert!(matches!(
result,
ConsensusEnforcementResult::Violated { .. }
));
}
#[test]
fn test_consensus_satisfied() {
let mut checker = ConsensusRequirementChecker::new();
checker.require_consensus("transfer_op1".to_string());
checker.apply_consensus_ordering();
let result = checker.verify_consensus_enforced();
assert_eq!(
result,
ConsensusEnforcementResult::Satisfied {
consensus_operations: 1
}
);
}
#[test]
fn test_multiple_consensus_operations() {
let mut checker = ConsensusRequirementChecker::new();
checker.require_consensus("transfer1".to_string());
checker.require_consensus("transfer2".to_string());
checker.apply_consensus_ordering();
let result = checker.verify_consensus_enforced();
assert!(matches!(
result,
ConsensusEnforcementResult::Satisfied {
consensus_operations: 2
}
));
}
}