Update parse_cipher for prd update
This commit is contained in:
parent
1bf8d91991
commit
3ed94c7538
184
src/api.rs
184
src/api.rs
@ -893,36 +893,37 @@ fn handle_prd(
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
PrdType::Update | PrdType::TxProposal | PrdType::Message => {
|
||||
// Those all have some new data we don't know about yet
|
||||
// We send a Confirm to get the pcd
|
||||
// Add the prd to our list of actions for this process
|
||||
relevant_process.insert_impending_request(prd.clone());
|
||||
let member: Member = serde_json::from_str(&prd.sender)?;
|
||||
let mut ciphers = vec![];
|
||||
for address in member.get_addresses() {
|
||||
if let Some(shared_secret) = lock_shared_secrets()?.get_secret_for_address(address.as_str().try_into()?) {
|
||||
let cipher = confirm_prd(&prd, &shared_secret)?;
|
||||
ciphers.push(cipher);
|
||||
} else {
|
||||
// For now we don't fail if we're missing an address for a member but maybe we should
|
||||
warn!("Failed to find secret for address {}", address);
|
||||
}
|
||||
PrdType::Update => {
|
||||
// Compute the merkle tree root for the proposed new state to see if we already know about it
|
||||
let update_merkle_root = prd.pcd_commitments.create_merkle_tree()?.root().ok_or(AnyhowError::msg("Invalid merkle tree"))?.to_lower_hex_string();
|
||||
if relevant_process.get_state_for_commitments_root(&update_merkle_root).is_ok() {
|
||||
// We already know about that state
|
||||
return Err(AnyhowError::msg("Received update for a state we already know"));
|
||||
}
|
||||
|
||||
// This should never happen
|
||||
if ciphers.is_empty() {
|
||||
return Err(anyhow::Error::msg(format!("No available secrets for member {:?}", member)));
|
||||
}
|
||||
let new_state = ProcessState {
|
||||
commited_in: OutPoint::from_str(&prd.root_commitment)?,
|
||||
pcd_commitment: prd.pcd_commitments,
|
||||
merkle_root: update_merkle_root.clone(),
|
||||
keys: prd.keys,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
// Compute the diffs
|
||||
// At this point we don't have the encrypted values
|
||||
// But it can still be useful to track diffs
|
||||
let diffs = create_diffs(&relevant_process, &new_state)?;
|
||||
|
||||
relevant_process.insert_concurrent_state(new_state);
|
||||
|
||||
let updated_process = UpdatedProcess {
|
||||
commitment_tx: outpoint,
|
||||
current_process: relevant_process.clone(),
|
||||
new_diffs: diffs,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
return Ok(ApiReturn {
|
||||
ciphers_to_send: ciphers,
|
||||
updated_process: Some(updated_process),
|
||||
..Default::default()
|
||||
});
|
||||
@ -936,9 +937,6 @@ fn handle_prd(
|
||||
})
|
||||
.ok_or(anyhow::Error::msg("Original request not found"))?;
|
||||
|
||||
// Once we found the prd update, we can add the received proofs as validation tokens
|
||||
let previous_state = to_update.clone();
|
||||
|
||||
to_update
|
||||
.validation_tokens
|
||||
.extend(prd.validation_tokens);
|
||||
@ -949,7 +947,7 @@ fn handle_prd(
|
||||
let updated_process = UpdatedProcess {
|
||||
commitment_tx: OutPoint::from_str(&prd.root_commitment)?,
|
||||
current_process: relevant_process.clone(),
|
||||
modified_state: Some((previous_state, updated_state.clone())),
|
||||
modified_state: Some(updated_state.merkle_root),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
@ -962,54 +960,6 @@ fn handle_prd(
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_pcd(pcd: Value) -> AnyhowResult<ApiReturn> {
|
||||
// We received an encrypted pcd, so we can compute the merkle root of a tree where all the encrypted values are the leaves
|
||||
// We pass an empty Outpoint as salt, as there's no point salting hash of encrypted values
|
||||
let encrypted_pcd_commitments = pcd.hash_all_fields(OutPoint::null())?;
|
||||
let encrypted_pcd_root = <Value as Pcd>::create_merkle_tree(&Value::Object(encrypted_pcd_commitments))?.root().unwrap().to_lower_hex_string();
|
||||
let mut processes = lock_processes()?;
|
||||
let updated_prd: Prd;
|
||||
for (outpoint, process) in processes.iter_mut() {
|
||||
// We check all pending requests and match the payload with the hash of this pcd
|
||||
if let Some(prd) = process
|
||||
.get_impending_requests_mut()
|
||||
.into_iter()
|
||||
.find(|r| *r.payload == encrypted_pcd_root)
|
||||
{
|
||||
// We update the process and return it
|
||||
prd.payload = pcd.to_string();
|
||||
updated_prd = prd.clone();
|
||||
// We can now safely mark the prd to be remove from the process
|
||||
prd.prd_type = PrdType::None;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
let new_state = ProcessState {
|
||||
commited_in: *outpoint,
|
||||
pcd_commitment: updated_prd.pcd_commitments,
|
||||
encrypted_pcd: pcd,
|
||||
keys: updated_prd.keys,
|
||||
validation_tokens: vec![]
|
||||
};
|
||||
process.insert_concurrent_state(new_state.clone())?;
|
||||
process.prune_impending_requests();
|
||||
|
||||
let udpated_process = UpdatedProcess {
|
||||
commitment_tx: *outpoint,
|
||||
current_process: process.clone(),
|
||||
new_state: Some(new_state),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
return Ok(ApiReturn {
|
||||
updated_process: Some(udpated_process),
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
|
||||
Err(anyhow::Error::msg("Failed to find matching prd"))
|
||||
}
|
||||
|
||||
fn handle_decrypted_message(
|
||||
secret: AnkSharedSecretHash,
|
||||
plain: Vec<u8>,
|
||||
@ -1017,13 +967,99 @@ fn handle_decrypted_message(
|
||||
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)
|
||||
} else if let Ok(pcd) = Value::from_str(&String::from_utf8(plain)?) {
|
||||
handle_pcd(pcd)
|
||||
} else {
|
||||
Err(anyhow::Error::msg("Failed to handle decrypted message"))
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
/// Use the provided Map to update a state
|
||||
/// The map uses hash commitment as keys, as in storage
|
||||
pub fn update_process_state(init_commitment: String, state_id: String, hash2values: String) -> ApiResult<ApiReturn> {
|
||||
let hash2values_map = serde_json::from_str::<Value>(&hash2values)?.to_value_object()?;
|
||||
|
||||
// Get the process
|
||||
let outpoint = OutPoint::from_str(&init_commitment)?;
|
||||
|
||||
let mut processes = lock_processes()?;
|
||||
{
|
||||
// First a mutable borrow of the process
|
||||
let process = processes.get_mut(&outpoint)
|
||||
.ok_or(ApiError::new("Unknown process".to_owned()))?;
|
||||
|
||||
// Get the state
|
||||
let state = process.get_latest_concurrent_states_mut()?
|
||||
.into_iter()
|
||||
.find(|state| state.merkle_root == state_id)
|
||||
.ok_or(ApiError::new("Unknown state".to_owned()))?;
|
||||
|
||||
// Update each value
|
||||
// Check if there's already something
|
||||
// If we have the key, decrypt and compare to the commitment
|
||||
if state.encrypted_pcd.as_object().is_some() && !state.encrypted_pcd.as_object().unwrap().is_empty() {
|
||||
return Err(ApiError::new("State already existing".to_owned()));
|
||||
}
|
||||
let state_commitments = state.pcd_commitment.to_value_object()?;
|
||||
let mut new_encrypted_pcd: Map<String, Value> = Map::with_capacity(hash2values_map.len());
|
||||
|
||||
for (hash, value) in hash2values_map {
|
||||
// Check the hash in pcd_commitment, get the corresponding field name
|
||||
let (field, _) = state_commitments.iter().find(|(field, commitment)| *hash == **commitment)
|
||||
.ok_or(ApiError::new(format!("Failed to find the commitment {}", hash)))?;
|
||||
|
||||
new_encrypted_pcd.insert(field.clone(), value);
|
||||
}
|
||||
|
||||
// decrypt all we can and check it matches the commitment
|
||||
state.encrypted_pcd = Value::Object(new_encrypted_pcd);
|
||||
let commited_in = serialize(&state.commited_in);
|
||||
|
||||
let clear_pcd = state.decrypt_pcd()?;
|
||||
|
||||
for (i, (key, value)) in clear_pcd.iter().enumerate() {
|
||||
// hash each value, and check the result against commitments
|
||||
if let Some(expected) = state_commitments.get(key.as_str()) {
|
||||
// value can already be the commitment, if we don't have the encryption key
|
||||
if value.is_hex_string(Some(32)).is_ok() {
|
||||
// check if the clear value is the commitment
|
||||
if expected.as_str().unwrap() == value.as_str().unwrap() { continue; }
|
||||
}
|
||||
// Otherwise we hash the value whatever it is, it must match the commitment
|
||||
let mut value_bin = value.to_string().into_bytes();
|
||||
value_bin.push(i.try_into().unwrap());
|
||||
let tagged_hash = AnkPcdHash::from_value_with_outpoint(&value_bin, &commited_in);
|
||||
if tagged_hash.as_byte_array().to_lower_hex_string() != expected.as_str().unwrap() {
|
||||
// We set the encrypted pcd back to empty
|
||||
state.encrypted_pcd = Value::Object(Map::new());
|
||||
return Err(ApiError::new(format!("Retrieved value for {} doesn't match the commitment", key)));
|
||||
}
|
||||
} else {
|
||||
// This shouldn't be possible
|
||||
state.encrypted_pcd = Value::Object(Map::new());
|
||||
return Err(ApiError::new(format!("Missing commitment for key {}", key)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If every value we can decrypt is valid, then we return the new state and diffs
|
||||
// We borrow it again immutably
|
||||
let process = processes.get(&outpoint).unwrap();
|
||||
let state = process.get_latest_concurrent_states()?.into_iter().find(|s| s.merkle_root == state_id).unwrap();
|
||||
let diffs = create_diffs(&process, &state)?;
|
||||
|
||||
let udpated_process = UpdatedProcess {
|
||||
commitment_tx: outpoint,
|
||||
current_process: process.clone(),
|
||||
new_diffs: diffs,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
Ok(ApiReturn {
|
||||
updated_process: Some(udpated_process),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn parse_cipher(cipher_msg: String) -> ApiResult<ApiReturn> {
|
||||
// Check that the cipher is not empty or too long
|
||||
|
Loading…
x
Reference in New Issue
Block a user