Break down parse_network_msg into parse_new_tx, parse_cipher

This commit is contained in:
Sosthene 2024-08-14 09:45:19 +02:00
parent ec47592581
commit b2cab53188

View File

@ -474,7 +474,7 @@ pub fn reset_device() -> ApiResult<()> {
Ok(()) Ok(())
} }
fn handle_recover_transaction( fn handle_transaction(
updated: HashMap<OutPoint, OwnedOutput>, updated: HashMap<OutPoint, OwnedOutput>,
tx: &Transaction, tx: &Transaction,
sp_wallet: &mut SpWallet, sp_wallet: &mut SpWallet,
@ -666,7 +666,7 @@ fn process_transaction(
tx_hex: String, tx_hex: String,
blockheight: u32, blockheight: u32,
tweak_data_hex: String, tweak_data_hex: String,
) -> anyhow::Result<CachedMessage> { ) -> anyhow::Result<Option<CachedMessage>> {
let tx = deserialize::<Transaction>(&Vec::from_hex(&tx_hex)?)?; let tx = deserialize::<Transaction>(&Vec::from_hex(&tx_hex)?)?;
let tweak_data = PublicKey::from_str(&tweak_data_hex)?; let tweak_data = PublicKey::from_str(&tweak_data_hex)?;
@ -676,105 +676,83 @@ fn process_transaction(
let updated = wallet.update_wallet_with_transaction(&tx, blockheight, tweak_data)?; let updated = wallet.update_wallet_with_transaction(&tx, blockheight, tweak_data)?;
if updated.len() > 0 { if updated.len() > 0 {
let updated_msg = handle_recover_transaction(updated, &tx, wallet, tweak_data)?; let updated_msg = handle_transaction(updated, &tx, wallet, tweak_data)?;
return Ok(updated_msg); return Ok(Some(updated_msg));
} }
Err(anyhow::Error::msg("No output found")) Ok(None)
}
fn process_new_tx_error(msg: NewTxMessage) -> anyhow::Result<CachedMessage> {
// how do we match this error with the cached message?
unimplemented!();
} }
#[wasm_bindgen] #[wasm_bindgen]
pub fn parse_network_msg(raw: String, fee_rate: u32) -> ApiResult<CachedMessage> { pub fn parse_new_tx(new_tx_msg: String, block_height: u32, fee_rate: u32) -> ApiResult<Option<CachedMessage>> {
if let Ok(ank_msg) = serde_json::from_str::<AnkNetworkMsg>(&raw) { let new_tx: NewTxMessage = serde_json::from_str(&new_tx_msg)?;
match ank_msg.flag {
AnkFlag::NewTx => { if let Some(error) = new_tx.error {
let tx_message = serde_json::from_str::<NewTxMessage>(&ank_msg.content)?; return Err(ApiError {
if let Some(ref error) = tx_message.error { message: format!("NewTx returned with an error: {}", error),
// Transaction failed to broadcast });
// we can retry later or check the availability of our spent output, depending on the actual error }
// we should probably look up the cached message and record the error
log::error!("{}", error); if new_tx.tweak_data.is_none() {
// let updated = process_new_tx_error(tx_message)?; return Err(ApiError {
let updated = CachedMessage::new(); message: "Missing tweak_data".to_owned(),
return Ok(updated); });
} }
if tx_message.tweak_data.is_none() {
return Err(ApiError { let msg =
message: "Missing tweak_data".to_owned(), process_transaction(new_tx.transaction, block_height, new_tx.tweak_data.unwrap())?;
});
} Ok(msg)
let network_msg = }
process_transaction(tx_message.transaction, 0, tx_message.tweak_data.unwrap())?;
return Ok(network_msg); #[wasm_bindgen]
} pub fn parse_cipher(cipher_msg: String, fee_rate: u32) -> ApiResult<CachedMessage> {
AnkFlag::Faucet => { // let's try to decrypt with keys we found in transactions but haven't used yet
let faucet_msg = serde_json::from_str::<FaucetMessage>(&ank_msg.content)?; let mut messages = lock_messages()?;
if let Some(error) = faucet_msg.error { let cipher = Vec::from_hex(&cipher_msg.trim_matches('\"'))?;
debug!("Faucet msg returned with an error: {}", error); if let Some(message) = messages.iter_mut().find(|m| match m.status {
} CachedMessageStatus::TxWaitingCipher | CachedMessageStatus::Trusted => {
unimplemented!(); m.try_decrypt_cipher(cipher.clone()).is_ok()
}
AnkFlag::Cipher => {
// let's try to decrypt with keys we found in transactions but haven't used yet
let mut messages = lock_messages()?;
let cipher = Vec::from_hex(&ank_msg.content.trim_matches('\"'))?;
if let Some(message) = messages.iter_mut().find(|m| match m.status {
CachedMessageStatus::TxWaitingCipher | CachedMessageStatus::Trusted => {
m.try_decrypt_cipher(cipher.clone()).is_ok()
}
_ => return false,
}) {
let plain = message.try_decrypt_cipher(cipher).unwrap();
debug!("Found message {}", String::from_utf8(plain.clone())?);
if message.status == CachedMessageStatus::TxWaitingCipher {
let cipher_msg: CipherMessage = serde_json::from_slice(&plain)?;
// does the retrieved message match with the commited hash?
let hash = create_commitment(serde_json::to_string(&cipher_msg)?);
if Some(hash) != message.commitment {
return Err(ApiError {
message: "Message doesn't match commitment".to_owned(),
});
}
message.sender = Some(cipher_msg.sender);
message.ciphertext = None;
if cipher_msg.message.starts_with("PAIRING") {
// we don't follow the classic confirmation pattern
// set the status to sth else
// if we agree, we must send another notification to remote
// the notification output here will be spent as our first session
message.status = CachedMessageStatus::Pairing;
} else if cipher_msg.message.starts_with("LOGIN") {
message.status = CachedMessageStatus::Login;
} else {
message.status = CachedMessageStatus::ReceivedMustConfirm;
}
message.plaintext.push(cipher_msg.message);
} else {
// We're receiving a message for some action already engaged
// Let's update the message by pushing what we just found out
message.plaintext.push(String::from_utf8(plain)?);
}
return Ok(message.clone());
} 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.ciphertext = Some(ank_msg.content);
messages.push(new_msg.clone());
return Ok(new_msg);
}
}
_ => unimplemented!(),
} }
_ => return false,
}) {
let plain = message.try_decrypt_cipher(cipher).unwrap();
// debug!("Found message {}", String::from_utf8(plain.clone())?);
if message.status == CachedMessageStatus::TxWaitingCipher {
let cipher_msg: CipherMessage = serde_json::from_slice(&plain)?;
// does the retrieved message match with the commited hash?
let hash = create_commitment(serde_json::to_string(&cipher_msg)?);
if Some(hash) != message.commitment {
return Err(ApiError {
message: "Message doesn't match commitment".to_owned(),
});
}
message.sender = Some(cipher_msg.sender);
message.ciphertext = None;
if cipher_msg.message.starts_with("PAIRING") {
// we don't follow the classic confirmation pattern
// if we agree, we must send another notification to remote
// the notification output here will be spent as our first session
message.status = CachedMessageStatus::Pairing;
} else if cipher_msg.message.starts_with("LOGIN") {
message.status = CachedMessageStatus::Login;
} else {
message.status = CachedMessageStatus::ReceivedMustConfirm;
}
message.plaintext.push(cipher_msg.message);
} else {
// We're receiving a message for some action already engaged
// Let's update the message by pushing what we just found out
message.plaintext.push(String::from_utf8(plain)?);
}
return Ok(message.clone());
} else { } else {
Err(ApiError { // let's keep it in case we receive the transaction later
message: format!("Can't parse message as a valid 4nk message: {}", raw), let mut new_msg = CachedMessage::new();
}) new_msg.status = CachedMessageStatus::CipherWaitingTx;
new_msg.ciphertext = Some(cipher_msg);
messages.push(new_msg.clone());
return Ok(new_msg);
} }
} }