Update process states validation logic

This commit is contained in:
Sosthene 2024-10-07 11:16:35 +02:00
parent 7a4344608e
commit 4744740303

View File

@ -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<bool, anyhow::Error> {
// Determine modified fields
let modified_fields: Vec<String> = if let Some(previous_state) = previous_state {
let res: Vec<String> = self
fn compute_modified_fields(&self, previous_state: Option<&ProcessState>) -> Vec<String> {
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();
.collect()
} else {
// No previous state; all fields are considered modified
new_state_obj.keys().cloned().collect()
}
}
if res.is_empty() {
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"));
}
res
} else {
self.encrypted_pcd
.as_object()
.unwrap()
.keys()
.cloned()
.collect()
};
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<String, RoleDefinition> = 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::<RoleDefinition>(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<RoleDefinition> = 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)| {
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,
AnkPcdHash::from_value(&self.encrypted_pcd),
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"))
}
}
}