Replace Member with Outpoint in RoleDefinition

This commit is contained in:
NicolasCantu 2025-03-19 11:46:47 +01:00 committed by Nicolas Cantu
parent 2b511caa14
commit 70616dfc94
2 changed files with 50 additions and 9 deletions

View File

@ -17,6 +17,7 @@ use sp_client::{
};
use tsify::Tsify;
use crate::serialization::OutPointMemberMap;
use crate::{
signature::{AnkHash, AnkValidationNoHash, AnkValidationYesHash, Proof},
serialization::hex_array_btree
@ -316,7 +317,7 @@ impl ValidationRule {
field: &str,
merkle_root: [u8; 32],
proofs: &[Proof],
members: &[Member],
members: &[&Member],
) -> Result<()> {
// Check if this rule applies to the field
if !self.fields.contains(&field.to_string()) {
@ -329,6 +330,7 @@ impl ValidationRule {
let validating_members = members
.iter()
.filter(|member| {
if member.sp_addresses.is_empty() { return false }; // This can happen when a member in the rule wasn't found in the network
let member_proofs: Vec<&Proof> = proofs
.iter()
.filter(|p| member.key_is_part_of_member(&p.get_key()))
@ -398,7 +400,7 @@ impl ValidationRule {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Tsify)]
#[tsify(into_wasm_abi, from_wasm_abi)]
pub struct RoleDefinition {
pub members: Vec<Member>,
pub members: Vec<OutPoint>, // We use the pairing process id so we don't have to update the role if the user add a device
pub validation_rules: Vec<ValidationRule>,
pub storages: Vec<String>,
}
@ -409,11 +411,24 @@ impl RoleDefinition {
diff: Vec<String>,
new_state_merkle_root: [u8; 32],
proofs: &[Proof],
members_list: &OutPointMemberMap,
) -> Result<()> {
let empty_member = Member::new(vec![]);
if diff.iter().all(|field| {
self.validation_rules
.iter()
.any(|rule| rule.is_satisfied(field, new_state_merkle_root, proofs, &self.members).is_ok())
.any(|rule| {
let members: Vec<&Member> = self.members.iter()
.map(|outpoint| {
if let Some(member) = members_list.0.get(outpoint) {
member
} else {
&empty_member
}
})
.collect();
rule.is_satisfied(field, new_state_merkle_root, proofs, &members).is_ok()
})
})
{
Ok(())

View File

@ -99,16 +99,37 @@ impl ProcessState {
}
/// This is a simplified and streamlined validation for obliteration state
fn handle_obliteration(&self) -> anyhow::Result<()> {
fn handle_obliteration(&self, members_list: &OutPointMemberMap) -> anyhow::Result<()> {
// We need an Apophis role
if let Some(apophis) = self.roles.get(SpecialRoles::APOPHIS.to_string().as_str()) {
apophis.is_satisfied(vec!["".to_owned()], [0u8; 32], &self.validation_tokens)
// Apophis should have only one rule
if apophis.validation_rules.len() != 1 { return Err(anyhow::Error::msg("Should have only one rule")); };
let obliteration_rule = apophis.validation_rules.get(0).unwrap();
let empty_field = "";
// This rule should have only one empty string as field
if obliteration_rule.fields.len() != 1 { return Err(anyhow::Error::msg("Should have only one field")); };
if obliteration_rule.fields.get(0).unwrap() != empty_field { return Err(anyhow::Error::msg("Field should be empty")); };
let members: Vec<&Member> = apophis.members.iter()
.filter_map(|outpoint| {
members_list.0.get(outpoint)
})
.collect();
if apophis.validation_rules.iter().all(
|r| r.is_satisfied(empty_field, [0u8; 32], &self.validation_tokens, &members).is_ok()
) {
Ok(())
} else {
Err(anyhow::Error::msg("Apophis is not satisfied"))
}
} else {
Err(anyhow::Error::msg("Missing an apophis role"))
}
}
pub fn is_valid(&self, previous_state: Option<&ProcessState>) -> anyhow::Result<()> {
pub fn is_valid(&self, previous_state: Option<&ProcessState>, members_list: &OutPointMemberMap) -> anyhow::Result<()> {
if self.validation_tokens.is_empty() {
return Err(anyhow::anyhow!(
"Can't validate a state with no proofs attached"
@ -117,7 +138,7 @@ impl ProcessState {
if self.validation_tokens.get(0).unwrap().get_message() == OBLITERATION_MSG {
// We're dealing with a destruction update
return self.handle_obliteration();
return self.handle_obliteration(members_list);
}
// Compute modified fields
@ -155,11 +176,16 @@ impl ProcessState {
applicable_roles.into_iter().any(|role_def| {
role_def.validation_rules.iter().any(|rule| {
let members: Vec<&Member> = role_def.members.iter()
.filter_map(|outpoint| {
members_list.0.get(outpoint)
})
.collect();
rule.is_satisfied(
field,
self.state_id,
&self.validation_tokens,
&role_def.members,
members.as_slice(),
).is_ok()
})
})
@ -176,7 +202,7 @@ impl ProcessState {
self.state_id == [0u8; 32]
}
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: &OutPoint) -> anyhow::Result<Vec<String>> {
let mut res: HashSet<String> = HashSet::new();
// Are we in that role?