Update process states validation logic
This commit is contained in:
parent
7a4344608e
commit
4744740303
@ -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"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user