diff --git a/src/process.rs b/src/process.rs index 9d66c57..662d1c1 100644 --- a/src/process.rs +++ b/src/process.rs @@ -24,49 +24,65 @@ pub struct ProcessState { } impl ProcessState { - /// A state is valid if the attached validation_tokens satisfy the updated conditions defined in the encrypted_pcd - pub fn is_valid(&self, previous_state: Option<&ProcessState>) -> Result { - // Determine modified fields - let modified_fields: Vec = if let Some(previous_state) = previous_state { - let res: Vec = self + fn compute_modified_fields(&self, previous_state: Option<&ProcessState>) -> Vec { + let new_state = &self.encrypted_pcd; + + // Ensure the new state is a JSON object + let new_state_obj = new_state + .as_object() + .expect("New state should be a JSON object"); + + if let Some(prev_state) = previous_state { + // Previous state exists; compute differences + let previous_state_obj = prev_state .encrypted_pcd .as_object() - .unwrap() + .expect("Previous state should be a JSON object"); + + // Compute modified fields by comparing with previous state + new_state_obj .iter() .filter_map(|(key, value)| { - let previous_value = previous_state.encrypted_pcd.get(key); + let previous_value = previous_state_obj.get(key); if previous_value.is_none() || value != previous_value.unwrap() { Some(key.clone()) } else { None } }) - .collect(); - - if res.is_empty() { - return Err(anyhow::anyhow!("State is identical to the previous state")); - } - - res - } else { - self.encrypted_pcd - .as_object() - .unwrap() - .keys() - .cloned() .collect() - }; + } else { + // No previous state; all fields are considered modified + new_state_obj.keys().cloned().collect() + } + } + + pub fn is_valid( + &self, + previous_state: Option<&ProcessState>, + ) -> anyhow::Result<()> { + if self.validation_tokens.is_empty() { + return Err(anyhow::anyhow!("Can't validate a state with no proofs attached")); + } + + // Compute modified fields + let modified_fields = self.compute_modified_fields(previous_state); + + if modified_fields.is_empty() { + return Err(anyhow::anyhow!("State is identical to the previous state")); + } + + println!("modified fields: {:?}", modified_fields); + + // Compute the hash of the new state + let new_state_hash = AnkPcdHash::from_value(&self.encrypted_pcd); - // Extract roles and their definitions let mut fields2plains = Map::new(); self.encrypted_pcd .decrypt_fields(&self.keys, &mut fields2plains)?; let mut roles2rules: HashMap = HashMap::new(); if let Some(roles) = fields2plains.get("roles") { - if roles.is_null() { - return Err(anyhow::anyhow!("Can't decrypt roles in the encrypted pcd")); - } if let Some(roles_map) = roles.as_object() { for (role, conditions) in roles_map { let role_def = serde_json::from_value::(conditions.clone())?; @@ -81,31 +97,43 @@ impl ProcessState { // Check if each modified field satisfies at least one applicable rule across all roles let all_fields_validated = modified_fields.iter().all(|field| { - let applicable_rules: Vec<(&RoleDefinition, &ValidationRule)> = roles2rules - .values() - .flat_map(|role_def| { - role_def - .get_applicable_rules(field) - .into_iter() - .map(move |rule| (role_def, rule)) - }) + println!("validating field: {}", field); + // Collect applicable rules from all roles for the current field + let applicable_roles: Vec = roles2rules.iter() + .map(|(_, role_def)| { + let mut filtered_role_def = role_def.clone(); + let rules = filtered_role_def.get_applicable_rules(field); + filtered_role_def.validation_rules = rules.into_iter().map(|r| r.clone()).collect(); + filtered_role_def + }) .collect(); - if applicable_rules.is_empty() { + if applicable_roles.is_empty() { return false; // No rules apply to this field, consider it invalid } - applicable_rules.into_iter().any(|(role_def, rule)| { - rule.is_satisfied( - field, - AnkPcdHash::from_value(&self.encrypted_pcd), - &self.validation_tokens, - &role_def.members, - ) + println!("applicable_roles: {:?}", applicable_roles); + + // Check if any applicable rule is satisfied + applicable_roles.into_iter().any(|role_def| { + let res = false; + for rule in role_def.validation_rules { + rule.is_satisfied( + field, + new_state_hash.clone(), + &self.validation_tokens, + &role_def.members, + ); + } + res }) }); - Ok(all_fields_validated) + if all_fields_validated { + Ok(()) + } else { + Err(anyhow::anyhow!("Not enough valid proofs")) + } } }