Roles is now part of ProcessState out of the pcd
This commit is contained in:
parent
ab1c16ff81
commit
46d405f046
31
src/pcd.rs
31
src/pcd.rs
@ -1,7 +1,7 @@
|
|||||||
use anyhow::{Error, Result};
|
use anyhow::{Error, Result};
|
||||||
use rs_merkle::{algorithms::Sha256, MerkleTree};
|
use rs_merkle::{algorithms::Sha256, MerkleTree};
|
||||||
use serde::ser::SerializeStruct;
|
use serde::ser::SerializeStruct;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::HashSet;
|
||||||
use std::hash::{Hash as StdHash, Hasher};
|
use std::hash::{Hash as StdHash, Hasher};
|
||||||
use std::fmt;
|
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<()> {
|
fn is_hex_string(&self, length: Option<usize>) -> Result<()> {
|
||||||
let value = serde_json::to_value(self)?;
|
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 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 = AnkValidationYesHash::from_merkle_root(new_state_merkle_root);
|
||||||
// let validation_hash = AnkValidationNoHash::from_commitment(new_state_hash);
|
|
||||||
|
|
||||||
let alice_spend_key: SecretKey = alice_wallet
|
let alice_spend_key: SecretKey = alice_wallet
|
||||||
.get_client()
|
.get_client()
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, HashSet},
|
collections::{BTreeMap, HashMap, HashSet},
|
||||||
sync::{Mutex, MutexGuard, OnceLock},
|
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"
|
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>")]
|
#[tsify(type = "Record<string, string>")]
|
||||||
pub descriptions: Map<String, Value>, // long descriptions that can be used for the ihm
|
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 {
|
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
|
// Check all descriptions matches clear_state
|
||||||
for (key, _) in &descriptions {
|
for (key, _) in &descriptions {
|
||||||
clear_state.get(key).ok_or(anyhow::Error::msg("Missing field in descriptions"))?;
|
clear_state.get(key).ok_or(anyhow::Error::msg("Missing field in descriptions"))?;
|
||||||
@ -59,6 +61,7 @@ impl ProcessState {
|
|||||||
keys,
|
keys,
|
||||||
validation_tokens: vec![],
|
validation_tokens: vec![],
|
||||||
descriptions,
|
descriptions,
|
||||||
|
roles,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(res)
|
Ok(res)
|
||||||
@ -160,22 +163,11 @@ impl ProcessState {
|
|||||||
return Err(anyhow::anyhow!("State is identical to the previous state"));
|
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
|
// Check if each modified field satisfies at least one applicable rule across all roles
|
||||||
let all_fields_validated = modified_fields.iter().all(|field| {
|
let all_fields_validated = modified_fields.iter().all(|field| {
|
||||||
// Collect applicable rules from all roles for the current 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()
|
.iter()
|
||||||
.filter_map(|(_, role_def)| {
|
.filter_map(|(_, role_def)| {
|
||||||
let mut filtered_role_def = role_def.clone();
|
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>> {
|
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();
|
let mut res: HashSet<String> = HashSet::new();
|
||||||
|
|
||||||
// Are we in that role?
|
// Are we in that role?
|
||||||
for (_, role_def) in roles {
|
for (_, role_def) in &self.roles {
|
||||||
if !role_def.members.contains(member) {
|
if !role_def.members.contains(member) {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
// what are the fields we can modify?
|
// 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() {
|
if rule.allows_modification() {
|
||||||
res.extend(rule.fields.iter().map(|f| f.clone()));
|
res.extend(rule.fields.iter().map(|f| f.clone()));
|
||||||
}
|
}
|
||||||
@ -656,7 +644,7 @@ mod tests {
|
|||||||
let carol = Member::new(vec![carol_address]).unwrap();
|
let carol = Member::new(vec![carol_address]).unwrap();
|
||||||
|
|
||||||
let validation_rule1 =
|
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 validation_rule2 = ValidationRule::new(1.0, vec!["field2".to_owned()], 0.5).unwrap();
|
||||||
|
|
||||||
let role_def1 = RoleDefinition {
|
let role_def1 = RoleDefinition {
|
||||||
@ -670,18 +658,19 @@ mod tests {
|
|||||||
storages: vec![]
|
storages: vec![]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let roles: BTreeMap<String, RoleDefinition> = BTreeMap::from([
|
||||||
|
("role1".to_owned(), role_def1),
|
||||||
|
("role2".to_owned(), role_def2)
|
||||||
|
]);
|
||||||
|
|
||||||
let clear_pcd = json!({
|
let clear_pcd = json!({
|
||||||
"field1": "value1",
|
"field1": "value1",
|
||||||
"field2": "value2",
|
"field2": "value2",
|
||||||
"roles": {
|
|
||||||
"role1": role_def1,
|
|
||||||
"role2": role_def2
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let outpoint = OutPoint::null();
|
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]
|
#[test]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user