Add the members_list everywhere necessary

This commit is contained in:
NicolasCantu 2025-03-26 12:42:59 +01:00
parent a02b752aaa
commit 4e8ac88336

View File

@ -23,6 +23,7 @@ use sdk_common::crypto::{
decrypt_with_key, encrypt_with_key, generate_key, AeadCore, Aes256Gcm, AnkSharedSecretHash, KeyInit, AAD 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::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::signature::{AnkHash, AnkMessageHash, AnkValidationNoHash, AnkValidationYesHash, Proof};
use sdk_common::sp_client::bitcoin::blockdata::fee_rate; use sdk_common::sp_client::bitcoin::blockdata::fee_rate;
use sdk_common::sp_client::bitcoin::consensus::{deserialize, serialize}; use sdk_common::sp_client::bitcoin::consensus::{deserialize, serialize};
@ -566,6 +567,7 @@ fn process_transaction(
tx_hex: String, tx_hex: String,
blockheight: u32, blockheight: u32,
tweak_data_hex: String, tweak_data_hex: String,
members_list: &OutPointMemberMap
) -> anyhow::Result<ApiReturn> { ) -> anyhow::Result<ApiReturn> {
let tx = deserialize::<Transaction>(&Vec::from_hex(&tx_hex)?)?; let tx = deserialize::<Transaction>(&Vec::from_hex(&tx_hex)?)?;
@ -575,7 +577,7 @@ fn process_transaction(
let processes = lock_processes()?; let processes = lock_processes()?;
let process = processes.get(&outpoint).unwrap(); let process = processes.get(&outpoint).unwrap();
let new_state = process.get_latest_commited_state().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 { let updated_process = UpdatedProcess {
process_id: outpoint, process_id: outpoint,
current_process: process.clone(), current_process: process.clone(),
@ -609,7 +611,7 @@ fn process_transaction(
} }
#[wasm_bindgen] #[wasm_bindgen]
pub fn parse_new_tx(new_tx_msg: String, block_height: u32) -> ApiResult<ApiReturn> { pub fn parse_new_tx(new_tx_msg: String, block_height: u32, members_list: OutPointMemberMap) -> ApiResult<ApiReturn> {
let new_tx: NewTxMessage = serde_json::from_str(&new_tx_msg)?; let new_tx: NewTxMessage = serde_json::from_str(&new_tx_msg)?;
if let Some(error) = new_tx.error { if let Some(error) = new_tx.error {
@ -627,6 +629,7 @@ pub fn parse_new_tx(new_tx_msg: String, block_height: u32) -> ApiResult<ApiRetur
new_tx.transaction, new_tx.transaction,
block_height, block_height,
new_tx.tweak_data.unwrap(), new_tx.tweak_data.unwrap(),
&members_list
)?) )?)
} }
@ -650,13 +653,22 @@ fn confirm_prd(prd: &Prd, shared_secret: &AnkSharedSecretHash) -> AnyhowResult<S
Ok(encrypt_with_key(shared_secret.as_byte_array(), prd_msg.as_bytes())?.to_lower_hex_string()) Ok(encrypt_with_key(shared_secret.as_byte_array(), prd_msg.as_bytes())?.to_lower_hex_string())
} }
fn create_diffs(process: &Process, new_state: &ProcessState) -> AnyhowResult<Vec<UserDiff>> { fn create_diffs(process: &Process, new_state: &ProcessState, members_list: &OutPointMemberMap) -> AnyhowResult<Vec<UserDiff>> {
let new_state_commitments = &new_state.pcd_commitment; let new_state_commitments = &new_state.pcd_commitment;
let device = lock_local_device()?; 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; let new_state_id = &new_state.state_id;
@ -740,7 +752,8 @@ fn handle_prd_connect(prd: Prd, secret: AnkSharedSecretHash) -> AnyhowResult<Api
fn handle_prd( fn handle_prd(
prd: Prd, prd: Prd,
secret: AnkSharedSecretHash secret: AnkSharedSecretHash,
members_list: &OutPointMemberMap,
) -> AnyhowResult<ApiReturn> { ) -> AnyhowResult<ApiReturn> {
debug!("handle_prd: {:#?}", prd); debug!("handle_prd: {:#?}", prd);
// Connect is a bit different here because there's no associated process // Connect is a bit different here because there's no associated process
@ -782,7 +795,7 @@ fn handle_prd(
}; };
// Compute the diffs // 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)?; relevant_process.insert_concurrent_state(new_state)?;
@ -858,7 +871,15 @@ fn handle_prd(
PrdType::Request => { PrdType::Request => {
// We are being requested encrypted data for one or more states, to be uploaded on storage // 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 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 // diffs will trigger upload of the encrypted data on storage
let mut diffs = vec![]; let mut diffs = vec![];
@ -909,7 +930,7 @@ fn handle_prd(
full_prd.filter_keys(&relevant_fields); full_prd.filter_keys(&relevant_fields);
let prd_msg = full_prd.to_network_msg(sp_wallet)?; 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() { for sp_address in addresses.into_iter() {
// We skip our own device address, no point sending ourself a cipher // We skip our own device address, no point sending ourself a cipher
if sp_address == local_address { if sp_address == local_address {
@ -963,17 +984,18 @@ fn handle_prd(
fn handle_decrypted_message( fn handle_decrypted_message(
secret: AnkSharedSecretHash, secret: AnkSharedSecretHash,
plain: Vec<u8>, plain: Vec<u8>,
members_list: &OutPointMemberMap
) -> anyhow::Result<ApiReturn> { ) -> anyhow::Result<ApiReturn> {
let local_address: SilentPaymentAddress = lock_local_device()?.get_wallet().get_client().get_receiving_address().try_into()?; 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) { if let Ok(prd) = Prd::extract_from_message(&plain, local_address) {
handle_prd(prd, secret) handle_prd(prd, secret, members_list)
} else { } else {
Err(anyhow::Error::msg("Failed to handle decrypted message")) Err(anyhow::Error::msg("Failed to handle decrypted message"))
} }
} }
#[wasm_bindgen] #[wasm_bindgen]
pub fn parse_cipher(cipher_msg: String) -> ApiResult<ApiReturn> { pub fn parse_cipher(cipher_msg: String, members_list: OutPointMemberMap) -> ApiResult<ApiReturn> {
// Check that the cipher is not empty or too long // Check that the cipher is not empty or too long
if cipher_msg.is_empty() || cipher_msg.len() > MAX_PRD_PAYLOAD_SIZE { if cipher_msg.is_empty() || cipher_msg.len() > MAX_PRD_PAYLOAD_SIZE {
return Err(ApiError::new( return Err(ApiError::new(
@ -985,7 +1007,7 @@ pub fn parse_cipher(cipher_msg: String) -> ApiResult<ApiReturn> {
let decrypt_res = lock_shared_secrets()?.try_decrypt(&cipher); let decrypt_res = lock_shared_secrets()?.try_decrypt(&cipher);
if let Ok((secret, plain)) = decrypt_res { 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))); .map_err(|e| ApiError::new(format!("Failed to handle decrypted message: {}", e)));
} }
@ -1109,6 +1131,7 @@ pub fn create_new_process(
public_data: JsValue, public_data: JsValue,
relay_address: String, relay_address: String,
fee_rate: u32, fee_rate: u32,
members_list: OutPointMemberMap,
) -> ApiResult<ApiReturn> { ) -> ApiResult<ApiReturn> {
let init_state: Pcd = serde_wasm_bindgen::from_value(init_state)?; let init_state: Pcd = serde_wasm_bindgen::from_value(init_state)?;
let roles: Roles = serde_wasm_bindgen::from_value(roles)?; 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 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<String> = init_state.iter().map(|(field, _)| field.clone()).collect(); let all_fields: Vec<String> = init_state.iter().map(|(field, _)| field.clone()).collect();
let mut fields2keys = BTreeMap::new(); 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 /// TODO allow modifications from user that doesn't have read access to all attributes
pub fn update_process( pub fn update_process(
mut process: Process, mut process: Process,
new_attributes: JsValue, members_list: OutPointMemberMap,
roles: JsValue,
new_public_data: JsValue,
) -> ApiResult<ApiReturn> { ) -> ApiResult<ApiReturn> {
let new_attributes: Pcd = serde_wasm_bindgen::from_value(new_attributes)?; let new_attributes: Pcd = serde_wasm_bindgen::from_value(new_attributes)?;
let roles: Roles = serde_wasm_bindgen::from_value(roles)?; 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())); 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<String> = new_attributes.iter().map(|(field, _)| field.clone()).collect(); let all_fields: Vec<String> = new_attributes.iter().map(|(field, _)| field.clone()).collect();
let mut encrypted_data = BTreeMap::new(); let mut encrypted_data = BTreeMap::new();
@ -1288,7 +1309,7 @@ pub fn update_process(
} }
#[wasm_bindgen] #[wasm_bindgen]
pub fn request_data(process_id: String, state_ids_str: Vec<String>, roles: JsValue) -> ApiResult<ApiReturn> { pub fn request_data(process_id: String, state_ids_str: Vec<String>, roles: JsValue, members_list: OutPointMemberMap) -> ApiResult<ApiReturn> {
let process_id = OutPoint::from_str(&process_id)?; let process_id = OutPoint::from_str(&process_id)?;
let local_device = lock_local_device()?; let local_device = lock_local_device()?;
let sender = local_device.to_member(); let sender = local_device.to_member();
@ -1323,7 +1344,7 @@ pub fn request_data(process_id: String, state_ids_str: Vec<String>, roles: JsVal
let prd_request = Prd::new_request( let prd_request = Prd::new_request(
process_id, process_id,
sender, members_list.0.get(&sender_pairing_id).unwrap().clone(),
state_ids state_ids
); );
@ -1351,6 +1372,7 @@ pub fn request_data(process_id: String, state_ids_str: Vec<String>, roles: JsVal
pub fn create_update_message( pub fn create_update_message(
process_id: String, process_id: String,
state_id: String, state_id: String,
members_list: OutPointMemberMap
) -> ApiResult<ApiReturn> { ) -> ApiResult<ApiReturn> {
let mut processes = lock_processes()?; let mut processes = lock_processes()?;
@ -1433,26 +1455,30 @@ pub fn create_update_message(
} }
#[wasm_bindgen] #[wasm_bindgen]
pub fn validate_state(process: Process, state_id: String) -> ApiResult<ApiReturn> { pub fn validate_state(process: Process, state_id: String, members_list: OutPointMemberMap) -> ApiResult<ApiReturn> {
add_validation_token(process, state_id, true) add_validation_token(process, state_id, true, &members_list)
} }
#[wasm_bindgen] #[wasm_bindgen]
pub fn refuse_state(process: Process, state_id: String) -> ApiResult<ApiReturn> { pub fn refuse_state(process: Process, state_id: String, members_list: OutPointMemberMap) -> ApiResult<ApiReturn> {
add_validation_token(process, state_id, false) add_validation_token(process, state_id, false, &members_list)
} }
#[wasm_bindgen] #[wasm_bindgen]
pub fn evaluate_state(process_id: String, previous_state: Option<ProcessState>, process_state: ProcessState) -> ApiResult<ApiReturn> { pub fn evaluate_state(process: Process, state_id: String, members_list: OutPointMemberMap) -> ApiResult<ApiReturn> {
process_state.is_valid(previous_state.as_ref())?; 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 // We create a commit msg with the valid state
let outpoint: OutPoint = OutPoint::from_str(&process_id)?;
let commit_msg = CommitMessage::new( let commit_msg = CommitMessage::new(
outpoint, process_id,
process_state.pcd_commitment, process_state.pcd_commitment.clone(),
process_state.roles, process_state.roles.clone(),
process_state.public_data, process_state.public_data.clone(),
vec![] vec![]
); );
@ -1462,7 +1488,7 @@ pub fn evaluate_state(process_id: String, previous_state: Option<ProcessState>,
}) })
} }
fn add_validation_token(mut process: Process, state_id: String, approval: bool) -> ApiResult<ApiReturn> { fn add_validation_token(mut process: Process, state_id: String, approval: bool, members_list: &OutPointMemberMap) -> ApiResult<ApiReturn> {
let process_id = process.get_process_id()?; 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 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() ..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 { Ok(ApiReturn {
updated_process: Some(updated_process), updated_process: Some(updated_process),
@ -1508,18 +1534,13 @@ fn add_validation_token(mut process: Process, state_id: String, approval: bool)
} }
#[wasm_bindgen] #[wasm_bindgen]
pub fn create_response_prd(process_id: String, state_id: String) -> ApiResult<ApiReturn> { pub fn create_response_prd(process: Process, state_id: String, members_list: OutPointMemberMap) -> ApiResult<ApiReturn> {
let mut processes = lock_processes()?; 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 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) let ciphers = new_response_prd(process_id, update_state, &members_list)?;
.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)?;
Ok(ApiReturn { Ok(ApiReturn {
ciphers_to_send: ciphers, ciphers_to_send: ciphers,
@ -1527,7 +1548,7 @@ pub fn create_response_prd(process_id: String, state_id: String) -> ApiResult<Ap
}) })
} }
fn new_response_prd(process_id: OutPoint, update_state: &mut ProcessState) -> AnyhowResult<Vec<String>> { fn new_response_prd(process_id: OutPoint, update_state: &ProcessState, members_list: &OutPointMemberMap) -> AnyhowResult<Vec<String>> {
let local_device = lock_local_device()?; let local_device = lock_local_device()?;
let sp_wallet = local_device.get_wallet(); let sp_wallet = local_device.get_wallet();
let local_address = sp_wallet.get_client().get_receiving_address(); 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() .iter()
.flat_map(|rule| rule.fields.clone()) .flat_map(|rule| rule.fields.clone())
.collect(); .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 // Check that we have a shared_secret with all members
if let Some(no_secret_address) = member.get_addresses().iter() 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()) .find(|a| shared_secrets.get_secret_for_address(a.as_str().try_into().unwrap()).is_none())