From 4e8ac88336db7345d44ab0c0074b765879984c98 Mon Sep 17 00:00:00 2001 From: NicolasCantu Date: Wed, 26 Mar 2025 12:42:59 +0100 Subject: [PATCH] Add the members_list everywhere necessary --- src/api.rs | 112 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 69 insertions(+), 43 deletions(-) diff --git a/src/api.rs b/src/api.rs index 49bf4af..c982c6e 100644 --- a/src/api.rs +++ b/src/api.rs @@ -23,6 +23,7 @@ use sdk_common::crypto::{ decrypt_with_key, encrypt_with_key, generate_key, AeadCore, Aes256Gcm, AnkSharedSecretHash, KeyInit, AAD }; use sdk_common::process::{check_tx_for_process_updates, lock_processes, Process, ProcessState}; +use sdk_common::serialization::OutPointMemberMap; use sdk_common::signature::{AnkHash, AnkMessageHash, AnkValidationNoHash, AnkValidationYesHash, Proof}; use sdk_common::sp_client::bitcoin::blockdata::fee_rate; use sdk_common::sp_client::bitcoin::consensus::{deserialize, serialize}; @@ -566,6 +567,7 @@ fn process_transaction( tx_hex: String, blockheight: u32, tweak_data_hex: String, + members_list: &OutPointMemberMap ) -> anyhow::Result { let tx = deserialize::(&Vec::from_hex(&tx_hex)?)?; @@ -575,7 +577,7 @@ fn process_transaction( let processes = lock_processes()?; let process = processes.get(&outpoint).unwrap(); let new_state = process.get_latest_commited_state().unwrap(); - let diffs = if let Ok(diffs) = create_diffs(process, new_state) { diffs } else { vec![] }; + let diffs = if let Ok(diffs) = create_diffs(process, new_state, members_list) { diffs } else { vec![] }; let updated_process = UpdatedProcess { process_id: outpoint, current_process: process.clone(), @@ -609,7 +611,7 @@ fn process_transaction( } #[wasm_bindgen] -pub fn parse_new_tx(new_tx_msg: String, block_height: u32) -> ApiResult { +pub fn parse_new_tx(new_tx_msg: String, block_height: u32, members_list: OutPointMemberMap) -> ApiResult { let new_tx: NewTxMessage = serde_json::from_str(&new_tx_msg)?; if let Some(error) = new_tx.error { @@ -627,6 +629,7 @@ pub fn parse_new_tx(new_tx_msg: String, block_height: u32) -> ApiResult AnyhowResult AnyhowResult> { +fn create_diffs(process: &Process, new_state: &ProcessState, members_list: &OutPointMemberMap) -> AnyhowResult> { let new_state_commitments = &new_state.pcd_commitment; let device = lock_local_device()?; - let our_id = device.to_member(); + let our_id = device.get_pairing_commitment(); - let fields_to_validate = new_state.get_fields_to_validate_for_member(&our_id)?; + let fields_to_validate = if let Some(our_id) = our_id { + new_state.get_fields_to_validate_for_member(&our_id)? + } else { + // Device is unpaired, we just take all the fields in the `pairing` role + if let Some(pairing_role) = new_state.roles.get("pairing") { + pairing_role.validation_rules.iter().flat_map(|r| r.fields.clone()).collect() + } else { + return Err(AnyhowError::msg("Missing pairing role")) + } + }; let new_state_id = &new_state.state_id; @@ -740,7 +752,8 @@ fn handle_prd_connect(prd: Prd, secret: AnkSharedSecretHash) -> AnyhowResult AnyhowResult { debug!("handle_prd: {:#?}", prd); // Connect is a bit different here because there's no associated process @@ -782,7 +795,7 @@ fn handle_prd( }; // Compute the diffs - let diffs = create_diffs(&relevant_process, &new_state)?; + let diffs = create_diffs(&relevant_process, &new_state, members_list)?; relevant_process.insert_concurrent_state(new_state)?; @@ -858,7 +871,15 @@ fn handle_prd( PrdType::Request => { // We are being requested encrypted data for one or more states, to be uploaded on storage let states: Vec<[u8; 32]> = serde_json::from_str(&prd.payload)?; - let requester = prd.sender; + let requester = if let Some((requester_process_id, _)) = members_list.0.iter() + .find(|(outpoint, member)| { + **member == prd.sender + }) + { + requester_process_id + } else { + return Err(AnyhowError::msg("Unknown requester")); + }; // diffs will trigger upload of the encrypted data on storage let mut diffs = vec![]; @@ -909,7 +930,7 @@ fn handle_prd( full_prd.filter_keys(&relevant_fields); let prd_msg = full_prd.to_network_msg(sp_wallet)?; - let addresses = requester.get_addresses(); + let addresses = prd.sender.get_addresses(); for sp_address in addresses.into_iter() { // We skip our own device address, no point sending ourself a cipher if sp_address == local_address { @@ -963,17 +984,18 @@ fn handle_prd( fn handle_decrypted_message( secret: AnkSharedSecretHash, plain: Vec, + members_list: &OutPointMemberMap ) -> anyhow::Result { let local_address: SilentPaymentAddress = lock_local_device()?.get_wallet().get_client().get_receiving_address().try_into()?; if let Ok(prd) = Prd::extract_from_message(&plain, local_address) { - handle_prd(prd, secret) + handle_prd(prd, secret, members_list) } else { Err(anyhow::Error::msg("Failed to handle decrypted message")) } } #[wasm_bindgen] -pub fn parse_cipher(cipher_msg: String) -> ApiResult { +pub fn parse_cipher(cipher_msg: String, members_list: OutPointMemberMap) -> ApiResult { // Check that the cipher is not empty or too long if cipher_msg.is_empty() || cipher_msg.len() > MAX_PRD_PAYLOAD_SIZE { return Err(ApiError::new( @@ -985,7 +1007,7 @@ pub fn parse_cipher(cipher_msg: String) -> ApiResult { let decrypt_res = lock_shared_secrets()?.try_decrypt(&cipher); if let Ok((secret, plain)) = decrypt_res { - return handle_decrypted_message(secret, plain) + return handle_decrypted_message(secret, plain, &members_list) .map_err(|e| ApiError::new(format!("Failed to handle decrypted message: {}", e))); } @@ -1109,6 +1131,7 @@ pub fn create_new_process( public_data: JsValue, relay_address: String, fee_rate: u32, + members_list: OutPointMemberMap, ) -> ApiResult { let init_state: Pcd = serde_wasm_bindgen::from_value(init_state)?; let roles: Roles = serde_wasm_bindgen::from_value(roles)?; @@ -1140,7 +1163,7 @@ pub fn create_new_process( let mut process = Process::new(process_id); - let diffs = create_diffs(&process, &new_state)?; + let diffs = create_diffs(&process, &new_state, &members_list)?; let all_fields: Vec = init_state.iter().map(|(field, _)| field.clone()).collect(); let mut fields2keys = BTreeMap::new(); @@ -1198,9 +1221,7 @@ pub fn create_new_process( /// TODO allow modifications from user that doesn't have read access to all attributes pub fn update_process( mut process: Process, - new_attributes: JsValue, - roles: JsValue, - new_public_data: JsValue, + members_list: OutPointMemberMap, ) -> ApiResult { let new_attributes: Pcd = serde_wasm_bindgen::from_value(new_attributes)?; let roles: Roles = serde_wasm_bindgen::from_value(roles)?; @@ -1239,7 +1260,7 @@ pub fn update_process( return Err(ApiError::new("New state already known".to_owned())); } - let diffs = create_diffs(&process, &new_state)?; + let diffs = create_diffs(&process, &new_state, &members_list)?; let all_fields: Vec = new_attributes.iter().map(|(field, _)| field.clone()).collect(); let mut encrypted_data = BTreeMap::new(); @@ -1288,7 +1309,7 @@ pub fn update_process( } #[wasm_bindgen] -pub fn request_data(process_id: String, state_ids_str: Vec, roles: JsValue) -> ApiResult { +pub fn request_data(process_id: String, state_ids_str: Vec, roles: JsValue, members_list: OutPointMemberMap) -> ApiResult { let process_id = OutPoint::from_str(&process_id)?; let local_device = lock_local_device()?; let sender = local_device.to_member(); @@ -1323,7 +1344,7 @@ pub fn request_data(process_id: String, state_ids_str: Vec, roles: JsVal let prd_request = Prd::new_request( process_id, - sender, + members_list.0.get(&sender_pairing_id).unwrap().clone(), state_ids ); @@ -1351,6 +1372,7 @@ pub fn request_data(process_id: String, state_ids_str: Vec, roles: JsVal pub fn create_update_message( process_id: String, state_id: String, + members_list: OutPointMemberMap ) -> ApiResult { let mut processes = lock_processes()?; @@ -1433,26 +1455,30 @@ pub fn create_update_message( } #[wasm_bindgen] -pub fn validate_state(process: Process, state_id: String) -> ApiResult { - add_validation_token(process, state_id, true) +pub fn validate_state(process: Process, state_id: String, members_list: OutPointMemberMap) -> ApiResult { + add_validation_token(process, state_id, true, &members_list) } #[wasm_bindgen] -pub fn refuse_state(process: Process, state_id: String) -> ApiResult { - add_validation_token(process, state_id, false) +pub fn refuse_state(process: Process, state_id: String, members_list: OutPointMemberMap) -> ApiResult { + add_validation_token(process, state_id, false, &members_list) } #[wasm_bindgen] -pub fn evaluate_state(process_id: String, previous_state: Option, process_state: ProcessState) -> ApiResult { - process_state.is_valid(previous_state.as_ref())?; +pub fn evaluate_state(process: Process, state_id: String, members_list: OutPointMemberMap) -> ApiResult { + let state_id: [u8; 32] = Vec::from_hex(&state_id)?.try_into().map_err(|_| ApiError::new("Invalid state id".to_owned()))?; + let process_id = process.get_process_id()?; + let process_state = process.get_state_for_id(&state_id)?; + let previous_state = process.get_parent_state(&process_state.commited_in); + + process_state.is_valid(previous_state, &members_list)?; // We create a commit msg with the valid state - let outpoint: OutPoint = OutPoint::from_str(&process_id)?; let commit_msg = CommitMessage::new( - outpoint, - process_state.pcd_commitment, - process_state.roles, - process_state.public_data, + process_id, + process_state.pcd_commitment.clone(), + process_state.roles.clone(), + process_state.public_data.clone(), vec![] ); @@ -1462,7 +1488,7 @@ pub fn evaluate_state(process_id: String, previous_state: Option, }) } -fn add_validation_token(mut process: Process, state_id: String, approval: bool) -> ApiResult { +fn add_validation_token(mut process: Process, state_id: String, approval: bool, members_list: &OutPointMemberMap) -> ApiResult { let process_id = process.get_process_id()?; let state_id: [u8; 32] = Vec::from_hex(&state_id)?.try_into().map_err(|_| ApiError::new("Invalid state_id".to_owned()))?; @@ -1497,7 +1523,7 @@ fn add_validation_token(mut process: Process, state_id: String, approval: bool) ..Default::default() }; - let ciphers_to_send = new_response_prd(process_id, process.get_state_for_id_mut(&state_id)?)?; + let ciphers_to_send = new_response_prd(process_id, process.get_state_for_id(&state_id)?, members_list)?; Ok(ApiReturn { updated_process: Some(updated_process), @@ -1508,18 +1534,13 @@ fn add_validation_token(mut process: Process, state_id: String, approval: bool) } #[wasm_bindgen] -pub fn create_response_prd(process_id: String, state_id: String) -> ApiResult { - let mut processes = lock_processes()?; +pub fn create_response_prd(process: Process, state_id: String, members_list: OutPointMemberMap) -> ApiResult { + let process_id = process.get_process_id()?; let state_id: [u8; 32] = Vec::from_hex(&state_id)?.try_into().map_err(|_| ApiError::new("Invalid state_id".to_owned()))?; - let outpoint = OutPoint::from_str(&process_id)?; + let update_state: &ProcessState = process.get_state_for_id(&state_id)?; - let process = processes.get_mut(&outpoint) - .ok_or(ApiError::new("Unknown process".to_owned()))?; - - let update_state: &mut ProcessState = process.get_state_for_id_mut(&state_id)?; - - let ciphers = new_response_prd(outpoint, update_state)?; + let ciphers = new_response_prd(process_id, update_state, &members_list)?; Ok(ApiReturn { ciphers_to_send: ciphers, @@ -1527,7 +1548,7 @@ pub fn create_response_prd(process_id: String, state_id: String) -> ApiResult AnyhowResult> { +fn new_response_prd(process_id: OutPoint, update_state: &ProcessState, members_list: &OutPointMemberMap) -> AnyhowResult> { let local_device = lock_local_device()?; let sp_wallet = local_device.get_wallet(); let local_address = sp_wallet.get_client().get_receiving_address(); @@ -1540,7 +1561,12 @@ fn new_response_prd(process_id: OutPoint, update_state: &mut ProcessState) -> An .iter() .flat_map(|rule| rule.fields.clone()) .collect(); - for member in &role.members { + for pairing_id in &role.members { + let member = if let Some(member) = members_list.0.get(pairing_id) { + member + } else { + continue; + }; // Check that we have a shared_secret with all members if let Some(no_secret_address) = member.get_addresses().iter() .find(|a| shared_secrets.get_secret_for_address(a.as_str().try_into().unwrap()).is_none())