Roles is now part of ProcessState out of the pcd

This commit is contained in:
NicolasCantu 2025-02-07 22:44:14 +01:00
parent 855cd948ef
commit 17ad1a0319
2 changed files with 16 additions and 56 deletions

View File

@ -1,7 +1,7 @@
use anyhow::{Error, Result};
use rs_merkle::{algorithms::Sha256, MerkleTree};
use serde::ser::SerializeStruct;
use std::collections::{HashMap, HashSet};
use std::collections::HashSet;
use std::hash::{Hash as StdHash, Hasher};
use std::fmt;
@ -336,34 +336,6 @@ pub trait Pcd<'a>: Serialize + Deserialize<'a> {
}
}
fn extract_roles(&self) -> Result<HashMap<String, RoleDefinition>> {
let obj = self.to_value_object()?;
let parse_roles_map = |m: &Map<String, Value>| {
let mut res: HashMap<String, RoleDefinition> = HashMap::new();
for (name, role_def) in m {
res.insert(name.clone(), serde_json::from_value(role_def.clone())?);
}
<Result<HashMap<String, RoleDefinition>, Error>>::Ok(res)
};
if let Some(roles) = obj.get("roles") {
match roles {
Value::Object(m) => {
parse_roles_map(m)
},
Value::String(s) => {
let m: Map<String, Value> = serde_json::from_str(&s)?;
parse_roles_map(&m)
}
_ => Err(Error::msg("\"roles\" is not an object"))
}
} else {
Err(Error::msg("No \"roles\" key in this pcd"))
}
}
fn is_hex_string(&self, length: Option<usize>) -> Result<()> {
let value = serde_json::to_value(self)?;
@ -1003,7 +975,6 @@ mod tests {
let new_state_merkle_root = Value::Object(new_state_commitments).create_merkle_tree().unwrap().root().unwrap();
let validation_hash = AnkValidationYesHash::from_merkle_root(new_state_merkle_root);
// let validation_hash = AnkValidationNoHash::from_commitment(new_state_hash);
let alice_spend_key: SecretKey = alice_wallet
.get_client()

View File

@ -1,5 +1,5 @@
use std::{
collections::{HashMap, HashSet},
collections::{BTreeMap, HashMap, HashSet},
sync::{Mutex, MutexGuard, OnceLock},
};
@ -28,10 +28,12 @@ pub struct ProcessState {
pub validation_tokens: Vec<Proof>, // Signature of the hash of the encrypted pcd tagged with some decision like "yes" or "no"
#[tsify(type = "Record<string, string>")]
pub descriptions: Map<String, Value>, // long descriptions that can be used for the ihm
#[tsify(type = "Record<string, RoleDefinition>")]
pub roles: BTreeMap<String, RoleDefinition>,
}
impl ProcessState {
pub fn new(commited_in: OutPoint, clear_state: Map<String, Value>, descriptions: Map<String, Value>) -> anyhow::Result<Self> {
pub fn new(commited_in: OutPoint, clear_state: Map<String, Value>, descriptions: Map<String, Value>, roles: BTreeMap<String, RoleDefinition>) -> anyhow::Result<Self> {
// Check all descriptions matches clear_state
for (key, _) in &descriptions {
clear_state.get(key).ok_or(anyhow::Error::msg("Missing field in descriptions"))?;
@ -59,6 +61,7 @@ impl ProcessState {
keys,
validation_tokens: vec![],
descriptions,
roles,
};
Ok(res)
@ -160,22 +163,11 @@ impl ProcessState {
return Err(anyhow::anyhow!("State is identical to the previous state"));
}
let roles2rules = match self.encrypted_pcd.extract_roles() {
Ok(roles) => roles,
Err(_) => {
let mut fields2plains = Map::new();
let fields2commit = self.pcd_commitment.as_object().ok_or(anyhow::Error::msg("pcd_commitment is not an object"))?;
self.encrypted_pcd
.decrypt_all(self.commited_in, &fields2commit, &self.keys, &mut fields2plains)?;
Value::Object(fields2plains).extract_roles()?
}
};
// Check if each modified field satisfies at least one applicable rule across all roles
let all_fields_validated = modified_fields.iter().all(|field| {
// Collect applicable rules from all roles for the current field
let applicable_roles: Vec<RoleDefinition> = roles2rules
let applicable_roles: Vec<RoleDefinition> = self.roles
.iter()
.filter_map(|(_, role_def)| {
let mut filtered_role_def = role_def.clone();
@ -222,19 +214,15 @@ impl ProcessState {
}
pub fn get_fields_to_validate_for_member(&self, member: &Member) -> anyhow::Result<Vec<String>> {
let decrypted = self.decrypt_pcd()?;
let roles = Value::Object(decrypted).extract_roles()?;
let mut res: HashSet<String> = HashSet::new();
// Are we in that role?
for (_, role_def) in roles {
for (_, role_def) in &self.roles {
if !role_def.members.contains(member) {
continue;
} else {
// what are the fields we can modify?
for rule in role_def.validation_rules {
for rule in &role_def.validation_rules {
if rule.allows_modification() {
res.extend(rule.fields.iter().map(|f| f.clone()));
}
@ -656,7 +644,7 @@ mod tests {
let carol = Member::new(vec![carol_address]).unwrap();
let validation_rule1 =
ValidationRule::new(1.0, vec!["field1".to_owned(), "roles".to_owned()], 0.5).unwrap();
ValidationRule::new(1.0, vec!["field1".to_owned()], 0.5).unwrap();
let validation_rule2 = ValidationRule::new(1.0, vec!["field2".to_owned()], 0.5).unwrap();
let role_def1 = RoleDefinition {
@ -670,18 +658,19 @@ mod tests {
storages: vec![]
};
let roles: BTreeMap<String, RoleDefinition> = BTreeMap::from([
("role1".to_owned(), role_def1),
("role2".to_owned(), role_def2)
]);
let clear_pcd = json!({
"field1": "value1",
"field2": "value2",
"roles": {
"role1": role_def1,
"role2": role_def2
}
});
let outpoint = OutPoint::null();
ProcessState::new(outpoint, clear_pcd.as_object().unwrap().clone(), Map::new()).unwrap()
ProcessState::new(outpoint, clear_pcd.as_object().unwrap().clone(), Map::new(), roles).unwrap()
}
#[test]