[bug] actually handle demiurge case
This commit is contained in:
parent
45b2dc1e43
commit
dada38ba0e
121
src/process.rs
121
src/process.rs
@ -8,7 +8,7 @@ use sp_client::{bitcoin::{OutPoint, Transaction}, silentpayments::SilentPaymentA
|
||||
use tsify::Tsify;
|
||||
|
||||
use crate::{
|
||||
pcd::{Member, Pcd, PcdCommitments, RoleDefinition, Roles}, serialization::{deserialize_hex, hex_array_btree, serialize_hex, OutPointMemberMap}, signature::{AnkHash, AnkValidationNoHash, AnkValidationYesHash, Proof}, MutexExt, SpecialRoles, APOPHIS, PAIREDADDRESSES, PAIRING
|
||||
pcd::{Member, Pcd, PcdCommitments, RoleDefinition, Roles, ValidationRule}, serialization::{deserialize_hex, hex_array_btree, serialize_hex, OutPointMemberMap}, signature::{AnkHash, AnkValidationNoHash, AnkValidationYesHash, Proof}, MutexExt, SpecialRoles, APOPHIS, PAIREDADDRESSES, PAIRING
|
||||
};
|
||||
|
||||
fn extract_paired_addresses(paired_addresses: &Value) -> anyhow::Result<Vec<SilentPaymentAddress>> {
|
||||
@ -82,6 +82,35 @@ impl ProcessState {
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_demiurge(&self, demiurge_role: &RoleDefinition) -> anyhow::Result<RoleDefinition> {
|
||||
if demiurge_role.members.is_empty() {
|
||||
return Err(anyhow::Error::msg("Invalid demiurge role: members can't be empty"));
|
||||
}
|
||||
// validation_rules is empty
|
||||
if !demiurge_role.validation_rules.is_empty() {
|
||||
return Err(anyhow::Error::msg("Invalid demiurge role: validation_rules must be empty"));
|
||||
}
|
||||
|
||||
// if demiurge_role.storages.is_empty() {
|
||||
// return Err(anyhow::Error::msg("Invalid demiurge role: storages can't be empty"));
|
||||
// }
|
||||
|
||||
let all_keys: Vec<String> = self.pcd_commitment.keys().map(|k| k.clone()).collect();
|
||||
|
||||
// define the rule
|
||||
let validation_rule = ValidationRule::new(
|
||||
1.0,
|
||||
all_keys.clone(),
|
||||
1.0
|
||||
)?;
|
||||
let role = RoleDefinition {
|
||||
members: demiurge_role.members.clone(),
|
||||
storages: demiurge_role.storages.clone(),
|
||||
validation_rules: vec![validation_rule]
|
||||
};
|
||||
Ok(role)
|
||||
}
|
||||
|
||||
/// This is a simplified and streamlined validation for obliteration state
|
||||
fn handle_obliteration(&self, apophis: &RoleDefinition, members_list: &OutPointMemberMap) -> anyhow::Result<()> {
|
||||
// Apophis should have only one rule
|
||||
@ -93,19 +122,7 @@ impl ProcessState {
|
||||
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"))
|
||||
}
|
||||
apophis.is_satisfied(vec![empty_field.to_owned()], [0u8; 32], &self.validation_tokens, &members_list)
|
||||
}
|
||||
|
||||
fn handle_pairing(&self, pairing_role: RoleDefinition, previous_addresses: Vec<SilentPaymentAddress>) -> anyhow::Result<()> {
|
||||
@ -131,7 +148,7 @@ impl ProcessState {
|
||||
vec![&previous_member]
|
||||
};
|
||||
|
||||
paired_addresses_rule.iter().next().unwrap().is_satisfied(PAIREDADDRESSES, self.state_id, &self.validation_tokens, members.as_slice())
|
||||
paired_addresses_rule.get(0).unwrap().is_satisfied(PAIREDADDRESSES, self.state_id, &self.validation_tokens, members.as_slice())
|
||||
}
|
||||
|
||||
pub fn is_valid(&self, previous_state: Option<&ProcessState>, members_list: &OutPointMemberMap) -> anyhow::Result<()> {
|
||||
@ -176,7 +193,18 @@ impl ProcessState {
|
||||
// That's optional though
|
||||
SpecialRoles::Demiurge => {
|
||||
// If we're not in initial state just ignore it
|
||||
if previous_state.is_some() { return None; }
|
||||
if previous_state.is_some() {
|
||||
return None;
|
||||
} else {
|
||||
// We try to validate with demiurge
|
||||
match self.handle_demiurge(role_def) {
|
||||
Ok(role) => return Some(role),
|
||||
Err(e) => {
|
||||
log::error!("{}", e.to_string());
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Otherwise we just continue normal validation
|
||||
}
|
||||
// We already handled other special roles
|
||||
@ -678,6 +706,11 @@ mod tests {
|
||||
let validation_rule4 = ValidationRule::new(1.0, vec!["public1".to_owned(), "public2".to_owned()], 0.5).unwrap();
|
||||
let apophis_rule = ValidationRule::new(1.0, vec!["".to_owned()], 1.0).unwrap();
|
||||
|
||||
let role_demiurge = RoleDefinition {
|
||||
members: vec![OutPoint::from_str(ALICE_BOB_PAIRING).unwrap()],
|
||||
validation_rules: vec![],
|
||||
storages: vec![]
|
||||
};
|
||||
let role_def1 = RoleDefinition {
|
||||
members: vec![OutPoint::from_str(ALICE_BOB_PAIRING).unwrap()],
|
||||
validation_rules: vec![validation_rule1],
|
||||
@ -708,6 +741,7 @@ mod tests {
|
||||
};
|
||||
|
||||
let roles: BTreeMap<String, RoleDefinition> = BTreeMap::from([
|
||||
("demiurge".to_owned(), role_demiurge),
|
||||
("role1".to_owned(), role_def1),
|
||||
("role2".to_owned(), role_def2),
|
||||
("role_roles".to_owned(), role_def_roles),
|
||||
@ -715,7 +749,7 @@ mod tests {
|
||||
("apophis".to_owned(), role_def_apophis)
|
||||
]);
|
||||
|
||||
let clear_pcd: BTreeMap<String, Value> = serde_json::from_value(json!({
|
||||
let private_data: BTreeMap<String, Value> = serde_json::from_value(json!({
|
||||
"field1": "value1",
|
||||
"field2": "value2",
|
||||
})).unwrap();
|
||||
@ -727,7 +761,7 @@ mod tests {
|
||||
"public2": "public2",
|
||||
})).unwrap();
|
||||
|
||||
ProcessState::new(outpoint, Pcd::new(clear_pcd), Pcd::new(public_data), Roles::new(roles)).unwrap()
|
||||
ProcessState::new(outpoint, Pcd::new(private_data), Pcd::new(public_data), Roles::new(roles)).unwrap()
|
||||
}
|
||||
|
||||
fn create_pairing_process_one() -> ProcessState {
|
||||
@ -838,6 +872,55 @@ mod tests {
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// AliceBob is the demiurge
|
||||
fn test_valid_demiurge() {
|
||||
let mut state = dummy_process_state();
|
||||
// We sign with Alice and Carol keys
|
||||
let alice_key: SecretKey = create_alice_wallet()
|
||||
.get_spend_key()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
let bob_key: SecretKey = create_bob_wallet()
|
||||
.get_spend_key()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
let message_hash = state.get_message_hash(true).unwrap();
|
||||
state.validation_tokens.push(Proof::new(message_hash, alice_key));
|
||||
state.validation_tokens.push(Proof::new(message_hash, bob_key));
|
||||
let result = state.is_valid(None, &OutPointMemberMap(get_members_map()));
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// Carol tries to bypass demiurge role
|
||||
fn test_error_demiurge() {
|
||||
let mut state = dummy_process_state();
|
||||
// We sign with Alice and Carol keys
|
||||
let carol_key: SecretKey = create_alice_wallet()
|
||||
.get_spend_key()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
let message_hash = state.get_message_hash(true).unwrap();
|
||||
state.validation_tokens.push(Proof::new(message_hash, carol_key));
|
||||
let result = state.is_valid(None, &OutPointMemberMap(get_members_map()));
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// Carol tries to bypass demiurge role
|
||||
fn test_error_demiurge_not_init_state() {
|
||||
let mut state = dummy_process_state();
|
||||
// We sign with Alice and Carol keys
|
||||
let carol_key: SecretKey = create_alice_wallet()
|
||||
.get_spend_key()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
let message_hash = state.get_message_hash(true).unwrap();
|
||||
state.validation_tokens.push(Proof::new(message_hash, carol_key));
|
||||
let result = state.is_valid(Some(&dummy_process_state()), &OutPointMemberMap(get_members_map()));
|
||||
assert!(result.is_err());
|
||||
}
|
||||
#[test]
|
||||
fn test_valid_pairing() {
|
||||
let mut pairing_first_state = create_pairing_process_one();
|
||||
@ -1096,7 +1179,7 @@ mod tests {
|
||||
state.validation_tokens.push(Proof::new(message_hash_yes, alice_key));
|
||||
state.validation_tokens.push(Proof::new(message_hash_yes, bob_key));
|
||||
state.validation_tokens.push(Proof::new(message_hash_no, carol_key));
|
||||
let result = state.is_valid(None, &OutPointMemberMap(get_members_map()));
|
||||
let result = state.is_valid(Some(&dummy_process_state()), &OutPointMemberMap(get_members_map()));
|
||||
assert!(result.is_err());
|
||||
assert_eq!(result.unwrap_err().to_string(), "Not enough valid proofs");
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user