From a686870e08244b7391bab8d8dd065219b6801a2e Mon Sep 17 00:00:00 2001 From: NicolasCantu Date: Wed, 26 Mar 2025 12:38:30 +0100 Subject: [PATCH] Update process tests --- src/process.rs | 239 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 216 insertions(+), 23 deletions(-) diff --git a/src/process.rs b/src/process.rs index c27542f..b74a2a9 100644 --- a/src/process.rs +++ b/src/process.rs @@ -250,6 +250,7 @@ impl ProcessState { /// A process is basically a succession of states /// The latest state MUST be an empty state with only the commited_in field set at the last unspent outpoint +/// Commiting this last empty state in a transaction is called obliterating a process, basically terminating it #[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize, Tsify)] #[tsify(into_wasm_abi, from_wasm_abi)] pub struct Process { @@ -755,6 +756,51 @@ mod tests { ProcessState::new(outpoint, Pcd::new(clear_pcd), Pcd::new(public_data), Roles::new(roles)).unwrap() } + fn create_pairing_process_one() -> ProcessState { + let carol_wallet = create_carol_wallet(); + let carol_address = carol_wallet.get_client().get_receiving_address(); + let pairing_rule = + ValidationRule::new(1.0, vec![PAIREDADDRESSES.to_owned()], 1.0).unwrap(); + let pairing_role_def = RoleDefinition { + members: vec![], + validation_rules: vec![pairing_rule], + storages: vec![] + }; + + let outpoint = OutPoint::from_str("8425e9749957fd8ca83460c21718be4017692fd3ae61cbb0f0d401e7a5ddce6a:0").unwrap(); + + let private_data = BTreeMap::from([("description".to_owned(), Value::String("pairing".to_owned()))]); + + let paired_addresses = Value::Array(vec![carol_address.try_into().unwrap()]); + + ProcessState::new(outpoint, Pcd::new(private_data), Pcd::new(BTreeMap::from([(PAIREDADDRESSES.to_owned(), paired_addresses)])), Roles::new(BTreeMap::from([(PAIRING.to_owned(), pairing_role_def)]))).unwrap() + } + + fn create_pairing_process_two() -> ProcessState { + let carol_wallet = create_carol_wallet(); + let carol_address = carol_wallet.get_client().get_receiving_address(); + let dave_wallet = create_dave_wallet(); + let dave_address = dave_wallet.get_client().get_receiving_address(); + let pairing_rule = + ValidationRule::new(1.0, vec![PAIREDADDRESSES.to_owned()], 1.0).unwrap(); + let pairing_role_def = RoleDefinition { + members: vec![], + validation_rules: vec![pairing_rule], + storages: vec![] + }; + + let outpoint = OutPoint::from_str("8425e9749957fd8ca83460c21718be4017692fd3ae61cbb0f0d401e7a5ddce6a:0").unwrap(); + + let private_data = BTreeMap::from([("description".to_owned(), Value::String("pairing".to_owned()))]); + + let paired_addresses = Value::Array(vec![ + carol_address.try_into().unwrap(), + dave_address.try_into().unwrap() + ]); + + ProcessState::new(outpoint, Pcd::new(private_data), Pcd::new(BTreeMap::from([(PAIREDADDRESSES.to_owned(), paired_addresses)])), Roles::new(BTreeMap::from([(PAIRING.to_owned(), pairing_role_def)]))).unwrap() + } + #[test] fn test_error_no_proofs() { let state = dummy_process_state(); @@ -767,24 +813,6 @@ mod tests { ); } - #[test] - fn test_error_identical_previous_state() { - let mut state = dummy_process_state(); - // We sign with a random key - let signing_key = - SecretKey::from_str("39b2a765dc93e02da04a0e9300224b4f99fa7b83cfae49036dff58613fd3277c") - .unwrap(); - let message_hash = state.get_message_hash(true).unwrap(); - state.validation_tokens.push(Proof::new(message_hash, signing_key)); - let members_map = get_members_map(); - let result = state.is_valid(Some(&state), &OutPointMemberMap(members_map)); - assert!(result.is_err()); - assert_eq!( - result.unwrap_err().to_string(), - "State is identical to the previous state" - ); - } - #[test] /// We provide a proof signed with a key that is not the spending key for either alice or bob fn test_error_invalid_proof() { @@ -839,6 +867,171 @@ mod tests { assert!(result.is_ok()); } + #[test] + fn test_valid_pairing() { + let mut pairing_first_state = create_pairing_process_one(); + let carol_key: SecretKey = create_carol_wallet() + .get_client() + .get_spend_key() + .try_into() + .unwrap(); + let message_hash = pairing_first_state.get_message_hash(true).unwrap(); + pairing_first_state.validation_tokens.push(Proof::new(message_hash, carol_key)); + let result = pairing_first_state.is_valid(None, &OutPointMemberMap(get_members_map())); + assert!(result.is_ok()); + } + + #[test] + fn test_error_pairing_wrong_proof() { + let mut pairing_first_state = create_pairing_process_one(); + let alice_key: SecretKey = create_alice_wallet() + .get_client() + .get_spend_key() + .try_into() + .unwrap(); + let message_hash = pairing_first_state.get_message_hash(true).unwrap(); + pairing_first_state.validation_tokens.push(Proof::new(message_hash, alice_key)); + let result = pairing_first_state.is_valid(None, &OutPointMemberMap(get_members_map())); + assert!(result.is_err()); + } + + #[test] + fn test_valid_pairing_add_device() { + let pairing_state = create_pairing_process_one(); + let mut paired_addresses = pairing_state.public_data.get(PAIREDADDRESSES).unwrap().clone(); + let mut pairing_process = Process::new(pairing_state.commited_in); + pairing_process.insert_concurrent_state(pairing_state).unwrap(); + let new_commitment = OutPoint::from_str("7f1a6d8923d6ee58a075c0e99e25472bb22a3eea221739281c2beaf829f03f27:0").unwrap(); + pairing_process.update_states_tip(new_commitment).unwrap(); + + let members_list = &OutPointMemberMap(HashMap::from( + [ + ( + pairing_process.get_process_id().unwrap(), + Member::new( + paired_addresses.as_array().unwrap().into_iter().map(|a| a.as_str().unwrap().try_into().unwrap()).collect() + )) + ]) + ); + + // Add Dave address + let dave_address = create_dave_wallet().get_client().get_receiving_address(); + paired_addresses.as_array_mut().unwrap().push(Value::String(dave_address)); + let roles = &pairing_process.get_latest_commited_state().unwrap().roles; + + let mut add_device_state = ProcessState::new(new_commitment, Pcd::new(BTreeMap::new()), Pcd::new(BTreeMap::from([(PAIREDADDRESSES.to_owned(), paired_addresses)])), roles.clone()).unwrap(); + + let carol_key: SecretKey = create_carol_wallet() + .get_client() + .get_spend_key() + .try_into() + .unwrap(); + let message_hash = add_device_state.get_message_hash(true).unwrap(); + add_device_state.validation_tokens.push(Proof::new(message_hash, carol_key)); + + let result = add_device_state.is_valid(pairing_process.get_latest_commited_state(), members_list); + assert!(result.is_ok()); + } + + #[test] + fn test_valid_pairing_rm_device() { + let pairing_state = create_pairing_process_two(); + let paired_addresses = pairing_state.public_data.get(PAIREDADDRESSES).unwrap().clone(); + let mut pairing_process = Process::new(pairing_state.commited_in); + pairing_process.insert_concurrent_state(pairing_state).unwrap(); + let new_commitment = OutPoint::from_str("7f1a6d8923d6ee58a075c0e99e25472bb22a3eea221739281c2beaf829f03f27:0").unwrap(); + pairing_process.update_states_tip(new_commitment).unwrap(); + + let members_list = &OutPointMemberMap(HashMap::from( + [ + ( + pairing_process.get_process_id().unwrap(), + Member::new( + paired_addresses.as_array().unwrap().into_iter().map(|a| a.as_str().unwrap().try_into().unwrap()).collect() + )) + ]) + ); + + // Remove Dave address + let dave_address = create_dave_wallet().get_client().get_receiving_address(); + let paired_addresses = extract_paired_addresses(&paired_addresses).unwrap(); + let filtered_paired_addresses = Value::from_iter(paired_addresses.into_iter().filter_map(|a| { + if a.to_string() != dave_address { + Some(a.to_string()) + } else { + None + } + })); + let roles = &pairing_process.get_latest_commited_state().unwrap().roles; + + let mut rm_device_state = ProcessState::new( + new_commitment, + Pcd::new(BTreeMap::new()), + Pcd::new( + BTreeMap::from([(PAIREDADDRESSES.to_owned(), filtered_paired_addresses)]) + ), + roles.clone() + ).unwrap(); + + // We need both devices to agree to remove one + + let carol_key: SecretKey = create_carol_wallet() + .get_client() + .get_spend_key() + .try_into() + .unwrap(); + let dave_key: SecretKey = create_dave_wallet() + .get_client() + .get_spend_key() + .try_into() + .unwrap(); + let message_hash = rm_device_state.get_message_hash(true).unwrap(); + rm_device_state.validation_tokens.push(Proof::new(message_hash, carol_key)); + rm_device_state.validation_tokens.push(Proof::new(message_hash, dave_key)); + + let result = rm_device_state.is_valid(pairing_process.get_latest_commited_state(), members_list); + assert!(result.is_ok()); + } + + /// We check that Dave can't add himself to the pairing + #[test] + fn test_error_pairing_add_device_wrong_signature() { + let pairing_state = create_pairing_process_one(); + let mut paired_addresses = pairing_state.public_data.get(PAIREDADDRESSES).unwrap().clone(); + let mut pairing_process = Process::new(pairing_state.commited_in); + pairing_process.insert_concurrent_state(pairing_state).unwrap(); + let new_commitment = OutPoint::from_str("7f1a6d8923d6ee58a075c0e99e25472bb22a3eea221739281c2beaf829f03f27:0").unwrap(); + pairing_process.update_states_tip(new_commitment).unwrap(); + + let members_list = &OutPointMemberMap(HashMap::from( + [ + ( + pairing_process.get_process_id().unwrap(), + Member::new( + paired_addresses.as_array().unwrap().into_iter().map(|a| a.as_str().unwrap().try_into().unwrap()).collect() + )) + ]) + ); + + // Add Dave address + let dave_address = create_dave_wallet().get_client().get_receiving_address(); + paired_addresses.as_array_mut().unwrap().push(Value::String(dave_address)); + let roles = &pairing_process.get_latest_commited_state().unwrap().roles; + + let mut add_device_state = ProcessState::new(new_commitment, Pcd::new(BTreeMap::new()), Pcd::new(BTreeMap::from([(PAIREDADDRESSES.to_owned(), paired_addresses)])), roles.clone()).unwrap(); + + let dave_key: SecretKey = create_dave_wallet() + .get_client() + .get_spend_key() + .try_into() + .unwrap(); + let message_hash = add_device_state.get_message_hash(true).unwrap(); + add_device_state.validation_tokens.push(Proof::new(message_hash, dave_key)); + + let result = add_device_state.is_valid(pairing_process.get_latest_commited_state(), members_list); + assert!(result.is_err()); + } + #[test] /// everyone signs for everything fn test_valid_all_signatures() { @@ -897,7 +1090,7 @@ mod tests { #[test] /// Dave signs to obliterate the process fn test_valid_obliteration() { - let mut state = dummy_process_state(); + let state = dummy_process_state(); let mut process = Process::new(state.commited_in); process.insert_concurrent_state(state.clone()).unwrap(); // We simulate a first commitment @@ -909,16 +1102,16 @@ mod tests { , 0 ) ).unwrap(); - // Now we take the last empty state and try to invalidate it - let empty_state = process.get_state_for_id(&[0u8; 32]).unwrap(); + // Now we take the last empty state and try to commit it to invalidate the whole process + let empty_state = process.get_state_for_id_mut(&[0u8; 32]).unwrap(); let dave_key: SecretKey = create_dave_wallet() .get_client() .get_spend_key() .try_into() .unwrap(); let message_hash = empty_state.get_message_hash(true).unwrap(); - state.validation_tokens.push(Proof::new(message_hash, dave_key)); - let result = state.is_valid(None, &OutPointMemberMap(get_members_map())); + empty_state.validation_tokens.push(Proof::new(message_hash, dave_key)); + let result = empty_state.is_valid(Some(&state), &OutPointMemberMap(get_members_map())); assert!(result.is_ok()); }