Update api.rs for latest common dev

This commit is contained in:
Sosthene 2024-10-07 11:22:54 +02:00
parent a592001fdb
commit 7c9eecab7a

View File

@ -84,7 +84,7 @@ use crate::{
pub struct ApiReturn {
pub updated_cached_msg: Vec<CachedMessage>,
pub updated_process: Option<(String, Process)>,
pub new_tx_to_send: Option<String>,
pub new_tx_to_send: Option<NewTxMessage>,
pub ciphers_to_send: Vec<String>,
pub commit_to_send: Option<CommitMessage>,
}
@ -261,6 +261,30 @@ pub fn pair_device(commitment_tx: String, mut sp_addresses: Vec<String>) -> ApiR
Ok(())
}
#[wasm_bindgen]
pub fn get_pairing_tx() -> ApiResult<String> {
let device = lock_local_device()?;
if !device.is_linked() {
return Err(ApiError::new("Device is not linked".to_owned()));
}
let pairing_commitment= device.get_process_commitment().unwrap();
let processes = lock_processes()?;
let process = processes.get(&OutPoint::new(pairing_commitment, 0)).ok_or(ApiError::new("Pairing process not found".to_owned()))?;
let state = process.get_latest_state().unwrap();
let mut decrypted_pcd = Map::new();
state.encrypted_pcd.decrypt_fields(&state.keys, &mut decrypted_pcd)?;
let pairing_tx = decrypted_pcd.get("pairing_tx").unwrap().as_str().unwrap();
Ok(pairing_tx.to_owned())
}
#[wasm_bindgen]
pub fn unpair_device() -> ApiResult<()> {
let mut local_device = lock_local_device()?;
@ -282,8 +306,84 @@ impl outputs_list {
}
#[wasm_bindgen]
pub fn login() -> ApiResult<()> {
unimplemented!();
pub fn login(previous_login_tx: String, fee_rate: u32) -> ApiResult<ApiReturn> {
// We first create a transaction that spends both pairing tx outputs
let previous_tx: Txid = deserialize(&Vec::from_hex(&previous_login_tx)?)?;
let device = lock_local_device()?;
if !device.is_linked() {
return Err(ApiError::new("Device is not linked".to_owned()));
}
let member = device.to_member().unwrap();
let nb_outputs = member.get_addresses().len();
let other_addresses = device.get_other_addresses();
// We get the pairing process out of cache
let commitment_txid = device.get_process_commitment().unwrap();
let commitment_outpoint = OutPoint::new(commitment_txid, 0);
let process = lock_processes()?.get(&commitment_outpoint).unwrap().clone();
let state = process.get_latest_state().unwrap().clone();
let mut shared_secrets = Vec::new();
for address in other_addresses {
let shared_secret = process.get_shared_secret_for_address(&SilentPaymentAddress::try_from(address)?);
if let Some(shared_secret) = shared_secret {
shared_secrets.push(shared_secret);
}
}
let mut decrypted_pcd = Map::new();
state.encrypted_pcd.decrypt_fields(&state.keys, &mut decrypted_pcd)?;
let pairing_tx = decrypted_pcd.get("pairing_tx").unwrap().as_str().unwrap();
let wallet = device.get_wallet();
let freezed_utxos = lock_freezed_utxos()?;
let recipients: Vec<Recipient> = device.to_member().unwrap().get_addresses().iter().map(|a| {
Recipient {
address: a.clone(),
amount: DEFAULT_AMOUNT,
nb_outputs: 1,
}
}).collect();
let mut mandatory_inputs = Vec::new();
for i in 0u32..nb_outputs.try_into().unwrap() {
mandatory_inputs.push(OutPoint::new(previous_tx, i));
}
let signed_psbt = create_transaction(
mandatory_inputs,
&freezed_utxos,
wallet,
recipients,
None,
Amount::from_sat(fee_rate.into()),
None,
)?;
// We send it in a TxProposal prd
let tx_proposal = Prd::new_tx_proposal(commitment_outpoint, member, signed_psbt);
debug!("tx_proposal: {:?}", tx_proposal);
// We encrypt the prd with the shared_secret for pairing process
let prd_msg = tx_proposal.to_network_msg(wallet)?;
debug!("prd_msg: {:?}", prd_msg);
let mut ciphers = Vec::new();
for shared_secret in shared_secrets {
let cipher = encrypt_with_key(shared_secret.as_byte_array(), prd_msg.as_bytes())?;
ciphers.push(cipher.to_lower_hex_string());
}
// We return the cipher
Ok(ApiReturn {
ciphers_to_send: ciphers,
..Default::default()
})
}
#[wasm_bindgen]
@ -641,7 +741,7 @@ pub fn response_prd(
let prd = Prd::new_response(
OutPoint::from_str(&root_commitment)?,
serde_json::to_string(&member)?,
proof,
vec![proof],
pcd_hash,
);
@ -940,118 +1040,6 @@ fn handle_decrypted_message(
.map_err(|e| anyhow::Error::msg(format!("Failed to handle decrypted message: {}", e)))
}
// fn match_with_active_processes(cipher: &[u8]) -> anyhow::Result<ApiReturn> {
// // Try decrypting the cipher with available processes and shared secrets
// let (plain, sp_address, process_root_commitment) =
// try_decrypt_with_processes(cipher, lock_processes()?)
// .ok_or_else(|| anyhow::Error::msg("No match in active processes"))?;
// debug!("matched with an active process");
// // Try to handle the decrypted payload as PRD first
// if let Ok(res) = handle_prd(&plain, sp_address, None) {
// return Ok(res);
// }
// // If not PRD, try to handle as PCD
// if let Ok(res) = handle_pcd(plain, sp_address, process_root_commitment) {
// return Ok(ApiReturn {
// updated_process: Some((process_root_commitment.to_string(), res)),
// ..Default::default()
// });
// }
// // If neither PRD nor PCD, return an error
// Err(anyhow::Error::msg("payload can't be parsed"))
// }
// /// Go through cached messages for tx waiting for a prd
// /// We update the process so that the
// fn match_cipher_to_cached_messages(cipher: &[u8]) -> anyhow::Result<ApiReturn> {
// // let's try to decrypt with keys we found in transactions but haven't used yet
// let mut messages = lock_messages()?;
// let mut plain = vec![];
// // debug!("messages: {:?}", messages);
// if let Some(message) = messages.iter_mut().find(|m| match m.status {
// CachedMessageStatus::TxWaitingPrd => {
// if let Ok(m) = m.try_decrypt_message(&cipher) {
// plain = m;
// return true;
// } else {
// return false;
// }
// }
// _ => return false,
// }) {
// // debug!("Found message {}", String::from_utf8(plain.clone())?);
// let commitment = AnkPrdHash::from_str(message.commitment.as_ref().unwrap())?;
// let prd = Prd::extract_from_message_with_commitment(&plain, &commitment)?;
// let proof_key = prd.proof.unwrap().get_key();
// let mut actual_sender = String::default();
// for sp_address in serde_json::from_str::<Member>(&prd.sender)?.get_addresses() {
// if proof_key
// == SilentPaymentAddress::try_from(sp_address.as_str())
// .unwrap()
// .get_spend_key()
// .x_only_public_key()
// .0
// {
// actual_sender = sp_address;
// break;
// } else {
// continue;
// }
// }
// let shared_secret = message.shared_secrets.first().unwrap();
// let root_outpoint = OutPoint::from_str(&prd.root_commitment)?;
// let mut processes = lock_processes()?;
// let updated_process: Process;
// if let Some(process) = processes.get_mut(&root_outpoint) {
// // we're actually replacing the shared_secret for that process and that sender if it exists
// process.shared_secrets.insert(
// actual_sender,
// Vec::from_hex(shared_secret)?.to_lower_hex_string(),
// );
// updated_process = process.clone();
// } else {
// let mut shared_secrets = HashMap::new();
// shared_secrets.insert(
// actual_sender,
// Vec::from_hex(shared_secret)?.to_lower_hex_string(),
// );
// let new_process = Process {
// shared_secrets,
// ..Default::default()
// };
// processes.insert(root_outpoint, new_process.clone());
// updated_process = new_process;
// }
// return Ok(ApiReturn {
// updated_cached_msg: vec![CachedMessage {
// id: message.id,
// ..Default::default()
// }],
// updated_process: Some((root_outpoint.to_string(), updated_process)),
// ..Default::default()
// });
// } else {
// // let's keep it in case we receive the transaction later
// let mut new_msg = CachedMessage::new();
// new_msg.status = CachedMessageStatus::CipherWaitingTx;
// new_msg.cipher.push(cipher.to_lower_hex_string());
// messages.push(new_msg.clone());
// return Ok(ApiReturn {
// updated_cached_msg: vec![new_msg],
// ..Default::default()
// });
// }
// }
#[wasm_bindgen]
pub fn parse_cipher(cipher_msg: String) -> ApiResult<ApiReturn> {
// Check that the cipher is not empty or too long
@ -1096,59 +1084,82 @@ pub fn get_available_amount() -> ApiResult<u64> {
}
#[wasm_bindgen]
/// This takes some commitment and creates a commit msg so that relay commits it on chain
/// This takes a reference to a process and creates a commit msg for the latest state
pub fn create_commit_message(
to_commit: String,
init_commitment_outpoint: String,
relay_address: String,
init_commitment_outpoint: Option<String>, // if None, we're initializing a new commitment chain
fee_rate: u32,
) -> ApiResult<ApiReturn> {
let value = Value::from_str(&to_commit)?;
let commitment = value.tagged_hash();
let outpoint = OutPoint::from_str(&init_commitment_outpoint)?;
// if the transaction exists, we don't need to create a transaction and just put the outpoint in the msg
if let Some(outpoint) = init_commitment_outpoint {
// Todo : if we have an init tx, look into cached processes and confirm that it exists
// We just send the message with the outpoint
return Ok(ApiReturn {
commit_to_send: Some(CommitMessage::new_update_commitment(
OutPoint::from_str(&outpoint)?,
0,
commitment.to_byte_array(),
)),
..Default::default()
});
if let Some(process) = lock_processes()?.get(&outpoint) {
match process.get_number_of_states() {
0 => Err(ApiError::new("Process has no states".to_owned())),
1 => {
// This is a creation
let state = process.get_latest_state().unwrap();
if state.commited_in != OutPoint::null() {
return Err(ApiError::new("Latest state is already commited".to_owned()));
}
let encrypted_pcd = state.encrypted_pcd.clone();
let keys = state.keys.clone();
let freezed_utxos = lock_freezed_utxos()?;
let local_device = lock_local_device()?;
let sp_wallet = local_device.get_wallet();
let signed_psbt = create_transaction(
vec![],
&freezed_utxos,
sp_wallet,
vec![Recipient {
address: relay_address,
amount: Amount::from_sat(1000),
nb_outputs: 1,
}],
None,
Amount::from_sat(fee_rate.into()),
None,
)?;
let tx = signed_psbt.extract_tx()?;
Ok(ApiReturn {
commit_to_send: Some(CommitMessage::new_first_commitment(
tx,
encrypted_pcd.as_object().unwrap().clone(),
keys,
)),
..Default::default()
})
}
_ => {
// We're updating an existing process
// Check that initial outpoint is not a placeholder and that latest state has a commited_in of null
if outpoint.vout != u32::MAX {
return Err(ApiError::new("Initial outpoint is a placeholder".to_owned()));
}
let state = process.get_latest_state().unwrap();
if state.commited_in != OutPoint::null() {
return Err(ApiError::new("Latest state is already commited".to_owned()));
}
let encrypted_pcd = state.encrypted_pcd.clone();
let keys = state.keys.clone();
// We just send the message with the outpoint
return Ok(ApiReturn {
commit_to_send: Some(CommitMessage::new_update_commitment(
outpoint,
encrypted_pcd.as_object().unwrap().clone(),
keys,
)),
..Default::default()
});
}
}
} else {
let freezed_utxos = lock_freezed_utxos()?;
let local_device = lock_local_device()?;
let sp_wallet = local_device.get_wallet();
let signed_psbt = create_transaction(
&vec![],
&freezed_utxos,
sp_wallet,
vec![Recipient {
address: relay_address,
amount: Amount::from_sat(1000),
nb_outputs: 1,
}],
None,
Amount::from_sat(fee_rate.into()),
None,
)?;
let tx = signed_psbt.extract_tx()?;
Ok(ApiReturn {
commit_to_send: Some(CommitMessage::new_first_commitment(
tx,
0,
commitment.to_byte_array(),
)),
..Default::default()
})
return Err(ApiError::new("Process not found".to_owned()));
}
}
@ -1174,7 +1185,7 @@ pub fn create_update_transaction(
if let Some(p) = processes.get_mut(&outpoint) {
// compare the provided new_state with the process defined template
let previous_state = &p.get_status_at(0).unwrap().encrypted_pcd;
let previous_state = &p.get_state_at(0).unwrap().encrypted_pcd;
if !compare_maps(previous_state.as_object().unwrap(), pcd_map) {
return Err(ApiError::new(
"Provided updated state is not consistent with the process template".to_owned(),
@ -1250,7 +1261,8 @@ pub fn create_update_transaction(
let mut fields2keys = Map::new();
let mut fields2cipher = Map::new();
let encrypted_pcd = pcd.clone();
encrypted_pcd.encrypt_fields(&mut fields2keys, &mut fields2cipher);
let fields_to_encrypt: Vec<String> = encrypted_pcd.as_object().unwrap().keys().map(|k| k.clone()).collect();
encrypted_pcd.encrypt_fields(&fields_to_encrypt, &mut fields2keys, &mut fields2cipher);
let local_device = lock_local_device()?;
@ -1273,7 +1285,7 @@ pub fn create_update_transaction(
let freezed_utxos = lock_freezed_utxos()?;
let signed_psbt = create_transaction(
&vec![],
vec![],
&freezed_utxos,
sp_wallet,
recipients,
@ -1320,7 +1332,7 @@ pub fn create_update_transaction(
commited_in: OutPoint::null(),
encrypted_pcd: Value::Object(fields2cipher),
keys: fields2keys,
validation_token: vec![],
validation_tokens: vec![],
});
// Create the new_tx message