Update api.rs for latest common dev
This commit is contained in:
parent
a592001fdb
commit
7c9eecab7a
294
src/api.rs
294
src/api.rs
@ -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,29 +1084,26 @@ 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 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();
|
||||
|
||||
// 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()
|
||||
});
|
||||
} else {
|
||||
let freezed_utxos = lock_freezed_utxos()?;
|
||||
|
||||
let local_device = lock_local_device()?;
|
||||
@ -1126,7 +1111,7 @@ pub fn create_commit_message(
|
||||
let sp_wallet = local_device.get_wallet();
|
||||
|
||||
let signed_psbt = create_transaction(
|
||||
&vec![],
|
||||
vec![],
|
||||
&freezed_utxos,
|
||||
sp_wallet,
|
||||
vec![Recipient {
|
||||
@ -1144,12 +1129,38 @@ pub fn create_commit_message(
|
||||
Ok(ApiReturn {
|
||||
commit_to_send: Some(CommitMessage::new_first_commitment(
|
||||
tx,
|
||||
0,
|
||||
commitment.to_byte_array(),
|
||||
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 {
|
||||
return Err(ApiError::new("Process not found".to_owned()));
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user