Add validation logic to ProcessState
This commit is contained in:
parent
9fe7daecb0
commit
617c73a3de
@ -11,7 +11,83 @@ pub struct ProcessState {
|
||||
pub commited_in: OutPoint,
|
||||
pub encrypted_pcd: Value, // Some fields may be clear, if the owner of the process decides so
|
||||
pub keys: Map<String, Value>, // We may not always have all the keys
|
||||
pub validation_token: Vec<Proof>, // This signs the encrypted pcd
|
||||
pub validation_tokens: Vec<Proof>, // Signature of the hash of the encrypted pcd tagged with some decision like "yes" or "no"
|
||||
}
|
||||
|
||||
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.encrypted_pcd.as_object().unwrap()
|
||||
.iter()
|
||||
.filter_map(|(key, value)| {
|
||||
let previous_value = previous_state.encrypted_pcd.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()
|
||||
};
|
||||
|
||||
// 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())?;
|
||||
roles2rules.insert(role.to_string(), role_def);
|
||||
}
|
||||
} else {
|
||||
return Err(anyhow::anyhow!("Roles is not an object"));
|
||||
}
|
||||
} else {
|
||||
return Err(anyhow::anyhow!("Missing roles in the encrypted pcd"));
|
||||
}
|
||||
|
||||
// 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))
|
||||
})
|
||||
.collect();
|
||||
|
||||
if applicable_rules.is_empty() {
|
||||
return false; // No rules apply to this field, consider it invalid
|
||||
}
|
||||
|
||||
let validation_tokens: Vec<&Proof> = self.validation_tokens.iter().collect();
|
||||
|
||||
applicable_rules.into_iter().any(|(role_def, rule)| {
|
||||
rule.is_satisfied(field, AnkPcdHash::from_value(&self.encrypted_pcd), &validation_tokens, &role_def.members)
|
||||
})
|
||||
});
|
||||
|
||||
Ok(all_fields_validated)
|
||||
}
|
||||
}
|
||||
|
||||
/// A process is basically a succession of states
|
||||
|
Loading…
x
Reference in New Issue
Block a user