Update to latest common
This commit is contained in:
parent
a99f41f50e
commit
f25c6f27de
236
src/api.rs
236
src/api.rs
@ -20,7 +20,7 @@ use anyhow::Error as AnyhowError;
|
|||||||
use anyhow::Result as AnyhowResult;
|
use anyhow::Result as AnyhowResult;
|
||||||
use sdk_common::aes_gcm::aead::{Aead, Payload};
|
use sdk_common::aes_gcm::aead::{Aead, Payload};
|
||||||
use sdk_common::crypto::{
|
use sdk_common::crypto::{
|
||||||
decrypt_with_key, encrypt_with_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::signature::{AnkHash, AnkMessageHash, AnkValidationNoHash, AnkValidationYesHash, Proof};
|
use sdk_common::signature::{AnkHash, AnkMessageHash, AnkValidationNoHash, AnkValidationYesHash, Proof};
|
||||||
@ -63,7 +63,7 @@ use sdk_common::network::{
|
|||||||
NewTxMessage,
|
NewTxMessage,
|
||||||
};
|
};
|
||||||
use sdk_common::pcd::{
|
use sdk_common::pcd::{
|
||||||
AnkPcdHash, AnkPcdTag, Member, Pcd, RoleDefinition, ValidationRule,
|
AnkPcdHash, AnkPcdTag, Member, Pcd, PcdCommitments, RoleDefinition, Roles, ValidationRule
|
||||||
};
|
};
|
||||||
use sdk_common::prd::{AnkPrdHash, Prd, PrdType};
|
use sdk_common::prd::{AnkPrdHash, Prd, PrdType};
|
||||||
use sdk_common::silentpayments::{create_transaction, map_outputs_to_sp_address};
|
use sdk_common::silentpayments::{create_transaction, map_outputs_to_sp_address};
|
||||||
@ -94,7 +94,7 @@ pub struct UserDiff {
|
|||||||
pub state_id: String, // TODO add a merkle proof that the new_value belongs to that state
|
pub state_id: String, // TODO add a merkle proof that the new_value belongs to that state
|
||||||
pub value_commitment: String,
|
pub value_commitment: String,
|
||||||
pub field: String,
|
pub field: String,
|
||||||
pub roles: BTreeMap<String, RoleDefinition>,
|
pub roles: Roles,
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
pub notify_user: bool,
|
pub notify_user: bool,
|
||||||
pub need_validation: bool,
|
pub need_validation: bool,
|
||||||
@ -108,8 +108,8 @@ pub struct UpdatedProcess {
|
|||||||
pub process_id: OutPoint,
|
pub process_id: OutPoint,
|
||||||
pub current_process: Process,
|
pub current_process: Process,
|
||||||
pub diffs: Vec<UserDiff>, // All diffs should have the same state_id
|
pub diffs: Vec<UserDiff>, // All diffs should have the same state_id
|
||||||
pub encrypted_data: HashMap<String, String>, // hashes in pcd commitment to ciphers
|
pub encrypted_data: BTreeMap<String, String>, // hashes in pcd commitment to ciphers
|
||||||
pub validated_state: Option<String>, // when we add/receive validation proofs for a state
|
pub validated_state: Option<[u8; 32]>, // when we add/receive validation proofs for a state
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Tsify, Serialize, Deserialize, Default)]
|
#[derive(Debug, PartialEq, Tsify, Serialize, Deserialize, Default)]
|
||||||
@ -126,15 +126,6 @@ pub struct ApiReturn {
|
|||||||
|
|
||||||
pub type ApiResult<T: FromWasmAbi> = Result<T, ApiError>;
|
pub type ApiResult<T: FromWasmAbi> = Result<T, ApiError>;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Tsify, Serialize, Deserialize, Default)]
|
|
||||||
#[tsify(into_wasm_abi)]
|
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
pub struct NewKey {
|
|
||||||
pub private_key: String,
|
|
||||||
pub x_only_public_key: String,
|
|
||||||
pub key_parity: bool
|
|
||||||
}
|
|
||||||
|
|
||||||
const IS_TESTNET: bool = true;
|
const IS_TESTNET: bool = true;
|
||||||
const DEFAULT_AMOUNT: Amount = Amount::from_sat(1000);
|
const DEFAULT_AMOUNT: Amount = Amount::from_sat(1000);
|
||||||
|
|
||||||
@ -623,41 +614,41 @@ fn confirm_prd(prd: &Prd, shared_secret: &AnkSharedSecretHash) -> AnyhowResult<S
|
|||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
let outpoint = OutPoint::from_str(&prd.process_id)?;
|
let outpoint = prd.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();
|
||||||
|
|
||||||
let prd_confirm = Prd::new_confirm(outpoint, sender, prd.pcd_commitments.clone());
|
let prd_confirm = Prd::new_confirm(outpoint, sender, prd.pcd_commitments.clone());
|
||||||
|
|
||||||
// debug!("Sending confirm prd: {:?}", prd_confirm);
|
|
||||||
|
|
||||||
let prd_msg = prd_confirm.to_network_msg(local_device.get_wallet())?;
|
let prd_msg = prd_confirm.to_network_msg(local_device.get_wallet())?;
|
||||||
|
|
||||||
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) -> AnyhowResult<Vec<UserDiff>> {
|
||||||
let new_state_commitments = new_state.pcd_commitment.as_object().ok_or(AnyhowError::msg("new_state commitments is not an object"))?;
|
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.to_member();
|
||||||
|
|
||||||
let fields_to_validate = new_state.get_fields_to_validate_for_member(&our_id)?;
|
let fields_to_validate = new_state.get_fields_to_validate_for_member(&our_id)?;
|
||||||
|
|
||||||
let new_state_root = &new_state.state_id;
|
let new_state_id = &new_state.state_id;
|
||||||
|
|
||||||
let new_public_data = &new_state.public_data;
|
let new_public_data = &new_state.public_data;
|
||||||
|
|
||||||
let process_id = process.get_process_id()?.to_string();
|
let process_id = process.get_process_id()?.to_string();
|
||||||
let mut diffs = vec![];
|
let mut diffs = vec![];
|
||||||
for (field, hash) in new_state_commitments {
|
for (field, hash) in new_state_commitments.iter() {
|
||||||
let description = new_public_data.get(field).map(|d| d.to_string());
|
let description_field = new_public_data.get(field);
|
||||||
|
let has_description = description_field.as_ref().is_some_and(|v| v.is_string());
|
||||||
|
let description = if has_description { description_field.unwrap().as_str().map(|s| s.to_owned()) } else { None };
|
||||||
let need_validation = fields_to_validate.contains(field);
|
let need_validation = fields_to_validate.contains(field);
|
||||||
diffs.push(UserDiff {
|
diffs.push(UserDiff {
|
||||||
process_id: process_id.clone(),
|
process_id: process_id.clone(),
|
||||||
state_id: new_state_root.to_owned(),
|
state_id: new_state_id.to_lower_hex_string(),
|
||||||
value_commitment: hash.as_str().unwrap().to_string(),
|
value_commitment: hash.to_lower_hex_string(),
|
||||||
field: field.to_owned(),
|
field: field.to_owned(),
|
||||||
description,
|
description,
|
||||||
notify_user: false,
|
notify_user: false,
|
||||||
@ -691,9 +682,8 @@ fn handle_prd_connect(prd: Prd, secret: AnkSharedSecretHash) -> AnyhowResult<Api
|
|||||||
return Err(anyhow::Error::msg("Previous proof signs another message"));
|
return Err(anyhow::Error::msg("Previous proof signs another message"));
|
||||||
}
|
}
|
||||||
// Now we can confirm the secret and link it to an address
|
// Now we can confirm the secret and link it to an address
|
||||||
let sender = serde_json::from_str::<Member>(&prd.sender)?;
|
|
||||||
let proof = prd.proof.unwrap();
|
let proof = prd.proof.unwrap();
|
||||||
let actual_sender = sender.get_address_for_key(&proof.get_key())
|
let actual_sender = prd.sender.get_address_for_key(&proof.get_key())
|
||||||
.ok_or(anyhow::Error::msg("Signer of the proof is not part of sender"))?;
|
.ok_or(anyhow::Error::msg("Signer of the proof is not part of sender"))?;
|
||||||
shared_secrets.confirm_secret_for_address(secret, actual_sender.clone().try_into()?);
|
shared_secrets.confirm_secret_for_address(secret, actual_sender.clone().try_into()?);
|
||||||
let mut secrets_return = SecretsStore::new();
|
let mut secrets_return = SecretsStore::new();
|
||||||
@ -704,8 +694,7 @@ fn handle_prd_connect(prd: Prd, secret: AnkSharedSecretHash) -> AnyhowResult<Api
|
|||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
let proof = prd.proof.unwrap();
|
let proof = prd.proof.unwrap();
|
||||||
let sender = serde_json::from_str::<Member>(&prd.sender)?;
|
let actual_sender = prd.sender.get_address_for_key(&proof.get_key())
|
||||||
let actual_sender = sender.get_address_for_key(&proof.get_key())
|
|
||||||
.ok_or(anyhow::Error::msg("Signer of the proof is not part of sender"))?;
|
.ok_or(anyhow::Error::msg("Signer of the proof is not part of sender"))?;
|
||||||
|
|
||||||
shared_secrets.confirm_secret_for_address(secret, actual_sender.clone().try_into()?);
|
shared_secrets.confirm_secret_for_address(secret, actual_sender.clone().try_into()?);
|
||||||
@ -736,7 +725,7 @@ fn handle_prd(
|
|||||||
return handle_prd_connect(prd, secret);
|
return handle_prd_connect(prd, secret);
|
||||||
}
|
}
|
||||||
|
|
||||||
let outpoint = OutPoint::from_str(&prd.process_id)?;
|
let outpoint = prd.process_id;
|
||||||
|
|
||||||
let mut processes = lock_processes()?;
|
let mut processes = lock_processes()?;
|
||||||
let relevant_process = match processes.entry(outpoint) {
|
let relevant_process = match processes.entry(outpoint) {
|
||||||
@ -750,7 +739,7 @@ fn handle_prd(
|
|||||||
match prd.prd_type {
|
match prd.prd_type {
|
||||||
PrdType::Update => {
|
PrdType::Update => {
|
||||||
// Compute the merkle tree root for the proposed new state to see if we already know about it
|
// 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();
|
let update_merkle_root = prd.pcd_commitments.create_merkle_tree()?.root().ok_or(AnyhowError::msg("Invalid merkle tree"))?;
|
||||||
if relevant_process.get_state_for_id(&update_merkle_root).is_ok() {
|
if relevant_process.get_state_for_id(&update_merkle_root).is_ok() {
|
||||||
// We already know about that state
|
// We already know about that state
|
||||||
return Err(AnyhowError::msg("Received update for a state we already know"));
|
return Err(AnyhowError::msg("Received update for a state we already know"));
|
||||||
@ -786,7 +775,7 @@ fn handle_prd(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
PrdType::Response => {
|
PrdType::Response => {
|
||||||
let update_state_id = prd.pcd_commitments.create_merkle_tree()?.root().ok_or(AnyhowError::msg("Invalid merkle tree"))?.to_lower_hex_string();
|
let update_state_id = prd.pcd_commitments.create_merkle_tree()?.root().ok_or(AnyhowError::msg("Invalid merkle tree"))?;
|
||||||
let mut to_update = relevant_process.get_state_for_id_mut(&update_state_id)?;
|
let mut to_update = relevant_process.get_state_for_id_mut(&update_state_id)?;
|
||||||
|
|
||||||
let new_validations = prd.validation_tokens;
|
let new_validations = prd.validation_tokens;
|
||||||
@ -819,19 +808,19 @@ fn handle_prd(
|
|||||||
|
|
||||||
let updated_state = to_update.clone();
|
let updated_state = to_update.clone();
|
||||||
|
|
||||||
let validated_state = Some(to_update.state_id.clone());
|
let validated_state = Some(to_update.state_id);
|
||||||
let mut commit_msg = CommitMessage::new_update_commitment(
|
let mut commit_msg = CommitMessage::new_update_commitment(
|
||||||
OutPoint::from_str(&prd.process_id)?,
|
prd.process_id,
|
||||||
updated_state.pcd_commitment,
|
updated_state.pcd_commitment,
|
||||||
updated_state.roles.clone().into_iter().collect(),
|
updated_state.roles,
|
||||||
updated_state.public_data.clone()
|
updated_state.public_data
|
||||||
);
|
);
|
||||||
|
|
||||||
commit_msg.set_validation_tokens(updated_state.validation_tokens);
|
commit_msg.set_validation_tokens(updated_state.validation_tokens);
|
||||||
|
|
||||||
// We must return an update of the process
|
// We must return an update of the process
|
||||||
let updated_process = UpdatedProcess {
|
let updated_process = UpdatedProcess {
|
||||||
process_id: OutPoint::from_str(&prd.process_id)?,
|
process_id: prd.process_id,
|
||||||
current_process: relevant_process.clone(),
|
current_process: relevant_process.clone(),
|
||||||
validated_state,
|
validated_state,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@ -846,7 +835,7 @@ 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: Member = serde_json::from_str(&prd.sender)?;
|
let requester = prd.sender;
|
||||||
|
|
||||||
// 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![];
|
||||||
@ -855,7 +844,7 @@ fn handle_prd(
|
|||||||
let mut push_to_storage = vec![];
|
let mut push_to_storage = vec![];
|
||||||
|
|
||||||
for state_id in states {
|
for state_id in states {
|
||||||
let state = match relevant_process.get_state_for_id(&state_id.to_lower_hex_string()) {
|
let state = match relevant_process.get_state_for_id(&state_id) {
|
||||||
Ok(state) => state,
|
Ok(state) => state,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
debug!("Ignoring request for unknown state {}", state_id.to_lower_hex_string());
|
debug!("Ignoring request for unknown state {}", state_id.to_lower_hex_string());
|
||||||
@ -869,7 +858,7 @@ fn handle_prd(
|
|||||||
|
|
||||||
let mut relevant_fields: HashSet<String> = HashSet::new();
|
let mut relevant_fields: HashSet<String> = HashSet::new();
|
||||||
let shared_secrets = lock_shared_secrets()?;
|
let shared_secrets = lock_shared_secrets()?;
|
||||||
for (name, role) in &state.roles {
|
for (name, role) in state.roles.iter() {
|
||||||
if !role.members.contains(&requester) {
|
if !role.members.contains(&requester) {
|
||||||
// This role doesn't concern requester
|
// This role doesn't concern requester
|
||||||
continue;
|
continue;
|
||||||
@ -912,21 +901,21 @@ fn handle_prd(
|
|||||||
ciphers.push(cipher.to_lower_hex_string());
|
ciphers.push(cipher.to_lower_hex_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
let pcd_commitment: HashMap<String, String> = serde_json::from_value(state.pcd_commitment.clone())?;
|
let pcd_commitment = &state.pcd_commitment;
|
||||||
for (field, hash) in pcd_commitment {
|
for (field, hash) in pcd_commitment.iter() {
|
||||||
// We only need field that are visible by requester
|
// We only need field that are visible by requester
|
||||||
if !relevant_fields.contains(&field) {
|
if !relevant_fields.contains(field.as_str()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let diff = UserDiff {
|
let diff = UserDiff {
|
||||||
process_id: outpoint.to_string(),
|
process_id: outpoint.to_string(),
|
||||||
state_id: state_id.to_lower_hex_string(),
|
state_id: state_id.to_lower_hex_string(),
|
||||||
value_commitment: hash.clone(),
|
value_commitment: hash.to_lower_hex_string(),
|
||||||
field,
|
field: field.to_owned(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
diffs.push(diff);
|
diffs.push(diff);
|
||||||
push_to_storage.push(hash);
|
push_to_storage.push(hash.to_lower_hex_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1092,15 +1081,15 @@ pub fn create_connect_transaction(addresses: Vec<String>, fee_rate: u32) -> ApiR
|
|||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn create_new_process(
|
pub fn create_new_process(
|
||||||
init_state_str: String,
|
init_state: JsValue,
|
||||||
roles: JsValue,
|
roles: JsValue,
|
||||||
public_data: JsValue,
|
public_data: JsValue,
|
||||||
relay_address: String,
|
relay_address: String,
|
||||||
fee_rate: u32,
|
fee_rate: u32,
|
||||||
) -> ApiResult<ApiReturn> {
|
) -> ApiResult<ApiReturn> {
|
||||||
let init_state: Value = <Value as Pcd>::new_from_string(&init_state_str)?;
|
let init_state: Pcd = serde_wasm_bindgen::from_value(init_state)?;
|
||||||
let roles: BTreeMap<String, RoleDefinition> = serde_wasm_bindgen::from_value(roles)?;
|
let roles: Roles = serde_wasm_bindgen::from_value(roles)?;
|
||||||
let public_data: BTreeMap<String, String> = serde_wasm_bindgen::from_value(public_data)?;
|
let public_data: Pcd = serde_wasm_bindgen::from_value(public_data)?;
|
||||||
|
|
||||||
// We create a transaction that spends to the relay address
|
// We create a transaction that spends to the relay address
|
||||||
let psbt = create_transaction_for_addresses(vec![relay_address.clone()], fee_rate)?;
|
let psbt = create_transaction_for_addresses(vec![relay_address.clone()], fee_rate)?;
|
||||||
@ -1122,7 +1111,7 @@ pub fn create_new_process(
|
|||||||
|
|
||||||
let new_tx_msg = NewTxMessage::new(serialize(&transaction).to_lower_hex_string(), None);
|
let new_tx_msg = NewTxMessage::new(serialize(&transaction).to_lower_hex_string(), None);
|
||||||
|
|
||||||
let mut new_state = ProcessState::new(process_id, init_state.as_object().unwrap().clone(), &public_data, roles.clone())?;
|
let mut new_state = ProcessState::new(process_id, init_state.clone(), public_data.clone(), roles.clone())?;
|
||||||
|
|
||||||
let pcd_commitment = new_state.pcd_commitment.clone();
|
let pcd_commitment = new_state.pcd_commitment.clone();
|
||||||
|
|
||||||
@ -1130,21 +1119,22 @@ pub fn create_new_process(
|
|||||||
|
|
||||||
let diffs = create_diffs(&process, &new_state)?;
|
let diffs = create_diffs(&process, &new_state)?;
|
||||||
|
|
||||||
let all_fields: Vec<String> = init_state.as_object().unwrap().into_iter().map(|(field, _)| field.clone()).collect();
|
let all_fields: Vec<String> = init_state.iter().map(|(field, _)| field.clone()).collect();
|
||||||
let mut fields2keys = Map::new();
|
let mut fields2keys = BTreeMap::new();
|
||||||
let mut fields2cipher = Map::new();
|
let mut encrypted_data = BTreeMap::new();
|
||||||
init_state.encrypt_fields(&all_fields, &mut fields2keys, &mut fields2cipher);
|
|
||||||
|
let mut rng = thread_rng();
|
||||||
|
for (field, plain_value) in init_state.iter() {
|
||||||
|
let hash = pcd_commitment.get(field).ok_or(anyhow::Error::msg("Missing commitment"))?;
|
||||||
|
let key = generate_key(&mut rng);
|
||||||
|
let serialized = serde_json::to_string(plain_value)?;
|
||||||
|
let cipher = encrypt_with_key(&key, serialized.as_bytes())?;
|
||||||
|
fields2keys.insert(field.to_owned(), key);
|
||||||
|
encrypted_data.insert(hash.to_lower_hex_string(), cipher.to_lower_hex_string());
|
||||||
|
}
|
||||||
|
|
||||||
new_state.keys = fields2keys;
|
new_state.keys = fields2keys;
|
||||||
|
|
||||||
let encrypted_data: HashMap<String, String> = fields2cipher.into_iter()
|
|
||||||
.map(|(k, v)| {
|
|
||||||
let hash = new_state.pcd_commitment.get(k).unwrap().to_owned();
|
|
||||||
let cipher = v.as_str().unwrap().to_owned();
|
|
||||||
(hash.as_str().unwrap().to_owned(), cipher)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
process.insert_concurrent_state(new_state.clone())?;
|
process.insert_concurrent_state(new_state.clone())?;
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -1159,7 +1149,7 @@ pub fn create_new_process(
|
|||||||
let commit_msg = CommitMessage::new_update_commitment(
|
let commit_msg = CommitMessage::new_update_commitment(
|
||||||
process_id,
|
process_id,
|
||||||
pcd_commitment,
|
pcd_commitment,
|
||||||
roles.into_iter().collect(),
|
roles,
|
||||||
public_data,
|
public_data,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1183,33 +1173,32 @@ pub fn create_new_process(
|
|||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
/// 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(
|
||||||
process: JsValue,
|
mut process: Process,
|
||||||
new_attributes: JsValue,
|
new_attributes: JsValue,
|
||||||
roles: JsValue,
|
roles: JsValue,
|
||||||
new_public_data: JsValue,
|
new_public_data: JsValue,
|
||||||
) -> ApiResult<ApiReturn> {
|
) -> ApiResult<ApiReturn> {
|
||||||
let mut process: Process = serde_wasm_bindgen::from_value(process)?;
|
let new_attributes: Pcd = serde_wasm_bindgen::from_value(new_attributes)?;
|
||||||
let new_attributes: Value = serde_wasm_bindgen::from_value(new_attributes)?;
|
let roles: Roles = serde_wasm_bindgen::from_value(roles)?;
|
||||||
let roles: BTreeMap<String, RoleDefinition> = serde_wasm_bindgen::from_value(roles)?;
|
let new_public_data: Pcd = serde_wasm_bindgen::from_value(new_public_data)?;
|
||||||
let new_public_data: BTreeMap<String, String> = serde_wasm_bindgen::from_value(new_public_data)?;
|
|
||||||
// debug!("{:#?}", process);
|
|
||||||
// debug!("{:#?}", new_attributes);
|
|
||||||
// debug!("{:#?}", roles);
|
|
||||||
|
|
||||||
let process_id = process.get_process_id()?;
|
let process_id = process.get_process_id()?;
|
||||||
|
|
||||||
let prev_state = process.get_latest_commited_state()
|
let prev_state = process.get_latest_commited_state()
|
||||||
.ok_or(ApiError::new("Process must have at least one state already commited".to_owned()))?;
|
.ok_or(ApiError::new("Process must have at least one state already commited".to_owned()))?;
|
||||||
|
|
||||||
let public_data = if new_public_data.len() > 0 { new_public_data } else { prev_state.public_data.clone() };
|
let mut prev_public_data = prev_state.public_data.clone();
|
||||||
|
for (field, value) in new_public_data.into_iter() {
|
||||||
|
prev_public_data.insert(field, value);
|
||||||
|
}
|
||||||
|
|
||||||
// We expect the whole set of attributes for now, even if value does'nt change since previous state
|
// We expect the whole set of attributes for now, even if value doesn't change since previous state
|
||||||
// We rehash everything with the new txid, so we need the clear value
|
// We rehash everything with the new txid, so we need the clear value
|
||||||
// eventually we would like to be able to create partial states even if we don't have read access to some attributes
|
// eventually we would like to be able to create partial states even if we don't have read access to some attributes
|
||||||
let mut new_state = ProcessState::new(
|
let mut new_state = ProcessState::new(
|
||||||
process.get_process_tip()?,
|
process.get_process_tip()?,
|
||||||
new_attributes.to_value_object()?,
|
new_attributes.clone(),
|
||||||
&public_data,
|
prev_public_data,
|
||||||
roles.clone()
|
roles.clone()
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -1228,20 +1217,18 @@ pub fn update_process(
|
|||||||
|
|
||||||
let diffs = create_diffs(&process, &new_state)?;
|
let diffs = create_diffs(&process, &new_state)?;
|
||||||
|
|
||||||
let all_fields: Vec<String> = new_attributes.as_object().unwrap().into_iter().map(|(field, _)| field.clone()).collect();
|
let all_fields: Vec<String> = new_attributes.iter().map(|(field, _)| field.clone()).collect();
|
||||||
let mut fields2keys = Map::new();
|
let mut encrypted_data = BTreeMap::new();
|
||||||
let mut fields2cipher = Map::new();
|
|
||||||
new_attributes.encrypt_fields(&all_fields, &mut fields2keys, &mut fields2cipher);
|
|
||||||
|
|
||||||
new_state.keys = fields2keys;
|
let mut rng = thread_rng();
|
||||||
|
for (field, plain_value) in new_attributes.iter() {
|
||||||
let encrypted_data: HashMap<String, String> = fields2cipher.into_iter()
|
let hash = new_state.pcd_commitment.get(field).ok_or(anyhow::Error::msg("Missing commitment"))?;
|
||||||
.map(|(k, v)| {
|
let key = generate_key(&mut rng);
|
||||||
let hash = new_state.pcd_commitment.get(k).unwrap().to_owned();
|
new_state.keys.insert(field.to_owned(), key);
|
||||||
let cipher = v.as_str().unwrap().to_owned();
|
let serialized = serde_json::to_string(plain_value)?;
|
||||||
(hash.as_str().unwrap().to_owned(), cipher)
|
let cipher = encrypt_with_key(&key, serialized.as_bytes())?;
|
||||||
})
|
encrypted_data.insert(hash.to_lower_hex_string(), cipher.to_lower_hex_string());
|
||||||
.collect();
|
}
|
||||||
|
|
||||||
// Add the new state to the process
|
// Add the new state to the process
|
||||||
process.insert_concurrent_state(new_state.clone())?;
|
process.insert_concurrent_state(new_state.clone())?;
|
||||||
@ -1264,7 +1251,7 @@ pub fn update_process(
|
|||||||
let commit_msg = CommitMessage::new_update_commitment(
|
let commit_msg = CommitMessage::new_update_commitment(
|
||||||
process_id,
|
process_id,
|
||||||
new_state.pcd_commitment,
|
new_state.pcd_commitment,
|
||||||
roles.into_iter().collect(),
|
roles,
|
||||||
new_state.public_data,
|
new_state.public_data,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1276,13 +1263,22 @@ pub fn update_process(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn request_data(process_id: String, state_ids: Vec<String>, roles: JsValue) -> ApiResult<ApiReturn> {
|
pub fn request_data(process_id: String, state_ids_str: Vec<String>, roles: JsValue) -> 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();
|
||||||
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();
|
||||||
let roles: Vec<BTreeMap<String, RoleDefinition>> = serde_wasm_bindgen::from_value(roles)?;
|
let roles: Vec<Roles> = serde_wasm_bindgen::from_value(roles)?;
|
||||||
|
|
||||||
|
let mut state_ids: Vec<[u8; 32]> = vec![];
|
||||||
|
for s in state_ids_str {
|
||||||
|
if (s.len() == 0 || s == String::from_utf8(Vec::from([0u8; 32])).unwrap()) { continue; }
|
||||||
|
let state_id: Result<[u8; 32], _> = Vec::from_hex(&s)?.try_into().map_err(|_| ApiError::new("Invalid state id".to_owned()));
|
||||||
|
if let Ok(state_id) = state_id {
|
||||||
|
state_ids.push(state_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut send_to: HashSet<SilentPaymentAddress> = HashSet::new();
|
let mut send_to: HashSet<SilentPaymentAddress> = HashSet::new();
|
||||||
for role in roles {
|
for role in roles {
|
||||||
@ -1294,7 +1290,7 @@ pub fn request_data(process_id: String, state_ids: Vec<String>, roles: JsValue)
|
|||||||
for member in members {
|
for member in members {
|
||||||
for address in member.get_addresses() {
|
for address in member.get_addresses() {
|
||||||
if address == local_address { continue };
|
if address == local_address { continue };
|
||||||
send_to.insert(SilentPaymentAddress::try_from(address).unwrap());
|
send_to.insert(SilentPaymentAddress::try_from(address)?);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1303,7 +1299,8 @@ pub fn request_data(process_id: String, state_ids: Vec<String>, roles: JsValue)
|
|||||||
let prd_request = Prd::new_request(
|
let prd_request = Prd::new_request(
|
||||||
process_id,
|
process_id,
|
||||||
sender,
|
sender,
|
||||||
state_ids.iter().map(|s| Vec::from_hex(s).unwrap().try_into().unwrap()).collect());
|
state_ids
|
||||||
|
);
|
||||||
|
|
||||||
let prd_msg = prd_request.to_network_msg(sp_wallet)?;
|
let prd_msg = prd_request.to_network_msg(sp_wallet)?;
|
||||||
|
|
||||||
@ -1333,6 +1330,7 @@ pub fn create_update_message(
|
|||||||
let mut processes = lock_processes()?;
|
let mut processes = lock_processes()?;
|
||||||
|
|
||||||
let process_id = OutPoint::from_str(&process_id)?;
|
let process_id = OutPoint::from_str(&process_id)?;
|
||||||
|
let state_id: [u8; 32] = Vec::from_hex(&state_id)?.try_into().map_err(|_| ApiError::new("Invalid state_id".to_owned()))?;
|
||||||
|
|
||||||
let process = processes.get_mut(&process_id)
|
let process = processes.get_mut(&process_id)
|
||||||
.ok_or(ApiError::new("Unknown process".to_owned()))?;
|
.ok_or(ApiError::new("Unknown process".to_owned()))?;
|
||||||
@ -1346,7 +1344,7 @@ pub fn create_update_message(
|
|||||||
|
|
||||||
let mut all_members: HashMap<Member, HashSet<String>> = HashMap::new();
|
let mut all_members: HashMap<Member, HashSet<String>> = HashMap::new();
|
||||||
let shared_secrets = lock_shared_secrets()?;
|
let shared_secrets = lock_shared_secrets()?;
|
||||||
for (name, role) in &update_state.roles {
|
for (name, role) in update_state.roles.iter() {
|
||||||
let fields: Vec<String> = role
|
let fields: Vec<String> = role
|
||||||
.validation_rules
|
.validation_rules
|
||||||
.iter()
|
.iter()
|
||||||
@ -1410,30 +1408,25 @@ pub fn create_update_message(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn validate_state(process_id: String, state_id: String) -> ApiResult<ApiReturn> {
|
pub fn validate_state(process: Process, state_id: String) -> ApiResult<ApiReturn> {
|
||||||
add_validation_token(process_id, state_id, true)
|
add_validation_token(process, state_id, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn refuse_state(process_id: String, state_id: String) -> ApiResult<ApiReturn> {
|
pub fn refuse_state(process: Process, state_id: String) -> ApiResult<ApiReturn> {
|
||||||
add_validation_token(process_id, state_id, false)
|
add_validation_token(process, state_id, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn evaluate_state(process_id: String, previous_state: Option<String>, state: String) -> ApiResult<ApiReturn> {
|
pub fn evaluate_state(process_id: String, previous_state: Option<ProcessState>, process_state: ProcessState) -> ApiResult<ApiReturn> {
|
||||||
let prev_state: Option<ProcessState> = if let Some(s) = previous_state { Some(serde_json::from_str(&s)?) } else { None };
|
process_state.is_valid(previous_state.as_ref())?;
|
||||||
let process_state: ProcessState = serde_json::from_str(&state)?;
|
|
||||||
|
|
||||||
process_state.is_valid(prev_state.as_ref())?;
|
|
||||||
|
|
||||||
let clear_pcd = process_state.decrypt_pcd()?;
|
|
||||||
|
|
||||||
// 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 outpoint: OutPoint = OutPoint::from_str(&process_id)?;
|
||||||
let commit_msg = CommitMessage::new_update_commitment(
|
let commit_msg = CommitMessage::new_update_commitment(
|
||||||
outpoint,
|
outpoint,
|
||||||
process_state.pcd_commitment,
|
process_state.pcd_commitment,
|
||||||
process_state.roles.clone().into_iter().collect(),
|
process_state.roles,
|
||||||
process_state.public_data,
|
process_state.public_data,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1443,27 +1436,18 @@ pub fn evaluate_state(process_id: String, previous_state: Option<String>, state:
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_validation_token(process_id: String, state_id: String, approval: bool) -> ApiResult<ApiReturn> {
|
fn add_validation_token(mut process: Process, state_id: String, approval: bool) -> 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 outpoint = OutPoint::from_str(&process_id)?;
|
if state_id == [0u8; 32] { return Err(ApiError::new("Can't validate empty state".to_owned())); }
|
||||||
|
|
||||||
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 update_state: &mut ProcessState = process.get_state_for_id_mut(&state_id)?;
|
||||||
|
|
||||||
let merkle_root: [u8; 32] = Vec::from_hex(&state_id)?
|
|
||||||
.try_into()
|
|
||||||
.map_err(
|
|
||||||
|_| ApiError::new(format!("Failed to deserialize state_id: {}", state_id))
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let message_hash = if approval {
|
let message_hash = if approval {
|
||||||
AnkHash::ValidationYes(AnkValidationYesHash::from_merkle_root(merkle_root))
|
AnkHash::ValidationYes(AnkValidationYesHash::from_merkle_root(state_id))
|
||||||
} else {
|
} else {
|
||||||
AnkHash::ValidationNo(AnkValidationNoHash::from_merkle_root(merkle_root))
|
AnkHash::ValidationNo(AnkValidationNoHash::from_merkle_root(state_id))
|
||||||
};
|
};
|
||||||
|
|
||||||
let local_device = lock_local_device()?;
|
let local_device = lock_local_device()?;
|
||||||
@ -1480,11 +1464,10 @@ fn add_validation_token(process_id: String, state_id: String, approval: bool) ->
|
|||||||
let update_is_valid = update_state.is_valid(process.get_parent_state(&update_state.commited_in));
|
let update_is_valid = update_state.is_valid(process.get_parent_state(&update_state.commited_in));
|
||||||
if update_is_valid.is_ok() {
|
if update_is_valid.is_ok() {
|
||||||
|
|
||||||
let pcd_commitment = update_state.pcd_commitment.clone();
|
|
||||||
let mut commit_msg = CommitMessage::new_update_commitment(
|
let mut commit_msg = CommitMessage::new_update_commitment(
|
||||||
process.get_process_id()?,
|
process.get_process_id()?,
|
||||||
pcd_commitment,
|
update_state.pcd_commitment.clone(),
|
||||||
update_state.roles.clone().into_iter().collect(),
|
update_state.roles.clone(),
|
||||||
update_state.public_data.clone(),
|
update_state.public_data.clone(),
|
||||||
);
|
);
|
||||||
commit_msg.set_validation_tokens(update_state.validation_tokens.clone());
|
commit_msg.set_validation_tokens(update_state.validation_tokens.clone());
|
||||||
@ -1496,13 +1479,13 @@ fn add_validation_token(process_id: String, state_id: String, approval: bool) ->
|
|||||||
};
|
};
|
||||||
|
|
||||||
let updated_process = UpdatedProcess {
|
let updated_process = UpdatedProcess {
|
||||||
process_id: OutPoint::from_str(&process_id)?,
|
process_id,
|
||||||
current_process: process.clone(),
|
current_process: process.clone(),
|
||||||
validated_state: Some(state_id.clone()),
|
validated_state: Some(state_id.clone()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let ciphers_to_send = new_response_prd(OutPoint::from_str(&process_id)?, process.get_state_for_id_mut(&state_id)?)?;
|
let ciphers_to_send = new_response_prd(process_id, process.get_state_for_id_mut(&state_id)?)?;
|
||||||
|
|
||||||
Ok(ApiReturn {
|
Ok(ApiReturn {
|
||||||
updated_process: Some(updated_process),
|
updated_process: Some(updated_process),
|
||||||
@ -1515,6 +1498,7 @@ fn add_validation_token(process_id: String, 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_id: String, state_id: String) -> ApiResult<ApiReturn> {
|
||||||
let mut processes = lock_processes()?;
|
let mut processes = lock_processes()?;
|
||||||
|
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 outpoint = OutPoint::from_str(&process_id)?;
|
||||||
|
|
||||||
@ -1538,7 +1522,7 @@ fn new_response_prd(process_id: OutPoint, update_state: &mut ProcessState) -> An
|
|||||||
|
|
||||||
let mut all_members: HashMap<Member, HashSet<String>> = HashMap::new();
|
let mut all_members: HashMap<Member, HashSet<String>> = HashMap::new();
|
||||||
let shared_secrets = lock_shared_secrets()?;
|
let shared_secrets = lock_shared_secrets()?;
|
||||||
for (name, role) in &update_state.roles {
|
for (name, role) in update_state.roles.iter() {
|
||||||
let fields: Vec<String> = role
|
let fields: Vec<String> = role
|
||||||
.validation_rules
|
.validation_rules
|
||||||
.iter()
|
.iter()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user